public static SHA1Result SHA1_Opt(byte[] message) { SHA1Result result = new SHA1Result { // Initialize buffers i0 = 0x67452301, i1 = 0xEFCDAB89, i2 = 0x98BADCFE, i3 = 0x10325476, i4 = 0xC3D2E1F0 }; // Pad message long len = message.Length * 8; int ml = message.Length + 1, max = ml + ((960 - (ml * 8 % 512)) % 512) / 8 + 8; // Replaces the allocation of a lot of bytes byte GetMsg(int idx) { if (idx < message.Length) { return(message[idx]); } else if (idx == message.Length) { return(0x80); } else if (max - idx <= 8) { return((byte)((len >> ((max - 1 - idx) * 8)) & 255)); } return(0); } int chunks = max / 64; // Replaces the recurring allocation of 80 uints uint ComputeIndex(int block, int idx) { if (idx < 16) { return((uint)((GetMsg(block * 64 + idx * 4) << 24) | (GetMsg(block * 64 + idx * 4 + 1) << 16) | (GetMsg(block * 64 + idx * 4 + 2) << 8) | (GetMsg(block * 64 + idx * 4 + 3) << 0))); } else { return(Rot(ComputeIndex(block, idx - 3) ^ ComputeIndex(block, idx - 8) ^ ComputeIndex(block, idx - 14) ^ ComputeIndex(block, idx - 16), 1)); } } // Perform hashing for each 512-bit block for (int i = 0; i < chunks; ++i) { // Initialize chunk-hash uint a = result.i0, b = result.i1, c = result.i2, d = result.i3, e = result.i4; // Do hash rounds for (int t = 0; t < 80; ++t) { uint tmp = Rot(a, 5) + func(t, b, c, d) + e + K(t) + ComputeIndex(i, t); e = d; d = c; c = Rot(b, 30); b = a; a = tmp; } result.i0 += a; result.i1 += b; result.i2 += c; result.i3 += d; result.i4 += e; } result.i0 = BinaryHelpers.SwapEndian(result.i0); result.i1 = BinaryHelpers.SwapEndian(result.i1); result.i2 = BinaryHelpers.SwapEndian(result.i2); result.i3 = BinaryHelpers.SwapEndian(result.i3); result.i4 = BinaryHelpers.SwapEndian(result.i4); return(result); }