Correctness proofs for the NTT-based binary convolution pipeline.
The core FFT correctness lemma: nttInplace v false roots computes the DFT of the
Montgomery-encoded input v.map toMont. That is, for each output index k,
result[k] = Σ_j (toMont (v[j])) · ω^(j·k) in ZMod mod32.toNat.
── Top-level ───────────────────────────────────────────────────────────────── #
Proof of circular_convolution_gf2_correct #
Proof outline:
- The guard
m < 2 * nis vacuous when2 * nfits in UInt64 (fromnext_pow2_ge). - The NTT pipeline computes
result[k]= the k-th value of the integer-valued LINEAR convolution of the 0/1 embeddings ofaandb(Montgomery factors cancel: forward NTT maps input to Montgomery domain, inverse NTT maps back out). - Folding:
result[i] + result[i+n]= the integer-valued CIRCULAR convolution at index i (valid because fa, fb have support in [0,n) and m ≥ 2n prevents aliasing). - Bit-0 of the folded sum equals the GF(2) circular convolution bit.
The integer-valued linear convolution of the 0/1 embeddings at index k.
Equations
Instances For
Integer circular convolution of two UInt32 vectors.
(fa ⊛_m fb)[k] = Σ_j fa[j] * fb[(k - j) mod m]
This is what the NTT pipeline computes internally (modulo mod32).
Equations
Instances For
ω = primRoot ^ ((p-1)/m) is a primitive m-th root of unity in ZMod p.
Apply IsPrimitiveRoot.pow_of_dvd to the primitive (p-1)-th root primRoot
(prim_root_PRIM_ROOT) with divisor d = (p-1)/m; it yields a primitive ((p-1)/d)-th
root, leaving three side goals: the order (p-1)/d = m, that d ≠ 0, and that d ∣ (p-1).
The NTT pipeline result at index k equals the integer linear convolution at k. Key insight: forward NTT converts inputs to Montgomery domain (× R); inverse NTT converts back (× R⁻¹), so the net Montgomery factor is 1 and results are plain integers. Also uses the NTT convolution theorem: pointwise product in frequency domain = circular convolution in time domain (= linear convolution here, due to zero-padding).