Skip to content

Instantly share code, notes, and snippets.

@SQLkiwi
Last active May 30, 2019 15:09
Show Gist options
  • Save SQLkiwi/7a5bb26b0bee56f6d28a1d26669ce8f2 to your computer and use it in GitHub Desktop.
Save SQLkiwi/7a5bb26b0bee56f6d28a1d26669ce8f2 to your computer and use it in GitHub Desktop.
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