Skip to main content

splitmix64_finalize

Function splitmix64_finalize 

Source
pub fn splitmix64_finalize(z: u64) -> u64
Expand description

splitmix64’s finalizer — the same function std/core’s mix64 computes.

std/core writes it in signed Nova with masked shifts, because Nova’s >> on a negative Int sign-extends; on u64 here the plain form is the same function. Its constants correspond: Nova’s -4658895280553007687 is 0xbf58476d1ce4e5b9 and -7723592293110705685 is 0x94d049bb133111eb.

This is LOAD-BEARING, not decoration. Map selects buckets with hash & (cap - 1) – the low bits – and FNV-1a’s low bits barely depend on its starting value: bit 0 of an FNV-1a result is bit 0 of the basis XOR the parity of the input bytes’ low bits, so changing the basis flips bit 0 identically for both keys of a colliding pair and leaves the collision standing. Measured, seeding alone left 30 of a constructed 48-key attack in one bucket and moved only 66.7% of keys at capacity 8; with this finalizer the same attack falls to 3 and 87.3% of keys move, against an ideal of 87.5%. The spec’s section 2 carries the method and the full figures.

pub for one reason: nova-driver’s async_end_to_end tests tie this function to std/core’s mix64 by running Nova’s .hash() through the real pipeline and comparing against this one, over a seed both sides read from the same process-global OnceLock. The records have long said the two compute the same function and nothing asserted it.

This is Rust-internal visibility and creates no Nova surface, which is what distinguishes it from ADR 0005’s prohibition on publishing mix64. That prohibition is about Nova’s namespace: publishing mix64 would make its exact definition a compatibility surface and forecloses the freedom ADR 0005 reserves to replace its constants or rounds. Nothing here reaches a Nova program, and mix64 stays module-private.