Last active
May 30, 2019 15:09
-
-
Save SQLkiwi/7a5bb26b0bee56f6d28a1d26669ce8f2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.SqlServer.Server; | |
using System; | |
public partial class UserDefinedFunctions | |
{ | |
private const ulong SpookyConst = 0xDEADBEEFDEADBEEF; | |
private const int BlockSize = 96; | |
private const int BufferSize = BlockSize * 2; | |
[return: SqlFacet(MaxSize = 16, IsFixedLength = true, IsNullable = false)] | |
[SqlFunction(DataAccess = DataAccessKind.None, SystemDataAccess = SystemDataAccessKind.None, IsDeterministic = true, IsPrecise = true) | |
] | |
public static byte[] SpookyHash(byte[] Input) | |
{ | |
int length = Input.Length; | |
if (length < BufferSize) | |
{ | |
return ShortHash(Input, length); | |
} | |
ulong[] buf = new ulong[BlockSize]; | |
ulong h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11; | |
h0 = h3 = h6 = h9 = 0; | |
h1 = h4 = h7 = h10 = 0; | |
h2 = h5 = h8 = h11 = SpookyConst; | |
int p64 = 0; | |
int end = (length / BlockSize) * BlockSize; | |
int remainder = length - end; | |
while (p64 < end) | |
{ | |
h0 += BitConverter.ToUInt64(Input, p64); h2 ^= h10; h11 ^= h0; h0 = (h0 << 11) | (h0 >> -11); h11 += h1; | |
h1 += BitConverter.ToUInt64(Input, p64 + 8); h3 ^= h11; h0 ^= h1; h1 = (h1 << 32) | (h1 >> 32); h0 += h2; | |
h2 += BitConverter.ToUInt64(Input, p64 + 16); h4 ^= h0; h1 ^= h2; h2 = (h2 << 43) | (h2 >> -43); h1 += h3; | |
h3 += BitConverter.ToUInt64(Input, p64 + 24); h5 ^= h1; h2 ^= h3; h3 = (h3 << 31) | (h3 >> -31); h2 += h4; | |
h4 += BitConverter.ToUInt64(Input, p64 + 32); h6 ^= h2; h3 ^= h4; h4 = (h4 << 17) | (h4 >> -17); h3 += h5; | |
h5 += BitConverter.ToUInt64(Input, p64 + 40); h7 ^= h3; h4 ^= h5; h5 = (h5 << 28) | (h5 >> -28); h4 += h6; | |
h6 += BitConverter.ToUInt64(Input, p64 + 48); h8 ^= h4; h5 ^= h6; h6 = (h6 << 39) | (h6 >> -39); h5 += h7; | |
h7 += BitConverter.ToUInt64(Input, p64 + 56); h9 ^= h5; h6 ^= h7; h7 = (h7 << 57) | (h7 >> -57); h6 += h8; | |
h8 += BitConverter.ToUInt64(Input, p64 + 64); h10 ^= h6; h7 ^= h8; h8 = (h8 << 55) | (h8 >> -55); h7 += h9; | |
h9 += BitConverter.ToUInt64(Input, p64 + 72); h11 ^= h7; h8 ^= h9; h9 = (h9 << 54) | (h9 >> -54); h8 += h10; | |
h10 += BitConverter.ToUInt64(Input, p64 + 80); h0 ^= h8; h9 ^= h10; h10 = (h10 << 22) | (h10 >> -22); h9 += h11; | |
h11 += BitConverter.ToUInt64(Input, p64 + 88); h1 ^= h9; h10 ^= h11; h11 = (h11 << 46) | (h11 >> -46); h10 += h0; | |
p64 += BlockSize; | |
} | |
if (remainder != 0) | |
{ | |
Buffer.BlockCopy(Input, end, buf, 0, remainder); | |
} | |
buf[BlockSize - 1] = (byte)remainder; | |
h0 += buf[0]; h1 += buf[1]; h2 += buf[2]; h3 += buf[3]; | |
h4 += buf[4]; h5 += buf[5]; h6 += buf[6]; h7 += buf[7]; | |
h8 += buf[8]; h9 += buf[9]; h10 += buf[10]; h11 += buf[11]; | |
h11 += h1; h2 ^= h11; h1 = (h1 << 44) | (h1 >> -44); | |
h0 += h2; h3 ^= h0; h2 = (h2 << 15) | (h2 >> -15); | |
h1 += h3; h4 ^= h1; h3 = (h3 << 34) | (h3 >> -34); | |
h2 += h4; h5 ^= h2; h4 = (h4 << 21) | (h4 >> -21); | |
h3 += h5; h6 ^= h3; h5 = (h5 << 38) | (h5 >> -38); | |
h4 += h6; h7 ^= h4; h6 = (h6 << 33) | (h6 >> -33); | |
h5 += h7; h8 ^= h5; h7 = (h7 << 10) | (h7 >> -10); | |
h6 += h8; h9 ^= h6; h8 = (h8 << 13) | (h8 >> -13); | |
h7 += h9; h10 ^= h7; h9 = (h9 << 38) | (h9 >> -38); | |
h8 += h10; h11 ^= h8; h10 = (h10 << 53) | (h10 >> -53); | |
h9 += h11; h0 ^= h9; h11 = (h11 << 42) | (h11 >> -42); | |
h10 += h0; h1 ^= h10; h0 = (h0 << 54) | (h0 >> -54); | |
h11 += h1; h2 ^= h11; h1 = (h1 << 44) | (h1 >> -44); | |
h0 += h2; h3 ^= h0; h2 = (h2 << 15) | (h2 >> -15); | |
h1 += h3; h4 ^= h1; h3 = (h3 << 34) | (h3 >> -34); | |
h2 += h4; h5 ^= h2; h4 = (h4 << 21) | (h4 >> -21); | |
h3 += h5; h6 ^= h3; h5 = (h5 << 38) | (h5 >> -38); | |
h4 += h6; h7 ^= h4; h6 = (h6 << 33) | (h6 >> -33); | |
h5 += h7; h8 ^= h5; h7 = (h7 << 10) | (h7 >> -10); | |
h6 += h8; h9 ^= h6; h8 = (h8 << 13) | (h8 >> -13); | |
h7 += h9; h10 ^= h7; h9 = (h9 << 38) | (h9 >> -38); | |
h8 += h10; h11 ^= h8; h10 = (h10 << 53) | (h10 >> -53); | |
h9 += h11; h0 ^= h9; h11 = (h11 << 42) | (h11 >> -42); | |
h10 += h0; h1 ^= h10; h0 = (h0 << 54) | (h0 >> -54); | |
h11 += h1; h2 ^= h11; h1 = (h1 << 44) | (h1 >> -44); | |
h0 += h2; h3 ^= h0; h2 = (h2 << 15) | (h2 >> -15); | |
h1 += h3; h4 ^= h1; h3 = (h3 << 34) | (h3 >> -34); | |
h2 += h4; h5 ^= h2; h4 = (h4 << 21) | (h4 >> -21); | |
h3 += h5; h6 ^= h3; h5 = (h5 << 38) | (h5 >> -38); | |
h4 += h6; h7 ^= h4; h6 = (h6 << 33) | (h6 >> -33); | |
h5 += h7; h8 ^= h5; h7 = (h7 << 10) | (h7 >> -10); | |
h6 += h8; h9 ^= h6; h8 = (h8 << 13) | (h8 >> -13); | |
h7 += h9; h10 ^= h7; h9 = (h9 << 38) | (h9 >> -38); | |
h8 += h10; h11 ^= h8; h10 = (h10 << 53) | (h10 >> -53); | |
h9 += h11; h0 ^= h9; | |
h10 += h0; h1 ^= h10; h0 = (h0 << 54) | (h0 >> -54); | |
byte[] hash = new byte[16]; | |
BitConverter.GetBytes(h0).CopyTo(hash, 0); | |
BitConverter.GetBytes(h1).CopyTo(hash, 8); | |
return hash; | |
} | |
private static byte[] ShortHash(byte[] input, int length) | |
{ | |
ulong a = 0; | |
ulong b = 0; | |
ulong c = SpookyConst; | |
ulong d = SpookyConst; | |
int p64 = 0; | |
int end = (length / 32) * 32; | |
int remainder = length & 31; | |
if (length > 15) | |
{ | |
for (; p64 < end; p64 += 32) | |
{ | |
c += BitConverter.ToUInt64(input, p64); | |
d += BitConverter.ToUInt64(input, p64 + 8); | |
c = (c << 50) | (c >> -50); c += d; a ^= c; | |
d = (d << 52) | (d >> -52); d += a; b ^= d; | |
a = (a << 30) | (a >> -30); a += b; c ^= a; | |
b = (b << 41) | (b >> -41); b += c; d ^= b; | |
c = (c << 54) | (c >> -54); c += d; a ^= c; | |
d = (d << 48) | (d >> -48); d += a; b ^= d; | |
a = (a << 38) | (a >> -38); a += b; c ^= a; | |
b = (b << 37) | (b >> -37); b += c; d ^= b; | |
c = (c << 62) | (c >> -62); c += d; a ^= c; | |
d = (d << 34) | (d >> -34); d += a; b ^= d; | |
a = (a << 5) | (a >> -5); a += b; c ^= a; | |
b = (b << 36) | (b >> -36); b += c; d ^= b; | |
a += BitConverter.ToUInt64(input, p64 + 16); | |
b += BitConverter.ToUInt64(input, p64 + 24); | |
} | |
if (remainder >= 16) | |
{ | |
c += BitConverter.ToUInt64(input, p64); | |
d += BitConverter.ToUInt64(input, p64 + 8); | |
c = (c << 50) | (c >> -50); c += d; a ^= c; | |
d = (d << 52) | (d >> -52); d += a; b ^= d; | |
a = (a << 30) | (a >> -30); a += b; c ^= a; | |
b = (b << 41) | (b >> -41); b += c; d ^= b; | |
c = (c << 54) | (c >> -54); c += d; a ^= c; | |
d = (d << 48) | (d >> -48); d += a; b ^= d; | |
a = (a << 38) | (a >> -38); a += b; c ^= a; | |
b = (b << 37) | (b >> -37); b += c; d ^= b; | |
c = (c << 62) | (c >> -62); c += d; a ^= c; | |
d = (d << 34) | (d >> -34); d += a; b ^= d; | |
a = (a << 5) | (a >> -5); a += b; c ^= a; | |
b = (b << 36) | (b >> -36); b += c; d ^= b; | |
p64 += 16; | |
remainder -= 16; | |
} | |
} | |
d += ((ulong)length) << 56; | |
switch (remainder) | |
{ | |
case 15: | |
d += (ulong)input[p64 + 14] << 48; | |
goto case 14; | |
case 14: | |
d += (ulong)input[p64 + 13] << 40; | |
goto case 13; | |
case 13: | |
d += (ulong)input[p64 + 12] << 32; | |
goto case 12; | |
case 12: | |
d += BitConverter.ToUInt32(input, p64 + 8); | |
c += BitConverter.ToUInt64(input, p64); | |
break; | |
case 11: | |
d += (ulong)input[p64 + 10] << 16; | |
goto case 10; | |
case 10: | |
d += (ulong)input[p64 + 9] << 8; | |
goto case 9; | |
case 9: | |
d += (ulong)input[p64 + 8]; | |
goto case 8; | |
case 8: | |
c += BitConverter.ToUInt64(input, p64); | |
break; | |
case 7: | |
c += (ulong)input[p64 + 6] << 48; | |
goto case 6; | |
case 6: | |
c += (ulong)input[p64 + 5] << 40; | |
goto case 5; | |
case 5: | |
c += (ulong)input[p64 + 4] << 32; | |
goto case 4; | |
case 4: | |
c += BitConverter.ToUInt32(input, p64); | |
break; | |
case 3: | |
c += (ulong)input[p64 + 2] << 16; | |
goto case 2; | |
case 2: | |
c += (ulong)input[p64 + 1] << 8; | |
goto case 1; | |
case 1: | |
c += (ulong)input[p64 + 1]; | |
break; | |
case 0: | |
c += SpookyConst; | |
d += SpookyConst; | |
break; | |
} | |
d ^= c; c = (c << 15) | (c >> -15); d += c; | |
a ^= d; d = (d << 52) | (d >> -52); a += d; | |
b ^= a; a = (a << 26) | (a >> -26); b += a; | |
c ^= b; b = (b << 51) | (b >> -51); c += b; | |
d ^= c; c = (c << 28) | (c >> -28); d += c; | |
a ^= d; d = (d << 9) | (d >> -9); a += d; | |
b ^= a; a = (a << 47) | (a >> -47); b += a; | |
c ^= b; b = (b << 54) | (b >> -54); c += b; | |
d ^= c; c = (c << 32) | (c >> -32); d += c; | |
a ^= d; d = (d << 25) | (d >> -25); a += d; | |
b ^= a; a = (a << 63) | (a >> -63); b += a; | |
byte[] hash = new byte[16]; | |
BitConverter.GetBytes(a).CopyTo(hash, 0); | |
BitConverter.GetBytes(b).CopyTo(hash, 8); | |
return hash; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment