Skip to content

Instantly share code, notes, and snippets.

@mjs3339
Last active December 15, 2018 10:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjs3339/603c3ae8b666b716c182cf6d97cbca06 to your computer and use it in GitHub Desktop.
Save mjs3339/603c3ae8b666b716c182cf6d97cbca06 to your computer and use it in GitHub Desktop.
C# Murmur3 128bit Non Cryptographic Hashing Algorithm
public class Murmur3 : HashAlgorithm
{
private ulong _h1;
private ulong _h2;
private ulong _length;
public Result Res;
public Result Seed;
public Murmur3() : this(new Result {H1 = 0, H2 = 0})
{
}
public Murmur3(Result seed)
{
Seed = seed;
Initialize();
}
public override int HashSize => 128;
public new static Murmur3 Create()
{
return new Murmur3();
}
protected override void HashCore(byte[] array, int ibStart, int cbSize)
{
_length += (uint) cbSize;
unsafe
{
fixed(byte* pbyte = array)
{
var ppbyte = pbyte + ibStart;
ulong k1;
ulong k2;
while(cbSize >= 16)
{
k1 = *(ulong*) ppbyte;
ppbyte += 8;
k2 = *(ulong*) ppbyte;
ppbyte += 8;
cbSize -= 16;
var O1 = k1 * 0x87c37b91114253d5ul;
_h1 = _h1 ^ (((O1 << 31) | (O1 >> 33)) * 0x4cf5ad432745937ful);
_h1 = (((_h1 << 27) | (_h1 >> 37)) + _h2) * 5 + 0x52dce729;
var O2 = k2 * 0x4cf5ad432745937ful;
_h2 = _h2 ^ (((O2 << 33) | (O2 >> 31)) * 0x87c37b91114253d5ul);
_h2 = (((_h2 << 31) | (_h2 >> 33)) + _h1) * 5 + 0x38495ab5;
}
k1 = 0;
k2 = 0;
switch(cbSize & 15)
{
case 15:
k2 ^= (ulong) *(ppbyte + 14) << 48;
goto case 14;
case 14:
k2 ^= (ulong) *(ppbyte + 13) << 40;
goto case 13;
case 13:
k2 ^= (ulong) *(ppbyte + 12) << 32;
goto case 12;
case 12:
k2 ^= (ulong) *(ppbyte + 11) << 24;
goto case 11;
case 11:
k2 ^= (ulong) *(ppbyte + 10) << 16;
goto case 10;
case 10:
k2 ^= (ulong) *(ppbyte + 9) << 8;
goto case 9;
case 9:
k2 ^= *(ppbyte + 8);
var O1 = k2 * 0x4cf5ad432745937ful;
_h2 ^= ((O1 << 33) | (O1 >> 31)) * 0x87c37b91114253d5ul;
goto case 8;
case 8:
k1 ^= (ulong) *(ppbyte + 7) << 56;
goto case 7;
case 7:
k1 ^= (ulong) *(ppbyte + 6) << 48;
goto case 6;
case 6:
k1 ^= (ulong) *(ppbyte + 5) << 40;
goto case 5;
case 5:
k1 ^= (ulong) *(ppbyte + 4) << 32;
goto case 4;
case 4:
k1 ^= (ulong) *(ppbyte + 3) << 24;
goto case 3;
case 3:
k1 ^= (ulong) *(ppbyte + 2) << 16;
goto case 2;
case 2:
k1 ^= (ulong) *(ppbyte + 1) << 8;
goto case 1;
case 1:
k1 ^= *ppbyte;
var O2 = k1 * 0x87c37b91114253d5ul;
_h1 ^= ((O2 << 31) | (O2 >> 33)) * 0x4cf5ad432745937ful;
break;
}
}
}
}
protected override byte[] HashFinal()
{
_h1 ^= _length;
_h2 ^= _length;
_h1 += _h2;
_h2 += _h1;
var V1 = _h1;
V1 = (V1 ^ (V1 >> 33)) * 0xFF51AFD7ED558CCDul;
V1 = (V1 ^ (V1 >> 33)) * 0xc4ceb9fe1a85ec53ul;
V1 ^= V1 >> 33;
_h1 = V1;
var V2 = _h2;
V2 = (V2 ^ (V2 >> 33)) * 0xFF51AFD7ED558CCDul;
V2 = (V2 ^ (V2 >> 33)) * 0xc4ceb9fe1a85ec53ul;
V2 ^= V2 >> 33;
_h2 = V2;
_h1 += _h2;
_h2 += _h1;
Res.H1 = _h1;
Res.H2 = _h2;
return Result.ResultToByteArray(Res);
}
public override void Initialize()
{
_h1 = Seed.H1;
_h2 = Seed.H2;
_length = 0;
}
public Result Hash128(byte[] array, Result feedback)
{
var ll = (uint) array.Length;
var cbSize = array.Length;
var h1 = feedback.H1;
var h2 = feedback.H2;
var h128 = new Result();
unsafe
{
fixed(byte* pbyte = array)
{
var ppbyte = pbyte;
ulong k1;
ulong k2;
while(cbSize >= 16)
{
k1 = *(ulong*) ppbyte;
ppbyte += 8;
k2 = *(ulong*) ppbyte;
ppbyte += 8;
cbSize -= 16;
var O1 = k1 * 0x87c37b91114253d5ul;
h1 = h1 ^ (((O1 << 31) | (O1 >> 33)) * 0x4cf5ad432745937ful);
h1 = (((h1 << 27) | (h1 >> 37)) + h2) * 5 + 0x52dce729;
var O2 = k2 * 0x4cf5ad432745937ful;
h2 = h2 ^ (((O2 << 33) | (O2 >> 31)) * 0x87c37b91114253d5ul);
h2 = (((h2 << 31) | (h2 >> 33)) + h1) * 5 + 0x38495ab5;
}
k1 = 0;
k2 = 0;
switch(cbSize & 15)
{
case 15:
k2 ^= (ulong) *(ppbyte + 14) << 48;
goto case 14;
case 14:
k2 ^= (ulong) *(ppbyte + 13) << 40;
goto case 13;
case 13:
k2 ^= (ulong) *(ppbyte + 12) << 32;
goto case 12;
case 12:
k2 ^= (ulong) *(ppbyte + 11) << 24;
goto case 11;
case 11:
k2 ^= (ulong) *(ppbyte + 10) << 16;
goto case 10;
case 10:
k2 ^= (ulong) *(ppbyte + 9) << 8;
goto case 9;
case 9:
k2 ^= *(ppbyte + 8);
var O1 = k2 * 0x4cf5ad432745937ful;
h2 ^= ((O1 << 33) | (O1 >> 31)) * 0x87c37b91114253d5ul;
goto case 8;
case 8:
k1 ^= (ulong) *(ppbyte + 7) << 56;
goto case 7;
case 7:
k1 ^= (ulong) *(ppbyte + 6) << 48;
goto case 6;
case 6:
k1 ^= (ulong) *(ppbyte + 5) << 40;
goto case 5;
case 5:
k1 ^= (ulong) *(ppbyte + 4) << 32;
goto case 4;
case 4:
k1 ^= (ulong) *(ppbyte + 3) << 24;
goto case 3;
case 3:
k1 ^= (ulong) *(ppbyte + 2) << 16;
goto case 2;
case 2:
k1 ^= (ulong) *(ppbyte + 1) << 8;
goto case 1;
case 1:
k1 ^= *ppbyte;
var O2 = k1 * 0x87c37b91114253d5ul;
h1 ^= ((O2 << 31) | (O2 >> 33)) * 0x4cf5ad432745937ful;
break;
}
}
}
h1 ^= ll;
h2 ^= ll;
h1 += h2;
h2 += h1;
var V1 = h1;
V1 = (V1 ^ (V1 >> 33)) * 0xFF51AFD7ED558CCDul;
V1 = (V1 ^ (V1 >> 33)) * 0xc4ceb9fe1a85ec53ul;
V1 ^= V1 >> 33;
h1 = V1;
var V2 = h2;
V2 = (V2 ^ (V2 >> 33)) * 0xFF51AFD7ED558CCDul;
V2 = (V2 ^ (V2 >> 33)) * 0xc4ceb9fe1a85ec53ul;
V2 ^= V2 >> 33;
h2 = V2;
h1 += h2;
h2 += h1;
h128.H1 = h1;
h128.H2 = h2;
return h128;
}
public struct Result
{
public ulong H1;
public ulong H2;
public static unsafe byte[] ResultToByteArray(Result result)
{
var fRes = new byte[16];
fixed(byte* pbyte = &fRes[0])
{
*(ulong*) pbyte = result.H1;
}
fixed(byte* pbyte = &fRes[8])
{
*(ulong*) pbyte = result.H2;
}
return fRes;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment