<PackageReference Include="System.IO.Hashing" Version="9.0.10" />

XxHash3

public sealed class XxHash3 : NonCryptographicHashAlgorithm
Provides an implementation of the XXH3 hash algorithm for generating a 64-bit hash.
using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.IO.Hashing { public sealed class XxHash3 : NonCryptographicHashAlgorithm { private new const int HashLengthInBytes = 8; private XxHashShared.State _state; public XxHash3() : this(0) { } public XxHash3(long seed) : base(8) { XxHashShared.Initialize(ref _state, (ulong)seed); } [System.Runtime.CompilerServices.NullableContext(1)] public static byte[] Hash(byte[] source) { return Hash(source, 0); } [System.Runtime.CompilerServices.NullableContext(1)] public static byte[] Hash(byte[] source, long seed) { if (source == null) throw new ArgumentNullException("source"); return Hash(new ReadOnlySpan<byte>(source), seed); } [return: System.Runtime.CompilerServices.Nullable(1)] public static byte[] Hash(ReadOnlySpan<byte> source, long seed = 0) { byte[] obj = new byte[8]; BinaryPrimitives.WriteUInt64BigEndian(value: HashToUInt64(source, seed), destination: obj); return obj; } public static int Hash(ReadOnlySpan<byte> source, Span<byte> destination, long seed = 0) { if (!TryHash(source, destination, out int bytesWritten, seed)) NonCryptographicHashAlgorithm.ThrowDestinationTooShort(); return bytesWritten; } public static bool TryHash(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten, long seed = 0) { if (destination.Length >= 8) { ulong value = HashToUInt64(source, seed); if (BitConverter.IsLittleEndian) value = BinaryPrimitives.ReverseEndianness(value); Unsafe.WriteUnaligned(ref MemoryMarshal.GetReference(destination), value); bytesWritten = 8; return true; } bytesWritten = 0; return false; } [CLSCompliant(false)] public unsafe static ulong HashToUInt64(ReadOnlySpan<byte> source, long seed = 0) { uint length = (uint)source.Length; fixed (byte* source2 = &MemoryMarshal.GetReference(source)) { if (length <= 16) return HashLength0To16(source2, length, (ulong)seed); if (length <= 128) return HashLength17To128(source2, length, (ulong)seed); if (length <= 240) return HashLength129To240(source2, length, (ulong)seed); return HashLengthOver240(source2, length, (ulong)seed); } } public override void Reset() { XxHashShared.Reset(ref _state); } public override void Append(ReadOnlySpan<byte> source) { XxHashShared.Append(ref _state, source); } protected override void GetCurrentHashCore(Span<byte> destination) { ulong currentHashAsUInt = GetCurrentHashAsUInt64(); BinaryPrimitives.WriteUInt64BigEndian(destination, currentHashAsUInt); } [CLSCompliant(false)] public unsafe ulong GetCurrentHashAsUInt64() { if (_state.TotalLength <= 240) { fixed (byte* pointer = _state.Buffer) { return HashToUInt64(new ReadOnlySpan<byte>(pointer, (int)_state.TotalLength), (long)_state.Seed); } } ulong* accumulators = stackalloc ulong[8]; XxHashShared.CopyAccumulators(ref _state, accumulators); fixed (byte* ptr = _state.Secret) { XxHashShared.DigestLong(ref _state, accumulators, ptr); return XxHashShared.MergeAccumulators(accumulators, ptr + 11, (ulong)((long)_state.TotalLength * -7046029288634856825)); } } private unsafe static ulong HashLength0To16(byte* source, uint length, ulong seed) { if (length > 8) return HashLength9To16(source, length, seed); if (length >= 4) return HashLength4To8(source, length, seed); if (length != 0) return HashLength1To3(source, length, seed); return XxHash64.Avalanche((ulong)((long)seed ^ -8707998980786479652)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static ulong HashLength1To3(byte* source, uint length, ulong seed) { byte num = *source; byte b = source[length >> 1]; byte b2 = source[length - 1]; return XxHash64.Avalanche((uint)((num << 16) | (b << 24) | b2 | (int)(length << 8)) ^ (2267503259 + seed)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static ulong HashLength4To8(byte* source, uint length, ulong seed) { seed ^= (ulong)BinaryPrimitives.ReverseEndianness((uint)seed) << 32; uint num = XxHashShared.ReadUInt32LE(source); uint num2 = XxHashShared.ReadUInt32LE(source + length - 4); ulong num3 = (ulong)(-4090762196417718878 - (long)seed); return XxHashShared.Rrmxmx((num2 + ((ulong)num << 32)) ^ num3, length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static ulong HashLength9To16(byte* source, uint length, ulong seed) { ulong num = 7458650908927343033 + seed; ulong num2 = (ulong)(-5812251307325107654 - (long)seed); ulong num3 = XxHashShared.ReadUInt64LE(source) ^ num; ulong num4 = XxHashShared.ReadUInt64LE(source + length - 8) ^ num2; return XxHashShared.Avalanche(length + BinaryPrimitives.ReverseEndianness(num3) + num4 + XxHashShared.Multiply64To128ThenFold(num3, num4)); } private unsafe static ulong HashLength17To128(byte* source, uint length, ulong seed) { ulong num = (ulong)(length * -7046029288634856825); switch ((length - 1) / 32) { default: num += XxHashShared.Mix16Bytes(source + 48, 4554437623014685352, 2111919702937427193, seed); num += XxHashShared.Mix16Bytes(source + length - 64, 3556072174620004746, 7238261902898274248, seed); goto case 2; case 2: num += XxHashShared.Mix16Bytes(source + 32, 14627906620379768892, 11758427054878871688, seed); num += XxHashShared.Mix16Bytes(source + length - 48, 5690594596133299313, 15613098826807580984, seed); goto case 1; case 1: num += XxHashShared.Mix16Bytes(source + 16, 8711581037947681227, 2410270004345854594, seed); num += XxHashShared.Mix16Bytes(source + length - 32, 10242386182634080440, 5487137525590930912, seed); break; case 0: break; } num += XxHashShared.Mix16Bytes(source, 13712233961653862072, 2066345149520216444, seed); num += XxHashShared.Mix16Bytes(source + length - 16, 15823274712020931806, 2262974939099578482, seed); return XxHashShared.Avalanche(num); } private unsafe static ulong HashLength129To240(byte* source, uint length, ulong seed) { ulong num = (ulong)(length * -7046029288634856825); num += XxHashShared.Mix16Bytes(source, 13712233961653862072, 2066345149520216444, seed); num += XxHashShared.Mix16Bytes(source + 16, 15823274712020931806, 2262974939099578482, seed); num += XxHashShared.Mix16Bytes(source + 32, 8711581037947681227, 2410270004345854594, seed); num += XxHashShared.Mix16Bytes(source + 48, 10242386182634080440, 5487137525590930912, seed); num += XxHashShared.Mix16Bytes(source + 64, 14627906620379768892, 11758427054878871688, seed); num += XxHashShared.Mix16Bytes(source + 80, 5690594596133299313, 15613098826807580984, seed); num += XxHashShared.Mix16Bytes(source + 96, 4554437623014685352, 2111919702937427193, seed); num += XxHashShared.Mix16Bytes(source + 112, 3556072174620004746, 7238261902898274248, seed); num = XxHashShared.Avalanche(num); switch ((length - 128) / 16) { default: num += XxHashShared.Mix16Bytes(source + 224, 13536968629829821247, 16163852396094277575, seed); goto case 6; case 6: num += XxHashShared.Mix16Bytes(source + 208, 17228863761319568023, 8573350489219836230, seed); goto case 5; case 5: num += XxHashShared.Mix16Bytes(source + 192, 7336514198459093435, 5216419214072683403, seed); goto case 4; case 4: num += XxHashShared.Mix16Bytes(source + 176, 10391458616325699444, 5920048007935066598, seed); goto case 3; case 3: num += XxHashShared.Mix16Bytes(source + 160, 15013455763555273806, 5046485836271438973, seed); goto case 2; case 2: num += XxHashShared.Mix16Bytes(source + 144, 11835586108195898345, 16607528436649670564, seed); goto case 1; case 1: num += XxHashShared.Mix16Bytes(source + 128, 9295848262624092985, 7914194659941938988, seed); break; case 0: break; } num += XxHashShared.Mix16Bytes(source + length - 16, 8320639771003045937, 16992983559143025252, seed); return XxHashShared.Avalanche(num); } private unsafe static ulong HashLengthOver240(byte* source, uint length, ulong seed) { fixed (byte* ptr = &MemoryMarshal.GetReference(XxHashShared.DefaultSecret)) { byte* ptr2 = ptr; if (seed != 0) { byte* intPtr = stackalloc byte[192]; XxHashShared.DeriveSecretFromSeed(intPtr, seed); ptr2 = intPtr; } byte* accumulators = stackalloc byte[64]; XxHashShared.InitializeAccumulators((ulong*)accumulators); XxHashShared.HashInternalLoop((ulong*)accumulators, source, length, ptr2); return XxHashShared.MergeAccumulators((ulong*)accumulators, ptr2 + 11, (ulong)(length * -7046029288634856825)); } } } }