alexeyfv

Published on

- 2 min read

xxHash: the fastest hashing algorithm in the .NET ecosystem

C# Performance Algorithms
img of xxHash: the fastest hashing algorithm in the .NET ecosystem

Recently at work, I needed to compute a stable hash for some objects. At first, I thought about using standard cryptographic algorithms like SHA1, SHA256, SHA512, or MD5. But they have two problems:

  1. The hash is too large — from 160 to 512 bits.
  2. They return a byte array, which causes extra memory allocations.

So I started looking for an alternative. I quickly found the xxHash repository and its C# implementation. The key advantages of xxHash are high speed and the ability to return the hash as an integer.

It’s important to understand that xxHash is not a cryptographic algorithm. It’s made for other use cases: fast hashing, comparing data, cache keys, or database indexes.

xxHash in .NET

To use xxHash in your app, you need to install the System.IO.Hashing package. It includes four versions of the xxHash algorithm:

AlgorithmHash size
XxHash3232 bits
XxHash6464 bits
XxHash364 bits
XxHash128128 bits

Performance

I compared these algorithms by how fast they compute a hash. I also added SHA1, SHA2, SHA3, and MD5 to the test. The results:

Comparison of xxHash speed with other hash algorithms

Benchmark results: xxHash is much faster than SHA and MD5

Here are the full results. As expected, xxHash is one of the fastest.

Example usage

xxHash is easy to use and has useful features:

Append method — lets you add data step by step, without extra allocations.
Integer output — the result can be uint, ulong, or UInt128, instead of a byte array.
Supports Span<T> — so you can work with stack memory and avoid heap allocations.

Here’s an example of how to use it:

   public class SomeObject
{
    [ThreadStatic]
    private static readonly XxHash3 hasher;

    static SomeObject() => hasher = new();

    public required int IntValue { get; init; }
    public required string StringValue { get; init; }
    public required DateTimeOffset DateTimeValue { get; init; }

    public ulong GetStableHashCode()
    {
        hasher.Reset();

        var idBytes = MemoryMarshal.Cast<int, byte>([IntValue]);
        hasher.Append(idBytes);

        var bytesCount = Encoding.UTF8.GetByteCount(StringValue);
        Span<byte> stringBytes = stackalloc byte[bytesCount];
        Encoding.UTF8.GetBytes(StringValue, stringBytes);
        hasher.Append(stringBytes);

        var unixTime = DateTimeValue.ToUnixTimeMilliseconds();
        var dateBytes = MemoryMarshal.Cast<long, byte>([unixTime]);
        hasher.Append(dateBytes);

        return hasher.GetCurrentHashAsUInt64();
    }
}

Conclusion

Using xxHash to compute stable hashes gives you many benefits:

High performance. One of the fastest algorithms available.
No heap allocations. With Span and Append, you can hash using only the stack and CPU registers.
Small and simple values. You get uint or ulong results (only 4 or 8 bytes). These work great with database indexes and allow simpler queries. Instead of WHERE col1 = ... AND col2 = ..., you can write WHERE Hash = .... This is especially useful when your table has hundreds of millions of rows.