using System; using System.Security.Cryptography; namespace DTLib { // // честно взятый с гитхаба алгоритм хеширования // выдаёт хеш в виде массива четырёх байтов // sealed class XXHash32 : HashAlgorithm { private const uint PRIME32_1 = 2654435761U; private const uint PRIME32_2 = 2246822519U; private const uint PRIME32_3 = 3266489917U; private const uint PRIME32_4 = 668265263U; private const uint PRIME32_5 = 374761393U; private static readonly Func FuncGetLittleEndianUInt32; private static readonly Func FuncGetFinalHashUInt32; private uint _Seed32; private uint _ACC32_1; private uint _ACC32_2; private uint _ACC32_3; private uint _ACC32_4; private uint _Hash32; private int _RemainingLength; private long _TotalLength = 0; private int _CurrentIndex; private byte[] _CurrentArray; static XXHash32() { if(BitConverter.IsLittleEndian) { FuncGetLittleEndianUInt32=new Func((x, i) => { unsafe { fixed(byte* array = x) { return *(uint*)(array+i); } } }); FuncGetFinalHashUInt32=new Func(i => (i&0x000000FFU)<<24|(i&0x0000FF00U)<<8|(i&0x00FF0000U)>>8|(i&0xFF000000U)>>24); } else { FuncGetLittleEndianUInt32=new Func((x, i) => { unsafe { fixed(byte* array = x) { return (uint)(array[i++]|(array[i++]<<8)|(array[i++]<<16)|(array[i]<<24)); } } }); FuncGetFinalHashUInt32=new Func(i => i); } } // Creates an instance of class by default seed(0). // public static new XXHash32 Create() => new(); // Initializes a new instance of the class by default seed(0). public XXHash32() => Initialize(0); // Initializes a new instance of the class, and sets the to the specified value. // Represent the seed to be used for xxHash32 computing. public XXHash32(uint seed) => Initialize(seed); // Gets the value of the computed hash code. // Hash computation has not yet completed. public uint HashUInt32 => State==0 ? _Hash32 : throw new InvalidOperationException("Hash computation has not yet completed."); // Gets or sets the value of seed used by xxHash32 algorithm. // Hash computation has not yet completed. public uint Seed { get => _Seed32; set { if(value!=_Seed32) { if(State!=0) throw new InvalidOperationException("Hash computation has not yet completed."); _Seed32=value; Initialize(); } } } // Initializes this instance for new hash computing. public override void Initialize() { _ACC32_1=_Seed32+PRIME32_1+PRIME32_2; _ACC32_2=_Seed32+PRIME32_2; _ACC32_3=_Seed32+0; _ACC32_4=_Seed32-PRIME32_1; } // Routes data written to the object into the hash algorithm for computing the hash. // The input to compute the hash code for. // The offset into the byte array from which to begin using data. // The number of bytes in the byte array to use as data. protected override void HashCore(byte[] array, int ibStart, int cbSize) { if(State!=1) State=1; int size = cbSize-ibStart; _RemainingLength=size&15; if(cbSize>=16) { int limit = size-_RemainingLength; do { _ACC32_1=Round32(_ACC32_1, FuncGetLittleEndianUInt32(array, ibStart)); ibStart+=4; _ACC32_2=Round32(_ACC32_2, FuncGetLittleEndianUInt32(array, ibStart)); ibStart+=4; _ACC32_3=Round32(_ACC32_3, FuncGetLittleEndianUInt32(array, ibStart)); ibStart+=4; _ACC32_4=Round32(_ACC32_4, FuncGetLittleEndianUInt32(array, ibStart)); ibStart+=4; } while(ibStartThe computed hash code. protected override byte[] HashFinal() { if(_TotalLength>=16) { _Hash32=RotateLeft32(_ACC32_1, 1)+RotateLeft32(_ACC32_2, 7)+RotateLeft32(_ACC32_3, 12)+RotateLeft32(_ACC32_4, 18); } else { _Hash32=_Seed32+PRIME32_5; } _Hash32+=(uint)_TotalLength; while(_RemainingLength>=4) { _Hash32=RotateLeft32(_Hash32+FuncGetLittleEndianUInt32(_CurrentArray, _CurrentIndex)*PRIME32_3, 17)*PRIME32_4; _CurrentIndex+=4; _RemainingLength-=4; } unsafe { fixed(byte* arrayPtr = _CurrentArray) { while(_RemainingLength-->=1) { _Hash32=RotateLeft32(_Hash32+arrayPtr[_CurrentIndex++]*PRIME32_5, 11)*PRIME32_1; } } } _Hash32=(_Hash32^(_Hash32>>15))*PRIME32_2; _Hash32=(_Hash32^(_Hash32>>13))*PRIME32_3; _Hash32^=_Hash32>>16; _TotalLength=State=0; return BitConverter.GetBytes(FuncGetFinalHashUInt32(_Hash32)); } private static uint Round32(uint input, uint value) => RotateLeft32(input+(value*PRIME32_2), 13)*PRIME32_1; private static uint RotateLeft32(uint value, int count) => (value<>(32-count)); private void Initialize(uint seed) { HashSizeValue=32; _Seed32=seed; Initialize(); } } }