Table of Contents

CityHash Class

Definition

Namespace
Bodu.IO.Hashing
Assembly
Bodu.IO.Hashing.dll
Package
Bodu.IO.Hashing 1.0.0
Source
CityHash.cs

Base class for the CityHash family of non-cryptographic hash algorithms developed by Google. See the CityHash reference repository for the specification.

public abstract class CityHash : NonCryptographicHashAlgorithm, IDisposable
Inheritance
CityHash
Implements
Derived
Inherited Members
Extension Methods

Remarks

CityHash is a one-shot algorithm. To satisfy the incremental input contract of NonCryptographicHashAlgorithm, this base class accumulates all bytes delivered through Append(ReadOnlySpan<byte>) into an internal buffer and invokes the derived variant's ComputeHashCore(ReadOnlySpan<byte>) from GetCurrentHashCore(Span<byte>) once all input is available.

Shared 32-bit mixing primitives (Mix(uint), Mur(uint, uint), Permute3(ref uint, ref uint, ref uint)) and shared 64-bit primitives (ShiftMix(ulong), HashLen16(ulong, ulong), HashLen16(ulong, ulong, ulong), WeakHashLen32WithSeeds(ulong, ulong, ulong, ulong, ulong, ulong), WeakHashLen32WithSeeds(ReadOnlySpan<byte>, ulong, ulong), Hash64Len0to16(ReadOnlySpan<byte>)) and algorithm constants are defined here and are available to all derived variants. Supported output sizes are 32, 64, and 128 bits.

When to choose CityHash. CityHash was designed for short-to-medium strings on 64-bit CPUs and tends to outperform MurmurHash3 on long inputs while matching it on short ones. It is the typical choice for in-memory hash tables, fingerprinting, and content-based sharding when both throughput and distribution quality matter. Pick CityHash32 for 32-bit slot indexes, CityHash64 for general-purpose 64-bit hashing, and CityHash128 for low-collision fingerprinting of large key spaces. For very small fixed-length keys, Fnv is simpler and competitive; for adversarial inputs use a member of Bodu.Security.Cryptography instead.

Buffering caveat. Because the algorithm needs the whole message before mixing, the base class buffers every appended byte until GetCurrentHashCore(Span<byte>) is called. Memory consumption grows linearly with input length between resets - avoid feeding it multi-gigabyte streams. Instances are not thread-safe; share behind explicit synchronization.

important

CityHash is not cryptographically secure. It must not be used for password hashing, digital signatures, or any application that requires collision resistance under adversarial conditions.

using Bodu.IO.Hashing;
using Bodu.IO.Hashing.Extensions;

// 64-bit fingerprint of a content blob - typical use case.
var city = new CityHash64();
byte[] fingerprint = city.ComputeHash(blob);

// Stream-hash a moderately sized file.
// Note: CityHash buffers fully - prefer Crc / xxHash for very large streams.
using FileStream fs = File.OpenRead("payload.bin");
byte[] streamDigest = city.ComputeHash(fs);

Constructors

CityHash(int)

Initializes a new instance of the CityHash class with the specified hash output size.

protected CityHash(int hashSize)

Parameters

hashSize int

The desired hash output size in bits. Must be one of 32, 64, or 128.

Exceptions

ArgumentOutOfRangeException

hashSize is not one of the supported values.

Fields

C1

The first Murmur-style mixing constant used in 32-bit operations.

protected const uint C1 = 3432918353

Field Value

uint

C2

The second Murmur-style mixing constant used in 32-bit operations.

protected const uint C2 = 461845907

Field Value

uint

HashMagic

The 32-bit finalization magic constant applied during the iterative mixing phase.

protected const uint HashMagic = 3864292196

Field Value

uint

K0

The first 64-bit mixing constant, derived from the CityHash reference implementation.

protected const ulong K0 = 14097894508562428199

Field Value

ulong

K1

The second 64-bit mixing constant, derived from the CityHash reference implementation.

protected const ulong K1 = 13011662864482103923

Field Value

ulong

K2

The third 64-bit mixing constant, derived from the CityHash reference implementation.

protected const ulong K2 = 11160318154034397263

Field Value

ulong

K3

The fourth 64-bit constant used by the 128-bit variant to seed the accumulator from the first 16 bytes of input.

protected const ulong K3 = 14504361325974414679

Field Value

ulong

KMul

The prime multiplier used by the 64-bit HashLen16(ulong, ulong) finalization step.

protected const ulong KMul = 11376068507788127593

Field Value

ulong

Methods

Append(ReadOnlySpan<byte>)

When overridden in a derived class, appends the contents of source to the data already processed for the current hash computation.

public override void Append(ReadOnlySpan<byte> source)

Parameters

source ReadOnlySpan<byte>

The data to process.

ComputeHashCore(ReadOnlySpan<byte>)

Performs the full hash computation over the complete accumulated input in a single pass.

protected abstract byte[] ComputeHashCore(ReadOnlySpan<byte> source)

Parameters

source ReadOnlySpan<byte>

The complete input bytes to hash.

Returns

byte[]

A byte array containing the final hash output.

