private void PushByte(uint value) { var data = pending; unsafe { ((byte *)&data)[pendingLength] = (byte)value; } if (pendingLength == 15) { HashBlock(ref hash, ref data); pending = default(Value128); pendingLength = 0; } else { pending = data; pendingLength++; } }
/// <summary>NOTE: Rewrites hash and clobbers data</summary> private static void HashBlock(ref Value128 hash, ref Value128 data) { data.v1 *= c1; data.v1 = ROTL32(data.v1, 15); data.v1 *= c2; hash.v1 ^= data.v1; hash.v1 = ROTL32(hash.v1, 19); hash.v1 += hash.v2; hash.v1 = hash.v1 * 5 + 0x561ccd1b; data.v2 *= c2; data.v2 = ROTL32(data.v2, 16); data.v2 *= c3; hash.v2 ^= data.v2; hash.v2 = ROTL32(hash.v2, 17); hash.v2 += hash.v3; hash.v2 = hash.v2 * 5 + 0x0bcaa747; data.v3 *= c3; data.v3 = ROTL32(data.v3, 17); data.v3 *= c4; hash.v3 ^= data.v3; hash.v3 = ROTL32(hash.v3, 15); hash.v3 += hash.v4; hash.v3 = hash.v3 * 5 + 0x96cd1c35; data.v4 *= c4; data.v4 = ROTL32(data.v4, 18); data.v4 *= c1; hash.v4 ^= data.v4; hash.v4 = ROTL32(hash.v4, 13); hash.v4 += hash.v1; hash.v4 = hash.v4 * 5 + 0x32ac3b17; }
/// <summary>NOTE: Rewrites hash and clobbers tail</summary> private static void HashTailAndFinalize(ref Value128 hash, ref Value128 tail, uint length) { // NOTE: We're truncating length to 32-bits, because it will almost always be small enough // // Tail: var tailLength = length & 15; switch ((tailLength + 3) >> 2) // Number of dwords of data in the tail, rounded up { case 4: tail.v4 *= c4; tail.v4 = ROTL32(tail.v4, 18); tail.v4 *= c1; hash.v4 ^= tail.v4; goto case 3; case 3: tail.v3 *= c3; tail.v3 = ROTL32(tail.v3, 17); tail.v3 *= c4; hash.v3 ^= tail.v3; goto case 2; case 2: tail.v2 *= c2; tail.v2 = ROTL32(tail.v2, 16); tail.v2 *= c3; hash.v2 ^= tail.v2; goto case 1; case 1: tail.v1 *= c1; tail.v1 = ROTL32(tail.v1, 15); tail.v1 *= c2; hash.v1 ^= tail.v1; break; } // // Finalization: hash.v1 ^= length; hash.v2 ^= length; hash.v3 ^= length; hash.v4 ^= length; hash.v1 += hash.v2; hash.v1 += hash.v3; hash.v1 += hash.v4; hash.v2 += hash.v1; hash.v3 += hash.v1; hash.v4 += hash.v1; hash.v1 = fmix32(hash.v1); hash.v2 = fmix32(hash.v2); hash.v3 = fmix32(hash.v3); hash.v4 = fmix32(hash.v4); hash.v1 += hash.v2; hash.v1 += hash.v3; hash.v1 += hash.v4; hash.v2 += hash.v1; hash.v3 += hash.v1; hash.v4 += hash.v1; }