diff NaCl/crypto_hash/sha512.cs @ 72:b7d981ccd434

NaCl: improved sha512 implementation
author Ivo Smits <Ivo@UCIS.nl>
date Sat, 02 Nov 2013 15:59:51 +0100
parents 7e9d1cfcc562
children
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);
+				}
+			}
 		}
 	}
 }