Search code examples
c#associationshashcode.net-7.0crc32

How to get constant hashcode (Uint32 or Int32) for a string but being outside of a range


According to this article the official "GetHashCode" for a string is made randomly per execution to prevent Hacking. But I need to persist the hashcode so I want it to be always the same per specific string.

In the same article I saw a way to get an HashCode but I wonder if there is better solution and/or if there is a way to direcly get a Hash code outside of a specific range (like 0 - 2000)? Any Uint32 ouside of [0-2000].


Solution

  • Crc32C.ARM.cs

    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Runtime.Intrinsics.Arm;
    
    namespace DiscountCard.Ext.Mod.CRC32
    {
        partial class Crc32C
        {
            public static class ImplARM
            {
                public static uint Update(uint crc, ReadOnlySpan<byte> input)
                {
                    crc ^= uint.MaxValue;
                    while (input.Length >= 4)
                    {
                        crc = Crc32.ComputeCrc32C(crc, Unsafe.ReadUnaligned<uint>(ref MemoryMarshal.GetReference(input)));
                        input = input.Slice(sizeof(uint));
                    }
                    for (int i = 0; i < input.Length; i++)
                    {
                        crc = Crc32.ComputeCrc32C(crc, input[i]);
                    }
                    return crc ^ uint.MaxValue;
                }
    
                public static uint Update64(uint crc, ReadOnlySpan<byte> input)
                {
                    crc ^= uint.MaxValue;
                    while (input.Length >= sizeof(ulong))
                    {
                        crc = Crc32.Arm64.ComputeCrc32C(crc, Unsafe.ReadUnaligned<ulong>(ref MemoryMarshal.GetReference(input)));
                        input = input.Slice(sizeof(ulong));
                    }
                    if (input.Length >= 4)
                    {
                        crc = Crc32.ComputeCrc32C(crc, Unsafe.ReadUnaligned<uint>(ref MemoryMarshal.GetReference(input)));
                        input = input.Slice(sizeof(uint));
                    }
                    for (int i = 0; i < input.Length; i++)
                    {
                        crc = Crc32.ComputeCrc32C(crc, input[i]);
                    }
                    return crc ^ uint.MaxValue;
                }
            }
        }
    }
    

    Crc32C.X86.cs

    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Runtime.Intrinsics.X86;
    
    namespace DiscountCard.Ext.Mod.CRC32
    {
        partial class Crc32C
        {
            public static class ImplX86
            {
                public static uint Update(uint crc, ReadOnlySpan<byte> input)
                {
                    crc ^= uint.MaxValue;
                    while (input.Length >= sizeof(uint))
                    {
                        crc = Sse42.Crc32(crc, Unsafe.ReadUnaligned<uint>(ref MemoryMarshal.GetReference(input)));
                        input = input.Slice(sizeof(uint));
                    }
                    for (int i = 0; i < input.Length; i++)
                    {
                        crc = Sse42.Crc32(crc, (byte)input[i]);
                    }
                    return crc ^ uint.MaxValue;
                }
    
                public static uint Update64(uint crc, ReadOnlySpan<byte> input)
                {
                    ulong crcl = crc ^ uint.MaxValue;
                    while (input.Length >= sizeof(ulong))
                    {
                        crcl = Sse42.X64.Crc32(crcl, Unsafe.ReadUnaligned<ulong>(ref MemoryMarshal.GetReference(input)));
                        input = input.Slice(sizeof(ulong));
                    }
                    crc = unchecked((uint)crcl);
                    if (input.Length >= 4)
                    {
                        crc = Sse42.Crc32(crc, Unsafe.ReadUnaligned<uint>(ref MemoryMarshal.GetReference(input)));
                        input = input.Slice(sizeof(uint));
                    }
                    for (int i = 0; i < input.Length; i++)
                    {
                        crc = Sse42.Crc32(crc, (byte)input[i]);
                    }
                    return crc ^ uint.MaxValue;
                }
            }
        }
    }
    

    Crc32C.cs

    #define X86_INTRINSICS
    
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    
    #if X86_INTRINSICS
    using System.Runtime.Intrinsics.X86;
    #endif
    #if ARM_INTRINSICS
    using System.Runtime.Intrinsics.Arm;
    #endif
    
    namespace DiscountCard.Ext.Mod.CRC32
    {
        public static unsafe partial class Crc32C
        {
    
            private static uint* table;
            private const uint poly = 0x82f63b78u;
            private static delegate*<uint, ReadOnlySpan<byte>, uint> ptr;
            static Crc32C()
            {
    #if X86_INTRINSICS
                if (Sse42.X64.IsSupported)
                {
                    ptr = &ImplX86.Update64;
                    goto end_decision;
                }
                if (Sse42.IsSupported)
                {
                    ptr = &ImplX86.Update;
                    goto end_decision;
                }
    #endif
    #if ARM_INTRINSICS
                if (Crc32.Arm64.IsSupported)
                {
                    ptr = &ImplARM.Update64;
                    goto end_decision;
                }
                if (Crc32.IsSupported)
                {
                    ptr = &ImplARM.Update;
                    goto end_decision;
                }
    #endif
                // FOR NO SPECIFIC OS ///////////
                InitializeTable();
                if (BitConverter.IsLittleEndian)
                {
                    ptr = &UpdateLittleEndianOptimized;
                    goto end_decision;
                }
                ptr = &UpdateNative;
                // END OF FOR NO SPECIFIC OS ///
    
            end_decision:;
            }
    
            static void InitializeTable()
            {
                table = (uint*)Marshal.AllocHGlobal(16 * 256 * 4);
                for (uint i = 0; i < 256; i++)
                {
                    uint res = i;
                    for (int t = 0; t < 16; t++)
                    {
                        for (int k = 0; k < 8; k++) res = (res & 1) == 1 ? poly ^ (res >> 1) : (res >> 1);
                        table[(t * 256) + i] = res;
                    }
                }
            }
    
            static uint UpdateLittleEndianOptimized(uint crci, ReadOnlySpan<byte> input)
            {
                // Copyright (C) 2013 Mark Adler
                ulong crc;
    
                crc = crci ^ 0xffffffff;
                while (input.Length >= sizeof(ulong))
                {
                    crc ^= Unsafe.ReadUnaligned<ulong>(ref MemoryMarshal.GetReference(input));
                    crc = table[(7 * 256) + (crc & 0xff)] ^
                          table[(6 * 256) + ((crc >> 8) & 0xff)] ^
                          table[(5 * 256) + ((crc >> 16) & 0xff)] ^
                          table[(4 * 256) + ((crc >> 24) & 0xff)] ^
                          table[(3 * 256) + ((crc >> 32) & 0xff)] ^
                          table[(2 * 256) + ((crc >> 40) & 0xff)] ^
                          table[(1 * 256) + ((crc >> 48) & 0xff)] ^
                          table[(0 * 256) + (crc >> 56)];
                    input = input.Slice(sizeof(ulong));
                }
                for (int i = 0; i < input.Length; i++)
                {
                    crc = table[(0 * 256) + ((crc ^ input[i]) & 0xff)] ^ (crc >> 8);
                }
                return (uint)crc ^ 0xffffffff;
            }
    
            static uint UpdateNative(uint crc, ReadOnlySpan<byte> input)
            {
                crc ^= uint.MaxValue;
                for (int i = 0; i < input.Length; i++)
                {
                    crc = table[(0 * 256) + ((crc ^ input[i]) & 0xff)] ^ (crc >> 8);
                }
                return crc ^ uint.MaxValue;
            }
    
    
            [MethodImpl(MethodImplOptions.AggressiveInlining)]
            public static uint Update(uint crc, ReadOnlySpan<byte> input) => ptr(crc, input);
    
        }
    }
    

    HOW TO USE?

    A. For CRC32C

    uint result = Crc32C.Update(0, Encoding.ASCII.GetBytes("There is no God but Allah"));
    MessageBox.Show(result.ToString("X")); // result: C16698CA
    

    B. For CRC32

    Change poly from

    private const uint poly = 0x82f63b78u;
    

    To

    private const uint poly = 0xedb88320u;
    
    
    
    uint result = Crc32C.Update(0, Encoding.ASCII.GetBytes("There is no God but Allah"));
    MessageBox.Show(result.ToString("X")); // result: 0xFABB17B6