MurMur3 hash update

master
Ogoun 4 weeks ago
parent d076d22f47
commit ef758a4676

@ -1,10 +1,8 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Linq;
using System.Reflection;
using ZeroLevel.Logging; using ZeroLevel.Logging;
using ZeroLevel.Services.Invokation; using ZeroLevel.Services.HashFunctions;
using ZeroLevel.Services.Serialization; using ZeroLevel.Services.Mathemathics;
namespace TestApp namespace TestApp
{ {
@ -54,10 +52,34 @@ namespace TestApp
internal static class Program internal static class Program
{ {
private static void Main(string[] args) private static void Main(string[] args)
{ {
var date = DateTime.Now;
var bytes = new byte[1531];
new Random().NextBytes(bytes);
var hash = Murmur3.ComputeULongHash(bytes);
Console.WriteLine($"{hash}");
new Random().NextBytes(bytes);
hash = Murmur3.ComputeULongHash(bytes);
Console.WriteLine($"{hash}");
bytes[0] = 10;
hash = Murmur3.ComputeULongHash(bytes);
Console.WriteLine($"{hash}");
new Random().NextBytes(bytes);
hash = Murmur3.ComputeULongHash(bytes);
Console.WriteLine($"{hash}");
Console.ReadKey();
/*
foreach (var c in Combinations.GenerateUniqueSets(new int[] { 1, 2, 3, 4, 5, 6 }, 3))
{
Console.WriteLine(string.Join('\t', c));
}
*/
} }
} }
} }

@ -0,0 +1,27 @@
using System;
using System.Linq;
namespace TestApp
{
internal class t
{
public int Calculate()
{
var c = int.Parse(Console.ReadLine());
var data = Console.ReadLine().Split(' ').Select(s => int.Parse(s)).ToArray();
int result = 0;
for (int i = 0; i < c - 1; i++)
{
for (int j = i + 1; j < c; j++)
{
var d1 = Math.Min(data[i], data[j]);
var d2 = Math.Max(data[i], data[j]);
if (d2 > 100000) continue;
if ((d1 != 0 && d2 != 0) && ((float)d1 / d2) >= .9f)
result++;
}
}
return result;
}
}
}

@ -0,0 +1,110 @@
using System;
using Xunit;
namespace ZeroLevel.UnitTests
{
public class BytesEncodingTests
{
public static void DeHashData(byte[] data, byte initialMask)
{
int i;
for (i = data.Length - 1; i > 9; i -= 8)
{
data[i - 0] ^= data[i - 1];
data[i - 1] ^= data[i - 2];
data[i - 2] ^= data[i - 3];
data[i - 3] ^= data[i - 4];
data[i - 4] ^= data[i - 5];
data[i - 5] ^= data[i - 6];
data[i - 6] ^= data[i - 7];
data[i - 7] ^= data[i - 8];
}
for (; i >= 1; i--)
{
data[i] ^= data[i - 1];
}
data[0] ^= initialMask;
}
public static void HashData(byte[] data, byte initialmask)
{
if (data == null || data.Length == 0) return;
int i = 1;
data[0] ^= initialmask;
for (; i < (data.Length - 8); i += 8)
{
data[i + 0] ^= data[i - 1];
data[i + 1] ^= data[i + 0];
data[i + 2] ^= data[i + 1];
data[i + 3] ^= data[i + 2];
data[i + 4] ^= data[i + 3];
data[i + 5] ^= data[i + 4];
data[i + 6] ^= data[i + 5];
data[i + 7] ^= data[i + 6];
}
for (; i < data.Length; i++)
{
data[i] ^= data[i - 1];
}
}
[Fact]
public void SpecialTest()
{
var arr = new byte[] { 244, 135 }; //, 125, 160, 109, 144, 187, 109, 88, 78, 175, 115, 83, 174, 165, 246, 253, 112 };
var copy = new byte[arr.Length];
Array.Copy(arr, copy, arr.Length);
byte initial = (byte)(arr.Length % 255);
HashData(arr, initial);
Assert.False(ArrayExtensions.UnsafeEquals(arr, copy));
DeHashData(arr, initial);
Assert.True(ArrayExtensions.UnsafeEquals(arr, copy));
}
[Fact]
public void BytesEncodingTest()
{
// Arrange
var r = new Random((int)Environment.TickCount);
for (int i = 1; i < 20; i ++)
{
// Act
var arr = new byte[i];
var copy = new byte[i];
r.NextBytes(arr);
Array.Copy(arr, copy, arr.Length);
// Assert
var initial = arr[0];
HashData(arr, initial);
Assert.False(ArrayExtensions.UnsafeEquals(arr, copy));
DeHashData(arr, initial);
Assert.True(ArrayExtensions.UnsafeEquals(arr, copy));
}
for (int i = 1; i < 200000; i += 17)
{
// Act
var arr = new byte[i];
var copy = new byte[i];
r.NextBytes(arr);
Array.Copy(arr, copy, arr.Length);
// Assert
var initial = arr[0];
HashData(arr, initial);
Assert.False(ArrayExtensions.UnsafeEquals(arr, copy));
DeHashData(arr, initial);
Assert.True(ArrayExtensions.UnsafeEquals(arr, copy));
}
}
}
}

