Last active
December 15, 2018 10:31
-
-
Save mjs3339/603c3ae8b666b716c182cf6d97cbca06 to your computer and use it in GitHub Desktop.
C# Murmur3 128bit Non Cryptographic Hashing Algorithm
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
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