Dispose()

Releases all resources used by the current instance and clears its buffered input state.

public void Dispose()

Remarks

After disposal, subsequent calls to Append(ReadOnlySpan<byte>), Reset(), or GetCurrentHashCore(Span<byte>) throw ObjectDisposedException. Calling Dispose() multiple times is safe and has no effect after the first invocation.

Dispose(bool)

Releases the resources used by the current instance, optionally clearing managed state.

protected virtual void Dispose(bool disposing)

Parameters

disposing bool

true when called from Dispose(); false when called from a finalizer. Managed resources are released only when disposing is true.

Remarks

Override in a derived class to release additional resources owned by the subclass. Always invoke base.Dispose(disposing) from the override so that the buffered input state is released.

GetCurrentHashCore(Span<byte>)

When overridden in a derived class, writes the computed hash value to destination without modifying accumulated state.

protected override void GetCurrentHashCore(Span<byte> destination)

Parameters

destination Span<byte>

The buffer that receives the computed hash value.

Hash64Len0to16(ReadOnlySpan<byte>)

Hashes 0 to 16 bytes to a 64-bit value, selecting a byte-, word-, or double-word code path based on the exact input length.

protected static ulong Hash64Len0to16(ReadOnlySpan<byte> s)

Parameters

s ReadOnlySpan<byte>

The input span. Length must be in the range [0, 16].

Returns

ulong

The 64-bit hash value.

Remarks

An empty input returns K2 directly.

HashLen16(ulong, ulong)

Combines two 64-bit values into a single 64-bit hash using the default KMul multiplier.

protected static ulong HashLen16(ulong u, ulong v)

Parameters

u ulong

The first input value.

v ulong

The second input value.

Returns

ulong

The combined 64-bit hash value.

HashLen16(ulong, ulong, ulong)

Combines two 64-bit values into a single 64-bit hash using a caller-supplied multiplier, applying two rounds of multiply-shift-XOR to thoroughly distribute entropy across all output bits.

protected static ulong HashLen16(ulong u, ulong v, ulong mul)

Parameters

u ulong

The first input value.

v ulong

The second input value.

mul ulong

The multiplier to apply during mixing. Typically a large odd prime.

Returns

ulong

The combined 64-bit hash value.

Mix(uint)

Applies a final avalanche mixing step to a 32-bit value, improving bit diffusion.

protected static uint Mix(uint h)

Parameters

h uint

The 32-bit value to mix.

Returns

uint

The mixed 32-bit result.

Mur(uint, uint)

Applies a single Murmur-style multiply-rotate-XOR step, combining two 32-bit values.

protected static uint Mur(uint a, uint h)

Parameters

a uint

The input value to multiply and fold.

h uint

The accumulator value to combine with the result.

Returns

uint

The result of the Murmur mixing step.

Permute3(ref uint, ref uint, ref uint)

Performs a cyclic three-way permutation of the given values, assigning a ← c, c ← b, b ← a.

protected static void Permute3(ref uint a, ref uint b, ref uint c)

Parameters

a uint

The first value, receives the original value of c.

b uint

The second value, receives the original value of a.

c uint

The third value, receives the original value of b.

Reset()

When overridden in a derived class, resets the hash computation to the initial state.

public override void Reset()

ShiftMix(ulong)

Applies a final 64-bit entropy spreading step by XOR-ing the value with its own 47-bit right shift.

protected static ulong ShiftMix(ulong val)

Parameters

val ulong

The 64-bit value to mix.

Returns

ulong

The mixed 64-bit result.

WeakHashLen32WithSeeds(ReadOnlySpan<byte>, ulong, ulong)

Reads four consecutive 64-bit little-endian words from the specified span and forwards them to WeakHashLen32WithSeeds(ulong, ulong, ulong, ulong, ulong, ulong) along with the provided seeds.

protected static (ulong First, ulong Second) WeakHashLen32WithSeeds(ReadOnlySpan<byte> s, ulong a, ulong b)

Parameters

s ReadOnlySpan<byte>

The input span. Must contain at least 32 bytes starting at offset 0.

a ulong

The first accumulator seed.

b ulong

The second accumulator seed.

Returns

(ulong First, ulong Second)

A tuple containing two independent 64-bit hash values derived from the 32-byte block and seeds.

WeakHashLen32WithSeeds(ulong, ulong, ulong, ulong, ulong, ulong)

Computes a weak 64-bit hash of 32 bytes using six provided seed values, returning a pair of independent 64-bit outputs.

protected static (ulong First, ulong Second) WeakHashLen32WithSeeds(ulong w, ulong x, ulong y, ulong z, ulong a, ulong b)

Parameters

w ulong

The first 64-bit word of the input block.

x ulong

The second 64-bit word of the input block.

y ulong

The third 64-bit word of the input block.

z ulong

The fourth 64-bit word of the input block.

a ulong

The first accumulator seed.

b ulong

The second accumulator seed.

Returns

(ulong First, ulong Second)

A tuple containing two independent 64-bit hash values derived from the mixed input and seeds.

Applies to

ProductVersions
.NET8, 10

See Also