<PackageReference Include="System.IO.Hashing" Version="10.0.0-preview.6.25358.103" />

XxHashShared

static class XxHashShared
using System.Buffers.Binary; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace System.IO.Hashing { internal static class XxHashShared { [StructLayout(LayoutKind.Auto)] public struct State { internal unsafe fixed ulong Accumulators[8]; internal unsafe fixed byte Secret[192]; internal unsafe fixed byte Buffer[256]; internal uint BufferedCount; internal ulong StripesProcessedInCurrentBlock; internal ulong TotalLength; internal ulong Seed; } public const int StripeLengthBytes = 64; public const int SecretLengthBytes = 192; public const int SecretSizeMin = 136; public const int SecretLastAccStartBytes = 7; public const int SecretConsumeRateBytes = 8; public const int SecretMergeAccsStartBytes = 11; public const int NumStripesPerBlock = 16; public const int AccumulatorCount = 8; public const int MidSizeMaxBytes = 240; public const int InternalBufferStripes = 4; public const int InternalBufferLengthBytes = 256; public const ulong DefaultSecretUInt64_0 = 13712233961653862072; public const ulong DefaultSecretUInt64_1 = 2066345149520216444; public const ulong DefaultSecretUInt64_2 = 15823274712020931806; public const ulong DefaultSecretUInt64_3 = 2262974939099578482; public const ulong DefaultSecretUInt64_4 = 8711581037947681227; public const ulong DefaultSecretUInt64_5 = 2410270004345854594; public const ulong DefaultSecretUInt64_6 = 10242386182634080440; public const ulong DefaultSecretUInt64_7 = 5487137525590930912; public const ulong DefaultSecretUInt64_8 = 14627906620379768892; public const ulong DefaultSecretUInt64_9 = 11758427054878871688; public const ulong DefaultSecretUInt64_10 = 5690594596133299313; public const ulong DefaultSecretUInt64_11 = 15613098826807580984; public const ulong DefaultSecretUInt64_12 = 4554437623014685352; public const ulong DefaultSecretUInt64_13 = 2111919702937427193; public const ulong DefaultSecretUInt64_14 = 3556072174620004746; public const ulong DefaultSecretUInt64_15 = 7238261902898274248; public const ulong DefaultSecret3UInt64_0 = 9295848262624092985; public const ulong DefaultSecret3UInt64_1 = 7914194659941938988; public const ulong DefaultSecret3UInt64_2 = 11835586108195898345; public const ulong DefaultSecret3UInt64_3 = 16607528436649670564; public const ulong DefaultSecret3UInt64_4 = 15013455763555273806; public const ulong DefaultSecret3UInt64_5 = 5046485836271438973; public const ulong DefaultSecret3UInt64_6 = 10391458616325699444; public const ulong DefaultSecret3UInt64_7 = 5920048007935066598; public const ulong DefaultSecret3UInt64_8 = 7336514198459093435; public const ulong DefaultSecret3UInt64_9 = 5216419214072683403; public const ulong DefaultSecret3UInt64_10 = 17228863761319568023; public const ulong DefaultSecret3UInt64_11 = 8573350489219836230; public const ulong DefaultSecret3UInt64_12 = 13536968629829821247; public const ulong DefaultSecret3UInt64_13 = 16163852396094277575; public const ulong Prime64_1 = 11400714785074694791; public const ulong Prime64_2 = 14029467366897019727; public const ulong Prime64_3 = 1609587929392839161; public const ulong Prime64_4 = 9650029242287828579; public const ulong Prime64_5 = 2870177450012600261; public const uint Prime32_1 = 2654435761; public const uint Prime32_2 = 2246822519; public const uint Prime32_3 = 3266489917; public const uint Prime32_4 = 668265263; public const uint Prime32_5 = 374761393; public unsafe static ReadOnlySpan<byte> DefaultSecret => new ReadOnlySpan<byte>(&global::<PrivateImplementationDetails>.2CF2F88BF9B71283059B6DF53E5BCDE20ADBFD9E8D6CE2C1AB106262BB283BED, 192); public unsafe static void Initialize(ref State state, ulong seed) { state.Seed = seed; fixed (byte* ptr = state.Secret) { if (seed == 0) DefaultSecret.CopyTo(new Span<byte>(ptr, 192)); else DeriveSecretFromSeed(ptr, seed); } Reset(ref state); } public unsafe static void Reset(ref State state) { state.BufferedCount = 0; state.StripesProcessedInCurrentBlock = 0; state.TotalLength = 0; fixed (ulong* accumulators = state.Accumulators) { InitializeAccumulators(accumulators); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Rrmxmx(ulong hash, uint length) { hash ^= (System.Numerics.BitOperations.RotateLeft(hash, 49) ^ System.Numerics.BitOperations.RotateLeft(hash, 24)); hash = (ulong)((long)hash * -6939452855193903323); hash ^= (hash >> 35) + length; hash = (ulong)((long)hash * -6939452855193903323); return XorShift(hash, 28); } public unsafe static void HashInternalLoop(ulong* accumulators, byte* source, uint length, byte* secret) { int num = (int)((length - 1) / 1024); Accumulate(accumulators, source, secret, 16, true, num); int num2 = 1024 * num; int stripesToProcess = (int)((length - 1 - num2) / 64); Accumulate(accumulators, source + num2, secret, stripesToProcess, false, 1); Accumulate512(accumulators, source + length - 64, secret + 121); } public unsafe static void ConsumeStripes(ulong* accumulators, ref ulong stripesSoFar, ulong stripesPerBlock, byte* source, ulong stripes, byte* secret) { ulong num = stripesPerBlock - stripesSoFar; if (num <= stripes) { ulong num2 = stripes - num; Accumulate(accumulators, source, secret + (int)stripesSoFar * 8, (int)num, false, 1); ScrambleAccumulators(accumulators, secret + 128); Accumulate(accumulators, source + (int)num * 64, secret, (int)num2, false, 1); stripesSoFar = num2; } else { Accumulate(accumulators, source, secret + (int)stripesSoFar * 8, (int)stripes, false, 1); stripesSoFar += stripes; } } public unsafe static void Append(ref State state, ReadOnlySpan<byte> source) { state.TotalLength += (uint)source.Length; fixed (byte* ptr = state.Buffer) { if (source.Length > 256 - state.BufferedCount) { fixed (byte* ptr2 = state.Secret) { fixed (ulong* accumulators = state.Accumulators) { fixed (byte* ptr3 = &MemoryMarshal.GetReference(source)) { int num = 0; ReadOnlySpan<byte> readOnlySpan; if (state.BufferedCount != 0) { int num2 = (int)(256 - state.BufferedCount); readOnlySpan = source.Slice(0, num2); readOnlySpan.CopyTo(new Span<byte>(ptr + state.BufferedCount, num2)); num = num2; ConsumeStripes(accumulators, ref state.StripesProcessedInCurrentBlock, 16, ptr, 4, ptr2); state.BufferedCount = 0; } if (source.Length - num > 1024) { ulong num3 = (ulong)(source.Length - num - 1) / 64; ulong num4 = 16 - state.StripesProcessedInCurrentBlock; Accumulate(accumulators, ptr3 + num, ptr2 + (int)state.StripesProcessedInCurrentBlock * 8, (int)num4, false, 1); ScrambleAccumulators(accumulators, ptr2 + 128); state.StripesProcessedInCurrentBlock = 0; num += (int)num4 * 64; for (num3 -= num4; num3 >= 16; num3 -= 16) { Accumulate(accumulators, ptr3 + num, ptr2, 16, false, 1); ScrambleAccumulators(accumulators, ptr2 + 128); num += 1024; } Accumulate(accumulators, ptr3 + num, ptr2, (int)num3, false, 1); num += (int)num3 * 64; state.StripesProcessedInCurrentBlock = num3; readOnlySpan = source.Slice(num - 64, 64); readOnlySpan.CopyTo(new Span<byte>(ptr + 256 - 64, 64)); } else if (source.Length - num > 256) { do { ConsumeStripes(accumulators, ref state.StripesProcessedInCurrentBlock, 16, ptr3 + num, 4, ptr2); num += 256; } while (source.Length - num > 256); readOnlySpan = source.Slice(num - 64, 64); readOnlySpan.CopyTo(new Span<byte>(ptr + 256 - 64, 64)); } Span<byte> destination = new Span<byte>(ptr, source.Length - num); readOnlySpan = source.Slice(num); readOnlySpan.CopyTo(destination); state.BufferedCount = (uint)destination.Length; } } } } else { source.CopyTo(new Span<byte>(ptr + state.BufferedCount, source.Length)); state.BufferedCount += (uint)source.Length; } } } public unsafe static void CopyAccumulators(ref State state, ulong* accumulators) { fixed (ulong* ptr = state.Accumulators) { for (int i = 0; i < 8; i++) { accumulators[i] = ptr[i]; } } } public unsafe static void DigestLong(ref State state, ulong* accumulators, byte* secret) { fixed (byte* ptr = state.Buffer) { byte* source; if (state.BufferedCount >= 64) { uint num = (state.BufferedCount - 1) / 64; ulong stripesSoFar = state.StripesProcessedInCurrentBlock; ConsumeStripes(accumulators, ref stripesSoFar, 16, ptr, num, secret); source = ptr + state.BufferedCount - 64; } else { byte* ptr2 = stackalloc byte[64]; int num2 = (int)(64 - state.BufferedCount); ReadOnlySpan<byte> readOnlySpan = new ReadOnlySpan<byte>(ptr + 256 - num2, num2); readOnlySpan.CopyTo(new Span<byte>(ptr2, 64)); readOnlySpan = new ReadOnlySpan<byte>(ptr, (int)state.BufferedCount); readOnlySpan.CopyTo(new Span<byte>(ptr2 + num2, (int)state.BufferedCount)); source = ptr2; } Accumulate512(accumulators, source, secret + 121); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void InitializeAccumulators(ulong* accumulators) { *accumulators = 3266489917; accumulators[1] = 11400714785074694791; accumulators[2] = 14029467366897019727; accumulators[3] = 1609587929392839161; accumulators[4] = 9650029242287828579; accumulators[5] = 2246822519; accumulators[6] = 2870177450012600261; accumulators[7] = 2654435761; } public unsafe static ulong MergeAccumulators(ulong* accumulators, byte* secret, ulong start) { return Avalanche(start + Multiply64To128ThenFold(*accumulators ^ ReadUInt64LE(secret), accumulators[1] ^ ReadUInt64LE(secret + 8)) + Multiply64To128ThenFold(accumulators[2] ^ ReadUInt64LE(secret + 16), accumulators[3] ^ ReadUInt64LE(secret + 24)) + Multiply64To128ThenFold(accumulators[4] ^ ReadUInt64LE(secret + 32), accumulators[5] ^ ReadUInt64LE(secret + 40)) + Multiply64To128ThenFold(accumulators[6] ^ ReadUInt64LE(secret + 48), accumulators[7] ^ ReadUInt64LE(secret + 56))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static ulong Mix16Bytes(byte* source, ulong secretLow, ulong secretHigh, ulong seed) { return Multiply64To128ThenFold(ReadUInt64LE(source) ^ (secretLow + seed), ReadUInt64LE(source + 8) ^ (secretHigh - seed)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Multiply32To64(uint v1, uint v2) { return (ulong)((long)v1 * (long)v2); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Avalanche(ulong hash) { hash = XorShift(hash, 37); hash *= 1609587791953885689; hash = XorShift(hash, 32); return hash; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Multiply64To128(ulong left, ulong right, out ulong lower) { ulong num = Multiply32To64((uint)left, (uint)right); ulong num2 = Multiply32To64((uint)(left >> 32), (uint)right); ulong num3 = Multiply32To64((uint)left, (uint)(right >> 32)); ulong num4 = Multiply32To64((uint)(left >> 32), (uint)(right >> 32)); ulong num5 = (num >> 32) + (num2 & uint.MaxValue) + num3; ulong result = (num2 >> 32) + (num5 >> 32) + num4; lower = ((num5 << 32) | (num & uint.MaxValue)); return result; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong Multiply64To128ThenFold(ulong left, ulong right) { ulong lower; ulong num = Multiply64To128(left, right, out lower); return lower ^ num; } public unsafe static void DeriveSecretFromSeed(byte* destinationSecret, ulong seed) { fixed (byte* ptr = &MemoryMarshal.GetReference(DefaultSecret)) { for (int i = 0; i < 192; i += 16) { WriteUInt64LE(destinationSecret + i, ReadUInt64LE(ptr + i) + seed); WriteUInt64LE(destinationSecret + i + 8, ReadUInt64LE(ptr + i + 8) - seed); } } } [MethodImpl(MethodImplOptions.NoInlining)] private unsafe static void Accumulate(ulong* accumulators, byte* source, byte* secret, int stripesToProcess, bool scramble = false, int blockCount = 1) { byte* secret2 = secret + 128; for (int i = 0; i < blockCount; i++) { for (int j = 0; j < stripesToProcess; j++) { Accumulate512Inlined(accumulators, source, secret + j * 8); source += 64; } if (scramble) ScrambleAccumulators(accumulators, secret2); } } [MethodImpl(MethodImplOptions.NoInlining)] public unsafe static void Accumulate512(ulong* accumulators, byte* source, byte* secret) { Accumulate512Inlined(accumulators, source, secret); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static void Accumulate512Inlined(ulong* accumulators, byte* source, byte* secret) { for (int i = 0; i < 8; i++) { ulong num = ReadUInt64LE(source + 8 * i); ulong num2 = num ^ ReadUInt64LE(secret + i * 8); accumulators[i ^ 1] += num; accumulators[i] += Multiply32To64((uint)num2, (uint)(num2 >> 32)); } } private unsafe static void ScrambleAccumulators(ulong* accumulators, byte* secret) { for (int i = 0; i < 8; i++) { ulong num = XorShift(*accumulators, 47) ^ ReadUInt64LE(secret); *accumulators = num * 2654435761; accumulators++; secret += 8; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong XorShift(ulong value, int shift) { return value ^ (value >> shift); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static uint ReadUInt32LE(byte* data) { if (!BitConverter.IsLittleEndian) return BinaryPrimitives.ReverseEndianness(Unsafe.ReadUnaligned<uint>(data)); return Unsafe.ReadUnaligned<uint>(data); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static ulong ReadUInt64LE(byte* data) { if (!BitConverter.IsLittleEndian) return BinaryPrimitives.ReverseEndianness(Unsafe.ReadUnaligned<ulong>(data)); return Unsafe.ReadUnaligned<ulong>(data); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private unsafe static void WriteUInt64LE(byte* data, ulong value) { if (!BitConverter.IsLittleEndian) value = BinaryPrimitives.ReverseEndianness(value); Unsafe.WriteUnaligned(data, value); } } }