@ -40,8 +40,19 @@ namespace ZeroLevel.Services.Encryption
public void DeHashData(byte[] data) public void DeHashData(byte[] data)
{ {
if (data.Length == 0) return; int i;
for (var i = data.Length - 1; i > 0; i--) for (i = data.Length - 1; i > 9; i -= 8)
{
data[i - 0] ^= data[i - 1];
data[i - 1] ^= data[i - 2];
data[i - 2] ^= data[i - 3];
data[i - 3] ^= data[i - 4];
data[i - 4] ^= data[i - 5];
data[i - 5] ^= data[i - 6];
data[i - 6] ^= data[i - 7];
data[i - 7] ^= data[i - 8];
}
for (; i >= 1; i--)
{ {
data[i] ^= data[i - 1]; data[i] ^= data[i - 1];
} }

@ -1,5 +1,6 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace ZeroLevel.Services.HashFunctions namespace ZeroLevel.Services.HashFunctions
{ {
@ -149,9 +150,150 @@ namespace ZeroLevel.Services.HashFunctions
return hash; return hash;
} }
public static ulong ComputeULongHash(byte[] bb, ulong seed = 0)
{
var h1 = seed;
ulong h2 = 0;
var length = 0UL;
int pos = 0;
ulong remaining = (ulong)bb.Length;
// read 128 bits, 16 bytes, 2 longs in eacy cycle
while (remaining >= READ_SIZE)
{
ulong k1 = bb.GetUInt64(pos);
pos += 8;
ulong k2 = bb.GetUInt64(pos);
pos += 8;
length += READ_SIZE;
remaining -= READ_SIZE;
h1 ^= MixKey1(k1);
h1 = h1.RotateLeft(27);
h1 += h2;
h1 = h1 * 5 + 0x52dce729;
h2 ^= MixKey2(k2);
h2 = h2.RotateLeft(31);
h2 += h1;
h2 = h2 * 5 + 0x38495ab5;
}
// if the input MOD 16 != 0
if (remaining > 0)
{
ulong k1 = 0;
ulong k2 = 0;
length += remaining;
// little endian (x86) processing
switch (remaining)
{
case 15:
k2 ^= (ulong)bb[pos + 14] << 48; // fall through
goto case 14;
case 14:
k2 ^= (ulong)bb[pos + 13] << 40; // fall through
goto case 13;
case 13:
k2 ^= (ulong)bb[pos + 12] << 32; // fall through
goto case 12;
case 12:
k2 ^= (ulong)bb[pos + 11] << 24; // fall through
goto case 11;
case 11:
k2 ^= (ulong)bb[pos + 10] << 16; // fall through
goto case 10;
case 10:
k2 ^= (ulong)bb[pos + 9] << 8; // fall through
goto case 9;
case 9:
k2 ^= (ulong)bb[pos + 8]; // fall through
goto case 8;
case 8:
k1 ^= bb.GetUInt64(pos);
break;
case 7:
k1 ^= (ulong)bb[pos + 6] << 48; // fall through
goto case 6;
case 6:
k1 ^= (ulong)bb[pos + 5] << 40; // fall through
goto case 5;
case 5:
k1 ^= (ulong)bb[pos + 4] << 32; // fall through
goto case 4;
case 4:
k1 ^= (ulong)bb[pos + 3] << 24; // fall through
goto case 3;
case 3:
k1 ^= (ulong)bb[pos + 2] << 16; // fall through
goto case 2;
case 2:
k1 ^= (ulong)bb[pos + 1] << 8; // fall through
goto case 1;
case 1:
k1 ^= (ulong)bb[pos]; // fall through
break;
default:
throw new Exception("Something went wrong with remaining bytes calculation.");
}
h1 ^= MixKey1(k1);
h2 ^= MixKey2(k2);
}
h1 ^= length;
h2 ^= length;
h1 += h2;
h2 += h1;
h1 = Murmur3.MixFinal(h1);
h2 = Murmur3.MixFinal(h2);
h1 += h2;
h2 += h1;
return h2;
}
/// <summary>
/// Hashes the <paramref name="bytes"/> into a MurmurHash3 as a <see cref="uint"/>.
/// </summary>
/// <param name="bytes">The span.</param>
/// <param name="seed">The seed for this algorithm.</param>
/// <returns>The MurmurHash3 as a <see cref="uint"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ComputeUIntHash(ref ReadOnlySpan<byte> bytes, uint seed)
{
ref byte bp = ref MemoryMarshal.GetReference(bytes);
ref uint endPoint = ref Unsafe.Add(ref Unsafe.As<byte, uint>(ref bp), bytes.Length >> 2);
if (bytes.Length >= 4)
{
do
{
seed = RotateLeft(seed ^ RotateLeft(Unsafe.ReadUnaligned<uint>(ref bp) * 3432918353U, 15) * 461845907U, 13) * 5 - 430675100;
bp = ref Unsafe.Add(ref bp, 4);
} while (Unsafe.IsAddressLessThan(ref Unsafe.As<byte, uint>(ref bp), ref endPoint));
}
var remainder = bytes.Length & 3;
if (remainder > 0)
{
uint num = 0;
if (remainder > 2) num ^= Unsafe.Add(ref endPoint, 2) << 16;
if (remainder > 1) num ^= Unsafe.Add(ref endPoint, 1) << 8;
num ^= endPoint;
seed ^= RotateLeft(num * 3432918353U, 15) * 461845907U;
}
seed ^= (uint)bytes.Length;
seed = (uint)((seed ^ (seed >> 16)) * -2048144789);
seed = (uint)((seed ^ (seed >> 13)) * -1028477387);
return seed ^ seed >> 16;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong RotateLeft(this ulong original, int bits) => (original << bits) | (original >> (64 - bits));
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong RotateLeft(this ulong original, int bits) => public static uint RotateLeft(this uint original, int bits) => (original << bits) | (original >> (32 - bits));
(original << bits) | (original >> (64 - bits));
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ulong RotateRight(this ulong original, int bits) => public static ulong RotateRight(this ulong original, int bits) =>

@ -0,0 +1,40 @@
using System.Collections.Generic;
namespace ZeroLevel.Services.Mathemathics
{
public static class Combinations
{
private static IEnumerable<int[]> GenerateIndiciesForUniqueSets(int m, int n)
{
int[] result = new int[m];
Stack<int> stack = new Stack<int>(m);
stack.Push(0);
while (stack.Count > 0)
{
int index = stack.Count - 1;
int value = stack.Pop();
while (value < n)
{
result[index++] = value++;
stack.Push(value);
if (index != m) continue;
yield return result;
break;
}
}
}
public static IEnumerable<T[]> GenerateUniqueSets<T>(T[] original, int k)
{
T[] result = new T[k];
foreach (var indices in GenerateIndiciesForUniqueSets(k, original.Length))
{
for (int i = 0; i < k; i++)
{
result[i] = original[indices[i]];
}
yield return result;
}
}
}
}

@ -8,7 +8,7 @@
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<Title>ZeroLevel</Title> <Title>ZeroLevel</Title>
<FileVersion>$(AssemblyVersion)</FileVersion> <FileVersion>$(AssemblyVersion)</FileVersion>
<AssemblyVersion>4.0.0.0</AssemblyVersion> <AssemblyVersion>4.0.0.1</AssemblyVersion>
<Version>$(AssemblyVersion)</Version> <Version>$(AssemblyVersion)</Version>
<AnalysisLevel>latest</AnalysisLevel> <AnalysisLevel>latest</AnalysisLevel>
<Authors>Ogoun</Authors> <Authors>Ogoun</Authors>
@ -32,6 +32,10 @@
<Content Include="v3.ico" /> <Content Include="v3.ico" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="v3.png"> <None Update="v3.png">
<Pack>True</Pack> <Pack>True</Pack>

Loading…
Cancel
Save

Powered by TurnKey Linux.