Algorithm Search⌘K

Proofs: FNV hash

These are the human proofs of FNV hash, at full length.

FNV computes its recurrence, and its steps are bijections of the state full

This proof shows: correctness, termination.

Notation. Fix a width ww and write N=2wN = 2^w, P=PwP = P_w and O=OwO = O_w. All states are in {0,…,N−1}\{0, \ldots, N - 1\}. For a byte β∈{0,…,255}\beta \in \{0, \ldots, 255\}, let fβ(x)=((x⊕β)⋅P) mod Nf_\beta(x) = ((x \oplus \beta) \cdot P) \bmod N be one step of FNV-1a and gβ(x)=((x⋅P) mod N)⊕βg_\beta(x) = ((x \cdot P) \bmod N) \oplus \beta one step of FNV-1. For a byte string z=z0⋯zk−1z = z_0 \cdots z_{k-1}, let Fz=fzk−1∘⋯∘fz0F_z = f_{z_{k-1}} \circ \cdots \circ f_{z_0}, with FεF_\varepsilon the identity, so that the FNV-1a hash of zz is Fz(O)F_z(O). The XOR of a state with a byte stays below NN because N≥256N \ge 256.

Lemma 1 (the procedure computes the recurrence). FNV-1A stops after nn passes of its loop and returns Fb(O)F_b(O).

Proof. The loop at line L2 runs for i=0,…,n−1i = 0, \ldots, n - 1, so it makes nn passes and stops. Let hih_i be the value of hh after ii passes. Then h0=Oh_0 = O by line L1. Lines L3 and L4 replace hih_i by ((hi⊕b[i])⋅P) mod N=fb[i](hi)((h_i \oplus b[i]) \cdot P) \bmod N = f_{b[i]}(h_i), so hi+1=fb[i](hi)h_{i+1} = f_{b[i]}(h_i). By induction on ii, hi=Fb[0]⋯b[i−1](O)h_i = F_{b[0] \cdots b[i-1]}(O), and line L5 returns hn=Fb(O)h_n = F_b(O). □\square

Lemma 2 (each step is a bijection). For every byte β\beta, fβf_\beta and gβg_\beta are bijections of {0,…,N−1}\{0, \ldots, N - 1\}.

Proof. The map x↦x⊕βx \mapsto x \oplus \beta is its own inverse on {0,…,N−1}\{0, \ldots, N - 1\}, so it is a bijection. PP is odd and NN is a power of 2, so gcd⁡(P,N)=1\gcd(P, N) = 1 and PP has an inverse P−1P^{-1} modulo NN; the map x↦(xP) mod Nx \mapsto (x P) \bmod N has the inverse y↦(yP−1) mod Ny \mapsto (y P^{-1}) \bmod N. A composition of bijections is a bijection. □\square

Lemma 3 (suffix extension). For all byte strings u,v,zu, v, z, the FNV-1a hashes satisfy h(uz)=h(vz)h(uz) = h(vz) if and only if h(u)=h(v)h(u) = h(v). The same holds for FNV-1.

Proof. By Lemma 1, h(uz)=Fz(Fu(O))=Fz(h(u))h(uz) = F_z(F_u(O)) = F_z(h(u)), and likewise h(vz)=Fz(h(v))h(vz) = F_z(h(v)). By Lemma 2, FzF_z is a composition of bijections, so it is injective, and Fz(h(u))=Fz(h(v))F_z(h(u)) = F_z(h(v)) holds exactly when h(u)=h(v)h(u) = h(v). For FNV-1, use gg in place of ff. □\square

Lemma 4 (one changed byte). If xx and yy have the same length and differ in exactly one position, then h(x)≠h(y)h(x) \ne h(y), for FNV-1a and for FNV-1.

Proof. Write x=uαzx = u \alpha z and y=uβzy = u \beta z with bytes α≠β\alpha \ne \beta. The state after uu is the same value ss for both. For FNV-1a, s⊕α≠s⊕βs \oplus \alpha \ne s \oplus \beta, and multiplication by PP modulo NN is injective (Lemma 2), so fα(s)≠fβ(s)f_\alpha(s) \ne f_\beta(s). For FNV-1, (sP mod N)⊕α≠(sP mod N)⊕β(sP \bmod N) \oplus \alpha \ne (sP \bmod N) \oplus \beta, so gα(s)≠gβ(s)g_\alpha(s) \ne g_\beta(s). The remaining steps for zz form an injective map by Lemma 2, so the final states differ. □\square

Lemma 5 (low bits). For 1≤k≤w1 \le k \le w, h(b) mod 2kh(b) \bmod 2^k depends only on O mod 2kO \bmod 2^k and on the values b[i] mod 2kb[i] \bmod 2^k. Bit 0 of h(b)h(b) equals bit 0 of OO XOR the parity of the number of indices ii with b[i]b[i] odd.

Proof. Bit jj of x⊕βx \oplus \beta is bit jj of xx XOR bit jj of β\beta, so (x⊕β) mod 2k=(x mod 2k)⊕(β mod 2k)(x \oplus \beta) \bmod 2^k = (x \bmod 2^k) \oplus (\beta \bmod 2^k). Since 2k2^k divides NN, (xP mod N) mod 2k=xP mod 2k=((x mod 2k)(P mod 2k)) mod 2k(xP \bmod N) \bmod 2^k = xP \bmod 2^k = ((x \bmod 2^k)(P \bmod 2^k)) \bmod 2^k. So fβ(x) mod 2kf_\beta(x) \bmod 2^k is a function of x mod 2kx \bmod 2^k and β mod 2k\beta \bmod 2^k. By induction on the steps, as in Lemma 1, the state after ii bytes modulo 2k2^k is a function of O mod 2kO \bmod 2^k and b[0] mod 2k,…,b[i−1] mod 2kb[0] \bmod 2^k, \ldots, b[i-1] \bmod 2^k. For k=1k = 1: PP is odd, so multiplication by PP keeps bit 0, and the XOR with b[i]b[i] flips bit 0 exactly when b[i]b[i] is odd. So bit 0 of the final state is bit 0 of OO, flipped once for each odd byte. □\square

Theorem. FNV-1A stops on every input and returns the FNV-1a hash Fb(O)F_b(O) defined by the recurrence. The hash satisfies the suffix extension property, never maps two strings of one length that differ in one byte to one value, and has the low-bit property of Lemma 5.

Proof. Termination and the returned value are Lemma 1. The other claims are Lemmas 3, 4 and 5. ■\blacksquare

Remark (what is not proved). No statement here bounds the number or the probability of collisions. FNV has no random parameter, and Lemma 3 shows that a single collision, which exists by the pigeonhole principle among any N+1N + 1 inputs, extends to infinitely many.

Back to FNV hash