changeset 72:b7d981ccd434

NaCl: improved sha512 implementation
author Ivo Smits <Ivo@UCIS.nl>
date Sat, 02 Nov 2013 15:59:51 +0100
parents 7e9d1cfcc562
children 6aca18ee4ec6
files NaCl/crypto_hash/sha512.cs NaCl/crypto_hashblocks/sha512.cs
diffstat 2 files changed, 94 insertions(+), 84 deletions(-) [+]
line wrap: on
line diff
--- a/NaCl/crypto_hash/sha512.cs	Fri Nov 01 00:07:36 2013 +0100
+++ b/NaCl/crypto_hash/sha512.cs	Sat Nov 02 15:59:51 2013 +0100
@@ -4,75 +4,79 @@
 	public static class sha512 {
 		public static int BYTES = 64;
 
-/*		static Byte[] iv = new Byte[64] {
-  0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
-  0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
-  0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
-  0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
-  0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
-  0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
-  0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
-  0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
-};*/
-
 		public static unsafe void crypto_hash(Byte[] outv, Byte[] inv, int inlen) {
 			if (outv.Length < 64) throw new ArgumentException("outv.Length < 64");
 			if (inv.Length < inlen) throw new ArgumentException("inv.Length < inlen");
 			fixed (Byte* outp = outv, inp = inv) crypto_hash(outp, inp, (UInt64)inlen);
 		}
 		public static unsafe void crypto_hash(Byte* outp, Byte* inp, UInt64 inlen) {
-//			Byte[] h = new Byte[64];
-			Byte[] padded = new Byte[256];
-			UInt64 i;
-			UInt64 bytes = inlen;
-			Byte[] h = new Byte[64] {
-  0x6a,0x09,0xe6,0x67,0xf3,0xbc,0xc9,0x08,
-  0xbb,0x67,0xae,0x85,0x84,0xca,0xa7,0x3b,
-  0x3c,0x6e,0xf3,0x72,0xfe,0x94,0xf8,0x2b,
-  0xa5,0x4f,0xf5,0x3a,0x5f,0x1d,0x36,0xf1,
-  0x51,0x0e,0x52,0x7f,0xad,0xe6,0x82,0xd1,
-  0x9b,0x05,0x68,0x8c,0x2b,0x3e,0x6c,0x1f,
-  0x1f,0x83,0xd9,0xab,0xfb,0x41,0xbd,0x6b,
-  0x5b,0xe0,0xcd,0x19,0x13,0x7e,0x21,0x79
-			};
+			sha512state state = new sha512state();
+			state.init();
+			state.process(inp, (int)inlen);
+			state.finish(outp);
+		}
 
-//			for (i = 0; i < 64; ++i) h[i] = iv[i];
-
-			fixed (Byte* hp = h) crypto_hashblocks.sha512.crypto_hashblocks(hp, inp, inlen);
-			inp += inlen;
-			inlen &= 127;
-			inp -= inlen;
-
-			for (i = 0; i < inlen; ++i) padded[i] = inp[i];
-			padded[inlen] = 0x80;
+		public unsafe struct sha512state {
+			fixed UInt64 state[8];
+			fixed Byte input[128];
+			int offset;
+			int length;
 
-			if (inlen < 112) {
-				for (i = inlen + 1; i < 119; ++i) padded[i] = 0;
-				padded[119] = (Byte)(bytes >> 61);
-				padded[120] = (Byte)(bytes >> 53);
-				padded[121] = (Byte)(bytes >> 45);
-				padded[122] = (Byte)(bytes >> 37);
-				padded[123] = (Byte)(bytes >> 29);
-				padded[124] = (Byte)(bytes >> 21);
-				padded[125] = (Byte)(bytes >> 13);
-				padded[126] = (Byte)(bytes >> 5);
-				padded[127] = (Byte)(bytes << 3);
-				fixed (Byte* hp = h, paddedp = padded) crypto_hashblocks.sha512.crypto_hashblocks(hp, paddedp, 128);
-			} else {
-				for (i = inlen + 1; i < 247; ++i) padded[i] = 0;
-				padded[247] = (Byte)(bytes >> 61);
-				padded[248] = (Byte)(bytes >> 53);
-				padded[249] = (Byte)(bytes >> 45);
-				padded[250] = (Byte)(bytes >> 37);
-				padded[251] = (Byte)(bytes >> 29);
-				padded[252] = (Byte)(bytes >> 21);
-				padded[253] = (Byte)(bytes >> 13);
-				padded[254] = (Byte)(bytes >> 5);
-				padded[255] = (Byte)(bytes << 3);
-				fixed (Byte* hp = h, paddedp = padded) crypto_hashblocks.sha512.crypto_hashblocks(hp, paddedp, 256);
+			public unsafe void init() {
+				fixed (UInt64* s = state) {
+					s[0] = 0x6a09e667f3bcc908; s[1] = 0xbb67ae8584caa73b; s[2] = 0x3c6ef372fe94f82b; s[3] = 0xa54ff53a5f1d36f1;
+					s[4] = 0x510e527fade682d1; s[5] = 0x9b05688c2b3e6c1f; s[6] = 0x1f83d9abfb41bd6b; s[7] = 0x5be0cd19137e2179;
+				}
+				offset = 0;
+				length = 0;
 			}
-
-			for (i = 0; i < 64; ++i) outp[i] = h[i];
+			public unsafe void process(Byte* inp, int inlen) {
+				fixed (sha512state* pthis = &this) {
+					length += inlen;
+					if (offset > 0) {
+						int blen = 128 - offset;
+						if (blen > inlen) blen = inlen;
+						for (int i = 0; i < blen; i++) pthis->input[offset++] = *inp++;
+						inlen -= blen;
+					}
+					if (offset == 128) {
+						crypto_hashblocks.sha512.crypto_hashblocks(pthis->state, pthis->input, (UInt64)offset);
+						offset = 0;
+					}
+					if (inlen >= 128) {
+						crypto_hashblocks.sha512.crypto_hashblocks(pthis->state, inp, (UInt64)inlen);
+						inp += inlen;
+						inlen &= 127;
+						inp -= inlen;
+					}
+					if (inlen > 0) {
+						for (int i = 0; i < inlen; i++) pthis->input[offset++] = *inp++;
+					}
+				}
+			}
+			public unsafe void finish(Byte* outp) {
+				fixed (sha512state* s = &this) {
+					s->input[offset++] = 0x80;
+					if (offset > 112) {
+						for (int i = offset; i < 128; i++) s->input[i] = 0;
+						crypto_hashblocks.sha512.crypto_hashblocks(s->state, s->input, 128);
+						offset = 0;
+					}
+					for (int i = offset; i < 119; i++) s->input[i] = 0;
+					UInt64 bytes = (UInt64)length;
+					s->input[119] = (Byte)(bytes >> 61);
+					s->input[120] = (Byte)(bytes >> 53);
+					s->input[121] = (Byte)(bytes >> 45);
+					s->input[122] = (Byte)(bytes >> 37);
+					s->input[123] = (Byte)(bytes >> 29);
+					s->input[124] = (Byte)(bytes >> 21);
+					s->input[125] = (Byte)(bytes >> 13);
+					s->input[126] = (Byte)(bytes >> 5);
+					s->input[127] = (Byte)(bytes << 3);
+					crypto_hashblocks.sha512.crypto_hashblocks(s->state, s->input, 128);
+					crypto_hashblocks.sha512.crypto_hashblocks_state_pack(outp, s->state);
+				}
+			}
 		}
 	}
 }
