Documentation

CompPoly.Fields.Binary.AdditiveNTT.Correctness

Additive NTT Correctness #

The stage-wise correctness argument and the final correctness theorem for the Additive NTT.

theorem AdditiveNTT.run_foldlM_modify_eq_foldl {σ : Type} (n : ) (f : σFin nσ) (init : σ) :
(StateT.run (Fin.foldlM n (fun (x : Unit) (i : Fin n) => do modifyThe σ fun (current : σ) => f current i pure ()) ()) init).2 = Fin.foldl n f init

Running a state fold made only of state updates gives the same final state as the corresponding pure fold.

theorem AdditiveNTT.bitsToU_bijective {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (i : Fin r) :

The bitsToU mapping is a bijection: showing that iterating bits corresponds exactly to the linear span.

theorem AdditiveNTT.evalWAt_eq_W {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (i : Fin r) (x : L) :
evalWAt β i x = Polynomial.eval x (W 𝔽q β i)

Prove that evalWAt equals the standard definition of W_i(x).

theorem AdditiveNTT.evalNormalizedWAt_eq_normalizedW {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (i : Fin r) (x : L) :

Prove that evalNormalizedWAt equals the standard definition of Ŵ_i(x).

theorem AdditiveNTT.computableTwiddleFactor_eq_twiddleFactor {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (i : Fin ) :
computableTwiddleFactor β h_ℓ_add_R_rate i, = twiddleFactor 𝔽q β h_ℓ_add_R_rate i,

Prove that computableTwiddleFactor equals the standard definition of twiddleFactor.

theorem AdditiveNTT.computableNTTStage_eq_NTTStage {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (i : Fin ) :
computableNTTStage β h_ℓ_add_R_rate i, = NTTStage 𝔽q β h_ℓ_add_R_rate i,

Prove that computableNTTStage equals the standard definition of NTTStage.

theorem AdditiveNTT.W_eval_succ_eq_mul_add {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] (i : Fin r) (h_i_add_1 : i + 1 < r) (x : L) :
Polynomial.eval x (W 𝔽q β (i + 1)) = Polynomial.eval x (W 𝔽q β i) * (Polynomial.eval x (W 𝔽q β i) + Polynomial.eval (β i) (W 𝔽q β i))

In the binary-field setting, the subspace vanishing polynomials satisfy the runtime recurrence used by evalWAtCachedConstants.

theorem AdditiveNTT.evalWAtCachedConstantsLoop_eq_W_of_correct {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] (constants : Array L) (i : Fin r) (j : ) (x acc : L) (hsize : constants.size = i) (hj_le : j i) (hj_lt_r : j < r) (hacc : acc = Polynomial.eval x (W 𝔽q β j, hj_lt_r)) (hcorrect : ∀ (k : ), j k∀ (hki : k < i), constants.getD k 0 = Polynomial.eval (β k, ) (W 𝔽q β k, )) :
evalWAtCachedConstantsLoop constants j acc = Polynomial.eval x (W 𝔽q β i)

The cached evaluator computes W_i(x) when the cache stores exactly W_k(β_k) for k < i. This is stated for the internal loop so later proofs can resume from a partially consumed cache.

theorem AdditiveNTT.evalWAtCachedConstants_eq_W_of_correct {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] (constants : Array L) (i : Fin r) (x : L) (hsize : constants.size = i) (hcorrect : ∀ (k : ) (hki : k < i), constants.getD k 0 = Polynomial.eval (β k, ) (W 𝔽q β k, )) :
evalWAtCachedConstants constants x = Polynomial.eval x (W 𝔽q β i)

The cached evaluator computes W_i(x) from a complete cache for stage i.

theorem AdditiveNTT.subspacePolynomialConstantsArrayLoop_spec {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (i : Fin r) (k : ) (constants : Array L) (hsize : constants.size = k) (hk_le : k i) (hcorrect : ∀ (m : ) (hmk : m < k), constants.getD m 0 = Polynomial.eval (β m, ) (W 𝔽q β m, )) :
have result := subspacePolynomialConstantsArrayLoop β i k constants; result.size = i ∀ (m : ) (hmi : m < i), result.getD m 0 = Polynomial.eval (β m, ) (W 𝔽q β m, )

The constants-array builder preserves the invariant that entry k stores W_k(β_k), and finishes with one entry for every k < i.

theorem AdditiveNTT.subspacePolynomialConstantsArrayLoop_size {r : } {L : Type} [Field L] (β : Fin rL) {R_rate : } (i : Fin r) (k : ) (constants : Array L) (hsize : constants.size = k) (hk_le : k i) :
theorem AdditiveNTT.subspacePolynomialConstantsArray_size {r : } {L : Type} [Field L] (β : Fin rL) {R_rate : } (i : Fin r) :
theorem AdditiveNTT.subspacePolynomialConstantsArray_getD {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (i : Fin r) (m : ) (hm : m < i) :
(subspacePolynomialConstantsArray β i).getD m 0 = Polynomial.eval (β m, ) (W 𝔽q β m, )
theorem AdditiveNTT.evalWAtCachedConstants_subspacePolynomialConstantsArray_eq_W {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (i : Fin r) (x : L) :
theorem AdditiveNTT.computableNormalizedWValuesArray_getD {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (i : Fin ) (k : Fin ( + R_rate - i - 1)) :
(computableNormalizedWValuesArray β h_ℓ_add_R_rate i).getD (↑k) 0 = Polynomial.eval (β i + 1 + k, ) (normalizedW 𝔽q β i, )
theorem AdditiveNTT.computableTwiddleTableArray_getD {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (i : Fin ) (u : Fin (2 ^ ( + R_rate - i - 1))) :
(computableTwiddleTableArray β h_ℓ_add_R_rate i).getD (↑u) 0 = twiddleFactor 𝔽q β h_ℓ_add_R_rate i, u
theorem AdditiveNTT.arrayToFinFunction_tileCoeffsArray {L : Type} [Field L] {R_rate : } (a : Fin (2 ^ )L) :
arrayToFinFunction (2 ^ ( + R_rate)) (tileCoeffsArray R_rate a) = tileCoeffs a
theorem AdditiveNTT.computableNTTStageArray_eq_computableNTTStage {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (i : Fin ) (b : Array L) :
arrayToFinFunction (2 ^ ( + R_rate)) (computableNTTStageArray i (computableTwiddleTableArray β h_ℓ_add_R_rate i) b) = computableNTTStage β h_ℓ_add_R_rate i, (arrayToFinFunction (2 ^ ( + R_rate)) b)
theorem AdditiveNTT.computableAdditiveNTT_eq_additiveNTT {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (a : Fin (2 ^ )L) :
computableAdditiveNTT β h_ℓ_add_R_rate a = additiveNTT 𝔽q β h_ℓ_add_R_rate a

The proof-oriented computable additive NTT agrees with the abstract additive NTT specification.

theorem AdditiveNTT.computableAdditiveNTTFastAction_run_eq_fold {r : } {L : Type} [Field L] (β : Fin rL) {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (a : Fin (2 ^ )L) :
(StateT.run (computableAdditiveNTTFastAction β h_ℓ_add_R_rate a) #[]).1 = Fin.foldl (fun (current : Array L) (i : Fin ) => have stage := - 1 - i, ; have twiddles := computableTwiddleTableArray β h_ℓ_add_R_rate stage; computableNTTStageArray stage twiddles current) (tileCoeffsArray R_rate a)
theorem AdditiveNTT.computableAdditiveNTTFast_eq_computableAdditiveNTT {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (a : Fin (2 ^ )L) :
arrayToFinFunction (2 ^ ( + R_rate)) (computableAdditiveNTTFast β h_ℓ_add_R_rate a) = computableAdditiveNTT β h_ℓ_add_R_rate a

The fast additive NTT array implementation is extensionally equal to the proof-oriented computable implementation after converting its output array to a Fin-indexed function.

This is the preferred proof boundary for the fast path: once this theorem is proved, correctness against the abstract additive NTT specification follows from computableAdditiveNTT_eq_additiveNTT.

theorem AdditiveNTT.computableAdditiveNTTFast_eq_additiveNTT {r : } [NeZero r] {L : Type} [Field L] [Fintype L] [DecidableEq L] {𝔽q : Type} [Field 𝔽q] [Fintype 𝔽q] [hFq_card : Fact (Fintype.card 𝔽q = 2)] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (a : Fin (2 ^ )L) :
arrayToFinFunction (2 ^ ( + R_rate)) (computableAdditiveNTTFast β h_ℓ_add_R_rate a) = additiveNTT 𝔽q β h_ℓ_add_R_rate a

The fast additive NTT array implementation is correct against the abstract additive NTT specification after converting its output array to a Fin-indexed function.

theorem AdditiveNTT.initial_tiled_coeffs_correctness {r : } [NeZero r] {L : Type u} [Field L] [Fintype L] [DecidableEq L] (𝔽q : Type u) [Field 𝔽q] [Fintype 𝔽q] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] [h_β₀_eq_1 : Fact (β 0 = 1)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (h_ℓ : r) (a : Fin (2 ^ )L) :
have b := tileCoeffs a; additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate b a ,
theorem AdditiveNTT.NTTStage_correctness {r : } [NeZero r] {L : Type u} [Field L] [Fintype L] [DecidableEq L] (𝔽q : Type u) [Field 𝔽q] [Fintype 𝔽q] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (i : Fin ) (input_buffer : Fin (2 ^ ( + R_rate))L) (original_coeffs : Fin (2 ^ )L) :
additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate input_buffer original_coeffs i + 1, additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate (NTTStage 𝔽q β h_ℓ_add_R_rate i, input_buffer) original_coeffs i,
theorem AdditiveNTT.foldl_NTTStage_inductive_aux {r : } [NeZero r] {L : Type u} [Field L] [Fintype L] [DecidableEq L] (𝔽q : Type u) [Field 𝔽q] [Fintype 𝔽q] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] [h_β₀_eq_1 : Fact (β 0 = 1)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (h_ℓ : r) (k : Fin ( + 1)) (original_coeffs : Fin (2 ^ )L) :
additiveNTTInvariant 𝔽q β h_ℓ_add_R_rate (Fin.foldl (↑k) (fun (current_b : Fin (2 ^ ( + R_rate))L) (i : Fin k) => NTTStage 𝔽q β h_ℓ_add_R_rate - i - 1, current_b) (tileCoeffs original_coeffs)) original_coeffs - k,
theorem AdditiveNTT.additiveNTT_correctness {r : } [NeZero r] {L : Type u} [Field L] [Fintype L] [DecidableEq L] (𝔽q : Type u) [Field 𝔽q] [Fintype 𝔽q] [h_Fq_char_prime : Fact (Nat.Prime (ringChar 𝔽q))] [Algebra 𝔽q L] (β : Fin rL) [hβ_lin_indep : Fact (LinearIndependent 𝔽q β)] [h_β₀_eq_1 : Fact (β 0 = 1)] {R_rate : } (h_ℓ_add_R_rate : + R_rate < r) (h_ℓ : r) (original_coeffs : Fin (2 ^ )L) (output_buffer : Fin (2 ^ ( + R_rate))L) (h_alg : output_buffer = additiveNTT 𝔽q β h_ℓ_add_R_rate original_coeffs) :
have P := polynomialFromNovelCoeffs 𝔽q β h_ℓ original_coeffs; ∀ (j : Fin (2 ^ ( + R_rate))), output_buffer j = Polynomial.eval (evaluationPointω 𝔽q β h_ℓ_add_R_rate 0, j) P