Lucerna.Gates.Hashing (Lucerna v0.0.1-alpha.0)

The frozen bucketing contract (never change this):

bucket = murmur3_x86_32(utf8("#{salt}:#{unit_id}"), seed 0) % 10000

Buckets are basis points in [0, 10000). Salts are stored in the runtime, never derived from keys. Every SDK in every language must reproduce these values bit-for-bit — the golden vectors in sdks/core/src/vectors.json enforce it.

Summary

Functions

The unit's bucket for a salt, in basis points [0, 10000).

MurmurHash3 x86 32-bit over the UTF-8 bytes of input, as uint32.

Functions

bucket(salt, unit_id)

@spec bucket(String.t(), String.t()) :: non_neg_integer()

The unit's bucket for a salt, in basis points [0, 10000).

murmur3(input, seed \\ 0)

@spec murmur3(String.t(), non_neg_integer()) :: non_neg_integer()

MurmurHash3 x86 32-bit over the UTF-8 bytes of input, as uint32.

Elixir strings are already UTF-8 binaries, so the four-byte blocks fall out of little-endian binary matching; 32-bit wraparound is emulated by masking after every multiply/add.