--- a/NaCl/crypto_hashblocks/sha512.cs	Fri Nov 01 00:07:36 2013 +0100
+++ b/NaCl/crypto_hashblocks/sha512.cs	Sat Nov 02 15:59:51 2013 +0100
@@ -25,27 +25,15 @@
 		private static int dummyvar = 0;
 		private static void dummymethod() { dummyvar++; }
 
-		public unsafe static void crypto_hashblocks(Byte* statebytes, Byte* inp, UInt64 inlen) {
-			UInt64[] state = new UInt64[8];
-			UInt64 a;
-			UInt64 b;
-			UInt64 c;
-			UInt64 d;
-			UInt64 e;
-			UInt64 f;
-			UInt64 g;
-			UInt64 h;
-			UInt64 T1;
-			UInt64 T2;
-
-			a = load_bigendian(statebytes + 0); state[0] = a;
-			b = load_bigendian(statebytes + 8); state[1] = b;
-			c = load_bigendian(statebytes + 16); state[2] = c;
-			d = load_bigendian(statebytes + 24); state[3] = d;
-			e = load_bigendian(statebytes + 32); state[4] = e;
-			f = load_bigendian(statebytes + 40); state[5] = f;
-			g = load_bigendian(statebytes + 48); state[6] = g;
-			h = load_bigendian(statebytes + 56); state[7] = h;
+		public unsafe static void crypto_hashblocks(UInt64* state, Byte* inp, UInt64 inlen) {
+			UInt64 a = state[0];
+			UInt64 b = state[1];
+			UInt64 c = state[2];
+			UInt64 d = state[3];
+			UInt64 e = state[4];
+			UInt64 f = state[5];
+			UInt64 g = state[6];
+			UInt64 h = state[7];
 
 			while (inlen >= 128) {
 				UInt64 w0 = load_bigendian(inp + 0);
@@ -65,6 +53,7 @@
 				UInt64 w14 = load_bigendian(inp + 112);
 				UInt64 w15 = load_bigendian(inp + 120);
 
+				UInt64 T1, T2;
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0x428a2f98d728ae22 + w0; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0x7137449123ef65cd + w1; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0xb5c0fbcfec4d3b2f + w2; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
@@ -102,7 +91,7 @@
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0x06ca6351e003826f + w14; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0x142929670a0e6e70 + w15; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
 
-				dummymethod(); 
+				dummymethod();
 				w0 = ((((w14) >> (19)) | ((w14) << (64 - (19)))) ^ (((w14) >> (61)) | ((w14) << (64 - (61)))) ^ ((w14) >> (6))) + w9 + ((((w1) >> (1)) | ((w1) << (64 - (1)))) ^ (((w1) >> (8)) | ((w1) << (64 - (8)))) ^ ((w1) >> (7))) + w0; w1 = ((((w15) >> (19)) | ((w15) << (64 - (19)))) ^ (((w15) >> (61)) | ((w15) << (64 - (61)))) ^ ((w15) >> (6))) + w10 + ((((w2) >> (1)) | ((w2) << (64 - (1)))) ^ (((w2) >> (8)) | ((w2) << (64 - (8)))) ^ ((w2) >> (7))) + w1; w2 = ((((w0) >> (19)) | ((w0) << (64 - (19)))) ^ (((w0) >> (61)) | ((w0) << (64 - (61)))) ^ ((w0) >> (6))) + w11 + ((((w3) >> (1)) | ((w3) << (64 - (1)))) ^ (((w3) >> (8)) | ((w3) << (64 - (8)))) ^ ((w3) >> (7))) + w2; w3 = ((((w1) >> (19)) | ((w1) << (64 - (19)))) ^ (((w1) >> (61)) | ((w1) << (64 - (61)))) ^ ((w1) >> (6))) + w12 + ((((w4) >> (1)) | ((w4) << (64 - (1)))) ^ (((w4) >> (8)) | ((w4) << (64 - (8)))) ^ ((w4) >> (7))) + w3; w4 = ((((w2) >> (19)) | ((w2) << (64 - (19)))) ^ (((w2) >> (61)) | ((w2) << (64 - (61)))) ^ ((w2) >> (6))) + w13 + ((((w5) >> (1)) | ((w5) << (64 - (1)))) ^ (((w5) >> (8)) | ((w5) << (64 - (8)))) ^ ((w5) >> (7))) + w4; w5 = ((((w3) >> (19)) | ((w3) << (64 - (19)))) ^ (((w3) >> (61)) | ((w3) << (64 - (61)))) ^ ((w3) >> (6))) + w14 + ((((w6) >> (1)) | ((w6) << (64 - (1)))) ^ (((w6) >> (8)) | ((w6) << (64 - (8)))) ^ ((w6) >> (7))) + w5; w6 = ((((w4) >> (19)) | ((w4) << (64 - (19)))) ^ (((w4) >> (61)) | ((w4) << (64 - (61)))) ^ ((w4) >> (6))) + w15 + ((((w7) >> (1)) | ((w7) << (64 - (1)))) ^ (((w7) >> (8)) | ((w7) << (64 - (8)))) ^ ((w7) >> (7))) + w6; w7 = ((((w5) >> (19)) | ((w5) << (64 - (19)))) ^ (((w5) >> (61)) | ((w5) << (64 - (61)))) ^ ((w5) >> (6))) + w0 + ((((w8) >> (1)) | ((w8) << (64 - (1)))) ^ (((w8) >> (8)) | ((w8) << (64 - (8)))) ^ ((w8) >> (7))) + w7; w8 = ((((w6) >> (19)) | ((w6) << (64 - (19)))) ^ (((w6) >> (61)) | ((w6) << (64 - (61)))) ^ ((w6) >> (6))) + w1 + ((((w9) >> (1)) | ((w9) << (64 - (1)))) ^ (((w9) >> (8)) | ((w9) << (64 - (8)))) ^ ((w9) >> (7))) + w8; w9 = ((((w7) >> (19)) | ((w7) << (64 - (19)))) ^ (((w7) >> (61)) | ((w7) << (64 - (61)))) ^ ((w7) >> (6))) + w2 + ((((w10) >> (1)) | ((w10) << (64 - (1)))) ^ (((w10) >> (8)) | ((w10) << (64 - (8)))) ^ ((w10) >> (7))) + w9; w10 = ((((w8) >> (19)) | ((w8) << (64 - (19)))) ^ (((w8) >> (61)) | ((w8) << (64 - (61)))) ^ ((w8) >> (6))) + w3 + ((((w11) >> (1)) | ((w11) << (64 - (1)))) ^ (((w11) >> (8)) | ((w11) << (64 - (8)))) ^ ((w11) >> (7))) + w10; w11 = ((((w9) >> (19)) | ((w9) << (64 - (19)))) ^ (((w9) >> (61)) | ((w9) << (64 - (61)))) ^ ((w9) >> (6))) + w4 + ((((w12) >> (1)) | ((w12) << (64 - (1)))) ^ (((w12) >> (8)) | ((w12) << (64 - (8)))) ^ ((w12) >> (7))) + w11; w12 = ((((w10) >> (19)) | ((w10) << (64 - (19)))) ^ (((w10) >> (61)) | ((w10) << (64 - (61)))) ^ ((w10) >> (6))) + w5 + ((((w13) >> (1)) | ((w13) << (64 - (1)))) ^ (((w13) >> (8)) | ((w13) << (64 - (8)))) ^ ((w13) >> (7))) + w12; w13 = ((((w11) >> (19)) | ((w11) << (64 - (19)))) ^ (((w11) >> (61)) | ((w11) << (64 - (61)))) ^ ((w11) >> (6))) + w6 + ((((w14) >> (1)) | ((w14) << (64 - (1)))) ^ (((w14) >> (8)) | ((w14) << (64 - (8)))) ^ ((w14) >> (7))) + w13; w14 = ((((w12) >> (19)) | ((w12) << (64 - (19)))) ^ (((w12) >> (61)) | ((w12) << (64 - (61)))) ^ ((w12) >> (6))) + w7 + ((((w15) >> (1)) | ((w15) << (64 - (1)))) ^ (((w15) >> (8)) | ((w15) << (64 - (8)))) ^ ((w15) >> (7))) + w14; w15 = ((((w13) >> (19)) | ((w13) << (64 - (19)))) ^ (((w13) >> (61)) | ((w13) << (64 - (61)))) ^ ((w13) >> (6))) + w8 + ((((w0) >> (1)) | ((w0) << (64 - (1)))) ^ (((w0) >> (8)) | ((w0) << (64 - (8)))) ^ ((w0) >> (7))) + w15;
 
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0x27b70a8546d22ffc + w0; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
@@ -122,7 +111,7 @@
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0xf40e35855771202a + w14; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0x106aa07032bbd1b8 + w15; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
 
-				dummymethod(); 
+				dummymethod();
 				w0 = ((((w14) >> (19)) | ((w14) << (64 - (19)))) ^ (((w14) >> (61)) | ((w14) << (64 - (61)))) ^ ((w14) >> (6))) + w9 + ((((w1) >> (1)) | ((w1) << (64 - (1)))) ^ (((w1) >> (8)) | ((w1) << (64 - (8)))) ^ ((w1) >> (7))) + w0; w1 = ((((w15) >> (19)) | ((w15) << (64 - (19)))) ^ (((w15) >> (61)) | ((w15) << (64 - (61)))) ^ ((w15) >> (6))) + w10 + ((((w2) >> (1)) | ((w2) << (64 - (1)))) ^ (((w2) >> (8)) | ((w2) << (64 - (8)))) ^ ((w2) >> (7))) + w1; w2 = ((((w0) >> (19)) | ((w0) << (64 - (19)))) ^ (((w0) >> (61)) | ((w0) << (64 - (61)))) ^ ((w0) >> (6))) + w11 + ((((w3) >> (1)) | ((w3) << (64 - (1)))) ^ (((w3) >> (8)) | ((w3) << (64 - (8)))) ^ ((w3) >> (7))) + w2; w3 = ((((w1) >> (19)) | ((w1) << (64 - (19)))) ^ (((w1) >> (61)) | ((w1) << (64 - (61)))) ^ ((w1) >> (6))) + w12 + ((((w4) >> (1)) | ((w4) << (64 - (1)))) ^ (((w4) >> (8)) | ((w4) << (64 - (8)))) ^ ((w4) >> (7))) + w3; w4 = ((((w2) >> (19)) | ((w2) << (64 - (19)))) ^ (((w2) >> (61)) | ((w2) << (64 - (61)))) ^ ((w2) >> (6))) + w13 + ((((w5) >> (1)) | ((w5) << (64 - (1)))) ^ (((w5) >> (8)) | ((w5) << (64 - (8)))) ^ ((w5) >> (7))) + w4; w5 = ((((w3) >> (19)) | ((w3) << (64 - (19)))) ^ (((w3) >> (61)) | ((w3) << (64 - (61)))) ^ ((w3) >> (6))) + w14 + ((((w6) >> (1)) | ((w6) << (64 - (1)))) ^ (((w6) >> (8)) | ((w6) << (64 - (8)))) ^ ((w6) >> (7))) + w5; w6 = ((((w4) >> (19)) | ((w4) << (64 - (19)))) ^ (((w4) >> (61)) | ((w4) << (64 - (61)))) ^ ((w4) >> (6))) + w15 + ((((w7) >> (1)) | ((w7) << (64 - (1)))) ^ (((w7) >> (8)) | ((w7) << (64 - (8)))) ^ ((w7) >> (7))) + w6; w7 = ((((w5) >> (19)) | ((w5) << (64 - (19)))) ^ (((w5) >> (61)) | ((w5) << (64 - (61)))) ^ ((w5) >> (6))) + w0 + ((((w8) >> (1)) | ((w8) << (64 - (1)))) ^ (((w8) >> (8)) | ((w8) << (64 - (8)))) ^ ((w8) >> (7))) + w7; w8 = ((((w6) >> (19)) | ((w6) << (64 - (19)))) ^ (((w6) >> (61)) | ((w6) << (64 - (61)))) ^ ((w6) >> (6))) + w1 + ((((w9) >> (1)) | ((w9) << (64 - (1)))) ^ (((w9) >> (8)) | ((w9) << (64 - (8)))) ^ ((w9) >> (7))) + w8; w9 = ((((w7) >> (19)) | ((w7) << (64 - (19)))) ^ (((w7) >> (61)) | ((w7) << (64 - (61)))) ^ ((w7) >> (6))) + w2 + ((((w10) >> (1)) | ((w10) << (64 - (1)))) ^ (((w10) >> (8)) | ((w10) << (64 - (8)))) ^ ((w10) >> (7))) + w9; w10 = ((((w8) >> (19)) | ((w8) << (64 - (19)))) ^ (((w8) >> (61)) | ((w8) << (64 - (61)))) ^ ((w8) >> (6))) + w3 + ((((w11) >> (1)) | ((w11) << (64 - (1)))) ^ (((w11) >> (8)) | ((w11) << (64 - (8)))) ^ ((w11) >> (7))) + w10; w11 = ((((w9) >> (19)) | ((w9) << (64 - (19)))) ^ (((w9) >> (61)) | ((w9) << (64 - (61)))) ^ ((w9) >> (6))) + w4 + ((((w12) >> (1)) | ((w12) << (64 - (1)))) ^ (((w12) >> (8)) | ((w12) << (64 - (8)))) ^ ((w12) >> (7))) + w11; w12 = ((((w10) >> (19)) | ((w10) << (64 - (19)))) ^ (((w10) >> (61)) | ((w10) << (64 - (61)))) ^ ((w10) >> (6))) + w5 + ((((w13) >> (1)) | ((w13) << (64 - (1)))) ^ (((w13) >> (8)) | ((w13) << (64 - (8)))) ^ ((w13) >> (7))) + w12; w13 = ((((w11) >> (19)) | ((w11) << (64 - (19)))) ^ (((w11) >> (61)) | ((w11) << (64 - (61)))) ^ ((w11) >> (6))) + w6 + ((((w14) >> (1)) | ((w14) << (64 - (1)))) ^ (((w14) >> (8)) | ((w14) << (64 - (8)))) ^ ((w14) >> (7))) + w13; w14 = ((((w12) >> (19)) | ((w12) << (64 - (19)))) ^ (((w12) >> (61)) | ((w12) << (64 - (61)))) ^ ((w12) >> (6))) + w7 + ((((w15) >> (1)) | ((w15) << (64 - (1)))) ^ (((w15) >> (8)) | ((w15) << (64 - (8)))) ^ ((w15) >> (7))) + w14; w15 = ((((w13) >> (19)) | ((w13) << (64 - (19)))) ^ (((w13) >> (61)) | ((w13) << (64 - (61)))) ^ ((w13) >> (6))) + w8 + ((((w0) >> (1)) | ((w0) << (64 - (1)))) ^ (((w0) >> (8)) | ((w0) << (64 - (8)))) ^ ((w0) >> (7))) + w15;
 
 				T1 = h + ((((e) >> (14)) | ((e) << (64 - (14)))) ^ (((e) >> (18)) | ((e) << (64 - (18)))) ^ (((e) >> (41)) | ((e) << (64 - (41))))) + ((e & f) ^ (~e & g)) + 0x19a4c116b8d2d0c8 + w0; T2 = ((((a) >> (28)) | ((a) << (64 - (28)))) ^ (((a) >> (34)) | ((a) << (64 - (34)))) ^ (((a) >> (39)) | ((a) << (64 - (39))))) + ((a & b) ^ (a & c) ^ (b & c)); h = g; g = f; f = e; e = d + T1; d = c; c = b; b = a; a = T1 + T2;
@@ -183,7 +172,18 @@
 				inp += 128;
 				inlen -= 128;
 			}
-
+		}
+		public unsafe static void crypto_hashblocks_state_unpack(UInt64* state, Byte* statebytes) {
+			state[0] = load_bigendian(statebytes + 0);
+			state[1] = load_bigendian(statebytes + 8);
+			state[2] = load_bigendian(statebytes + 16);
+			state[3] = load_bigendian(statebytes + 24);
+			state[4] = load_bigendian(statebytes + 32);
+			state[5] = load_bigendian(statebytes + 40);
+			state[6] = load_bigendian(statebytes + 48);
+			state[7] = load_bigendian(statebytes + 56);
+		}
+		public unsafe static void crypto_hashblocks_state_pack(Byte* statebytes, UInt64* state) {
 			store_bigendian(statebytes + 0, state[0]);
 			store_bigendian(statebytes + 8, state[1]);
 			store_bigendian(statebytes + 16, state[2]);
@@ -193,5 +193,11 @@
 			store_bigendian(statebytes + 48, state[6]);
 			store_bigendian(statebytes + 56, state[7]);
 		}
+		public unsafe static void crypto_hashblocks(Byte* statebytes, Byte* inp, UInt64 inlen) {
+			UInt64* state = stackalloc UInt64[8];
+			crypto_hashblocks_state_unpack(state, statebytes);
+			crypto_hashblocks(state, inp, inlen);
+			crypto_hashblocks_state_pack(statebytes, state);
+		}
 	}
 }
\ No newline at end of file