diff --git a/CompPoly.lean b/CompPoly.lean index 46108405..d24b44c0 100644 --- a/CompPoly.lean +++ b/CompPoly.lean @@ -80,6 +80,47 @@ import CompPoly.Fields.Binary.BF128Ghash.Prelude import CompPoly.Fields.Binary.BF128Ghash.XPowTwoPowGcdCertificate import CompPoly.Fields.Binary.BF128Ghash.XPowTwoPowModCertificate import CompPoly.Fields.Binary.Common +import CompPoly.Fields.Binary.Extension.Basic +import CompPoly.Fields.Binary.Extension.Enumeration +import CompPoly.Fields.Binary.Extension.Impl +import CompPoly.Fields.Binary.Extension.Prelude +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_32 +import CompPoly.Fields.Binary.GF2_32.Basic +import CompPoly.Fields.Binary.GF2_32.Impl +import CompPoly.Fields.Binary.GF2_32.Prelude +import CompPoly.Fields.Binary.GF2_32.Primitive +import CompPoly.Fields.Binary.GF2_32.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_32.RootContexts +import CompPoly.Fields.Binary.GF2_32.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_32.XPowTwoPowModCertificate +import CompPoly.Fields.Binary.GF2_48 +import CompPoly.Fields.Binary.GF2_48.Basic +import CompPoly.Fields.Binary.GF2_48.Impl +import CompPoly.Fields.Binary.GF2_48.Prelude +import CompPoly.Fields.Binary.GF2_48.Primitive +import CompPoly.Fields.Binary.GF2_48.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_48.RootContexts +import CompPoly.Fields.Binary.GF2_48.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_48.XPowTwoPowModCertificate +import CompPoly.Fields.Binary.GF2_64 +import CompPoly.Fields.Binary.GF2_64.Basic +import CompPoly.Fields.Binary.GF2_64.Impl +import CompPoly.Fields.Binary.GF2_64.Prelude +import CompPoly.Fields.Binary.GF2_64.Primitive +import CompPoly.Fields.Binary.GF2_64.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_64.RootContexts +import CompPoly.Fields.Binary.GF2_64.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_64.XPowTwoPowModCertificate +import CompPoly.Fields.Binary.GF2_72 +import CompPoly.Fields.Binary.GF2_72.Basic +import CompPoly.Fields.Binary.GF2_72.Impl +import CompPoly.Fields.Binary.GF2_72.Prelude +import CompPoly.Fields.Binary.GF2_72.Primitive +import CompPoly.Fields.Binary.GF2_72.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_72.RootContexts +import CompPoly.Fields.Binary.GF2_72.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_72.XPowTwoPowModCertificate import CompPoly.Fields.Binary.Tower.Abstract.Algebra import CompPoly.Fields.Binary.Tower.Abstract.Basis import CompPoly.Fields.Binary.Tower.Abstract.Core @@ -218,6 +259,10 @@ import CompPoly.Univariate.Roots.Correctness import CompPoly.Univariate.Roots.Enumeration import CompPoly.Univariate.Roots.Extraction import CompPoly.Univariate.Roots.RootProduct +import CompPoly.Univariate.Roots.Shoup +import CompPoly.Univariate.Roots.Shoup.Basic +import CompPoly.Univariate.Roots.Shoup.Correctness +import CompPoly.Univariate.Roots.Shoup.FrobeniusLinear import CompPoly.Univariate.Roots.SmoothSubgroup import CompPoly.Univariate.Roots.SmoothSubgroup.Basic import CompPoly.Univariate.Roots.SmoothSubgroup.Correctness diff --git a/CompPoly/Fields/Binary/Extension/Basic.lean b/CompPoly/Fields/Binary/Extension/Basic.lean new file mode 100644 index 00000000..e2d2a811 --- /dev/null +++ b/CompPoly/Fields/Binary/Extension/Basic.lean @@ -0,0 +1,110 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Prelude +import Mathlib.FieldTheory.Finite.Basic +import Mathlib.RingTheory.AdjoinRoot + +/-! +# Direct Binary-Extension Quotient Fields + +Generic quotient/specification surface for direct binary extensions +`GF(2)[X] / (X^m + tail)`. + +The field and cardinality instances are conditional on a future +`Fact (Irreducible (polynomial data))`, so concrete modules can expose the type +early while certificate files later make it a genuine finite field. +-/ + +namespace BinaryField + +namespace Extension + +open Polynomial AdjoinRoot + +noncomputable section + +/-- Quotient/specification carrier for a direct binary extension. -/ +abbrev SpecField (data : DefiningPolynomialData) : Type := + AdjoinRoot (polynomial data) + +/-- The quotient specification is inhabited. -/ +instance instInhabitedSpecField (data : DefiningPolynomialData) : + Inhabited (SpecField data) := + ⟨0⟩ + +/-- Conditional field instance, available once irreducibility is certified. -/ +instance instFieldSpecField (data : DefiningPolynomialData) + [Fact (Irreducible (polynomial data))] : + Field (SpecField data) := + AdjoinRoot.instField + +/-- Conditional nontriviality, available once irreducibility is certified. -/ +instance instNontrivialSpecField (data : DefiningPolynomialData) + [Fact (Irreducible (polynomial data))] : + Nontrivial (SpecField data) := + inferInstance + +/-- Algebra structure over `GF(2)`. -/ +instance instAlgebraSpecField (data : DefiningPolynomialData) : + Algebra (ZMod 2) (SpecField data) := + AdjoinRoot.instAlgebra (polynomial data) + +/-- Conditional characteristic-two instance, available once irreducibility is certified. -/ +instance instCharTwoSpecField (data : DefiningPolynomialData) + [Fact (Irreducible (polynomial data))] : + CharP (SpecField data) 2 := by + haveI : CharP (ZMod 2) 2 := inferInstance + exact charP_of_injective_algebraMap' (ZMod 2) 2 + +/-- Canonical embedding of `GF(2)` into the quotient specification. -/ +def ofGF2 (data : DefiningPolynomialData) : ZMod 2 →+* SpecField data := + algebraMap (ZMod 2) (SpecField data) + +/-- The quotient root/generator. -/ +def root (data : DefiningPolynomialData) : SpecField data := + AdjoinRoot.root (polynomial data) + +/-- The quotient root satisfies the defining polynomial. -/ +theorem root_satisfies_polynomial (data : DefiningPolynomialData) : + eval₂ (algebraMap (ZMod 2) (SpecField data)) (root data) + (polynomial data) = 0 := by + unfold root + exact AdjoinRoot.eval₂_root (polynomial data) + +/-- Conditional finite type, available once irreducibility is certified. -/ +instance instFintypeSpecField (data : DefiningPolynomialData) + [Fact (Irreducible (polynomial data))] : + Fintype (SpecField data) := by + have hpoly_ne_zero : polynomial data ≠ 0 := + Irreducible.ne_zero (Fact.out : Irreducible (polynomial data)) + let pb := AdjoinRoot.powerBasis hpoly_ne_zero + letI : Module.Finite (ZMod 2) (SpecField data) := PowerBasis.finite pb + haveI : Finite (SpecField data) := by + have : Module.finrank (ZMod 2) (SpecField data) = pb.dim := + PowerBasis.finrank pb + exact Finite.of_equiv (Fin pb.dim →₀ ZMod 2) (pb.basis.repr.toEquiv.symm) + exact Fintype.ofFinite (SpecField data) + +/-- Cardinality of a certified direct binary-extension quotient. -/ +theorem specField_card (data : DefiningPolynomialData) + [Fact (Irreducible (polynomial data))] : + Fintype.card (SpecField data) = 2 ^ data.degree := by + rw [Module.card_eq_pow_finrank (K := ZMod 2) (V := SpecField data)] + have hpoly_ne_zero : polynomial data ≠ 0 := + Irreducible.ne_zero (Fact.out : Irreducible (polynomial data)) + let pb := AdjoinRoot.powerBasis hpoly_ne_zero + rw [PowerBasis.finrank pb] + have h_pb_dim : pb.dim = (polynomial data).natDegree := by + rfl + rw [h_pb_dim, polynomial_natDegree] + norm_num + +end + +end Extension + +end BinaryField diff --git a/CompPoly/Fields/Binary/Extension/Enumeration.lean b/CompPoly/Fields/Binary/Extension/Enumeration.lean new file mode 100644 index 00000000..0833c338 --- /dev/null +++ b/CompPoly/Fields/Binary/Extension/Enumeration.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Impl +import CompPoly.Univariate.Roots.Enumeration + +/-! +# Direct Binary-Extension Field Enumerations + +Lazy finite-field enumeration contexts for executable direct binary-extension +carriers. +-/ + +namespace BinaryField + +namespace Extension + +namespace Concrete + +open CompPoly.CPolynomial.Roots.FiniteField + +variable (params : ExecutableParams) + +private theorem toNat_lt (a : ConcreteField params) : + toNat params a < fieldSize params.degree := by + simpa [toNat, toBitVec, fieldSize] using (toBitVec params a).isLt + +private theorem ofNat_toNat (a : ConcreteField params) : + ofNat params (toNat params a) = a := by + apply BitVec.eq_of_toNat_eq + simp [toNat, toBitVec, ofNat, ofBitVec] + +/-- Lazy complete enumeration for a direct executable binary-extension carrier. -/ +def fieldEnumeration : FieldEnumeration (ConcreteField params) where + size := fieldSize params.degree + elem i := ofNat params i.val + complete := by + intro a + exact ⟨⟨toNat params a, toNat_lt params a⟩, ofNat_toNat params a⟩ + +end Concrete + +end Extension + +end BinaryField diff --git a/CompPoly/Fields/Binary/Extension/Impl.lean b/CompPoly/Fields/Binary/Extension/Impl.lean new file mode 100644 index 00000000..1235a15f --- /dev/null +++ b/CompPoly/Fields/Binary/Extension/Impl.lean @@ -0,0 +1,1099 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Basic +import Mathlib.Data.BitVec + +/-! +# Direct Binary-Extension Executable Operations + +Executable `BitVec` operations for direct binary extensions. These definitions +are the computation layer used by concrete fields; algebraic field instances and +operation-equivalence proofs are supplied only after irreducibility and reduction +certificates are available. +-/ + +namespace BinaryField + +namespace Extension + +open Polynomial + +/-- Executable metadata for a direct binary extension. -/ +structure ExecutableParams where + degree : Nat + tailExponents : List Nat + tailExponents_bound : ∀ exponent ∈ tailExponents, exponent < degree + +/-- Executable carrier for a direct binary extension. -/ +@[reducible] +def ConcreteField (params : ExecutableParams) : Type := + BitVec params.degree + +namespace Concrete + +variable (params : ExecutableParams) + +/-- View an executable field element as its raw bit-vector representation. -/ +def toBitVec (a : ConcreteField params) : BitVec params.degree := + a + +/-- Reinterpret a raw bit-vector as an executable field element. -/ +def ofBitVec (a : BitVec params.degree) : ConcreteField params := + a + +@[simp] +lemma toBitVec_ofBitVec (a : BitVec params.degree) : + toBitVec params (ofBitVec params a) = a := + rfl + +@[simp] +lemma ofBitVec_toBitVec (a : ConcreteField params) : + ofBitVec params (toBitVec params a) = a := + rfl + +/-- Raw natural-number encoding of an executable field element. -/ +def toNat (a : ConcreteField params) : Nat := + (toBitVec params a).toNat + +/-- Raw bit-pattern constructor. This is not a field `NatCast`. -/ +def ofNat (n : Nat) : ConcreteField params := + ofBitVec params (BitVec.ofNat params.degree n) + +/-- Zero bit-pattern. -/ +def zero : ConcreteField params := + ofNat params 0 + +/-- One bit-pattern. -/ +def one : ConcreteField params := + ofNat params 1 + +/-- Polynomial-basis generator bit-pattern, representing `X`. -/ +def root : ConcreteField params := + ofNat params 2 + +/-- Characteristic-two addition by XOR. -/ +def add (a b : ConcreteField params) : ConcreteField params := + ofBitVec params (toBitVec params a ^^^ toBitVec params b) + +/-- Characteristic-two negation. -/ +def neg (a : ConcreteField params) : ConcreteField params := + a + +/-- Characteristic-two subtraction by XOR. -/ +def sub (a b : ConcreteField params) : ConcreteField params := + add params a b + +/-- One high-degree reduction step for `X^degree + tail`. -/ +def reduceNatStep (x : Nat) (exponent : Nat) : Nat := + if x.testBit exponent then + let shift := exponent - params.degree + x ^^^ (1 <<< exponent) ^^^ sparseMulByNat params.tailExponents (1 <<< shift) + else + x + +/-- One high-degree reduction step preserves the polynomial residue modulo `P`. -/ +theorem reduceNatStep_mod_eq {P : Polynomial (ZMod 2)} + (hP_ne_zero : P ≠ 0) + (hP : P = X ^ params.degree + sparsePolynomial params.tailExponents) + {x exponent : Nat} + (hdeg : params.degree ≤ exponent) + (hexp : exponent < 2 * params.degree) + (hshift : exponent - params.degree < params.degree) : + toPoly (BitVec.ofNat (2 * params.degree) (reduceNatStep params x exponent)) % P = + toPoly (BitVec.ofNat (2 * params.degree) x) % P := by + unfold reduceNatStep + by_cases hbit : x.testBit exponent + · simp [hbit] + rw [toPoly_xor, toPoly_xor] + let shift := exponent - params.degree + have hOneExp : + toPoly (BitVec.ofNat (2 * params.degree) (1 <<< exponent)) = + (X : Polynomial (ZMod 2)) ^ exponent := by + simpa using Extension.toPoly_one_shiftLeft (w := 2 * params.degree) exponent hexp + have hShiftToNat : ((1 <<< shift : BitVec params.degree).toNat) = 1 <<< shift := by + change (BitVec.ofNat params.degree (1 <<< shift)).toNat = 1 <<< shift + rw [BitVec.toNat_ofNat] + apply Nat.mod_eq_of_lt + rw [Nat.shiftLeft_eq, one_mul] + exact Nat.pow_lt_pow_right (by norm_num) hshift + have hSparse := Extension.toPoly_sparseMulByNat + (w := params.degree) (W := 2 * params.degree) + (hW := by omega) (exponents := params.tailExponents) + (hExp := by + intro e he + have he_lt := params.tailExponents_bound e he + omega) + (a := (1 <<< shift : BitVec params.degree)) + rw [hShiftToNat] at hSparse + have hShiftPoly : + toPoly (BitVec.zeroExtend (2 * params.degree) + (1 <<< shift : BitVec params.degree)) = (X : Polynomial (ZMod 2)) ^ shift := by + rw [Extension.toPoly_zeroExtend (by omega)] + simpa using Extension.toPoly_one_shiftLeft shift hshift + rw [hShiftPoly] at hSparse + have hTerm : + toPoly (BitVec.ofNat (2 * params.degree) (1 <<< exponent)) + + toPoly + (BitVec.ofNat (2 * params.degree) + (sparseMulByNat params.tailExponents (1 <<< shift))) = + (X : Polynomial (ZMod 2)) ^ shift * P := by + rw [hOneExp, hSparse, hP] + have hExpEq : exponent = shift + params.degree := by + unfold shift + omega + rw [hExpEq, pow_add] + ring + rw [add_assoc, hTerm] + rw [CanonicalEuclideanDomain.add_mod_eq (hn := hP_ne_zero)] + rw [CanonicalEuclideanDomain.mul_mod_eq (hn := hP_ne_zero)] + simp only [EuclideanDomain.mod_self, mul_zero, EuclideanDomain.zero_mod, add_zero] + rw [CanonicalEuclideanDomain.mod_mod_eq_mod (hn := hP_ne_zero)] + · have hfalse : x.testBit exponent = false := Bool.eq_false_iff.mpr hbit + simp [hfalse] + +/-- Clearing a known high bit by XOR drops a value below that bit. -/ +theorem xor_clear_high_bit_lt {x exponent : Nat} (hx : x < 2 ^ (exponent + 1)) + (hbit : x.testBit exponent = true) : + x ^^^ (1 <<< exponent) < 2 ^ exponent := by + apply Nat.lt_pow_two_of_testBit + intro i hi + rw [Nat.testBit_xor] + by_cases hie : i = exponent + · subst i + have hOne : (1 <<< exponent).testBit exponent = true := by + rw [Nat.testBit_shiftLeft] + simp + rw [hbit, hOne] + rfl + · have hx_i : x.testBit i = false := by + apply Nat.testBit_eq_false_of_lt + exact lt_of_lt_of_le hx (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) (by omega)) + have hshift_i : (1 <<< exponent).testBit i = false := by + rw [Nat.testBit_shiftLeft] + simp only [ge_iff_le, hi, decide_true, Bool.true_and] + apply Nat.testBit_eq_false_of_lt + exact Nat.one_lt_two_pow (Nat.ne_of_gt (by omega : 0 < i - exponent)) + rw [hx_i, hshift_i] + rfl + +/-- A value below `2^(exponent+1)` with top bit unset is below `2^exponent`. -/ +theorem lt_two_pow_of_top_bit_false {x exponent : Nat} + (hx : x < 2 ^ (exponent + 1)) (hbit : x.testBit exponent = false) : + x < 2 ^ exponent := by + apply Nat.lt_pow_two_of_testBit + intro i hi + by_cases hie : i = exponent + · subst i + exact hbit + · apply Nat.testBit_eq_false_of_lt + exact lt_of_lt_of_le hx (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) (by omega)) + +/-- XORing shifted one-hot tail terms stays below a common bound. -/ +theorem sparseMulByNat_one_shiftLeft_lt (exponents : List Nat) {shift bound : Nat} + (hExp : ∀ exponent ∈ exponents, shift + exponent < bound) : + sparseMulByNat exponents (1 <<< shift) < 2 ^ bound := by + induction exponents with + | nil => + simp [sparseMulByNat] + | cons exponent rest ih => + simp only [sparseMulByNat] + apply Nat.xor_lt_two_pow + · rw [Nat.shiftLeft_eq, Nat.shiftLeft_eq, one_mul, ← Nat.pow_add] + exact Nat.pow_lt_pow_right (by norm_num) (hExp exponent (by simp)) + · apply ih + intro e he + exact hExp e (by simp [he]) + +/-- One high-degree reduction step clears the processed bit and preserves lower width. -/ +theorem reduceNatStep_lt_two_pow {x exponent : Nat} + (hx : x < 2 ^ (exponent + 1)) + (hdeg : params.degree ≤ exponent) : + reduceNatStep params x exponent < 2 ^ exponent := by + unfold reduceNatStep + by_cases hbit : x.testBit exponent + · simp [hbit] + apply Nat.xor_lt_two_pow + · exact xor_clear_high_bit_lt hx hbit + · apply sparseMulByNat_one_shiftLeft_lt + intro tail htail + have htail_lt := params.tailExponents_bound tail htail + omega + · have hfalse : x.testBit exponent = false := Bool.eq_false_iff.mpr hbit + simp [hfalse] + exact lt_two_pow_of_top_bit_false hx hfalse + +/-- Reduce high bits `degree + extra - 1` down through `degree`. -/ +def reduceNatAux : Nat → Nat → Nat + | 0, x => x + | extra + 1, x => + reduceNatAux extra (reduceNatStep params x (params.degree + extra)) + +/-- Repeated high-degree reduction preserves the polynomial residue modulo `P`. -/ +theorem reduceNatAux_mod_eq {P : Polynomial (ZMod 2)} + (hP_ne_zero : P ≠ 0) + (hP : P = X ^ params.degree + sparsePolynomial params.tailExponents) + {n x : Nat} (hn : n ≤ params.degree) : + toPoly (BitVec.ofNat (2 * params.degree) (reduceNatAux params n x)) % P = + toPoly (BitVec.ofNat (2 * params.degree) x) % P := by + induction n generalizing x with + | zero => rfl + | succ n ih => + simp [reduceNatAux] + rw [ih (x := reduceNatStep params x (params.degree + n)) (by omega)] + exact reduceNatStep_mod_eq params hP_ne_zero hP + (x := x) (exponent := params.degree + n) + (by omega) (by omega) (by omega) + +/-- Repeated high-degree reduction returns a value below the base field width. -/ +theorem reduceNatAux_lt_two_pow {n x : Nat} (hn : n ≤ params.degree) + (hx : x < 2 ^ (params.degree + n)) : + reduceNatAux params n x < 2 ^ params.degree := by + induction n generalizing x with + | zero => + simpa [reduceNatAux] using hx + | succ n ih => + simp [reduceNatAux] + apply ih (by omega) + exact reduceNatStep_lt_two_pow params + (x := x) (exponent := params.degree + n) + (by simpa [Nat.add_assoc] using hx) + (by omega) + +/-- Reduce a carry-less product modulo the executable defining polynomial. -/ +def reduceNat (x : Nat) : Nat := + reduceNatAux params params.degree x % 2 ^ params.degree + +/-- Polynomial semantics of natural-number reduction modulo a direct defining polynomial. -/ +theorem toPoly_reduceNat {P : Polynomial (ZMod 2)} + (hP_ne_zero : P ≠ 0) + (hP : P = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : P.degree = params.degree) + {x : Nat} (hx : x < 2 ^ (2 * params.degree)) : + toPoly (BitVec.ofNat params.degree (reduceNat params x)) = + toPoly (BitVec.ofNat (2 * params.degree) x) % P := by + have hWidth : params.degree ≤ 2 * params.degree := by omega + have hxAux : x < 2 ^ (params.degree + params.degree) := by + simpa [two_mul] using hx + have hAuxBound : reduceNatAux params params.degree x < 2 ^ params.degree := + reduceNatAux_lt_two_pow params le_rfl hxAux + let aux := reduceNatAux params params.degree x + let v : BitVec params.degree := BitVec.ofNat params.degree aux + have hReduceNat : reduceNat params x = aux := by + dsimp [aux] + unfold reduceNat + rw [Nat.mod_eq_of_lt hAuxBound] + have hWideBound : aux < 2 ^ (2 * params.degree) := by + dsimp [aux] + exact lt_of_lt_of_le hAuxBound (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) hWidth) + have hWideEq : + (BitVec.ofNat (2 * params.degree) aux : BitVec (2 * params.degree)) = + BitVec.zeroExtend (2 * params.degree) v := by + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_ofNat, Extension.zeroExtend_toNat hWidth] + dsimp [v, aux] + rw [BitVec.toNat_ofNat] + rw [Nat.mod_eq_of_lt hWideBound, Nat.mod_eq_of_lt hAuxBound] + have hNarrowWide : + toPoly v = + toPoly (BitVec.ofNat (2 * params.degree) aux : BitVec (2 * params.degree)) := by + rw [hWideEq] + exact (Extension.toPoly_zeroExtend hWidth v).symm + have hWideReduced : + toPoly (BitVec.ofNat (2 * params.degree) aux : BitVec (2 * params.degree)) % P = + toPoly (BitVec.ofNat (2 * params.degree) aux : BitVec (2 * params.degree)) := by + rw [Polynomial.mod_eq_self_iff (hq0 := hP_ne_zero), hP_degree] + apply toPoly_degree_of_lt_two_pow + rw [BitVec.toNat_ofNat, Nat.mod_eq_of_lt hWideBound] + dsimp [aux] + exact hAuxBound + calc + toPoly (BitVec.ofNat params.degree (reduceNat params x)) + = toPoly v := by + dsimp [v] + rw [hReduceNat] + _ = toPoly (BitVec.ofNat (2 * params.degree) aux : BitVec (2 * params.degree)) := + hNarrowWide + _ = toPoly (BitVec.ofNat (2 * params.degree) aux : BitVec (2 * params.degree)) % P := + hWideReduced.symm + _ = toPoly (BitVec.ofNat (2 * params.degree) x) % P := by + dsimp [aux] + exact reduceNatAux_mod_eq params hP_ne_zero hP (n := params.degree) (x := x) le_rfl + +/-- Reduce a natural-number polynomial encoding to the executable carrier. -/ +def reduce (x : Nat) : ConcreteField params := + ofNat params (reduceNat params x) + +/-- Polynomial semantics of executable reduction modulo a direct defining polynomial. -/ +theorem toPoly_reduce {P : Polynomial (ZMod 2)} + (hP_ne_zero : P ≠ 0) + (hP : P = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : P.degree = params.degree) + {x : Nat} (hx : x < 2 ^ (2 * params.degree)) : + toPoly (toBitVec params (reduce params x)) = + toPoly (BitVec.ofNat (2 * params.degree) x) % P := by + change toPoly (BitVec.ofNat params.degree (reduceNat params x)) = + toPoly (BitVec.ofNat (2 * params.degree) x) % P + exact toPoly_reduceNat params hP_ne_zero hP hP_degree hx + +/-- Carry-less multiplication of `n` low bits of `a` by a `width`-bit value stays bounded. -/ +theorem clMulNat_lt_two_pow {a b width n : Nat} (hb : b < 2 ^ width) : + clMulNat a b n < 2 ^ (width + n) := by + induction n with + | zero => + simp [clMulNat] + | succ n ih => + simp [clMulNat] + by_cases hbit : a.testBit n + · simp [hbit] + have hterm : b <<< n < 2 ^ (width + n) := by + exact Nat.shiftLeft_lt hb + have hxor : clMulNat a b n ^^^ (b <<< n) < 2 ^ (width + n) := + Nat.xor_lt_two_pow ih hterm + exact lt_of_lt_of_le hxor + (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) (by omega)) + · simp [hbit] + exact lt_of_lt_of_le ih + (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) (by omega)) + +/-- Carry-less multiplication followed by defining-polynomial reduction. -/ +def mul (a b : ConcreteField params) : ConcreteField params := + reduce params (clMulNat (toNat params a) (toNat params b) params.degree) + +/-- Squaring in the executable carrier. -/ +def square (a : ConcreteField params) : ConcreteField params := + mul params a a + +/-- Fast exponentiation by repeated squaring. -/ +def pow (a : ConcreteField params) : Nat → ConcreteField params + | 0 => one params + | exponent + 1 => + let half := pow a ((exponent + 1) / 2) + let halfSq := square params half + if (exponent + 1) % 2 = 0 then halfSq else mul params halfSq a +termination_by exponent => exponent +decreasing_by + omega + +/-- Fermat-style inverse candidate. Correctness is proved after field certification. -/ +def inv (a : ConcreteField params) : ConcreteField params := + if toNat params a = 0 then zero params + else pow params a (2 ^ params.degree - 2) + +/-- Repeated Frobenius-squaring trace accumulator. -/ +def traceLoop : Nat → ConcreteField params → ConcreteField params → ConcreteField params + | 0, acc, _cur => acc + | steps + 1, acc, cur => + traceLoop steps (add params acc cur) (square params cur) + +/-- Executable absolute-trace candidate `z + z^2 + ... + z^(2^(degree-1))`. -/ +def traceValue (z : ConcreteField params) : ConcreteField params := + traceLoop params params.degree (zero params) z + +/-- Polynomial basis `#[1, alpha, ..., alpha^(degree-1)]`. -/ +def polynomialBasis : Array (ConcreteField params) := + Array.ofFn fun exponent : Fin params.degree ↦ pow params (root params) exponent.val + +/-- Base constants for characteristic two. -/ +def baseConstants : Array (ConcreteField params) := + #[zero params, one params] + +instance instBEqConcreteField : BEq (ConcreteField params) := + inferInstanceAs (BEq (BitVec params.degree)) + +instance instLawfulBEqConcreteField : LawfulBEq (ConcreteField params) := + inferInstanceAs (LawfulBEq (BitVec params.degree)) + +instance instInhabitedConcreteField : Inhabited (ConcreteField params) := + ⟨zero params⟩ + +instance instZeroConcreteField : Zero (ConcreteField params) where + zero := zero params + +instance instOneConcreteField : One (ConcreteField params) where + one := one params + +instance instAddConcreteField : Add (ConcreteField params) where + add := add params + +instance instNegConcreteField : Neg (ConcreteField params) where + neg := neg params + +instance instSubConcreteField : Sub (ConcreteField params) where + sub := sub params + +instance instMulConcreteField : Mul (ConcreteField params) where + mul := mul params + +instance instPowConcreteField : Pow (ConcreteField params) Nat where + pow := pow params + +instance instInvConcreteField : Inv (ConcreteField params) where + inv := inv params + +instance instDivConcreteField : Div (ConcreteField params) where + div a b := mul params a (inv params b) + +instance instHDivConcreteField : + HDiv (ConcreteField params) (ConcreteField params) (ConcreteField params) where + hDiv a b := mul params a (inv params b) + +/-- XOR addition is associative on the executable carrier. -/ +theorem add_assoc (a b c : ConcreteField params) : + add params (add params a b) c = add params a (add params b c) := by + exact BitVec.xor_assoc a b c + +/-- XOR addition is commutative on the executable carrier. -/ +theorem add_comm (a b : ConcreteField params) : + add params a b = add params b a := by + exact BitVec.xor_comm a b + +/-- Zero is a right identity for executable addition. -/ +theorem add_zero (a : ConcreteField params) : + add params a (zero params) = a := by + change a ^^^ 0 = a + exact BitVec.xor_zero + +/-- Zero is a left identity for executable addition. -/ +theorem zero_add (a : ConcreteField params) : + add params (zero params) a = a := by + change 0 ^^^ a = a + exact BitVec.zero_xor + +/-- Executable negation is additive inverse in characteristic two. -/ +theorem neg_add_cancel (a : ConcreteField params) : + add params (neg params a) a = zero params := by + change a ^^^ a = 0 + exact BitVec.xor_self + +/-- Parity form of natural scalar recursion for the XOR additive group. -/ +theorem nsmul_succ (n : Nat) (x : ConcreteField params) : + (if (n + 1) % 2 = 0 then zero params else x) = + add params (if n % 2 = 0 then zero params else x) x := by + have h_mod : (n + 1) % 2 = (n % 2 + 1) % 2 := Nat.add_mod n 1 2 + by_cases h : n % 2 = 0 + · rw [h, Nat.zero_add] at h_mod + rw [h] + have h_succ : (n + 1) % 2 = 1 := by omega + rw [h_succ] + simp only [↓reduceIte] + change x = 0 ^^^ x + exact (BitVec.zero_xor).symm + · have h1 : n % 2 = 1 := Nat.mod_two_ne_zero.mp h + rw [h1] at h_mod ⊢ + have h_succ : (n + 1) % 2 = 0 := by omega + rw [h_succ] + simp only [↓reduceIte] + change 0 = x ^^^ x + exact (BitVec.xor_self).symm + +/-- Parity form of integer scalar recursion for the XOR additive group. -/ +theorem zsmul_succ (n : Nat) (x : ConcreteField params) : + (if (n + 1 : Int) % 2 = 0 then zero params else x) = + add params (if (n : Int) % 2 = 0 then zero params else x) x := by + norm_cast + exact nsmul_succ params n x + +private theorem int_neg_mod_two (n : Int) : (-n) % 2 = n % 2 := by + simp only [Int.neg_emod_two] + +/-- Parity form of negative integer scalar recursion for the XOR additive group. -/ +theorem zsmul_neg (n : Nat) (x : ConcreteField params) : + (if (Int.negSucc n) % 2 = 0 then zero params else x) = + neg params (if (n + 1 : Int) % 2 = 0 then zero params else x) := by + have h_neg : Int.negSucc n = - (n + 1 : Int) := rfl + rw [h_neg] + rw [int_neg_mod_two] + simp + rfl + +instance instAddCommGroupConcreteField : AddCommGroup (ConcreteField params) where + add := add params + zero := zero params + neg := neg params + sub := sub params + add_assoc := add_assoc params + add_comm := add_comm params + add_zero := add_zero params + zero_add := zero_add params + neg_add_cancel := neg_add_cancel params + sub_eq_add_neg := by intro _ _; rfl + nsmul := fun n x => if n % 2 = 0 then zero params else x + zsmul := fun n x => if n % 2 = 0 then zero params else x + nsmul_zero := fun _ => rfl + nsmul_succ := nsmul_succ params + zsmul_zero' := fun _ => rfl + zsmul_succ' := zsmul_succ params + zsmul_neg' := zsmul_neg params + +/-- Natural casts for characteristic-two executable fields use parity. -/ +def natCast (n : Nat) : ConcreteField params := + if n % 2 = 0 then zero params else one params + +instance instNatCastConcreteField : NatCast (ConcreteField params) where + natCast := natCast params + +@[simp] +theorem natCast_eq (n : Nat) : (↑n : ConcreteField params) = natCast params n := + rfl + +theorem natCast_zero : + natCast params 0 = zero params := by + simp [natCast] + +theorem natCast_succ (n : Nat) : + natCast params (n + 1) = add params (natCast params n) (one params) := by + unfold natCast + by_cases h : n % 2 = 0 + · have h_succ : (n + 1) % 2 = 1 := by omega + simp [h, h_succ, zero_add] + · have h_succ : (n + 1) % 2 = 0 := by omega + simp only [h, h_succ, ↓reduceIte] + exact (neg_add_cancel params (one params)).symm + +/-- Integer casts for characteristic-two executable fields use parity. -/ +def intCast (n : Int) : ConcreteField params := + if n % 2 = 0 then zero params else one params + +instance instIntCastConcreteField : IntCast (ConcreteField params) where + intCast := intCast params + +@[simp] +theorem intCast_eq (n : Int) : (↑n : ConcreteField params) = intCast params n := + rfl + +theorem intCast_ofNat (n : Nat) : + intCast params (n : Int) = natCast params n := by + unfold intCast natCast + by_cases h : n % 2 = 0 + · have h_int : (n : Int) % 2 = 0 := by norm_cast + simp [h, h_int] + · have h_n : n % 2 = 1 := by omega + have h_int : (n : Int) % 2 = 1 := by norm_cast + simp [h_n, h_int] + +theorem intCast_negSucc (n : Nat) : + intCast params (Int.negSucc n) = neg params (natCast params (n + 1)) := by + by_cases h_mod : (n + 1) % 2 = 0 + · have h_neg : (-(n + 1 : Int)) % 2 = 0 := by omega + unfold intCast natCast + have int_neg_succ : Int.negSucc n = -(n + 1 : Int) := by rfl + rw [int_neg_succ, h_neg, h_mod] + rfl + · have h_neg : (-(n + 1 : Int)) % 2 = 1 := by omega + unfold intCast natCast + have int_neg_succ : Int.negSucc n = -(n + 1 : Int) := by rfl + rw [int_neg_succ, h_neg] + simp [h_mod, neg] + +/-- Plain equivalence between the executable carrier and its bounded natural encoding. -/ +noncomputable def equivFin : ConcreteField params ≃ Fin (2 ^ params.degree) where + toFun a := ⟨toNat params a, (toBitVec params a).isLt⟩ + invFun i := ofNat params i.val + left_inv := by + intro a + apply BitVec.eq_of_toNat_eq + simp [toNat, toBitVec, ofNat, ofBitVec] + right_inv := by + intro i + apply Fin.ext + simp [toNat, toBitVec, ofNat, ofBitVec] + +/-- Fintype instance for the raw executable carrier. -/ +noncomputable instance instFintypeConcreteField : Fintype (ConcreteField params) := + Fintype.ofEquiv (Fin (2 ^ params.degree)) (equivFin params).symm + +/-- Finite instance for the raw executable carrier. -/ +instance instFiniteConcreteField : Finite (ConcreteField params) := + Fintype.finite (instFintypeConcreteField params) + +/-- The executable carrier has `2^degree` bit-patterns. -/ +theorem concreteField_card : + Fintype.card (ConcreteField params) = 2 ^ params.degree := by + rw [Fintype.card_congr (equivFin params)] + simp + +section QuotientCompatibility + +variable {data : DefiningPolynomialData} + +/-- Canonical map from the executable bit-vector carrier to the quotient specification. -/ +noncomputable def toSpec (a : ConcreteField params) : SpecField data := + AdjoinRoot.mk (polynomial data) (toPoly (toBitVec params a)) + +/-- The executable-to-specification map is injective when the defining degree matches. -/ +theorem toSpec_injective (hDegree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) : + Function.Injective (toSpec params (data := data)) := by + intro a b h + unfold toSpec at h + have h_sub : + toPoly (toBitVec params a) - toPoly (toBitVec params b) = + toPoly (toBitVec params a ^^^ toBitVec params b) := by + rw [toPoly_xor] + ring_nf + exact ZMod2Poly.sub_eq_add (toPoly (toBitVec params a)) (toPoly (toBitVec params b)) + let diff := toBitVec params a ^^^ toBitVec params b + have h_deg : (toPoly diff).degree < params.degree := + toPoly_degree_lt_w hDegree_pos diff + have h_dvd : + polynomial data ∣ + (toPoly (toBitVec params a) - toPoly (toBitVec params b)) := by + rw [AdjoinRoot.mk_eq_mk] at h + exact h + have h_zero : toPoly diff = 0 := by + by_contra h_nz + have h_diff_nz : + toPoly (toBitVec params a) - toPoly (toBitVec params b) ≠ 0 := by + rw [h_sub] + exact h_nz + have h_deg_poly : + (polynomial data).degree ≤ + (toPoly (toBitVec params a) - toPoly (toBitVec params b)).degree := + Polynomial.degree_le_of_dvd (h1 := h_dvd) (h2 := h_diff_nz) + have h_eq_deg : + (toPoly (toBitVec params a) - toPoly (toBitVec params b)).degree = + (toPoly diff).degree := by + rw [h_sub.symm] + rw [hDegree, h_eq_deg] at h_deg_poly + exact not_le_of_gt h_deg h_deg_poly + have h_diff_eq_zero : diff = 0 := by + by_contra h_nz + have h_diff_ne_zero : diff ≠ 0 := h_nz + rw [← toPoly_ne_zero_iff_ne_zero (v := diff)] at h_diff_ne_zero + exact h_diff_ne_zero h_zero + exact BitVec.xor_eq_zero_iff.mp h_diff_eq_zero + +/-- The executable zero maps to the quotient zero. -/ +theorem toSpec_zero : + toSpec params (data := data) (zero params) = 0 := by + simp [toSpec, zero, ofNat, ofBitVec, toBitVec, toPoly_zero_eq_zero] + +/-- The executable one maps to the quotient one. -/ +theorem toSpec_one (hDegree_pos : 0 < params.degree) : + toSpec params (data := data) (one params) = 1 := by + simp [toSpec, one, ofNat, ofBitVec, toBitVec, toPoly_one_eq_one hDegree_pos, map_one] + +/-- The executable polynomial-basis generator maps to the quotient root. -/ +theorem toSpec_root (hDegree_root : 1 < params.degree) : + toSpec params (data := data) (root params) = Extension.root data := by + unfold toSpec root ofNat ofBitVec toBitVec Extension.root + congr + change BinaryField.toPoly (BitVec.ofNat params.degree 2) = + (Polynomial.X : Polynomial (ZMod 2)) + let oneShift : BitVec params.degree := BitVec.ofNat params.degree (1 <<< 1) + have hvec : (BitVec.ofNat params.degree 2 : BitVec params.degree) = oneShift := by + unfold oneShift + congr + rw [hvec] + have hpoly : BinaryField.toPoly oneShift = (Polynomial.X : Polynomial (ZMod 2)) := by + unfold oneShift + simpa [BitVec.ofNat_eq_ofNat] using + (Extension.toPoly_one_shiftLeft (w := params.degree) 1 hDegree_root) + exact hpoly + +/-- Executable XOR addition maps to quotient addition. -/ +theorem toSpec_add (a b : ConcreteField params) : + toSpec params (data := data) (add params a b) = + toSpec params (data := data) a + toSpec params (data := data) b := by + unfold toSpec add ofBitVec toBitVec + rw [toPoly_xor] + exact map_add (AdjoinRoot.mk (polynomial data)) (toPoly a) (toPoly b) + +/-- Executable characteristic-two negation maps to quotient negation. -/ +theorem toSpec_neg (a : ConcreteField params) : + toSpec params (data := data) (neg params a) = + -toSpec params (data := data) a := by + unfold toSpec neg toBitVec + rw [← map_neg (AdjoinRoot.mk (polynomial data))] + congr + exact (ZMod2Poly.neg_eq_self (toPoly a)).symm + +/-- Executable characteristic-two subtraction maps to quotient subtraction. -/ +theorem toSpec_sub (a b : ConcreteField params) : + toSpec params (data := data) (sub params a b) = + toSpec params (data := data) a - toSpec params (data := data) b := by + rw [sub, toSpec_add, sub_eq_add_neg, ← toSpec_neg] + rfl + +/-- Executable multiplication maps to quotient multiplication. -/ +theorem toSpec_mul + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (a b : ConcreteField params) : + toSpec params (data := data) (mul params a b) = + toSpec params (data := data) a * toSpec params (data := data) b := by + unfold toSpec mul + have hMulBound : clMulNat (toNat params a) (toNat params b) params.degree < + 2 ^ (2 * params.degree) := by + have hb : (toNat params b) < 2 ^ params.degree := (toBitVec params b).isLt + have h := clMulNat_lt_two_pow + (a := toNat params a) (b := toNat params b) + (width := params.degree) (n := params.degree) hb + simpa [two_mul] using h + have hReduce := toPoly_reduce params (P := polynomial data) + (polynomial_ne_zero data) hP hP_degree hMulBound + change AdjoinRoot.mk (polynomial data) + (toPoly (toBitVec params (reduce params + (clMulNat (toNat params a) (toNat params b) params.degree)))) = + AdjoinRoot.mk (polynomial data) (toPoly (toBitVec params a)) * + AdjoinRoot.mk (polynomial data) (toPoly (toBitVec params b)) + rw [hReduce] + have hCl : + toPoly (BitVec.ofNat (2 * params.degree) + (clMulNat (toNat params a) (toNat params b) params.degree)) = + toPoly (toBitVec params a) * toPoly (toBitVec params b) := by + simpa [toNat] using Extension.toPoly_clMulNat (toBitVec params a) (toBitVec params b) + rw [hCl] + rw [← map_mul (AdjoinRoot.mk (polynomial data)), AdjoinRoot.mk_eq_mk] + apply dvd_sub_comm.mp + exact CanonicalEuclideanDomain.dvd_sub_mod + (a := toPoly (toBitVec params a) * toPoly (toBitVec params b)) + (b := polynomial data) + +/-- Executable fast exponentiation maps to quotient exponentiation. -/ +theorem toSpec_pow + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a : ConcreteField params) : + ∀ n : Nat, + toSpec params (data := data) (pow params a n) = + (toSpec params (data := data) a) ^ n := by + intro n + induction n using Nat.strong_induction_on with + | h n ih => + cases n with + | zero => + simp [pow, toSpec_one params (data := data) hDegree_pos] + | succ exponent => + have hhalf : (exponent + 1) / 2 < exponent + 1 := by + exact Nat.div_lt_self (by omega) (by norm_num) + have hih := ih ((exponent + 1) / 2) hhalf + rw [pow] + by_cases hEven : (exponent + 1) % 2 = 0 + · simp [hEven, square] + rw [toSpec_mul params (data := data) hP hP_degree, hih] + rw [← pow_add] + congr 1 + have hmod := Nat.mod_add_div (exponent + 1) 2 + omega + · simp [hEven, square] + rw [toSpec_mul params (data := data) hP hP_degree, + toSpec_mul params (data := data) hP hP_degree, hih] + rw [← pow_add, ← pow_succ] + congr 1 + have hmod := Nat.mod_add_div (exponent + 1) 2 + have hmod_lt : (exponent + 1) % 2 < 2 := Nat.mod_lt _ (by norm_num) + omega + +/-- A zero natural encoding denotes executable zero. -/ +theorem eq_zero_of_toNat_eq_zero {a : ConcreteField params} + (h : toNat params a = 0) : + a = zero params := by + apply BitVec.eq_of_toNat_eq + simpa [toNat, toBitVec, zero, ofNat, ofBitVec] using h + +/-- A nonzero executable element has nonzero natural encoding. -/ +theorem toNat_ne_zero_of_ne_zero {a : ConcreteField params} + (h : a ≠ zero params) : + toNat params a ≠ 0 := by + intro hnat + exact h (eq_zero_of_toNat_eq_zero params hnat) + +/-- Executable zero and one are distinct for positive widths. -/ +theorem zero_ne_one (hDegree_pos : 0 < params.degree) : + zero params ≠ one params := by + intro h + have hnat := congrArg (toNat params) h + simp [toNat, toBitVec, zero, one, ofNat, ofBitVec] at hnat + omega + +/-- The quotient image of a nonzero executable element is nonzero. -/ +theorem toSpec_ne_zero + (hDegree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + {a : ConcreteField params} (h : a ≠ zero params) : + toSpec params (data := data) a ≠ 0 := by + intro hz + have hz' : toSpec params (data := data) a = + toSpec params (data := data) (zero params) := by + simpa [toSpec_zero params (data := data)] using hz + exact h (toSpec_injective params (data := data) hDegree hDegree_pos hz') + +/-- Executable inversion maps to the Fermat inverse exponent in the quotient. -/ +theorem toSpec_inv_of_ne_zero + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + {a : ConcreteField params} (h : a ≠ zero params) : + toSpec params (data := data) (inv params a) = + (toSpec params (data := data) a) ^ (2 ^ params.degree - 2) := by + unfold inv + have hnat : toNat params a ≠ 0 := toNat_ne_zero_of_ne_zero params h + simp [hnat] + exact toSpec_pow params (data := data) hP hP_degree hDegree_pos a (2 ^ params.degree - 2) + +/-- Fast executable power satisfies the monoid successor law. -/ +theorem pow_succ_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (n : Nat) (a : ConcreteField params) : + pow params a (n + 1) = mul params (pow params a n) a := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_pow params (data := data) hP hP_degree hDegree_pos, + toSpec_mul params (data := data) hP hP_degree, + toSpec_pow params (data := data) hP hP_degree hDegree_pos] + exact pow_succ (toSpec params (data := data) a) n + +/-- Associativity of executable multiplication, transported through the quotient. -/ +theorem mul_assoc_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a b c : ConcreteField params) : + mul params (mul params a b) c = mul params a (mul params b c) := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + repeat rw [toSpec_mul params (data := data) hP hP_degree] + exact _root_.mul_assoc (toSpec params (data := data) a) + (toSpec params (data := data) b) (toSpec params (data := data) c) + +/-- Left identity for executable multiplication. -/ +theorem one_mul_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a : ConcreteField params) : + mul params (one params) a = a := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_mul params (data := data) hP hP_degree, + toSpec_one params (data := data) hDegree_pos] + exact _root_.one_mul (toSpec params (data := data) a) + +/-- Right identity for executable multiplication. -/ +theorem mul_one_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a : ConcreteField params) : + mul params a (one params) = a := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_mul params (data := data) hP hP_degree, + toSpec_one params (data := data) hDegree_pos] + exact _root_.mul_one (toSpec params (data := data) a) + +/-- Left distributivity for executable multiplication. -/ +theorem left_distrib_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a b c : ConcreteField params) : + mul params a (add params b c) = + add params (mul params a b) (mul params a c) := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_add params (data := data), toSpec_mul params (data := data) hP hP_degree, + toSpec_add params (data := data), toSpec_mul params (data := data) hP hP_degree, + toSpec_mul params (data := data) hP hP_degree] + exact _root_.mul_add (toSpec params (data := data) a) + (toSpec params (data := data) b) (toSpec params (data := data) c) + +/-- Right distributivity for executable multiplication. -/ +theorem right_distrib_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a b c : ConcreteField params) : + mul params (add params a b) c = + add params (mul params a c) (mul params b c) := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_add params (data := data), toSpec_mul params (data := data) hP hP_degree, + toSpec_add params (data := data), toSpec_mul params (data := data) hP hP_degree, + toSpec_mul params (data := data) hP hP_degree] + exact _root_.add_mul (toSpec params (data := data) a) + (toSpec params (data := data) b) (toSpec params (data := data) c) + +/-- Left zero for executable multiplication. -/ +theorem zero_mul_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a : ConcreteField params) : + mul params (zero params) a = zero params := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_mul params (data := data) hP hP_degree, + toSpec_zero params (data := data)] + exact MulZeroClass.zero_mul (toSpec params (data := data) a) + +/-- Right zero for executable multiplication. -/ +theorem mul_zero_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a : ConcreteField params) : + mul params a (zero params) = zero params := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_mul params (data := data) hP hP_degree, + toSpec_zero params (data := data)] + exact MulZeroClass.mul_zero (toSpec params (data := data) a) + +/-- Commutativity of executable multiplication. -/ +theorem mul_comm_of_spec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a b : ConcreteField params) : + mul params a b = mul params b a := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + repeat rw [toSpec_mul params (data := data) hP hP_degree] + exact _root_.mul_comm (toSpec params (data := data) a) + (toSpec params (data := data) b) + +/-- Executable inverse of zero is zero. -/ +theorem inv_zero : + inv params (zero params) = zero params := by + unfold inv + simp [toNat, toBitVec, zero, ofNat, ofBitVec] + +/-- Division is multiplication by inverse. -/ +theorem div_eq_mul_inv (a b : ConcreteField params) : + (instDivConcreteField params).div a b = mul params a (inv params b) := + rfl + +/-- Nontriviality witness for positive-width executable fields. -/ +theorem exists_pair_ne (hDegree_pos : 0 < params.degree) : + ∃ x y : ConcreteField params, x ≠ y := + ⟨zero params, one params, zero_ne_one params hDegree_pos⟩ + +/-- Ring structure for a certified executable direct binary extension. -/ +@[reducible] +def instRingConcreteFieldOfSpec + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) : + Ring (ConcreteField params) where + add := add params + zero := zero params + neg := neg params + sub := sub params + mul := mul params + one := one params + nsmul := fun n x => if n % 2 = 0 then zero params else x + zsmul := fun n x => if n % 2 = 0 then zero params else x + npow := fun n x => pow params x n + add_assoc := add_assoc params + add_comm := add_comm params + add_zero := add_zero params + zero_add := zero_add params + neg_add_cancel := neg_add_cancel params + sub_eq_add_neg := by intro _ _; rfl + nsmul_zero := fun _ => rfl + nsmul_succ := nsmul_succ params + zsmul_zero' := fun _ => rfl + zsmul_succ' := zsmul_succ params + zsmul_neg' := zsmul_neg params + mul_assoc := mul_assoc_of_spec params (data := data) hP hP_degree hDegree_pos + one_mul := one_mul_of_spec params (data := data) hP hP_degree hDegree_pos + mul_one := mul_one_of_spec params (data := data) hP hP_degree hDegree_pos + left_distrib := left_distrib_of_spec params (data := data) hP hP_degree hDegree_pos + right_distrib := right_distrib_of_spec params (data := data) hP hP_degree hDegree_pos + zero_mul := zero_mul_of_spec params (data := data) hP hP_degree hDegree_pos + mul_zero := mul_zero_of_spec params (data := data) hP hP_degree hDegree_pos + natCast := natCast params + natCast_zero := natCast_zero params + natCast_succ := natCast_succ params + intCast := intCast params + intCast_ofNat := intCast_ofNat params + intCast_negSucc := intCast_negSucc params + npow_zero := by + intro x + change pow params x 0 = one params + simp [pow] + npow_succ := by + intro n x + change pow params x (n + 1) = mul params (pow params x n) x + exact pow_succ_of_spec params (data := data) hP hP_degree hDegree_pos n x + +/-- Multiplication by the executable inverse cancels nonzero elements. -/ +theorem mul_inv_cancel_of_spec [Fact (Irreducible (polynomial data))] + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) + (a : ConcreteField params) (h : a ≠ zero params) : + mul params a (inv params a) = one params := by + apply toSpec_injective params (data := data) hP_degree hDegree_pos + rw [toSpec_mul params (data := data) hP hP_degree, + toSpec_one params (data := data) hDegree_pos, + toSpec_inv_of_ne_zero params (data := data) hP hP_degree hDegree_pos h] + rw [← pow_succ'] + have h_exp : 2 ^ params.degree - 2 + 1 = 2 ^ params.degree - 1 := by + have htwo : 2 ≤ 2 ^ params.degree := by + exact Nat.succ_le_of_lt (Nat.one_lt_two_pow hDegree_pos.ne') + omega + rw [h_exp] + have hcard : + Fintype.card (SpecField data) = 2 ^ params.degree := by + have hdata : data.degree = params.degree := by + have hdegNat : + (polynomial data).natDegree = params.degree := + (Polynomial.degree_eq_iff_natDegree_eq (polynomial_ne_zero data)).mp hP_degree + rw [polynomial_natDegree data] at hdegNat + exact hdegNat + rw [Extension.specField_card data, hdata] + have hq_ne : + toSpec params (data := data) a ≠ 0 := + toSpec_ne_zero params (data := data) hP_degree hDegree_pos h + have hfinite := + FiniteField.pow_card_sub_one_eq_one + (K := SpecField data) (toSpec params (data := data) a) hq_ne + rwa [hcard] at hfinite + +/-- Division-ring structure for a certified executable direct binary extension. -/ +@[reducible] +def instDivisionRingConcreteFieldOfSpec [Fact (Irreducible (polynomial data))] + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) : + DivisionRing (ConcreteField params) where + toRing := instRingConcreteFieldOfSpec params (data := data) hP hP_degree hDegree_pos + inv := inv params + div := fun a b => mul params a (inv params b) + exists_pair_ne := exists_pair_ne params hDegree_pos + mul_inv_cancel := by + intro a h + change mul params a (inv params a) = one params + exact mul_inv_cancel_of_spec params (data := data) hP hP_degree hDegree_pos + a (by simpa using h) + inv_zero := by + change inv params (zero params) = zero params + exact inv_zero params + div_eq_mul_inv := by + intro a b + rfl + qsmul := _ + nnqsmul := _ + +/-- Field structure for a certified executable direct binary extension. -/ +@[reducible] +def instFieldConcreteFieldOfSpec [Fact (Irreducible (polynomial data))] + (hP : polynomial data = X ^ params.degree + sparsePolynomial params.tailExponents) + (hP_degree : (polynomial data).degree = params.degree) + (hDegree_pos : 0 < params.degree) : + Field (ConcreteField params) where + toDivisionRing := + instDivisionRingConcreteFieldOfSpec params (data := data) hP hP_degree hDegree_pos + mul_comm := by + intro a b + change mul params a b = mul params b a + exact mul_comm_of_spec params (data := data) hP hP_degree hDegree_pos a b + +end QuotientCompatibility + +end Concrete + +end Extension + +end BinaryField diff --git a/CompPoly/Fields/Binary/Extension/Prelude.lean b/CompPoly/Fields/Binary/Extension/Prelude.lean new file mode 100644 index 00000000..f8bf1864 --- /dev/null +++ b/CompPoly/Fields/Binary/Extension/Prelude.lean @@ -0,0 +1,384 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Common +import Mathlib.Algebra.Polynomial.Degree.IsMonicOfDegree + +/-! +# Direct Binary-Extension Prelude + +Shared small helpers for direct polynomial-basis extensions +`GF(2)[X] / (X^m + tail)`. + +The concrete `GF2_48` and `GF2_72` modules use this file for defining-polynomial +metadata, sparse bitmask helpers, and kernel-safe Nat-level carry-less +multiplication checkers. Field instances and irreducibility certificates live in +the concrete field modules. +-/ + +namespace BinaryField + +namespace Extension + +open Polynomial + +/-- Metadata for a direct binary extension polynomial `X^degree + tail`. -/ +structure DefiningPolynomialData where + degree : Nat + tail : Polynomial (ZMod 2) + tailDegree : Nat + bitmask : Nat + tail_natDegree : tail.natDegree = tailDegree + tailDegree_lt_degree : tailDegree < degree + +/-- The monic defining polynomial `X^degree + tail` over `GF(2)`. -/ +noncomputable def polynomial (data : DefiningPolynomialData) : Polynomial (ZMod 2) := + X ^ data.degree + data.tail + +/-- `X^degree + tail` is monic of degree `degree` when `tail` has smaller degree. -/ +lemma polynomial_isMonicOfDegree (data : DefiningPolynomialData) : + IsMonicOfDegree (polynomial data) data.degree := by + unfold polynomial + exact (Polynomial.isMonicOfDegree_X_pow (ZMod 2) data.degree).add_right (by + rw [data.tail_natDegree] + exact data.tailDegree_lt_degree) + +/-- The natural degree of the direct-extension defining polynomial. -/ +lemma polynomial_natDegree (data : DefiningPolynomialData) : + (polynomial data).natDegree = data.degree := + (polynomial_isMonicOfDegree data).natDegree_eq + +/-- The direct-extension defining polynomial is monic. -/ +lemma polynomial_monic (data : DefiningPolynomialData) : + (polynomial data).Monic := + (polynomial_isMonicOfDegree data).monic + +/-- The direct-extension defining polynomial is nonzero. -/ +lemma polynomial_ne_zero (data : DefiningPolynomialData) : + polynomial data ≠ 0 := + (polynomial_monic data).ne_zero + +/-- The degree of the direct-extension defining polynomial. -/ +lemma polynomial_degree (data : DefiningPolynomialData) : + (polynomial data).degree = data.degree := by + rw [degree_eq_natDegree (hp := polynomial_ne_zero data), polynomial_natDegree] + +/-- Field cardinality for a degree-`m` binary extension. -/ +def fieldSize (degree : Nat) : Nat := + 2 ^ degree + +/-- Multiplicative-group order for a degree-`m` binary extension. -/ +def multiplicativeGroupOrder (degree : Nat) : Nat := + fieldSize degree - 1 + +/-- Fold a smooth-refinement schedule from a starting multiplicative order. -/ +def foldSmoothSchedule (schedule : Array Nat) (order : Nat) : Nat := + schedule.toList.foldl (fun order ell ↦ order / ell) order + +/-- Carry-less polynomial multiplication on natural-number bit encodings. + +The recursion visits exactly the low `width` bits of `a`, using only kernel-safe +`Nat.testBit`, `Nat.xor`, and `Nat.shiftLeft` primitives. +-/ +def clMulNat (a b : Nat) : Nat → Nat + | 0 => 0 + | width + 1 => + let prev := clMulNat a b width + if a.testBit width then prev ^^^ (b <<< width) else prev + +/-- Carry-less squaring on natural-number bit encodings. -/ +abbrev clSqNat (a width : Nat) : Nat := + clMulNat a a width + +/-- XOR together shifts of `a` at the supplied polynomial exponents. -/ +def sparseMulByNat : List Nat → Nat → Nat + | [], _ => 0 + | exponent :: rest, a => (a <<< exponent) ^^^ sparseMulByNat rest a + +/-- Kernel-safe Boolean checker for a modular squaring certificate step. -/ +def checkSquareStep (width : Nat) (polyExponents : List Nat) + (rPrev q rNext : BitVec width) : Bool := + let lhs := clSqNat rPrev.toNat width + let rhs := sparseMulByNat polyExponents q.toNat ^^^ rNext.toNat + lhs == rhs + +/-- Kernel-safe Boolean checker for a polynomial division certificate step. -/ +def checkDivStep (width : Nat) (a q b r : BitVec width) : Bool := + let rhs := clMulNat q.toNat b.toNat width ^^^ r.toNat + a.toNat == rhs + +/-- Zero-extend a bit-vector to a larger width without changing its natural value. -/ +lemma zeroExtend_toNat {w W : Nat} (h : w ≤ W) (v : BitVec w) : + (BitVec.zeroExtend W v).toNat = v.toNat := by + simp [BitVec.zeroExtend, BitVec.toNat_setWidth] + exact Nat.mod_eq_of_lt (BitVec.toNat_lt_twoPow_of_le (x := v) h) + +/-- Zero-extension preserves the polynomial interpretation of a bit-vector. -/ +lemma toPoly_zeroExtend {w W : Nat} (h : w ≤ W) (v : BitVec w) : + toPoly (BitVec.zeroExtend W v) = toPoly v := by + ext n + by_cases hnW : n < W + · by_cases hnw : n < w + · have hnat := zeroExtend_toNat h v + simp [toPoly_coeff, hnW, hnw, BitVec.getLsb, hnat] + · have hwle : w ≤ n := Nat.le_of_not_gt hnw + have hvbit : v.toNat.testBit n = false := + Nat.testBit_eq_false_of_lt + (lt_of_lt_of_le v.isLt (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) hwle)) + have lhs : (toPoly (BitVec.zeroExtend W v)).coeff n = 0 := by + rw [toPoly_coeff] + simp [hnW, BitVec.getLsb, zeroExtend_toNat h v, hvbit] + have rhs : (toPoly v).coeff n = 0 := by + rw [toPoly_coeff] + simp [hnw] + rw [lhs, rhs] + · have hnw : ¬ n < w := by omega + simp [toPoly_coeff, hnW, hnw] + +/-- `BitVec.ofNat` transports `Nat.xor` to `BitVec.xor`. -/ +lemma ofNat_xor {W : Nat} (x y : Nat) : + (BitVec.ofNat W (x ^^^ y) : BitVec W) = + (BitVec.ofNat W x : BitVec W) ^^^ (BitVec.ofNat W y : BitVec W) := by + apply BitVec.eq_of_toNat_eq + change (x ^^^ y) % 2 ^ W = + (((BitVec.ofNat W x : BitVec W) ^^^ (BitVec.ofNat W y : BitVec W)).toNat) + rw [BitVec.toNat_xor, BitVec.toNat_ofNat, BitVec.toNat_ofNat, Nat.xor_mod_two_pow] + +/-- `BitVec.ofNat` transports left shift modulo the target width. -/ +lemma ofNat_shiftLeft {W : Nat} (x n : Nat) : + (BitVec.ofNat W (x <<< n) : BitVec W) = + ((BitVec.ofNat W x : BitVec W) <<< n) := by + apply BitVec.eq_of_toNat_eq + simp [Nat.shiftLeft_eq, Nat.mod_mul_mod] + +/-- Bit-vector view of the structural `Nat` carry-less multiplication checker. -/ +lemma clMulNat_bv_eq_fold_range (a b : Nat) (W : Nat) : + ∀ n, + (BitVec.ofNat W (clMulNat a b n) : BitVec W) = + (Finset.range n).fold BitVec.xor 0 + (fun i => if a.testBit i then ((BitVec.ofNat W b : BitVec W) <<< i) else 0) + | 0 => by simp [clMulNat] + | n + 1 => by + rw [Finset.range_add_one, Finset.fold_insert (by simp)] + by_cases hbit : a.testBit n + · simp [clMulNat, hbit, clMulNat_bv_eq_fold_range a b W n, ofNat_shiftLeft, + BitVec.xor_comm] + · simp [clMulNat, hbit, clMulNat_bv_eq_fold_range a b W n] + +/-- Polynomial semantics of structural `Nat` carry-less multiplication. -/ +lemma toPoly_clMulNat {w : Nat} (a b : BitVec w) : + toPoly (BitVec.ofNat (2 * w) (clMulNat a.toNat b.toNat w)) = toPoly a * toPoly b := by + rw [clMulNat_bv_eq_fold_range a.toNat b.toNat (2 * w) w] + rw [fold_range_xor_eq_foldl] + rw [toPoly_fold_xor + (f := fun i => + if a.toNat.testBit i = true then ((BitVec.ofNat (2 * w) b.toNat : BitVec (2 * w)) <<< i) + else 0)] + conv_rhs => + enter [1] + unfold toPoly + simp only [BitVec.getLsb] + change (∑ i ∈ Finset.range w, + toPoly (if a.toNat.testBit i = true then + ((BitVec.ofNat (2 * w) b.toNat : BitVec (2 * w)) <<< i) else 0)) = + (∑ i : Fin w, if a.toNat.testBit i.val = true then (X : Polynomial (ZMod 2)) ^ i.val else 0) * + toPoly b + rw [Fin.sum_univ_eq_sum_range + (f := fun i => if a.toNat.testBit i = true then (X : Polynomial (ZMod 2)) ^ i else 0) + (n := w)] + rw [Finset.sum_mul] + apply Finset.sum_congr rfl + intro i hi + simp only [Finset.mem_range] at hi + by_cases hbit : a.toNat.testBit i + · simp [hbit] + have hWidth : w ≤ 2 * w := Nat.le_mul_of_pos_left w (by norm_num : 0 < 2) + have hb_lt : (BitVec.setWidth (2 * w) b).toNat < 2 ^ w := by + simpa [BitVec.zeroExtend] using + (by + rw [zeroExtend_toNat hWidth b] + exact b.isLt : + (BitVec.zeroExtend (2 * w) b).toNat < 2 ^ w) + have h_no_overflow : w + i ≤ 2 * w := by omega + rw [toPoly_shiftLeft_no_overflow (d := w) (BitVec.setWidth (2 * w) b) + (ha := hb_lt) (h_no_overflow := h_no_overflow)] + have hpoly : toPoly (BitVec.setWidth (2 * w) b) = toPoly b := by + simpa [BitVec.zeroExtend] using toPoly_zeroExtend hWidth b + rw [hpoly] + ring + · have hbitFalse : a.toNat.testBit i = false := Bool.eq_false_iff.mpr hbit + simp [hbitFalse, toPoly_zero_eq_zero] + +/-- Sparse polynomial with coefficients at the listed exponents. -/ +noncomputable def sparsePolynomial : List Nat → Polynomial (ZMod 2) + | [] => 0 + | exponent :: rest => X ^ exponent + sparsePolynomial rest + +/-- Polynomial semantics of `sparseMulByNat`. -/ +lemma toPoly_sparseMulByNat {w W : Nat} (hW : w ≤ W) (exponents : List Nat) + (hExp : ∀ exponent ∈ exponents, w + exponent ≤ W) (a : BitVec w) : + toPoly (BitVec.ofNat W (sparseMulByNat exponents a.toNat)) = + toPoly (BitVec.zeroExtend W a) * sparsePolynomial exponents := by + induction exponents generalizing a with + | nil => + simp [sparseMulByNat, sparsePolynomial, toPoly_zero_eq_zero] + | cons exponent rest ih => + have hExp_head : w + exponent ≤ W := hExp exponent (by simp) + have hExp_rest : ∀ exponent ∈ rest, w + exponent ≤ W := by + intro e he + exact hExp e (by simp [he]) + change toPoly (BitVec.ofNat W ((a.toNat <<< exponent) ^^^ sparseMulByNat rest a.toNat)) = + toPoly (BitVec.zeroExtend W a) * (X ^ exponent + sparsePolynomial rest) + rw [ofNat_xor] + rw [toPoly_xor] + rw [ih hExp_rest a] + have ha_lt : (BitVec.zeroExtend W a).toNat < 2 ^ w := by + rw [zeroExtend_toNat hW a] + exact a.isLt + have hshift : + toPoly (BitVec.ofNat W (a.toNat <<< exponent)) = + toPoly (BitVec.zeroExtend W a) * X ^ exponent := by + have hofNat_eq : (BitVec.ofNat W a.toNat : BitVec W) = BitVec.zeroExtend W a := by + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_ofNat, zeroExtend_toNat hW a] + exact Nat.mod_eq_of_lt + (lt_of_lt_of_le a.isLt (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) hW)) + rw [ofNat_shiftLeft, hofNat_eq] + exact toPoly_shiftLeft_no_overflow (d := w) (BitVec.zeroExtend W a) + (ha := ha_lt) (h_no_overflow := hExp_head) + rw [hshift] + ring + +/-- Soundness of the kernel-safe square-step checker. -/ +theorem checkSquareStep_correct {width : Nat} {polyExponents : List Nat} + (hExp : ∀ exponent ∈ polyExponents, width + exponent ≤ 2 * width) + (rPrev q rNext : BitVec width) : + checkSquareStep width polyExponents rPrev q rNext = true → + (toPoly rPrev) ^ 2 = + toPoly (BitVec.zeroExtend (2 * width) q) * sparsePolynomial polyExponents + + toPoly rNext := by + intro h + unfold checkSquareStep at h + rw [beq_iff_eq] at h + have hWidth : width ≤ 2 * width := Nat.le_mul_of_pos_left width (by norm_num : 0 < 2) + have hBv : + (BitVec.ofNat (2 * width) (clSqNat rPrev.toNat width) : BitVec (2 * width)) = + (BitVec.ofNat (2 * width) (sparseMulByNat polyExponents q.toNat ^^^ rNext.toNat) : + BitVec (2 * width)) := by + simpa using congrArg (fun n => (BitVec.ofNat (2 * width) n : BitVec (2 * width))) h + rw [ofNat_xor] at hBv + apply_fun toPoly at hBv + rw [toPoly_xor] at hBv + rw [toPoly_clMulNat rPrev rPrev] at hBv + rw [← pow_two] at hBv + rw [toPoly_sparseMulByNat hWidth polyExponents hExp q] at hBv + have hr : toPoly (BitVec.ofNat (2 * width) rNext.toNat : BitVec (2 * width)) = + toPoly rNext := by + have hofNat_eq : + (BitVec.ofNat (2 * width) rNext.toNat : BitVec (2 * width)) = + BitVec.zeroExtend (2 * width) rNext := by + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_ofNat, zeroExtend_toNat hWidth rNext] + exact Nat.mod_eq_of_lt + (lt_of_lt_of_le rNext.isLt (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) hWidth)) + rw [hofNat_eq, toPoly_zeroExtend hWidth] + rw [hr] at hBv + exact hBv + +/-- Soundness of the kernel-safe division-step checker. -/ +theorem checkDivStep_correct {width : Nat} (a q b r : BitVec width) : + checkDivStep width a q b r = true → + toPoly a = toPoly q * toPoly b + toPoly r := by + intro h + unfold checkDivStep at h + rw [beq_iff_eq] at h + have hWidth : width ≤ 2 * width := Nat.le_mul_of_pos_left width (by norm_num : 0 < 2) + have hBv : + (BitVec.ofNat (2 * width) a.toNat : BitVec (2 * width)) = + (BitVec.ofNat (2 * width) (clMulNat q.toNat b.toNat width ^^^ r.toNat) : + BitVec (2 * width)) := by + simpa using congrArg (fun n => (BitVec.ofNat (2 * width) n : BitVec (2 * width))) h + rw [ofNat_xor] at hBv + apply_fun toPoly at hBv + rw [toPoly_xor, toPoly_clMulNat q b] at hBv + have ha : + toPoly (BitVec.ofNat (2 * width) a.toNat : BitVec (2 * width)) = toPoly a := by + have hofNat_eq : + (BitVec.ofNat (2 * width) a.toNat : BitVec (2 * width)) = + BitVec.zeroExtend (2 * width) a := by + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_ofNat, zeroExtend_toNat hWidth a] + exact Nat.mod_eq_of_lt + (lt_of_lt_of_le a.isLt (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) hWidth)) + rw [hofNat_eq, toPoly_zeroExtend hWidth] + have hr : + toPoly (BitVec.ofNat (2 * width) r.toNat : BitVec (2 * width)) = toPoly r := by + have hofNat_eq : + (BitVec.ofNat (2 * width) r.toNat : BitVec (2 * width)) = + BitVec.zeroExtend (2 * width) r := by + apply BitVec.eq_of_toNat_eq + rw [BitVec.toNat_ofNat, zeroExtend_toNat hWidth r] + exact Nat.mod_eq_of_lt + (lt_of_lt_of_le r.isLt (pow_le_pow_right' (by decide : (1 : Nat) ≤ 2) hWidth)) + rw [hofNat_eq, toPoly_zeroExtend hWidth] + rw [ha, hr] at hBv + exact hBv + +/-- Helper lemma for chaining modular Frobenius-squaring certificate steps. -/ +lemma chain_step {width : Nat} {P : Polynomial (ZMod 2)} (hP : P ≠ 0) {k : Nat} + {prev next : Polynomial (ZMod 2)} {qVal : BitVec width} + (hPrev : X ^ (2 ^ k) % P = prev % P) + (hStep : prev ^ 2 = toPoly (BitVec.zeroExtend (2 * width) qVal) * P + next) : + X ^ (2 ^ (k + 1)) % P = next % P := by + rw [pow_succ', pow_mul, ← pow_mul, mul_comm, pow_mul, pow_two] + rw [CanonicalEuclideanDomain.mul_mod_eq (hn := hP), hPrev] + rw [← CanonicalEuclideanDomain.mul_mod_eq (hn := hP), ← pow_two] + conv_lhs => rw [hStep] + conv_lhs => rw [CanonicalEuclideanDomain.add_mod_eq (hn := hP)] + conv_lhs => rw [CanonicalEuclideanDomain.mul_mod_eq (hn := hP)] + conv_lhs => simp only [EuclideanDomain.mod_self, mul_zero, zero_add] + conv_lhs => rw [EuclideanDomain.zero_mod, zero_add] + rw [CanonicalEuclideanDomain.mod_mod_eq_mod (hn := hP)] + +/-- Polynomial interpretation of a one-hot bitvector. -/ +lemma toPoly_one_shiftLeft {w : Nat} (n : Nat) (h : n < w) : + toPoly (1 <<< n : BitVec w) = X ^ n := by + rw [toPoly] + rw [Finset.sum_eq_single (⟨n, h⟩ : Fin w)] + · simp only + simp only [BitVec.natCast_eq_ofNat, ite_eq_left_iff, Bool.not_eq_true] + intro h_getLsb_eq_false + have h_getLsb_eq_true : (BitVec.ofNat w (1 <<< n)).getLsb ⟨n, h⟩ = true := by + rw [BitVec.getLsb] + simp only [BitVec.toNat_ofNat, Nat.testBit_mod_two_pow, h, decide_true, + Nat.testBit_shiftLeft, ge_iff_le, le_refl, tsub_self, Nat.testBit_zero, + Nat.mod_succ, Bool.and_self] + rw [h_getLsb_eq_false] at h_getLsb_eq_true + exact (Bool.false_ne_true h_getLsb_eq_true).elim + · intro b _ hb_ne_n_fin + split_ifs with h_lsb + · exfalso + have h_getLsb_eq_false : ((1 <<< n) : BitVec w).getLsb b = false := by + rw [BitVec.getLsb] + have h_lhs : ((1 <<< n) : BitVec w).toNat = 1 <<< n := by + simp only [Nat.shiftLeft_eq, one_mul, BitVec.natCast_eq_ofNat, + BitVec.toNat_ofNat] + apply Nat.mod_eq_of_lt + apply Nat.pow_lt_pow_right (ha := by omega) (h := by omega) + rw [h_lhs] + rw [Nat.one_shiftLeft] + rw [Nat.testBit_two_pow] + let h_ne := Fin.val_ne_of_ne hb_ne_n_fin + exact decide_eq_false (id (Ne.symm h_ne)) + rw [h_getLsb_eq_false] at h_lsb + exact (Bool.false_ne_true h_lsb).elim + · rfl + · intro h_absurd + simp at h_absurd + +end Extension + +end BinaryField diff --git a/CompPoly/Fields/Binary/Extension/Primitive.lean b/CompPoly/Fields/Binary/Extension/Primitive.lean new file mode 100644 index 00000000..8076e532 --- /dev/null +++ b/CompPoly/Fields/Binary/Extension/Primitive.lean @@ -0,0 +1,509 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Impl +import Mathlib.Data.Nat.Prime.Defs +import Mathlib.Tactic.IntervalCases +import Mathlib.Tactic.NormNum + +/-! +# Direct Binary-Extension Irreducibility And Primitive-Order Helpers + +Reusable proof helpers for the concrete `GF(2^48)` and `GF(2^72)` certificate +files. The concrete modules still need generated modular-power and gcd +certificates; this file supplies the small field-theoretic shell those +certificates plug into. +-/ + +namespace BinaryField + +namespace Extension + +open Polynomial + +namespace Concrete + +variable (params : ExecutableParams) + +/-- Natural-number encoding of executable multiplication modulo the defining polynomial. -/ +def mulNat (x y : Nat) : Nat := + reduceNat params (clMulNat x y params.degree) + +/-- Natural-number encoding of executable squaring modulo the defining polynomial. -/ +def squareNat (x : Nat) : Nat := + mulNat params x x + +/-- Raw bit-pattern construction preserves bounded natural encodings. -/ +theorem toNat_ofNat_of_lt {n : Nat} (hn : n < 2 ^ params.degree) : + toNat params (ofNat params n) = n := by + simp [toNat, toBitVec, ofNat, ofBitVec, BitVec.toNat_ofNat, Nat.mod_eq_of_lt hn] + +/-- A bounded raw bit-pattern different from `1` is not executable one. -/ +theorem ofNat_ne_one_of_lt {n : Nat} (hDegree_pos : 0 < params.degree) + (hn : n < 2 ^ params.degree) (hne : n ≠ 1) : + ofNat params n ≠ one params := by + intro h + have hnat := congrArg (toNat params) h + rw [toNat_ofNat_of_lt params hn] at hnat + have hone : toNat params (one params) = 1 := by + unfold one + exact toNat_ofNat_of_lt params (n := 1) (Nat.one_lt_two_pow hDegree_pos.ne') + rw [hone] at hnat + exact hne hnat + +/-- Nat-level modular multiplication returns a bounded residue. -/ +theorem mulNat_lt_two_pow (x y : Nat) : + mulNat params x y < 2 ^ params.degree := by + unfold mulNat reduceNat + exact Nat.mod_lt _ (pow_pos (by norm_num : 0 < 2) params.degree) + +/-- Executable multiplication agrees with Nat-level modular multiplication on bounded inputs. -/ +theorem mul_ofNat_of_lt {x y : Nat} (hx : x < 2 ^ params.degree) + (hy : y < 2 ^ params.degree) : + mul params (ofNat params x) (ofNat params y) = ofNat params (mulNat params x y) := by + unfold mul mulNat reduce + rw [toNat_ofNat_of_lt params hx, toNat_ofNat_of_lt params hy] + +/-- Executable squaring agrees with Nat-level modular squaring on bounded inputs. -/ +theorem square_ofNat_of_lt {x : Nat} (hx : x < 2 ^ params.degree) : + square params (ofNat params x) = ofNat params (squareNat params x) := by + unfold square squareNat + exact mul_ofNat_of_lt params hx hx + +/-- +Consume a structurally checked power chain. + +Each subsequent `(exponent, residue)` entry must use the previous exponent as +`exponent / 2` and the previous residue as the halving-recursion result for +`Concrete.pow`. +-/ +def consumePowNatChain (a : Nat) : + Nat → Nat → List (Nat × Nat) → Option (Nat × Nat) + | prevExponent, prevResidue, [] => some (prevExponent, prevResidue) + | prevExponent, prevResidue, (exponent, residue) :: rest => + if exponent == 0 then + none + else if prevExponent == exponent / 2 then + let halfSq := squareNat params prevResidue + let expected := + if exponent % 2 = 0 then halfSq else mulNat params halfSq a + if residue == expected then + consumePowNatChain a exponent expected rest + else + none + else + none + +/-- Check a structurally encoded Nat-level power chain. -/ +def checkPowNatChain (a target : Nat) (cert : List (Nat × Nat)) (expected : Nat) : Bool := + match cert with + | [] => false + | (startExponent, startResidue) :: rest => + if startExponent == 0 then + if startResidue == 1 then + match consumePowNatChain params a 0 1 rest with + | some (lastExponent, lastResidue) => + if lastExponent == target then + if lastResidue == expected then true else false + else + false + | none => false + else + false + else + false + +/-- A consumed structural power chain evaluates to the existing `Concrete.pow`. -/ +theorem consumePowNatChain_correct {a : Nat} (ha : a < 2 ^ params.degree) : + ∀ cert prevExponent prevResidue lastExponent lastResidue, + pow params (ofNat params a) prevExponent = ofNat params prevResidue → + prevResidue < 2 ^ params.degree → + consumePowNatChain params a prevExponent prevResidue cert = + some (lastExponent, lastResidue) → + pow params (ofNat params a) lastExponent = ofNat params lastResidue ∧ + lastResidue < 2 ^ params.degree := by + intro cert + induction cert with + | nil => + intro prevExponent prevResidue lastExponent lastResidue hprev hprevBound hchain + simp [consumePowNatChain] at hchain + rcases hchain with ⟨rfl, rfl⟩ + exact ⟨hprev, hprevBound⟩ + | cons step rest ih => + intro prevExponent prevResidue lastExponent lastResidue hprev hprevBound hchain + rcases step with ⟨exponent, residue⟩ + simp only [consumePowNatChain] at hchain + by_cases hzero : exponent == 0 + · simp [hzero] at hchain + · simp [hzero] at hchain + let halfSq := squareNat params prevResidue + let expected := + if exponent % 2 = 0 then halfSq else mulNat params halfSq a + have hhalfEq : prevExponent = exponent / 2 := hchain.1 + have hchainRest : + consumePowNatChain params a exponent expected rest = + some (lastExponent, lastResidue) := by + simpa [expected, halfSq] using hchain.2.2 + cases exponent with + | zero => + simp at hzero + | succ exponent' => + have hpowCurrent : + pow params (ofNat params a) (exponent' + 1) = + ofNat params expected := by + rw [pow] + rw [← hhalfEq, hprev] + by_cases heven : (exponent' + 1) % 2 = 0 + · simp [expected, halfSq, heven, + square_ofNat_of_lt params hprevBound] + · have hhalfSqBound : + squareNat params prevResidue < 2 ^ params.degree := + mulNat_lt_two_pow params prevResidue prevResidue + rw [square_ofNat_of_lt params hprevBound] + simp only [heven, ↓reduceIte] + rw [mul_ofNat_of_lt params hhalfSqBound ha] + simp [expected, halfSq, squareNat, heven] + have hboundCurrent : + expected < 2 ^ params.degree := by + by_cases heven : (exponent' + 1) % 2 = 0 + · simp [expected, halfSq, heven] + exact mulNat_lt_two_pow params prevResidue prevResidue + · simp [expected, halfSq, heven] + exact mulNat_lt_two_pow params (squareNat params prevResidue) a + exact ih (exponent' + 1) expected lastExponent lastResidue + hpowCurrent hboundCurrent hchainRest + +/-- A checked structural power chain proves the requested power residue. -/ +theorem pow_eq_of_checkPowNatChain {a target : Nat} {cert : List (Nat × Nat)} + {expected : Nat} (hDegree_pos : 0 < params.degree) (ha : a < 2 ^ params.degree) + (hcert : checkPowNatChain params a target cert expected = true) : + pow params (ofNat params a) target = ofNat params expected ∧ + expected < 2 ^ params.degree := by + unfold checkPowNatChain at hcert + cases cert with + | nil => + simp at hcert + | cons start rest => + rcases start with ⟨startExponent, startResidue⟩ + by_cases hstartExp : startExponent == 0 + · simp [hstartExp] at hcert + cases hconsume : consumePowNatChain params a 0 1 rest with + | none => + simp [hconsume] at hcert + | some last => + rcases last with ⟨lastExponent, lastResidue⟩ + simp [hconsume] at hcert + have hlastExp : lastExponent = target := hcert.2.1 + have hlastResidue : lastResidue = expected := hcert.2.2 + have hchain := + consumePowNatChain_correct params ha rest + 0 1 lastExponent lastResidue + (by simp [pow, one]) + (Nat.one_lt_two_pow hDegree_pos.ne') + hconsume + rw [← hlastExp, ← hlastResidue] + exact hchain + · simp [hstartExp] at hcert + +end Concrete + +noncomputable section + +/-- A reducible degree-`n` polynomial has an irreducible factor of degree at most `n / 2`. -/ +lemma exists_irreducible_factor_le_half_of_reducible {R : Type*} [Field R] + (P : Polynomial R) {n : Nat} (h_pos : 0 < n) (h_deg : P.natDegree = n) + (h_red : ¬ Irreducible P) : + ∃ q, Irreducible q ∧ q ∣ P ∧ 2 * q.natDegree ≤ n := by + have h_not_unit : ¬ IsUnit P := by + by_contra h_unit + rw [Polynomial.isUnit_iff_degree_eq_zero] at h_unit + have h_ne_zero : P ≠ 0 := by + intro hzero + rw [hzero, Polynomial.natDegree_zero] at h_deg + omega + have h_natDeg_zero : P.natDegree = 0 := + (Polynomial.degree_eq_iff_natDegree_eq h_ne_zero).mp h_unit + omega + have h_exists_split : ∃ a b, P = a * b ∧ ¬ IsUnit a ∧ ¬ IsUnit b := by + rw [irreducible_iff, not_and_or, not_forall] at h_red + simp only [h_not_unit, not_false_eq_true] at h_red + push Not at h_red + simp only [IsEmpty.exists_iff, false_or] at h_red + rcases h_red with ⟨a, b, h_eq, h_non_units⟩ + exact ⟨a, b, h_eq, h_non_units⟩ + rcases h_exists_split with ⟨a, b, h_eq, ha_nonunit, hb_nonunit⟩ + have h_a_ne_zero : a ≠ 0 := by + intro ha_zero + rw [h_eq, ha_zero, zero_mul, Polynomial.natDegree_zero] at h_deg + omega + have h_b_ne_zero : b ≠ 0 := by + intro hb_zero + rw [h_eq, hb_zero, mul_zero, Polynomial.natDegree_zero] at h_deg + omega + have h_deg_sum : a.natDegree + b.natDegree = n := by + rw [← h_deg, h_eq] + exact (Polynomial.natDegree_mul (hp := h_a_ne_zero) (hq := h_b_ne_zero)).symm + by_cases h_le : a.natDegree ≤ b.natDegree + · have h_a_half : 2 * a.natDegree ≤ n := by omega + obtain ⟨q, hq_irr, hq_dvd_a⟩ := + WfDvdMonoid.exists_irreducible_factor ha_nonunit h_a_ne_zero + refine ⟨q, hq_irr, dvd_trans hq_dvd_a (Dvd.intro b h_eq.symm), ?_⟩ + have hq_le_a : q.natDegree ≤ a.natDegree := + Polynomial.natDegree_le_of_dvd hq_dvd_a h_a_ne_zero + omega + · have h_b_half : 2 * b.natDegree ≤ n := by omega + obtain ⟨q, hq_irr, hq_dvd_b⟩ := + WfDvdMonoid.exists_irreducible_factor hb_nonunit h_b_ne_zero + refine ⟨q, hq_irr, dvd_trans hq_dvd_b (Dvd.intro_left a h_eq.symm), ?_⟩ + have hq_le_b : q.natDegree ≤ b.natDegree := + Polynomial.natDegree_le_of_dvd hq_dvd_b h_b_ne_zero + omega + +private lemma dvd_32_of_dvd_32_le_half {d : Nat} (hdvd : d ∣ 32) (hle : 2 * d ≤ 32) : + d ∣ 16 := by + rcases hdvd with ⟨k, hk⟩ + have hdle : d ≤ 16 := by omega + interval_cases d + all_goals omega + +private lemma dvd_48_of_dvd_48_le_half {d : Nat} (hdvd : d ∣ 48) (hle : 2 * d ≤ 48) : + d ∣ 24 ∨ d ∣ 16 := by + rcases hdvd with ⟨k, hk⟩ + have hdle : d ≤ 24 := by omega + interval_cases d + all_goals omega + +private lemma dvd_64_of_dvd_64_le_half {d : Nat} (hdvd : d ∣ 64) (hle : 2 * d ≤ 64) : + d ∣ 32 := by + rcases hdvd with ⟨k, hk⟩ + have hdle : d ≤ 32 := by omega + interval_cases d + all_goals omega + +private lemma dvd_72_of_dvd_72_le_half {d : Nat} (hdvd : d ∣ 72) (hle : 2 * d ≤ 72) : + d ∣ 36 ∨ d ∣ 24 := by + rcases hdvd with ⟨k, hk⟩ + have hdle : d ≤ 36 := by omega + interval_cases d + all_goals omega + +/-- +Rabin irreducibility test specialized to degree `32` over `GF(2)`. + +The concrete certificate files provide the divisibility check +`P ∣ X^(2^32) - X` and the gcd check for the only prime factor `2` of +`32`. +-/ +lemma irreducible_of_rabin_32_passed_over_GF2 (P : Polynomial (ZMod 2)) + (h_deg : P.natDegree = 32) + (h_trace : P ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 32) + X)) + (h_gcd16 : + EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 16) + X) P = 1) : + Irreducible P := by + have h_ringCharZmod2 : ringChar (ZMod 2) = 2 := by + exact ZMod.ringChar_zmod_n 2 + letI : Fact (Nat.Prime (ringChar (ZMod 2))) := by + exact Fact.mk (by + rw [h_ringCharZmod2] + exact Nat.prime_two) + by_contra h_red + rcases exists_irreducible_factor_le_half_of_reducible + P (by norm_num : 0 < 32) h_deg h_red with + ⟨q, hq_irr, hq_dvd_P, hq_half⟩ + have hq_dvd_trace : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 32) + X) := + dvd_trans hq_dvd_P h_trace + have h_sub_eq := CharTwo.sub_eq_add ((X : Polynomial (ZMod 2)) ^ 2 ^ 32) X + simp only [← h_sub_eq] at hq_dvd_trace + have h_deg_dvd_32 : q.natDegree ∣ 32 := by + apply Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 32) (q := q) (hq_irr := hq_irr).mp + rw [ZMod.card] + exact hq_dvd_trace + have h_dvd16 := dvd_32_of_dvd_32_le_half h_deg_dvd_32 hq_half + have hq_dvd_check : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 16) - X) := by + have hres := + Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 16) (q := q) (hq_irr := hq_irr).mpr h_dvd16 + rw [ZMod.card] at hres + exact hres + rw [CharTwo.sub_eq_add] at hq_dvd_check + have hq_dvd_gcd : + q ∣ EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 16) + X) P := + EuclideanDomain.dvd_gcd (by convert hq_dvd_check) hq_dvd_P + rw [h_gcd16] at hq_dvd_gcd + exact (irreducible_iff.mp hq_irr).1 (isUnit_of_dvd_one hq_dvd_gcd) + +/-- +Rabin irreducibility test specialized to degree `48` over `GF(2)`. + +The concrete certificate files provide the divisibility check +`P ∣ X^(2^48) - X` and the two gcd checks for prime factors `2` and `3` of +`48`. +-/ +lemma irreducible_of_rabin_48_passed_over_GF2 (P : Polynomial (ZMod 2)) + (h_deg : P.natDegree = 48) + (h_trace : P ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 48) + X)) + (h_gcd24 : + EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 24) + X) P = 1) + (h_gcd16 : + EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 16) + X) P = 1) : + Irreducible P := by + have h_ringCharZmod2 : ringChar (ZMod 2) = 2 := by + exact ZMod.ringChar_zmod_n 2 + letI : Fact (Nat.Prime (ringChar (ZMod 2))) := by + exact Fact.mk (by + rw [h_ringCharZmod2] + exact Nat.prime_two) + by_contra h_red + rcases exists_irreducible_factor_le_half_of_reducible + P (by norm_num : 0 < 48) h_deg h_red with + ⟨q, hq_irr, hq_dvd_P, hq_half⟩ + have hq_dvd_trace : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 48) + X) := + dvd_trans hq_dvd_P h_trace + have h_sub_eq := CharTwo.sub_eq_add ((X : Polynomial (ZMod 2)) ^ 2 ^ 48) X + simp only [← h_sub_eq] at hq_dvd_trace + have h_deg_dvd_48 : q.natDegree ∣ 48 := by + apply Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 48) (q := q) (hq_irr := hq_irr).mp + rw [ZMod.card] + exact hq_dvd_trace + rcases dvd_48_of_dvd_48_le_half h_deg_dvd_48 hq_half with h_dvd24 | h_dvd16 + · have hq_dvd_check : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 24) - X) := by + have hres := + Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 24) (q := q) (hq_irr := hq_irr).mpr h_dvd24 + rw [ZMod.card] at hres + exact hres + rw [CharTwo.sub_eq_add] at hq_dvd_check + have hq_dvd_gcd : + q ∣ EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 24) + X) P := + EuclideanDomain.dvd_gcd (by convert hq_dvd_check) hq_dvd_P + rw [h_gcd24] at hq_dvd_gcd + exact (irreducible_iff.mp hq_irr).1 (isUnit_of_dvd_one hq_dvd_gcd) + · have hq_dvd_check : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 16) - X) := by + have hres := + Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 16) (q := q) (hq_irr := hq_irr).mpr h_dvd16 + rw [ZMod.card] at hres + exact hres + rw [CharTwo.sub_eq_add] at hq_dvd_check + have hq_dvd_gcd : + q ∣ EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 16) + X) P := + EuclideanDomain.dvd_gcd (by convert hq_dvd_check) hq_dvd_P + rw [h_gcd16] at hq_dvd_gcd + exact (irreducible_iff.mp hq_irr).1 (isUnit_of_dvd_one hq_dvd_gcd) + +/-- +Rabin irreducibility test specialized to degree `64` over `GF(2)`. + +The concrete certificate files provide the divisibility check +`P ∣ X^(2^64) - X` and the gcd check for the only prime factor `2` of +`64`. +-/ +lemma irreducible_of_rabin_64_passed_over_GF2 (P : Polynomial (ZMod 2)) + (h_deg : P.natDegree = 64) + (h_trace : P ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 64) + X)) + (h_gcd32 : + EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 32) + X) P = 1) : + Irreducible P := by + have h_ringCharZmod2 : ringChar (ZMod 2) = 2 := by + exact ZMod.ringChar_zmod_n 2 + letI : Fact (Nat.Prime (ringChar (ZMod 2))) := by + exact Fact.mk (by + rw [h_ringCharZmod2] + exact Nat.prime_two) + by_contra h_red + rcases exists_irreducible_factor_le_half_of_reducible + P (by norm_num : 0 < 64) h_deg h_red with + ⟨q, hq_irr, hq_dvd_P, hq_half⟩ + have hq_dvd_trace : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 64) + X) := + dvd_trans hq_dvd_P h_trace + have h_sub_eq := CharTwo.sub_eq_add ((X : Polynomial (ZMod 2)) ^ 2 ^ 64) X + simp only [← h_sub_eq] at hq_dvd_trace + have h_deg_dvd_64 : q.natDegree ∣ 64 := by + apply Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 64) (q := q) (hq_irr := hq_irr).mp + rw [ZMod.card] + exact hq_dvd_trace + have h_dvd32 := dvd_64_of_dvd_64_le_half h_deg_dvd_64 hq_half + have hq_dvd_check : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 32) - X) := by + have hres := + Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 32) (q := q) (hq_irr := hq_irr).mpr h_dvd32 + rw [ZMod.card] at hres + exact hres + rw [CharTwo.sub_eq_add] at hq_dvd_check + have hq_dvd_gcd : + q ∣ EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 32) + X) P := + EuclideanDomain.dvd_gcd (by convert hq_dvd_check) hq_dvd_P + rw [h_gcd32] at hq_dvd_gcd + exact (irreducible_iff.mp hq_irr).1 (isUnit_of_dvd_one hq_dvd_gcd) + +/-- +Rabin irreducibility test specialized to degree `72` over `GF(2)`. + +The concrete certificate files provide the divisibility check +`P ∣ X^(2^72) - X` and the two gcd checks for prime factors `2` and `3` of +`72`. +-/ +lemma irreducible_of_rabin_72_passed_over_GF2 (P : Polynomial (ZMod 2)) + (h_deg : P.natDegree = 72) + (h_trace : P ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 72) + X)) + (h_gcd36 : + EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 36) + X) P = 1) + (h_gcd24 : + EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 24) + X) P = 1) : + Irreducible P := by + have h_ringCharZmod2 : ringChar (ZMod 2) = 2 := by + exact ZMod.ringChar_zmod_n 2 + letI : Fact (Nat.Prime (ringChar (ZMod 2))) := by + exact Fact.mk (by + rw [h_ringCharZmod2] + exact Nat.prime_two) + by_contra h_red + rcases exists_irreducible_factor_le_half_of_reducible + P (by norm_num : 0 < 72) h_deg h_red with + ⟨q, hq_irr, hq_dvd_P, hq_half⟩ + have hq_dvd_trace : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 72) + X) := + dvd_trans hq_dvd_P h_trace + have h_sub_eq := CharTwo.sub_eq_add ((X : Polynomial (ZMod 2)) ^ 2 ^ 72) X + simp only [← h_sub_eq] at hq_dvd_trace + have h_deg_dvd_72 : q.natDegree ∣ 72 := by + apply Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 72) (q := q) (hq_irr := hq_irr).mp + rw [ZMod.card] + exact hq_dvd_trace + rcases dvd_72_of_dvd_72_le_half h_deg_dvd_72 hq_half with h_dvd36 | h_dvd24 + · have hq_dvd_check : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 36) - X) := by + have hres := + Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 36) (q := q) (hq_irr := hq_irr).mpr h_dvd36 + rw [ZMod.card] at hres + exact hres + rw [CharTwo.sub_eq_add] at hq_dvd_check + have hq_dvd_gcd : + q ∣ EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 36) + X) P := + EuclideanDomain.dvd_gcd (by convert hq_dvd_check) hq_dvd_P + rw [h_gcd36] at hq_dvd_gcd + exact (irreducible_iff.mp hq_irr).1 (isUnit_of_dvd_one hq_dvd_gcd) + · have hq_dvd_check : q ∣ ((X : Polynomial (ZMod 2)) ^ (2 ^ 24) - X) := by + have hres := + Polynomial.irreducible_dvd_X_pow_sub_X_iff_natDegree_dvd + (R := ZMod 2) (n := 24) (q := q) (hq_irr := hq_irr).mpr h_dvd24 + rw [ZMod.card] at hres + exact hres + rw [CharTwo.sub_eq_add] at hq_dvd_check + have hq_dvd_gcd : + q ∣ EuclideanDomain.gcd ((X : Polynomial (ZMod 2)) ^ (2 ^ 24) + X) P := + EuclideanDomain.dvd_gcd (by convert hq_dvd_check) hq_dvd_P + rw [h_gcd24] at hq_dvd_gcd + exact (irreducible_iff.mp hq_irr).1 (isUnit_of_dvd_one hq_dvd_gcd) + +end + +end Extension + +end BinaryField diff --git a/CompPoly/Fields/Binary/GF2_32.lean b/CompPoly/Fields/Binary/GF2_32.lean new file mode 100644 index 00000000..ed2c8264 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32.lean @@ -0,0 +1,16 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_32.Prelude +import CompPoly.Fields.Binary.GF2_32.Basic +import CompPoly.Fields.Binary.GF2_32.Impl +import CompPoly.Fields.Binary.GF2_32.XPowTwoPowModCertificate +import CompPoly.Fields.Binary.GF2_32.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_32.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_32.Primitive +import CompPoly.Fields.Binary.GF2_32.RootContexts + +/-! # GF(2^32) Binary Field Facade -/ diff --git a/CompPoly/Fields/Binary/GF2_32/Basic.lean b/CompPoly/Fields/Binary/GF2_32/Basic.lean new file mode 100644 index 00000000..d7b6c77a --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/Basic.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Basic +import CompPoly.Fields.Binary.GF2_32.Prelude + +/-! +# GF(2^32) Quotient Specification + +The quotient/specification carrier for the candidate polynomial +`X ^ 32 + X ^ 22 + X ^ 2 + X + 1`. + +Field, finite, characteristic, and cardinality instances are conditional on the +irreducibility certificate that will be provided by the concrete certificate +modules. +-/ + +namespace GF2_32 + +open Polynomial AdjoinRoot + +noncomputable section + +/-- Quotient/specification carrier for `GF(2^32)`. -/ +abbrev SpecField : Type := + BinaryField.Extension.SpecField definingPolynomialData + +private instance instIrreduciblePolynomialFact [Fact (Irreducible definingPolynomial)] : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using (inferInstance : Fact (Irreducible definingPolynomial)) + +/-- Conditional field instance, available once irreducibility is certified. -/ +instance instFieldSpecField [Fact (Irreducible definingPolynomial)] : + Field SpecField := + inferInstanceAs (Field (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional nontriviality, available once irreducibility is certified. -/ +instance instNontrivialSpecField [Fact (Irreducible definingPolynomial)] : + Nontrivial SpecField := + inferInstance + +/-- Quotient/specification carrier is inhabited. -/ +instance instInhabitedSpecField : Inhabited SpecField := + inferInstance + +/-- Algebra structure over `GF(2)`. -/ +instance instAlgebraSpecField : Algebra (ZMod 2) SpecField := + inferInstanceAs (Algebra (ZMod 2) (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional characteristic-two instance, available once irreducibility is certified. -/ +instance instCharTwoSpecField [Fact (Irreducible definingPolynomial)] : + CharP SpecField 2 := + inferInstance + +/-- Canonical embedding of `GF(2)` into `SpecField`. -/ +def ofGF2 : ZMod 2 →+* SpecField := + BinaryField.Extension.ofGF2 definingPolynomialData + +/-- The quotient root/generator. -/ +def root : SpecField := + BinaryField.Extension.root definingPolynomialData + +/-- The quotient root satisfies the defining polynomial. -/ +theorem root_satisfies_definingPolynomial : + Polynomial.eval₂ (algebraMap (ZMod 2) SpecField) root definingPolynomial = 0 := + BinaryField.Extension.root_satisfies_polynomial definingPolynomialData + +/-- Conditional finite type, available once irreducibility is certified. -/ +instance instFintypeSpecField [Fact (Irreducible definingPolynomial)] : + Fintype SpecField := + inferInstanceAs (Fintype (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Cardinality of the certified quotient specification. -/ +theorem SpecField_card [Fact (Irreducible definingPolynomial)] : + Fintype.card SpecField = 2 ^ extensionDegree := + BinaryField.Extension.specField_card definingPolynomialData + +end + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_32/Impl.lean b/CompPoly/Fields/Binary/GF2_32/Impl.lean new file mode 100644 index 00000000..8cdffe8d --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/Impl.lean @@ -0,0 +1,365 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Impl +import CompPoly.Fields.Binary.GF2_32.Basic +import Mathlib.Algebra.Algebra.ZMod +import Mathlib.Algebra.CharP.CharAndCard +import Init.Data.Array.Lemmas + +/-! +# GF(2^32) Executable Bit-Vector Operations + +Executable operations for the `GF(2^32)` candidate polynomial +`X ^ 32 + X ^ 22 + X ^ 2 + X + 1`. + +This file exposes the raw `BitVec` carrier and arithmetic definitions. It does +claim the certified `Field` instance conditionally on the irreducibility +certificate supplied by `GF2_32.Primitive`. +-/ + +namespace GF2_32 + +namespace Concrete + +/-- Executable parameters for the `GF(2^32)` candidate polynomial. -/ +def params : BinaryField.Extension.ExecutableParams where + degree := extensionDegree + tailExponents := [0, 1, 2, 22] + tailExponents_bound := by + intro exponent h + simp at h + rcases h with rfl | rfl | rfl | rfl <;> unfold extensionDegree <;> omega + +/-- The executable tail list denotes the low-degree part of the GF32 polynomial. -/ +lemma definingPolynomial_eq_executableSparse : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ params.degree + + BinaryField.Extension.sparsePolynomial params.tailExponents := by + rw [show BinaryField.Extension.polynomial definingPolynomialData = definingPolynomial by rfl] + rw [definingPolynomial_eq_X_pow_add_tail] + simp [params, extensionDegree, definingTail, BinaryField.Extension.sparsePolynomial] + ring_nf + +end Concrete + +/-- Executable bit-vector carrier for `GF(2^32)`. -/ +@[reducible] +def ConcreteField : Type := + BinaryField.Extension.ConcreteField Concrete.params + +namespace ConcreteField + +abbrev rawWidth : Nat := + extensionDegree + +def toBitVec : ConcreteField → B32 := + BinaryField.Extension.Concrete.toBitVec Concrete.params + +def ofBitVec : B32 → ConcreteField := + BinaryField.Extension.Concrete.ofBitVec Concrete.params + +def toNat : ConcreteField → Nat := + BinaryField.Extension.Concrete.toNat Concrete.params + +def ofNat (x : Nat) : ConcreteField := + BinaryField.Extension.Concrete.ofNat Concrete.params x + +def root : ConcreteField := + BinaryField.Extension.Concrete.root Concrete.params + +def add : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.add Concrete.params + +def mul : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.mul Concrete.params + +def square : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.square Concrete.params + +def pow : ConcreteField → Nat → ConcreteField := + BinaryField.Extension.Concrete.pow Concrete.params + +def inv : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.inv Concrete.params + +def traceValue : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.traceValue Concrete.params + +def polynomialBasis : Array ConcreteField := + BinaryField.Extension.Concrete.polynomialBasis Concrete.params + +def baseConstants : Array ConcreteField := + BinaryField.Extension.Concrete.baseConstants Concrete.params + +noncomputable def toSpec : ConcreteField → SpecField := + BinaryField.Extension.Concrete.toSpec Concrete.params (data := definingPolynomialData) + +instance : BEq ConcreteField := + BinaryField.Extension.Concrete.instBEqConcreteField Concrete.params + +instance : LawfulBEq ConcreteField := + BinaryField.Extension.Concrete.instLawfulBEqConcreteField Concrete.params + +instance : Inhabited ConcreteField := + BinaryField.Extension.Concrete.instInhabitedConcreteField Concrete.params + +instance : Zero ConcreteField := + BinaryField.Extension.Concrete.instZeroConcreteField Concrete.params + +instance : One ConcreteField := + BinaryField.Extension.Concrete.instOneConcreteField Concrete.params + +instance : Add ConcreteField := + BinaryField.Extension.Concrete.instAddConcreteField Concrete.params + +instance : Neg ConcreteField := + BinaryField.Extension.Concrete.instNegConcreteField Concrete.params + +instance : Sub ConcreteField := + BinaryField.Extension.Concrete.instSubConcreteField Concrete.params + +instance : Mul ConcreteField := + BinaryField.Extension.Concrete.instMulConcreteField Concrete.params + +instance : Pow ConcreteField Nat := + BinaryField.Extension.Concrete.instPowConcreteField Concrete.params + +instance : Inv ConcreteField := + BinaryField.Extension.Concrete.instInvConcreteField Concrete.params + +/-- Certified executable field structure for `GF(2^32)`. -/ +instance (priority := 2000) instFieldConcreteField + [Fact (Irreducible definingPolynomial)] : + Field ConcreteField := by + haveI : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using + (inferInstance : Fact (Irreducible definingPolynomial)) + let hP : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ Concrete.params.degree + + BinaryField.Extension.sparsePolynomial Concrete.params.tailExponents := + Concrete.definingPolynomial_eq_executableSparse + let hP_degree : + (BinaryField.Extension.polynomial definingPolynomialData).degree = + Concrete.params.degree := by + simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + let hDegree_pos : 0 < Concrete.params.degree := by + unfold Concrete.params extensionDegree + norm_num + exact + { toDivisionRing := + { toRing := + { add := BinaryField.Extension.Concrete.add Concrete.params + zero := BinaryField.Extension.Concrete.zero Concrete.params + neg := BinaryField.Extension.Concrete.neg Concrete.params + sub := BinaryField.Extension.Concrete.sub Concrete.params + mul := BinaryField.Extension.Concrete.mul Concrete.params + one := BinaryField.Extension.Concrete.one Concrete.params + nsmul := fun m x => + if m % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + zsmul := fun m x => + if m % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + npow := fun m x => BinaryField.Extension.Concrete.pow Concrete.params x m + add_assoc := BinaryField.Extension.Concrete.add_assoc Concrete.params + add_comm := BinaryField.Extension.Concrete.add_comm Concrete.params + add_zero := BinaryField.Extension.Concrete.add_zero Concrete.params + zero_add := BinaryField.Extension.Concrete.zero_add Concrete.params + neg_add_cancel := BinaryField.Extension.Concrete.neg_add_cancel Concrete.params + sub_eq_add_neg := by intro _ _; rfl + nsmul_zero := fun _ => rfl + nsmul_succ := BinaryField.Extension.Concrete.nsmul_succ Concrete.params + zsmul_zero' := fun _ => rfl + zsmul_succ' := BinaryField.Extension.Concrete.zsmul_succ Concrete.params + zsmul_neg' := BinaryField.Extension.Concrete.zsmul_neg Concrete.params + mul_assoc := + BinaryField.Extension.Concrete.mul_assoc_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + one_mul := + BinaryField.Extension.Concrete.one_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_one := + BinaryField.Extension.Concrete.mul_one_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + left_distrib := + BinaryField.Extension.Concrete.left_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + right_distrib := + BinaryField.Extension.Concrete.right_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + zero_mul := + BinaryField.Extension.Concrete.zero_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_zero := + BinaryField.Extension.Concrete.mul_zero_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + natCast := BinaryField.Extension.Concrete.natCast Concrete.params + natCast_zero := BinaryField.Extension.Concrete.natCast_zero Concrete.params + natCast_succ := BinaryField.Extension.Concrete.natCast_succ Concrete.params + intCast := BinaryField.Extension.Concrete.intCast Concrete.params + intCast_ofNat := BinaryField.Extension.Concrete.intCast_ofNat Concrete.params + intCast_negSucc := BinaryField.Extension.Concrete.intCast_negSucc Concrete.params + npow_zero := by + intro x + change BinaryField.Extension.Concrete.pow Concrete.params x 0 = + BinaryField.Extension.Concrete.one Concrete.params + simp [BinaryField.Extension.Concrete.pow] + npow_succ := by + intro m x + change BinaryField.Extension.Concrete.pow Concrete.params x (m + 1) = + BinaryField.Extension.Concrete.mul Concrete.params + (BinaryField.Extension.Concrete.pow Concrete.params x m) x + exact BinaryField.Extension.Concrete.pow_succ_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos m x } + inv := BinaryField.Extension.Concrete.inv Concrete.params + div := fun a b => + BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params b) + exists_pair_ne := + BinaryField.Extension.Concrete.exists_pair_ne Concrete.params hDegree_pos + mul_inv_cancel := by + intro a h + change BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params a) = + BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.mul_inv_cancel_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a (by simpa using h) + inv_zero := by + change BinaryField.Extension.Concrete.inv Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = + BinaryField.Extension.Concrete.zero Concrete.params + exact BinaryField.Extension.Concrete.inv_zero Concrete.params + div_eq_mul_inv := by + intro a b + rfl + qsmul := _ + nnqsmul := _ } + mul_comm := by + intro a b + change BinaryField.Extension.Concrete.mul Concrete.params a b = + BinaryField.Extension.Concrete.mul Concrete.params b a + exact BinaryField.Extension.Concrete.mul_comm_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a b } + +noncomputable instance : Fintype ConcreteField := + BinaryField.Extension.Concrete.instFintypeConcreteField Concrete.params + +instance : Finite ConcreteField := + BinaryField.Extension.Concrete.instFiniteConcreteField Concrete.params + +/-- The raw executable carrier has `2^32` bit-patterns. -/ +theorem card : + Fintype.card ConcreteField = 2 ^ extensionDegree := by + simpa [Concrete.params] using + BinaryField.Extension.Concrete.concreteField_card Concrete.params + +/-- The certified executable carrier has characteristic two. -/ +noncomputable instance instCharTwoConcreteField [Fact (Irreducible definingPolynomial)] : + CharP ConcreteField 2 := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : IsDomain ConcreteField := Field.isDomain + haveI : Fact (Nat.Prime 2) := ⟨Nat.prime_two⟩ + exact charP_of_card_eq_prime_pow (R := ConcreteField) (p := 2) + (f := extensionDegree) card + +/-- Canonical `GF(2)` algebra structure on the certified executable carrier. -/ +noncomputable instance instAlgebraConcreteField [Fact (Irreducible definingPolynomial)] : + Algebra (ZMod 2) ConcreteField := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : CharP ConcreteField 2 := instCharTwoConcreteField + exact ZMod.algebra ConcreteField 2 + +@[simp] +theorem polynomialBasis_size : + polynomialBasis.size = extensionDegree := by + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis] + exact Array.size_ofFn + +@[simp] +theorem baseConstants_size : + baseConstants.size = 2 := by + simp [baseConstants, BinaryField.Extension.Concrete.baseConstants] + +theorem toSpec_injective : + Function.Injective toSpec := by + apply BinaryField.Extension.Concrete.toSpec_injective + · simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + · unfold Concrete.params extensionDegree + norm_num + +theorem toSpec_zero : + toSpec 0 = 0 := by + exact BinaryField.Extension.Concrete.toSpec_zero Concrete.params + +theorem toSpec_one : + toSpec 1 = 1 := by + exact BinaryField.Extension.Concrete.toSpec_one Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + +theorem toSpec_add (a b : ConcreteField) : + toSpec (a + b) = toSpec a + toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_add Concrete.params a b + +theorem toSpec_neg (a : ConcreteField) : + toSpec (-a) = -toSpec a := by + exact BinaryField.Extension.Concrete.toSpec_neg Concrete.params a + +theorem toSpec_sub (a b : ConcreteField) : + toSpec (a - b) = toSpec a - toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_sub Concrete.params a b + +theorem toSpec_mul (a b : ConcreteField) : + toSpec (a * b) = toSpec a * toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_mul Concrete.params + (data := definingPolynomialData) + Concrete.definingPolynomial_eq_executableSparse + (by simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree) + a b + +/-- Ring homomorphism from executable GF32 elements to the quotient specification. -/ +noncomputable def toSpecRingHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →+* SpecField where + toFun := toSpec + map_zero' := toSpec_zero + map_one' := toSpec_one + map_add' := toSpec_add + map_mul' := toSpec_mul + +/-- Algebra homomorphism from executable GF32 elements to the quotient specification. -/ +noncomputable def toSpecAlgHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →ₐ[ZMod 2] SpecField where + __ := toSpecRingHom + commutes' := by + intro r + exact RingHom.congr_fun + (RingHom.ext_zmod (toSpecRingHom.comp (algebraMap (ZMod 2) ConcreteField)) + (algebraMap (ZMod 2) SpecField)) r + +/-- Algebra equivalence between executable GF32 elements and the quotient specification. -/ +noncomputable def toSpecAlgEquiv [Fact (Irreducible definingPolynomial)] : + ConcreteField ≃ₐ[ZMod 2] SpecField := + AlgEquiv.ofBijective toSpecAlgHom <| by + apply Function.Injective.bijective_of_nat_card_le + · exact toSpec_injective + · rw [Nat.card_eq_fintype_card, Nat.card_eq_fintype_card] + rw [card, BinaryField.Extension.specField_card definingPolynomialData] + simp [definingPolynomialData, extensionDegree] + +/-- The executable polynomial-basis generator maps to the quotient root. -/ +theorem toSpec_root : + toSpec root = GF2_32.root := by + exact BinaryField.Extension.Concrete.toSpec_root Concrete.params + (data := definingPolynomialData) + (by unfold Concrete.params extensionDegree; norm_num) + +end ConcreteField + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_32/Prelude.lean b/CompPoly/Fields/Binary/GF2_32/Prelude.lean new file mode 100644 index 00000000..f58e127e --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/Prelude.lean @@ -0,0 +1,158 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Prelude +import Mathlib.Tactic.ComputeDegree + +/-! +# GF(2^32) Prelude + +Defining constants and small executable metadata for the direct binary extension +with candidate primitive polynomial + +`X ^ 32 + X ^ 22 + X ^ 2 + X + 1`. + +Irreducibility and primitive-order certificates are added in later `GF2_32` +modules before this polynomial is used to construct public field instances. +-/ + +namespace GF2_32 + +open Polynomial + +noncomputable section + +/-- Extension degree for `GF(2^32)`. -/ +def extensionDegree : Nat := + 32 + +/-- Raw executable carrier width for `GF(2^32)`. -/ +abbrev B32 : Type := + BitVec extensionDegree + +/-- Field cardinality of `GF(2^32)`. -/ +def fieldSize : Nat := + BinaryField.Extension.fieldSize extensionDegree + +/-- Multiplicative group order of `GF(2^32)`. -/ +def multiplicativeGroupOrder : Nat := + BinaryField.Extension.multiplicativeGroupOrder extensionDegree + +/-- Low-degree tail `X ^ 22 + X ^ 2 + X + 1`. -/ +def definingTail : Polynomial (ZMod 2) := + X ^ 22 + X ^ 2 + X + 1 + +/-- Candidate primitive polynomial bitmask: `X ^ 32 + X ^ 22 + X ^ 2 + X + 1`. -/ +def definingBitmask : Nat := + 0x100400007 + +/-- Exponents with nonzero coefficients in the full defining polynomial. -/ +def definingPolynomialExponents : List Nat := + [0, 1, 2, 22, 32] + +/-- The tail has natural degree `22`. -/ +lemma definingTail_natDegree : + definingTail.natDegree = 22 := by + unfold definingTail + compute_degree! + +/-- The tail is monic. -/ +lemma definingTail_monic : + definingTail.Monic := by + unfold definingTail + monicity! + +/-- Metadata for the direct binary extension polynomial. -/ +def definingPolynomialData : BinaryField.Extension.DefiningPolynomialData where + degree := extensionDegree + tail := definingTail + tailDegree := 22 + bitmask := definingBitmask + tail_natDegree := definingTail_natDegree + tailDegree_lt_degree := by + unfold extensionDegree + omega + +/-- Candidate defining polynomial for `GF(2^32)`. -/ +def definingPolynomial : Polynomial (ZMod 2) := + BinaryField.Extension.polynomial definingPolynomialData + +/-- Expanded form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_X_pow_add_tail : + definingPolynomial = X ^ 32 + definingTail := by + rfl + +/-- Expanded sparse form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_sparse : + definingPolynomial = X ^ 32 + X ^ 22 + X ^ 2 + X + 1 := by + unfold definingPolynomial BinaryField.Extension.polynomial definingPolynomialData definingTail + extensionDegree + ring + +/-- The candidate defining polynomial is monic of degree `32`. -/ +lemma definingPolynomial_isMonicOfDegree : + IsMonicOfDegree definingPolynomial extensionDegree := + BinaryField.Extension.polynomial_isMonicOfDegree definingPolynomialData + +/-- The candidate defining polynomial has natural degree `32`. -/ +lemma definingPolynomial_natDegree : + definingPolynomial.natDegree = extensionDegree := + BinaryField.Extension.polynomial_natDegree definingPolynomialData + +/-- The candidate defining polynomial is monic. -/ +lemma definingPolynomial_monic : + definingPolynomial.Monic := + BinaryField.Extension.polynomial_monic definingPolynomialData + +/-- The candidate defining polynomial is nonzero. -/ +lemma definingPolynomial_ne_zero : + definingPolynomial ≠ 0 := + BinaryField.Extension.polynomial_ne_zero definingPolynomialData + +/-- The candidate defining polynomial has degree `32`. -/ +lemma definingPolynomial_degree : + definingPolynomial.degree = extensionDegree := + BinaryField.Extension.polynomial_degree definingPolynomialData + +/-- Bit-vector encoding of the candidate defining polynomial. -/ +def P_val : BitVec (2 * extensionDegree) := + (1 <<< 32) ^^^ (1 <<< 22) ^^^ (1 <<< 2) ^^^ (1 <<< 1) ^^^ 1 + +/-- The `BitVec` encoding denotes the candidate defining polynomial. -/ +lemma definingPolynomial_eq_P_val : + definingPolynomial = BinaryField.toPoly P_val := by + rw [definingPolynomial_eq_sparse] + unfold P_val extensionDegree + repeat rw [BinaryField.toPoly_xor] + rw [BinaryField.Extension.toPoly_one_shiftLeft 32 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 22 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 2 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 1 (by omega)] + rw [(show (1 : BitVec 64) = 1 <<< 0 by simp)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 0 (by omega)] + simp only [pow_zero, pow_one] + +/-- The exponent list denotes the candidate defining polynomial. -/ +lemma sparsePolynomial_definingPolynomialExponents : + BinaryField.Extension.sparsePolynomial definingPolynomialExponents = definingPolynomial := by + rw [definingPolynomial_eq_sparse] + simp [definingPolynomialExponents, BinaryField.Extension.sparsePolynomial] + ring_nf + +/-- Smooth subgroup refinement schedule for `2^32 - 1`. -/ +def smoothRootSchedule : Array Nat := + #[3, 5, 17, 257, 65537] + +/-- The GF32 smooth schedule refines the multiplicative group down to singleton cosets. -/ +lemma smoothRootSchedule_fold_eq_one : + smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (fieldSize - 1) = 1 := by + unfold smoothRootSchedule fieldSize BinaryField.Extension.fieldSize extensionDegree + decide + +end + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_32/Primitive.lean b/CompPoly/Fields/Binary/GF2_32/Primitive.lean new file mode 100644 index 00000000..ecfc0147 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/Primitive.lean @@ -0,0 +1,145 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_32.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_32.PrimitivePowerCertificate +import Mathlib.GroupTheory.OrderOfElement +import CompPoly.Fields.Binary.GF2_32.Impl + +/-! +# GF(2^32) Primitive-Order Scaffold + +Small primitive-order metadata and Rabin irreducibility certificate for the +`GF(2^32)` candidate. +-/ + +namespace GF2_32 + +set_option maxRecDepth 100000 + +/-- Distinct prime factors of `2^32 - 1`. -/ +def primitivePrimeFactors : List Nat := + [3, 5, 17, 257, 65537] + +/-- Factorization of the multiplicative-group order `2^32 - 1`. -/ +lemma multiplicativeGroupOrder_factorization : + multiplicativeGroupOrder = 3 * 5 * 17 * 257 * 65537 := by + unfold multiplicativeGroupOrder BinaryField.Extension.multiplicativeGroupOrder + BinaryField.Extension.fieldSize extensionDegree + norm_num + +/-- The GF2_32 candidate polynomial passes Rabin's irreducibility test. -/ +theorem definingPolynomial_irreducible : Irreducible definingPolynomial := + BinaryField.Extension.irreducible_of_rabin_32_passed_over_GF2 + definingPolynomial + (by simpa [extensionDegree] using definingPolynomial_natDegree) + X_pow_2_pow_32_add_X_dvd + rabin_gcd_condition_16 + +/-- Register the certified irreducibility fact for quotient-field instances. -/ +instance instIrreducibleDefiningPolynomial : Fact (Irreducible definingPolynomial) := + ⟨definingPolynomial_irreducible⟩ + +/-- Local kernel-safe primality certificate for the largest GF32 group-order factor. -/ +private theorem prime_65537 : Nat.Prime 65537 := by + rw [Nat.prime_def_le_sqrt] + constructor + · norm_num + · intro m hm2 hmsqrt hdvd + have hm_le_sq : m * m ≤ 65537 := (Nat.le_sqrt.mp hmsqrt) + have hm_le : m ≤ 256 := by + by_contra h + have hm257 : 257 ≤ m := by omega + have hsq : 257 * 257 ≤ m * m := Nat.mul_le_mul hm257 hm257 + omega + interval_cases m <;> norm_num at hdvd + +/-- Prime divisors of `fieldSize - 1` are exactly the certified prime factors. -/ +private lemma prime_dvd_fieldSize_sub_one_cases {p : Nat} + (hp : p.Prime) (hdvd : p ∣ fieldSize - 1) : + p = 3 ∨ p = 5 ∨ p = 17 ∨ p = 257 ∨ p = 65537 := by + have hpdvd : p ∣ multiplicativeGroupOrder := by + simpa [multiplicativeGroupOrder, BinaryField.Extension.multiplicativeGroupOrder] using hdvd + rw [multiplicativeGroupOrder_factorization] at hpdvd + rcases hp.dvd_mul.mp hpdvd with hpdvd | h65537 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h257 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h17 + · rcases hp.dvd_mul.mp hpdvd with h3 | h5 + · left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 3)).mp + h3 + · right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 5)).mp + h5 + · right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 17)).mp + h17 + · right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 257)).mp + h257 + · right + right + right + right + exact + (Nat.prime_dvd_prime_iff_eq hp prime_65537).mp + h65537 + +/-- Polynomial-basis generator used by smooth root contexts. -/ +def primitiveRoot : ConcreteField := + ConcreteField.root + +/-- The polynomial-basis generator is nonzero. -/ +theorem primitiveRoot_ne_zero : primitiveRoot ≠ (0 : ConcreteField) := by + unfold primitiveRoot ConcreteField.root BinaryField.Extension.Concrete.root + change BinaryField.Extension.Concrete.ofNat Concrete.params 2 ≠ + BinaryField.Extension.Concrete.zero Concrete.params + intro h + have hnat := congrArg (BinaryField.Extension.Concrete.toNat Concrete.params) h + rw [BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num)] at hnat + have hzero : + BinaryField.Extension.Concrete.toNat Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = 0 := by + unfold BinaryField.Extension.Concrete.zero + exact BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (n := 0) (by unfold Concrete.params extensionDegree; norm_num) + rw [hzero] at hnat + norm_num at hnat + +/-- The polynomial-basis generator has full multiplicative order. -/ +theorem primitiveRoot_order : orderOf primitiveRoot = fieldSize - 1 := by + let fieldInst : Field ConcreteField := ConcreteField.instFieldConcreteField + letI : Field ConcreteField := fieldInst + refine orderOf_eq_of_pow_and_pow_div_prime (n := fieldSize - 1) ?_ ?_ ?_ + · unfold fieldSize BinaryField.Extension.fieldSize extensionDegree + norm_num + · have hcard : Fintype.card ConcreteField = fieldSize := by + simpa [fieldSize] using ConcreteField.card + have hfermat := FiniteField.pow_card_sub_one_eq_one + (K := ConcreteField) primitiveRoot primitiveRoot_ne_zero + simpa [hcard] using hfermat + · intro p hp hdvd + rcases prime_dvd_fieldSize_sub_one_cases hp hdvd with + rfl | rfl | rfl | rfl | rfl + · simpa [primitiveRoot] using root_pow_div_3_ne_one + · simpa [primitiveRoot] using root_pow_div_5_ne_one + · simpa [primitiveRoot] using root_pow_div_17_ne_one + · simpa [primitiveRoot] using root_pow_div_257_ne_one + · simpa [primitiveRoot] using root_pow_div_65537_ne_one + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_32/PrimitivePowerCertificate.lean b/CompPoly/Fields/Binary/GF2_32/PrimitivePowerCertificate.lean new file mode 100644 index 00000000..231f0101 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/PrimitivePowerCertificate.lean @@ -0,0 +1,372 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_32.Impl +import Mathlib.Tactic.NormNum + +/-! +# GF2^32 Primitive-Power Certificates + +Generated structural power-chain certificates for the polynomial-basis +root. These certify the nontrivial prime-divisor powers used to prove +that the root has full multiplicative order. +-/ + +namespace GF2_32 + +set_option maxRecDepth 50000 + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (2, 4), + (5, 32), + (10, 1024), + (21, 2097152), + (42, 4201479), + (85, 10543122), + (170, 1346493811), + (341, 3323544796), + (682, 4027602832), + (1365, 1556035943), + (2730, 1739416994), + (5461, 3493923718), + (10922, 4066962303), + (21845, 4104604283), + (43690, 3995013102), + (87381, 3546564175), + (174762, 3055722894), + (349525, 2490840567), + (699050, 2186346002), + (1398101, 674290231), + (2796202, 499347406), + (5592405, 130325264), + (11184810, 275753947), + (22369621, 2794060042), + (44739242, 3445344052), + (89478485, 3252423199), + (178956970, 2972626249), + (357913941, 478257971), + (715827882, 1135962393), + (1431655765, 1754248962)] + +/-- Residue of `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Residue : Nat := + 1754248962 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 3) rootPowDiv3Chain rootPowDiv3Residue = true := by + rfl + +private theorem root_pow_div_3_certified : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue ∧ + rootPowDiv3Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 3) + (cert := rootPowDiv3Chain) (expected := rootPowDiv3Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_3_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_eq : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue := + root_pow_div_3_certified.1 + +/-- The `3`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_3_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 3) ≠ (1 : ConcreteField) := by + rw [root_pow_div_3_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv3Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv3Residue] using root_pow_div_3_certified.2) + (by unfold rootPowDiv3Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (6, 64), + (12, 4096), + (25, 33554432), + (51, 2151157248), + (102, 2422474439), + (204, 3324370958), + (409, 3233822785), + (819, 3759896285), + (1638, 3091156298), + (3276, 2330437444), + (6553, 2301734431), + (13107, 2844192533), + (26214, 2313465105), + (52428, 2510799046), + (104857, 80649081), + (209715, 2733207820), + (419430, 2355869500), + (838860, 2509576331), + (1677721, 617516525), + (3355443, 3100635308), + (6710886, 2331465787), + (13421772, 3522020697), + (26843545, 1152699485), + (53687091, 1081844386), + (107374182, 605563332), + (214748364, 1484147479), + (429496729, 3484531228), + (858993459, 1137006577)] + +/-- Residue of `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Residue : Nat := + 1137006577 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 5) rootPowDiv5Chain rootPowDiv5Residue = true := by + rfl + +private theorem root_pow_div_5_certified : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue ∧ + rootPowDiv5Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 5) + (cert := rootPowDiv5Chain) (expected := rootPowDiv5Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_5_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_eq : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue := + root_pow_div_5_certified.1 + +/-- The `5`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_5_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 5) ≠ (1 : ConcreteField) := by + rw [root_pow_div_5_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv5Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv5Residue] using root_pow_div_5_certified.2) + (by unfold rootPowDiv5Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (7, 128), + (15, 32768), + (30, 1073741824), + (60, 807143168), + (120, 1528022784), + (240, 1922283191), + (481, 4272326556), + (963, 4259600839), + (1927, 4286224077), + (3855, 2112558589), + (7710, 989680522), + (15420, 266230836), + (30840, 297457931), + (61680, 386276190), + (123361, 2933888798), + (246723, 1004503703), + (493447, 2670756220), + (986895, 670527999), + (1973790, 153937234), + (3947580, 1352039791), + (7895160, 1733104697), + (15790320, 2019584237), + (31580641, 1437933004), + (63161283, 3304367054), + (126322567, 3933337751), + (252645135, 1370394541)] + +/-- Residue of `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Residue : Nat := + 1370394541 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 17) rootPowDiv17Chain rootPowDiv17Residue = true := by + rfl + +private theorem root_pow_div_17_certified : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue ∧ + rootPowDiv17Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 17) + (cert := rootPowDiv17Chain) (expected := rootPowDiv17Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_17_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_eq : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue := + root_pow_div_17_certified.1 + +/-- The `17`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_17_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 17) ≠ (1 : ConcreteField) := by + rw [root_pow_div_17_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv17Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv17Residue] using root_pow_div_17_certified.2) + (by unfold rootPowDiv17Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 257)`. -/ +def rootPowDiv257Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (7, 128), + (15, 32768), + (31, 2147483648), + (63, 2157983751), + (127, 2191753411), + (255, 2325425877), + (510, 3518626982), + (1020, 3795534868), + (2040, 4251387404), + (4080, 3951680331), + (8160, 3920936430), + (16320, 3921470543), + (32640, 3908936078), + (65280, 3920330836), + (130561, 1931169607), + (261123, 1546235260), + (522247, 3480831990), + (1044495, 3278150689), + (2088991, 3364809555), + (4177983, 1804695437), + (8355967, 2066345588), + (16711935, 1462464888)] + +/-- Residue of `root ^ ((fieldSize - 1) / 257)`. -/ +def rootPowDiv257Residue : Nat := + 1462464888 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 257)`. -/ +theorem root_pow_div_257_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 257) rootPowDiv257Chain rootPowDiv257Residue = true := by + rfl + +private theorem root_pow_div_257_certified : + ConcreteField.root ^ ((fieldSize - 1) / 257) = + ConcreteField.ofNat rootPowDiv257Residue ∧ + rootPowDiv257Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 257) + (cert := rootPowDiv257Chain) (expected := rootPowDiv257Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_257_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 257)`. -/ +theorem root_pow_div_257_eq : + ConcreteField.root ^ ((fieldSize - 1) / 257) = + ConcreteField.ofNat rootPowDiv257Residue := + root_pow_div_257_certified.1 + +/-- The `257`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_257_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 257) ≠ (1 : ConcreteField) := by + rw [root_pow_div_257_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv257Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv257Residue] using root_pow_div_257_certified.2) + (by unfold rootPowDiv257Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 65537)`. -/ +def rootPowDiv65537Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (7, 128), + (15, 32768), + (31, 2147483648), + (63, 2157983751), + (127, 2191753411), + (255, 2325425877), + (511, 2738092363), + (1023, 270147765), + (2047, 2885879674), + (4095, 2615462159), + (8191, 2232683971), + (16383, 678210915), + (32767, 3148615908), + (65535, 496518513)] + +/-- Residue of `root ^ ((fieldSize - 1) / 65537)`. -/ +def rootPowDiv65537Residue : Nat := + 496518513 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 65537)`. -/ +theorem root_pow_div_65537_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 65537) rootPowDiv65537Chain rootPowDiv65537Residue = true := by + rfl + +private theorem root_pow_div_65537_certified : + ConcreteField.root ^ ((fieldSize - 1) / 65537) = + ConcreteField.ofNat rootPowDiv65537Residue ∧ + rootPowDiv65537Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 65537) + (cert := rootPowDiv65537Chain) (expected := rootPowDiv65537Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_65537_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 65537)`. -/ +theorem root_pow_div_65537_eq : + ConcreteField.root ^ ((fieldSize - 1) / 65537) = + ConcreteField.ofNat rootPowDiv65537Residue := + root_pow_div_65537_certified.1 + +/-- The `65537`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_65537_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 65537) ≠ (1 : ConcreteField) := by + rw [root_pow_div_65537_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv65537Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv65537Residue] using root_pow_div_65537_certified.2) + (by unfold rootPowDiv65537Residue; norm_num) + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_32/RootContexts.lean b/CompPoly/Fields/Binary/GF2_32/RootContexts.lean new file mode 100644 index 00000000..da68486b --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/RootContexts.lean @@ -0,0 +1,248 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_32.Primitive +import CompPoly.Fields.Binary.Extension.Enumeration +import CompPoly.Univariate.Roots.Context +import CompPoly.Univariate.Roots.Shoup.Basic +import CompPoly.Univariate.Roots.SmoothSubgroup +import Mathlib.FieldTheory.Finite.Trace + +/-! +# GF(2^32) Root-Search Contexts + +Certified finite-field context for the executable `GF(2^32)` carrier. +-/ + +namespace GF2_32 + +open CompPoly +open CompPoly.CPolynomial.Roots.FiniteField + +private theorem exists_basis_trace_ne {K L ι : Type*} [Field K] [Field L] [Algebra K L] + [FiniteDimensional K L] [Algebra.IsSeparable K L] + (b : Module.Basis ι K L) {x : L} (hx : x ≠ 0) : + ∃ i, Algebra.trace K L (b i * x) ≠ 0 := by + have hnd := (traceForm_nondegenerate K L).1 x + by_contra hnone + push Not at hnone + have hzero : (Algebra.traceForm K L) x = 0 := by + apply b.ext + intro i + rw [Algebra.traceForm_apply] + simpa [mul_comm] using hnone i + exact hx (hnd (by + intro y + rw [hzero] + rfl)) + +/-- Finite-field context for the executable `GF(2^32)` carrier. -/ +def finiteFieldContext : + CompPoly.CPolynomial.Roots.FiniteField.FiniteFieldContext ConcreteField where + q := fieldSize + finite := by infer_instance + card_eq := by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card + frobenius_fixed := by + intro a + have hcard : Fintype.card ConcreteField = fieldSize := by + exact ConcreteField.card + simpa [hcard] using FiniteField.pow_card a + +/-- Lazy complete enumeration for `GF(2^32)`. -/ +def fieldEnumeration : + CompPoly.CPolynomial.Roots.FiniteField.FieldEnumeration ConcreteField := + BinaryField.Extension.Concrete.fieldEnumeration Concrete.params + +namespace ConcreteField + +local instance fieldInst : Field ConcreteField := + instFieldConcreteField + +local instance commRingInst : CommRing ConcreteField := + fieldInst.toCommRing + +noncomputable local instance algebraInst : Algebra (ZMod 2) ConcreteField := + instAlgebraConcreteField + +/-- Algebraic trace value embedded back into executable `GF(2^32)`. -/ +noncomputable def algebraicTraceValue (z : ConcreteField) : ConcreteField := + algebraMap (ZMod 2) ConcreteField (Algebra.trace (ZMod 2) ConcreteField z) + +/-- The executable GF32 carrier has dimension `32` over `GF(2)`. -/ +theorem finrank_eq_extensionDegree : + Module.finrank (ZMod 2) ConcreteField = extensionDegree := by + have h := FiniteField.pow_finrank_eq_card (p := 2) (k := ConcreteField) + rw [card] at h + exact Nat.pow_right_injective (by norm_num : 1 < 2) h + +/-- The algebraic trace equals the Shoup Frobenius power sum. -/ +theorem algebraicTraceValue_eq_powerSum (z : ConcreteField) : + algebraicTraceValue z = tracePowerSum 2 extensionDegree z := by + unfold algebraicTraceValue + have htrace := FiniteField.algebraMap_trace_eq_sum_pow (ZMod 2) ConcreteField z + rw [finrank_eq_extensionDegree] at htrace + rw [htrace] + rw [tracePowerSum_eq_sum_range] + simp + +/-- The GF32 trace lands in the embedded `GF(2)` constants. -/ +theorem algebraicTraceValue_mem_base (z : ConcreteField) : + algebraicTraceValue z ∈ baseConstants.toList := by + unfold algebraicTraceValue baseConstants BinaryField.Extension.Concrete.baseConstants + let t : ZMod 2 := Algebra.trace (ZMod 2) ConcreteField z + change algebraMap (ZMod 2) ConcreteField t ∈ + [BinaryField.Extension.Concrete.zero Concrete.params, + BinaryField.Extension.Concrete.one Concrete.params] + have ht : ∀ u : ZMod 2, u = 0 ∨ u = 1 := by + intro u + fin_cases u + · left + rfl + · right + rfl + rcases ht t with ht0 | ht1 + · rw [ht0, map_zero] + left + · rw [ht1, map_one] + right + left + +/-- The transported quotient power basis for executable `GF(2^32)`. -/ +noncomputable def polynomialPowerBasis : PowerBasis (ZMod 2) ConcreteField := + (AdjoinRoot.powerBasis (BinaryField.Extension.polynomial_ne_zero definingPolynomialData)).map + toSpecAlgEquiv.symm + +@[simp] +theorem polynomialPowerBasis_dim_eq : + polynomialPowerBasis.dim = extensionDegree := by + simp [polynomialPowerBasis, BinaryField.Extension.polynomial_natDegree, + definingPolynomialData, extensionDegree] + +/-- The executable polynomial basis as a Lean basis. -/ +noncomputable def polynomialBasisBasis : + Module.Basis (Fin extensionDegree) (ZMod 2) ConcreteField := + polynomialPowerBasis.basis.reindex (finCongr polynomialPowerBasis_dim_eq) + +theorem polynomialBasisBasis_apply (i : Fin extensionDegree) : + polynomialBasisBasis i = root ^ i.val := by + unfold polynomialBasisBasis polynomialPowerBasis + rw [Module.Basis.reindex_apply] + change toSpecAlgEquiv.symm + (AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i)) = root ^ i.val + rw [show + AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i) = + (BinaryField.Extension.root definingPolynomialData) ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val by + simp [AdjoinRoot.powerBasisAux, BinaryField.Extension.root]] + rw [map_pow] + change toSpecAlgEquiv.symm GF2_32.root ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val = root ^ i.val + have hrootSymm : toSpecAlgEquiv.symm GF2_32.root = root := by + rw [AlgEquiv.symm_apply_eq] + exact toSpec_root.symm + rw [hrootSymm] + congr 1 + +/-- Each Lean polynomial-basis vector is present in the executable basis array. -/ +theorem polynomialBasisBasis_mem (i : Fin extensionDegree) : + polynomialBasisBasis i ∈ polynomialBasis.toList := by + rw [polynomialBasisBasis_apply] + rw [← Array.mem_def] + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis, Array.mem_ofFn] + exact ⟨i, rfl⟩ + +/-- The executable polynomial basis separates distinct elements by GF32 trace coordinates. -/ +theorem algebraicTraceValue_separates {a b : ConcreteField} (hne : a ≠ b) : + ∃ beta, beta ∈ polynomialBasis.toList ∧ algebraicTraceValue (beta * (a - b)) ≠ 0 := by + have hx : a - b ≠ 0 := sub_ne_zero.mpr hne + rcases exists_basis_trace_ne polynomialBasisBasis hx with ⟨i, htrace⟩ + refine ⟨polynomialBasisBasis i, polynomialBasisBasis_mem i, ?_⟩ + unfold algebraicTraceValue + intro hzero + apply htrace + have hz' : + algebraMap (ZMod 2) ConcreteField + (Algebra.trace (ZMod 2) ConcreteField (polynomialBasisBasis i * (a - b))) = + algebraMap (ZMod 2) ConcreteField 0 := by + rw [map_zero] + exact hzero + exact (FaithfulSMul.algebraMap_injective (ZMod 2) ConcreteField) hz' + +end ConcreteField + +/-- Shoup trace splitter context for `GF(2^32)`. -/ +def shoupTraceContext : + CPolynomial.Roots.FiniteField.SmallPrimeTraceContext ConcreteField where + toFiniteFieldContext := finiteFieldContext + p := 2 + k := extensionDegree + p_prime := Nat.prime_two + q_eq := by + simp [finiteFieldContext, fieldSize, BinaryField.Extension.fieldSize] + baseConstants := ConcreteField.baseConstants + baseConstants_size := ConcreteField.baseConstants_size + basis := ConcreteField.polynomialBasis + basis_size := ConcreteField.polynomialBasis_size + traceValue := tracePowerSum 2 extensionDegree + traceValue_eq_powerSum := fun _ ↦ rfl + traceValue_mem_base := by + intro z + rw [← ConcreteField.algebraicTraceValue_eq_powerSum] + exact ConcreteField.algebraicTraceValue_mem_base z + trace_separates := by + intro a b hne + rcases ConcreteField.algebraicTraceValue_separates hne with ⟨beta, hbeta, htrace⟩ + refine ⟨beta, hbeta, ?_⟩ + rwa [← ConcreteField.algebraicTraceValue_eq_powerSum] + +/-- Smooth cyclic splitter context for `GF(2^32)` with the supplied leaf evaluator. -/ +def smoothCyclicRootContextWith + (leafEvaluator : CPolynomial.BatchEvalContext ConcreteField) : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + CPolynomial.Roots.FiniteField.smoothCyclicRootContextOf + fieldSize + primitiveRoot + smoothRootSchedule + leafEvaluator + (CPolynomial.Roots.FiniteField.smoothSplitterInput + fieldSize primitiveRoot smoothRootSchedule) + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + smoothRootSchedule_fold_eq_one + (by + intro M D p factor h + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_sound + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule h) + (by + intro M D p a _hvalid hp hroot + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_complete + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + (by decide) + hp hroot) + +/-- Smooth cyclic splitter context for `GF(2^32)` using Horner leaf evaluation. -/ +def smoothHornerRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith (CPolynomial.BatchEvalContext.horner ConcreteField) + +/-- Smooth cyclic splitter context for `GF(2^32)` using subproduct-tree leaf evaluation. -/ +def smoothSubproductRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith + (CPolynomial.BatchEvalContext.subproduct ConcreteField + CPolynomial.MulContext.naive CPolynomial.ModContext.naive) + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_32/XPowTwoPowGcdCertificate.lean b/CompPoly/Fields/Binary/GF2_32/XPowTwoPowGcdCertificate.lean new file mode 100644 index 00000000..01707c88 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/XPowTwoPowGcdCertificate.lean @@ -0,0 +1,399 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_32.XPowTwoPowModCertificate + +/-! +# GF(2^32) Rabin GCD Certificate + +Kernel-safe Euclidean-division certificate for the Rabin gcd check of +`X ^ 32 + X ^ 22 + X ^ 2 + X + 1`. +-/ + +namespace GF2_32 + +open Polynomial + +set_option maxRecDepth 1500 + +private abbrev B64 : Type := BitVec (2 * extensionDegree) + +def gcdPVal : B64 := BitVec.ofNat (2 * extensionDegree) 4299161607 + +/-- Numeric 64-bit encoding of the GF32 defining polynomial. -/ +lemma definingPolynomial_eq_gcdPVal : + definingPolynomial = BinaryField.toPoly gcdPVal := by + rw [definingPolynomial_eq_P_val] + have h : P_val = gcdPVal := by + decide + rw [h] + +/-- Any GF32-width polynomial is already reduced modulo the defining polynomial. -/ +lemma toPoly_mod_definingPolynomial_eq_self (v : B32) : + BinaryField.toPoly v % definingPolynomial = BinaryField.toPoly v := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + exact BinaryField.toPoly_degree_lt_w + (w := extensionDegree) (h_w_pos := by unfold extensionDegree; omega) v + +/-- Soundness wrapper specialized to 64-bit Euclidean-division certificates. -/ +private theorem verify_div_step {a q b r : B64} + (h : BinaryField.Extension.checkDivStep (2 * extensionDegree) a q b r = true) : + BinaryField.toPoly a = BinaryField.toPoly q * BinaryField.toPoly b + + BinaryField.toPoly r := by + exact BinaryField.Extension.checkDivStep_correct a q b r h + +private theorem toPoly_ne_zero {v : B64} (h : v ≠ 0) : + BinaryField.toPoly v ≠ 0 := + (BinaryField.toPoly_ne_zero_iff_ne_zero v).mpr h + +/-- Initial Rabin gcd remainder for exponent `16`. -/ +def gcd16_b1Val : B64 := BitVec.ofNat (2 * extensionDegree) 993037024 + +lemma gcd16_b1Val_eq_zeroExtend : + gcd16_b1Val = BitVec.zeroExtend (2 * extensionDegree) (r16Val ^^^ r0Val) := by + decide + +def gcd16_a1Val : B64 := gcdPVal +def gcd16_q1Val : B64 := BitVec.ofNat (2 * extensionDegree) 13 +def gcd16_r1Val : B64 := BitVec.ofNat (2 * extensionDegree) 238483047 + +def gcd16_a2Val : B64 := gcd16_b1Val +def gcd16_b2Val : B64 := gcd16_r1Val +def gcd16_q2Val : B64 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd16_r2Val : B64 := BitVec.ofNat (2 * extensionDegree) 65753980 + +def gcd16_a3Val : B64 := gcd16_b2Val +def gcd16_b3Val : B64 := gcd16_r2Val +def gcd16_q3Val : B64 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd16_r3Val : B64 := BitVec.ofNat (2 * extensionDegree) 26983319 + +def gcd16_a4Val : B64 := gcd16_b3Val +def gcd16_b4Val : B64 := gcd16_r3Val +def gcd16_q4Val : B64 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r4Val : B64 := BitVec.ofNat (2 * extensionDegree) 14427218 + +def gcd16_a5Val : B64 := gcd16_b4Val +def gcd16_b5Val : B64 := gcd16_r4Val +def gcd16_q5Val : B64 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r5Val : B64 := BitVec.ofNat (2 * extensionDegree) 2356019 + +def gcd16_a6Val : B64 := gcd16_b5Val +def gcd16_b6Val : B64 := gcd16_r5Val +def gcd16_q6Val : B64 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd16_r6Val : B64 := BitVec.ofNat (2 * extensionDegree) 1314552 + +def gcd16_a7Val : B64 := gcd16_b6Val +def gcd16_b7Val : B64 := gcd16_r6Val +def gcd16_q7Val : B64 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r7Val : B64 := BitVec.ofNat (2 * extensionDegree) 782019 + +def gcd16_a8Val : B64 := gcd16_b7Val +def gcd16_b8Val : B64 := gcd16_r7Val +def gcd16_q8Val : B64 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r8Val : B64 := BitVec.ofNat (2 * extensionDegree) 250750 + +def gcd16_a9Val : B64 := gcd16_b8Val +def gcd16_b9Val : B64 := gcd16_r8Val +def gcd16_q9Val : B64 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd16_r9Val : B64 := BitVec.ofNat (2 * extensionDegree) 54969 + +def gcd16_a10Val : B64 := gcd16_b9Val +def gcd16_b10Val : B64 := gcd16_r9Val +def gcd16_q10Val : B64 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd16_r10Val : B64 := BitVec.ofNat (2 * extensionDegree) 24355 + +def gcd16_a11Val : B64 := gcd16_b10Val +def gcd16_b11Val : B64 := gcd16_r10Val +def gcd16_q11Val : B64 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r11Val : B64 := BitVec.ofNat (2 * extensionDegree) 14300 + +def gcd16_a12Val : B64 := gcd16_b11Val +def gcd16_b12Val : B64 := gcd16_r11Val +def gcd16_q12Val : B64 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r12Val : B64 := BitVec.ofNat (2 * extensionDegree) 1863 + +def gcd16_a13Val : B64 := gcd16_b12Val +def gcd16_b13Val : B64 := gcd16_r12Val +def gcd16_q13Val : B64 := BitVec.ofNat (2 * extensionDegree) 10 +def gcd16_r13Val : B64 := BitVec.ofNat (2 * extensionDegree) 874 + +def gcd16_a14Val : B64 := gcd16_b13Val +def gcd16_b14Val : B64 := gcd16_r13Val +def gcd16_q14Val : B64 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r14Val : B64 := BitVec.ofNat (2 * extensionDegree) 403 + +def gcd16_a15Val : B64 := gcd16_b14Val +def gcd16_b15Val : B64 := gcd16_r14Val +def gcd16_q15Val : B64 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r15Val : B64 := BitVec.ofNat (2 * extensionDegree) 76 + +def gcd16_a16Val : B64 := gcd16_b15Val +def gcd16_b16Val : B64 := gcd16_r15Val +def gcd16_q16Val : B64 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd16_r16Val : B64 := BitVec.ofNat (2 * extensionDegree) 59 + +def gcd16_a17Val : B64 := gcd16_b16Val +def gcd16_b17Val : B64 := gcd16_r16Val +def gcd16_q17Val : B64 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r17Val : B64 := BitVec.ofNat (2 * extensionDegree) 1 + +def gcd16_a18Val : B64 := gcd16_b17Val +def gcd16_b18Val : B64 := gcd16_r17Val +def gcd16_q18Val : B64 := BitVec.ofNat (2 * extensionDegree) 59 +def gcd16_r18Val : B64 := BitVec.ofNat (2 * extensionDegree) 0 + +/-- Reduce the exponent `16` Rabin gcd to the generated Euclidean trace. -/ +lemma gcd16_start_reduction : + EuclideanDomain.gcd (X ^ (2 ^ 16) + X) definingPolynomial = + EuclideanDomain.gcd definingPolynomial (BinaryField.toPoly gcd16_b1Val) := by + rw [ZMod2Poly.euclidean_gcd_comm] + rw [EuclideanDomain.gcd_val] + conv_lhs => + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_16_mod_eq] + rw [r16] + rw [toPoly_mod_definingPolynomial_eq_self r16Val, X_mod_definingPolynomial] + rw [← r0_eq_X] + rw [r0] + rw [← BinaryField.toPoly_xor] + rw [toPoly_mod_definingPolynomial_eq_self (r16Val ^^^ r0Val)] + rw [← BinaryField.Extension.toPoly_zeroExtend + (show extensionDegree ≤ 2 * extensionDegree by unfold extensionDegree; norm_num) + (r16Val ^^^ r0Val)] + rw [← gcd16_b1Val_eq_zeroExtend] + rw [ZMod2Poly.euclidean_gcd_comm] + +lemma gcd16_step_1 : + BinaryField.toPoly gcd16_a1Val = + BinaryField.toPoly gcd16_q1Val * BinaryField.toPoly gcd16_b1Val + + BinaryField.toPoly gcd16_r1Val := by + exact verify_div_step (a := gcd16_a1Val) (q := gcd16_q1Val) + (b := gcd16_b1Val) (r := gcd16_r1Val) (by rfl) + +lemma gcd16_step_2 : + BinaryField.toPoly gcd16_a2Val = + BinaryField.toPoly gcd16_q2Val * BinaryField.toPoly gcd16_b2Val + + BinaryField.toPoly gcd16_r2Val := by + exact verify_div_step (a := gcd16_a2Val) (q := gcd16_q2Val) + (b := gcd16_b2Val) (r := gcd16_r2Val) (by rfl) + +lemma gcd16_step_3 : + BinaryField.toPoly gcd16_a3Val = + BinaryField.toPoly gcd16_q3Val * BinaryField.toPoly gcd16_b3Val + + BinaryField.toPoly gcd16_r3Val := by + exact verify_div_step (a := gcd16_a3Val) (q := gcd16_q3Val) + (b := gcd16_b3Val) (r := gcd16_r3Val) (by rfl) + +lemma gcd16_step_4 : + BinaryField.toPoly gcd16_a4Val = + BinaryField.toPoly gcd16_q4Val * BinaryField.toPoly gcd16_b4Val + + BinaryField.toPoly gcd16_r4Val := by + exact verify_div_step (a := gcd16_a4Val) (q := gcd16_q4Val) + (b := gcd16_b4Val) (r := gcd16_r4Val) (by rfl) + +lemma gcd16_step_5 : + BinaryField.toPoly gcd16_a5Val = + BinaryField.toPoly gcd16_q5Val * BinaryField.toPoly gcd16_b5Val + + BinaryField.toPoly gcd16_r5Val := by + exact verify_div_step (a := gcd16_a5Val) (q := gcd16_q5Val) + (b := gcd16_b5Val) (r := gcd16_r5Val) (by rfl) + +lemma gcd16_step_6 : + BinaryField.toPoly gcd16_a6Val = + BinaryField.toPoly gcd16_q6Val * BinaryField.toPoly gcd16_b6Val + + BinaryField.toPoly gcd16_r6Val := by + exact verify_div_step (a := gcd16_a6Val) (q := gcd16_q6Val) + (b := gcd16_b6Val) (r := gcd16_r6Val) (by rfl) + +lemma gcd16_step_7 : + BinaryField.toPoly gcd16_a7Val = + BinaryField.toPoly gcd16_q7Val * BinaryField.toPoly gcd16_b7Val + + BinaryField.toPoly gcd16_r7Val := by + exact verify_div_step (a := gcd16_a7Val) (q := gcd16_q7Val) + (b := gcd16_b7Val) (r := gcd16_r7Val) (by rfl) + +lemma gcd16_step_8 : + BinaryField.toPoly gcd16_a8Val = + BinaryField.toPoly gcd16_q8Val * BinaryField.toPoly gcd16_b8Val + + BinaryField.toPoly gcd16_r8Val := by + exact verify_div_step (a := gcd16_a8Val) (q := gcd16_q8Val) + (b := gcd16_b8Val) (r := gcd16_r8Val) (by rfl) + +lemma gcd16_step_9 : + BinaryField.toPoly gcd16_a9Val = + BinaryField.toPoly gcd16_q9Val * BinaryField.toPoly gcd16_b9Val + + BinaryField.toPoly gcd16_r9Val := by + exact verify_div_step (a := gcd16_a9Val) (q := gcd16_q9Val) + (b := gcd16_b9Val) (r := gcd16_r9Val) (by rfl) + +lemma gcd16_step_10 : + BinaryField.toPoly gcd16_a10Val = + BinaryField.toPoly gcd16_q10Val * BinaryField.toPoly gcd16_b10Val + + BinaryField.toPoly gcd16_r10Val := by + exact verify_div_step (a := gcd16_a10Val) (q := gcd16_q10Val) + (b := gcd16_b10Val) (r := gcd16_r10Val) (by rfl) + +lemma gcd16_step_11 : + BinaryField.toPoly gcd16_a11Val = + BinaryField.toPoly gcd16_q11Val * BinaryField.toPoly gcd16_b11Val + + BinaryField.toPoly gcd16_r11Val := by + exact verify_div_step (a := gcd16_a11Val) (q := gcd16_q11Val) + (b := gcd16_b11Val) (r := gcd16_r11Val) (by rfl) + +lemma gcd16_step_12 : + BinaryField.toPoly gcd16_a12Val = + BinaryField.toPoly gcd16_q12Val * BinaryField.toPoly gcd16_b12Val + + BinaryField.toPoly gcd16_r12Val := by + exact verify_div_step (a := gcd16_a12Val) (q := gcd16_q12Val) + (b := gcd16_b12Val) (r := gcd16_r12Val) (by rfl) + +lemma gcd16_step_13 : + BinaryField.toPoly gcd16_a13Val = + BinaryField.toPoly gcd16_q13Val * BinaryField.toPoly gcd16_b13Val + + BinaryField.toPoly gcd16_r13Val := by + exact verify_div_step (a := gcd16_a13Val) (q := gcd16_q13Val) + (b := gcd16_b13Val) (r := gcd16_r13Val) (by rfl) + +lemma gcd16_step_14 : + BinaryField.toPoly gcd16_a14Val = + BinaryField.toPoly gcd16_q14Val * BinaryField.toPoly gcd16_b14Val + + BinaryField.toPoly gcd16_r14Val := by + exact verify_div_step (a := gcd16_a14Val) (q := gcd16_q14Val) + (b := gcd16_b14Val) (r := gcd16_r14Val) (by rfl) + +lemma gcd16_step_15 : + BinaryField.toPoly gcd16_a15Val = + BinaryField.toPoly gcd16_q15Val * BinaryField.toPoly gcd16_b15Val + + BinaryField.toPoly gcd16_r15Val := by + exact verify_div_step (a := gcd16_a15Val) (q := gcd16_q15Val) + (b := gcd16_b15Val) (r := gcd16_r15Val) (by rfl) + +lemma gcd16_step_16 : + BinaryField.toPoly gcd16_a16Val = + BinaryField.toPoly gcd16_q16Val * BinaryField.toPoly gcd16_b16Val + + BinaryField.toPoly gcd16_r16Val := by + exact verify_div_step (a := gcd16_a16Val) (q := gcd16_q16Val) + (b := gcd16_b16Val) (r := gcd16_r16Val) (by rfl) + +lemma gcd16_step_17 : + BinaryField.toPoly gcd16_a17Val = + BinaryField.toPoly gcd16_q17Val * BinaryField.toPoly gcd16_b17Val + + BinaryField.toPoly gcd16_r17Val := by + exact verify_div_step (a := gcd16_a17Val) (q := gcd16_q17Val) + (b := gcd16_b17Val) (r := gcd16_r17Val) (by rfl) + +lemma gcd16_step_18 : + BinaryField.toPoly gcd16_a18Val = + BinaryField.toPoly gcd16_q18Val * BinaryField.toPoly gcd16_b18Val + + BinaryField.toPoly gcd16_r18Val := by + exact verify_div_step (a := gcd16_a18Val) (q := gcd16_q18Val) + (b := gcd16_b18Val) (r := gcd16_r18Val) (by rfl) + +/-- Rabin gcd condition for exponent `16`. -/ +lemma rabin_gcd_condition_16 : + EuclideanDomain.gcd (X ^ (2 ^ 16) + X) definingPolynomial = 1 := by + rw [gcd16_start_reduction] + rw [definingPolynomial_eq_gcdPVal] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a1Val) + (BinaryField.toPoly gcd16_b1Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b1Val) (by decide)) + gcd16_step_1] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a2Val) + (BinaryField.toPoly gcd16_b2Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b2Val) (by decide)) + gcd16_step_2] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a3Val) + (BinaryField.toPoly gcd16_b3Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b3Val) (by decide)) + gcd16_step_3] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a4Val) + (BinaryField.toPoly gcd16_b4Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b4Val) (by decide)) + gcd16_step_4] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a5Val) + (BinaryField.toPoly gcd16_b5Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b5Val) (by decide)) + gcd16_step_5] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a6Val) + (BinaryField.toPoly gcd16_b6Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b6Val) (by decide)) + gcd16_step_6] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a7Val) + (BinaryField.toPoly gcd16_b7Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b7Val) (by decide)) + gcd16_step_7] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a8Val) + (BinaryField.toPoly gcd16_b8Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b8Val) (by decide)) + gcd16_step_8] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a9Val) + (BinaryField.toPoly gcd16_b9Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b9Val) (by decide)) + gcd16_step_9] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a10Val) + (BinaryField.toPoly gcd16_b10Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b10Val) (by decide)) + gcd16_step_10] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a11Val) + (BinaryField.toPoly gcd16_b11Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b11Val) (by decide)) + gcd16_step_11] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a12Val) + (BinaryField.toPoly gcd16_b12Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b12Val) (by decide)) + gcd16_step_12] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a13Val) + (BinaryField.toPoly gcd16_b13Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b13Val) (by decide)) + gcd16_step_13] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a14Val) + (BinaryField.toPoly gcd16_b14Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b14Val) (by decide)) + gcd16_step_14] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a15Val) + (BinaryField.toPoly gcd16_b15Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b15Val) (by decide)) + gcd16_step_15] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a16Val) + (BinaryField.toPoly gcd16_b16Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b16Val) (by decide)) + gcd16_step_16] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a17Val) + (BinaryField.toPoly gcd16_b17Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b17Val) (by decide)) + gcd16_step_17] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a18Val) + (BinaryField.toPoly gcd16_b18Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b18Val) (by decide)) + gcd16_step_18] + change EuclideanDomain.gcd + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 1 : B64)) + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 0 : B64)) = 1 + rw [BinaryField.toPoly_one_eq_one + (w := 2 * extensionDegree) (h_w_pos := by unfold extensionDegree; omega)] + rw [BinaryField.toPoly_zero_eq_zero] + exact BinaryField.gcd_one_zero + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_32/XPowTwoPowModCertificate.lean b/CompPoly/Fields/Binary/GF2_32/XPowTwoPowModCertificate.lean new file mode 100644 index 00000000..ab5878a5 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_32/XPowTwoPowModCertificate.lean @@ -0,0 +1,761 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_32.Prelude +import Mathlib.Tactic.NormNum + +/-! +# GF(2^32) Modular Frobenius Certificate + +Kernel-safe certificate data for repeated squaring of `X` modulo +`X ^ 32 + X ^ 22 + X ^ 2 + X + 1`. +-/ + +namespace GF2_32 + +open Polynomial + +set_option maxRecDepth 1500 + +/-- Certificate exponents fit in the doubled-width checker. -/ +lemma certificateExponents_bound : + ∀ exponent ∈ definingPolynomialExponents, + extensionDegree + exponent ≤ 2 * extensionDegree := by + unfold definingPolynomialExponents extensionDegree + decide + +/-- Soundness wrapper specialized to the GF32 defining polynomial. -/ +private theorem verify_square_step {rPrev q rNext : B32} + (h : + BinaryField.Extension.checkSquareStep extensionDegree definingPolynomialExponents + rPrev q rNext = true) : + (BinaryField.toPoly rPrev) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q) * + definingPolynomial + BinaryField.toPoly rNext := by + rw [← sparsePolynomial_definingPolynomialExponents] + exact BinaryField.Extension.checkSquareStep_correct certificateExponents_bound + rPrev q rNext h + +def r0Val : B32 := BitVec.ofNat extensionDegree 2 +noncomputable def r0 : Polynomial (ZMod 2) := BinaryField.toPoly r0Val + +def q1Val : B32 := BitVec.ofNat extensionDegree 0 +def r1Val : B32 := BitVec.ofNat extensionDegree 4 +noncomputable def r1 : Polynomial (ZMod 2) := BinaryField.toPoly r1Val + +def q2Val : B32 := BitVec.ofNat extensionDegree 0 +def r2Val : B32 := BitVec.ofNat extensionDegree 16 +noncomputable def r2 : Polynomial (ZMod 2) := BinaryField.toPoly r2Val + +def q3Val : B32 := BitVec.ofNat extensionDegree 0 +def r3Val : B32 := BitVec.ofNat extensionDegree 256 +noncomputable def r3 : Polynomial (ZMod 2) := BinaryField.toPoly r3Val + +def q4Val : B32 := BitVec.ofNat extensionDegree 0 +def r4Val : B32 := BitVec.ofNat extensionDegree 65536 +noncomputable def r4 : Polynomial (ZMod 2) := BinaryField.toPoly r4Val + +def q5Val : B32 := BitVec.ofNat extensionDegree 1 +def r5Val : B32 := BitVec.ofNat extensionDegree 4194311 +noncomputable def r5 : Polynomial (ZMod 2) := BinaryField.toPoly r5Val + +def q6Val : B32 := BitVec.ofNat extensionDegree 4100 +def r6Val : B32 := BitVec.ofNat extensionDegree 16805897 +noncomputable def r6 : Polynomial (ZMod 2) := BinaryField.toPoly r6Val + +def q7Val : B32 := BitVec.ofNat extensionDegree 65600 +def r7Val : B32 := BitVec.ofNat extensionDegree 84345217 +noncomputable def r7 : Polynomial (ZMod 2) := BinaryField.toPoly r7Val + +def q8Val : B32 := BitVec.ofNat extensionDegree 1115220 +def r8Val : B32 := BitVec.ofNat extensionDegree 360078765 +noncomputable def r8 : Polynomial (ZMod 2) := BinaryField.toPoly r8Val + +def q9Val : B32 := BitVec.ofNat extensionDegree 17912128 +def r9Val : B32 := BitVec.ofNat extensionDegree 1177023121 +noncomputable def r9 : Polynomial (ZMod 2) := BinaryField.toPoly r9Val + +def q10Val : B32 := BitVec.ofNat extensionDegree 269484053 +def r10Val : B32 := BitVec.ofNat extensionDegree 540295530 +noncomputable def r10 : Polynomial (ZMod 2) := BinaryField.toPoly r10Val + +def q11Val : B32 := BitVec.ofNat extensionDegree 67175761 +def r11Val : B32 := BitVec.ofNat extensionDegree 1480986355 +noncomputable def r11 : Polynomial (ZMod 2) := BinaryField.toPoly r11Val + +def q12Val : B32 := BitVec.ofNat extensionDegree 289685764 +def r12Val : B32 := BitVec.ofNat extensionDegree 931762713 +noncomputable def r12 : Polynomial (ZMod 2) := BinaryField.toPoly r12Val + +def q13Val : B32 := BitVec.ofNat extensionDegree 85198144 +def r13Val : B32 := BitVec.ofNat extensionDegree 174594945 +noncomputable def r13 : Polynomial (ZMod 2) := BinaryField.toPoly r13Val + +def q14Val : B32 := BitVec.ofNat extensionDegree 4457793 +def r14Val : B32 := BitVec.ofNat extensionDegree 1356421830 +noncomputable def r14 : Polynomial (ZMod 2) := BinaryField.toPoly r14Val + +def q15Val : B32 := BitVec.ofNat extensionDegree 285478981 +def r15Val : B32 := BitVec.ofNat extensionDegree 1998070223 +noncomputable def r15 : Polynomial (ZMod 2) := BinaryField.toPoly r15Val + +def q16Val : B32 := BitVec.ofNat extensionDegree 353387857 +def r16Val : B32 := BitVec.ofNat extensionDegree 993037026 +noncomputable def r16 : Polynomial (ZMod 2) := BinaryField.toPoly r16Val + +def q17Val : B32 := BitVec.ofNat extensionDegree 88364053 +def r17Val : B32 := BitVec.ofNat extensionDegree 1608120431 +noncomputable def r17 : Polynomial (ZMod 2) := BinaryField.toPoly r17Val + +def q18Val : B32 := BitVec.ofNat extensionDegree 290522368 +def r18Val : B32 := BitVec.ofNat extensionDegree 1677135701 +noncomputable def r18 : Polynomial (ZMod 2) := BinaryField.toPoly r18Val + +def q19Val : B32 := BitVec.ofNat extensionDegree 335566080 +def r19Val : B32 := BitVec.ofNat extensionDegree 743750161 +noncomputable def r19 : Polynomial (ZMod 2) := BinaryField.toPoly r19Val + +def q20Val : B32 := BitVec.ofNat extensionDegree 72418641 +def r20Val : B32 := BitVec.ofNat extensionDegree 213064630 +noncomputable def r20 : Polynomial (ZMod 2) := BinaryField.toPoly r20Val + +def q21Val : B32 := BitVec.ofNat extensionDegree 5263633 +def r21Val : B32 := BitVec.ofNat extensionDegree 1152709219 +noncomputable def r21 : Polynomial (ZMod 2) := BinaryField.toPoly r21Val + +def q22Val : B32 := BitVec.ofNat extensionDegree 269762560 +def r22Val : B32 := BitVec.ofNat extensionDegree 627692549 +noncomputable def r22 : Polynomial (ZMod 2) := BinaryField.toPoly r22Val + +def q23Val : B32 := BitVec.ofNat extensionDegree 68161605 +def r23Val : B32 := BitVec.ofNat extensionDegree 1545630154 +noncomputable def r23 : Polynomial (ZMod 2) := BinaryField.toPoly r23Val + +def q24Val : B32 := BitVec.ofNat extensionDegree 290738452 +def r24Val : B32 := BitVec.ofNat extensionDegree 648865576 +noncomputable def r24 : Polynomial (ZMod 2) := BinaryField.toPoly r24Val + +def q25Val : B32 := BitVec.ofNat extensionDegree 68501760 +def r25Val : B32 := BitVec.ofNat extensionDegree 142590784 +noncomputable def r25 : Polynomial (ZMod 2) := BinaryField.toPoly r25Val + +def q26Val : B32 := BitVec.ofNat extensionDegree 4195668 +def r26Val : B32 := BitVec.ofNat extensionDegree 80022188 +noncomputable def r26 : Polynomial (ZMod 2) := BinaryField.toPoly r26Val + +def q27Val : B32 := BitVec.ofNat extensionDegree 1070084 +def r27Val : B32 := BitVec.ofNat extensionDegree 20310092 +noncomputable def r27 : Polynomial (ZMod 2) := BinaryField.toPoly r27Val + +def q28Val : B32 := BitVec.ofNat extensionDegree 66896 +def r28Val : B32 := BitVec.ofNat extensionDegree 4655840 +noncomputable def r28 : Polynomial (ZMod 2) := BinaryField.toPoly r28Val + +def q29Val : B32 := BitVec.ofNat extensionDegree 4113 +def r29Val : B32 := BitVec.ofNat extensionDegree 67380343 +noncomputable def r29 : Polynomial (ZMod 2) := BinaryField.toPoly r29Val + +def q30Val : B32 := BitVec.ofNat extensionDegree 1049617 +def r30Val : B32 := BitVec.ofNat extensionDegree 2099554 +noncomputable def r30 : Polynomial (ZMod 2) := BinaryField.toPoly r30Val + +def q31Val : B32 := BitVec.ofNat extensionDegree 1025 +def r31Val : B32 := BitVec.ofNat extensionDegree 67587 +noncomputable def r31 : Polynomial (ZMod 2) := BinaryField.toPoly r31Val + +def q32Val : B32 := BitVec.ofNat extensionDegree 1 +def r32Val : B32 := BitVec.ofNat extensionDegree 2 +noncomputable def r32 : Polynomial (ZMod 2) := BinaryField.toPoly r32Val + +/-- The initial remainder denotes `X`. -/ +lemma r0_eq_X : r0 = X := by + rw [r0, r0Val, extensionDegree] + have h : (BitVec.ofNat 32 2 : BitVec 32) = (1 <<< 1 : BitVec 32) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 32) 1 (by decide) + +/-- The final remainder after 32 Frobenius steps denotes `X`. -/ +lemma r32_eq_X : r32 = X := by + rw [r32, r32Val, extensionDegree] + have h : (BitVec.ofNat 32 2 : BitVec 32) = (1 <<< 1 : BitVec 32) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 32) 1 (by decide) + +/-- Certificate step 1: square and reduce modulo the GF32 polynomial. -/ +lemma step_1 : + r0 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + r1 := by + change (BinaryField.toPoly r0Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + BinaryField.toPoly r1Val + exact verify_square_step (rPrev := r0Val) (q := q1Val) + (rNext := r1Val) (by rfl) + +/-- Certificate step 2: square and reduce modulo the GF32 polynomial. -/ +lemma step_2 : + r1 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + r2 := by + change (BinaryField.toPoly r1Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + BinaryField.toPoly r2Val + exact verify_square_step (rPrev := r1Val) (q := q2Val) + (rNext := r2Val) (by rfl) + +/-- Certificate step 3: square and reduce modulo the GF32 polynomial. -/ +lemma step_3 : + r2 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + r3 := by + change (BinaryField.toPoly r2Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + BinaryField.toPoly r3Val + exact verify_square_step (rPrev := r2Val) (q := q3Val) + (rNext := r3Val) (by rfl) + +/-- Certificate step 4: square and reduce modulo the GF32 polynomial. -/ +lemma step_4 : + r3 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + r4 := by + change (BinaryField.toPoly r3Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + BinaryField.toPoly r4Val + exact verify_square_step (rPrev := r3Val) (q := q4Val) + (rNext := r4Val) (by rfl) + +/-- Certificate step 5: square and reduce modulo the GF32 polynomial. -/ +lemma step_5 : + r4 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + r5 := by + change (BinaryField.toPoly r4Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + BinaryField.toPoly r5Val + exact verify_square_step (rPrev := r4Val) (q := q5Val) + (rNext := r5Val) (by rfl) + +/-- Certificate step 6: square and reduce modulo the GF32 polynomial. -/ +lemma step_6 : + r5 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + r6 := by + change (BinaryField.toPoly r5Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + BinaryField.toPoly r6Val + exact verify_square_step (rPrev := r5Val) (q := q6Val) + (rNext := r6Val) (by rfl) + +/-- Certificate step 7: square and reduce modulo the GF32 polynomial. -/ +lemma step_7 : + r6 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + r7 := by + change (BinaryField.toPoly r6Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + BinaryField.toPoly r7Val + exact verify_square_step (rPrev := r6Val) (q := q7Val) + (rNext := r7Val) (by rfl) + +/-- Certificate step 8: square and reduce modulo the GF32 polynomial. -/ +lemma step_8 : + r7 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + r8 := by + change (BinaryField.toPoly r7Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + BinaryField.toPoly r8Val + exact verify_square_step (rPrev := r7Val) (q := q8Val) + (rNext := r8Val) (by rfl) + +/-- Certificate step 9: square and reduce modulo the GF32 polynomial. -/ +lemma step_9 : + r8 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + r9 := by + change (BinaryField.toPoly r8Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + BinaryField.toPoly r9Val + exact verify_square_step (rPrev := r8Val) (q := q9Val) + (rNext := r9Val) (by rfl) + +/-- Certificate step 10: square and reduce modulo the GF32 polynomial. -/ +lemma step_10 : + r9 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + r10 := by + change (BinaryField.toPoly r9Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + BinaryField.toPoly r10Val + exact verify_square_step (rPrev := r9Val) (q := q10Val) + (rNext := r10Val) (by rfl) + +/-- Certificate step 11: square and reduce modulo the GF32 polynomial. -/ +lemma step_11 : + r10 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + r11 := by + change (BinaryField.toPoly r10Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + BinaryField.toPoly r11Val + exact verify_square_step (rPrev := r10Val) (q := q11Val) + (rNext := r11Val) (by rfl) + +/-- Certificate step 12: square and reduce modulo the GF32 polynomial. -/ +lemma step_12 : + r11 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + r12 := by + change (BinaryField.toPoly r11Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + BinaryField.toPoly r12Val + exact verify_square_step (rPrev := r11Val) (q := q12Val) + (rNext := r12Val) (by rfl) + +/-- Certificate step 13: square and reduce modulo the GF32 polynomial. -/ +lemma step_13 : + r12 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + r13 := by + change (BinaryField.toPoly r12Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + BinaryField.toPoly r13Val + exact verify_square_step (rPrev := r12Val) (q := q13Val) + (rNext := r13Val) (by rfl) + +/-- Certificate step 14: square and reduce modulo the GF32 polynomial. -/ +lemma step_14 : + r13 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + r14 := by + change (BinaryField.toPoly r13Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + BinaryField.toPoly r14Val + exact verify_square_step (rPrev := r13Val) (q := q14Val) + (rNext := r14Val) (by rfl) + +/-- Certificate step 15: square and reduce modulo the GF32 polynomial. -/ +lemma step_15 : + r14 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + r15 := by + change (BinaryField.toPoly r14Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + BinaryField.toPoly r15Val + exact verify_square_step (rPrev := r14Val) (q := q15Val) + (rNext := r15Val) (by rfl) + +/-- Certificate step 16: square and reduce modulo the GF32 polynomial. -/ +lemma step_16 : + r15 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + r16 := by + change (BinaryField.toPoly r15Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + BinaryField.toPoly r16Val + exact verify_square_step (rPrev := r15Val) (q := q16Val) + (rNext := r16Val) (by rfl) + +/-- Certificate step 17: square and reduce modulo the GF32 polynomial. -/ +lemma step_17 : + r16 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + r17 := by + change (BinaryField.toPoly r16Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + BinaryField.toPoly r17Val + exact verify_square_step (rPrev := r16Val) (q := q17Val) + (rNext := r17Val) (by rfl) + +/-- Certificate step 18: square and reduce modulo the GF32 polynomial. -/ +lemma step_18 : + r17 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + r18 := by + change (BinaryField.toPoly r17Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + BinaryField.toPoly r18Val + exact verify_square_step (rPrev := r17Val) (q := q18Val) + (rNext := r18Val) (by rfl) + +/-- Certificate step 19: square and reduce modulo the GF32 polynomial. -/ +lemma step_19 : + r18 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + r19 := by + change (BinaryField.toPoly r18Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + BinaryField.toPoly r19Val + exact verify_square_step (rPrev := r18Val) (q := q19Val) + (rNext := r19Val) (by rfl) + +/-- Certificate step 20: square and reduce modulo the GF32 polynomial. -/ +lemma step_20 : + r19 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + r20 := by + change (BinaryField.toPoly r19Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + BinaryField.toPoly r20Val + exact verify_square_step (rPrev := r19Val) (q := q20Val) + (rNext := r20Val) (by rfl) + +/-- Certificate step 21: square and reduce modulo the GF32 polynomial. -/ +lemma step_21 : + r20 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + r21 := by + change (BinaryField.toPoly r20Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + BinaryField.toPoly r21Val + exact verify_square_step (rPrev := r20Val) (q := q21Val) + (rNext := r21Val) (by rfl) + +/-- Certificate step 22: square and reduce modulo the GF32 polynomial. -/ +lemma step_22 : + r21 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + r22 := by + change (BinaryField.toPoly r21Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + BinaryField.toPoly r22Val + exact verify_square_step (rPrev := r21Val) (q := q22Val) + (rNext := r22Val) (by rfl) + +/-- Certificate step 23: square and reduce modulo the GF32 polynomial. -/ +lemma step_23 : + r22 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + r23 := by + change (BinaryField.toPoly r22Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + BinaryField.toPoly r23Val + exact verify_square_step (rPrev := r22Val) (q := q23Val) + (rNext := r23Val) (by rfl) + +/-- Certificate step 24: square and reduce modulo the GF32 polynomial. -/ +lemma step_24 : + r23 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + r24 := by + change (BinaryField.toPoly r23Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + BinaryField.toPoly r24Val + exact verify_square_step (rPrev := r23Val) (q := q24Val) + (rNext := r24Val) (by rfl) + +/-- Certificate step 25: square and reduce modulo the GF32 polynomial. -/ +lemma step_25 : + r24 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + r25 := by + change (BinaryField.toPoly r24Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + BinaryField.toPoly r25Val + exact verify_square_step (rPrev := r24Val) (q := q25Val) + (rNext := r25Val) (by rfl) + +/-- Certificate step 26: square and reduce modulo the GF32 polynomial. -/ +lemma step_26 : + r25 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + r26 := by + change (BinaryField.toPoly r25Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + BinaryField.toPoly r26Val + exact verify_square_step (rPrev := r25Val) (q := q26Val) + (rNext := r26Val) (by rfl) + +/-- Certificate step 27: square and reduce modulo the GF32 polynomial. -/ +lemma step_27 : + r26 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + r27 := by + change (BinaryField.toPoly r26Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + BinaryField.toPoly r27Val + exact verify_square_step (rPrev := r26Val) (q := q27Val) + (rNext := r27Val) (by rfl) + +/-- Certificate step 28: square and reduce modulo the GF32 polynomial. -/ +lemma step_28 : + r27 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + r28 := by + change (BinaryField.toPoly r27Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + BinaryField.toPoly r28Val + exact verify_square_step (rPrev := r27Val) (q := q28Val) + (rNext := r28Val) (by rfl) + +/-- Certificate step 29: square and reduce modulo the GF32 polynomial. -/ +lemma step_29 : + r28 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + r29 := by + change (BinaryField.toPoly r28Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + BinaryField.toPoly r29Val + exact verify_square_step (rPrev := r28Val) (q := q29Val) + (rNext := r29Val) (by rfl) + +/-- Certificate step 30: square and reduce modulo the GF32 polynomial. -/ +lemma step_30 : + r29 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + r30 := by + change (BinaryField.toPoly r29Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + BinaryField.toPoly r30Val + exact verify_square_step (rPrev := r29Val) (q := q30Val) + (rNext := r30Val) (by rfl) + +/-- Certificate step 31: square and reduce modulo the GF32 polynomial. -/ +lemma step_31 : + r30 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + r31 := by + change (BinaryField.toPoly r30Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + BinaryField.toPoly r31Val + exact verify_square_step (rPrev := r30Val) (q := q31Val) + (rNext := r31Val) (by rfl) + +/-- Certificate step 32: square and reduce modulo the GF32 polynomial. -/ +lemma step_32 : + r31 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + r32 := by + change (BinaryField.toPoly r31Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + BinaryField.toPoly r32Val + exact verify_square_step (rPrev := r31Val) (q := q32Val) + (rNext := r32Val) (by rfl) + + +/-- The degree-one polynomial `X` is already reduced modulo the GF32 polynomial. -/ +lemma X_mod_definingPolynomial : + X % definingPolynomial = X := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + unfold extensionDegree + norm_num [degree_X] + +lemma X_pow_2_pow_0_mod_eq : + X ^ (2 ^ 0) % definingPolynomial = r0 % definingPolynomial := by + rw [pow_zero, pow_one, r0_eq_X] + +lemma X_pow_2_pow_1_mod_eq : + X ^ (2 ^ 1) % definingPolynomial = r1 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 0) X_pow_2_pow_0_mod_eq step_1 + +lemma X_pow_2_pow_2_mod_eq : + X ^ (2 ^ 2) % definingPolynomial = r2 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 1) X_pow_2_pow_1_mod_eq step_2 + +lemma X_pow_2_pow_3_mod_eq : + X ^ (2 ^ 3) % definingPolynomial = r3 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 2) X_pow_2_pow_2_mod_eq step_3 + +lemma X_pow_2_pow_4_mod_eq : + X ^ (2 ^ 4) % definingPolynomial = r4 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 3) X_pow_2_pow_3_mod_eq step_4 + +lemma X_pow_2_pow_5_mod_eq : + X ^ (2 ^ 5) % definingPolynomial = r5 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 4) X_pow_2_pow_4_mod_eq step_5 + +lemma X_pow_2_pow_6_mod_eq : + X ^ (2 ^ 6) % definingPolynomial = r6 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 5) X_pow_2_pow_5_mod_eq step_6 + +lemma X_pow_2_pow_7_mod_eq : + X ^ (2 ^ 7) % definingPolynomial = r7 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 6) X_pow_2_pow_6_mod_eq step_7 + +lemma X_pow_2_pow_8_mod_eq : + X ^ (2 ^ 8) % definingPolynomial = r8 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 7) X_pow_2_pow_7_mod_eq step_8 + +lemma X_pow_2_pow_9_mod_eq : + X ^ (2 ^ 9) % definingPolynomial = r9 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 8) X_pow_2_pow_8_mod_eq step_9 + +lemma X_pow_2_pow_10_mod_eq : + X ^ (2 ^ 10) % definingPolynomial = r10 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 9) X_pow_2_pow_9_mod_eq step_10 + +lemma X_pow_2_pow_11_mod_eq : + X ^ (2 ^ 11) % definingPolynomial = r11 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 10) X_pow_2_pow_10_mod_eq step_11 + +lemma X_pow_2_pow_12_mod_eq : + X ^ (2 ^ 12) % definingPolynomial = r12 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 11) X_pow_2_pow_11_mod_eq step_12 + +lemma X_pow_2_pow_13_mod_eq : + X ^ (2 ^ 13) % definingPolynomial = r13 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 12) X_pow_2_pow_12_mod_eq step_13 + +lemma X_pow_2_pow_14_mod_eq : + X ^ (2 ^ 14) % definingPolynomial = r14 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 13) X_pow_2_pow_13_mod_eq step_14 + +lemma X_pow_2_pow_15_mod_eq : + X ^ (2 ^ 15) % definingPolynomial = r15 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 14) X_pow_2_pow_14_mod_eq step_15 + +lemma X_pow_2_pow_16_mod_eq : + X ^ (2 ^ 16) % definingPolynomial = r16 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 15) X_pow_2_pow_15_mod_eq step_16 + +lemma X_pow_2_pow_17_mod_eq : + X ^ (2 ^ 17) % definingPolynomial = r17 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 16) X_pow_2_pow_16_mod_eq step_17 + +lemma X_pow_2_pow_18_mod_eq : + X ^ (2 ^ 18) % definingPolynomial = r18 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 17) X_pow_2_pow_17_mod_eq step_18 + +lemma X_pow_2_pow_19_mod_eq : + X ^ (2 ^ 19) % definingPolynomial = r19 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 18) X_pow_2_pow_18_mod_eq step_19 + +lemma X_pow_2_pow_20_mod_eq : + X ^ (2 ^ 20) % definingPolynomial = r20 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 19) X_pow_2_pow_19_mod_eq step_20 + +lemma X_pow_2_pow_21_mod_eq : + X ^ (2 ^ 21) % definingPolynomial = r21 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 20) X_pow_2_pow_20_mod_eq step_21 + +lemma X_pow_2_pow_22_mod_eq : + X ^ (2 ^ 22) % definingPolynomial = r22 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 21) X_pow_2_pow_21_mod_eq step_22 + +lemma X_pow_2_pow_23_mod_eq : + X ^ (2 ^ 23) % definingPolynomial = r23 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 22) X_pow_2_pow_22_mod_eq step_23 + +lemma X_pow_2_pow_24_mod_eq : + X ^ (2 ^ 24) % definingPolynomial = r24 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 23) X_pow_2_pow_23_mod_eq step_24 + +lemma X_pow_2_pow_25_mod_eq : + X ^ (2 ^ 25) % definingPolynomial = r25 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 24) X_pow_2_pow_24_mod_eq step_25 + +lemma X_pow_2_pow_26_mod_eq : + X ^ (2 ^ 26) % definingPolynomial = r26 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 25) X_pow_2_pow_25_mod_eq step_26 + +lemma X_pow_2_pow_27_mod_eq : + X ^ (2 ^ 27) % definingPolynomial = r27 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 26) X_pow_2_pow_26_mod_eq step_27 + +lemma X_pow_2_pow_28_mod_eq : + X ^ (2 ^ 28) % definingPolynomial = r28 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 27) X_pow_2_pow_27_mod_eq step_28 + +lemma X_pow_2_pow_29_mod_eq : + X ^ (2 ^ 29) % definingPolynomial = r29 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 28) X_pow_2_pow_28_mod_eq step_29 + +lemma X_pow_2_pow_30_mod_eq : + X ^ (2 ^ 30) % definingPolynomial = r30 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 29) X_pow_2_pow_29_mod_eq step_30 + +lemma X_pow_2_pow_31_mod_eq : + X ^ (2 ^ 31) % definingPolynomial = r31 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 30) X_pow_2_pow_30_mod_eq step_31 + +lemma X_pow_2_pow_32_mod_eq : + X ^ (2 ^ 32) % definingPolynomial = r32 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 31) X_pow_2_pow_31_mod_eq step_32 + +/-- Rabin trace-condition remainder for the GF32 candidate polynomial. -/ +lemma X_pow_2_pow_32_add_X_mod_eq_zero : + (X ^ (2 ^ 32) + X) % definingPolynomial = 0 := by + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_32_mod_eq, r32_eq_X, X_mod_definingPolynomial] + simp only [CharTwo.add_self_eq_zero, EuclideanDomain.zero_mod] + +/-- Rabin trace divisibility condition for the GF32 candidate polynomial. -/ +lemma X_pow_2_pow_32_add_X_dvd : + definingPolynomial ∣ X ^ (2 ^ 32) + X := by + rw [← EuclideanDomain.mod_eq_zero] + exact X_pow_2_pow_32_add_X_mod_eq_zero + +end GF2_32 diff --git a/CompPoly/Fields/Binary/GF2_48.lean b/CompPoly/Fields/Binary/GF2_48.lean new file mode 100644 index 00000000..b049907d --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48.lean @@ -0,0 +1,16 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_48.Prelude +import CompPoly.Fields.Binary.GF2_48.Basic +import CompPoly.Fields.Binary.GF2_48.Impl +import CompPoly.Fields.Binary.GF2_48.XPowTwoPowModCertificate +import CompPoly.Fields.Binary.GF2_48.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_48.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_48.Primitive +import CompPoly.Fields.Binary.GF2_48.RootContexts + +/-! # GF(2^48) Binary Field Facade -/ diff --git a/CompPoly/Fields/Binary/GF2_48/Basic.lean b/CompPoly/Fields/Binary/GF2_48/Basic.lean new file mode 100644 index 00000000..af24b7e1 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/Basic.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Basic +import CompPoly.Fields.Binary.GF2_48.Prelude + +/-! +# GF(2^48) Quotient Specification + +The quotient/specification carrier for the candidate polynomial +`X^48 + X^9 + X^7 + X^4 + 1`. + +Field, finite, characteristic, and cardinality instances are conditional on the +irreducibility certificate that will be provided by the concrete certificate +modules. +-/ + +namespace GF2_48 + +open Polynomial AdjoinRoot + +noncomputable section + +/-- Quotient/specification carrier for `GF(2^48)`. -/ +abbrev SpecField : Type := + BinaryField.Extension.SpecField definingPolynomialData + +private instance instIrreduciblePolynomialFact [Fact (Irreducible definingPolynomial)] : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using (inferInstance : Fact (Irreducible definingPolynomial)) + +/-- Conditional field instance, available once irreducibility is certified. -/ +instance instFieldSpecField [Fact (Irreducible definingPolynomial)] : + Field SpecField := + inferInstanceAs (Field (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional nontriviality, available once irreducibility is certified. -/ +instance instNontrivialSpecField [Fact (Irreducible definingPolynomial)] : + Nontrivial SpecField := + inferInstance + +/-- Quotient/specification carrier is inhabited. -/ +instance instInhabitedSpecField : Inhabited SpecField := + inferInstance + +/-- Algebra structure over `GF(2)`. -/ +instance instAlgebraSpecField : Algebra (ZMod 2) SpecField := + inferInstanceAs (Algebra (ZMod 2) (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional characteristic-two instance, available once irreducibility is certified. -/ +instance instCharTwoSpecField [Fact (Irreducible definingPolynomial)] : + CharP SpecField 2 := + inferInstance + +/-- Canonical embedding of `GF(2)` into `SpecField`. -/ +def ofGF2 : ZMod 2 →+* SpecField := + BinaryField.Extension.ofGF2 definingPolynomialData + +/-- The quotient root/generator. -/ +def root : SpecField := + BinaryField.Extension.root definingPolynomialData + +/-- The quotient root satisfies the defining polynomial. -/ +theorem root_satisfies_definingPolynomial : + Polynomial.eval₂ (algebraMap (ZMod 2) SpecField) root definingPolynomial = 0 := + BinaryField.Extension.root_satisfies_polynomial definingPolynomialData + +/-- Conditional finite type, available once irreducibility is certified. -/ +instance instFintypeSpecField [Fact (Irreducible definingPolynomial)] : + Fintype SpecField := + inferInstanceAs (Fintype (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Cardinality of the certified quotient specification. -/ +theorem SpecField_card [Fact (Irreducible definingPolynomial)] : + Fintype.card SpecField = 2 ^ extensionDegree := + BinaryField.Extension.specField_card definingPolynomialData + +end + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_48/Impl.lean b/CompPoly/Fields/Binary/GF2_48/Impl.lean new file mode 100644 index 00000000..65adb911 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/Impl.lean @@ -0,0 +1,365 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Impl +import CompPoly.Fields.Binary.GF2_48.Basic +import Mathlib.Algebra.Algebra.ZMod +import Mathlib.Algebra.CharP.CharAndCard +import Init.Data.Array.Lemmas + +/-! +# GF(2^48) Executable Bit-Vector Operations + +Executable operations for the `GF(2^48)` candidate polynomial +`X^48 + X^9 + X^7 + X^4 + 1`. + +This file exposes the raw `BitVec` carrier and arithmetic definitions. It does +claim the certified `Field` instance conditionally on the irreducibility +certificate supplied by `GF2_48.Primitive`. +-/ + +namespace GF2_48 + +namespace Concrete + +/-- Executable parameters for the `GF(2^48)` candidate polynomial. -/ +def params : BinaryField.Extension.ExecutableParams where + degree := extensionDegree + tailExponents := [0, 4, 7, 9] + tailExponents_bound := by + intro exponent h + simp at h + rcases h with rfl | rfl | rfl | rfl <;> unfold extensionDegree <;> omega + +/-- The executable tail list denotes the low-degree part of the GF48 polynomial. -/ +lemma definingPolynomial_eq_executableSparse : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ params.degree + + BinaryField.Extension.sparsePolynomial params.tailExponents := by + rw [show BinaryField.Extension.polynomial definingPolynomialData = definingPolynomial by rfl] + rw [definingPolynomial_eq_X_pow_add_tail] + simp [params, extensionDegree, definingTail, BinaryField.Extension.sparsePolynomial] + ring_nf + +end Concrete + +/-- Executable bit-vector carrier for `GF(2^48)`. -/ +@[reducible] +def ConcreteField : Type := + BinaryField.Extension.ConcreteField Concrete.params + +namespace ConcreteField + +abbrev rawWidth : Nat := + extensionDegree + +def toBitVec : ConcreteField → B48 := + BinaryField.Extension.Concrete.toBitVec Concrete.params + +def ofBitVec : B48 → ConcreteField := + BinaryField.Extension.Concrete.ofBitVec Concrete.params + +def toNat : ConcreteField → Nat := + BinaryField.Extension.Concrete.toNat Concrete.params + +def ofNat (n : Nat) : ConcreteField := + BinaryField.Extension.Concrete.ofNat Concrete.params n + +def root : ConcreteField := + BinaryField.Extension.Concrete.root Concrete.params + +def add : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.add Concrete.params + +def mul : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.mul Concrete.params + +def square : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.square Concrete.params + +def pow : ConcreteField → Nat → ConcreteField := + BinaryField.Extension.Concrete.pow Concrete.params + +def inv : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.inv Concrete.params + +def traceValue : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.traceValue Concrete.params + +def polynomialBasis : Array ConcreteField := + BinaryField.Extension.Concrete.polynomialBasis Concrete.params + +def baseConstants : Array ConcreteField := + BinaryField.Extension.Concrete.baseConstants Concrete.params + +noncomputable def toSpec : ConcreteField → SpecField := + BinaryField.Extension.Concrete.toSpec Concrete.params (data := definingPolynomialData) + +instance : BEq ConcreteField := + BinaryField.Extension.Concrete.instBEqConcreteField Concrete.params + +instance : LawfulBEq ConcreteField := + BinaryField.Extension.Concrete.instLawfulBEqConcreteField Concrete.params + +instance : Inhabited ConcreteField := + BinaryField.Extension.Concrete.instInhabitedConcreteField Concrete.params + +instance : Zero ConcreteField := + BinaryField.Extension.Concrete.instZeroConcreteField Concrete.params + +instance : One ConcreteField := + BinaryField.Extension.Concrete.instOneConcreteField Concrete.params + +instance : Add ConcreteField := + BinaryField.Extension.Concrete.instAddConcreteField Concrete.params + +instance : Neg ConcreteField := + BinaryField.Extension.Concrete.instNegConcreteField Concrete.params + +instance : Sub ConcreteField := + BinaryField.Extension.Concrete.instSubConcreteField Concrete.params + +instance : Mul ConcreteField := + BinaryField.Extension.Concrete.instMulConcreteField Concrete.params + +instance : Pow ConcreteField Nat := + BinaryField.Extension.Concrete.instPowConcreteField Concrete.params + +instance : Inv ConcreteField := + BinaryField.Extension.Concrete.instInvConcreteField Concrete.params + +/-- Certified executable field structure for `GF(2^48)`. -/ +instance (priority := 2000) instFieldConcreteField + [Fact (Irreducible definingPolynomial)] : + Field ConcreteField := by + haveI : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using + (inferInstance : Fact (Irreducible definingPolynomial)) + let hP : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ Concrete.params.degree + + BinaryField.Extension.sparsePolynomial Concrete.params.tailExponents := + Concrete.definingPolynomial_eq_executableSparse + let hP_degree : + (BinaryField.Extension.polynomial definingPolynomialData).degree = + Concrete.params.degree := by + simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + let hDegree_pos : 0 < Concrete.params.degree := by + unfold Concrete.params extensionDegree + norm_num + exact + { toDivisionRing := + { toRing := + { add := BinaryField.Extension.Concrete.add Concrete.params + zero := BinaryField.Extension.Concrete.zero Concrete.params + neg := BinaryField.Extension.Concrete.neg Concrete.params + sub := BinaryField.Extension.Concrete.sub Concrete.params + mul := BinaryField.Extension.Concrete.mul Concrete.params + one := BinaryField.Extension.Concrete.one Concrete.params + nsmul := fun n x => + if n % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + zsmul := fun n x => + if n % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + npow := fun n x => BinaryField.Extension.Concrete.pow Concrete.params x n + add_assoc := BinaryField.Extension.Concrete.add_assoc Concrete.params + add_comm := BinaryField.Extension.Concrete.add_comm Concrete.params + add_zero := BinaryField.Extension.Concrete.add_zero Concrete.params + zero_add := BinaryField.Extension.Concrete.zero_add Concrete.params + neg_add_cancel := BinaryField.Extension.Concrete.neg_add_cancel Concrete.params + sub_eq_add_neg := by intro _ _; rfl + nsmul_zero := fun _ => rfl + nsmul_succ := BinaryField.Extension.Concrete.nsmul_succ Concrete.params + zsmul_zero' := fun _ => rfl + zsmul_succ' := BinaryField.Extension.Concrete.zsmul_succ Concrete.params + zsmul_neg' := BinaryField.Extension.Concrete.zsmul_neg Concrete.params + mul_assoc := + BinaryField.Extension.Concrete.mul_assoc_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + one_mul := + BinaryField.Extension.Concrete.one_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_one := + BinaryField.Extension.Concrete.mul_one_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + left_distrib := + BinaryField.Extension.Concrete.left_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + right_distrib := + BinaryField.Extension.Concrete.right_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + zero_mul := + BinaryField.Extension.Concrete.zero_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_zero := + BinaryField.Extension.Concrete.mul_zero_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + natCast := BinaryField.Extension.Concrete.natCast Concrete.params + natCast_zero := BinaryField.Extension.Concrete.natCast_zero Concrete.params + natCast_succ := BinaryField.Extension.Concrete.natCast_succ Concrete.params + intCast := BinaryField.Extension.Concrete.intCast Concrete.params + intCast_ofNat := BinaryField.Extension.Concrete.intCast_ofNat Concrete.params + intCast_negSucc := BinaryField.Extension.Concrete.intCast_negSucc Concrete.params + npow_zero := by + intro x + change BinaryField.Extension.Concrete.pow Concrete.params x 0 = + BinaryField.Extension.Concrete.one Concrete.params + simp [BinaryField.Extension.Concrete.pow] + npow_succ := by + intro n x + change BinaryField.Extension.Concrete.pow Concrete.params x (n + 1) = + BinaryField.Extension.Concrete.mul Concrete.params + (BinaryField.Extension.Concrete.pow Concrete.params x n) x + exact BinaryField.Extension.Concrete.pow_succ_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos n x } + inv := BinaryField.Extension.Concrete.inv Concrete.params + div := fun a b => + BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params b) + exists_pair_ne := + BinaryField.Extension.Concrete.exists_pair_ne Concrete.params hDegree_pos + mul_inv_cancel := by + intro a h + change BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params a) = + BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.mul_inv_cancel_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a (by simpa using h) + inv_zero := by + change BinaryField.Extension.Concrete.inv Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = + BinaryField.Extension.Concrete.zero Concrete.params + exact BinaryField.Extension.Concrete.inv_zero Concrete.params + div_eq_mul_inv := by + intro a b + rfl + qsmul := _ + nnqsmul := _ } + mul_comm := by + intro a b + change BinaryField.Extension.Concrete.mul Concrete.params a b = + BinaryField.Extension.Concrete.mul Concrete.params b a + exact BinaryField.Extension.Concrete.mul_comm_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a b } + +noncomputable instance : Fintype ConcreteField := + BinaryField.Extension.Concrete.instFintypeConcreteField Concrete.params + +instance : Finite ConcreteField := + BinaryField.Extension.Concrete.instFiniteConcreteField Concrete.params + +/-- The raw executable carrier has `2^48` bit-patterns. -/ +theorem card : + Fintype.card ConcreteField = 2 ^ extensionDegree := by + simpa [Concrete.params] using + BinaryField.Extension.Concrete.concreteField_card Concrete.params + +/-- The certified executable carrier has characteristic two. -/ +noncomputable instance instCharTwoConcreteField [Fact (Irreducible definingPolynomial)] : + CharP ConcreteField 2 := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : IsDomain ConcreteField := Field.isDomain + haveI : Fact (Nat.Prime 2) := ⟨Nat.prime_two⟩ + exact charP_of_card_eq_prime_pow (R := ConcreteField) (p := 2) + (f := extensionDegree) card + +/-- Canonical `GF(2)` algebra structure on the certified executable carrier. -/ +noncomputable instance instAlgebraConcreteField [Fact (Irreducible definingPolynomial)] : + Algebra (ZMod 2) ConcreteField := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : CharP ConcreteField 2 := instCharTwoConcreteField + exact ZMod.algebra ConcreteField 2 + +@[simp] +theorem polynomialBasis_size : + polynomialBasis.size = extensionDegree := by + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis] + exact Array.size_ofFn + +@[simp] +theorem baseConstants_size : + baseConstants.size = 2 := by + simp [baseConstants, BinaryField.Extension.Concrete.baseConstants] + +theorem toSpec_injective : + Function.Injective toSpec := by + apply BinaryField.Extension.Concrete.toSpec_injective + · simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + · unfold Concrete.params extensionDegree + norm_num + +theorem toSpec_zero : + toSpec 0 = 0 := by + exact BinaryField.Extension.Concrete.toSpec_zero Concrete.params + +theorem toSpec_one : + toSpec 1 = 1 := by + exact BinaryField.Extension.Concrete.toSpec_one Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + +theorem toSpec_add (a b : ConcreteField) : + toSpec (a + b) = toSpec a + toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_add Concrete.params a b + +theorem toSpec_neg (a : ConcreteField) : + toSpec (-a) = -toSpec a := by + exact BinaryField.Extension.Concrete.toSpec_neg Concrete.params a + +theorem toSpec_sub (a b : ConcreteField) : + toSpec (a - b) = toSpec a - toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_sub Concrete.params a b + +theorem toSpec_mul (a b : ConcreteField) : + toSpec (a * b) = toSpec a * toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_mul Concrete.params + (data := definingPolynomialData) + Concrete.definingPolynomial_eq_executableSparse + (by simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree) + a b + +/-- Ring homomorphism from executable GF48 elements to the quotient specification. -/ +noncomputable def toSpecRingHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →+* SpecField where + toFun := toSpec + map_zero' := toSpec_zero + map_one' := toSpec_one + map_add' := toSpec_add + map_mul' := toSpec_mul + +/-- Algebra homomorphism from executable GF48 elements to the quotient specification. -/ +noncomputable def toSpecAlgHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →ₐ[ZMod 2] SpecField where + __ := toSpecRingHom + commutes' := by + intro r + exact RingHom.congr_fun + (RingHom.ext_zmod (toSpecRingHom.comp (algebraMap (ZMod 2) ConcreteField)) + (algebraMap (ZMod 2) SpecField)) r + +/-- Algebra equivalence between executable GF48 elements and the quotient specification. -/ +noncomputable def toSpecAlgEquiv [Fact (Irreducible definingPolynomial)] : + ConcreteField ≃ₐ[ZMod 2] SpecField := + AlgEquiv.ofBijective toSpecAlgHom <| by + apply Function.Injective.bijective_of_nat_card_le + · exact toSpec_injective + · rw [Nat.card_eq_fintype_card, Nat.card_eq_fintype_card] + rw [card, BinaryField.Extension.specField_card definingPolynomialData] + simp [definingPolynomialData, extensionDegree] + +/-- The executable polynomial-basis generator maps to the quotient root. -/ +theorem toSpec_root : + toSpec root = GF2_48.root := by + exact BinaryField.Extension.Concrete.toSpec_root Concrete.params + (data := definingPolynomialData) + (by unfold Concrete.params extensionDegree; norm_num) + +end ConcreteField + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_48/Prelude.lean b/CompPoly/Fields/Binary/GF2_48/Prelude.lean new file mode 100644 index 00000000..28cfd849 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/Prelude.lean @@ -0,0 +1,158 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Prelude +import Mathlib.Tactic.ComputeDegree + +/-! +# GF(2^48) Prelude + +Defining constants and small executable metadata for the direct binary extension +with candidate primitive polynomial + +`X^48 + X^9 + X^7 + X^4 + 1`. + +Irreducibility and primitive-order certificates are added in later `GF2_48` +modules before this polynomial is used to construct public field instances. +-/ + +namespace GF2_48 + +open Polynomial + +noncomputable section + +/-- Extension degree for `GF(2^48)`. -/ +def extensionDegree : Nat := + 48 + +/-- Raw executable carrier width for `GF(2^48)`. -/ +abbrev B48 : Type := + BitVec extensionDegree + +/-- Field cardinality of `GF(2^48)`. -/ +def fieldSize : Nat := + BinaryField.Extension.fieldSize extensionDegree + +/-- Multiplicative group order of `GF(2^48)`. -/ +def multiplicativeGroupOrder : Nat := + BinaryField.Extension.multiplicativeGroupOrder extensionDegree + +/-- Low-degree tail `X^9 + X^7 + X^4 + 1`. -/ +def definingTail : Polynomial (ZMod 2) := + X ^ 9 + X ^ 7 + X ^ 4 + 1 + +/-- Candidate primitive polynomial bitmask: `X^48 + X^9 + X^7 + X^4 + 1`. -/ +def definingBitmask : Nat := + 0x1000000000291 + +/-- Exponents with nonzero coefficients in the full defining polynomial. -/ +def definingPolynomialExponents : List Nat := + [0, 4, 7, 9, 48] + +/-- The tail has natural degree `9`. -/ +lemma definingTail_natDegree : + definingTail.natDegree = 9 := by + unfold definingTail + compute_degree! + +/-- The tail is monic. -/ +lemma definingTail_monic : + definingTail.Monic := by + unfold definingTail + monicity! + +/-- Metadata for the direct binary extension polynomial. -/ +def definingPolynomialData : BinaryField.Extension.DefiningPolynomialData where + degree := extensionDegree + tail := definingTail + tailDegree := 9 + bitmask := definingBitmask + tail_natDegree := definingTail_natDegree + tailDegree_lt_degree := by + unfold extensionDegree + omega + +/-- Candidate defining polynomial for `GF(2^48)`. -/ +def definingPolynomial : Polynomial (ZMod 2) := + BinaryField.Extension.polynomial definingPolynomialData + +/-- Expanded form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_X_pow_add_tail : + definingPolynomial = X ^ 48 + definingTail := by + rfl + +/-- Expanded sparse form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_sparse : + definingPolynomial = X ^ 48 + X ^ 9 + X ^ 7 + X ^ 4 + 1 := by + unfold definingPolynomial BinaryField.Extension.polynomial definingPolynomialData definingTail + extensionDegree + ring + +/-- The candidate defining polynomial is monic of degree `48`. -/ +lemma definingPolynomial_isMonicOfDegree : + IsMonicOfDegree definingPolynomial extensionDegree := + BinaryField.Extension.polynomial_isMonicOfDegree definingPolynomialData + +/-- The candidate defining polynomial has natural degree `48`. -/ +lemma definingPolynomial_natDegree : + definingPolynomial.natDegree = extensionDegree := + BinaryField.Extension.polynomial_natDegree definingPolynomialData + +/-- The candidate defining polynomial is monic. -/ +lemma definingPolynomial_monic : + definingPolynomial.Monic := + BinaryField.Extension.polynomial_monic definingPolynomialData + +/-- The candidate defining polynomial is nonzero. -/ +lemma definingPolynomial_ne_zero : + definingPolynomial ≠ 0 := + BinaryField.Extension.polynomial_ne_zero definingPolynomialData + +/-- The candidate defining polynomial has degree `48`. -/ +lemma definingPolynomial_degree : + definingPolynomial.degree = extensionDegree := + BinaryField.Extension.polynomial_degree definingPolynomialData + +/-- Bit-vector encoding of the candidate defining polynomial. -/ +def P_val : BitVec (2 * extensionDegree) := + (1 <<< 48) ^^^ (1 <<< 9) ^^^ (1 <<< 7) ^^^ (1 <<< 4) ^^^ 1 + +/-- The `BitVec` encoding denotes the candidate defining polynomial. -/ +lemma definingPolynomial_eq_P_val : + definingPolynomial = BinaryField.toPoly P_val := by + rw [definingPolynomial_eq_sparse] + unfold P_val extensionDegree + repeat rw [BinaryField.toPoly_xor] + rw [BinaryField.Extension.toPoly_one_shiftLeft 48 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 9 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 7 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 4 (by omega)] + rw [(show (1 : BitVec 96) = 1 <<< 0 by simp)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 0 (by omega)] + simp only [pow_zero] + +/-- The exponent list denotes the candidate defining polynomial. -/ +lemma sparsePolynomial_definingPolynomialExponents : + BinaryField.Extension.sparsePolynomial definingPolynomialExponents = definingPolynomial := by + rw [definingPolynomial_eq_sparse] + simp [definingPolynomialExponents, BinaryField.Extension.sparsePolynomial] + ring_nf + +/-- Smooth subgroup refinement schedule for `2^48 - 1`. -/ +def smoothRootSchedule : Array Nat := + #[3, 3, 5, 7, 13, 17, 97, 241, 257, 673] + +/-- The GF48 smooth schedule refines the multiplicative group down to singleton cosets. -/ +lemma smoothRootSchedule_fold_eq_one : + smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (fieldSize - 1) = 1 := by + unfold smoothRootSchedule fieldSize BinaryField.Extension.fieldSize extensionDegree + decide + +end + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_48/Primitive.lean b/CompPoly/Fields/Binary/GF2_48/Primitive.lean new file mode 100644 index 00000000..a2a025fd --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/Primitive.lean @@ -0,0 +1,182 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_48.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_48.PrimitivePowerCertificate +import Mathlib.GroupTheory.OrderOfElement +import CompPoly.Fields.Binary.GF2_48.Impl + +/-! +# GF(2^48) Primitive-Order Scaffold + +Small primitive-order metadata and Rabin irreducibility certificate for the +`GF(2^48)` candidate. +-/ + +namespace GF2_48 + +set_option maxRecDepth 20000 + +/-- Distinct prime factors of `2^48 - 1`. -/ +def primitivePrimeFactors : List Nat := + [3, 5, 7, 13, 17, 97, 241, 257, 673] + +/-- Factorization of the multiplicative-group order `2^48 - 1`. -/ +lemma multiplicativeGroupOrder_factorization : + multiplicativeGroupOrder = 3 ^ 2 * 5 * 7 * 13 * 17 * 97 * 241 * 257 * 673 := by + unfold multiplicativeGroupOrder BinaryField.Extension.multiplicativeGroupOrder + BinaryField.Extension.fieldSize extensionDegree + norm_num + +/-- The GF48 candidate polynomial passes Rabin's irreducibility test. -/ +theorem definingPolynomial_irreducible : Irreducible definingPolynomial := + BinaryField.Extension.irreducible_of_rabin_48_passed_over_GF2 + definingPolynomial + (by simpa [extensionDegree] using definingPolynomial_natDegree) + X_pow_2_pow_48_add_X_dvd + rabin_gcd_condition_24 + rabin_gcd_condition_16 + +/-- Register the certified irreducibility fact for quotient-field instances. -/ +instance instIrreducibleDefiningPolynomial : Fact (Irreducible definingPolynomial) := + ⟨definingPolynomial_irreducible⟩ + +/-- Prime divisors of `fieldSize - 1` are exactly the certified prime factors. -/ +private lemma prime_dvd_fieldSize_sub_one_cases {p : Nat} + (hp : p.Prime) (hdvd : p ∣ fieldSize - 1) : + p = 3 ∨ p = 5 ∨ p = 7 ∨ p = 13 ∨ p = 17 ∨ p = 97 ∨ p = 241 ∨ p = 257 ∨ p = 673 := by + have hpdvd : p ∣ multiplicativeGroupOrder := by + simpa [multiplicativeGroupOrder, BinaryField.Extension.multiplicativeGroupOrder] using hdvd + rw [multiplicativeGroupOrder_factorization] at hpdvd + rcases hp.dvd_mul.mp hpdvd with hpdvd | h673 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h257 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h241 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h97 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h17 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h13 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h7 + · rcases hp.dvd_mul.mp hpdvd with h3pow | h5 + · left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 3)).mp + (hp.dvd_of_dvd_pow h3pow) + · right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 5)).mp + h5 + · right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 7)).mp + h7 + · right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 13)).mp + h13 + · right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 17)).mp + h17 + · right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 97)).mp + h97 + · right + right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 241)).mp + h241 + · right + right + right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 257)).mp + h257 + · right + right + right + right + right + right + right + right + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 673)).mp + h673 + +/-- Polynomial-basis generator used by smooth root contexts. -/ +def primitiveRoot : ConcreteField := + ConcreteField.root + +/-- The polynomial-basis generator is nonzero. -/ +theorem primitiveRoot_ne_zero : primitiveRoot ≠ (0 : ConcreteField) := by + unfold primitiveRoot ConcreteField.root BinaryField.Extension.Concrete.root + change BinaryField.Extension.Concrete.ofNat Concrete.params 2 ≠ + BinaryField.Extension.Concrete.zero Concrete.params + intro h + have hnat := congrArg (BinaryField.Extension.Concrete.toNat Concrete.params) h + rw [BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num)] at hnat + have hzero : + BinaryField.Extension.Concrete.toNat Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = 0 := by + unfold BinaryField.Extension.Concrete.zero + exact BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (n := 0) (by unfold Concrete.params extensionDegree; norm_num) + rw [hzero] at hnat + norm_num at hnat + +/-- The polynomial-basis generator has full multiplicative order. -/ +theorem primitiveRoot_order : orderOf primitiveRoot = fieldSize - 1 := by + let fieldInst : Field ConcreteField := ConcreteField.instFieldConcreteField + letI : Field ConcreteField := fieldInst + refine orderOf_eq_of_pow_and_pow_div_prime (n := fieldSize - 1) ?_ ?_ ?_ + · unfold fieldSize BinaryField.Extension.fieldSize extensionDegree + norm_num + · have hcard : Fintype.card ConcreteField = fieldSize := by + simpa [fieldSize] using ConcreteField.card + have hfermat := FiniteField.pow_card_sub_one_eq_one + (K := ConcreteField) primitiveRoot primitiveRoot_ne_zero + simpa [hcard] using hfermat + · intro p hp hdvd + rcases prime_dvd_fieldSize_sub_one_cases hp hdvd with + rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl | rfl + · simpa [primitiveRoot] using root_pow_div_3_ne_one + · simpa [primitiveRoot] using root_pow_div_5_ne_one + · simpa [primitiveRoot] using root_pow_div_7_ne_one + · simpa [primitiveRoot] using root_pow_div_13_ne_one + · simpa [primitiveRoot] using root_pow_div_17_ne_one + · simpa [primitiveRoot] using root_pow_div_97_ne_one + · simpa [primitiveRoot] using root_pow_div_241_ne_one + · simpa [primitiveRoot] using root_pow_div_257_ne_one + · simpa [primitiveRoot] using root_pow_div_673_ne_one + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_48/PrimitivePowerCertificate.lean b/CompPoly/Fields/Binary/GF2_48/PrimitivePowerCertificate.lean new file mode 100644 index 00000000..a0780648 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/PrimitivePowerCertificate.lean @@ -0,0 +1,537 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_48.Impl +import Mathlib.Tactic.NormNum + +/-! +# GF2^48 Primitive-Power Certificates + +Generated structural power-chain certificates for the polynomial-basis +root. These certify the nontrivial prime-divisor powers used to prove +that the root has full multiplicative order. +-/ + +namespace GF2_48 + +set_option maxRecDepth 50000 + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (5, 32), (10, 1024), (21, 2097152), (42, 4398046511104), + (85, 90297392431104), (170, 153168264577307), (341, 239113957168115), (682, 126119346275310), + (1365, 68118054016467), (2730, 85786808640717), (5461, 15575669117153), + (10922, 143347404838421), (21845, 172606321685184), (43690, 80831776680898), + (87381, 86622958655337), (174762, 232881539791740), (349525, 202935929788109), + (699050, 54870390925357), (1398101, 183260923738027), (2796202, 61567496953679), + (5592405, 79173554647435), (11184810, 269385973704121), (22369621, 137576615846835), + (44739242, 100924215630453), (89478485, 99039778605076), (178956970, 138550707487263), + (357913941, 15427885231210), (715827882, 217981134220997), (1431655765, 251730884502424), + (2863311530, 114970032252646), (5726623061, 80698868357301), (11453246122, 179165345868221), + (22906492245, 207849359609366), (45812984490, 34723303299245), (91625968981, 36041016527950), + (183251937962, 19641450941483), (366503875925, 189237286047101), + (733007751850, 154233819647710), (1466015503701, 169815596898641), + (2932031007402, 121176297650067), (5864062014805, 191984876758421), + (11728124029610, 166796011300363), (23456248059221, 247199318462005), + (46912496118442, 94075238128051), (93824992236885, 101580418639119)] + +/-- Residue of `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Residue : Nat := + 101580418639119 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 3) rootPowDiv3Chain rootPowDiv3Residue = true := by + rfl + +private theorem root_pow_div_3_certified : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue ∧ + rootPowDiv3Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 3) + (cert := rootPowDiv3Chain) (expected := rootPowDiv3Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_3_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_eq : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue := + root_pow_div_3_certified.1 + +/-- The `3`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_3_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 3) ≠ (1 : ConcreteField) := by + rw [root_pow_div_3_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv3Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv3Residue] using root_pow_div_3_certified.2) + (by unfold rootPowDiv3Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (6, 64), (12, 4096), (25, 33554432), (51, 5256), (102, 17842240), + (204, 1099780067985), (409, 5643621474306), (819, 96430950192256), (1638, 246469869353227), + (3276, 22053167914995), (6553, 134703828887893), (13107, 129640253166786), + (26214, 258761870046052), (52428, 186911430657782), (104857, 118792979732263), + (209715, 158518644506271), (419430, 215911181407254), (838860, 115629506514696), + (1677721, 120078505330877), (3355443, 70065354013493), (6710886, 18039512702409), + (13421772, 233607316320823), (26843545, 231901518996583), (53687091, 34110304840399), + (107374182, 94288478391335), (214748364, 204543569237387), (429496729, 235893740838106), + (858993459, 85630304092143), (1717986918, 226512346234361), (3435973836, 144315422935369), + (6871947673, 19628631989960), (13743895347, 191550654281559), (27487790694, 217758663924747), + (54975581388, 38489827985485), (109951162777, 28046756068182), (219902325555, 217987274961484), + (439804651110, 125796626944665), (879609302220, 245615824766069), + (1759218604441, 39497553457270), (3518437208883, 18166515285246), + (7036874417766, 233801619693878), (14073748835532, 279203897055231), + (28147497671065, 24213435108770), (56294995342131, 121637617569279)] + +/-- Residue of `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Residue : Nat := + 121637617569279 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 5) rootPowDiv5Chain rootPowDiv5Residue = true := by + rfl + +private theorem root_pow_div_5_certified : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue ∧ + rootPowDiv5Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 5) + (cert := rootPowDiv5Chain) (expected := rootPowDiv5Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_5_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_eq : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue := + root_pow_div_5_certified.1 + +/-- The `5`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_5_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 5) ≠ (1 : ConcreteField) := by + rw [root_pow_div_5_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv5Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv5Residue] using root_pow_div_5_certified.2) + (by unfold rootPowDiv5Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 7)`. -/ +def rootPowDiv7Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (9, 512), (18, 262144), (36, 68719476736), (73, 22045261824), + (146, 730549828), (292, 70665371580549), (585, 3276481702480), (1170, 82275195641793), + (2340, 262641432909245), (4681, 8367384970623), (9362, 36727545386192), (18724, 95619477462522), + (37449, 262800110579727), (74898, 163644114730423), (149796, 256850855091730), + (299593, 226941206178685), (599186, 143431298912077), (1198372, 12304234700128), + (2396745, 239388755334419), (4793490, 37643018696235), (9586980, 33316286093995), + (19173961, 4782933384524), (38347922, 45622856404625), (76695844, 253868309161983), + (153391689, 78805978789580), (306783378, 35453015546669), (613566756, 88068370847915), + (1227133513, 184884603787655), (2454267026, 180656635747994), (4908534052, 119266248636254), + (9817068105, 170333197127607), (19634136210, 64401606288898), (39268272420, 47225849691784), + (78536544841, 140374837168207), (157073089682, 88509217214948), (314146179364, 162882359309643), + (628292358729, 273487679720629), (1256584717458, 37297901438020), + (2513169434916, 72923599746298), (5026338869833, 22914149051736), + (10052677739666, 278776472013475), (20105355479332, 82952670984256), + (40210710958665, 92122832017475)] + +/-- Residue of `root ^ ((fieldSize - 1) / 7)`. -/ +def rootPowDiv7Residue : Nat := + 92122832017475 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 7)`. -/ +theorem root_pow_div_7_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 7) rootPowDiv7Chain rootPowDiv7Residue = true := by + rfl + +private theorem root_pow_div_7_certified : + ConcreteField.root ^ ((fieldSize - 1) / 7) = + ConcreteField.ofNat rootPowDiv7Residue ∧ + rootPowDiv7Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 7) + (cert := rootPowDiv7Chain) (expected := rootPowDiv7Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_7_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 7)`. -/ +theorem root_pow_div_7_eq : + ConcreteField.root ^ ((fieldSize - 1) / 7) = + ConcreteField.ofNat rootPowDiv7Residue := + root_pow_div_7_certified.1 + +/-- The `7`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_7_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 7) ≠ (1 : ConcreteField) := by + rw [root_pow_div_7_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv7Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv7Residue] using root_pow_div_7_certified.2) + (by unfold rootPowDiv7Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 13)`. -/ +def rootPowDiv13Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (9, 512), (19, 524288), (39, 549755813888), (78, 705448378368), + (157, 1496166047744), (315, 52209907031560), (630, 163485128753386), (1260, 273404014519891), + (2520, 41415108901841), (5041, 137266615548278), (10082, 28152253055264), + (20164, 60690029723555), (40329, 106760880792193), (80659, 146399995613956), + (161319, 102926423345762), (322638, 99450172705871), (645277, 92776042313788), + (1290555, 88975207756077), (2581110, 217238579388559), (5162220, 116972852988376), + (10324440, 258823563135506), (20648881, 265965013271647), (41297762, 144119733978644), + (82595524, 9379569031989), (165191049, 248261459756817), (330382099, 51201868472556), + (660764199, 158111427237095), (1321528398, 228804162913652), (2643056797, 35789625632615), + (5286113595, 37287086094932), (10572227190, 6629939730799), (21144454380, 42131216019856), + (42288908760, 109107314005418), (84577817521, 56867250300166), (169155635042, 225921276629404), + (338311270084, 223064276232716), (676622540169, 95717651322115), + (1353245080339, 214409264398509), (2706490160679, 194761820552120), + (5412980321358, 162290903296685), (10825960642717, 64626218883221), + (21651921285435, 93528367818650)] + +/-- Residue of `root ^ ((fieldSize - 1) / 13)`. -/ +def rootPowDiv13Residue : Nat := + 93528367818650 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 13)`. -/ +theorem root_pow_div_13_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 13) rootPowDiv13Chain rootPowDiv13Residue = true := by + rfl + +private theorem root_pow_div_13_certified : + ConcreteField.root ^ ((fieldSize - 1) / 13) = + ConcreteField.ofNat rootPowDiv13Residue ∧ + rootPowDiv13Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 13) + (cert := rootPowDiv13Chain) (expected := rootPowDiv13Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_13_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 13)`. -/ +theorem root_pow_div_13_eq : + ConcreteField.root ^ ((fieldSize - 1) / 13) = + ConcreteField.ofNat rootPowDiv13Residue := + root_pow_div_13_certified.1 + +/-- The `13`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_13_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 13) ≠ (1 : ConcreteField) := by + rw [root_pow_div_13_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv13Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv13Residue] using root_pow_div_13_certified.2) + (by unfold rootPowDiv13Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (7, 128), (15, 32768), (30, 1073741824), (60, 2691072), + (120, 4677236162560), (240, 45325101367953), (481, 78825126860111), (963, 257808250225490), + (1927, 137346191716309), (3855, 65446122679784), (7710, 49620820364440), + (15420, 240373327265903), (30840, 70245636929278), (61680, 93810842067848), + (123361, 279128825875845), (246723, 163375128126624), (493447, 241780583993789), + (986895, 132134602612446), (1973790, 106771955911093), (3947580, 24817350337730), + (7895160, 179991599648743), (15790320, 32064567349470), (31580641, 59052695360878), + (63161283, 93404791989633), (126322567, 135391122981295), (252645135, 127225952834146), + (505290270, 149778248921956), (1010580540, 269708456730673), (2021161080, 280005451069508), + (4042322160, 26107615066004), (8084644321, 108268330336639), (16169288643, 174145398047366), + (32338577287, 50872759621420), (64677154575, 42169890118085), (129354309150, 130271431394858), + (258708618300, 266516302632929), (517417236600, 227745986508421), + (1034834473200, 163664482617048), (2069668946401, 232808671277239), + (4139337892803, 170263705038701), (8278675785607, 131489751431172), + (16557351571215, 105996826927705)] + +/-- Residue of `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Residue : Nat := + 105996826927705 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 17) rootPowDiv17Chain rootPowDiv17Residue = true := by + rfl + +private theorem root_pow_div_17_certified : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue ∧ + rootPowDiv17Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 17) + (cert := rootPowDiv17Chain) (expected := rootPowDiv17Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_17_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_eq : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue := + root_pow_div_17_certified.1 + +/-- The `17`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_17_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 17) ≠ (1 : ConcreteField) := by + rw [root_pow_div_17_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv17Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv17Residue] using root_pow_div_17_certified.2) + (by unfold rootPowDiv17Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 97)`. -/ +def rootPowDiv97Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (5, 32), (10, 1024), (21, 2097152), (42, 4398046511104), + (84, 45148696215552), (168, 249398298677674), (337, 67721180456260), (675, 31771632970544), + (1351, 160034639044804), (2702, 144450920964371), (5405, 56951288155232), + (10810, 225436609020441), (21620, 246022787930717), (43240, 17631167540670), + (86480, 145430587562403), (172960, 45343731141541), (345921, 122123457612135), + (691843, 144745062986911), (1383687, 158728924284874), (2767375, 187418305352855), + (5534751, 233377707517317), (11069503, 267157925589607), (22139006, 175653402286977), + (44278013, 35399789981606), (88556026, 17905099681915), (177112053, 36118051354997), + (354224106, 6439006591086), (708448213, 241991237211680), (1416896427, 19996957273180), + (2833792855, 200236385714687), (5667585710, 266382709865277), (11335171420, 245364872495632), + (22670342840, 76483442030251), (45340685681, 103813662583544), (90681371362, 21384588760155), + (181362742725, 160441147996927), (362725485451, 50738510970421), (725450970903, 51251138592239), + (1450901941807, 52656619740269), (2901803883615, 141451938052813)] + +/-- Residue of `root ^ ((fieldSize - 1) / 97)`. -/ +def rootPowDiv97Residue : Nat := + 141451938052813 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 97)`. -/ +theorem root_pow_div_97_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 97) rootPowDiv97Chain rootPowDiv97Residue = true := by + rfl + +private theorem root_pow_div_97_certified : + ConcreteField.root ^ ((fieldSize - 1) / 97) = + ConcreteField.ofNat rootPowDiv97Residue ∧ + rootPowDiv97Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 97) + (cert := rootPowDiv97Chain) (expected := rootPowDiv97Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_97_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 97)`. -/ +theorem root_pow_div_97_eq : + ConcreteField.root ^ ((fieldSize - 1) / 97) = + ConcreteField.ofNat rootPowDiv97Residue := + root_pow_div_97_certified.1 + +/-- The `97`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_97_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 97) ≠ (1 : ConcreteField) := by + rw [root_pow_div_97_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv97Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv97Residue] using root_pow_div_97_certified.2) + (by unfold rootPowDiv97Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 241)`. -/ +def rootPowDiv241Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (8, 256), (16, 65536), (33, 8589934592), (67, 344457216), + (135, 141287244525600), (271, 142295118784968), (543, 146707456578880), (1087, 129085588640842), + (2175, 94304222573403), (4350, 262066767323791), (8701, 180830601058933), + (17403, 229528675566388), (34807, 153633219510341), (69615, 267116754424953), + (139230, 175672023904721), (278460, 23193596112087), (556920, 205434478303011), + (1113840, 64663449552888), (2227680, 51168180848473), (4455360, 218686688357226), + (8910720, 114156637382349), (17821441, 79814377066022), (35642882, 270426720254392), + (71285764, 263081917350165), (142571528, 163729440612390), (285143056, 277656597194823), + (570286113, 197263269948456), (1140572227, 57102817894851), (2281144455, 195743861958185), + (4562288911, 30798870074337), (9124577823, 196274495017836), (18249155647, 210428564687715), + (36498311295, 144923404912984), (72996622590, 80648881724916), (145993245181, 219886962402121), + (291986490363, 213308358474648), (583972980727, 30932552665530), + (1167945961455, 170101039684070)] + +/-- Residue of `root ^ ((fieldSize - 1) / 241)`. -/ +def rootPowDiv241Residue : Nat := + 170101039684070 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 241)`. -/ +theorem root_pow_div_241_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 241) rootPowDiv241Chain rootPowDiv241Residue = true := by + rfl + +private theorem root_pow_div_241_certified : + ConcreteField.root ^ ((fieldSize - 1) / 241) = + ConcreteField.ofNat rootPowDiv241Residue ∧ + rootPowDiv241Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 241) + (cert := rootPowDiv241Chain) (expected := rootPowDiv241Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_241_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 241)`. -/ +theorem root_pow_div_241_eq : + ConcreteField.root ^ ((fieldSize - 1) / 241) = + ConcreteField.ofNat rootPowDiv241Residue := + root_pow_div_241_certified.1 + +/-- The `241`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_241_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 241) ≠ (1 : ConcreteField) := by + rw [root_pow_div_241_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv241Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv241Residue] using root_pow_div_241_certified.2) + (by unfold rootPowDiv241Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 257)`. -/ +def rootPowDiv257Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (7, 128), (15, 32768), (31, 2147483648), (63, 21528576), + (127, 35736275387682), (255, 150944501902172), (510, 266893304808229), (1020, 224197440815428), + (2040, 190300878332045), (4080, 171265265718559), (8160, 118873039358802), + (16320, 221080466616902), (32640, 196274878469085), (65280, 153519777481257), + (130561, 132854211039473), (261123, 214645074412512), (522247, 168471309130256), + (1044495, 122255799173388), (2088991, 151258196137493), (4177983, 224639745914961), + (8355967, 170362051025673), (16711935, 140203517980204), (33423870, 22149350809009), + (66847740, 207048542309747), (133695480, 80787359482749), (267390960, 254680610974441), + (534781920, 39762856893667), (1069563840, 61623038660587), (2139127680, 105899874875736), + (4278255360, 70899523738755), (8556510721, 150499693688920), (17113021443, 116155302349785), + (34226042887, 110485280299679), (68452085775, 90615530287782), (136904171551, 66416804183559), + (273808343103, 194359622149394), (547616686207, 37084812156993), + (1095233372415, 154835689853052)] + +/-- Residue of `root ^ ((fieldSize - 1) / 257)`. -/ +def rootPowDiv257Residue : Nat := + 154835689853052 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 257)`. -/ +theorem root_pow_div_257_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 257) rootPowDiv257Chain rootPowDiv257Residue = true := by + rfl + +private theorem root_pow_div_257_certified : + ConcreteField.root ^ ((fieldSize - 1) / 257) = + ConcreteField.ofNat rootPowDiv257Residue ∧ + rootPowDiv257Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 257) + (cert := rootPowDiv257Chain) (expected := rootPowDiv257Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_257_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 257)`. -/ +theorem root_pow_div_257_eq : + ConcreteField.root ^ ((fieldSize - 1) / 257) = + ConcreteField.ofNat rootPowDiv257Residue := + root_pow_div_257_certified.1 + +/-- The `257`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_257_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 257) ≠ (1 : ConcreteField) := by + rw [root_pow_div_257_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv257Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv257Residue] using root_pow_div_257_certified.2) + (by unfold rootPowDiv257Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 673)`. -/ +def rootPowDiv673Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (6, 64), (12, 4096), (24, 16777216), (48, 657), (97, 557570), + (194, 275951910916), (389, 490168524832), (779, 37708044730368), (1558, 16758898680830), + (3116, 141321843072260), (6232, 88673711331296), (12464, 141486659320730), + (24928, 72223204541108), (49857, 15897856632058), (99715, 14205409967249), + (199431, 56244673534131), (398863, 29948425826977), (797727, 100857033517028), + (1595455, 231279147536700), (3190911, 209417934873285), (6381823, 183359765335384), + (12763647, 218871802943262), (25527294, 124003223520393), (51054588, 216161968472304), + (102109177, 230815027203736), (204218355, 13252978378981), (408436711, 27091015536921), + (816873423, 80636314690798), (1633746846, 249498523823977), (3267493693, 164442984598724), + (6534987386, 209395057117975), (13069974772, 78481257136120), (26139949545, 81114814604152), + (52279899091, 253550418637257), (104559798183, 255002750420036), (209119596367, 79230113247982), + (418239192735, 220465521204419)] + +/-- Residue of `root ^ ((fieldSize - 1) / 673)`. -/ +def rootPowDiv673Residue : Nat := + 220465521204419 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 673)`. -/ +theorem root_pow_div_673_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 673) rootPowDiv673Chain rootPowDiv673Residue = true := by + rfl + +private theorem root_pow_div_673_certified : + ConcreteField.root ^ ((fieldSize - 1) / 673) = + ConcreteField.ofNat rootPowDiv673Residue ∧ + rootPowDiv673Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 673) + (cert := rootPowDiv673Chain) (expected := rootPowDiv673Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_673_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 673)`. -/ +theorem root_pow_div_673_eq : + ConcreteField.root ^ ((fieldSize - 1) / 673) = + ConcreteField.ofNat rootPowDiv673Residue := + root_pow_div_673_certified.1 + +/-- The `673`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_673_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 673) ≠ (1 : ConcreteField) := by + rw [root_pow_div_673_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv673Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv673Residue] using root_pow_div_673_certified.2) + (by unfold rootPowDiv673Residue; norm_num) + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_48/RootContexts.lean b/CompPoly/Fields/Binary/GF2_48/RootContexts.lean new file mode 100644 index 00000000..62238cb0 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/RootContexts.lean @@ -0,0 +1,248 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_48.Primitive +import CompPoly.Fields.Binary.Extension.Enumeration +import CompPoly.Univariate.Roots.Context +import CompPoly.Univariate.Roots.Shoup.Basic +import CompPoly.Univariate.Roots.SmoothSubgroup +import Mathlib.FieldTheory.Finite.Trace + +/-! +# GF(2^48) Root-Search Contexts + +Certified finite-field context for the executable `GF(2^48)` carrier. +-/ + +namespace GF2_48 + +open CompPoly +open CompPoly.CPolynomial.Roots.FiniteField + +private theorem exists_basis_trace_ne {K L ι : Type*} [Field K] [Field L] [Algebra K L] + [FiniteDimensional K L] [Algebra.IsSeparable K L] + (b : Module.Basis ι K L) {x : L} (hx : x ≠ 0) : + ∃ i, Algebra.trace K L (b i * x) ≠ 0 := by + have hnd := (traceForm_nondegenerate K L).1 x + by_contra hnone + push Not at hnone + have hzero : (Algebra.traceForm K L) x = 0 := by + apply b.ext + intro i + rw [Algebra.traceForm_apply] + simpa [mul_comm] using hnone i + exact hx (hnd (by + intro y + rw [hzero] + rfl)) + +/-- Finite-field context for the executable `GF(2^48)` carrier. -/ +def finiteFieldContext : + CompPoly.CPolynomial.Roots.FiniteField.FiniteFieldContext ConcreteField where + q := fieldSize + finite := by infer_instance + card_eq := by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card + frobenius_fixed := by + intro a + have hcard : Fintype.card ConcreteField = fieldSize := by + exact ConcreteField.card + simpa [hcard] using FiniteField.pow_card a + +/-- Lazy complete enumeration for `GF(2^48)`. -/ +def fieldEnumeration : + CompPoly.CPolynomial.Roots.FiniteField.FieldEnumeration ConcreteField := + BinaryField.Extension.Concrete.fieldEnumeration Concrete.params + +namespace ConcreteField + +local instance fieldInst : Field ConcreteField := + instFieldConcreteField + +local instance commRingInst : CommRing ConcreteField := + fieldInst.toCommRing + +noncomputable local instance algebraInst : Algebra (ZMod 2) ConcreteField := + instAlgebraConcreteField + +/-- Algebraic trace value embedded back into executable `GF(2^48)`. -/ +noncomputable def algebraicTraceValue (z : ConcreteField) : ConcreteField := + algebraMap (ZMod 2) ConcreteField (Algebra.trace (ZMod 2) ConcreteField z) + +/-- The executable GF48 carrier has dimension `48` over `GF(2)`. -/ +theorem finrank_eq_extensionDegree : + Module.finrank (ZMod 2) ConcreteField = extensionDegree := by + have h := FiniteField.pow_finrank_eq_card (p := 2) (k := ConcreteField) + rw [card] at h + exact Nat.pow_right_injective (by norm_num : 1 < 2) h + +/-- The algebraic trace equals the Shoup Frobenius power sum. -/ +theorem algebraicTraceValue_eq_powerSum (z : ConcreteField) : + algebraicTraceValue z = tracePowerSum 2 extensionDegree z := by + unfold algebraicTraceValue + have htrace := FiniteField.algebraMap_trace_eq_sum_pow (ZMod 2) ConcreteField z + rw [finrank_eq_extensionDegree] at htrace + rw [htrace] + rw [tracePowerSum_eq_sum_range] + simp + +/-- The GF48 trace lands in the embedded `GF(2)` constants. -/ +theorem algebraicTraceValue_mem_base (z : ConcreteField) : + algebraicTraceValue z ∈ baseConstants.toList := by + unfold algebraicTraceValue baseConstants BinaryField.Extension.Concrete.baseConstants + let t : ZMod 2 := Algebra.trace (ZMod 2) ConcreteField z + change algebraMap (ZMod 2) ConcreteField t ∈ + [BinaryField.Extension.Concrete.zero Concrete.params, + BinaryField.Extension.Concrete.one Concrete.params] + have ht : ∀ u : ZMod 2, u = 0 ∨ u = 1 := by + intro u + fin_cases u + · left + rfl + · right + rfl + rcases ht t with ht0 | ht1 + · rw [ht0, map_zero] + left + · rw [ht1, map_one] + right + left + +/-- The transported quotient power basis for executable `GF(2^48)`. -/ +noncomputable def polynomialPowerBasis : PowerBasis (ZMod 2) ConcreteField := + (AdjoinRoot.powerBasis (BinaryField.Extension.polynomial_ne_zero definingPolynomialData)).map + toSpecAlgEquiv.symm + +@[simp] +theorem polynomialPowerBasis_dim_eq : + polynomialPowerBasis.dim = extensionDegree := by + simp [polynomialPowerBasis, BinaryField.Extension.polynomial_natDegree, + definingPolynomialData, extensionDegree] + +/-- The executable polynomial basis as a Lean basis. -/ +noncomputable def polynomialBasisBasis : + Module.Basis (Fin extensionDegree) (ZMod 2) ConcreteField := + polynomialPowerBasis.basis.reindex (finCongr polynomialPowerBasis_dim_eq) + +theorem polynomialBasisBasis_apply (i : Fin extensionDegree) : + polynomialBasisBasis i = root ^ i.val := by + unfold polynomialBasisBasis polynomialPowerBasis + rw [Module.Basis.reindex_apply] + change toSpecAlgEquiv.symm + (AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i)) = root ^ i.val + rw [show + AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i) = + (BinaryField.Extension.root definingPolynomialData) ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val by + simp [AdjoinRoot.powerBasisAux, BinaryField.Extension.root]] + rw [map_pow] + change toSpecAlgEquiv.symm GF2_48.root ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val = root ^ i.val + have hrootSymm : toSpecAlgEquiv.symm GF2_48.root = root := by + rw [AlgEquiv.symm_apply_eq] + exact toSpec_root.symm + rw [hrootSymm] + congr 1 + +/-- Each Lean polynomial-basis vector is present in the executable basis array. -/ +theorem polynomialBasisBasis_mem (i : Fin extensionDegree) : + polynomialBasisBasis i ∈ polynomialBasis.toList := by + rw [polynomialBasisBasis_apply] + rw [← Array.mem_def] + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis, Array.mem_ofFn] + exact ⟨i, rfl⟩ + +/-- The executable polynomial basis separates distinct elements by GF48 trace coordinates. -/ +theorem algebraicTraceValue_separates {a b : ConcreteField} (hne : a ≠ b) : + ∃ beta, beta ∈ polynomialBasis.toList ∧ algebraicTraceValue (beta * (a - b)) ≠ 0 := by + have hx : a - b ≠ 0 := sub_ne_zero.mpr hne + rcases exists_basis_trace_ne polynomialBasisBasis hx with ⟨i, htrace⟩ + refine ⟨polynomialBasisBasis i, polynomialBasisBasis_mem i, ?_⟩ + unfold algebraicTraceValue + intro hzero + apply htrace + have hz' : + algebraMap (ZMod 2) ConcreteField + (Algebra.trace (ZMod 2) ConcreteField (polynomialBasisBasis i * (a - b))) = + algebraMap (ZMod 2) ConcreteField 0 := by + rw [map_zero] + exact hzero + exact (FaithfulSMul.algebraMap_injective (ZMod 2) ConcreteField) hz' + +end ConcreteField + +/-- Shoup trace splitter context for `GF(2^48)`. -/ +def shoupTraceContext : + CPolynomial.Roots.FiniteField.SmallPrimeTraceContext ConcreteField where + toFiniteFieldContext := finiteFieldContext + p := 2 + k := extensionDegree + p_prime := Nat.prime_two + q_eq := by + simp [finiteFieldContext, fieldSize, BinaryField.Extension.fieldSize] + baseConstants := ConcreteField.baseConstants + baseConstants_size := ConcreteField.baseConstants_size + basis := ConcreteField.polynomialBasis + basis_size := ConcreteField.polynomialBasis_size + traceValue := tracePowerSum 2 extensionDegree + traceValue_eq_powerSum := fun _ ↦ rfl + traceValue_mem_base := by + intro z + rw [← ConcreteField.algebraicTraceValue_eq_powerSum] + exact ConcreteField.algebraicTraceValue_mem_base z + trace_separates := by + intro a b hne + rcases ConcreteField.algebraicTraceValue_separates hne with ⟨beta, hbeta, htrace⟩ + refine ⟨beta, hbeta, ?_⟩ + rwa [← ConcreteField.algebraicTraceValue_eq_powerSum] + +/-- Smooth cyclic splitter context for `GF(2^48)` with the supplied leaf evaluator. -/ +def smoothCyclicRootContextWith + (leafEvaluator : CPolynomial.BatchEvalContext ConcreteField) : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + CPolynomial.Roots.FiniteField.smoothCyclicRootContextOf + fieldSize + primitiveRoot + smoothRootSchedule + leafEvaluator + (CPolynomial.Roots.FiniteField.smoothSplitterInput + fieldSize primitiveRoot smoothRootSchedule) + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + smoothRootSchedule_fold_eq_one + (by + intro M D p factor h + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_sound + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule h) + (by + intro M D p a _hvalid hp hroot + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_complete + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + (by decide) + hp hroot) + +/-- Smooth cyclic splitter context for `GF(2^48)` using Horner leaf evaluation. -/ +def smoothHornerRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith (CPolynomial.BatchEvalContext.horner ConcreteField) + +/-- Smooth cyclic splitter context for `GF(2^48)` using subproduct-tree leaf evaluation. -/ +def smoothSubproductRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith + (CPolynomial.BatchEvalContext.subproduct ConcreteField + CPolynomial.MulContext.naive CPolynomial.ModContext.naive) + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_48/XPowTwoPowGcdCertificate.lean b/CompPoly/Fields/Binary/GF2_48/XPowTwoPowGcdCertificate.lean new file mode 100644 index 00000000..aa37c60c --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/XPowTwoPowGcdCertificate.lean @@ -0,0 +1,1051 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_48.XPowTwoPowModCertificate + +/-! +# GF(2^48) Rabin GCD Certificate + +Kernel-safe Euclidean-division certificates for the two Rabin gcd checks of +`X^48 + X^9 + X^7 + X^4 + 1`. +-/ + +namespace GF2_48 + +open Polynomial + +set_option maxRecDepth 1500 + +private abbrev B96 : Type := BitVec (2 * extensionDegree) + +def gcdPVal : B96 := BitVec.ofNat (2 * extensionDegree) 281474976711313 + +/-- Numeric 96-bit encoding of the GF48 defining polynomial. -/ +lemma definingPolynomial_eq_gcdPVal : + definingPolynomial = BinaryField.toPoly gcdPVal := by + rw [definingPolynomial_eq_P_val] + have h : P_val = gcdPVal := by + decide + rw [h] + +/-- Any GF48-width polynomial is already reduced modulo the defining polynomial. -/ +lemma toPoly_mod_definingPolynomial_eq_self (v : B48) : + BinaryField.toPoly v % definingPolynomial = BinaryField.toPoly v := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + exact BinaryField.toPoly_degree_lt_w + (w := extensionDegree) (h_w_pos := by unfold extensionDegree; omega) v + +/-- Soundness wrapper specialized to 96-bit Euclidean-division certificates. -/ +private theorem verify_div_step {a q b r : B96} + (h : BinaryField.Extension.checkDivStep (2 * extensionDegree) a q b r = true) : + BinaryField.toPoly a = BinaryField.toPoly q * BinaryField.toPoly b + + BinaryField.toPoly r := by + exact BinaryField.Extension.checkDivStep_correct a q b r h + +private theorem toPoly_ne_zero {v : B96} (h : v ≠ 0) : + BinaryField.toPoly v ≠ 0 := + (BinaryField.toPoly_ne_zero_iff_ne_zero v).mpr h + +/-- Initial Rabin gcd remainder for exponent `24`. -/ +def gcd24_b1Val : B96 := BitVec.ofNat (2 * extensionDegree) 221427043524971 + +lemma gcd24_b1Val_eq_zeroExtend : + gcd24_b1Val = BitVec.zeroExtend (2 * extensionDegree) (r24Val ^^^ r0Val) := by + decide + +def gcd24_a1Val : B96 := gcdPVal +def gcd24_q1Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r1Val : B96 := BitVec.ofNat (2 * extensionDegree) 100764241240364 + +def gcd24_a2Val : B96 := gcd24_b1Val +def gcd24_b2Val : B96 := gcd24_r1Val +def gcd24_q2Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r2Val : B96 := BitVec.ofNat (2 * extensionDegree) 41283243967007 + +def gcd24_a3Val : B96 := gcd24_b2Val +def gcd24_b3Val : B96 := gcd24_r2Val +def gcd24_q3Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r3Val : B96 := BitVec.ofNat (2 * extensionDegree) 18403983172882 + +def gcd24_a4Val : B96 := gcd24_b3Val +def gcd24_b4Val : B96 := gcd24_r3Val +def gcd24_q4Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r4Val : B96 := BitVec.ofNat (2 * extensionDegree) 5454689585211 + +def gcd24_a5Val : B96 := gcd24_b4Val +def gcd24_b5Val : B96 := gcd24_r4Val +def gcd24_q5Val : B96 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r5Val : B96 := BitVec.ofNat (2 * extensionDegree) 3732623721982 + +def gcd24_a6Val : B96 := gcd24_b5Val +def gcd24_b6Val : B96 := gcd24_r5Val +def gcd24_q6Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r6Val : B96 := BitVec.ofNat (2 * extensionDegree) 1482670720569 + +def gcd24_a7Val : B96 := gcd24_b6Val +def gcd24_b7Val : B96 := gcd24_r6Val +def gcd24_q7Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r7Val : B96 := BitVec.ofNat (2 * extensionDegree) 611154546613 + +def gcd24_a8Val : B96 := gcd24_b7Val +def gcd24_b8Val : B96 := gcd24_r7Val +def gcd24_q8Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r8Val : B96 := BitVec.ofNat (2 * extensionDegree) 299058288979 + +def gcd24_a9Val : B96 := gcd24_b8Val +def gcd24_b9Val : B96 := gcd24_r8Val +def gcd24_q9Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r9Val : B96 := BitVec.ofNat (2 * extensionDegree) 21627993363 + +def gcd24_a10Val : B96 := gcd24_b9Val +def gcd24_b10Val : B96 := gcd24_r9Val +def gcd24_q10Val : B96 := BitVec.ofNat (2 * extensionDegree) 20 +def gcd24_r10Val : B96 := BitVec.ofNat (2 * extensionDegree) 4694441007 + +def gcd24_a11Val : B96 := gcd24_b10Val +def gcd24_b11Val : B96 := gcd24_r10Val +def gcd24_q11Val : B96 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd24_r11Val : B96 := BitVec.ofNat (2 * extensionDegree) 1104310656 + +def gcd24_a12Val : B96 := gcd24_b11Val +def gcd24_b12Val : B96 := gcd24_r11Val +def gcd24_q12Val : B96 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r12Val : B96 := BitVec.ofNat (2 * extensionDegree) 277264943 + +def gcd24_a13Val : B96 := gcd24_b12Val +def gcd24_b13Val : B96 := gcd24_r12Val +def gcd24_q13Val : B96 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r13Val : B96 := BitVec.ofNat (2 * extensionDegree) 63478076 + +def gcd24_a14Val : B96 := gcd24_b13Val +def gcd24_b14Val : B96 := gcd24_r13Val +def gcd24_q14Val : B96 := BitVec.ofNat (2 * extensionDegree) 12 +def gcd24_r14Val : B96 := BitVec.ofNat (2 * extensionDegree) 31463231 + +def gcd24_a15Val : B96 := gcd24_b14Val +def gcd24_b15Val : B96 := gcd24_r14Val +def gcd24_q15Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r15Val : B96 := BitVec.ofNat (2 * extensionDegree) 571202 + +def gcd24_a16Val : B96 := gcd24_b15Val +def gcd24_b16Val : B96 := gcd24_r15Val +def gcd24_q16Val : B96 := BitVec.ofNat (2 * extensionDegree) 63 +def gcd24_r16Val : B96 := BitVec.ofNat (2 * extensionDegree) 210305 + +def gcd24_a17Val : B96 := gcd24_b16Val +def gcd24_b17Val : B96 := gcd24_r16Val +def gcd24_q17Val : B96 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd24_r17Val : B96 := BitVec.ofNat (2 * extensionDegree) 81861 + +def gcd24_a18Val : B96 := gcd24_b17Val +def gcd24_b18Val : B96 := gcd24_r17Val +def gcd24_q18Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r18Val : B96 := BitVec.ofNat (2 * extensionDegree) 30158 + +def gcd24_a19Val : B96 := gcd24_b18Val +def gcd24_b19Val : B96 := gcd24_r18Val +def gcd24_q19Val : B96 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd24_r19Val : B96 := BitVec.ofNat (2 * extensionDegree) 865 + +def gcd24_a20Val : B96 := gcd24_b19Val +def gcd24_b20Val : B96 := gcd24_r19Val +def gcd24_q20Val : B96 := BitVec.ofNat (2 * extensionDegree) 41 +def gcd24_r20Val : B96 := BitVec.ofNat (2 * extensionDegree) 391 + +def gcd24_a21Val : B96 := gcd24_b20Val +def gcd24_b21Val : B96 := gcd24_r20Val +def gcd24_q21Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r21Val : B96 := BitVec.ofNat (2 * extensionDegree) 111 + +def gcd24_a22Val : B96 := gcd24_b21Val +def gcd24_b22Val : B96 := gcd24_r21Val +def gcd24_q22Val : B96 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r22Val : B96 := BitVec.ofNat (2 * extensionDegree) 59 + +def gcd24_a23Val : B96 := gcd24_b22Val +def gcd24_b23Val : B96 := gcd24_r22Val +def gcd24_q23Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r23Val : B96 := BitVec.ofNat (2 * extensionDegree) 25 + +def gcd24_a24Val : B96 := gcd24_b23Val +def gcd24_b24Val : B96 := gcd24_r23Val +def gcd24_q24Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r24Val : B96 := BitVec.ofNat (2 * extensionDegree) 9 + +def gcd24_a25Val : B96 := gcd24_b24Val +def gcd24_b25Val : B96 := gcd24_r24Val +def gcd24_q25Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r25Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 + +def gcd24_a26Val : B96 := gcd24_b25Val +def gcd24_b26Val : B96 := gcd24_r25Val +def gcd24_q26Val : B96 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r26Val : B96 := BitVec.ofNat (2 * extensionDegree) 1 + +def gcd24_a27Val : B96 := gcd24_b26Val +def gcd24_b27Val : B96 := gcd24_r26Val +def gcd24_q27Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r27Val : B96 := BitVec.ofNat (2 * extensionDegree) 0 + +/-- Reduce the exponent `24` Rabin gcd to the generated Euclidean trace. -/ +lemma gcd24_start_reduction : + EuclideanDomain.gcd (X ^ (2 ^ 24) + X) definingPolynomial = + EuclideanDomain.gcd definingPolynomial (BinaryField.toPoly gcd24_b1Val) := by + rw [ZMod2Poly.euclidean_gcd_comm] + rw [EuclideanDomain.gcd_val] + conv_lhs => + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_24_mod_eq] + rw [r24] + rw [toPoly_mod_definingPolynomial_eq_self r24Val, X_mod_definingPolynomial] + rw [← r0_eq_X] + rw [r0] + rw [← BinaryField.toPoly_xor] + rw [toPoly_mod_definingPolynomial_eq_self (r24Val ^^^ r0Val)] + rw [← BinaryField.Extension.toPoly_zeroExtend + (show extensionDegree ≤ 2 * extensionDegree by unfold extensionDegree; norm_num) + (r24Val ^^^ r0Val)] + rw [← gcd24_b1Val_eq_zeroExtend] + rw [ZMod2Poly.euclidean_gcd_comm] + +lemma gcd24_step_1 : + BinaryField.toPoly gcd24_a1Val = + BinaryField.toPoly gcd24_q1Val * BinaryField.toPoly gcd24_b1Val + + BinaryField.toPoly gcd24_r1Val := by + exact verify_div_step (a := gcd24_a1Val) (q := gcd24_q1Val) + (b := gcd24_b1Val) (r := gcd24_r1Val) (by rfl) + +lemma gcd24_step_2 : + BinaryField.toPoly gcd24_a2Val = + BinaryField.toPoly gcd24_q2Val * BinaryField.toPoly gcd24_b2Val + + BinaryField.toPoly gcd24_r2Val := by + exact verify_div_step (a := gcd24_a2Val) (q := gcd24_q2Val) + (b := gcd24_b2Val) (r := gcd24_r2Val) (by rfl) + +lemma gcd24_step_3 : + BinaryField.toPoly gcd24_a3Val = + BinaryField.toPoly gcd24_q3Val * BinaryField.toPoly gcd24_b3Val + + BinaryField.toPoly gcd24_r3Val := by + exact verify_div_step (a := gcd24_a3Val) (q := gcd24_q3Val) + (b := gcd24_b3Val) (r := gcd24_r3Val) (by rfl) + +lemma gcd24_step_4 : + BinaryField.toPoly gcd24_a4Val = + BinaryField.toPoly gcd24_q4Val * BinaryField.toPoly gcd24_b4Val + + BinaryField.toPoly gcd24_r4Val := by + exact verify_div_step (a := gcd24_a4Val) (q := gcd24_q4Val) + (b := gcd24_b4Val) (r := gcd24_r4Val) (by rfl) + +lemma gcd24_step_5 : + BinaryField.toPoly gcd24_a5Val = + BinaryField.toPoly gcd24_q5Val * BinaryField.toPoly gcd24_b5Val + + BinaryField.toPoly gcd24_r5Val := by + exact verify_div_step (a := gcd24_a5Val) (q := gcd24_q5Val) + (b := gcd24_b5Val) (r := gcd24_r5Val) (by rfl) + +lemma gcd24_step_6 : + BinaryField.toPoly gcd24_a6Val = + BinaryField.toPoly gcd24_q6Val * BinaryField.toPoly gcd24_b6Val + + BinaryField.toPoly gcd24_r6Val := by + exact verify_div_step (a := gcd24_a6Val) (q := gcd24_q6Val) + (b := gcd24_b6Val) (r := gcd24_r6Val) (by rfl) + +lemma gcd24_step_7 : + BinaryField.toPoly gcd24_a7Val = + BinaryField.toPoly gcd24_q7Val * BinaryField.toPoly gcd24_b7Val + + BinaryField.toPoly gcd24_r7Val := by + exact verify_div_step (a := gcd24_a7Val) (q := gcd24_q7Val) + (b := gcd24_b7Val) (r := gcd24_r7Val) (by rfl) + +lemma gcd24_step_8 : + BinaryField.toPoly gcd24_a8Val = + BinaryField.toPoly gcd24_q8Val * BinaryField.toPoly gcd24_b8Val + + BinaryField.toPoly gcd24_r8Val := by + exact verify_div_step (a := gcd24_a8Val) (q := gcd24_q8Val) + (b := gcd24_b8Val) (r := gcd24_r8Val) (by rfl) + +lemma gcd24_step_9 : + BinaryField.toPoly gcd24_a9Val = + BinaryField.toPoly gcd24_q9Val * BinaryField.toPoly gcd24_b9Val + + BinaryField.toPoly gcd24_r9Val := by + exact verify_div_step (a := gcd24_a9Val) (q := gcd24_q9Val) + (b := gcd24_b9Val) (r := gcd24_r9Val) (by rfl) + +lemma gcd24_step_10 : + BinaryField.toPoly gcd24_a10Val = + BinaryField.toPoly gcd24_q10Val * BinaryField.toPoly gcd24_b10Val + + BinaryField.toPoly gcd24_r10Val := by + exact verify_div_step (a := gcd24_a10Val) (q := gcd24_q10Val) + (b := gcd24_b10Val) (r := gcd24_r10Val) (by rfl) + +lemma gcd24_step_11 : + BinaryField.toPoly gcd24_a11Val = + BinaryField.toPoly gcd24_q11Val * BinaryField.toPoly gcd24_b11Val + + BinaryField.toPoly gcd24_r11Val := by + exact verify_div_step (a := gcd24_a11Val) (q := gcd24_q11Val) + (b := gcd24_b11Val) (r := gcd24_r11Val) (by rfl) + +lemma gcd24_step_12 : + BinaryField.toPoly gcd24_a12Val = + BinaryField.toPoly gcd24_q12Val * BinaryField.toPoly gcd24_b12Val + + BinaryField.toPoly gcd24_r12Val := by + exact verify_div_step (a := gcd24_a12Val) (q := gcd24_q12Val) + (b := gcd24_b12Val) (r := gcd24_r12Val) (by rfl) + +lemma gcd24_step_13 : + BinaryField.toPoly gcd24_a13Val = + BinaryField.toPoly gcd24_q13Val * BinaryField.toPoly gcd24_b13Val + + BinaryField.toPoly gcd24_r13Val := by + exact verify_div_step (a := gcd24_a13Val) (q := gcd24_q13Val) + (b := gcd24_b13Val) (r := gcd24_r13Val) (by rfl) + +lemma gcd24_step_14 : + BinaryField.toPoly gcd24_a14Val = + BinaryField.toPoly gcd24_q14Val * BinaryField.toPoly gcd24_b14Val + + BinaryField.toPoly gcd24_r14Val := by + exact verify_div_step (a := gcd24_a14Val) (q := gcd24_q14Val) + (b := gcd24_b14Val) (r := gcd24_r14Val) (by rfl) + +lemma gcd24_step_15 : + BinaryField.toPoly gcd24_a15Val = + BinaryField.toPoly gcd24_q15Val * BinaryField.toPoly gcd24_b15Val + + BinaryField.toPoly gcd24_r15Val := by + exact verify_div_step (a := gcd24_a15Val) (q := gcd24_q15Val) + (b := gcd24_b15Val) (r := gcd24_r15Val) (by rfl) + +lemma gcd24_step_16 : + BinaryField.toPoly gcd24_a16Val = + BinaryField.toPoly gcd24_q16Val * BinaryField.toPoly gcd24_b16Val + + BinaryField.toPoly gcd24_r16Val := by + exact verify_div_step (a := gcd24_a16Val) (q := gcd24_q16Val) + (b := gcd24_b16Val) (r := gcd24_r16Val) (by rfl) + +lemma gcd24_step_17 : + BinaryField.toPoly gcd24_a17Val = + BinaryField.toPoly gcd24_q17Val * BinaryField.toPoly gcd24_b17Val + + BinaryField.toPoly gcd24_r17Val := by + exact verify_div_step (a := gcd24_a17Val) (q := gcd24_q17Val) + (b := gcd24_b17Val) (r := gcd24_r17Val) (by rfl) + +lemma gcd24_step_18 : + BinaryField.toPoly gcd24_a18Val = + BinaryField.toPoly gcd24_q18Val * BinaryField.toPoly gcd24_b18Val + + BinaryField.toPoly gcd24_r18Val := by + exact verify_div_step (a := gcd24_a18Val) (q := gcd24_q18Val) + (b := gcd24_b18Val) (r := gcd24_r18Val) (by rfl) + +lemma gcd24_step_19 : + BinaryField.toPoly gcd24_a19Val = + BinaryField.toPoly gcd24_q19Val * BinaryField.toPoly gcd24_b19Val + + BinaryField.toPoly gcd24_r19Val := by + exact verify_div_step (a := gcd24_a19Val) (q := gcd24_q19Val) + (b := gcd24_b19Val) (r := gcd24_r19Val) (by rfl) + +lemma gcd24_step_20 : + BinaryField.toPoly gcd24_a20Val = + BinaryField.toPoly gcd24_q20Val * BinaryField.toPoly gcd24_b20Val + + BinaryField.toPoly gcd24_r20Val := by + exact verify_div_step (a := gcd24_a20Val) (q := gcd24_q20Val) + (b := gcd24_b20Val) (r := gcd24_r20Val) (by rfl) + +lemma gcd24_step_21 : + BinaryField.toPoly gcd24_a21Val = + BinaryField.toPoly gcd24_q21Val * BinaryField.toPoly gcd24_b21Val + + BinaryField.toPoly gcd24_r21Val := by + exact verify_div_step (a := gcd24_a21Val) (q := gcd24_q21Val) + (b := gcd24_b21Val) (r := gcd24_r21Val) (by rfl) + +lemma gcd24_step_22 : + BinaryField.toPoly gcd24_a22Val = + BinaryField.toPoly gcd24_q22Val * BinaryField.toPoly gcd24_b22Val + + BinaryField.toPoly gcd24_r22Val := by + exact verify_div_step (a := gcd24_a22Val) (q := gcd24_q22Val) + (b := gcd24_b22Val) (r := gcd24_r22Val) (by rfl) + +lemma gcd24_step_23 : + BinaryField.toPoly gcd24_a23Val = + BinaryField.toPoly gcd24_q23Val * BinaryField.toPoly gcd24_b23Val + + BinaryField.toPoly gcd24_r23Val := by + exact verify_div_step (a := gcd24_a23Val) (q := gcd24_q23Val) + (b := gcd24_b23Val) (r := gcd24_r23Val) (by rfl) + +lemma gcd24_step_24 : + BinaryField.toPoly gcd24_a24Val = + BinaryField.toPoly gcd24_q24Val * BinaryField.toPoly gcd24_b24Val + + BinaryField.toPoly gcd24_r24Val := by + exact verify_div_step (a := gcd24_a24Val) (q := gcd24_q24Val) + (b := gcd24_b24Val) (r := gcd24_r24Val) (by rfl) + +lemma gcd24_step_25 : + BinaryField.toPoly gcd24_a25Val = + BinaryField.toPoly gcd24_q25Val * BinaryField.toPoly gcd24_b25Val + + BinaryField.toPoly gcd24_r25Val := by + exact verify_div_step (a := gcd24_a25Val) (q := gcd24_q25Val) + (b := gcd24_b25Val) (r := gcd24_r25Val) (by rfl) + +lemma gcd24_step_26 : + BinaryField.toPoly gcd24_a26Val = + BinaryField.toPoly gcd24_q26Val * BinaryField.toPoly gcd24_b26Val + + BinaryField.toPoly gcd24_r26Val := by + exact verify_div_step (a := gcd24_a26Val) (q := gcd24_q26Val) + (b := gcd24_b26Val) (r := gcd24_r26Val) (by rfl) + +lemma gcd24_step_27 : + BinaryField.toPoly gcd24_a27Val = + BinaryField.toPoly gcd24_q27Val * BinaryField.toPoly gcd24_b27Val + + BinaryField.toPoly gcd24_r27Val := by + exact verify_div_step (a := gcd24_a27Val) (q := gcd24_q27Val) + (b := gcd24_b27Val) (r := gcd24_r27Val) (by rfl) + +/-- Rabin gcd condition for exponent `24`. -/ +lemma rabin_gcd_condition_24 : + EuclideanDomain.gcd (X ^ (2 ^ 24) + X) definingPolynomial = 1 := by + rw [gcd24_start_reduction] + rw [definingPolynomial_eq_gcdPVal] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a1Val) + (BinaryField.toPoly gcd24_b1Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b1Val) (by decide)) + gcd24_step_1] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a2Val) + (BinaryField.toPoly gcd24_b2Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b2Val) (by decide)) + gcd24_step_2] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a3Val) + (BinaryField.toPoly gcd24_b3Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b3Val) (by decide)) + gcd24_step_3] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a4Val) + (BinaryField.toPoly gcd24_b4Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b4Val) (by decide)) + gcd24_step_4] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a5Val) + (BinaryField.toPoly gcd24_b5Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b5Val) (by decide)) + gcd24_step_5] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a6Val) + (BinaryField.toPoly gcd24_b6Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b6Val) (by decide)) + gcd24_step_6] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a7Val) + (BinaryField.toPoly gcd24_b7Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b7Val) (by decide)) + gcd24_step_7] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a8Val) + (BinaryField.toPoly gcd24_b8Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b8Val) (by decide)) + gcd24_step_8] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a9Val) + (BinaryField.toPoly gcd24_b9Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b9Val) (by decide)) + gcd24_step_9] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a10Val) + (BinaryField.toPoly gcd24_b10Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b10Val) (by decide)) + gcd24_step_10] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a11Val) + (BinaryField.toPoly gcd24_b11Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b11Val) (by decide)) + gcd24_step_11] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a12Val) + (BinaryField.toPoly gcd24_b12Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b12Val) (by decide)) + gcd24_step_12] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a13Val) + (BinaryField.toPoly gcd24_b13Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b13Val) (by decide)) + gcd24_step_13] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a14Val) + (BinaryField.toPoly gcd24_b14Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b14Val) (by decide)) + gcd24_step_14] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a15Val) + (BinaryField.toPoly gcd24_b15Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b15Val) (by decide)) + gcd24_step_15] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a16Val) + (BinaryField.toPoly gcd24_b16Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b16Val) (by decide)) + gcd24_step_16] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a17Val) + (BinaryField.toPoly gcd24_b17Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b17Val) (by decide)) + gcd24_step_17] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a18Val) + (BinaryField.toPoly gcd24_b18Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b18Val) (by decide)) + gcd24_step_18] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a19Val) + (BinaryField.toPoly gcd24_b19Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b19Val) (by decide)) + gcd24_step_19] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a20Val) + (BinaryField.toPoly gcd24_b20Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b20Val) (by decide)) + gcd24_step_20] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a21Val) + (BinaryField.toPoly gcd24_b21Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b21Val) (by decide)) + gcd24_step_21] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a22Val) + (BinaryField.toPoly gcd24_b22Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b22Val) (by decide)) + gcd24_step_22] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a23Val) + (BinaryField.toPoly gcd24_b23Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b23Val) (by decide)) + gcd24_step_23] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a24Val) + (BinaryField.toPoly gcd24_b24Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b24Val) (by decide)) + gcd24_step_24] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a25Val) + (BinaryField.toPoly gcd24_b25Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b25Val) (by decide)) + gcd24_step_25] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a26Val) + (BinaryField.toPoly gcd24_b26Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b26Val) (by decide)) + gcd24_step_26] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a27Val) + (BinaryField.toPoly gcd24_b27Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b27Val) (by decide)) + gcd24_step_27] + change EuclideanDomain.gcd + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 1 : B96)) + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 0 : B96)) = 1 + rw [BinaryField.toPoly_one_eq_one + (w := 2 * extensionDegree) (h_w_pos := by unfold extensionDegree; omega)] + rw [BinaryField.toPoly_zero_eq_zero] + exact BinaryField.gcd_one_zero + +/-- Initial Rabin gcd remainder for exponent `16`. -/ +def gcd16_b1Val : B96 := BitVec.ofNat (2 * extensionDegree) 197658536369218 + +lemma gcd16_b1Val_eq_zeroExtend : + gcd16_b1Val = BitVec.zeroExtend (2 * extensionDegree) (r16Val ^^^ r0Val) := by + decide + +def gcd16_a1Val : B96 := gcdPVal +def gcd16_q1Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r1Val : B96 := BitVec.ofNat (2 * extensionDegree) 113842096028181 + +def gcd16_a2Val : B96 := gcd16_b1Val +def gcd16_b2Val : B96 := gcd16_r1Val +def gcd16_q2Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r2Val : B96 := BitVec.ofNat (2 * extensionDegree) 30093762761341 + +def gcd16_a3Val : B96 := gcd16_b2Val +def gcd16_b3Val : B96 := gcd16_r2Val +def gcd16_q3Val : B96 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd16_r3Val : B96 := BitVec.ofNat (2 * extensionDegree) 12038484653025 + +def gcd16_a4Val : B96 := gcd16_b3Val +def gcd16_b4Val : B96 := gcd16_r3Val +def gcd16_q4Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r4Val : B96 := BitVec.ofNat (2 * extensionDegree) 4715716806238 + +def gcd16_a5Val : B96 := gcd16_b4Val +def gcd16_b5Val : B96 := gcd16_r4Val +def gcd16_q5Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r5Val : B96 := BitVec.ofNat (2 * extensionDegree) 2615649369949 + +def gcd16_a6Val : B96 := gcd16_b5Val +def gcd16_b6Val : B96 := gcd16_r5Val +def gcd16_q6Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r6Val : B96 := BitVec.ofNat (2 * extensionDegree) 601145735396 + +def gcd16_a7Val : B96 := gcd16_b6Val +def gcd16_b7Val : B96 := gcd16_r6Val +def gcd16_q7Val : B96 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd16_r7Val : B96 := BitVec.ofNat (2 * extensionDegree) 338708274381 + +def gcd16_a8Val : B96 := gcd16_b7Val +def gcd16_b8Val : B96 := gcd16_r7Val +def gcd16_q8Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r8Val : B96 := BitVec.ofNat (2 * extensionDegree) 95802081662 + +def gcd16_a9Val : B96 := gcd16_b8Val +def gcd16_b9Val : B96 := gcd16_r8Val +def gcd16_q9Val : B96 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd16_r9Val : B96 := BitVec.ofNat (2 * extensionDegree) 7152785483 + +def gcd16_a10Val : B96 := gcd16_b9Val +def gcd16_b10Val : B96 := gcd16_r9Val +def gcd16_q10Val : B96 := BitVec.ofNat (2 * extensionDegree) 25 +def gcd16_r10Val : B96 := BitVec.ofNat (2 * extensionDegree) 330457053 + +def gcd16_a11Val : B96 := gcd16_b10Val +def gcd16_b11Val : B96 := gcd16_r10Val +def gcd16_q11Val : B96 := BitVec.ofNat (2 * extensionDegree) 24 +def gcd16_r11Val : B96 := BitVec.ofNat (2 * extensionDegree) 216128371 + +def gcd16_a12Val : B96 := gcd16_b11Val +def gcd16_b12Val : B96 := gcd16_r11Val +def gcd16_q12Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r12Val : B96 := BitVec.ofNat (2 * extensionDegree) 110113352 + +def gcd16_a13Val : B96 := gcd16_b12Val +def gcd16_b13Val : B96 := gcd16_r12Val +def gcd16_q13Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r13Val : B96 := BitVec.ofNat (2 * extensionDegree) 29474787 + +def gcd16_a14Val : B96 := gcd16_b13Val +def gcd16_b14Val : B96 := gcd16_r13Val +def gcd16_q14Val : B96 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd16_r14Val : B96 := BitVec.ofNat (2 * extensionDegree) 5730855 + +def gcd16_a15Val : B96 := gcd16_b14Val +def gcd16_b15Val : B96 := gcd16_r14Val +def gcd16_q15Val : B96 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd16_r15Val : B96 := BitVec.ofNat (2 * extensionDegree) 3314481 + +def gcd16_a16Val : B96 := gcd16_b15Val +def gcd16_b16Val : B96 := gcd16_r15Val +def gcd16_q16Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r16Val : B96 := BitVec.ofNat (2 * extensionDegree) 51060 + +def gcd16_a17Val : B96 := gcd16_b16Val +def gcd16_b17Val : B96 := gcd16_r16Val +def gcd16_q17Val : B96 := BitVec.ofNat (2 * extensionDegree) 68 +def gcd16_r17Val : B96 := BitVec.ofNat (2 * extensionDegree) 21473 + +def gcd16_a18Val : B96 := gcd16_b17Val +def gcd16_b18Val : B96 := gcd16_r17Val +def gcd16_q18Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r18Val : B96 := BitVec.ofNat (2 * extensionDegree) 13143 + +def gcd16_a19Val : B96 := gcd16_b18Val +def gcd16_b19Val : B96 := gcd16_r18Val +def gcd16_q19Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r19Val : B96 := BitVec.ofNat (2 * extensionDegree) 1560 + +def gcd16_a20Val : B96 := gcd16_b19Val +def gcd16_b20Val : B96 := gcd16_r19Val +def gcd16_q20Val : B96 := BitVec.ofNat (2 * extensionDegree) 8 +def gcd16_r20Val : B96 := BitVec.ofNat (2 * extensionDegree) 919 + +def gcd16_a21Val : B96 := gcd16_b20Val +def gcd16_b21Val : B96 := gcd16_r20Val +def gcd16_q21Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r21Val : B96 := BitVec.ofNat (2 * extensionDegree) 310 + +def gcd16_a22Val : B96 := gcd16_b21Val +def gcd16_b22Val : B96 := gcd16_r21Val +def gcd16_q22Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r22Val : B96 := BitVec.ofNat (2 * extensionDegree) 205 + +def gcd16_a23Val : B96 := gcd16_b22Val +def gcd16_b23Val : B96 := gcd16_r22Val +def gcd16_q23Val : B96 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd16_r23Val : B96 := BitVec.ofNat (2 * extensionDegree) 97 + +def gcd16_a24Val : B96 := gcd16_b23Val +def gcd16_b24Val : B96 := gcd16_r23Val +def gcd16_q24Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r24Val : B96 := BitVec.ofNat (2 * extensionDegree) 15 + +def gcd16_a25Val : B96 := gcd16_b24Val +def gcd16_b25Val : B96 := gcd16_r24Val +def gcd16_q25Val : B96 := BitVec.ofNat (2 * extensionDegree) 10 +def gcd16_r25Val : B96 := BitVec.ofNat (2 * extensionDegree) 7 + +def gcd16_a26Val : B96 := gcd16_b25Val +def gcd16_b26Val : B96 := gcd16_r25Val +def gcd16_q26Val : B96 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd16_r26Val : B96 := BitVec.ofNat (2 * extensionDegree) 1 + +def gcd16_a27Val : B96 := gcd16_b26Val +def gcd16_b27Val : B96 := gcd16_r26Val +def gcd16_q27Val : B96 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd16_r27Val : B96 := BitVec.ofNat (2 * extensionDegree) 0 + +/-- Reduce the exponent `16` Rabin gcd to the generated Euclidean trace. -/ +lemma gcd16_start_reduction : + EuclideanDomain.gcd (X ^ (2 ^ 16) + X) definingPolynomial = + EuclideanDomain.gcd definingPolynomial (BinaryField.toPoly gcd16_b1Val) := by + rw [ZMod2Poly.euclidean_gcd_comm] + rw [EuclideanDomain.gcd_val] + conv_lhs => + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_16_mod_eq] + rw [r16] + rw [toPoly_mod_definingPolynomial_eq_self r16Val, X_mod_definingPolynomial] + rw [← r0_eq_X] + rw [r0] + rw [← BinaryField.toPoly_xor] + rw [toPoly_mod_definingPolynomial_eq_self (r16Val ^^^ r0Val)] + rw [← BinaryField.Extension.toPoly_zeroExtend + (show extensionDegree ≤ 2 * extensionDegree by unfold extensionDegree; norm_num) + (r16Val ^^^ r0Val)] + rw [← gcd16_b1Val_eq_zeroExtend] + rw [ZMod2Poly.euclidean_gcd_comm] + +lemma gcd16_step_1 : + BinaryField.toPoly gcd16_a1Val = + BinaryField.toPoly gcd16_q1Val * BinaryField.toPoly gcd16_b1Val + + BinaryField.toPoly gcd16_r1Val := by + exact verify_div_step (a := gcd16_a1Val) (q := gcd16_q1Val) + (b := gcd16_b1Val) (r := gcd16_r1Val) (by rfl) + +lemma gcd16_step_2 : + BinaryField.toPoly gcd16_a2Val = + BinaryField.toPoly gcd16_q2Val * BinaryField.toPoly gcd16_b2Val + + BinaryField.toPoly gcd16_r2Val := by + exact verify_div_step (a := gcd16_a2Val) (q := gcd16_q2Val) + (b := gcd16_b2Val) (r := gcd16_r2Val) (by rfl) + +lemma gcd16_step_3 : + BinaryField.toPoly gcd16_a3Val = + BinaryField.toPoly gcd16_q3Val * BinaryField.toPoly gcd16_b3Val + + BinaryField.toPoly gcd16_r3Val := by + exact verify_div_step (a := gcd16_a3Val) (q := gcd16_q3Val) + (b := gcd16_b3Val) (r := gcd16_r3Val) (by rfl) + +lemma gcd16_step_4 : + BinaryField.toPoly gcd16_a4Val = + BinaryField.toPoly gcd16_q4Val * BinaryField.toPoly gcd16_b4Val + + BinaryField.toPoly gcd16_r4Val := by + exact verify_div_step (a := gcd16_a4Val) (q := gcd16_q4Val) + (b := gcd16_b4Val) (r := gcd16_r4Val) (by rfl) + +lemma gcd16_step_5 : + BinaryField.toPoly gcd16_a5Val = + BinaryField.toPoly gcd16_q5Val * BinaryField.toPoly gcd16_b5Val + + BinaryField.toPoly gcd16_r5Val := by + exact verify_div_step (a := gcd16_a5Val) (q := gcd16_q5Val) + (b := gcd16_b5Val) (r := gcd16_r5Val) (by rfl) + +lemma gcd16_step_6 : + BinaryField.toPoly gcd16_a6Val = + BinaryField.toPoly gcd16_q6Val * BinaryField.toPoly gcd16_b6Val + + BinaryField.toPoly gcd16_r6Val := by + exact verify_div_step (a := gcd16_a6Val) (q := gcd16_q6Val) + (b := gcd16_b6Val) (r := gcd16_r6Val) (by rfl) + +lemma gcd16_step_7 : + BinaryField.toPoly gcd16_a7Val = + BinaryField.toPoly gcd16_q7Val * BinaryField.toPoly gcd16_b7Val + + BinaryField.toPoly gcd16_r7Val := by + exact verify_div_step (a := gcd16_a7Val) (q := gcd16_q7Val) + (b := gcd16_b7Val) (r := gcd16_r7Val) (by rfl) + +lemma gcd16_step_8 : + BinaryField.toPoly gcd16_a8Val = + BinaryField.toPoly gcd16_q8Val * BinaryField.toPoly gcd16_b8Val + + BinaryField.toPoly gcd16_r8Val := by + exact verify_div_step (a := gcd16_a8Val) (q := gcd16_q8Val) + (b := gcd16_b8Val) (r := gcd16_r8Val) (by rfl) + +lemma gcd16_step_9 : + BinaryField.toPoly gcd16_a9Val = + BinaryField.toPoly gcd16_q9Val * BinaryField.toPoly gcd16_b9Val + + BinaryField.toPoly gcd16_r9Val := by + exact verify_div_step (a := gcd16_a9Val) (q := gcd16_q9Val) + (b := gcd16_b9Val) (r := gcd16_r9Val) (by rfl) + +lemma gcd16_step_10 : + BinaryField.toPoly gcd16_a10Val = + BinaryField.toPoly gcd16_q10Val * BinaryField.toPoly gcd16_b10Val + + BinaryField.toPoly gcd16_r10Val := by + exact verify_div_step (a := gcd16_a10Val) (q := gcd16_q10Val) + (b := gcd16_b10Val) (r := gcd16_r10Val) (by rfl) + +lemma gcd16_step_11 : + BinaryField.toPoly gcd16_a11Val = + BinaryField.toPoly gcd16_q11Val * BinaryField.toPoly gcd16_b11Val + + BinaryField.toPoly gcd16_r11Val := by + exact verify_div_step (a := gcd16_a11Val) (q := gcd16_q11Val) + (b := gcd16_b11Val) (r := gcd16_r11Val) (by rfl) + +lemma gcd16_step_12 : + BinaryField.toPoly gcd16_a12Val = + BinaryField.toPoly gcd16_q12Val * BinaryField.toPoly gcd16_b12Val + + BinaryField.toPoly gcd16_r12Val := by + exact verify_div_step (a := gcd16_a12Val) (q := gcd16_q12Val) + (b := gcd16_b12Val) (r := gcd16_r12Val) (by rfl) + +lemma gcd16_step_13 : + BinaryField.toPoly gcd16_a13Val = + BinaryField.toPoly gcd16_q13Val * BinaryField.toPoly gcd16_b13Val + + BinaryField.toPoly gcd16_r13Val := by + exact verify_div_step (a := gcd16_a13Val) (q := gcd16_q13Val) + (b := gcd16_b13Val) (r := gcd16_r13Val) (by rfl) + +lemma gcd16_step_14 : + BinaryField.toPoly gcd16_a14Val = + BinaryField.toPoly gcd16_q14Val * BinaryField.toPoly gcd16_b14Val + + BinaryField.toPoly gcd16_r14Val := by + exact verify_div_step (a := gcd16_a14Val) (q := gcd16_q14Val) + (b := gcd16_b14Val) (r := gcd16_r14Val) (by rfl) + +lemma gcd16_step_15 : + BinaryField.toPoly gcd16_a15Val = + BinaryField.toPoly gcd16_q15Val * BinaryField.toPoly gcd16_b15Val + + BinaryField.toPoly gcd16_r15Val := by + exact verify_div_step (a := gcd16_a15Val) (q := gcd16_q15Val) + (b := gcd16_b15Val) (r := gcd16_r15Val) (by rfl) + +lemma gcd16_step_16 : + BinaryField.toPoly gcd16_a16Val = + BinaryField.toPoly gcd16_q16Val * BinaryField.toPoly gcd16_b16Val + + BinaryField.toPoly gcd16_r16Val := by + exact verify_div_step (a := gcd16_a16Val) (q := gcd16_q16Val) + (b := gcd16_b16Val) (r := gcd16_r16Val) (by rfl) + +lemma gcd16_step_17 : + BinaryField.toPoly gcd16_a17Val = + BinaryField.toPoly gcd16_q17Val * BinaryField.toPoly gcd16_b17Val + + BinaryField.toPoly gcd16_r17Val := by + exact verify_div_step (a := gcd16_a17Val) (q := gcd16_q17Val) + (b := gcd16_b17Val) (r := gcd16_r17Val) (by rfl) + +lemma gcd16_step_18 : + BinaryField.toPoly gcd16_a18Val = + BinaryField.toPoly gcd16_q18Val * BinaryField.toPoly gcd16_b18Val + + BinaryField.toPoly gcd16_r18Val := by + exact verify_div_step (a := gcd16_a18Val) (q := gcd16_q18Val) + (b := gcd16_b18Val) (r := gcd16_r18Val) (by rfl) + +lemma gcd16_step_19 : + BinaryField.toPoly gcd16_a19Val = + BinaryField.toPoly gcd16_q19Val * BinaryField.toPoly gcd16_b19Val + + BinaryField.toPoly gcd16_r19Val := by + exact verify_div_step (a := gcd16_a19Val) (q := gcd16_q19Val) + (b := gcd16_b19Val) (r := gcd16_r19Val) (by rfl) + +lemma gcd16_step_20 : + BinaryField.toPoly gcd16_a20Val = + BinaryField.toPoly gcd16_q20Val * BinaryField.toPoly gcd16_b20Val + + BinaryField.toPoly gcd16_r20Val := by + exact verify_div_step (a := gcd16_a20Val) (q := gcd16_q20Val) + (b := gcd16_b20Val) (r := gcd16_r20Val) (by rfl) + +lemma gcd16_step_21 : + BinaryField.toPoly gcd16_a21Val = + BinaryField.toPoly gcd16_q21Val * BinaryField.toPoly gcd16_b21Val + + BinaryField.toPoly gcd16_r21Val := by + exact verify_div_step (a := gcd16_a21Val) (q := gcd16_q21Val) + (b := gcd16_b21Val) (r := gcd16_r21Val) (by rfl) + +lemma gcd16_step_22 : + BinaryField.toPoly gcd16_a22Val = + BinaryField.toPoly gcd16_q22Val * BinaryField.toPoly gcd16_b22Val + + BinaryField.toPoly gcd16_r22Val := by + exact verify_div_step (a := gcd16_a22Val) (q := gcd16_q22Val) + (b := gcd16_b22Val) (r := gcd16_r22Val) (by rfl) + +lemma gcd16_step_23 : + BinaryField.toPoly gcd16_a23Val = + BinaryField.toPoly gcd16_q23Val * BinaryField.toPoly gcd16_b23Val + + BinaryField.toPoly gcd16_r23Val := by + exact verify_div_step (a := gcd16_a23Val) (q := gcd16_q23Val) + (b := gcd16_b23Val) (r := gcd16_r23Val) (by rfl) + +lemma gcd16_step_24 : + BinaryField.toPoly gcd16_a24Val = + BinaryField.toPoly gcd16_q24Val * BinaryField.toPoly gcd16_b24Val + + BinaryField.toPoly gcd16_r24Val := by + exact verify_div_step (a := gcd16_a24Val) (q := gcd16_q24Val) + (b := gcd16_b24Val) (r := gcd16_r24Val) (by rfl) + +lemma gcd16_step_25 : + BinaryField.toPoly gcd16_a25Val = + BinaryField.toPoly gcd16_q25Val * BinaryField.toPoly gcd16_b25Val + + BinaryField.toPoly gcd16_r25Val := by + exact verify_div_step (a := gcd16_a25Val) (q := gcd16_q25Val) + (b := gcd16_b25Val) (r := gcd16_r25Val) (by rfl) + +lemma gcd16_step_26 : + BinaryField.toPoly gcd16_a26Val = + BinaryField.toPoly gcd16_q26Val * BinaryField.toPoly gcd16_b26Val + + BinaryField.toPoly gcd16_r26Val := by + exact verify_div_step (a := gcd16_a26Val) (q := gcd16_q26Val) + (b := gcd16_b26Val) (r := gcd16_r26Val) (by rfl) + +lemma gcd16_step_27 : + BinaryField.toPoly gcd16_a27Val = + BinaryField.toPoly gcd16_q27Val * BinaryField.toPoly gcd16_b27Val + + BinaryField.toPoly gcd16_r27Val := by + exact verify_div_step (a := gcd16_a27Val) (q := gcd16_q27Val) + (b := gcd16_b27Val) (r := gcd16_r27Val) (by rfl) + +/-- Rabin gcd condition for exponent `16`. -/ +lemma rabin_gcd_condition_16 : + EuclideanDomain.gcd (X ^ (2 ^ 16) + X) definingPolynomial = 1 := by + rw [gcd16_start_reduction] + rw [definingPolynomial_eq_gcdPVal] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a1Val) + (BinaryField.toPoly gcd16_b1Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b1Val) (by decide)) + gcd16_step_1] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a2Val) + (BinaryField.toPoly gcd16_b2Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b2Val) (by decide)) + gcd16_step_2] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a3Val) + (BinaryField.toPoly gcd16_b3Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b3Val) (by decide)) + gcd16_step_3] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a4Val) + (BinaryField.toPoly gcd16_b4Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b4Val) (by decide)) + gcd16_step_4] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a5Val) + (BinaryField.toPoly gcd16_b5Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b5Val) (by decide)) + gcd16_step_5] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a6Val) + (BinaryField.toPoly gcd16_b6Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b6Val) (by decide)) + gcd16_step_6] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a7Val) + (BinaryField.toPoly gcd16_b7Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b7Val) (by decide)) + gcd16_step_7] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a8Val) + (BinaryField.toPoly gcd16_b8Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b8Val) (by decide)) + gcd16_step_8] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a9Val) + (BinaryField.toPoly gcd16_b9Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b9Val) (by decide)) + gcd16_step_9] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a10Val) + (BinaryField.toPoly gcd16_b10Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b10Val) (by decide)) + gcd16_step_10] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a11Val) + (BinaryField.toPoly gcd16_b11Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b11Val) (by decide)) + gcd16_step_11] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a12Val) + (BinaryField.toPoly gcd16_b12Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b12Val) (by decide)) + gcd16_step_12] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a13Val) + (BinaryField.toPoly gcd16_b13Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b13Val) (by decide)) + gcd16_step_13] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a14Val) + (BinaryField.toPoly gcd16_b14Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b14Val) (by decide)) + gcd16_step_14] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a15Val) + (BinaryField.toPoly gcd16_b15Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b15Val) (by decide)) + gcd16_step_15] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a16Val) + (BinaryField.toPoly gcd16_b16Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b16Val) (by decide)) + gcd16_step_16] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a17Val) + (BinaryField.toPoly gcd16_b17Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b17Val) (by decide)) + gcd16_step_17] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a18Val) + (BinaryField.toPoly gcd16_b18Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b18Val) (by decide)) + gcd16_step_18] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a19Val) + (BinaryField.toPoly gcd16_b19Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b19Val) (by decide)) + gcd16_step_19] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a20Val) + (BinaryField.toPoly gcd16_b20Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b20Val) (by decide)) + gcd16_step_20] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a21Val) + (BinaryField.toPoly gcd16_b21Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b21Val) (by decide)) + gcd16_step_21] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a22Val) + (BinaryField.toPoly gcd16_b22Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b22Val) (by decide)) + gcd16_step_22] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a23Val) + (BinaryField.toPoly gcd16_b23Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b23Val) (by decide)) + gcd16_step_23] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a24Val) + (BinaryField.toPoly gcd16_b24Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b24Val) (by decide)) + gcd16_step_24] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a25Val) + (BinaryField.toPoly gcd16_b25Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b25Val) (by decide)) + gcd16_step_25] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a26Val) + (BinaryField.toPoly gcd16_b26Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b26Val) (by decide)) + gcd16_step_26] + change EuclideanDomain.gcd (BinaryField.toPoly gcd16_a27Val) + (BinaryField.toPoly gcd16_b27Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd16_b27Val) (by decide)) + gcd16_step_27] + change EuclideanDomain.gcd + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 1 : B96)) + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 0 : B96)) = 1 + rw [BinaryField.toPoly_one_eq_one + (w := 2 * extensionDegree) (h_w_pos := by unfold extensionDegree; omega)] + rw [BinaryField.toPoly_zero_eq_zero] + exact BinaryField.gcd_one_zero + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_48/XPowTwoPowModCertificate.lean b/CompPoly/Fields/Binary/GF2_48/XPowTwoPowModCertificate.lean new file mode 100644 index 00000000..0d7019df --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_48/XPowTwoPowModCertificate.lean @@ -0,0 +1,1096 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_48.Prelude +import Mathlib.Tactic.NormNum + +/-! +# GF(2^48) Modular Frobenius Certificate + +Kernel-safe certificate data for repeated squaring of `X` modulo +`X^48 + X^9 + X^7 + X^4 + 1`. +-/ + +namespace GF2_48 + +open Polynomial + +set_option maxRecDepth 1500 + +/-- Certificate exponents fit in the doubled-width checker. -/ +lemma certificateExponents_bound : + ∀ exponent ∈ definingPolynomialExponents, + extensionDegree + exponent ≤ 2 * extensionDegree := by + unfold definingPolynomialExponents extensionDegree + decide + +/-- Soundness wrapper specialized to the GF48 defining polynomial. -/ +private theorem verify_square_step {rPrev q rNext : B48} + (h : + BinaryField.Extension.checkSquareStep extensionDegree definingPolynomialExponents + rPrev q rNext = true) : + (BinaryField.toPoly rPrev) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q) * + definingPolynomial + BinaryField.toPoly rNext := by + rw [← sparsePolynomial_definingPolynomialExponents] + exact BinaryField.Extension.checkSquareStep_correct certificateExponents_bound + rPrev q rNext h + +def r0Val : B48 := BitVec.ofNat extensionDegree 2 +noncomputable def r0 : Polynomial (ZMod 2) := BinaryField.toPoly r0Val + +def q1Val : B48 := BitVec.ofNat extensionDegree 0 +def r1Val : B48 := BitVec.ofNat extensionDegree 4 +noncomputable def r1 : Polynomial (ZMod 2) := BinaryField.toPoly r1Val + +def q2Val : B48 := BitVec.ofNat extensionDegree 0 +def r2Val : B48 := BitVec.ofNat extensionDegree 16 +noncomputable def r2 : Polynomial (ZMod 2) := BinaryField.toPoly r2Val + +def q3Val : B48 := BitVec.ofNat extensionDegree 0 +def r3Val : B48 := BitVec.ofNat extensionDegree 256 +noncomputable def r3 : Polynomial (ZMod 2) := BinaryField.toPoly r3Val + +def q4Val : B48 := BitVec.ofNat extensionDegree 0 +def r4Val : B48 := BitVec.ofNat extensionDegree 65536 +noncomputable def r4 : Polynomial (ZMod 2) := BinaryField.toPoly r4Val + +def q5Val : B48 := BitVec.ofNat extensionDegree 0 +def r5Val : B48 := BitVec.ofNat extensionDegree 4294967296 +noncomputable def r5 : Polynomial (ZMod 2) := BinaryField.toPoly r5Val + +def q6Val : B48 := BitVec.ofNat extensionDegree 65536 +def r6Val : B48 := BitVec.ofNat extensionDegree 43057152 +noncomputable def r6 : Polynomial (ZMod 2) := BinaryField.toPoly r6Val + +def q7Val : B48 := BitVec.ofNat extensionDegree 4 +def r7Val : B48 := BitVec.ofNat extensionDegree 71472550775364 +noncomputable def r7 : Polynomial (ZMod 2) := BinaryField.toPoly r7Val + +def q8Val : B48 := BitVec.ofNat extensionDegree 17596481077289 +def r8Val : B48 := BitVec.ofNat extensionDegree 20414027093033 +noncomputable def r8 : Polynomial (ZMod 2) := BinaryField.toPoly r8Val + +def q9Val : B48 := BitVec.ofNat extensionDegree 1117782081542 +def r9Val : B48 := BitVec.ofNat extensionDegree 223148289100583 +noncomputable def r9 : Polynomial (ZMod 2) := BinaryField.toPoly r9Val + +def q10Val : B48 := BitVec.ofNat extensionDegree 88254414409865 +def r10Val : B48 := BitVec.ofNat extensionDegree 209459332516492 +noncomputable def r10 : Polynomial (ZMod 2) := BinaryField.toPoly r10Val + +def q11Val : B48 := BitVec.ofNat extensionDegree 76228153327869 +def r11Val : B48 := BitVec.ofNat extensionDegree 21853882125309 +noncomputable def r11 : Polynomial (ZMod 2) := BinaryField.toPoly r11Val + +def q12Val : B48 := BitVec.ofNat extensionDegree 1122395754498 +def r12Val : B48 := BitVec.ofNat extensionDegree 225757782360179 +noncomputable def r12 : Polynomial (ZMod 2) := BinaryField.toPoly r12Val + +def q13Val : B48 := BitVec.ofNat extensionDegree 88309108117917 +def r13Val : B48 := BitVec.ofNat extensionDegree 224002308041160 +noncomputable def r13 : Polynomial (ZMod 2) := BinaryField.toPoly r13Val + +def q14Val : B48 := BitVec.ofNat extensionDegree 88258445066700 +def r14Val : B48 := BitVec.ofNat extensionDegree 186283198673740 +noncomputable def r14 : Polynomial (ZMod 2) := BinaryField.toPoly r14Val + +def q15Val : B48 := BitVec.ofNat extensionDegree 75046304355579 +def r15Val : B48 := BitVec.ofNat extensionDegree 271539852787867 +noncomputable def r15 : Polynomial (ZMod 2) := BinaryField.toPoly r15Val + +def q16Val : B48 := BitVec.ofNat extensionDegree 93545815101653 +def r16Val : B48 := BitVec.ofNat extensionDegree 197658536369216 +noncomputable def r16 : Polynomial (ZMod 2) := BinaryField.toPoly r16Val + +def q17Val : B48 := BitVec.ofNat extensionDegree 75889120400824 +def r17Val : B48 := BitVec.ofNat extensionDegree 224404135260728 +noncomputable def r17 : Polynomial (ZMod 2) := BinaryField.toPoly r17Val + +def q18Val : B48 := BitVec.ofNat extensionDegree 88304548578509 +def r18Val : B48 := BitVec.ofNat extensionDegree 155316491629021 +noncomputable def r18 : Polynomial (ZMod 2) := BinaryField.toPoly r18Val + +def q19Val : B48 := BitVec.ofNat extensionDegree 70716905231780 +def r19Val : B48 := BitVec.ofNat extensionDegree 246004442301621 +noncomputable def r19 : Polynomial (ZMod 2) := BinaryField.toPoly r19Val + +def q20Val : B48 := BitVec.ofNat extensionDegree 89426677010906 +def r20Val : B48 := BitVec.ofNat extensionDegree 88202974793835 +noncomputable def r20 : Polynomial (ZMod 2) := BinaryField.toPoly r20Val + +def q21Val : B48 := BitVec.ofNat extensionDegree 18691785757039 +def r21Val : B48 := BitVec.ofNat extensionDegree 233429063662170 +noncomputable def r21 : Polynomial (ZMod 2) := BinaryField.toPoly r21Val + +def q22Val : B48 := BitVec.ofNat extensionDegree 89129435075983 +def r22Val : B48 := BitVec.ofNat extensionDegree 277611832247739 +noncomputable def r22 : Polynomial (ZMod 2) := BinaryField.toPoly r22Val + +def q23Val : B48 := BitVec.ofNat extensionDegree 93802443325633 +def r23Val : B48 := BitVec.ofNat extensionDegree 83975349791508 +noncomputable def r23 : Polynomial (ZMod 2) := BinaryField.toPoly r23Val + +def q24Val : B48 := BitVec.ofNat extensionDegree 17936118972521 +def r24Val : B48 := BitVec.ofNat extensionDegree 221427043524969 +noncomputable def r24 : Polynomial (ZMod 2) := BinaryField.toPoly r24Val + +def q25Val : B48 := BitVec.ofNat extensionDegree 88240438968461 +def r25Val : B48 := BitVec.ofNat extensionDegree 253862780158108 +noncomputable def r25 : Polynomial (ZMod 2) := BinaryField.toPoly r25Val + +def q26Val : B48 := BitVec.ofNat extensionDegree 92446285693127 +def r26Val : B48 := BitVec.ofNat extensionDegree 112983624949863 +noncomputable def r26 : Polynomial (ZMod 2) := BinaryField.toPoly r26Val + +def q27Val : B48 := BitVec.ofNat extensionDegree 22077474340979 +def r27Val : B48 := BitVec.ofNat extensionDegree 42645238107350 +noncomputable def r27 : Polynomial (ZMod 2) := BinaryField.toPoly r27Val + +def q28Val : B48 := BitVec.ofNat extensionDegree 4485292294494 +def r28Val : B48 := BitVec.ofNat extensionDegree 131707965757098 +noncomputable def r28 : Polynomial (ZMod 2) := BinaryField.toPoly r28Val + +def q29Val : B48 := BitVec.ofNat extensionDegree 23181284951093 +def r29Val : B48 := BitVec.ofNat extensionDegree 180654501999521 +noncomputable def r29 : Polynomial (ZMod 2) := BinaryField.toPoly r29Val + +def q30Val : B48 := BitVec.ofNat extensionDegree 74835783931067 +def r30Val : B48 := BitVec.ofNat extensionDegree 63207326773386 +noncomputable def r30 : Polynomial (ZMod 2) := BinaryField.toPoly r30Val + +def q31Val : B48 := BitVec.ofNat extensionDegree 5777088594252 +def r31Val : B48 := BitVec.ofNat extensionDegree 109901199584200 +noncomputable def r31 : Polynomial (ZMod 2) := BinaryField.toPoly r31Val + +def q32Val : B48 := BitVec.ofNat extensionDegree 22013134508402 +def r32Val : B48 := BitVec.ofNat extensionDegree 10190489258770 +noncomputable def r32 : Polynomial (ZMod 2) := BinaryField.toPoly r32Val + +def q33Val : B48 := BitVec.ofNat extensionDegree 279442375744 +def r33Val : B48 := BitVec.ofNat extensionDegree 197552288538948 +noncomputable def r33 : Polynomial (ZMod 2) := BinaryField.toPoly r33Val + +def q34Val : B48 := BitVec.ofNat extensionDegree 75888923248109 +def r34Val : B48 := BitVec.ofNat extensionDegree 220172058650541 +noncomputable def r34 : Polynomial (ZMod 2) := BinaryField.toPoly r34Val + +def q35Val : B48 := BitVec.ofNat extensionDegree 88235897540828 +def r35Val : B48 := BitVec.ofNat extensionDegree 251823706197837 +noncomputable def r35 : Polynomial (ZMod 2) := BinaryField.toPoly r35Val + +def q36Val : B48 := BitVec.ofNat extensionDegree 92431995375763 +def r36Val : B48 := BitVec.ofNat extensionDegree 140535427589746 +noncomputable def r36 : Polynomial (ZMod 2) := BinaryField.toPoly r36Val + +def q37Val : B48 := BitVec.ofNat extensionDegree 23456175379761 +def r37Val : B48 := BitVec.ofNat extensionDegree 76260727450021 +noncomputable def r37 : Polynomial (ZMod 2) := BinaryField.toPoly r37Val + +def q38Val : B48 := BitVec.ofNat extensionDegree 17665490243896 +def r38Val : B48 := BitVec.ofNat extensionDegree 134876894063273 +noncomputable def r38 : Polynomial (ZMod 2) := BinaryField.toPoly r38Val + +def q39Val : B48 := BitVec.ofNat extensionDegree 23382947337568 +def r39Val : B48 := BitVec.ofNat extensionDegree 135171159389985 +noncomputable def r39 : Polynomial (ZMod 2) := BinaryField.toPoly r39Val + +def q40Val : B48 := BitVec.ofNat extensionDegree 23383216838001 +def r40Val : B48 := BitVec.ofNat extensionDegree 68734577630432 +noncomputable def r40 : Polynomial (ZMod 2) := BinaryField.toPoly r40Val + +def q41Val : B48 := BitVec.ofNat extensionDegree 5859409477656 +def r41Val : B48 := BitVec.ofNat extensionDegree 91952450185624 +noncomputable def r41 : Polynomial (ZMod 2) := BinaryField.toPoly r41Val + +def q42Val : B48 := BitVec.ofNat extensionDegree 18714313429354 +def r42Val : B48 := BitVec.ofNat extensionDegree 155555175540618 +noncomputable def r42 : Polynomial (ZMod 2) := BinaryField.toPoly r42Val + +def q43Val : B48 := BitVec.ofNat extensionDegree 70716993306784 +def r43Val : B48 := BitVec.ofNat extensionDegree 170035323624164 +noncomputable def r43 : Polynomial (ZMod 2) := BinaryField.toPoly r43Val + +def q44Val : B48 := BitVec.ofNat extensionDegree 71761455551731 +def r44Val : B48 := BitVec.ofNat extensionDegree 139269664903251 +noncomputable def r44 : Polynomial (ZMod 2) := BinaryField.toPoly r44Val + +def q45Val : B48 := BitVec.ofNat extensionDegree 23451666744693 +def r45Val : B48 := BitVec.ofNat extensionDegree 24944818525088 +noncomputable def r45 : Polynomial (ZMod 2) := BinaryField.toPoly r45Val + +def q46Val : B48 := BitVec.ofNat extensionDegree 1186557416519 +def r46Val : B48 := BitVec.ofNat extensionDegree 196445362190775 +noncomputable def r46 : Polynomial (ZMod 2) := BinaryField.toPoly r46Val + +def q47Val : B48 := BitVec.ofNat extensionDegree 75884627509420 +def r47Val : B48 := BitVec.ofNat extensionDegree 175921858347385 +noncomputable def r47 : Polynomial (ZMod 2) := BinaryField.toPoly r47Val + +def q48Val : B48 := BitVec.ofNat extensionDegree 71834759681523 +def r48Val : B48 := BitVec.ofNat extensionDegree 2 +noncomputable def r48 : Polynomial (ZMod 2) := BinaryField.toPoly r48Val + +/-- The initial remainder denotes `X`. -/ +lemma r0_eq_X : r0 = X := by + rw [r0, r0Val, extensionDegree] + have h : (BitVec.ofNat 48 2 : BitVec 48) = (1 <<< 1 : BitVec 48) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 48) 1 (by decide) + +/-- The final remainder after 48 Frobenius steps denotes `X`. -/ +lemma r48_eq_X : r48 = X := by + rw [r48, r48Val, extensionDegree] + have h : (BitVec.ofNat 48 2 : BitVec 48) = (1 <<< 1 : BitVec 48) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 48) 1 (by decide) + +/-- Certificate step 1: square and reduce modulo the GF48 polynomial. -/ +lemma step_1 : + r0 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + r1 := by + change (BinaryField.toPoly r0Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + BinaryField.toPoly r1Val + exact verify_square_step (rPrev := r0Val) (q := q1Val) + (rNext := r1Val) (by rfl) + +/-- Certificate step 2: square and reduce modulo the GF48 polynomial. -/ +lemma step_2 : + r1 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + r2 := by + change (BinaryField.toPoly r1Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + BinaryField.toPoly r2Val + exact verify_square_step (rPrev := r1Val) (q := q2Val) + (rNext := r2Val) (by rfl) + +/-- Certificate step 3: square and reduce modulo the GF48 polynomial. -/ +lemma step_3 : + r2 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + r3 := by + change (BinaryField.toPoly r2Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + BinaryField.toPoly r3Val + exact verify_square_step (rPrev := r2Val) (q := q3Val) + (rNext := r3Val) (by rfl) + +/-- Certificate step 4: square and reduce modulo the GF48 polynomial. -/ +lemma step_4 : + r3 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + r4 := by + change (BinaryField.toPoly r3Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + BinaryField.toPoly r4Val + exact verify_square_step (rPrev := r3Val) (q := q4Val) + (rNext := r4Val) (by rfl) + +/-- Certificate step 5: square and reduce modulo the GF48 polynomial. -/ +lemma step_5 : + r4 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + r5 := by + change (BinaryField.toPoly r4Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + BinaryField.toPoly r5Val + exact verify_square_step (rPrev := r4Val) (q := q5Val) + (rNext := r5Val) (by rfl) + +/-- Certificate step 6: square and reduce modulo the GF48 polynomial. -/ +lemma step_6 : + r5 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + r6 := by + change (BinaryField.toPoly r5Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + BinaryField.toPoly r6Val + exact verify_square_step (rPrev := r5Val) (q := q6Val) + (rNext := r6Val) (by rfl) + +/-- Certificate step 7: square and reduce modulo the GF48 polynomial. -/ +lemma step_7 : + r6 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + r7 := by + change (BinaryField.toPoly r6Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + BinaryField.toPoly r7Val + exact verify_square_step (rPrev := r6Val) (q := q7Val) + (rNext := r7Val) (by rfl) + +/-- Certificate step 8: square and reduce modulo the GF48 polynomial. -/ +lemma step_8 : + r7 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + r8 := by + change (BinaryField.toPoly r7Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + BinaryField.toPoly r8Val + exact verify_square_step (rPrev := r7Val) (q := q8Val) + (rNext := r8Val) (by rfl) + +/-- Certificate step 9: square and reduce modulo the GF48 polynomial. -/ +lemma step_9 : + r8 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + r9 := by + change (BinaryField.toPoly r8Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + BinaryField.toPoly r9Val + exact verify_square_step (rPrev := r8Val) (q := q9Val) + (rNext := r9Val) (by rfl) + +/-- Certificate step 10: square and reduce modulo the GF48 polynomial. -/ +lemma step_10 : + r9 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + r10 := by + change (BinaryField.toPoly r9Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + BinaryField.toPoly r10Val + exact verify_square_step (rPrev := r9Val) (q := q10Val) + (rNext := r10Val) (by rfl) + +/-- Certificate step 11: square and reduce modulo the GF48 polynomial. -/ +lemma step_11 : + r10 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + r11 := by + change (BinaryField.toPoly r10Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + BinaryField.toPoly r11Val + exact verify_square_step (rPrev := r10Val) (q := q11Val) + (rNext := r11Val) (by rfl) + +/-- Certificate step 12: square and reduce modulo the GF48 polynomial. -/ +lemma step_12 : + r11 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + r12 := by + change (BinaryField.toPoly r11Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + BinaryField.toPoly r12Val + exact verify_square_step (rPrev := r11Val) (q := q12Val) + (rNext := r12Val) (by rfl) + +/-- Certificate step 13: square and reduce modulo the GF48 polynomial. -/ +lemma step_13 : + r12 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + r13 := by + change (BinaryField.toPoly r12Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + BinaryField.toPoly r13Val + exact verify_square_step (rPrev := r12Val) (q := q13Val) + (rNext := r13Val) (by rfl) + +/-- Certificate step 14: square and reduce modulo the GF48 polynomial. -/ +lemma step_14 : + r13 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + r14 := by + change (BinaryField.toPoly r13Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + BinaryField.toPoly r14Val + exact verify_square_step (rPrev := r13Val) (q := q14Val) + (rNext := r14Val) (by rfl) + +/-- Certificate step 15: square and reduce modulo the GF48 polynomial. -/ +lemma step_15 : + r14 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + r15 := by + change (BinaryField.toPoly r14Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + BinaryField.toPoly r15Val + exact verify_square_step (rPrev := r14Val) (q := q15Val) + (rNext := r15Val) (by rfl) + +/-- Certificate step 16: square and reduce modulo the GF48 polynomial. -/ +lemma step_16 : + r15 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + r16 := by + change (BinaryField.toPoly r15Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + BinaryField.toPoly r16Val + exact verify_square_step (rPrev := r15Val) (q := q16Val) + (rNext := r16Val) (by rfl) + +/-- Certificate step 17: square and reduce modulo the GF48 polynomial. -/ +lemma step_17 : + r16 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + r17 := by + change (BinaryField.toPoly r16Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + BinaryField.toPoly r17Val + exact verify_square_step (rPrev := r16Val) (q := q17Val) + (rNext := r17Val) (by rfl) + +/-- Certificate step 18: square and reduce modulo the GF48 polynomial. -/ +lemma step_18 : + r17 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + r18 := by + change (BinaryField.toPoly r17Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + BinaryField.toPoly r18Val + exact verify_square_step (rPrev := r17Val) (q := q18Val) + (rNext := r18Val) (by rfl) + +/-- Certificate step 19: square and reduce modulo the GF48 polynomial. -/ +lemma step_19 : + r18 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + r19 := by + change (BinaryField.toPoly r18Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + BinaryField.toPoly r19Val + exact verify_square_step (rPrev := r18Val) (q := q19Val) + (rNext := r19Val) (by rfl) + +/-- Certificate step 20: square and reduce modulo the GF48 polynomial. -/ +lemma step_20 : + r19 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + r20 := by + change (BinaryField.toPoly r19Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + BinaryField.toPoly r20Val + exact verify_square_step (rPrev := r19Val) (q := q20Val) + (rNext := r20Val) (by rfl) + +/-- Certificate step 21: square and reduce modulo the GF48 polynomial. -/ +lemma step_21 : + r20 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + r21 := by + change (BinaryField.toPoly r20Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + BinaryField.toPoly r21Val + exact verify_square_step (rPrev := r20Val) (q := q21Val) + (rNext := r21Val) (by rfl) + +/-- Certificate step 22: square and reduce modulo the GF48 polynomial. -/ +lemma step_22 : + r21 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + r22 := by + change (BinaryField.toPoly r21Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + BinaryField.toPoly r22Val + exact verify_square_step (rPrev := r21Val) (q := q22Val) + (rNext := r22Val) (by rfl) + +/-- Certificate step 23: square and reduce modulo the GF48 polynomial. -/ +lemma step_23 : + r22 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + r23 := by + change (BinaryField.toPoly r22Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + BinaryField.toPoly r23Val + exact verify_square_step (rPrev := r22Val) (q := q23Val) + (rNext := r23Val) (by rfl) + +/-- Certificate step 24: square and reduce modulo the GF48 polynomial. -/ +lemma step_24 : + r23 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + r24 := by + change (BinaryField.toPoly r23Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + BinaryField.toPoly r24Val + exact verify_square_step (rPrev := r23Val) (q := q24Val) + (rNext := r24Val) (by rfl) + +/-- Certificate step 25: square and reduce modulo the GF48 polynomial. -/ +lemma step_25 : + r24 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + r25 := by + change (BinaryField.toPoly r24Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + BinaryField.toPoly r25Val + exact verify_square_step (rPrev := r24Val) (q := q25Val) + (rNext := r25Val) (by rfl) + +/-- Certificate step 26: square and reduce modulo the GF48 polynomial. -/ +lemma step_26 : + r25 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + r26 := by + change (BinaryField.toPoly r25Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + BinaryField.toPoly r26Val + exact verify_square_step (rPrev := r25Val) (q := q26Val) + (rNext := r26Val) (by rfl) + +/-- Certificate step 27: square and reduce modulo the GF48 polynomial. -/ +lemma step_27 : + r26 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + r27 := by + change (BinaryField.toPoly r26Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + BinaryField.toPoly r27Val + exact verify_square_step (rPrev := r26Val) (q := q27Val) + (rNext := r27Val) (by rfl) + +/-- Certificate step 28: square and reduce modulo the GF48 polynomial. -/ +lemma step_28 : + r27 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + r28 := by + change (BinaryField.toPoly r27Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + BinaryField.toPoly r28Val + exact verify_square_step (rPrev := r27Val) (q := q28Val) + (rNext := r28Val) (by rfl) + +/-- Certificate step 29: square and reduce modulo the GF48 polynomial. -/ +lemma step_29 : + r28 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + r29 := by + change (BinaryField.toPoly r28Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + BinaryField.toPoly r29Val + exact verify_square_step (rPrev := r28Val) (q := q29Val) + (rNext := r29Val) (by rfl) + +/-- Certificate step 30: square and reduce modulo the GF48 polynomial. -/ +lemma step_30 : + r29 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + r30 := by + change (BinaryField.toPoly r29Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + BinaryField.toPoly r30Val + exact verify_square_step (rPrev := r29Val) (q := q30Val) + (rNext := r30Val) (by rfl) + +/-- Certificate step 31: square and reduce modulo the GF48 polynomial. -/ +lemma step_31 : + r30 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + r31 := by + change (BinaryField.toPoly r30Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + BinaryField.toPoly r31Val + exact verify_square_step (rPrev := r30Val) (q := q31Val) + (rNext := r31Val) (by rfl) + +/-- Certificate step 32: square and reduce modulo the GF48 polynomial. -/ +lemma step_32 : + r31 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + r32 := by + change (BinaryField.toPoly r31Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + BinaryField.toPoly r32Val + exact verify_square_step (rPrev := r31Val) (q := q32Val) + (rNext := r32Val) (by rfl) + +/-- Certificate step 33: square and reduce modulo the GF48 polynomial. -/ +lemma step_33 : + r32 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q33Val) * + definingPolynomial + r33 := by + change (BinaryField.toPoly r32Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q33Val) * + definingPolynomial + BinaryField.toPoly r33Val + exact verify_square_step (rPrev := r32Val) (q := q33Val) + (rNext := r33Val) (by rfl) + +/-- Certificate step 34: square and reduce modulo the GF48 polynomial. -/ +lemma step_34 : + r33 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q34Val) * + definingPolynomial + r34 := by + change (BinaryField.toPoly r33Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q34Val) * + definingPolynomial + BinaryField.toPoly r34Val + exact verify_square_step (rPrev := r33Val) (q := q34Val) + (rNext := r34Val) (by rfl) + +/-- Certificate step 35: square and reduce modulo the GF48 polynomial. -/ +lemma step_35 : + r34 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q35Val) * + definingPolynomial + r35 := by + change (BinaryField.toPoly r34Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q35Val) * + definingPolynomial + BinaryField.toPoly r35Val + exact verify_square_step (rPrev := r34Val) (q := q35Val) + (rNext := r35Val) (by rfl) + +/-- Certificate step 36: square and reduce modulo the GF48 polynomial. -/ +lemma step_36 : + r35 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q36Val) * + definingPolynomial + r36 := by + change (BinaryField.toPoly r35Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q36Val) * + definingPolynomial + BinaryField.toPoly r36Val + exact verify_square_step (rPrev := r35Val) (q := q36Val) + (rNext := r36Val) (by rfl) + +/-- Certificate step 37: square and reduce modulo the GF48 polynomial. -/ +lemma step_37 : + r36 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q37Val) * + definingPolynomial + r37 := by + change (BinaryField.toPoly r36Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q37Val) * + definingPolynomial + BinaryField.toPoly r37Val + exact verify_square_step (rPrev := r36Val) (q := q37Val) + (rNext := r37Val) (by rfl) + +/-- Certificate step 38: square and reduce modulo the GF48 polynomial. -/ +lemma step_38 : + r37 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q38Val) * + definingPolynomial + r38 := by + change (BinaryField.toPoly r37Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q38Val) * + definingPolynomial + BinaryField.toPoly r38Val + exact verify_square_step (rPrev := r37Val) (q := q38Val) + (rNext := r38Val) (by rfl) + +/-- Certificate step 39: square and reduce modulo the GF48 polynomial. -/ +lemma step_39 : + r38 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q39Val) * + definingPolynomial + r39 := by + change (BinaryField.toPoly r38Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q39Val) * + definingPolynomial + BinaryField.toPoly r39Val + exact verify_square_step (rPrev := r38Val) (q := q39Val) + (rNext := r39Val) (by rfl) + +/-- Certificate step 40: square and reduce modulo the GF48 polynomial. -/ +lemma step_40 : + r39 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q40Val) * + definingPolynomial + r40 := by + change (BinaryField.toPoly r39Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q40Val) * + definingPolynomial + BinaryField.toPoly r40Val + exact verify_square_step (rPrev := r39Val) (q := q40Val) + (rNext := r40Val) (by rfl) + +/-- Certificate step 41: square and reduce modulo the GF48 polynomial. -/ +lemma step_41 : + r40 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q41Val) * + definingPolynomial + r41 := by + change (BinaryField.toPoly r40Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q41Val) * + definingPolynomial + BinaryField.toPoly r41Val + exact verify_square_step (rPrev := r40Val) (q := q41Val) + (rNext := r41Val) (by rfl) + +/-- Certificate step 42: square and reduce modulo the GF48 polynomial. -/ +lemma step_42 : + r41 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q42Val) * + definingPolynomial + r42 := by + change (BinaryField.toPoly r41Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q42Val) * + definingPolynomial + BinaryField.toPoly r42Val + exact verify_square_step (rPrev := r41Val) (q := q42Val) + (rNext := r42Val) (by rfl) + +/-- Certificate step 43: square and reduce modulo the GF48 polynomial. -/ +lemma step_43 : + r42 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q43Val) * + definingPolynomial + r43 := by + change (BinaryField.toPoly r42Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q43Val) * + definingPolynomial + BinaryField.toPoly r43Val + exact verify_square_step (rPrev := r42Val) (q := q43Val) + (rNext := r43Val) (by rfl) + +/-- Certificate step 44: square and reduce modulo the GF48 polynomial. -/ +lemma step_44 : + r43 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q44Val) * + definingPolynomial + r44 := by + change (BinaryField.toPoly r43Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q44Val) * + definingPolynomial + BinaryField.toPoly r44Val + exact verify_square_step (rPrev := r43Val) (q := q44Val) + (rNext := r44Val) (by rfl) + +/-- Certificate step 45: square and reduce modulo the GF48 polynomial. -/ +lemma step_45 : + r44 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q45Val) * + definingPolynomial + r45 := by + change (BinaryField.toPoly r44Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q45Val) * + definingPolynomial + BinaryField.toPoly r45Val + exact verify_square_step (rPrev := r44Val) (q := q45Val) + (rNext := r45Val) (by rfl) + +/-- Certificate step 46: square and reduce modulo the GF48 polynomial. -/ +lemma step_46 : + r45 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q46Val) * + definingPolynomial + r46 := by + change (BinaryField.toPoly r45Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q46Val) * + definingPolynomial + BinaryField.toPoly r46Val + exact verify_square_step (rPrev := r45Val) (q := q46Val) + (rNext := r46Val) (by rfl) + +/-- Certificate step 47: square and reduce modulo the GF48 polynomial. -/ +lemma step_47 : + r46 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q47Val) * + definingPolynomial + r47 := by + change (BinaryField.toPoly r46Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q47Val) * + definingPolynomial + BinaryField.toPoly r47Val + exact verify_square_step (rPrev := r46Val) (q := q47Val) + (rNext := r47Val) (by rfl) + +/-- Certificate step 48: square and reduce modulo the GF48 polynomial. -/ +lemma step_48 : + r47 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q48Val) * + definingPolynomial + r48 := by + change (BinaryField.toPoly r47Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q48Val) * + definingPolynomial + BinaryField.toPoly r48Val + exact verify_square_step (rPrev := r47Val) (q := q48Val) + (rNext := r48Val) (by rfl) + +/-- The degree-one polynomial `X` is already reduced modulo the GF48 polynomial. -/ +lemma X_mod_definingPolynomial : + X % definingPolynomial = X := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + unfold extensionDegree + norm_num [degree_X] + +lemma X_pow_2_pow_0_mod_eq : + X ^ (2 ^ 0) % definingPolynomial = r0 % definingPolynomial := by + rw [pow_zero, pow_one, r0_eq_X] + +lemma X_pow_2_pow_1_mod_eq : + X ^ (2 ^ 1) % definingPolynomial = r1 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 0) X_pow_2_pow_0_mod_eq step_1 + +lemma X_pow_2_pow_2_mod_eq : + X ^ (2 ^ 2) % definingPolynomial = r2 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 1) X_pow_2_pow_1_mod_eq step_2 + +lemma X_pow_2_pow_3_mod_eq : + X ^ (2 ^ 3) % definingPolynomial = r3 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 2) X_pow_2_pow_2_mod_eq step_3 + +lemma X_pow_2_pow_4_mod_eq : + X ^ (2 ^ 4) % definingPolynomial = r4 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 3) X_pow_2_pow_3_mod_eq step_4 + +lemma X_pow_2_pow_5_mod_eq : + X ^ (2 ^ 5) % definingPolynomial = r5 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 4) X_pow_2_pow_4_mod_eq step_5 + +lemma X_pow_2_pow_6_mod_eq : + X ^ (2 ^ 6) % definingPolynomial = r6 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 5) X_pow_2_pow_5_mod_eq step_6 + +lemma X_pow_2_pow_7_mod_eq : + X ^ (2 ^ 7) % definingPolynomial = r7 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 6) X_pow_2_pow_6_mod_eq step_7 + +lemma X_pow_2_pow_8_mod_eq : + X ^ (2 ^ 8) % definingPolynomial = r8 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 7) X_pow_2_pow_7_mod_eq step_8 + +lemma X_pow_2_pow_9_mod_eq : + X ^ (2 ^ 9) % definingPolynomial = r9 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 8) X_pow_2_pow_8_mod_eq step_9 + +lemma X_pow_2_pow_10_mod_eq : + X ^ (2 ^ 10) % definingPolynomial = r10 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 9) X_pow_2_pow_9_mod_eq step_10 + +lemma X_pow_2_pow_11_mod_eq : + X ^ (2 ^ 11) % definingPolynomial = r11 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 10) X_pow_2_pow_10_mod_eq step_11 + +lemma X_pow_2_pow_12_mod_eq : + X ^ (2 ^ 12) % definingPolynomial = r12 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 11) X_pow_2_pow_11_mod_eq step_12 + +lemma X_pow_2_pow_13_mod_eq : + X ^ (2 ^ 13) % definingPolynomial = r13 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 12) X_pow_2_pow_12_mod_eq step_13 + +lemma X_pow_2_pow_14_mod_eq : + X ^ (2 ^ 14) % definingPolynomial = r14 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 13) X_pow_2_pow_13_mod_eq step_14 + +lemma X_pow_2_pow_15_mod_eq : + X ^ (2 ^ 15) % definingPolynomial = r15 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 14) X_pow_2_pow_14_mod_eq step_15 + +lemma X_pow_2_pow_16_mod_eq : + X ^ (2 ^ 16) % definingPolynomial = r16 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 15) X_pow_2_pow_15_mod_eq step_16 + +lemma X_pow_2_pow_17_mod_eq : + X ^ (2 ^ 17) % definingPolynomial = r17 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 16) X_pow_2_pow_16_mod_eq step_17 + +lemma X_pow_2_pow_18_mod_eq : + X ^ (2 ^ 18) % definingPolynomial = r18 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 17) X_pow_2_pow_17_mod_eq step_18 + +lemma X_pow_2_pow_19_mod_eq : + X ^ (2 ^ 19) % definingPolynomial = r19 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 18) X_pow_2_pow_18_mod_eq step_19 + +lemma X_pow_2_pow_20_mod_eq : + X ^ (2 ^ 20) % definingPolynomial = r20 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 19) X_pow_2_pow_19_mod_eq step_20 + +lemma X_pow_2_pow_21_mod_eq : + X ^ (2 ^ 21) % definingPolynomial = r21 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 20) X_pow_2_pow_20_mod_eq step_21 + +lemma X_pow_2_pow_22_mod_eq : + X ^ (2 ^ 22) % definingPolynomial = r22 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 21) X_pow_2_pow_21_mod_eq step_22 + +lemma X_pow_2_pow_23_mod_eq : + X ^ (2 ^ 23) % definingPolynomial = r23 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 22) X_pow_2_pow_22_mod_eq step_23 + +lemma X_pow_2_pow_24_mod_eq : + X ^ (2 ^ 24) % definingPolynomial = r24 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 23) X_pow_2_pow_23_mod_eq step_24 + +lemma X_pow_2_pow_25_mod_eq : + X ^ (2 ^ 25) % definingPolynomial = r25 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 24) X_pow_2_pow_24_mod_eq step_25 + +lemma X_pow_2_pow_26_mod_eq : + X ^ (2 ^ 26) % definingPolynomial = r26 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 25) X_pow_2_pow_25_mod_eq step_26 + +lemma X_pow_2_pow_27_mod_eq : + X ^ (2 ^ 27) % definingPolynomial = r27 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 26) X_pow_2_pow_26_mod_eq step_27 + +lemma X_pow_2_pow_28_mod_eq : + X ^ (2 ^ 28) % definingPolynomial = r28 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 27) X_pow_2_pow_27_mod_eq step_28 + +lemma X_pow_2_pow_29_mod_eq : + X ^ (2 ^ 29) % definingPolynomial = r29 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 28) X_pow_2_pow_28_mod_eq step_29 + +lemma X_pow_2_pow_30_mod_eq : + X ^ (2 ^ 30) % definingPolynomial = r30 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 29) X_pow_2_pow_29_mod_eq step_30 + +lemma X_pow_2_pow_31_mod_eq : + X ^ (2 ^ 31) % definingPolynomial = r31 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 30) X_pow_2_pow_30_mod_eq step_31 + +lemma X_pow_2_pow_32_mod_eq : + X ^ (2 ^ 32) % definingPolynomial = r32 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 31) X_pow_2_pow_31_mod_eq step_32 + +lemma X_pow_2_pow_33_mod_eq : + X ^ (2 ^ 33) % definingPolynomial = r33 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 32) X_pow_2_pow_32_mod_eq step_33 + +lemma X_pow_2_pow_34_mod_eq : + X ^ (2 ^ 34) % definingPolynomial = r34 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 33) X_pow_2_pow_33_mod_eq step_34 + +lemma X_pow_2_pow_35_mod_eq : + X ^ (2 ^ 35) % definingPolynomial = r35 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 34) X_pow_2_pow_34_mod_eq step_35 + +lemma X_pow_2_pow_36_mod_eq : + X ^ (2 ^ 36) % definingPolynomial = r36 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 35) X_pow_2_pow_35_mod_eq step_36 + +lemma X_pow_2_pow_37_mod_eq : + X ^ (2 ^ 37) % definingPolynomial = r37 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 36) X_pow_2_pow_36_mod_eq step_37 + +lemma X_pow_2_pow_38_mod_eq : + X ^ (2 ^ 38) % definingPolynomial = r38 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 37) X_pow_2_pow_37_mod_eq step_38 + +lemma X_pow_2_pow_39_mod_eq : + X ^ (2 ^ 39) % definingPolynomial = r39 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 38) X_pow_2_pow_38_mod_eq step_39 + +lemma X_pow_2_pow_40_mod_eq : + X ^ (2 ^ 40) % definingPolynomial = r40 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 39) X_pow_2_pow_39_mod_eq step_40 + +lemma X_pow_2_pow_41_mod_eq : + X ^ (2 ^ 41) % definingPolynomial = r41 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 40) X_pow_2_pow_40_mod_eq step_41 + +lemma X_pow_2_pow_42_mod_eq : + X ^ (2 ^ 42) % definingPolynomial = r42 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 41) X_pow_2_pow_41_mod_eq step_42 + +lemma X_pow_2_pow_43_mod_eq : + X ^ (2 ^ 43) % definingPolynomial = r43 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 42) X_pow_2_pow_42_mod_eq step_43 + +lemma X_pow_2_pow_44_mod_eq : + X ^ (2 ^ 44) % definingPolynomial = r44 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 43) X_pow_2_pow_43_mod_eq step_44 + +lemma X_pow_2_pow_45_mod_eq : + X ^ (2 ^ 45) % definingPolynomial = r45 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 44) X_pow_2_pow_44_mod_eq step_45 + +lemma X_pow_2_pow_46_mod_eq : + X ^ (2 ^ 46) % definingPolynomial = r46 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 45) X_pow_2_pow_45_mod_eq step_46 + +lemma X_pow_2_pow_47_mod_eq : + X ^ (2 ^ 47) % definingPolynomial = r47 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 46) X_pow_2_pow_46_mod_eq step_47 + +lemma X_pow_2_pow_48_mod_eq : + X ^ (2 ^ 48) % definingPolynomial = r48 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 47) X_pow_2_pow_47_mod_eq step_48 + +/-- Rabin trace-condition remainder for the GF48 candidate polynomial. -/ +lemma X_pow_2_pow_48_add_X_mod_eq_zero : + (X ^ (2 ^ 48) + X) % definingPolynomial = 0 := by + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_48_mod_eq, r48_eq_X, X_mod_definingPolynomial] + simp only [CharTwo.add_self_eq_zero, EuclideanDomain.zero_mod] + +/-- Rabin trace divisibility condition for the GF48 candidate polynomial. -/ +lemma X_pow_2_pow_48_add_X_dvd : + definingPolynomial ∣ X ^ (2 ^ 48) + X := by + rw [← EuclideanDomain.mod_eq_zero] + exact X_pow_2_pow_48_add_X_mod_eq_zero + +end GF2_48 diff --git a/CompPoly/Fields/Binary/GF2_64.lean b/CompPoly/Fields/Binary/GF2_64.lean new file mode 100644 index 00000000..ad58a3d2 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64.lean @@ -0,0 +1,16 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_64.Prelude +import CompPoly.Fields.Binary.GF2_64.Basic +import CompPoly.Fields.Binary.GF2_64.Impl +import CompPoly.Fields.Binary.GF2_64.XPowTwoPowModCertificate +import CompPoly.Fields.Binary.GF2_64.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_64.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_64.Primitive +import CompPoly.Fields.Binary.GF2_64.RootContexts + +/-! # GF(2^64) Binary Field Facade -/ diff --git a/CompPoly/Fields/Binary/GF2_64/Basic.lean b/CompPoly/Fields/Binary/GF2_64/Basic.lean new file mode 100644 index 00000000..ab70c229 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/Basic.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Basic +import CompPoly.Fields.Binary.GF2_64.Prelude + +/-! +# GF(2^64) Quotient Specification + +The quotient/specification carrier for the candidate polynomial +`X ^ 64 + X ^ 4 + X ^ 3 + X + 1`. + +Field, finite, characteristic, and cardinality instances are conditional on the +irreducibility certificate that will be provided by the concrete certificate +modules. +-/ + +namespace GF2_64 + +open Polynomial AdjoinRoot + +noncomputable section + +/-- Quotient/specification carrier for `GF(2^64)`. -/ +abbrev SpecField : Type := + BinaryField.Extension.SpecField definingPolynomialData + +private instance instIrreduciblePolynomialFact [Fact (Irreducible definingPolynomial)] : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using (inferInstance : Fact (Irreducible definingPolynomial)) + +/-- Conditional field instance, available once irreducibility is certified. -/ +instance instFieldSpecField [Fact (Irreducible definingPolynomial)] : + Field SpecField := + inferInstanceAs (Field (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional nontriviality, available once irreducibility is certified. -/ +instance instNontrivialSpecField [Fact (Irreducible definingPolynomial)] : + Nontrivial SpecField := + inferInstance + +/-- Quotient/specification carrier is inhabited. -/ +instance instInhabitedSpecField : Inhabited SpecField := + inferInstance + +/-- Algebra structure over `GF(2)`. -/ +instance instAlgebraSpecField : Algebra (ZMod 2) SpecField := + inferInstanceAs (Algebra (ZMod 2) (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional characteristic-two instance, available once irreducibility is certified. -/ +instance instCharTwoSpecField [Fact (Irreducible definingPolynomial)] : + CharP SpecField 2 := + inferInstance + +/-- Canonical embedding of `GF(2)` into `SpecField`. -/ +def ofGF2 : ZMod 2 →+* SpecField := + BinaryField.Extension.ofGF2 definingPolynomialData + +/-- The quotient root/generator. -/ +def root : SpecField := + BinaryField.Extension.root definingPolynomialData + +/-- The quotient root satisfies the defining polynomial. -/ +theorem root_satisfies_definingPolynomial : + Polynomial.eval₂ (algebraMap (ZMod 2) SpecField) root definingPolynomial = 0 := + BinaryField.Extension.root_satisfies_polynomial definingPolynomialData + +/-- Conditional finite type, available once irreducibility is certified. -/ +instance instFintypeSpecField [Fact (Irreducible definingPolynomial)] : + Fintype SpecField := + inferInstanceAs (Fintype (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Cardinality of the certified quotient specification. -/ +theorem SpecField_card [Fact (Irreducible definingPolynomial)] : + Fintype.card SpecField = 2 ^ extensionDegree := + BinaryField.Extension.specField_card definingPolynomialData + +end + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_64/Impl.lean b/CompPoly/Fields/Binary/GF2_64/Impl.lean new file mode 100644 index 00000000..6e0114ca --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/Impl.lean @@ -0,0 +1,365 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Impl +import CompPoly.Fields.Binary.GF2_64.Basic +import Mathlib.Algebra.Algebra.ZMod +import Mathlib.Algebra.CharP.CharAndCard +import Init.Data.Array.Lemmas + +/-! +# GF(2^64) Executable Bit-Vector Operations + +Executable operations for the `GF(2^64)` candidate polynomial +`X ^ 64 + X ^ 4 + X ^ 3 + X + 1`. + +This file exposes the raw `BitVec` carrier and arithmetic definitions. It does +claim the certified `Field` instance conditionally on the irreducibility +certificate supplied by `GF2_64.Primitive`. +-/ + +namespace GF2_64 + +namespace Concrete + +/-- Executable parameters for the `GF(2^64)` candidate polynomial. -/ +def params : BinaryField.Extension.ExecutableParams where + degree := extensionDegree + tailExponents := [0, 1, 3, 4] + tailExponents_bound := by + intro exponent h + simp at h + rcases h with rfl | rfl | rfl | rfl <;> unfold extensionDegree <;> omega + +/-- The executable tail list denotes the low-degree part of the GF64 polynomial. -/ +lemma definingPolynomial_eq_executableSparse : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ params.degree + + BinaryField.Extension.sparsePolynomial params.tailExponents := by + rw [show BinaryField.Extension.polynomial definingPolynomialData = definingPolynomial by rfl] + rw [definingPolynomial_eq_X_pow_add_tail] + simp [params, extensionDegree, definingTail, BinaryField.Extension.sparsePolynomial] + ring_nf + +end Concrete + +/-- Executable bit-vector carrier for `GF(2^64)`. -/ +@[reducible] +def ConcreteField : Type := + BinaryField.Extension.ConcreteField Concrete.params + +namespace ConcreteField + +abbrev rawWidth : Nat := + extensionDegree + +def toBitVec : ConcreteField → B64 := + BinaryField.Extension.Concrete.toBitVec Concrete.params + +def ofBitVec : B64 → ConcreteField := + BinaryField.Extension.Concrete.ofBitVec Concrete.params + +def toNat : ConcreteField → Nat := + BinaryField.Extension.Concrete.toNat Concrete.params + +def ofNat (x : Nat) : ConcreteField := + BinaryField.Extension.Concrete.ofNat Concrete.params x + +def root : ConcreteField := + BinaryField.Extension.Concrete.root Concrete.params + +def add : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.add Concrete.params + +def mul : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.mul Concrete.params + +def square : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.square Concrete.params + +def pow : ConcreteField → Nat → ConcreteField := + BinaryField.Extension.Concrete.pow Concrete.params + +def inv : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.inv Concrete.params + +def traceValue : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.traceValue Concrete.params + +def polynomialBasis : Array ConcreteField := + BinaryField.Extension.Concrete.polynomialBasis Concrete.params + +def baseConstants : Array ConcreteField := + BinaryField.Extension.Concrete.baseConstants Concrete.params + +noncomputable def toSpec : ConcreteField → SpecField := + BinaryField.Extension.Concrete.toSpec Concrete.params (data := definingPolynomialData) + +instance : BEq ConcreteField := + BinaryField.Extension.Concrete.instBEqConcreteField Concrete.params + +instance : LawfulBEq ConcreteField := + BinaryField.Extension.Concrete.instLawfulBEqConcreteField Concrete.params + +instance : Inhabited ConcreteField := + BinaryField.Extension.Concrete.instInhabitedConcreteField Concrete.params + +instance : Zero ConcreteField := + BinaryField.Extension.Concrete.instZeroConcreteField Concrete.params + +instance : One ConcreteField := + BinaryField.Extension.Concrete.instOneConcreteField Concrete.params + +instance : Add ConcreteField := + BinaryField.Extension.Concrete.instAddConcreteField Concrete.params + +instance : Neg ConcreteField := + BinaryField.Extension.Concrete.instNegConcreteField Concrete.params + +instance : Sub ConcreteField := + BinaryField.Extension.Concrete.instSubConcreteField Concrete.params + +instance : Mul ConcreteField := + BinaryField.Extension.Concrete.instMulConcreteField Concrete.params + +instance : Pow ConcreteField Nat := + BinaryField.Extension.Concrete.instPowConcreteField Concrete.params + +instance : Inv ConcreteField := + BinaryField.Extension.Concrete.instInvConcreteField Concrete.params + +/-- Certified executable field structure for `GF(2^64)`. -/ +instance (priority := 2000) instFieldConcreteField + [Fact (Irreducible definingPolynomial)] : + Field ConcreteField := by + haveI : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using + (inferInstance : Fact (Irreducible definingPolynomial)) + let hP : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ Concrete.params.degree + + BinaryField.Extension.sparsePolynomial Concrete.params.tailExponents := + Concrete.definingPolynomial_eq_executableSparse + let hP_degree : + (BinaryField.Extension.polynomial definingPolynomialData).degree = + Concrete.params.degree := by + simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + let hDegree_pos : 0 < Concrete.params.degree := by + unfold Concrete.params extensionDegree + norm_num + exact + { toDivisionRing := + { toRing := + { add := BinaryField.Extension.Concrete.add Concrete.params + zero := BinaryField.Extension.Concrete.zero Concrete.params + neg := BinaryField.Extension.Concrete.neg Concrete.params + sub := BinaryField.Extension.Concrete.sub Concrete.params + mul := BinaryField.Extension.Concrete.mul Concrete.params + one := BinaryField.Extension.Concrete.one Concrete.params + nsmul := fun m x => + if m % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + zsmul := fun m x => + if m % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + npow := fun m x => BinaryField.Extension.Concrete.pow Concrete.params x m + add_assoc := BinaryField.Extension.Concrete.add_assoc Concrete.params + add_comm := BinaryField.Extension.Concrete.add_comm Concrete.params + add_zero := BinaryField.Extension.Concrete.add_zero Concrete.params + zero_add := BinaryField.Extension.Concrete.zero_add Concrete.params + neg_add_cancel := BinaryField.Extension.Concrete.neg_add_cancel Concrete.params + sub_eq_add_neg := by intro _ _; rfl + nsmul_zero := fun _ => rfl + nsmul_succ := BinaryField.Extension.Concrete.nsmul_succ Concrete.params + zsmul_zero' := fun _ => rfl + zsmul_succ' := BinaryField.Extension.Concrete.zsmul_succ Concrete.params + zsmul_neg' := BinaryField.Extension.Concrete.zsmul_neg Concrete.params + mul_assoc := + BinaryField.Extension.Concrete.mul_assoc_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + one_mul := + BinaryField.Extension.Concrete.one_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_one := + BinaryField.Extension.Concrete.mul_one_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + left_distrib := + BinaryField.Extension.Concrete.left_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + right_distrib := + BinaryField.Extension.Concrete.right_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + zero_mul := + BinaryField.Extension.Concrete.zero_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_zero := + BinaryField.Extension.Concrete.mul_zero_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + natCast := BinaryField.Extension.Concrete.natCast Concrete.params + natCast_zero := BinaryField.Extension.Concrete.natCast_zero Concrete.params + natCast_succ := BinaryField.Extension.Concrete.natCast_succ Concrete.params + intCast := BinaryField.Extension.Concrete.intCast Concrete.params + intCast_ofNat := BinaryField.Extension.Concrete.intCast_ofNat Concrete.params + intCast_negSucc := BinaryField.Extension.Concrete.intCast_negSucc Concrete.params + npow_zero := by + intro x + change BinaryField.Extension.Concrete.pow Concrete.params x 0 = + BinaryField.Extension.Concrete.one Concrete.params + simp [BinaryField.Extension.Concrete.pow] + npow_succ := by + intro m x + change BinaryField.Extension.Concrete.pow Concrete.params x (m + 1) = + BinaryField.Extension.Concrete.mul Concrete.params + (BinaryField.Extension.Concrete.pow Concrete.params x m) x + exact BinaryField.Extension.Concrete.pow_succ_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos m x } + inv := BinaryField.Extension.Concrete.inv Concrete.params + div := fun a b => + BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params b) + exists_pair_ne := + BinaryField.Extension.Concrete.exists_pair_ne Concrete.params hDegree_pos + mul_inv_cancel := by + intro a h + change BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params a) = + BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.mul_inv_cancel_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a (by simpa using h) + inv_zero := by + change BinaryField.Extension.Concrete.inv Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = + BinaryField.Extension.Concrete.zero Concrete.params + exact BinaryField.Extension.Concrete.inv_zero Concrete.params + div_eq_mul_inv := by + intro a b + rfl + qsmul := _ + nnqsmul := _ } + mul_comm := by + intro a b + change BinaryField.Extension.Concrete.mul Concrete.params a b = + BinaryField.Extension.Concrete.mul Concrete.params b a + exact BinaryField.Extension.Concrete.mul_comm_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a b } + +noncomputable instance : Fintype ConcreteField := + BinaryField.Extension.Concrete.instFintypeConcreteField Concrete.params + +instance : Finite ConcreteField := + BinaryField.Extension.Concrete.instFiniteConcreteField Concrete.params + +/-- The raw executable carrier has `2^64` bit-patterns. -/ +theorem card : + Fintype.card ConcreteField = 2 ^ extensionDegree := by + simpa [Concrete.params] using + BinaryField.Extension.Concrete.concreteField_card Concrete.params + +/-- The certified executable carrier has characteristic two. -/ +noncomputable instance instCharTwoConcreteField [Fact (Irreducible definingPolynomial)] : + CharP ConcreteField 2 := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : IsDomain ConcreteField := Field.isDomain + haveI : Fact (Nat.Prime 2) := ⟨Nat.prime_two⟩ + exact charP_of_card_eq_prime_pow (R := ConcreteField) (p := 2) + (f := extensionDegree) card + +/-- Canonical `GF(2)` algebra structure on the certified executable carrier. -/ +noncomputable instance instAlgebraConcreteField [Fact (Irreducible definingPolynomial)] : + Algebra (ZMod 2) ConcreteField := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : CharP ConcreteField 2 := instCharTwoConcreteField + exact ZMod.algebra ConcreteField 2 + +@[simp] +theorem polynomialBasis_size : + polynomialBasis.size = extensionDegree := by + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis] + exact Array.size_ofFn + +@[simp] +theorem baseConstants_size : + baseConstants.size = 2 := by + simp [baseConstants, BinaryField.Extension.Concrete.baseConstants] + +theorem toSpec_injective : + Function.Injective toSpec := by + apply BinaryField.Extension.Concrete.toSpec_injective + · simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + · unfold Concrete.params extensionDegree + norm_num + +theorem toSpec_zero : + toSpec 0 = 0 := by + exact BinaryField.Extension.Concrete.toSpec_zero Concrete.params + +theorem toSpec_one : + toSpec 1 = 1 := by + exact BinaryField.Extension.Concrete.toSpec_one Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + +theorem toSpec_add (a b : ConcreteField) : + toSpec (a + b) = toSpec a + toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_add Concrete.params a b + +theorem toSpec_neg (a : ConcreteField) : + toSpec (-a) = -toSpec a := by + exact BinaryField.Extension.Concrete.toSpec_neg Concrete.params a + +theorem toSpec_sub (a b : ConcreteField) : + toSpec (a - b) = toSpec a - toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_sub Concrete.params a b + +theorem toSpec_mul (a b : ConcreteField) : + toSpec (a * b) = toSpec a * toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_mul Concrete.params + (data := definingPolynomialData) + Concrete.definingPolynomial_eq_executableSparse + (by simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree) + a b + +/-- Ring homomorphism from executable GF64 elements to the quotient specification. -/ +noncomputable def toSpecRingHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →+* SpecField where + toFun := toSpec + map_zero' := toSpec_zero + map_one' := toSpec_one + map_add' := toSpec_add + map_mul' := toSpec_mul + +/-- Algebra homomorphism from executable GF64 elements to the quotient specification. -/ +noncomputable def toSpecAlgHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →ₐ[ZMod 2] SpecField where + __ := toSpecRingHom + commutes' := by + intro r + exact RingHom.congr_fun + (RingHom.ext_zmod (toSpecRingHom.comp (algebraMap (ZMod 2) ConcreteField)) + (algebraMap (ZMod 2) SpecField)) r + +/-- Algebra equivalence between executable GF64 elements and the quotient specification. -/ +noncomputable def toSpecAlgEquiv [Fact (Irreducible definingPolynomial)] : + ConcreteField ≃ₐ[ZMod 2] SpecField := + AlgEquiv.ofBijective toSpecAlgHom <| by + apply Function.Injective.bijective_of_nat_card_le + · exact toSpec_injective + · rw [Nat.card_eq_fintype_card, Nat.card_eq_fintype_card] + rw [card, BinaryField.Extension.specField_card definingPolynomialData] + simp [definingPolynomialData, extensionDegree] + +/-- The executable polynomial-basis generator maps to the quotient root. -/ +theorem toSpec_root : + toSpec root = GF2_64.root := by + exact BinaryField.Extension.Concrete.toSpec_root Concrete.params + (data := definingPolynomialData) + (by unfold Concrete.params extensionDegree; norm_num) + +end ConcreteField + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_64/Prelude.lean b/CompPoly/Fields/Binary/GF2_64/Prelude.lean new file mode 100644 index 00000000..a4210b66 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/Prelude.lean @@ -0,0 +1,158 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Prelude +import Mathlib.Tactic.ComputeDegree + +/-! +# GF(2^64) Prelude + +Defining constants and small executable metadata for the direct binary extension +with candidate primitive polynomial + +`X ^ 64 + X ^ 4 + X ^ 3 + X + 1`. + +Irreducibility and primitive-order certificates are added in later `GF2_64` +modules before this polynomial is used to construct public field instances. +-/ + +namespace GF2_64 + +open Polynomial + +noncomputable section + +/-- Extension degree for `GF(2^64)`. -/ +def extensionDegree : Nat := + 64 + +/-- Raw executable carrier width for `GF(2^64)`. -/ +abbrev B64 : Type := + BitVec extensionDegree + +/-- Field cardinality of `GF(2^64)`. -/ +def fieldSize : Nat := + BinaryField.Extension.fieldSize extensionDegree + +/-- Multiplicative group order of `GF(2^64)`. -/ +def multiplicativeGroupOrder : Nat := + BinaryField.Extension.multiplicativeGroupOrder extensionDegree + +/-- Low-degree tail `X ^ 4 + X ^ 3 + X + 1`. -/ +def definingTail : Polynomial (ZMod 2) := + X ^ 4 + X ^ 3 + X + 1 + +/-- Candidate primitive polynomial bitmask: `X ^ 64 + X ^ 4 + X ^ 3 + X + 1`. -/ +def definingBitmask : Nat := + 0x1000000000000001b + +/-- Exponents with nonzero coefficients in the full defining polynomial. -/ +def definingPolynomialExponents : List Nat := + [0, 1, 3, 4, 64] + +/-- The tail has natural degree `4`. -/ +lemma definingTail_natDegree : + definingTail.natDegree = 4 := by + unfold definingTail + compute_degree! + +/-- The tail is monic. -/ +lemma definingTail_monic : + definingTail.Monic := by + unfold definingTail + monicity! + +/-- Metadata for the direct binary extension polynomial. -/ +def definingPolynomialData : BinaryField.Extension.DefiningPolynomialData where + degree := extensionDegree + tail := definingTail + tailDegree := 4 + bitmask := definingBitmask + tail_natDegree := definingTail_natDegree + tailDegree_lt_degree := by + unfold extensionDegree + omega + +/-- Candidate defining polynomial for `GF(2^64)`. -/ +def definingPolynomial : Polynomial (ZMod 2) := + BinaryField.Extension.polynomial definingPolynomialData + +/-- Expanded form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_X_pow_add_tail : + definingPolynomial = X ^ 64 + definingTail := by + rfl + +/-- Expanded sparse form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_sparse : + definingPolynomial = X ^ 64 + X ^ 4 + X ^ 3 + X + 1 := by + unfold definingPolynomial BinaryField.Extension.polynomial definingPolynomialData definingTail + extensionDegree + ring + +/-- The candidate defining polynomial is monic of degree `64`. -/ +lemma definingPolynomial_isMonicOfDegree : + IsMonicOfDegree definingPolynomial extensionDegree := + BinaryField.Extension.polynomial_isMonicOfDegree definingPolynomialData + +/-- The candidate defining polynomial has natural degree `64`. -/ +lemma definingPolynomial_natDegree : + definingPolynomial.natDegree = extensionDegree := + BinaryField.Extension.polynomial_natDegree definingPolynomialData + +/-- The candidate defining polynomial is monic. -/ +lemma definingPolynomial_monic : + definingPolynomial.Monic := + BinaryField.Extension.polynomial_monic definingPolynomialData + +/-- The candidate defining polynomial is nonzero. -/ +lemma definingPolynomial_ne_zero : + definingPolynomial ≠ 0 := + BinaryField.Extension.polynomial_ne_zero definingPolynomialData + +/-- The candidate defining polynomial has degree `64`. -/ +lemma definingPolynomial_degree : + definingPolynomial.degree = extensionDegree := + BinaryField.Extension.polynomial_degree definingPolynomialData + +/-- Bit-vector encoding of the candidate defining polynomial. -/ +def P_val : BitVec (2 * extensionDegree) := + (1 <<< 64) ^^^ (1 <<< 4) ^^^ (1 <<< 3) ^^^ (1 <<< 1) ^^^ 1 + +/-- The `BitVec` encoding denotes the candidate defining polynomial. -/ +lemma definingPolynomial_eq_P_val : + definingPolynomial = BinaryField.toPoly P_val := by + rw [definingPolynomial_eq_sparse] + unfold P_val extensionDegree + repeat rw [BinaryField.toPoly_xor] + rw [BinaryField.Extension.toPoly_one_shiftLeft 64 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 4 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 3 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 1 (by omega)] + rw [(show (1 : BitVec 128) = 1 <<< 0 by simp)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 0 (by omega)] + simp only [pow_zero, pow_one] + +/-- The exponent list denotes the candidate defining polynomial. -/ +lemma sparsePolynomial_definingPolynomialExponents : + BinaryField.Extension.sparsePolynomial definingPolynomialExponents = definingPolynomial := by + rw [definingPolynomial_eq_sparse] + simp [definingPolynomialExponents, BinaryField.Extension.sparsePolynomial] + ring_nf + +/-- Smooth subgroup refinement schedule for `2^64 - 1`. -/ +def smoothRootSchedule : Array Nat := + #[3, 5, 17, 257, 641, 65537, 6700417] + +/-- The GF64 smooth schedule refines the multiplicative group down to singleton cosets. -/ +lemma smoothRootSchedule_fold_eq_one : + smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (fieldSize - 1) = 1 := by + unfold smoothRootSchedule fieldSize BinaryField.Extension.fieldSize extensionDegree + decide + +end + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_64/Primitive.lean b/CompPoly/Fields/Binary/GF2_64/Primitive.lean new file mode 100644 index 00000000..0360ac5d --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/Primitive.lean @@ -0,0 +1,182 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_64.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_64.PrimitivePowerCertificate +import Mathlib.GroupTheory.OrderOfElement +import CompPoly.Fields.Binary.GF2_64.Impl + +/-! +# GF(2^64) Primitive-Order Scaffold + +Small primitive-order metadata and Rabin irreducibility certificate for the +`GF(2^64)` candidate. +-/ + +namespace GF2_64 + +set_option maxRecDepth 100000 + +/-- Distinct prime factors of `2^64 - 1`. -/ +def primitivePrimeFactors : List Nat := + [3, 5, 17, 257, 641, 65537, 6700417] + +/-- Factorization of the multiplicative-group order `2^64 - 1`. -/ +lemma multiplicativeGroupOrder_factorization : + multiplicativeGroupOrder = 3 * 5 * 17 * 257 * 641 * 65537 * 6700417 := by + unfold multiplicativeGroupOrder BinaryField.Extension.multiplicativeGroupOrder + BinaryField.Extension.fieldSize extensionDegree + norm_num + +/-- The GF2_64 candidate polynomial passes Rabin's irreducibility test. -/ +theorem definingPolynomial_irreducible : Irreducible definingPolynomial := + BinaryField.Extension.irreducible_of_rabin_64_passed_over_GF2 + definingPolynomial + (by simpa [extensionDegree] using definingPolynomial_natDegree) + X_pow_2_pow_64_add_X_dvd + rabin_gcd_condition_32 + +/-- Register the certified irreducibility fact for quotient-field instances. -/ +instance instIrreducibleDefiningPolynomial : Fact (Irreducible definingPolynomial) := + ⟨definingPolynomial_irreducible⟩ + +/-- Local kernel-safe primality certificate for the `65537` group-order factor. -/ +private theorem prime_65537 : Nat.Prime 65537 := by + rw [Nat.prime_def_le_sqrt] + constructor + · norm_num + · intro m hm2 hmsqrt hdvd + have hm_le_sq : m * m ≤ 65537 := (Nat.le_sqrt.mp hmsqrt) + have hm_le : m ≤ 256 := by + by_contra h + have hm257 : 257 ≤ m := by omega + have hsq : 257 * 257 ≤ m * m := Nat.mul_le_mul hm257 hm257 + omega + interval_cases m <;> norm_num at hdvd + +/-- Local kernel-safe primality certificate for the largest GF64 group-order factor. -/ +private theorem prime_6700417 : Nat.Prime 6700417 := by + rw [Nat.prime_def_le_sqrt] + constructor + · norm_num + · intro m hm2 hmsqrt hdvd + have hm_le_sq : m * m ≤ 6700417 := (Nat.le_sqrt.mp hmsqrt) + have hm_le : m ≤ 2588 := by + by_contra h + have hm2589 : 2589 ≤ m := by omega + have hsq : 2589 * 2589 ≤ m * m := Nat.mul_le_mul hm2589 hm2589 + omega + interval_cases m <;> norm_num at hdvd + +/-- Prime divisors of `fieldSize - 1` are exactly the certified prime factors. -/ +private lemma prime_dvd_fieldSize_sub_one_cases {p : Nat} + (hp : p.Prime) (hdvd : p ∣ fieldSize - 1) : + p = 3 ∨ p = 5 ∨ p = 17 ∨ p = 257 ∨ p = 641 ∨ p = 65537 ∨ p = 6700417 := by + have hpdvd : p ∣ multiplicativeGroupOrder := by + simpa [multiplicativeGroupOrder, BinaryField.Extension.multiplicativeGroupOrder] using hdvd + rw [multiplicativeGroupOrder_factorization] at hpdvd + rcases hp.dvd_mul.mp hpdvd with hpdvd | h6700417 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h65537 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h641 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h257 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h17 + · rcases hp.dvd_mul.mp hpdvd with h3 | h5 + · left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 3)).mp + h3 + · right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 5)).mp + h5 + · right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 17)).mp + h17 + · right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 257)).mp + h257 + · right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 641)).mp + h641 + · right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp prime_65537).mp + h65537 + · right + right + right + right + right + right + exact + (Nat.prime_dvd_prime_iff_eq hp prime_6700417).mp + h6700417 + +/-- Polynomial-basis generator used by smooth root contexts. -/ +def primitiveRoot : ConcreteField := + ConcreteField.root + +/-- The polynomial-basis generator is nonzero. -/ +theorem primitiveRoot_ne_zero : primitiveRoot ≠ (0 : ConcreteField) := by + unfold primitiveRoot ConcreteField.root BinaryField.Extension.Concrete.root + change BinaryField.Extension.Concrete.ofNat Concrete.params 2 ≠ + BinaryField.Extension.Concrete.zero Concrete.params + intro h + have hnat := congrArg (BinaryField.Extension.Concrete.toNat Concrete.params) h + rw [BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num)] at hnat + have hzero : + BinaryField.Extension.Concrete.toNat Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = 0 := by + unfold BinaryField.Extension.Concrete.zero + exact BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (n := 0) (by unfold Concrete.params extensionDegree; norm_num) + rw [hzero] at hnat + norm_num at hnat + +/-- The polynomial-basis generator has full multiplicative order. -/ +theorem primitiveRoot_order : orderOf primitiveRoot = fieldSize - 1 := by + let fieldInst : Field ConcreteField := ConcreteField.instFieldConcreteField + letI : Field ConcreteField := fieldInst + refine orderOf_eq_of_pow_and_pow_div_prime (n := fieldSize - 1) ?_ ?_ ?_ + · unfold fieldSize BinaryField.Extension.fieldSize extensionDegree + norm_num + · have hcard : Fintype.card ConcreteField = fieldSize := by + simpa [fieldSize] using ConcreteField.card + have hfermat := FiniteField.pow_card_sub_one_eq_one + (K := ConcreteField) primitiveRoot primitiveRoot_ne_zero + simpa [hcard] using hfermat + · intro p hp hdvd + rcases prime_dvd_fieldSize_sub_one_cases hp hdvd with + rfl | rfl | rfl | rfl | rfl | rfl | rfl + · simpa [primitiveRoot] using root_pow_div_3_ne_one + · simpa [primitiveRoot] using root_pow_div_5_ne_one + · simpa [primitiveRoot] using root_pow_div_17_ne_one + · simpa [primitiveRoot] using root_pow_div_257_ne_one + · simpa [primitiveRoot] using root_pow_div_641_ne_one + · simpa [primitiveRoot] using root_pow_div_65537_ne_one + · simpa [primitiveRoot] using root_pow_div_6700417_ne_one + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_64/PrimitivePowerCertificate.lean b/CompPoly/Fields/Binary/GF2_64/PrimitivePowerCertificate.lean new file mode 100644 index 00000000..77610e61 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/PrimitivePowerCertificate.lean @@ -0,0 +1,717 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_64.Impl +import Mathlib.Tactic.NormNum + +/-! +# GF2^64 Primitive-Power Certificates + +Generated structural power-chain certificates for the polynomial-basis +root. These certify the nontrivial prime-divisor powers used to prove +that the root has full multiplicative order. +-/ + +namespace GF2_64 + +set_option maxRecDepth 50000 + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (2, 4), + (5, 32), + (10, 1024), + (21, 2097152), + (42, 4398046511104), + (85, 56623104), + (170, 1429365116108800), + (341, 3668797554688), + (682, 365095035034053340), + (1365, 240410548471636640), + (2730, 4983231460161116188), + (5461, 4744244927560792685), + (10922, 12977174872011159626), + (21845, 5577735636430933375), + (43690, 11978056309670548770), + (87381, 8870512220009982119), + (174762, 9580854867404007525), + (349525, 283172313511053403), + (699050, 27333090561073285), + (1398101, 144458462052347636), + (2796202, 5001551169862247328), + (5592405, 7743719202701829493), + (11184810, 16134095663629651926), + (22369621, 14990400136725602578), + (44739242, 9084907874049376581), + (89478485, 2502479396378613473), + (178956970, 3278310103988839425), + (357913941, 6079615500721804652), + (715827882, 12660948147669634711), + (1431655765, 8980538088000184925), + (2863311530, 15308770099851454029), + (5726623061, 9025546545411214670), + (11453246122, 15365971086693523512), + (22906492245, 18436822897148651354), + (45812984490, 73602847640625433), + (91625968981, 2888497718686628154), + (183251937962, 7674217092863469891), + (366503875925, 10770255747030896017), + (733007751850, 10284975553068631936), + (1466015503701, 2636129607266100217), + (2932031007402, 7539747033546575770), + (5864062014805, 1523899303434289661), + (11728124029610, 6845236036137451414), + (23456248059221, 8661698266377926533), + (46912496118442, 15318281316170197782), + (93824992236885, 6153913113235778674), + (187649984473770, 12590900751084468504), + (375299968947541, 6241392359340867991), + (750599937895082, 13537483124624848846), + (1501199875790165, 4738027310139864785), + (3002399751580330, 11532633803407155562), + (6004799503160661, 8250739964050374057), + (12009599006321322, 15163568353485845146), + (24019198012642645, 8429364114987332836), + (48038396025285290, 15269178436121023499), + (96076792050570581, 17609702562285369574), + (192153584101141162, 193879326829526857), + (384307168202282325, 3095595981615055618), + (768614336404564650, 4520231837250186676), + (1537228672809129301, 16733099453633052576), + (3074457345618258602, 1986500647487271729), + (6148914691236517205, 1858076378458151938)] + +/-- Residue of `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Residue : Nat := + 1858076378458151938 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 3) rootPowDiv3Chain rootPowDiv3Residue = true := by + rfl + +private theorem root_pow_div_3_certified : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue ∧ + rootPowDiv3Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 3) + (cert := rootPowDiv3Chain) (expected := rootPowDiv3Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_3_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_eq : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue := + root_pow_div_3_certified.1 + +/-- The `3`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_3_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 3) ≠ (1 : ConcreteField) := by + rw [root_pow_div_3_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv3Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv3Residue] using root_pow_div_3_certified.2) + (by unfold rootPowDiv3Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (6, 64), + (12, 4096), + (25, 33554432), + (51, 2251799813685248), + (102, 7421703487488), + (204, 31158272), + (409, 741664247250944), + (819, 614742265454497112), + (1638, 1695209234734939115), + (3276, 775130197547892574), + (6553, 12537001131179822224), + (13107, 17615980313972881911), + (26214, 572385715309389091), + (52428, 4739272290175120857), + (104857, 13842492915490533145), + (209715, 13871847693897305998), + (419430, 8455439506674631074), + (838860, 9493498753804115715), + (1677721, 12169678962202302099), + (3355443, 17847407213643894547), + (6710886, 542118931229881903), + (13421772, 4954123332599001826), + (26843545, 4849497804619816645), + (53687091, 7658167510715674113), + (107374182, 11523011428416975302), + (214748364, 11029696507194194569), + (429496729, 13383781749761052059), + (858993459, 4736030129335515051), + (1717986918, 11825872944594744153), + (3435973836, 13303924860188256192), + (6871947673, 4721276808310060623), + (13743895347, 7501028808047771839), + (27487790694, 14970345159955071973), + (54975581388, 7349999157695252967), + (109951162777, 3538319141024286047), + (219902325555, 17194375590543073860), + (439804651110, 5645975784458735702), + (879609302220, 16291961861482157576), + (1759218604441, 13470997692184657978), + (3518437208883, 4717150064516401577), + (7036874417766, 17680995585741177905), + (14073748835532, 4823281833483465308), + (28147497671065, 14039441887863849435), + (56294995342131, 13861647657052316390), + (112589990684262, 8160990201683069433), + (225179981368524, 9736465841236211841), + (450359962737049, 650412515276143405), + (900719925474099, 10357861010334771266), + (1801439850948198, 10610728455063578357), + (3602879701896396, 9972857463710343756), + (7205759403792793, 12671927713076749239), + (14411518807585587, 17736012934613873235), + (28823037615171174, 1340234834950776819), + (57646075230342348, 827128078216238258), + (115292150460684697, 12632352266407194960), + (230584300921369395, 6245875499889307641), + (461168601842738790, 18149135383924833834), + (922337203685477580, 339314029946848734), + (1844674407370955161, 12233269549184699558), + (3689348814741910323, 6753221685647269129)] + +/-- Residue of `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Residue : Nat := + 6753221685647269129 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 5) rootPowDiv5Chain rootPowDiv5Residue = true := by + rfl + +private theorem root_pow_div_5_certified : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue ∧ + rootPowDiv5Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 5) + (cert := rootPowDiv5Chain) (expected := rootPowDiv5Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_5_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_eq : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue := + root_pow_div_5_certified.1 + +/-- The `5`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_5_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 5) ≠ (1 : ConcreteField) := by + rw [root_pow_div_5_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv5Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv5Residue] using root_pow_div_5_certified.2) + (by unfold rootPowDiv5Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (7, 128), + (15, 32768), + (30, 1073741824), + (60, 1152921504606846976), + (120, 1945555039024054272), + (240, 2141180147837960192), + (481, 4096988742676381696), + (963, 16397284557568314936), + (1927, 12883440346528595156), + (3855, 5502357835101356655), + (7710, 11971056134035252030), + (15420, 17999049644792178958), + (30840, 6110368521546413774), + (61680, 18133241910698190584), + (123361, 9358888601177629748), + (246723, 2889815726003302671), + (493447, 6172354125460813092), + (986895, 18265286746424954883), + (1973790, 5002322587161575919), + (3947580, 17649500154884868153), + (7895160, 284318660805990683), + (15790320, 5773639088123718213), + (31580641, 6097997731130832313), + (63161283, 16127198964082528943), + (126322567, 14997240368184985798), + (252645135, 8944283063646812964), + (505290270, 9598693700748772119), + (1010580540, 9276046253884316239), + (2021161080, 10467175751356451512), + (4042322160, 14937230767959529837), + (8084644321, 17054372478629103640), + (16169288643, 1605532020783822772), + (32338577287, 10742001702566384374), + (64677154575, 3881597435267773023), + (129354309150, 7397277944650245694), + (258708618300, 15699530505333446804), + (517417236600, 3208881070711777873), + (1034834473200, 7652414838927637418), + (2069668946401, 11491186187456768165), + (4139337892803, 11144026633947481581), + (8278675785607, 13357662386041159221), + (16557351571215, 7140415565801644003), + (33114703142430, 15593444141465942046), + (66229406284860, 7534953760740305829), + (132458812569720, 15763600732378596822), + (264917625139440, 4372767040240876693), + (529835250278881, 6973635062753595202), + (1059670500557763, 10965820371697859397), + (2119341001115527, 11070541345736729347), + (4238682002231055, 13335704236759936587), + (8477364004462110, 12811155757958806980), + (16954728008924220, 13121633050386294417), + (33909456017848440, 16329222712584433963), + (67818912035696880, 6641557631996314280), + (135637824071393761, 8856607681970768885), + (271275648142787523, 10087666430596238049), + (542551296285575047, 10187180005000642125), + (1085102592571150095, 934417933708345563)] + +/-- Residue of `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Residue : Nat := + 934417933708345563 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 17) rootPowDiv17Chain rootPowDiv17Residue = true := by + rfl + +private theorem root_pow_div_17_certified : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue ∧ + rootPowDiv17Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 17) + (cert := rootPowDiv17Chain) (expected := rootPowDiv17Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_17_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_eq : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue := + root_pow_div_17_certified.1 + +/-- The `17`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_17_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 17) ≠ (1 : ConcreteField) := by + rw [root_pow_div_17_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv17Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv17Residue] using root_pow_div_17_certified.2) + (by unfold rootPowDiv17Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 257)`. -/ +def rootPowDiv257Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (7, 128), + (15, 32768), + (31, 2147483648), + (63, 9223372036854775808), + (127, 9223372036854775983), + (255, 9223372036854810629), + (510, 13835058056360099915), + (1020, 6917546619827130372), + (2040, 15852670688780353547), + (4080, 7868914448923099140), + (8160, 15810861415100579851), + (16320, 7905746674450609924), + (32640, 10050318714223441623), + (65280, 14048561813064617288), + (130561, 14003573154494000564), + (261123, 16199998851856285484), + (522247, 11143697931309953068), + (1044495, 13510782506780650327), + (2088991, 4712324870270884331), + (4177983, 16725579547643685031), + (8355967, 13054416880880094150), + (16711935, 14230917241974333543), + (33423870, 8426113191624343295), + (66847740, 10589962743355204133), + (133695480, 10033763316657226832), + (267390960, 15489626251543104045), + (534781920, 7755012294843499644), + (1069563840, 16043379140506339467), + (2139127680, 2909041589022223219), + (4278255360, 3158690311495552990), + (8556510721, 17816484055161149936), + (17113021443, 550917475208425946), + (34226042887, 2381130819332677936), + (68452085775, 17923778717675082454), + (136904171551, 9441773188340007204), + (273808343103, 598593371972789903), + (547616686207, 1126265079727325354), + (1095233372415, 2595017038785196166), + (2190466744830, 8783238042965782547), + (4380933489660, 10780590433868302274), + (8761866979320, 11455074362790071365), + (17523733958640, 9892809175183578955), + (35047467917280, 10848035612234666456), + (70094935834560, 10348927729312353217), + (140189871669120, 15426110064449967963), + (280379743338240, 9141563848451407107), + (560759486676481, 2458669077384804607), + (1121518973352963, 8852555409678609060), + (2243037946705927, 9473033605397112885), + (4486075893411855, 785751923792335491), + (8972151786823711, 422266354773421490), + (17944303573647423, 862573781629307622), + (35888607147294847, 12486372504028562856), + (71777214294589695, 6259950186334376129)] + +/-- Residue of `root ^ ((fieldSize - 1) / 257)`. -/ +def rootPowDiv257Residue : Nat := + 6259950186334376129 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 257)`. -/ +theorem root_pow_div_257_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 257) rootPowDiv257Chain rootPowDiv257Residue = true := by + rfl + +private theorem root_pow_div_257_certified : + ConcreteField.root ^ ((fieldSize - 1) / 257) = + ConcreteField.ofNat rootPowDiv257Residue ∧ + rootPowDiv257Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 257) + (cert := rootPowDiv257Chain) (expected := rootPowDiv257Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_257_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 257)`. -/ +theorem root_pow_div_257_eq : + ConcreteField.root ^ ((fieldSize - 1) / 257) = + ConcreteField.ofNat rootPowDiv257Residue := + root_pow_div_257_certified.1 + +/-- The `257`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_257_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 257) ≠ (1 : ConcreteField) := by + rw [root_pow_div_257_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv257Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv257Residue] using root_pow_div_257_certified.2) + (by unfold rootPowDiv257Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 641)`. -/ +def rootPowDiv641Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (6, 64), + (12, 4096), + (25, 33554432), + (51, 2251799813685248), + (102, 7421703487488), + (204, 31158272), + (408, 370832123625472), + (817, 153685566363624278), + (1635, 2517744163555561342), + (3271, 15012202378562382320), + (6543, 18170756862725007674), + (13086, 28199878090168517), + (26173, 11539237407358712012), + (52347, 18023503466788146575), + (104694, 48757091473971919), + (209388, 6149641648998841173), + (418776, 13739051797956841741), + (837552, 11551731855768840976), + (1675104, 13566235451271814125), + (3350208, 12781674114376263099), + (6700416, 13190719059879418216), + (13400833, 14343415190391100335), + (26801667, 5263586565831700496), + (53603335, 7860653167533373869), + (107206671, 3914786640680795407), + (214413343, 14968100261656620540), + (428826687, 16432308167853118202), + (857653375, 1252147369269413764), + (1715306751, 11429910066283625334), + (3430613503, 3476658674257064401), + (6861227006, 2526626407823178929), + (13722454012, 4333324053496131505), + (27444908025, 6945386695125100898), + (54889816051, 3470921799577998237), + (109779632102, 3694476400150069537), + (219559264204, 8242345632324104925), + (439118528409, 3338064937220306103), + (878237056819, 9086958808615604772), + (1756474113639, 11536026967193564013), + (3512948227278, 17961562390662465996), + (7025896454556, 1503820422458456737), + (14051792909112, 5666422559142507185), + (28103585818224, 17535602372484461485), + (56207171636449, 307779687151503054), + (112414343272898, 5039797362426662984), + (224828686545796, 16265052519128305756), + (449657373091593, 4184382385916090284), + (899314746183187, 16823370750287228992), + (1798629492366375, 4584384662368261762), + (3597258984732751, 7641397096994770438), + (7194517969465503, 3841587427645904613), + (14389035938931007, 14266695536909557140), + (28778071877862015, 7779978215417873058)] + +/-- Residue of `root ^ ((fieldSize - 1) / 641)`. -/ +def rootPowDiv641Residue : Nat := + 7779978215417873058 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 641)`. -/ +theorem root_pow_div_641_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 641) rootPowDiv641Chain rootPowDiv641Residue = true := by + rfl + +private theorem root_pow_div_641_certified : + ConcreteField.root ^ ((fieldSize - 1) / 641) = + ConcreteField.ofNat rootPowDiv641Residue ∧ + rootPowDiv641Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 641) + (cert := rootPowDiv641Chain) (expected := rootPowDiv641Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_641_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 641)`. -/ +theorem root_pow_div_641_eq : + ConcreteField.root ^ ((fieldSize - 1) / 641) = + ConcreteField.ofNat rootPowDiv641Residue := + root_pow_div_641_certified.1 + +/-- The `641`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_641_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 641) ≠ (1 : ConcreteField) := by + rw [root_pow_div_641_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv641Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv641Residue] using root_pow_div_641_certified.2) + (by unfold rootPowDiv641Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 65537)`. -/ +def rootPowDiv65537Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (3, 8), + (7, 128), + (15, 32768), + (31, 2147483648), + (63, 9223372036854775808), + (127, 9223372036854775983), + (255, 9223372036854810629), + (511, 9223372039010648205), + (1023, 140737488388109), + (2047, 55834575010), + (4095, 34526), + (8191, 2150146728), + (16383, 9223381384985872512), + (32767, 36029349141217455), + (65535, 9272771591053052074), + (131070, 13836935268454033522), + (262140, 2305862589952212549), + (524280, 4131020304175097613), + (1048560, 6957704021784009441), + (2097120, 11048036110380782337), + (4194240, 11014396488249292615), + (8388480, 10143929262081728584), + (16776960, 15521217246677174957), + (33553920, 4312069708791884235), + (67107840, 2424478959916259118), + (134215680, 4330396582168917476), + (268431360, 3490387098519200791), + (536862720, 3626688616775211641), + (1073725440, 2462619771810090993), + (2147450880, 3182121027457317229), + (4294901760, 7742038277098398358), + (8589803521, 13819056402066206571), + (17179607043, 13871343205798092101), + (34359214087, 5334375927601494808), + (68718428175, 16677394170408557005), + (137436856351, 3676534277026740430), + (274873712703, 16638137442702143088), + (549747425407, 10454565298279346484), + (1099494850815, 3896800843627850369), + (2198989701631, 8005321385189303170), + (4397979403263, 1597716869343557885), + (8795958806527, 4015086932901931308), + (17591917613055, 4972478849236428280), + (35183835226111, 7166537877424996291), + (70367670452223, 1787838675202753407), + (140735340904447, 1235365684474725500), + (281470681808895, 2026190363967203278)] + +/-- Residue of `root ^ ((fieldSize - 1) / 65537)`. -/ +def rootPowDiv65537Residue : Nat := + 2026190363967203278 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 65537)`. -/ +theorem root_pow_div_65537_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 65537) rootPowDiv65537Chain rootPowDiv65537Residue = true := by + rfl + +private theorem root_pow_div_65537_certified : + ConcreteField.root ^ ((fieldSize - 1) / 65537) = + ConcreteField.ofNat rootPowDiv65537Residue ∧ + rootPowDiv65537Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 65537) + (cert := rootPowDiv65537Chain) (expected := rootPowDiv65537Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_65537_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 65537)`. -/ +theorem root_pow_div_65537_eq : + ConcreteField.root ^ ((fieldSize - 1) / 65537) = + ConcreteField.ofNat rootPowDiv65537Residue := + root_pow_div_65537_certified.1 + +/-- The `65537`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_65537_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 65537) ≠ (1 : ConcreteField) := by + rw [root_pow_div_65537_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv65537Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv65537Residue] using root_pow_div_65537_certified.2) + (by unfold rootPowDiv65537Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 6700417)`. -/ +def rootPowDiv6700417Chain : List (Nat × Nat) := + [(0, 1), + (1, 2), + (2, 4), + (5, 32), + (10, 1024), + (20, 1048576), + (40, 1099511627776), + (80, 1769472), + (160, 1395864371200), + (320, 1749419), + (640, 1392727114821), + (1281, 2315413167550055234), + (2563, 14988220327703224528), + (5127, 15996786455491289562), + (10255, 8805137778939470258), + (20511, 277233553980940197), + (41023, 11736513695949326074), + (82047, 6554630823350282655), + (164095, 15806666150837387953), + (328191, 8351919345915834966), + (656383, 10252510146753435987), + (1312767, 1060966642988709669), + (2625535, 2753893685143373178), + (5251071, 18129492098565621510), + (10502143, 3152972240194895986), + (21004287, 15558470632917411048), + (42008575, 6848318466046628716), + (84017151, 8082878837150412909), + (168034303, 9550010875068132311), + (336068607, 2985619513454219229), + (672137215, 15390803841133607572), + (1344274431, 6769929685099678786), + (2688548863, 6543875676375545373), + (5377097726, 16783560468053995857), + (10754195453, 13235724490548147288), + (21508390906, 12074620434524055146), + (43016781813, 15249642109578593833), + (86033563627, 8377108833218422510), + (172067127255, 1144969938178970419), + (344134254511, 9694755075876601732), + (688268509023, 12375203333100091535), + (1376537018047, 9026313549350721747), + (2753074036095, 69034349764540817)] + +/-- Residue of `root ^ ((fieldSize - 1) / 6700417)`. -/ +def rootPowDiv6700417Residue : Nat := + 69034349764540817 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 6700417)`. -/ +theorem root_pow_div_6700417_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 6700417) rootPowDiv6700417Chain rootPowDiv6700417Residue = true := by + rfl + +private theorem root_pow_div_6700417_certified : + ConcreteField.root ^ ((fieldSize - 1) / 6700417) = + ConcreteField.ofNat rootPowDiv6700417Residue ∧ + rootPowDiv6700417Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 6700417) + (cert := rootPowDiv6700417Chain) (expected := rootPowDiv6700417Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_6700417_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 6700417)`. -/ +theorem root_pow_div_6700417_eq : + ConcreteField.root ^ ((fieldSize - 1) / 6700417) = + ConcreteField.ofNat rootPowDiv6700417Residue := + root_pow_div_6700417_certified.1 + +/-- The `6700417`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_6700417_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 6700417) ≠ (1 : ConcreteField) := by + rw [root_pow_div_6700417_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv6700417Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv6700417Residue] using root_pow_div_6700417_certified.2) + (by unfold rootPowDiv6700417Residue; norm_num) + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_64/RootContexts.lean b/CompPoly/Fields/Binary/GF2_64/RootContexts.lean new file mode 100644 index 00000000..bd8d8eba --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/RootContexts.lean @@ -0,0 +1,248 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_64.Primitive +import CompPoly.Fields.Binary.Extension.Enumeration +import CompPoly.Univariate.Roots.Context +import CompPoly.Univariate.Roots.Shoup.Basic +import CompPoly.Univariate.Roots.SmoothSubgroup +import Mathlib.FieldTheory.Finite.Trace + +/-! +# GF(2^64) Root-Search Contexts + +Certified finite-field context for the executable `GF(2^64)` carrier. +-/ + +namespace GF2_64 + +open CompPoly +open CompPoly.CPolynomial.Roots.FiniteField + +private theorem exists_basis_trace_ne {K L ι : Type*} [Field K] [Field L] [Algebra K L] + [FiniteDimensional K L] [Algebra.IsSeparable K L] + (b : Module.Basis ι K L) {x : L} (hx : x ≠ 0) : + ∃ i, Algebra.trace K L (b i * x) ≠ 0 := by + have hnd := (traceForm_nondegenerate K L).1 x + by_contra hnone + push Not at hnone + have hzero : (Algebra.traceForm K L) x = 0 := by + apply b.ext + intro i + rw [Algebra.traceForm_apply] + simpa [mul_comm] using hnone i + exact hx (hnd (by + intro y + rw [hzero] + rfl)) + +/-- Finite-field context for the executable `GF(2^64)` carrier. -/ +def finiteFieldContext : + CompPoly.CPolynomial.Roots.FiniteField.FiniteFieldContext ConcreteField where + q := fieldSize + finite := by infer_instance + card_eq := by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card + frobenius_fixed := by + intro a + have hcard : Fintype.card ConcreteField = fieldSize := by + exact ConcreteField.card + simpa [hcard] using FiniteField.pow_card a + +/-- Lazy complete enumeration for `GF(2^64)`. -/ +def fieldEnumeration : + CompPoly.CPolynomial.Roots.FiniteField.FieldEnumeration ConcreteField := + BinaryField.Extension.Concrete.fieldEnumeration Concrete.params + +namespace ConcreteField + +local instance fieldInst : Field ConcreteField := + instFieldConcreteField + +local instance commRingInst : CommRing ConcreteField := + fieldInst.toCommRing + +noncomputable local instance algebraInst : Algebra (ZMod 2) ConcreteField := + instAlgebraConcreteField + +/-- Algebraic trace value embedded back into executable `GF(2^64)`. -/ +noncomputable def algebraicTraceValue (z : ConcreteField) : ConcreteField := + algebraMap (ZMod 2) ConcreteField (Algebra.trace (ZMod 2) ConcreteField z) + +/-- The executable GF64 carrier has dimension `64` over `GF(2)`. -/ +theorem finrank_eq_extensionDegree : + Module.finrank (ZMod 2) ConcreteField = extensionDegree := by + have h := FiniteField.pow_finrank_eq_card (p := 2) (k := ConcreteField) + rw [card] at h + exact Nat.pow_right_injective (by norm_num : 1 < 2) h + +/-- The algebraic trace equals the Shoup Frobenius power sum. -/ +theorem algebraicTraceValue_eq_powerSum (z : ConcreteField) : + algebraicTraceValue z = tracePowerSum 2 extensionDegree z := by + unfold algebraicTraceValue + have htrace := FiniteField.algebraMap_trace_eq_sum_pow (ZMod 2) ConcreteField z + rw [finrank_eq_extensionDegree] at htrace + rw [htrace] + rw [tracePowerSum_eq_sum_range] + simp + +/-- The GF64 trace lands in the embedded `GF(2)` constants. -/ +theorem algebraicTraceValue_mem_base (z : ConcreteField) : + algebraicTraceValue z ∈ baseConstants.toList := by + unfold algebraicTraceValue baseConstants BinaryField.Extension.Concrete.baseConstants + let t : ZMod 2 := Algebra.trace (ZMod 2) ConcreteField z + change algebraMap (ZMod 2) ConcreteField t ∈ + [BinaryField.Extension.Concrete.zero Concrete.params, + BinaryField.Extension.Concrete.one Concrete.params] + have ht : ∀ u : ZMod 2, u = 0 ∨ u = 1 := by + intro u + fin_cases u + · left + rfl + · right + rfl + rcases ht t with ht0 | ht1 + · rw [ht0, map_zero] + left + · rw [ht1, map_one] + right + left + +/-- The transported quotient power basis for executable `GF(2^64)`. -/ +noncomputable def polynomialPowerBasis : PowerBasis (ZMod 2) ConcreteField := + (AdjoinRoot.powerBasis (BinaryField.Extension.polynomial_ne_zero definingPolynomialData)).map + toSpecAlgEquiv.symm + +@[simp] +theorem polynomialPowerBasis_dim_eq : + polynomialPowerBasis.dim = extensionDegree := by + simp [polynomialPowerBasis, BinaryField.Extension.polynomial_natDegree, + definingPolynomialData, extensionDegree] + +/-- The executable polynomial basis as a Lean basis. -/ +noncomputable def polynomialBasisBasis : + Module.Basis (Fin extensionDegree) (ZMod 2) ConcreteField := + polynomialPowerBasis.basis.reindex (finCongr polynomialPowerBasis_dim_eq) + +theorem polynomialBasisBasis_apply (i : Fin extensionDegree) : + polynomialBasisBasis i = root ^ i.val := by + unfold polynomialBasisBasis polynomialPowerBasis + rw [Module.Basis.reindex_apply] + change toSpecAlgEquiv.symm + (AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i)) = root ^ i.val + rw [show + AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i) = + (BinaryField.Extension.root definingPolynomialData) ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val by + simp [AdjoinRoot.powerBasisAux, BinaryField.Extension.root]] + rw [map_pow] + change toSpecAlgEquiv.symm GF2_64.root ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val = root ^ i.val + have hrootSymm : toSpecAlgEquiv.symm GF2_64.root = root := by + rw [AlgEquiv.symm_apply_eq] + exact toSpec_root.symm + rw [hrootSymm] + congr 1 + +/-- Each Lean polynomial-basis vector is present in the executable basis array. -/ +theorem polynomialBasisBasis_mem (i : Fin extensionDegree) : + polynomialBasisBasis i ∈ polynomialBasis.toList := by + rw [polynomialBasisBasis_apply] + rw [← Array.mem_def] + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis, Array.mem_ofFn] + exact ⟨i, rfl⟩ + +/-- The executable polynomial basis separates distinct elements by GF64 trace coordinates. -/ +theorem algebraicTraceValue_separates {a b : ConcreteField} (hne : a ≠ b) : + ∃ beta, beta ∈ polynomialBasis.toList ∧ algebraicTraceValue (beta * (a - b)) ≠ 0 := by + have hx : a - b ≠ 0 := sub_ne_zero.mpr hne + rcases exists_basis_trace_ne polynomialBasisBasis hx with ⟨i, htrace⟩ + refine ⟨polynomialBasisBasis i, polynomialBasisBasis_mem i, ?_⟩ + unfold algebraicTraceValue + intro hzero + apply htrace + have hz' : + algebraMap (ZMod 2) ConcreteField + (Algebra.trace (ZMod 2) ConcreteField (polynomialBasisBasis i * (a - b))) = + algebraMap (ZMod 2) ConcreteField 0 := by + rw [map_zero] + exact hzero + exact (FaithfulSMul.algebraMap_injective (ZMod 2) ConcreteField) hz' + +end ConcreteField + +/-- Shoup trace splitter context for `GF(2^64)`. -/ +def shoupTraceContext : + CPolynomial.Roots.FiniteField.SmallPrimeTraceContext ConcreteField where + toFiniteFieldContext := finiteFieldContext + p := 2 + k := extensionDegree + p_prime := Nat.prime_two + q_eq := by + simp [finiteFieldContext, fieldSize, BinaryField.Extension.fieldSize] + baseConstants := ConcreteField.baseConstants + baseConstants_size := ConcreteField.baseConstants_size + basis := ConcreteField.polynomialBasis + basis_size := ConcreteField.polynomialBasis_size + traceValue := tracePowerSum 2 extensionDegree + traceValue_eq_powerSum := fun _ ↦ rfl + traceValue_mem_base := by + intro z + rw [← ConcreteField.algebraicTraceValue_eq_powerSum] + exact ConcreteField.algebraicTraceValue_mem_base z + trace_separates := by + intro a b hne + rcases ConcreteField.algebraicTraceValue_separates hne with ⟨beta, hbeta, htrace⟩ + refine ⟨beta, hbeta, ?_⟩ + rwa [← ConcreteField.algebraicTraceValue_eq_powerSum] + +/-- Smooth cyclic splitter context for `GF(2^64)` with the supplied leaf evaluator. -/ +def smoothCyclicRootContextWith + (leafEvaluator : CPolynomial.BatchEvalContext ConcreteField) : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + CPolynomial.Roots.FiniteField.smoothCyclicRootContextOf + fieldSize + primitiveRoot + smoothRootSchedule + leafEvaluator + (CPolynomial.Roots.FiniteField.smoothSplitterInput + fieldSize primitiveRoot smoothRootSchedule) + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + smoothRootSchedule_fold_eq_one + (by + intro M D p factor h + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_sound + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule h) + (by + intro M D p a _hvalid hp hroot + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_complete + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + (by decide) + hp hroot) + +/-- Smooth cyclic splitter context for `GF(2^64)` using Horner leaf evaluation. -/ +def smoothHornerRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith (CPolynomial.BatchEvalContext.horner ConcreteField) + +/-- Smooth cyclic splitter context for `GF(2^64)` using subproduct-tree leaf evaluation. -/ +def smoothSubproductRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith + (CPolynomial.BatchEvalContext.subproduct ConcreteField + CPolynomial.MulContext.naive CPolynomial.ModContext.naive) + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_64/XPowTwoPowGcdCertificate.lean b/CompPoly/Fields/Binary/GF2_64/XPowTwoPowGcdCertificate.lean new file mode 100644 index 00000000..b1f1ab64 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/XPowTwoPowGcdCertificate.lean @@ -0,0 +1,654 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_64.XPowTwoPowModCertificate + +/-! +# GF(2^64) Rabin GCD Certificate + +Kernel-safe Euclidean-division certificate for the Rabin gcd check of +`X ^ 64 + X ^ 4 + X ^ 3 + X + 1`. +-/ + +namespace GF2_64 + +open Polynomial + +set_option maxRecDepth 1500 + +private abbrev B128 : Type := BitVec (2 * extensionDegree) + +def gcdPVal : B128 := BitVec.ofNat (2 * extensionDegree) 18446744073709551643 + +/-- Numeric 128-bit encoding of the GF64 defining polynomial. -/ +lemma definingPolynomial_eq_gcdPVal : + definingPolynomial = BinaryField.toPoly gcdPVal := by + rw [definingPolynomial_eq_P_val] + have h : P_val = gcdPVal := by + decide + rw [h] + +/-- Any GF64-width polynomial is already reduced modulo the defining polynomial. -/ +lemma toPoly_mod_definingPolynomial_eq_self (v : B64) : + BinaryField.toPoly v % definingPolynomial = BinaryField.toPoly v := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + exact BinaryField.toPoly_degree_lt_w + (w := extensionDegree) (h_w_pos := by unfold extensionDegree; omega) v + +/-- Soundness wrapper specialized to 128-bit Euclidean-division certificates. -/ +private theorem verify_div_step {a q b r : B128} + (h : BinaryField.Extension.checkDivStep (2 * extensionDegree) a q b r = true) : + BinaryField.toPoly a = BinaryField.toPoly q * BinaryField.toPoly b + + BinaryField.toPoly r := by + exact BinaryField.Extension.checkDivStep_correct a q b r h + +private theorem toPoly_ne_zero {v : B128} (h : v ≠ 0) : + BinaryField.toPoly v ≠ 0 := + (BinaryField.toPoly_ne_zero_iff_ne_zero v).mpr h + +/-- Initial Rabin gcd remainder for exponent `32`. -/ +def gcd32_b1Val : B128 := BitVec.ofNat (2 * extensionDegree) 6656922126492271879 + +lemma gcd32_b1Val_eq_zeroExtend : + gcd32_b1Val = BitVec.zeroExtend (2 * extensionDegree) (r32Val ^^^ r0Val) := by + decide + +def gcd32_a1Val : B128 := gcdPVal +def gcd32_q1Val : B128 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd32_r1Val : B128 := BitVec.ofNat (2 * extensionDegree) 3308649267891572992 + +def gcd32_a2Val : B128 := gcd32_b1Val +def gcd32_b2Val : B128 := gcd32_r1Val +def gcd32_q2Val : B128 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd32_r2Val : B128 := BitVec.ofNat (2 * extensionDegree) 556052245088806663 + +def gcd32_a3Val : B128 := gcd32_b2Val +def gcd32_b3Val : B128 := gcd32_r2Val +def gcd32_q3Val : B128 := BitVec.ofNat (2 * extensionDegree) 14 +def gcd32_r3Val : B128 := BitVec.ofNat (2 * extensionDegree) 135773225131735850 + +def gcd32_a4Val : B128 := gcd32_b3Val +def gcd32_b4Val : B128 := gcd32_r3Val +def gcd32_q4Val : B128 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd32_r4Val : B128 := BitVec.ofNat (2 * extensionDegree) 17463060920945583 + +def gcd32_a5Val : B128 := gcd32_b4Val +def gcd32_b5Val : B128 := gcd32_r4Val +def gcd32_q5Val : B128 := BitVec.ofNat (2 * extensionDegree) 8 +def gcd32_r5Val : B128 := BitVec.ofNat (2 * extensionDegree) 5076972710274642 + +def gcd32_a6Val : B128 := gcd32_b5Val +def gcd32_b6Val : B128 := gcd32_r5Val +def gcd32_q6Val : B128 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd32_r6Val : B128 := BitVec.ofNat (2 * extensionDegree) 2270494763000153 + +def gcd32_a7Val : B128 := gcd32_b6Val +def gcd32_b7Val : B128 := gcd32_r6Val +def gcd32_q7Val : B128 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd32_r7Val : B128 := BitVec.ofNat (2 * extensionDegree) 610758598485216 + +def gcd32_a8Val : B128 := gcd32_b7Val +def gcd32_b8Val : B128 := gcd32_r7Val +def gcd32_q8Val : B128 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd32_r8Val : B128 := BitVec.ofNat (2 * extensionDegree) 207728323179225 + +def gcd32_a9Val : B128 := gcd32_b8Val +def gcd32_b9Val : B128 := gcd32_r8Val +def gcd32_q9Val : B128 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd32_r9Val : B128 := BitVec.ofNat (2 * extensionDegree) 110091923692893 + +def gcd32_a10Val : B128 := gcd32_b9Val +def gcd32_b10Val : B128 := gcd32_r9Val +def gcd32_q10Val : B128 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd32_r10Val : B128 := BitVec.ofNat (2 * extensionDegree) 18196952945982 + +def gcd32_a11Val : B128 := gcd32_b10Val +def gcd32_b11Val : B128 := gcd32_r10Val +def gcd32_q11Val : B128 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd32_r11Val : B128 := BitVec.ofNat (2 * extensionDegree) 7741149963225 + +def gcd32_a12Val : B128 := gcd32_b11Val +def gcd32_b12Val : B128 := gcd32_r11Val +def gcd32_q12Val : B128 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd32_r12Val : B128 := BitVec.ofNat (2 * extensionDegree) 2961647328744 + +def gcd32_a13Val : B128 := gcd32_b12Val +def gcd32_b13Val : B128 := gcd32_r12Val +def gcd32_q13Val : B128 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd32_r13Val : B128 := BitVec.ofNat (2 * extensionDegree) 931744581089 + +def gcd32_a14Val : B128 := gcd32_b13Val +def gcd32_b14Val : B128 := gcd32_r13Val +def gcd32_q14Val : B128 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd32_r14Val : B128 := BitVec.ofNat (2 * extensionDegree) 428125962670 + +def gcd32_a15Val : B128 := gcd32_b14Val +def gcd32_b15Val : B128 := gcd32_r14Val +def gcd32_q15Val : B128 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd32_r15Val : B128 := BitVec.ofNat (2 * extensionDegree) 136043923133 + +def gcd32_a16Val : B128 := gcd32_b15Val +def gcd32_b16Val : B128 := gcd32_r15Val +def gcd32_q16Val : B128 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd32_r16Val : B128 := BitVec.ofNat (2 * extensionDegree) 11575516647 + +def gcd32_a17Val : B128 := gcd32_b16Val +def gcd32_b17Val : B128 := gcd32_r16Val +def gcd32_q17Val : B128 := BitVec.ofNat (2 * extensionDegree) 12 +def gcd32_r17Val : B128 := BitVec.ofNat (2 * extensionDegree) 3836354073 + +def gcd32_a18Val : B128 := gcd32_b17Val +def gcd32_b18Val : B128 := gcd32_r17Val +def gcd32_q18Val : B128 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd32_r18Val : B128 := BitVec.ofNat (2 * extensionDegree) 245499816 + +def gcd32_a19Val : B128 := gcd32_b18Val +def gcd32_b19Val : B128 := gcd32_r18Val +def gcd32_q19Val : B128 := BitVec.ofNat (2 * extensionDegree) 17 +def gcd32_r19Val : B128 := BitVec.ofNat (2 * extensionDegree) 2646833 + +def gcd32_a20Val : B128 := gcd32_b19Val +def gcd32_b20Val : B128 := gcd32_r19Val +def gcd32_q20Val : B128 := BitVec.ofNat (2 * extensionDegree) 110 +def gcd32_r20Val : B128 := BitVec.ofNat (2 * extensionDegree) 327398 + +def gcd32_a21Val : B128 := gcd32_b20Val +def gcd32_b21Val : B128 := gcd32_r20Val +def gcd32_q21Val : B128 := BitVec.ofNat (2 * extensionDegree) 11 +def gcd32_r21Val : B128 := BitVec.ofNat (2 * extensionDegree) 169771 + +def gcd32_a22Val : B128 := gcd32_b21Val +def gcd32_b22Val : B128 := gcd32_r21Val +def gcd32_q22Val : B128 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd32_r22Val : B128 := BitVec.ofNat (2 * extensionDegree) 118960 + +def gcd32_a23Val : B128 := gcd32_b22Val +def gcd32_b23Val : B128 := gcd32_r22Val +def gcd32_q23Val : B128 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd32_r23Val : B128 := BitVec.ofNat (2 * extensionDegree) 59131 + +def gcd32_a24Val : B128 := gcd32_b23Val +def gcd32_b24Val : B128 := gcd32_r23Val +def gcd32_q24Val : B128 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd32_r24Val : B128 := BitVec.ofNat (2 * extensionDegree) 7494 + +def gcd32_a25Val : B128 := gcd32_b24Val +def gcd32_b25Val : B128 := gcd32_r24Val +def gcd32_q25Val : B128 := BitVec.ofNat (2 * extensionDegree) 8 +def gcd32_r25Val : B128 := BitVec.ofNat (2 * extensionDegree) 3275 + +def gcd32_a26Val : B128 := gcd32_b25Val +def gcd32_b26Val : B128 := gcd32_r25Val +def gcd32_q26Val : B128 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd32_r26Val : B128 := BitVec.ofNat (2 * extensionDegree) 1232 + +def gcd32_a27Val : B128 := gcd32_b26Val +def gcd32_b27Val : B128 := gcd32_r26Val +def gcd32_q27Val : B128 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd32_r27Val : B128 := BitVec.ofNat (2 * extensionDegree) 443 + +def gcd32_a28Val : B128 := gcd32_b27Val +def gcd32_b28Val : B128 := gcd32_r27Val +def gcd32_q28Val : B128 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd32_r28Val : B128 := BitVec.ofNat (2 * extensionDegree) 241 + +def gcd32_a29Val : B128 := gcd32_b28Val +def gcd32_b29Val : B128 := gcd32_r28Val +def gcd32_q29Val : B128 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd32_r29Val : B128 := BitVec.ofNat (2 * extensionDegree) 89 + +def gcd32_a30Val : B128 := gcd32_b29Val +def gcd32_b30Val : B128 := gcd32_r29Val +def gcd32_q30Val : B128 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd32_r30Val : B128 := BitVec.ofNat (2 * extensionDegree) 26 + +def gcd32_a31Val : B128 := gcd32_b30Val +def gcd32_b31Val : B128 := gcd32_r30Val +def gcd32_q31Val : B128 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd32_r31Val : B128 := BitVec.ofNat (2 * extensionDegree) 5 + +def gcd32_a32Val : B128 := gcd32_b31Val +def gcd32_b32Val : B128 := gcd32_r31Val +def gcd32_q32Val : B128 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd32_r32Val : B128 := BitVec.ofNat (2 * extensionDegree) 1 + +def gcd32_a33Val : B128 := gcd32_b32Val +def gcd32_b33Val : B128 := gcd32_r32Val +def gcd32_q33Val : B128 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd32_r33Val : B128 := BitVec.ofNat (2 * extensionDegree) 0 + +/-- Reduce the exponent `32` Rabin gcd to the generated Euclidean trace. -/ +lemma gcd32_start_reduction : + EuclideanDomain.gcd (X ^ (2 ^ 32) + X) definingPolynomial = + EuclideanDomain.gcd definingPolynomial (BinaryField.toPoly gcd32_b1Val) := by + rw [ZMod2Poly.euclidean_gcd_comm] + rw [EuclideanDomain.gcd_val] + conv_lhs => + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_32_mod_eq] + rw [r32] + rw [toPoly_mod_definingPolynomial_eq_self r32Val, X_mod_definingPolynomial] + rw [← r0_eq_X] + rw [r0] + rw [← BinaryField.toPoly_xor] + rw [toPoly_mod_definingPolynomial_eq_self (r32Val ^^^ r0Val)] + rw [← BinaryField.Extension.toPoly_zeroExtend + (show extensionDegree ≤ 2 * extensionDegree by unfold extensionDegree; norm_num) + (r32Val ^^^ r0Val)] + rw [← gcd32_b1Val_eq_zeroExtend] + rw [ZMod2Poly.euclidean_gcd_comm] + +lemma gcd32_step_1 : + BinaryField.toPoly gcd32_a1Val = + BinaryField.toPoly gcd32_q1Val * BinaryField.toPoly gcd32_b1Val + + BinaryField.toPoly gcd32_r1Val := by + exact verify_div_step (a := gcd32_a1Val) (q := gcd32_q1Val) + (b := gcd32_b1Val) (r := gcd32_r1Val) (by rfl) + +lemma gcd32_step_2 : + BinaryField.toPoly gcd32_a2Val = + BinaryField.toPoly gcd32_q2Val * BinaryField.toPoly gcd32_b2Val + + BinaryField.toPoly gcd32_r2Val := by + exact verify_div_step (a := gcd32_a2Val) (q := gcd32_q2Val) + (b := gcd32_b2Val) (r := gcd32_r2Val) (by rfl) + +lemma gcd32_step_3 : + BinaryField.toPoly gcd32_a3Val = + BinaryField.toPoly gcd32_q3Val * BinaryField.toPoly gcd32_b3Val + + BinaryField.toPoly gcd32_r3Val := by + exact verify_div_step (a := gcd32_a3Val) (q := gcd32_q3Val) + (b := gcd32_b3Val) (r := gcd32_r3Val) (by rfl) + +lemma gcd32_step_4 : + BinaryField.toPoly gcd32_a4Val = + BinaryField.toPoly gcd32_q4Val * BinaryField.toPoly gcd32_b4Val + + BinaryField.toPoly gcd32_r4Val := by + exact verify_div_step (a := gcd32_a4Val) (q := gcd32_q4Val) + (b := gcd32_b4Val) (r := gcd32_r4Val) (by rfl) + +lemma gcd32_step_5 : + BinaryField.toPoly gcd32_a5Val = + BinaryField.toPoly gcd32_q5Val * BinaryField.toPoly gcd32_b5Val + + BinaryField.toPoly gcd32_r5Val := by + exact verify_div_step (a := gcd32_a5Val) (q := gcd32_q5Val) + (b := gcd32_b5Val) (r := gcd32_r5Val) (by rfl) + +lemma gcd32_step_6 : + BinaryField.toPoly gcd32_a6Val = + BinaryField.toPoly gcd32_q6Val * BinaryField.toPoly gcd32_b6Val + + BinaryField.toPoly gcd32_r6Val := by + exact verify_div_step (a := gcd32_a6Val) (q := gcd32_q6Val) + (b := gcd32_b6Val) (r := gcd32_r6Val) (by rfl) + +lemma gcd32_step_7 : + BinaryField.toPoly gcd32_a7Val = + BinaryField.toPoly gcd32_q7Val * BinaryField.toPoly gcd32_b7Val + + BinaryField.toPoly gcd32_r7Val := by + exact verify_div_step (a := gcd32_a7Val) (q := gcd32_q7Val) + (b := gcd32_b7Val) (r := gcd32_r7Val) (by rfl) + +lemma gcd32_step_8 : + BinaryField.toPoly gcd32_a8Val = + BinaryField.toPoly gcd32_q8Val * BinaryField.toPoly gcd32_b8Val + + BinaryField.toPoly gcd32_r8Val := by + exact verify_div_step (a := gcd32_a8Val) (q := gcd32_q8Val) + (b := gcd32_b8Val) (r := gcd32_r8Val) (by rfl) + +lemma gcd32_step_9 : + BinaryField.toPoly gcd32_a9Val = + BinaryField.toPoly gcd32_q9Val * BinaryField.toPoly gcd32_b9Val + + BinaryField.toPoly gcd32_r9Val := by + exact verify_div_step (a := gcd32_a9Val) (q := gcd32_q9Val) + (b := gcd32_b9Val) (r := gcd32_r9Val) (by rfl) + +lemma gcd32_step_10 : + BinaryField.toPoly gcd32_a10Val = + BinaryField.toPoly gcd32_q10Val * BinaryField.toPoly gcd32_b10Val + + BinaryField.toPoly gcd32_r10Val := by + exact verify_div_step (a := gcd32_a10Val) (q := gcd32_q10Val) + (b := gcd32_b10Val) (r := gcd32_r10Val) (by rfl) + +lemma gcd32_step_11 : + BinaryField.toPoly gcd32_a11Val = + BinaryField.toPoly gcd32_q11Val * BinaryField.toPoly gcd32_b11Val + + BinaryField.toPoly gcd32_r11Val := by + exact verify_div_step (a := gcd32_a11Val) (q := gcd32_q11Val) + (b := gcd32_b11Val) (r := gcd32_r11Val) (by rfl) + +lemma gcd32_step_12 : + BinaryField.toPoly gcd32_a12Val = + BinaryField.toPoly gcd32_q12Val * BinaryField.toPoly gcd32_b12Val + + BinaryField.toPoly gcd32_r12Val := by + exact verify_div_step (a := gcd32_a12Val) (q := gcd32_q12Val) + (b := gcd32_b12Val) (r := gcd32_r12Val) (by rfl) + +lemma gcd32_step_13 : + BinaryField.toPoly gcd32_a13Val = + BinaryField.toPoly gcd32_q13Val * BinaryField.toPoly gcd32_b13Val + + BinaryField.toPoly gcd32_r13Val := by + exact verify_div_step (a := gcd32_a13Val) (q := gcd32_q13Val) + (b := gcd32_b13Val) (r := gcd32_r13Val) (by rfl) + +lemma gcd32_step_14 : + BinaryField.toPoly gcd32_a14Val = + BinaryField.toPoly gcd32_q14Val * BinaryField.toPoly gcd32_b14Val + + BinaryField.toPoly gcd32_r14Val := by + exact verify_div_step (a := gcd32_a14Val) (q := gcd32_q14Val) + (b := gcd32_b14Val) (r := gcd32_r14Val) (by rfl) + +lemma gcd32_step_15 : + BinaryField.toPoly gcd32_a15Val = + BinaryField.toPoly gcd32_q15Val * BinaryField.toPoly gcd32_b15Val + + BinaryField.toPoly gcd32_r15Val := by + exact verify_div_step (a := gcd32_a15Val) (q := gcd32_q15Val) + (b := gcd32_b15Val) (r := gcd32_r15Val) (by rfl) + +lemma gcd32_step_16 : + BinaryField.toPoly gcd32_a16Val = + BinaryField.toPoly gcd32_q16Val * BinaryField.toPoly gcd32_b16Val + + BinaryField.toPoly gcd32_r16Val := by + exact verify_div_step (a := gcd32_a16Val) (q := gcd32_q16Val) + (b := gcd32_b16Val) (r := gcd32_r16Val) (by rfl) + +lemma gcd32_step_17 : + BinaryField.toPoly gcd32_a17Val = + BinaryField.toPoly gcd32_q17Val * BinaryField.toPoly gcd32_b17Val + + BinaryField.toPoly gcd32_r17Val := by + exact verify_div_step (a := gcd32_a17Val) (q := gcd32_q17Val) + (b := gcd32_b17Val) (r := gcd32_r17Val) (by rfl) + +lemma gcd32_step_18 : + BinaryField.toPoly gcd32_a18Val = + BinaryField.toPoly gcd32_q18Val * BinaryField.toPoly gcd32_b18Val + + BinaryField.toPoly gcd32_r18Val := by + exact verify_div_step (a := gcd32_a18Val) (q := gcd32_q18Val) + (b := gcd32_b18Val) (r := gcd32_r18Val) (by rfl) + +lemma gcd32_step_19 : + BinaryField.toPoly gcd32_a19Val = + BinaryField.toPoly gcd32_q19Val * BinaryField.toPoly gcd32_b19Val + + BinaryField.toPoly gcd32_r19Val := by + exact verify_div_step (a := gcd32_a19Val) (q := gcd32_q19Val) + (b := gcd32_b19Val) (r := gcd32_r19Val) (by rfl) + +lemma gcd32_step_20 : + BinaryField.toPoly gcd32_a20Val = + BinaryField.toPoly gcd32_q20Val * BinaryField.toPoly gcd32_b20Val + + BinaryField.toPoly gcd32_r20Val := by + exact verify_div_step (a := gcd32_a20Val) (q := gcd32_q20Val) + (b := gcd32_b20Val) (r := gcd32_r20Val) (by rfl) + +lemma gcd32_step_21 : + BinaryField.toPoly gcd32_a21Val = + BinaryField.toPoly gcd32_q21Val * BinaryField.toPoly gcd32_b21Val + + BinaryField.toPoly gcd32_r21Val := by + exact verify_div_step (a := gcd32_a21Val) (q := gcd32_q21Val) + (b := gcd32_b21Val) (r := gcd32_r21Val) (by rfl) + +lemma gcd32_step_22 : + BinaryField.toPoly gcd32_a22Val = + BinaryField.toPoly gcd32_q22Val * BinaryField.toPoly gcd32_b22Val + + BinaryField.toPoly gcd32_r22Val := by + exact verify_div_step (a := gcd32_a22Val) (q := gcd32_q22Val) + (b := gcd32_b22Val) (r := gcd32_r22Val) (by rfl) + +lemma gcd32_step_23 : + BinaryField.toPoly gcd32_a23Val = + BinaryField.toPoly gcd32_q23Val * BinaryField.toPoly gcd32_b23Val + + BinaryField.toPoly gcd32_r23Val := by + exact verify_div_step (a := gcd32_a23Val) (q := gcd32_q23Val) + (b := gcd32_b23Val) (r := gcd32_r23Val) (by rfl) + +lemma gcd32_step_24 : + BinaryField.toPoly gcd32_a24Val = + BinaryField.toPoly gcd32_q24Val * BinaryField.toPoly gcd32_b24Val + + BinaryField.toPoly gcd32_r24Val := by + exact verify_div_step (a := gcd32_a24Val) (q := gcd32_q24Val) + (b := gcd32_b24Val) (r := gcd32_r24Val) (by rfl) + +lemma gcd32_step_25 : + BinaryField.toPoly gcd32_a25Val = + BinaryField.toPoly gcd32_q25Val * BinaryField.toPoly gcd32_b25Val + + BinaryField.toPoly gcd32_r25Val := by + exact verify_div_step (a := gcd32_a25Val) (q := gcd32_q25Val) + (b := gcd32_b25Val) (r := gcd32_r25Val) (by rfl) + +lemma gcd32_step_26 : + BinaryField.toPoly gcd32_a26Val = + BinaryField.toPoly gcd32_q26Val * BinaryField.toPoly gcd32_b26Val + + BinaryField.toPoly gcd32_r26Val := by + exact verify_div_step (a := gcd32_a26Val) (q := gcd32_q26Val) + (b := gcd32_b26Val) (r := gcd32_r26Val) (by rfl) + +lemma gcd32_step_27 : + BinaryField.toPoly gcd32_a27Val = + BinaryField.toPoly gcd32_q27Val * BinaryField.toPoly gcd32_b27Val + + BinaryField.toPoly gcd32_r27Val := by + exact verify_div_step (a := gcd32_a27Val) (q := gcd32_q27Val) + (b := gcd32_b27Val) (r := gcd32_r27Val) (by rfl) + +lemma gcd32_step_28 : + BinaryField.toPoly gcd32_a28Val = + BinaryField.toPoly gcd32_q28Val * BinaryField.toPoly gcd32_b28Val + + BinaryField.toPoly gcd32_r28Val := by + exact verify_div_step (a := gcd32_a28Val) (q := gcd32_q28Val) + (b := gcd32_b28Val) (r := gcd32_r28Val) (by rfl) + +lemma gcd32_step_29 : + BinaryField.toPoly gcd32_a29Val = + BinaryField.toPoly gcd32_q29Val * BinaryField.toPoly gcd32_b29Val + + BinaryField.toPoly gcd32_r29Val := by + exact verify_div_step (a := gcd32_a29Val) (q := gcd32_q29Val) + (b := gcd32_b29Val) (r := gcd32_r29Val) (by rfl) + +lemma gcd32_step_30 : + BinaryField.toPoly gcd32_a30Val = + BinaryField.toPoly gcd32_q30Val * BinaryField.toPoly gcd32_b30Val + + BinaryField.toPoly gcd32_r30Val := by + exact verify_div_step (a := gcd32_a30Val) (q := gcd32_q30Val) + (b := gcd32_b30Val) (r := gcd32_r30Val) (by rfl) + +lemma gcd32_step_31 : + BinaryField.toPoly gcd32_a31Val = + BinaryField.toPoly gcd32_q31Val * BinaryField.toPoly gcd32_b31Val + + BinaryField.toPoly gcd32_r31Val := by + exact verify_div_step (a := gcd32_a31Val) (q := gcd32_q31Val) + (b := gcd32_b31Val) (r := gcd32_r31Val) (by rfl) + +lemma gcd32_step_32 : + BinaryField.toPoly gcd32_a32Val = + BinaryField.toPoly gcd32_q32Val * BinaryField.toPoly gcd32_b32Val + + BinaryField.toPoly gcd32_r32Val := by + exact verify_div_step (a := gcd32_a32Val) (q := gcd32_q32Val) + (b := gcd32_b32Val) (r := gcd32_r32Val) (by rfl) + +lemma gcd32_step_33 : + BinaryField.toPoly gcd32_a33Val = + BinaryField.toPoly gcd32_q33Val * BinaryField.toPoly gcd32_b33Val + + BinaryField.toPoly gcd32_r33Val := by + exact verify_div_step (a := gcd32_a33Val) (q := gcd32_q33Val) + (b := gcd32_b33Val) (r := gcd32_r33Val) (by rfl) + +/-- Rabin gcd condition for exponent `32`. -/ +lemma rabin_gcd_condition_32 : + EuclideanDomain.gcd (X ^ (2 ^ 32) + X) definingPolynomial = 1 := by + rw [gcd32_start_reduction] + rw [definingPolynomial_eq_gcdPVal] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a1Val) + (BinaryField.toPoly gcd32_b1Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b1Val) (by decide)) + gcd32_step_1] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a2Val) + (BinaryField.toPoly gcd32_b2Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b2Val) (by decide)) + gcd32_step_2] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a3Val) + (BinaryField.toPoly gcd32_b3Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b3Val) (by decide)) + gcd32_step_3] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a4Val) + (BinaryField.toPoly gcd32_b4Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b4Val) (by decide)) + gcd32_step_4] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a5Val) + (BinaryField.toPoly gcd32_b5Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b5Val) (by decide)) + gcd32_step_5] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a6Val) + (BinaryField.toPoly gcd32_b6Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b6Val) (by decide)) + gcd32_step_6] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a7Val) + (BinaryField.toPoly gcd32_b7Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b7Val) (by decide)) + gcd32_step_7] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a8Val) + (BinaryField.toPoly gcd32_b8Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b8Val) (by decide)) + gcd32_step_8] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a9Val) + (BinaryField.toPoly gcd32_b9Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b9Val) (by decide)) + gcd32_step_9] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a10Val) + (BinaryField.toPoly gcd32_b10Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b10Val) (by decide)) + gcd32_step_10] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a11Val) + (BinaryField.toPoly gcd32_b11Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b11Val) (by decide)) + gcd32_step_11] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a12Val) + (BinaryField.toPoly gcd32_b12Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b12Val) (by decide)) + gcd32_step_12] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a13Val) + (BinaryField.toPoly gcd32_b13Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b13Val) (by decide)) + gcd32_step_13] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a14Val) + (BinaryField.toPoly gcd32_b14Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b14Val) (by decide)) + gcd32_step_14] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a15Val) + (BinaryField.toPoly gcd32_b15Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b15Val) (by decide)) + gcd32_step_15] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a16Val) + (BinaryField.toPoly gcd32_b16Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b16Val) (by decide)) + gcd32_step_16] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a17Val) + (BinaryField.toPoly gcd32_b17Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b17Val) (by decide)) + gcd32_step_17] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a18Val) + (BinaryField.toPoly gcd32_b18Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b18Val) (by decide)) + gcd32_step_18] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a19Val) + (BinaryField.toPoly gcd32_b19Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b19Val) (by decide)) + gcd32_step_19] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a20Val) + (BinaryField.toPoly gcd32_b20Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b20Val) (by decide)) + gcd32_step_20] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a21Val) + (BinaryField.toPoly gcd32_b21Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b21Val) (by decide)) + gcd32_step_21] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a22Val) + (BinaryField.toPoly gcd32_b22Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b22Val) (by decide)) + gcd32_step_22] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a23Val) + (BinaryField.toPoly gcd32_b23Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b23Val) (by decide)) + gcd32_step_23] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a24Val) + (BinaryField.toPoly gcd32_b24Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b24Val) (by decide)) + gcd32_step_24] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a25Val) + (BinaryField.toPoly gcd32_b25Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b25Val) (by decide)) + gcd32_step_25] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a26Val) + (BinaryField.toPoly gcd32_b26Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b26Val) (by decide)) + gcd32_step_26] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a27Val) + (BinaryField.toPoly gcd32_b27Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b27Val) (by decide)) + gcd32_step_27] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a28Val) + (BinaryField.toPoly gcd32_b28Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b28Val) (by decide)) + gcd32_step_28] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a29Val) + (BinaryField.toPoly gcd32_b29Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b29Val) (by decide)) + gcd32_step_29] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a30Val) + (BinaryField.toPoly gcd32_b30Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b30Val) (by decide)) + gcd32_step_30] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a31Val) + (BinaryField.toPoly gcd32_b31Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b31Val) (by decide)) + gcd32_step_31] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a32Val) + (BinaryField.toPoly gcd32_b32Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b32Val) (by decide)) + gcd32_step_32] + change EuclideanDomain.gcd (BinaryField.toPoly gcd32_a33Val) + (BinaryField.toPoly gcd32_b33Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd32_b33Val) (by decide)) + gcd32_step_33] + change EuclideanDomain.gcd + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 1 : B128)) + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 0 : B128)) = 1 + rw [BinaryField.toPoly_one_eq_one + (w := 2 * extensionDegree) (h_w_pos := by unfold extensionDegree; omega)] + rw [BinaryField.toPoly_zero_eq_zero] + exact BinaryField.gcd_one_zero + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_64/XPowTwoPowModCertificate.lean b/CompPoly/Fields/Binary/GF2_64/XPowTwoPowModCertificate.lean new file mode 100644 index 00000000..b462cf26 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_64/XPowTwoPowModCertificate.lean @@ -0,0 +1,1433 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_64.Prelude +import Mathlib.Tactic.NormNum + +/-! +# GF(2^64) Modular Frobenius Certificate + +Kernel-safe certificate data for repeated squaring of `X` modulo +`X ^ 64 + X ^ 4 + X ^ 3 + X + 1`. +-/ + +namespace GF2_64 + +open Polynomial + +set_option maxRecDepth 1500 + +/-- Certificate exponents fit in the doubled-width checker. -/ +lemma certificateExponents_bound : + ∀ exponent ∈ definingPolynomialExponents, + extensionDegree + exponent ≤ 2 * extensionDegree := by + unfold definingPolynomialExponents extensionDegree + decide + +/-- Soundness wrapper specialized to the GF64 defining polynomial. -/ +private theorem verify_square_step {rPrev q rNext : B64} + (h : + BinaryField.Extension.checkSquareStep extensionDegree definingPolynomialExponents + rPrev q rNext = true) : + (BinaryField.toPoly rPrev) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q) * + definingPolynomial + BinaryField.toPoly rNext := by + rw [← sparsePolynomial_definingPolynomialExponents] + exact BinaryField.Extension.checkSquareStep_correct certificateExponents_bound + rPrev q rNext h + +def r0Val : B64 := BitVec.ofNat extensionDegree 2 +noncomputable def r0 : Polynomial (ZMod 2) := BinaryField.toPoly r0Val + +def q1Val : B64 := BitVec.ofNat extensionDegree 0 +def r1Val : B64 := BitVec.ofNat extensionDegree 4 +noncomputable def r1 : Polynomial (ZMod 2) := BinaryField.toPoly r1Val + +def q2Val : B64 := BitVec.ofNat extensionDegree 0 +def r2Val : B64 := BitVec.ofNat extensionDegree 16 +noncomputable def r2 : Polynomial (ZMod 2) := BinaryField.toPoly r2Val + +def q3Val : B64 := BitVec.ofNat extensionDegree 0 +def r3Val : B64 := BitVec.ofNat extensionDegree 256 +noncomputable def r3 : Polynomial (ZMod 2) := BinaryField.toPoly r3Val + +def q4Val : B64 := BitVec.ofNat extensionDegree 0 +def r4Val : B64 := BitVec.ofNat extensionDegree 65536 +noncomputable def r4 : Polynomial (ZMod 2) := BinaryField.toPoly r4Val + +def q5Val : B64 := BitVec.ofNat extensionDegree 0 +def r5Val : B64 := BitVec.ofNat extensionDegree 4294967296 +noncomputable def r5 : Polynomial (ZMod 2) := BinaryField.toPoly r5Val + +def q6Val : B64 := BitVec.ofNat extensionDegree 1 +def r6Val : B64 := BitVec.ofNat extensionDegree 27 +noncomputable def r6 : Polynomial (ZMod 2) := BinaryField.toPoly r6Val + +def q7Val : B64 := BitVec.ofNat extensionDegree 0 +def r7Val : B64 := BitVec.ofNat extensionDegree 325 +noncomputable def r7 : Polynomial (ZMod 2) := BinaryField.toPoly r7Val + +def q8Val : B64 := BitVec.ofNat extensionDegree 0 +def r8Val : B64 := BitVec.ofNat extensionDegree 69649 +noncomputable def r8 : Polynomial (ZMod 2) := BinaryField.toPoly r8Val + +def q9Val : B64 := BitVec.ofNat extensionDegree 0 +def r9Val : B64 := BitVec.ofNat extensionDegree 4311744769 +noncomputable def r9 : Polynomial (ZMod 2) := BinaryField.toPoly r9Val + +def q10Val : B64 := BitVec.ofNat extensionDegree 1 +def r10Val : B64 := BitVec.ofNat extensionDegree 281474976776218 +noncomputable def r10 : Polynomial (ZMod 2) := BinaryField.toPoly r10Val + +def q11Val : B64 := BitVec.ofNat extensionDegree 4294967296 +def r11Val : B64 := BitVec.ofNat extensionDegree 111669150020 +noncomputable def r11 : Polynomial (ZMod 2) := BinaryField.toPoly r11Val + +def q12Val : B64 := BitVec.ofNat extensionDegree 324 +def r12Val : B64 := BitVec.ofNat extensionDegree 69052 +noncomputable def r12 : Polynomial (ZMod 2) := BinaryField.toPoly r12Val + +def q13Val : B64 := BitVec.ofNat extensionDegree 0 +def r13Val : B64 := BitVec.ofNat extensionDegree 4300293456 +noncomputable def r13 : Polynomial (ZMod 2) := BinaryField.toPoly r13Val + +def q14Val : B64 := BitVec.ofNat extensionDegree 1 +def r14Val : B64 := BitVec.ofNat extensionDegree 18696262193435 +noncomputable def r14 : Polynomial (ZMod 2) := BinaryField.toPoly r14Val + +def q15Val : B64 := BitVec.ofNat extensionDegree 16842753 +def r15Val : B64 := BitVec.ofNat extensionDegree 72058698282434910 +noncomputable def r15 : Polynomial (ZMod 2) := BinaryField.toPoly r15Val + +def q16Val : B64 := BitVec.ofNat extensionDegree 281474976776193 +def r16Val : B64 := BitVec.ofNat extensionDegree 98799108396552527 +noncomputable def r16 : Polynomial (ZMod 2) := BinaryField.toPoly r16Val + +def q17Val : B64 := BitVec.ofNat extensionDegree 300531746672656 +def r17Val : B64 := BitVec.ofNat extensionDegree 7508852687479269 +noncomputable def r17 : Polynomial (ZMod 2) := BinaryField.toPoly r17Val + +def q18Val : B64 := BitVec.ofNat extensionDegree 1392715567109 +def r18Val : B64 := BitVec.ofNat extensionDegree 313291816297574 +noncomputable def r18 : Polynomial (ZMod 2) := BinaryField.toPoly r18Val + +def q19Val : B64 := BitVec.ofNat extensionDegree 4317008981 +def r19Val : B64 := BitVec.ofNat extensionDegree 6076785667380547347 +noncomputable def r19 : Polynomial (ZMod 2) := BinaryField.toPoly r19Val + +def q20Val : B64 := BitVec.ofNat extensionDegree 1229501463002091861 +def r20Val : B64 := BitVec.ofNat extensionDegree 13470757684146121986 +noncomputable def r20 : Polynomial (ZMod 2) := BinaryField.toPoly r20Val + +def q21Val : B64 := BitVec.ofNat extensionDegree 4991207750979831122 +def r21Val : B64 := BitVec.ofNat extensionDegree 12749500389507444802 +noncomputable def r21 : Polynomial (ZMod 2) := BinaryField.toPoly r21Val + +def q22Val : B64 := BitVec.ofNat extensionDegree 4972066712951521367 +def r22Val : B64 := BitVec.ofNat extensionDegree 16291502563427555125 +noncomputable def r22 : Polynomial (ZMod 2) := BinaryField.toPoly r22Val + +def q23Val : B64 := BitVec.ofNat extensionDegree 6053964988803256322 +def r23Val : B64 := BitVec.ofNat extensionDegree 5203926764172326183 +noncomputable def r23 : Polynomial (ZMod 2) := BinaryField.toPoly r23Val + +def q24Val : B64 := BitVec.ofNat extensionDegree 1170941675557966085 +def r24Val : B64 := BitVec.ofNat extensionDegree 13174495406275522402 +noncomputable def r24 : Polynomial (ZMod 2) := BinaryField.toPoly r24Val + +def q25Val : B64 := BitVec.ofNat extensionDegree 4977692621692555287 +def r25Val : B64 := BitVec.ofNat extensionDegree 12024447909651637749 +noncomputable def r25 : Polynomial (ZMod 2) := BinaryField.toPoly r25Val + +def q26Val : B64 := BitVec.ofNat extensionDegree 4905635319967466562 +def r26Val : B64 := BitVec.ofNat extensionDegree 13393486797395263463 +noncomputable def r26 : Polynomial (ZMod 2) := BinaryField.toPoly r26Val + +def q27Val : B64 := BitVec.ofNat extensionDegree 4990359287705440275 +def r27Val : B64 := BitVec.ofNat extensionDegree 16251283266509727112 +noncomputable def r27 : Polynomial (ZMod 2) := BinaryField.toPoly r27Val + +def q28Val : B64 := BitVec.ofNat extensionDegree 6053190017856045074 +def r28Val : B64 := BitVec.ofNat extensionDegree 1733189407169659334 +noncomputable def r28 : Polynomial (ZMod 2) := BinaryField.toPoly r28Val + +def q29Val : B64 := BitVec.ofNat extensionDegree 90072341514830097 +def r29Val : B64 := BitVec.ofNat extensionDegree 1771135578840730303 +noncomputable def r29 : Polynomial (ZMod 2) := BinaryField.toPoly r29Val + +def q30Val : B64 := BitVec.ofNat extensionDegree 90143529809220688 +def r30Val : B64 := BitVec.ofNat extensionDegree 5532544551272160805 +noncomputable def r30 : Polynomial (ZMod 2) := BinaryField.toPoly r30Val + +def q31Val : B64 := BitVec.ofNat extensionDegree 1175527554946520337 +def r31Val : B64 := BitVec.ofNat extensionDegree 16371482399015699130 +noncomputable def r31 : Polynomial (ZMod 2) := BinaryField.toPoly r31Val + +def q32Val : B64 := BitVec.ofNat extensionDegree 6054250793186377735 +def r32Val : B64 := BitVec.ofNat extensionDegree 6656922126492271877 +noncomputable def r32 : Polynomial (ZMod 2) := BinaryField.toPoly r32Val + +def q33Val : B64 := BitVec.ofNat extensionDegree 1247519104261493780 +def r33Val : B64 := BitVec.ofNat extensionDegree 13359044734667447757 +noncomputable def r33 : Polynomial (ZMod 2) := BinaryField.toPoly r33Val + +def q34Val : B64 := BitVec.ofNat extensionDegree 4990291922419455046 +def r34Val : B64 := BitVec.ofNat extensionDegree 13081489766298454731 +noncomputable def r34 : Polynomial (ZMod 2) := BinaryField.toPoly r34Val + +def q35Val : B64 := BitVec.ofNat extensionDegree 4976829725369517058 +def r35Val : B64 := BitVec.ofNat extensionDegree 12969455067531443315 +noncomputable def r35 : Polynomial (ZMod 2) := BinaryField.toPoly r35Val + +def q36Val : B64 := BitVec.ofNat extensionDegree 4973475166928782403 +def r36Val : B64 := BitVec.ofNat extensionDegree 12854470937230884840 +noncomputable def r36 : Polynomial (ZMod 2) := BinaryField.toPoly r36Val + +def q37Val : B64 := BitVec.ofNat extensionDegree 4973121947744404754 +def r37Val : B64 := BitVec.ofNat extensionDegree 12933450780795347654 +noncomputable def r37 : Polynomial (ZMod 2) := BinaryField.toPoly r37Val + +def q38Val : B64 := BitVec.ofNat extensionDegree 4973404798205318423 +def r38Val : B64 := BitVec.ofNat extensionDegree 16314237025689753317 +noncomputable def r38 : Polynomial (ZMod 2) := BinaryField.toPoly r38Val + +def q39Val : B64 := BitVec.ofNat extensionDegree 6053985880878613506 +def r39Val : B64 := BitVec.ofNat extensionDegree 589001530574911527 +noncomputable def r39 : Polynomial (ZMod 2) := BinaryField.toPoly r39Val + +def q40Val : B64 := BitVec.ofNat extensionDegree 18019141232447505 +def r40Val : B64 := BitVec.ofNat extensionDegree 1406365973223339454 +noncomputable def r40 : Polynomial (ZMod 2) := BinaryField.toPoly r40Val + +def q41Val : B64 := BitVec.ofNat extensionDegree 73535406725141524 +def r41Val : B64 := BitVec.ofNat extensionDegree 5437469698763298952 +noncomputable def r41 : Polynomial (ZMod 2) := BinaryField.toPoly r41Val + +def q42Val : B64 := BitVec.ofNat extensionDegree 1172366442101822464 +def r42Val : B64 := BitVec.ofNat extensionDegree 16637286567612537920 +noncomputable def r42 : Polynomial (ZMod 2) := BinaryField.toPoly r42Val + +def q43Val : B64 := BitVec.ofNat extensionDegree 6058559780245820759 +def r43Val : B64 := BitVec.ofNat extensionDegree 1791104586889564209 +noncomputable def r43 : Polynomial (ZMod 2) := BinaryField.toPoly r43Val + +def q44Val : B64 := BitVec.ofNat extensionDegree 90161349614633985 +def r44Val : B64 := BitVec.ofNat extensionDegree 5532225425759037722 +noncomputable def r44 : Polynomial (ZMod 2) := BinaryField.toPoly r44Val + +def q45Val : B64 := BitVec.ofNat extensionDegree 1175527549913089301 +def r45Val : B64 := BitVec.ofNat extensionDegree 17465559541434070915 +noncomputable def r45 : Polynomial (ZMod 2) := BinaryField.toPoly r45Val + +def q46Val : B64 := BitVec.ofNat extensionDegree 6126043400610337110 +def r46Val : B64 := BitVec.ofNat extensionDegree 6285227636684303407 +noncomputable def r46 : Polynomial (ZMod 2) := BinaryField.toPoly r46Val + +def q47Val : B64 := BitVec.ofNat extensionDegree 1230895850982540625 +def r47Val : B64 := BitVec.ofNat extensionDegree 12575863927935300670 +noncomputable def r47 : Polynomial (ZMod 2) := BinaryField.toPoly r47Val + +def q48Val : B64 := BitVec.ofNat extensionDegree 4923630747618722134 +def r48Val : B64 := BitVec.ofNat extensionDegree 18039947418024139134 +noncomputable def r48 : Polynomial (ZMod 2) := BinaryField.toPoly r48Val + +def q49Val : B64 := BitVec.ofNat extensionDegree 6144054776738890055 +def r49Val : B64 := BitVec.ofNat extensionDegree 5812368083904874709 +noncomputable def r49 : Polynomial (ZMod 2) := BinaryField.toPoly r49Val + +def q50Val : B64 := BitVec.ofNat extensionDegree 1225054145754518853 +def r50Val : B64 := BitVec.ofNat extensionDegree 12612049045170180262 +noncomputable def r50 : Polynomial (ZMod 2) := BinaryField.toPoly r50Val + +def q51Val : B64 := BitVec.ofNat extensionDegree 4923841854930505798 +def r51Val : B64 := BitVec.ofNat extensionDegree 18321212328940417678 +noncomputable def r51 : Polynomial (ZMod 2) := BinaryField.toPoly r51Val + +def q52Val : B64 := BitVec.ofNat extensionDegree 6148557000634613826 +def r52Val : B64 := BitVec.ofNat extensionDegree 80132871367001762 +noncomputable def r52 : Polynomial (ZMod 2) := BinaryField.toPoly r52Val + +def q53Val : B64 := BitVec.ofNat extensionDegree 282919243355216 +def r53Val : B64 := BitVec.ofNat extensionDegree 3193222135652212 +noncomputable def r53 : Polynomial (ZMod 2) := BinaryField.toPoly r53Val + +def q54Val : B64 := BitVec.ofNat extensionDegree 296642151701 +def r54Val : B64 := BitVec.ofNat extensionDegree 6130814885544944599 +noncomputable def r54 : Polynomial (ZMod 2) := BinaryField.toPoly r54Val + +def q55Val : B64 := BitVec.ofNat extensionDegree 1229765345776321556 +def r55Val : B64 := BitVec.ofNat extensionDegree 18373379959575346377 +noncomputable def r55 : Polynomial (ZMod 2) := BinaryField.toPoly r55Val + +def q56Val : B64 := BitVec.ofNat extensionDegree 6148633146398426435 +def r56Val : B64 := BitVec.ofNat extensionDegree 74962121387008428 +noncomputable def r56 : Polynomial (ZMod 2) := BinaryField.toPoly r56Val + +def q57Val : B64 := BitVec.ofNat extensionDegree 281767319782420 +def r57Val : B64 := BitVec.ofNat extensionDegree 6150600619072481676 +noncomputable def r57 : Polynomial (ZMod 2) := BinaryField.toPoly r57Val + +def q58Val : B64 := BitVec.ofNat extensionDegree 1229783161584763985 +def r58Val : B64 := BitVec.ofNat extensionDegree 18446652706856364859 +noncomputable def r58 : Polynomial (ZMod 2) := BinaryField.toPoly r58Val + +def q59Val : B64 := BitVec.ofNat extensionDegree 6148914690950976531 +def r59Val : B64 := BitVec.ofNat extensionDegree 6148825560630040792 +noncomputable def r59 : Polynomial (ZMod 2) := BinaryField.toPoly r59Val + +def q60Val : B64 := BitVec.ofNat extensionDegree 1229782937962024977 +def r60Val : B64 := BitVec.ofNat extensionDegree 18446655764902830315 +noncomputable def r60 : Polynomial (ZMod 2) := BinaryField.toPoly r60Val + +def q61Val : B64 := BitVec.ofNat extensionDegree 6148914690951300178 +def r61Val : B64 := BitVec.ofNat extensionDegree 93462766681859 +noncomputable def r61 : Polynomial (ZMod 2) := BinaryField.toPoly r61Val + +def q62Val : B64 := BitVec.ofNat extensionDegree 286326784 +def r62Val : B64 := BitVec.ofNat extensionDegree 6148820870539116549 +noncomputable def r62 : Polynomial (ZMod 2) := BinaryField.toPoly r62Val + +def q63Val : B64 := BitVec.ofNat extensionDegree 1229782937960972289 +def r63Val : B64 := BitVec.ofNat extensionDegree 18446744069414584330 +noncomputable def r63 : Polynomial (ZMod 2) := BinaryField.toPoly r63Val + +def q64Val : B64 := BitVec.ofNat extensionDegree 6148914691236517202 +def r64Val : B64 := BitVec.ofNat extensionDegree 2 +noncomputable def r64 : Polynomial (ZMod 2) := BinaryField.toPoly r64Val + +/-- The initial remainder denotes `X`. -/ +lemma r0_eq_X : r0 = X := by + rw [r0, r0Val, extensionDegree] + have h : (BitVec.ofNat 64 2 : BitVec 64) = (1 <<< 1 : BitVec 64) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 64) 1 (by decide) + +/-- The final remainder after 64 Frobenius steps denotes `X`. -/ +lemma r64_eq_X : r64 = X := by + rw [r64, r64Val, extensionDegree] + have h : (BitVec.ofNat 64 2 : BitVec 64) = (1 <<< 1 : BitVec 64) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 64) 1 (by decide) + +/-- Certificate step 1: square and reduce modulo the GF64 polynomial. -/ +lemma step_1 : + r0 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + r1 := by + change (BinaryField.toPoly r0Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + BinaryField.toPoly r1Val + exact verify_square_step (rPrev := r0Val) (q := q1Val) + (rNext := r1Val) (by rfl) + +/-- Certificate step 2: square and reduce modulo the GF64 polynomial. -/ +lemma step_2 : + r1 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + r2 := by + change (BinaryField.toPoly r1Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + BinaryField.toPoly r2Val + exact verify_square_step (rPrev := r1Val) (q := q2Val) + (rNext := r2Val) (by rfl) + +/-- Certificate step 3: square and reduce modulo the GF64 polynomial. -/ +lemma step_3 : + r2 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + r3 := by + change (BinaryField.toPoly r2Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + BinaryField.toPoly r3Val + exact verify_square_step (rPrev := r2Val) (q := q3Val) + (rNext := r3Val) (by rfl) + +/-- Certificate step 4: square and reduce modulo the GF64 polynomial. -/ +lemma step_4 : + r3 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + r4 := by + change (BinaryField.toPoly r3Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + BinaryField.toPoly r4Val + exact verify_square_step (rPrev := r3Val) (q := q4Val) + (rNext := r4Val) (by rfl) + +/-- Certificate step 5: square and reduce modulo the GF64 polynomial. -/ +lemma step_5 : + r4 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + r5 := by + change (BinaryField.toPoly r4Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + BinaryField.toPoly r5Val + exact verify_square_step (rPrev := r4Val) (q := q5Val) + (rNext := r5Val) (by rfl) + +/-- Certificate step 6: square and reduce modulo the GF64 polynomial. -/ +lemma step_6 : + r5 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + r6 := by + change (BinaryField.toPoly r5Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + BinaryField.toPoly r6Val + exact verify_square_step (rPrev := r5Val) (q := q6Val) + (rNext := r6Val) (by rfl) + +/-- Certificate step 7: square and reduce modulo the GF64 polynomial. -/ +lemma step_7 : + r6 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + r7 := by + change (BinaryField.toPoly r6Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + BinaryField.toPoly r7Val + exact verify_square_step (rPrev := r6Val) (q := q7Val) + (rNext := r7Val) (by rfl) + +/-- Certificate step 8: square and reduce modulo the GF64 polynomial. -/ +lemma step_8 : + r7 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + r8 := by + change (BinaryField.toPoly r7Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + BinaryField.toPoly r8Val + exact verify_square_step (rPrev := r7Val) (q := q8Val) + (rNext := r8Val) (by rfl) + +/-- Certificate step 9: square and reduce modulo the GF64 polynomial. -/ +lemma step_9 : + r8 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + r9 := by + change (BinaryField.toPoly r8Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + BinaryField.toPoly r9Val + exact verify_square_step (rPrev := r8Val) (q := q9Val) + (rNext := r9Val) (by rfl) + +/-- Certificate step 10: square and reduce modulo the GF64 polynomial. -/ +lemma step_10 : + r9 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + r10 := by + change (BinaryField.toPoly r9Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + BinaryField.toPoly r10Val + exact verify_square_step (rPrev := r9Val) (q := q10Val) + (rNext := r10Val) (by rfl) + +/-- Certificate step 11: square and reduce modulo the GF64 polynomial. -/ +lemma step_11 : + r10 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + r11 := by + change (BinaryField.toPoly r10Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + BinaryField.toPoly r11Val + exact verify_square_step (rPrev := r10Val) (q := q11Val) + (rNext := r11Val) (by rfl) + +/-- Certificate step 12: square and reduce modulo the GF64 polynomial. -/ +lemma step_12 : + r11 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + r12 := by + change (BinaryField.toPoly r11Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + BinaryField.toPoly r12Val + exact verify_square_step (rPrev := r11Val) (q := q12Val) + (rNext := r12Val) (by rfl) + +/-- Certificate step 13: square and reduce modulo the GF64 polynomial. -/ +lemma step_13 : + r12 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + r13 := by + change (BinaryField.toPoly r12Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + BinaryField.toPoly r13Val + exact verify_square_step (rPrev := r12Val) (q := q13Val) + (rNext := r13Val) (by rfl) + +/-- Certificate step 14: square and reduce modulo the GF64 polynomial. -/ +lemma step_14 : + r13 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + r14 := by + change (BinaryField.toPoly r13Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + BinaryField.toPoly r14Val + exact verify_square_step (rPrev := r13Val) (q := q14Val) + (rNext := r14Val) (by rfl) + +/-- Certificate step 15: square and reduce modulo the GF64 polynomial. -/ +lemma step_15 : + r14 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + r15 := by + change (BinaryField.toPoly r14Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + BinaryField.toPoly r15Val + exact verify_square_step (rPrev := r14Val) (q := q15Val) + (rNext := r15Val) (by rfl) + +/-- Certificate step 16: square and reduce modulo the GF64 polynomial. -/ +lemma step_16 : + r15 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + r16 := by + change (BinaryField.toPoly r15Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + BinaryField.toPoly r16Val + exact verify_square_step (rPrev := r15Val) (q := q16Val) + (rNext := r16Val) (by rfl) + +/-- Certificate step 17: square and reduce modulo the GF64 polynomial. -/ +lemma step_17 : + r16 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + r17 := by + change (BinaryField.toPoly r16Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + BinaryField.toPoly r17Val + exact verify_square_step (rPrev := r16Val) (q := q17Val) + (rNext := r17Val) (by rfl) + +/-- Certificate step 18: square and reduce modulo the GF64 polynomial. -/ +lemma step_18 : + r17 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + r18 := by + change (BinaryField.toPoly r17Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + BinaryField.toPoly r18Val + exact verify_square_step (rPrev := r17Val) (q := q18Val) + (rNext := r18Val) (by rfl) + +/-- Certificate step 19: square and reduce modulo the GF64 polynomial. -/ +lemma step_19 : + r18 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + r19 := by + change (BinaryField.toPoly r18Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + BinaryField.toPoly r19Val + exact verify_square_step (rPrev := r18Val) (q := q19Val) + (rNext := r19Val) (by rfl) + +/-- Certificate step 20: square and reduce modulo the GF64 polynomial. -/ +lemma step_20 : + r19 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + r20 := by + change (BinaryField.toPoly r19Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + BinaryField.toPoly r20Val + exact verify_square_step (rPrev := r19Val) (q := q20Val) + (rNext := r20Val) (by rfl) + +/-- Certificate step 21: square and reduce modulo the GF64 polynomial. -/ +lemma step_21 : + r20 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + r21 := by + change (BinaryField.toPoly r20Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + BinaryField.toPoly r21Val + exact verify_square_step (rPrev := r20Val) (q := q21Val) + (rNext := r21Val) (by rfl) + +/-- Certificate step 22: square and reduce modulo the GF64 polynomial. -/ +lemma step_22 : + r21 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + r22 := by + change (BinaryField.toPoly r21Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + BinaryField.toPoly r22Val + exact verify_square_step (rPrev := r21Val) (q := q22Val) + (rNext := r22Val) (by rfl) + +/-- Certificate step 23: square and reduce modulo the GF64 polynomial. -/ +lemma step_23 : + r22 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + r23 := by + change (BinaryField.toPoly r22Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + BinaryField.toPoly r23Val + exact verify_square_step (rPrev := r22Val) (q := q23Val) + (rNext := r23Val) (by rfl) + +/-- Certificate step 24: square and reduce modulo the GF64 polynomial. -/ +lemma step_24 : + r23 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + r24 := by + change (BinaryField.toPoly r23Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + BinaryField.toPoly r24Val + exact verify_square_step (rPrev := r23Val) (q := q24Val) + (rNext := r24Val) (by rfl) + +/-- Certificate step 25: square and reduce modulo the GF64 polynomial. -/ +lemma step_25 : + r24 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + r25 := by + change (BinaryField.toPoly r24Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + BinaryField.toPoly r25Val + exact verify_square_step (rPrev := r24Val) (q := q25Val) + (rNext := r25Val) (by rfl) + +/-- Certificate step 26: square and reduce modulo the GF64 polynomial. -/ +lemma step_26 : + r25 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + r26 := by + change (BinaryField.toPoly r25Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + BinaryField.toPoly r26Val + exact verify_square_step (rPrev := r25Val) (q := q26Val) + (rNext := r26Val) (by rfl) + +/-- Certificate step 27: square and reduce modulo the GF64 polynomial. -/ +lemma step_27 : + r26 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + r27 := by + change (BinaryField.toPoly r26Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + BinaryField.toPoly r27Val + exact verify_square_step (rPrev := r26Val) (q := q27Val) + (rNext := r27Val) (by rfl) + +/-- Certificate step 28: square and reduce modulo the GF64 polynomial. -/ +lemma step_28 : + r27 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + r28 := by + change (BinaryField.toPoly r27Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + BinaryField.toPoly r28Val + exact verify_square_step (rPrev := r27Val) (q := q28Val) + (rNext := r28Val) (by rfl) + +/-- Certificate step 29: square and reduce modulo the GF64 polynomial. -/ +lemma step_29 : + r28 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + r29 := by + change (BinaryField.toPoly r28Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + BinaryField.toPoly r29Val + exact verify_square_step (rPrev := r28Val) (q := q29Val) + (rNext := r29Val) (by rfl) + +/-- Certificate step 30: square and reduce modulo the GF64 polynomial. -/ +lemma step_30 : + r29 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + r30 := by + change (BinaryField.toPoly r29Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + BinaryField.toPoly r30Val + exact verify_square_step (rPrev := r29Val) (q := q30Val) + (rNext := r30Val) (by rfl) + +/-- Certificate step 31: square and reduce modulo the GF64 polynomial. -/ +lemma step_31 : + r30 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + r31 := by + change (BinaryField.toPoly r30Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + BinaryField.toPoly r31Val + exact verify_square_step (rPrev := r30Val) (q := q31Val) + (rNext := r31Val) (by rfl) + +/-- Certificate step 32: square and reduce modulo the GF64 polynomial. -/ +lemma step_32 : + r31 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + r32 := by + change (BinaryField.toPoly r31Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + BinaryField.toPoly r32Val + exact verify_square_step (rPrev := r31Val) (q := q32Val) + (rNext := r32Val) (by rfl) + +/-- Certificate step 33: square and reduce modulo the GF64 polynomial. -/ +lemma step_33 : + r32 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q33Val) * + definingPolynomial + r33 := by + change (BinaryField.toPoly r32Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q33Val) * + definingPolynomial + BinaryField.toPoly r33Val + exact verify_square_step (rPrev := r32Val) (q := q33Val) + (rNext := r33Val) (by rfl) + +/-- Certificate step 34: square and reduce modulo the GF64 polynomial. -/ +lemma step_34 : + r33 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q34Val) * + definingPolynomial + r34 := by + change (BinaryField.toPoly r33Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q34Val) * + definingPolynomial + BinaryField.toPoly r34Val + exact verify_square_step (rPrev := r33Val) (q := q34Val) + (rNext := r34Val) (by rfl) + +/-- Certificate step 35: square and reduce modulo the GF64 polynomial. -/ +lemma step_35 : + r34 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q35Val) * + definingPolynomial + r35 := by + change (BinaryField.toPoly r34Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q35Val) * + definingPolynomial + BinaryField.toPoly r35Val + exact verify_square_step (rPrev := r34Val) (q := q35Val) + (rNext := r35Val) (by rfl) + +/-- Certificate step 36: square and reduce modulo the GF64 polynomial. -/ +lemma step_36 : + r35 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q36Val) * + definingPolynomial + r36 := by + change (BinaryField.toPoly r35Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q36Val) * + definingPolynomial + BinaryField.toPoly r36Val + exact verify_square_step (rPrev := r35Val) (q := q36Val) + (rNext := r36Val) (by rfl) + +/-- Certificate step 37: square and reduce modulo the GF64 polynomial. -/ +lemma step_37 : + r36 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q37Val) * + definingPolynomial + r37 := by + change (BinaryField.toPoly r36Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q37Val) * + definingPolynomial + BinaryField.toPoly r37Val + exact verify_square_step (rPrev := r36Val) (q := q37Val) + (rNext := r37Val) (by rfl) + +/-- Certificate step 38: square and reduce modulo the GF64 polynomial. -/ +lemma step_38 : + r37 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q38Val) * + definingPolynomial + r38 := by + change (BinaryField.toPoly r37Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q38Val) * + definingPolynomial + BinaryField.toPoly r38Val + exact verify_square_step (rPrev := r37Val) (q := q38Val) + (rNext := r38Val) (by rfl) + +/-- Certificate step 39: square and reduce modulo the GF64 polynomial. -/ +lemma step_39 : + r38 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q39Val) * + definingPolynomial + r39 := by + change (BinaryField.toPoly r38Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q39Val) * + definingPolynomial + BinaryField.toPoly r39Val + exact verify_square_step (rPrev := r38Val) (q := q39Val) + (rNext := r39Val) (by rfl) + +/-- Certificate step 40: square and reduce modulo the GF64 polynomial. -/ +lemma step_40 : + r39 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q40Val) * + definingPolynomial + r40 := by + change (BinaryField.toPoly r39Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q40Val) * + definingPolynomial + BinaryField.toPoly r40Val + exact verify_square_step (rPrev := r39Val) (q := q40Val) + (rNext := r40Val) (by rfl) + +/-- Certificate step 41: square and reduce modulo the GF64 polynomial. -/ +lemma step_41 : + r40 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q41Val) * + definingPolynomial + r41 := by + change (BinaryField.toPoly r40Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q41Val) * + definingPolynomial + BinaryField.toPoly r41Val + exact verify_square_step (rPrev := r40Val) (q := q41Val) + (rNext := r41Val) (by rfl) + +/-- Certificate step 42: square and reduce modulo the GF64 polynomial. -/ +lemma step_42 : + r41 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q42Val) * + definingPolynomial + r42 := by + change (BinaryField.toPoly r41Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q42Val) * + definingPolynomial + BinaryField.toPoly r42Val + exact verify_square_step (rPrev := r41Val) (q := q42Val) + (rNext := r42Val) (by rfl) + +/-- Certificate step 43: square and reduce modulo the GF64 polynomial. -/ +lemma step_43 : + r42 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q43Val) * + definingPolynomial + r43 := by + change (BinaryField.toPoly r42Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q43Val) * + definingPolynomial + BinaryField.toPoly r43Val + exact verify_square_step (rPrev := r42Val) (q := q43Val) + (rNext := r43Val) (by rfl) + +/-- Certificate step 44: square and reduce modulo the GF64 polynomial. -/ +lemma step_44 : + r43 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q44Val) * + definingPolynomial + r44 := by + change (BinaryField.toPoly r43Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q44Val) * + definingPolynomial + BinaryField.toPoly r44Val + exact verify_square_step (rPrev := r43Val) (q := q44Val) + (rNext := r44Val) (by rfl) + +/-- Certificate step 45: square and reduce modulo the GF64 polynomial. -/ +lemma step_45 : + r44 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q45Val) * + definingPolynomial + r45 := by + change (BinaryField.toPoly r44Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q45Val) * + definingPolynomial + BinaryField.toPoly r45Val + exact verify_square_step (rPrev := r44Val) (q := q45Val) + (rNext := r45Val) (by rfl) + +/-- Certificate step 46: square and reduce modulo the GF64 polynomial. -/ +lemma step_46 : + r45 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q46Val) * + definingPolynomial + r46 := by + change (BinaryField.toPoly r45Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q46Val) * + definingPolynomial + BinaryField.toPoly r46Val + exact verify_square_step (rPrev := r45Val) (q := q46Val) + (rNext := r46Val) (by rfl) + +/-- Certificate step 47: square and reduce modulo the GF64 polynomial. -/ +lemma step_47 : + r46 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q47Val) * + definingPolynomial + r47 := by + change (BinaryField.toPoly r46Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q47Val) * + definingPolynomial + BinaryField.toPoly r47Val + exact verify_square_step (rPrev := r46Val) (q := q47Val) + (rNext := r47Val) (by rfl) + +/-- Certificate step 48: square and reduce modulo the GF64 polynomial. -/ +lemma step_48 : + r47 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q48Val) * + definingPolynomial + r48 := by + change (BinaryField.toPoly r47Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q48Val) * + definingPolynomial + BinaryField.toPoly r48Val + exact verify_square_step (rPrev := r47Val) (q := q48Val) + (rNext := r48Val) (by rfl) + +/-- Certificate step 49: square and reduce modulo the GF64 polynomial. -/ +lemma step_49 : + r48 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q49Val) * + definingPolynomial + r49 := by + change (BinaryField.toPoly r48Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q49Val) * + definingPolynomial + BinaryField.toPoly r49Val + exact verify_square_step (rPrev := r48Val) (q := q49Val) + (rNext := r49Val) (by rfl) + +/-- Certificate step 50: square and reduce modulo the GF64 polynomial. -/ +lemma step_50 : + r49 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q50Val) * + definingPolynomial + r50 := by + change (BinaryField.toPoly r49Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q50Val) * + definingPolynomial + BinaryField.toPoly r50Val + exact verify_square_step (rPrev := r49Val) (q := q50Val) + (rNext := r50Val) (by rfl) + +/-- Certificate step 51: square and reduce modulo the GF64 polynomial. -/ +lemma step_51 : + r50 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q51Val) * + definingPolynomial + r51 := by + change (BinaryField.toPoly r50Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q51Val) * + definingPolynomial + BinaryField.toPoly r51Val + exact verify_square_step (rPrev := r50Val) (q := q51Val) + (rNext := r51Val) (by rfl) + +/-- Certificate step 52: square and reduce modulo the GF64 polynomial. -/ +lemma step_52 : + r51 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q52Val) * + definingPolynomial + r52 := by + change (BinaryField.toPoly r51Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q52Val) * + definingPolynomial + BinaryField.toPoly r52Val + exact verify_square_step (rPrev := r51Val) (q := q52Val) + (rNext := r52Val) (by rfl) + +/-- Certificate step 53: square and reduce modulo the GF64 polynomial. -/ +lemma step_53 : + r52 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q53Val) * + definingPolynomial + r53 := by + change (BinaryField.toPoly r52Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q53Val) * + definingPolynomial + BinaryField.toPoly r53Val + exact verify_square_step (rPrev := r52Val) (q := q53Val) + (rNext := r53Val) (by rfl) + +/-- Certificate step 54: square and reduce modulo the GF64 polynomial. -/ +lemma step_54 : + r53 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q54Val) * + definingPolynomial + r54 := by + change (BinaryField.toPoly r53Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q54Val) * + definingPolynomial + BinaryField.toPoly r54Val + exact verify_square_step (rPrev := r53Val) (q := q54Val) + (rNext := r54Val) (by rfl) + +/-- Certificate step 55: square and reduce modulo the GF64 polynomial. -/ +lemma step_55 : + r54 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q55Val) * + definingPolynomial + r55 := by + change (BinaryField.toPoly r54Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q55Val) * + definingPolynomial + BinaryField.toPoly r55Val + exact verify_square_step (rPrev := r54Val) (q := q55Val) + (rNext := r55Val) (by rfl) + +/-- Certificate step 56: square and reduce modulo the GF64 polynomial. -/ +lemma step_56 : + r55 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q56Val) * + definingPolynomial + r56 := by + change (BinaryField.toPoly r55Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q56Val) * + definingPolynomial + BinaryField.toPoly r56Val + exact verify_square_step (rPrev := r55Val) (q := q56Val) + (rNext := r56Val) (by rfl) + +/-- Certificate step 57: square and reduce modulo the GF64 polynomial. -/ +lemma step_57 : + r56 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q57Val) * + definingPolynomial + r57 := by + change (BinaryField.toPoly r56Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q57Val) * + definingPolynomial + BinaryField.toPoly r57Val + exact verify_square_step (rPrev := r56Val) (q := q57Val) + (rNext := r57Val) (by rfl) + +/-- Certificate step 58: square and reduce modulo the GF64 polynomial. -/ +lemma step_58 : + r57 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q58Val) * + definingPolynomial + r58 := by + change (BinaryField.toPoly r57Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q58Val) * + definingPolynomial + BinaryField.toPoly r58Val + exact verify_square_step (rPrev := r57Val) (q := q58Val) + (rNext := r58Val) (by rfl) + +/-- Certificate step 59: square and reduce modulo the GF64 polynomial. -/ +lemma step_59 : + r58 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q59Val) * + definingPolynomial + r59 := by + change (BinaryField.toPoly r58Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q59Val) * + definingPolynomial + BinaryField.toPoly r59Val + exact verify_square_step (rPrev := r58Val) (q := q59Val) + (rNext := r59Val) (by rfl) + +/-- Certificate step 60: square and reduce modulo the GF64 polynomial. -/ +lemma step_60 : + r59 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q60Val) * + definingPolynomial + r60 := by + change (BinaryField.toPoly r59Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q60Val) * + definingPolynomial + BinaryField.toPoly r60Val + exact verify_square_step (rPrev := r59Val) (q := q60Val) + (rNext := r60Val) (by rfl) + +/-- Certificate step 61: square and reduce modulo the GF64 polynomial. -/ +lemma step_61 : + r60 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q61Val) * + definingPolynomial + r61 := by + change (BinaryField.toPoly r60Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q61Val) * + definingPolynomial + BinaryField.toPoly r61Val + exact verify_square_step (rPrev := r60Val) (q := q61Val) + (rNext := r61Val) (by rfl) + +/-- Certificate step 62: square and reduce modulo the GF64 polynomial. -/ +lemma step_62 : + r61 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q62Val) * + definingPolynomial + r62 := by + change (BinaryField.toPoly r61Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q62Val) * + definingPolynomial + BinaryField.toPoly r62Val + exact verify_square_step (rPrev := r61Val) (q := q62Val) + (rNext := r62Val) (by rfl) + +/-- Certificate step 63: square and reduce modulo the GF64 polynomial. -/ +lemma step_63 : + r62 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q63Val) * + definingPolynomial + r63 := by + change (BinaryField.toPoly r62Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q63Val) * + definingPolynomial + BinaryField.toPoly r63Val + exact verify_square_step (rPrev := r62Val) (q := q63Val) + (rNext := r63Val) (by rfl) + +/-- Certificate step 64: square and reduce modulo the GF64 polynomial. -/ +lemma step_64 : + r63 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q64Val) * + definingPolynomial + r64 := by + change (BinaryField.toPoly r63Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q64Val) * + definingPolynomial + BinaryField.toPoly r64Val + exact verify_square_step (rPrev := r63Val) (q := q64Val) + (rNext := r64Val) (by rfl) + + +/-- The degree-one polynomial `X` is already reduced modulo the GF64 polynomial. -/ +lemma X_mod_definingPolynomial : + X % definingPolynomial = X := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + unfold extensionDegree + norm_num [degree_X] + +lemma X_pow_2_pow_0_mod_eq : + X ^ (2 ^ 0) % definingPolynomial = r0 % definingPolynomial := by + rw [pow_zero, pow_one, r0_eq_X] + +lemma X_pow_2_pow_1_mod_eq : + X ^ (2 ^ 1) % definingPolynomial = r1 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 0) X_pow_2_pow_0_mod_eq step_1 + +lemma X_pow_2_pow_2_mod_eq : + X ^ (2 ^ 2) % definingPolynomial = r2 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 1) X_pow_2_pow_1_mod_eq step_2 + +lemma X_pow_2_pow_3_mod_eq : + X ^ (2 ^ 3) % definingPolynomial = r3 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 2) X_pow_2_pow_2_mod_eq step_3 + +lemma X_pow_2_pow_4_mod_eq : + X ^ (2 ^ 4) % definingPolynomial = r4 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 3) X_pow_2_pow_3_mod_eq step_4 + +lemma X_pow_2_pow_5_mod_eq : + X ^ (2 ^ 5) % definingPolynomial = r5 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 4) X_pow_2_pow_4_mod_eq step_5 + +lemma X_pow_2_pow_6_mod_eq : + X ^ (2 ^ 6) % definingPolynomial = r6 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 5) X_pow_2_pow_5_mod_eq step_6 + +lemma X_pow_2_pow_7_mod_eq : + X ^ (2 ^ 7) % definingPolynomial = r7 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 6) X_pow_2_pow_6_mod_eq step_7 + +lemma X_pow_2_pow_8_mod_eq : + X ^ (2 ^ 8) % definingPolynomial = r8 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 7) X_pow_2_pow_7_mod_eq step_8 + +lemma X_pow_2_pow_9_mod_eq : + X ^ (2 ^ 9) % definingPolynomial = r9 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 8) X_pow_2_pow_8_mod_eq step_9 + +lemma X_pow_2_pow_10_mod_eq : + X ^ (2 ^ 10) % definingPolynomial = r10 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 9) X_pow_2_pow_9_mod_eq step_10 + +lemma X_pow_2_pow_11_mod_eq : + X ^ (2 ^ 11) % definingPolynomial = r11 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 10) X_pow_2_pow_10_mod_eq step_11 + +lemma X_pow_2_pow_12_mod_eq : + X ^ (2 ^ 12) % definingPolynomial = r12 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 11) X_pow_2_pow_11_mod_eq step_12 + +lemma X_pow_2_pow_13_mod_eq : + X ^ (2 ^ 13) % definingPolynomial = r13 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 12) X_pow_2_pow_12_mod_eq step_13 + +lemma X_pow_2_pow_14_mod_eq : + X ^ (2 ^ 14) % definingPolynomial = r14 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 13) X_pow_2_pow_13_mod_eq step_14 + +lemma X_pow_2_pow_15_mod_eq : + X ^ (2 ^ 15) % definingPolynomial = r15 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 14) X_pow_2_pow_14_mod_eq step_15 + +lemma X_pow_2_pow_16_mod_eq : + X ^ (2 ^ 16) % definingPolynomial = r16 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 15) X_pow_2_pow_15_mod_eq step_16 + +lemma X_pow_2_pow_17_mod_eq : + X ^ (2 ^ 17) % definingPolynomial = r17 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 16) X_pow_2_pow_16_mod_eq step_17 + +lemma X_pow_2_pow_18_mod_eq : + X ^ (2 ^ 18) % definingPolynomial = r18 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 17) X_pow_2_pow_17_mod_eq step_18 + +lemma X_pow_2_pow_19_mod_eq : + X ^ (2 ^ 19) % definingPolynomial = r19 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 18) X_pow_2_pow_18_mod_eq step_19 + +lemma X_pow_2_pow_20_mod_eq : + X ^ (2 ^ 20) % definingPolynomial = r20 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 19) X_pow_2_pow_19_mod_eq step_20 + +lemma X_pow_2_pow_21_mod_eq : + X ^ (2 ^ 21) % definingPolynomial = r21 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 20) X_pow_2_pow_20_mod_eq step_21 + +lemma X_pow_2_pow_22_mod_eq : + X ^ (2 ^ 22) % definingPolynomial = r22 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 21) X_pow_2_pow_21_mod_eq step_22 + +lemma X_pow_2_pow_23_mod_eq : + X ^ (2 ^ 23) % definingPolynomial = r23 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 22) X_pow_2_pow_22_mod_eq step_23 + +lemma X_pow_2_pow_24_mod_eq : + X ^ (2 ^ 24) % definingPolynomial = r24 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 23) X_pow_2_pow_23_mod_eq step_24 + +lemma X_pow_2_pow_25_mod_eq : + X ^ (2 ^ 25) % definingPolynomial = r25 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 24) X_pow_2_pow_24_mod_eq step_25 + +lemma X_pow_2_pow_26_mod_eq : + X ^ (2 ^ 26) % definingPolynomial = r26 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 25) X_pow_2_pow_25_mod_eq step_26 + +lemma X_pow_2_pow_27_mod_eq : + X ^ (2 ^ 27) % definingPolynomial = r27 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 26) X_pow_2_pow_26_mod_eq step_27 + +lemma X_pow_2_pow_28_mod_eq : + X ^ (2 ^ 28) % definingPolynomial = r28 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 27) X_pow_2_pow_27_mod_eq step_28 + +lemma X_pow_2_pow_29_mod_eq : + X ^ (2 ^ 29) % definingPolynomial = r29 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 28) X_pow_2_pow_28_mod_eq step_29 + +lemma X_pow_2_pow_30_mod_eq : + X ^ (2 ^ 30) % definingPolynomial = r30 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 29) X_pow_2_pow_29_mod_eq step_30 + +lemma X_pow_2_pow_31_mod_eq : + X ^ (2 ^ 31) % definingPolynomial = r31 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 30) X_pow_2_pow_30_mod_eq step_31 + +lemma X_pow_2_pow_32_mod_eq : + X ^ (2 ^ 32) % definingPolynomial = r32 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 31) X_pow_2_pow_31_mod_eq step_32 + +lemma X_pow_2_pow_33_mod_eq : + X ^ (2 ^ 33) % definingPolynomial = r33 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 32) X_pow_2_pow_32_mod_eq step_33 + +lemma X_pow_2_pow_34_mod_eq : + X ^ (2 ^ 34) % definingPolynomial = r34 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 33) X_pow_2_pow_33_mod_eq step_34 + +lemma X_pow_2_pow_35_mod_eq : + X ^ (2 ^ 35) % definingPolynomial = r35 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 34) X_pow_2_pow_34_mod_eq step_35 + +lemma X_pow_2_pow_36_mod_eq : + X ^ (2 ^ 36) % definingPolynomial = r36 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 35) X_pow_2_pow_35_mod_eq step_36 + +lemma X_pow_2_pow_37_mod_eq : + X ^ (2 ^ 37) % definingPolynomial = r37 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 36) X_pow_2_pow_36_mod_eq step_37 + +lemma X_pow_2_pow_38_mod_eq : + X ^ (2 ^ 38) % definingPolynomial = r38 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 37) X_pow_2_pow_37_mod_eq step_38 + +lemma X_pow_2_pow_39_mod_eq : + X ^ (2 ^ 39) % definingPolynomial = r39 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 38) X_pow_2_pow_38_mod_eq step_39 + +lemma X_pow_2_pow_40_mod_eq : + X ^ (2 ^ 40) % definingPolynomial = r40 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 39) X_pow_2_pow_39_mod_eq step_40 + +lemma X_pow_2_pow_41_mod_eq : + X ^ (2 ^ 41) % definingPolynomial = r41 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 40) X_pow_2_pow_40_mod_eq step_41 + +lemma X_pow_2_pow_42_mod_eq : + X ^ (2 ^ 42) % definingPolynomial = r42 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 41) X_pow_2_pow_41_mod_eq step_42 + +lemma X_pow_2_pow_43_mod_eq : + X ^ (2 ^ 43) % definingPolynomial = r43 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 42) X_pow_2_pow_42_mod_eq step_43 + +lemma X_pow_2_pow_44_mod_eq : + X ^ (2 ^ 44) % definingPolynomial = r44 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 43) X_pow_2_pow_43_mod_eq step_44 + +lemma X_pow_2_pow_45_mod_eq : + X ^ (2 ^ 45) % definingPolynomial = r45 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 44) X_pow_2_pow_44_mod_eq step_45 + +lemma X_pow_2_pow_46_mod_eq : + X ^ (2 ^ 46) % definingPolynomial = r46 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 45) X_pow_2_pow_45_mod_eq step_46 + +lemma X_pow_2_pow_47_mod_eq : + X ^ (2 ^ 47) % definingPolynomial = r47 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 46) X_pow_2_pow_46_mod_eq step_47 + +lemma X_pow_2_pow_48_mod_eq : + X ^ (2 ^ 48) % definingPolynomial = r48 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 47) X_pow_2_pow_47_mod_eq step_48 + +lemma X_pow_2_pow_49_mod_eq : + X ^ (2 ^ 49) % definingPolynomial = r49 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 48) X_pow_2_pow_48_mod_eq step_49 + +lemma X_pow_2_pow_50_mod_eq : + X ^ (2 ^ 50) % definingPolynomial = r50 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 49) X_pow_2_pow_49_mod_eq step_50 + +lemma X_pow_2_pow_51_mod_eq : + X ^ (2 ^ 51) % definingPolynomial = r51 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 50) X_pow_2_pow_50_mod_eq step_51 + +lemma X_pow_2_pow_52_mod_eq : + X ^ (2 ^ 52) % definingPolynomial = r52 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 51) X_pow_2_pow_51_mod_eq step_52 + +lemma X_pow_2_pow_53_mod_eq : + X ^ (2 ^ 53) % definingPolynomial = r53 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 52) X_pow_2_pow_52_mod_eq step_53 + +lemma X_pow_2_pow_54_mod_eq : + X ^ (2 ^ 54) % definingPolynomial = r54 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 53) X_pow_2_pow_53_mod_eq step_54 + +lemma X_pow_2_pow_55_mod_eq : + X ^ (2 ^ 55) % definingPolynomial = r55 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 54) X_pow_2_pow_54_mod_eq step_55 + +lemma X_pow_2_pow_56_mod_eq : + X ^ (2 ^ 56) % definingPolynomial = r56 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 55) X_pow_2_pow_55_mod_eq step_56 + +lemma X_pow_2_pow_57_mod_eq : + X ^ (2 ^ 57) % definingPolynomial = r57 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 56) X_pow_2_pow_56_mod_eq step_57 + +lemma X_pow_2_pow_58_mod_eq : + X ^ (2 ^ 58) % definingPolynomial = r58 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 57) X_pow_2_pow_57_mod_eq step_58 + +lemma X_pow_2_pow_59_mod_eq : + X ^ (2 ^ 59) % definingPolynomial = r59 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 58) X_pow_2_pow_58_mod_eq step_59 + +lemma X_pow_2_pow_60_mod_eq : + X ^ (2 ^ 60) % definingPolynomial = r60 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 59) X_pow_2_pow_59_mod_eq step_60 + +lemma X_pow_2_pow_61_mod_eq : + X ^ (2 ^ 61) % definingPolynomial = r61 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 60) X_pow_2_pow_60_mod_eq step_61 + +lemma X_pow_2_pow_62_mod_eq : + X ^ (2 ^ 62) % definingPolynomial = r62 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 61) X_pow_2_pow_61_mod_eq step_62 + +lemma X_pow_2_pow_63_mod_eq : + X ^ (2 ^ 63) % definingPolynomial = r63 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 62) X_pow_2_pow_62_mod_eq step_63 + +lemma X_pow_2_pow_64_mod_eq : + X ^ (2 ^ 64) % definingPolynomial = r64 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 63) X_pow_2_pow_63_mod_eq step_64 + +/-- Rabin trace-condition remainder for the GF64 candidate polynomial. -/ +lemma X_pow_2_pow_64_add_X_mod_eq_zero : + (X ^ (2 ^ 64) + X) % definingPolynomial = 0 := by + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_64_mod_eq, r64_eq_X, X_mod_definingPolynomial] + simp only [CharTwo.add_self_eq_zero, EuclideanDomain.zero_mod] + +/-- Rabin trace divisibility condition for the GF64 candidate polynomial. -/ +lemma X_pow_2_pow_64_add_X_dvd : + definingPolynomial ∣ X ^ (2 ^ 64) + X := by + rw [← EuclideanDomain.mod_eq_zero] + exact X_pow_2_pow_64_add_X_mod_eq_zero + +end GF2_64 diff --git a/CompPoly/Fields/Binary/GF2_72.lean b/CompPoly/Fields/Binary/GF2_72.lean new file mode 100644 index 00000000..ef930796 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72.lean @@ -0,0 +1,16 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_72.Prelude +import CompPoly.Fields.Binary.GF2_72.Basic +import CompPoly.Fields.Binary.GF2_72.Impl +import CompPoly.Fields.Binary.GF2_72.XPowTwoPowModCertificate +import CompPoly.Fields.Binary.GF2_72.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_72.PrimitivePowerCertificate +import CompPoly.Fields.Binary.GF2_72.Primitive +import CompPoly.Fields.Binary.GF2_72.RootContexts + +/-! # GF(2^72) Binary Field Facade -/ diff --git a/CompPoly/Fields/Binary/GF2_72/Basic.lean b/CompPoly/Fields/Binary/GF2_72/Basic.lean new file mode 100644 index 00000000..4116300b --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/Basic.lean @@ -0,0 +1,83 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Basic +import CompPoly.Fields.Binary.GF2_72.Prelude + +/-! +# GF(2^72) Quotient Specification + +The quotient/specification carrier for the candidate polynomial +`X^72 + X^6 + X^4 + X^3 + X^2 + X + 1`. + +Field, finite, characteristic, and cardinality instances are conditional on the +irreducibility certificate that will be provided by the concrete certificate +modules. +-/ + +namespace GF2_72 + +open Polynomial AdjoinRoot + +noncomputable section + +/-- Quotient/specification carrier for `GF(2^72)`. -/ +abbrev SpecField : Type := + BinaryField.Extension.SpecField definingPolynomialData + +private instance instIrreduciblePolynomialFact [Fact (Irreducible definingPolynomial)] : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using (inferInstance : Fact (Irreducible definingPolynomial)) + +/-- Conditional field instance, available once irreducibility is certified. -/ +instance instFieldSpecField [Fact (Irreducible definingPolynomial)] : + Field SpecField := + inferInstanceAs (Field (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional nontriviality, available once irreducibility is certified. -/ +instance instNontrivialSpecField [Fact (Irreducible definingPolynomial)] : + Nontrivial SpecField := + inferInstance + +/-- Quotient/specification carrier is inhabited. -/ +instance instInhabitedSpecField : Inhabited SpecField := + inferInstance + +/-- Algebra structure over `GF(2)`. -/ +instance instAlgebraSpecField : Algebra (ZMod 2) SpecField := + inferInstanceAs (Algebra (ZMod 2) (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Conditional characteristic-two instance, available once irreducibility is certified. -/ +instance instCharTwoSpecField [Fact (Irreducible definingPolynomial)] : + CharP SpecField 2 := + inferInstance + +/-- Canonical embedding of `GF(2)` into `SpecField`. -/ +def ofGF2 : ZMod 2 →+* SpecField := + BinaryField.Extension.ofGF2 definingPolynomialData + +/-- The quotient root/generator. -/ +def root : SpecField := + BinaryField.Extension.root definingPolynomialData + +/-- The quotient root satisfies the defining polynomial. -/ +theorem root_satisfies_definingPolynomial : + Polynomial.eval₂ (algebraMap (ZMod 2) SpecField) root definingPolynomial = 0 := + BinaryField.Extension.root_satisfies_polynomial definingPolynomialData + +/-- Conditional finite type, available once irreducibility is certified. -/ +instance instFintypeSpecField [Fact (Irreducible definingPolynomial)] : + Fintype SpecField := + inferInstanceAs (Fintype (BinaryField.Extension.SpecField definingPolynomialData)) + +/-- Cardinality of the certified quotient specification. -/ +theorem SpecField_card [Fact (Irreducible definingPolynomial)] : + Fintype.card SpecField = 2 ^ extensionDegree := + BinaryField.Extension.specField_card definingPolynomialData + +end + +end GF2_72 diff --git a/CompPoly/Fields/Binary/GF2_72/Impl.lean b/CompPoly/Fields/Binary/GF2_72/Impl.lean new file mode 100644 index 00000000..b6552238 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/Impl.lean @@ -0,0 +1,365 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Impl +import CompPoly.Fields.Binary.GF2_72.Basic +import Mathlib.Algebra.Algebra.ZMod +import Mathlib.Algebra.CharP.CharAndCard +import Init.Data.Array.Lemmas + +/-! +# GF(2^72) Executable Bit-Vector Operations + +Executable operations for the `GF(2^72)` candidate polynomial +`X^72 + X^6 + X^4 + X^3 + X^2 + X + 1`. + +This file exposes the raw `BitVec` carrier and arithmetic definitions. It does +claim the certified `Field` instance conditionally on the irreducibility +certificate supplied by `GF2_72.Primitive`. +-/ + +namespace GF2_72 + +namespace Concrete + +/-- Executable parameters for the `GF(2^72)` candidate polynomial. -/ +def params : BinaryField.Extension.ExecutableParams where + degree := extensionDegree + tailExponents := [0, 1, 2, 3, 4, 6] + tailExponents_bound := by + intro exponent h + simp at h + rcases h with rfl | rfl | rfl | rfl | rfl | rfl <;> unfold extensionDegree <;> omega + +/-- The executable tail list denotes the low-degree part of the GF72 polynomial. -/ +lemma definingPolynomial_eq_executableSparse : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ params.degree + + BinaryField.Extension.sparsePolynomial params.tailExponents := by + rw [show BinaryField.Extension.polynomial definingPolynomialData = definingPolynomial by rfl] + rw [definingPolynomial_eq_X_pow_add_tail] + simp [params, extensionDegree, definingTail, BinaryField.Extension.sparsePolynomial] + ring_nf + +end Concrete + +/-- Executable bit-vector carrier for `GF(2^72)`. -/ +@[reducible] +def ConcreteField : Type := + BinaryField.Extension.ConcreteField Concrete.params + +namespace ConcreteField + +abbrev rawWidth : Nat := + extensionDegree + +def toBitVec : ConcreteField → B72 := + BinaryField.Extension.Concrete.toBitVec Concrete.params + +def ofBitVec : B72 → ConcreteField := + BinaryField.Extension.Concrete.ofBitVec Concrete.params + +def toNat : ConcreteField → Nat := + BinaryField.Extension.Concrete.toNat Concrete.params + +def ofNat (n : Nat) : ConcreteField := + BinaryField.Extension.Concrete.ofNat Concrete.params n + +def root : ConcreteField := + BinaryField.Extension.Concrete.root Concrete.params + +def add : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.add Concrete.params + +def mul : ConcreteField → ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.mul Concrete.params + +def square : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.square Concrete.params + +def pow : ConcreteField → Nat → ConcreteField := + BinaryField.Extension.Concrete.pow Concrete.params + +def inv : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.inv Concrete.params + +def traceValue : ConcreteField → ConcreteField := + BinaryField.Extension.Concrete.traceValue Concrete.params + +def polynomialBasis : Array ConcreteField := + BinaryField.Extension.Concrete.polynomialBasis Concrete.params + +def baseConstants : Array ConcreteField := + BinaryField.Extension.Concrete.baseConstants Concrete.params + +noncomputable def toSpec : ConcreteField → SpecField := + BinaryField.Extension.Concrete.toSpec Concrete.params (data := definingPolynomialData) + +instance : BEq ConcreteField := + BinaryField.Extension.Concrete.instBEqConcreteField Concrete.params + +instance : LawfulBEq ConcreteField := + BinaryField.Extension.Concrete.instLawfulBEqConcreteField Concrete.params + +instance : Inhabited ConcreteField := + BinaryField.Extension.Concrete.instInhabitedConcreteField Concrete.params + +instance : Zero ConcreteField := + BinaryField.Extension.Concrete.instZeroConcreteField Concrete.params + +instance : One ConcreteField := + BinaryField.Extension.Concrete.instOneConcreteField Concrete.params + +instance : Add ConcreteField := + BinaryField.Extension.Concrete.instAddConcreteField Concrete.params + +instance : Neg ConcreteField := + BinaryField.Extension.Concrete.instNegConcreteField Concrete.params + +instance : Sub ConcreteField := + BinaryField.Extension.Concrete.instSubConcreteField Concrete.params + +instance : Mul ConcreteField := + BinaryField.Extension.Concrete.instMulConcreteField Concrete.params + +instance : Pow ConcreteField Nat := + BinaryField.Extension.Concrete.instPowConcreteField Concrete.params + +instance : Inv ConcreteField := + BinaryField.Extension.Concrete.instInvConcreteField Concrete.params + +/-- Certified executable field structure for `GF(2^72)`. -/ +instance (priority := 2000) instFieldConcreteField + [Fact (Irreducible definingPolynomial)] : + Field ConcreteField := by + haveI : + Fact (Irreducible (BinaryField.Extension.polynomial definingPolynomialData)) := by + simpa [definingPolynomial] using + (inferInstance : Fact (Irreducible definingPolynomial)) + let hP : + BinaryField.Extension.polynomial definingPolynomialData = + Polynomial.X ^ Concrete.params.degree + + BinaryField.Extension.sparsePolynomial Concrete.params.tailExponents := + Concrete.definingPolynomial_eq_executableSparse + let hP_degree : + (BinaryField.Extension.polynomial definingPolynomialData).degree = + Concrete.params.degree := by + simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + let hDegree_pos : 0 < Concrete.params.degree := by + unfold Concrete.params extensionDegree + norm_num + exact + { toDivisionRing := + { toRing := + { add := BinaryField.Extension.Concrete.add Concrete.params + zero := BinaryField.Extension.Concrete.zero Concrete.params + neg := BinaryField.Extension.Concrete.neg Concrete.params + sub := BinaryField.Extension.Concrete.sub Concrete.params + mul := BinaryField.Extension.Concrete.mul Concrete.params + one := BinaryField.Extension.Concrete.one Concrete.params + nsmul := fun n x => + if n % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + zsmul := fun n x => + if n % 2 = 0 then BinaryField.Extension.Concrete.zero Concrete.params else x + npow := fun n x => BinaryField.Extension.Concrete.pow Concrete.params x n + add_assoc := BinaryField.Extension.Concrete.add_assoc Concrete.params + add_comm := BinaryField.Extension.Concrete.add_comm Concrete.params + add_zero := BinaryField.Extension.Concrete.add_zero Concrete.params + zero_add := BinaryField.Extension.Concrete.zero_add Concrete.params + neg_add_cancel := BinaryField.Extension.Concrete.neg_add_cancel Concrete.params + sub_eq_add_neg := by intro _ _; rfl + nsmul_zero := fun _ => rfl + nsmul_succ := BinaryField.Extension.Concrete.nsmul_succ Concrete.params + zsmul_zero' := fun _ => rfl + zsmul_succ' := BinaryField.Extension.Concrete.zsmul_succ Concrete.params + zsmul_neg' := BinaryField.Extension.Concrete.zsmul_neg Concrete.params + mul_assoc := + BinaryField.Extension.Concrete.mul_assoc_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + one_mul := + BinaryField.Extension.Concrete.one_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_one := + BinaryField.Extension.Concrete.mul_one_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + left_distrib := + BinaryField.Extension.Concrete.left_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + right_distrib := + BinaryField.Extension.Concrete.right_distrib_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + zero_mul := + BinaryField.Extension.Concrete.zero_mul_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + mul_zero := + BinaryField.Extension.Concrete.mul_zero_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos + natCast := BinaryField.Extension.Concrete.natCast Concrete.params + natCast_zero := BinaryField.Extension.Concrete.natCast_zero Concrete.params + natCast_succ := BinaryField.Extension.Concrete.natCast_succ Concrete.params + intCast := BinaryField.Extension.Concrete.intCast Concrete.params + intCast_ofNat := BinaryField.Extension.Concrete.intCast_ofNat Concrete.params + intCast_negSucc := BinaryField.Extension.Concrete.intCast_negSucc Concrete.params + npow_zero := by + intro x + change BinaryField.Extension.Concrete.pow Concrete.params x 0 = + BinaryField.Extension.Concrete.one Concrete.params + simp [BinaryField.Extension.Concrete.pow] + npow_succ := by + intro n x + change BinaryField.Extension.Concrete.pow Concrete.params x (n + 1) = + BinaryField.Extension.Concrete.mul Concrete.params + (BinaryField.Extension.Concrete.pow Concrete.params x n) x + exact BinaryField.Extension.Concrete.pow_succ_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos n x } + inv := BinaryField.Extension.Concrete.inv Concrete.params + div := fun a b => + BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params b) + exists_pair_ne := + BinaryField.Extension.Concrete.exists_pair_ne Concrete.params hDegree_pos + mul_inv_cancel := by + intro a h + change BinaryField.Extension.Concrete.mul Concrete.params a + (BinaryField.Extension.Concrete.inv Concrete.params a) = + BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.mul_inv_cancel_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a (by simpa using h) + inv_zero := by + change BinaryField.Extension.Concrete.inv Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = + BinaryField.Extension.Concrete.zero Concrete.params + exact BinaryField.Extension.Concrete.inv_zero Concrete.params + div_eq_mul_inv := by + intro a b + rfl + qsmul := _ + nnqsmul := _ } + mul_comm := by + intro a b + change BinaryField.Extension.Concrete.mul Concrete.params a b = + BinaryField.Extension.Concrete.mul Concrete.params b a + exact BinaryField.Extension.Concrete.mul_comm_of_spec Concrete.params + (data := definingPolynomialData) hP hP_degree hDegree_pos a b } + +noncomputable instance : Fintype ConcreteField := + BinaryField.Extension.Concrete.instFintypeConcreteField Concrete.params + +instance : Finite ConcreteField := + BinaryField.Extension.Concrete.instFiniteConcreteField Concrete.params + +/-- The raw executable carrier has `2^72` bit-patterns. -/ +theorem card : + Fintype.card ConcreteField = 2 ^ extensionDegree := by + simpa [Concrete.params] using + BinaryField.Extension.Concrete.concreteField_card Concrete.params + +/-- The certified executable carrier has characteristic two. -/ +noncomputable instance instCharTwoConcreteField [Fact (Irreducible definingPolynomial)] : + CharP ConcreteField 2 := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : IsDomain ConcreteField := Field.isDomain + haveI : Fact (Nat.Prime 2) := ⟨Nat.prime_two⟩ + exact charP_of_card_eq_prime_pow (R := ConcreteField) (p := 2) + (f := extensionDegree) card + +/-- Canonical `GF(2)` algebra structure on the certified executable carrier. -/ +noncomputable instance instAlgebraConcreteField [Fact (Irreducible definingPolynomial)] : + Algebra (ZMod 2) ConcreteField := by + let fieldInst : Field ConcreteField := instFieldConcreteField + letI : Field ConcreteField := fieldInst + letI : CommRing ConcreteField := fieldInst.toCommRing + letI : CharP ConcreteField 2 := instCharTwoConcreteField + exact ZMod.algebra ConcreteField 2 + +@[simp] +theorem polynomialBasis_size : + polynomialBasis.size = extensionDegree := by + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis] + exact Array.size_ofFn + +@[simp] +theorem baseConstants_size : + baseConstants.size = 2 := by + simp [baseConstants, BinaryField.Extension.Concrete.baseConstants] + +theorem toSpec_injective : + Function.Injective toSpec := by + apply BinaryField.Extension.Concrete.toSpec_injective + · simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree + · unfold Concrete.params extensionDegree + norm_num + +theorem toSpec_zero : + toSpec 0 = 0 := by + exact BinaryField.Extension.Concrete.toSpec_zero Concrete.params + +theorem toSpec_one : + toSpec 1 = 1 := by + exact BinaryField.Extension.Concrete.toSpec_one Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + +theorem toSpec_add (a b : ConcreteField) : + toSpec (a + b) = toSpec a + toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_add Concrete.params a b + +theorem toSpec_neg (a : ConcreteField) : + toSpec (-a) = -toSpec a := by + exact BinaryField.Extension.Concrete.toSpec_neg Concrete.params a + +theorem toSpec_sub (a b : ConcreteField) : + toSpec (a - b) = toSpec a - toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_sub Concrete.params a b + +theorem toSpec_mul (a b : ConcreteField) : + toSpec (a * b) = toSpec a * toSpec b := by + exact BinaryField.Extension.Concrete.toSpec_mul Concrete.params + (data := definingPolynomialData) + Concrete.definingPolynomial_eq_executableSparse + (by simpa [Concrete.params, definingPolynomial] using definingPolynomial_degree) + a b + +/-- Ring homomorphism from executable GF72 elements to the quotient specification. -/ +noncomputable def toSpecRingHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →+* SpecField where + toFun := toSpec + map_zero' := toSpec_zero + map_one' := toSpec_one + map_add' := toSpec_add + map_mul' := toSpec_mul + +/-- Algebra homomorphism from executable GF72 elements to the quotient specification. -/ +noncomputable def toSpecAlgHom [Fact (Irreducible definingPolynomial)] : + ConcreteField →ₐ[ZMod 2] SpecField where + __ := toSpecRingHom + commutes' := by + intro r + exact RingHom.congr_fun + (RingHom.ext_zmod (toSpecRingHom.comp (algebraMap (ZMod 2) ConcreteField)) + (algebraMap (ZMod 2) SpecField)) r + +/-- Algebra equivalence between executable GF72 elements and the quotient specification. -/ +noncomputable def toSpecAlgEquiv [Fact (Irreducible definingPolynomial)] : + ConcreteField ≃ₐ[ZMod 2] SpecField := + AlgEquiv.ofBijective toSpecAlgHom <| by + apply Function.Injective.bijective_of_nat_card_le + · exact toSpec_injective + · rw [Nat.card_eq_fintype_card, Nat.card_eq_fintype_card] + rw [card, BinaryField.Extension.specField_card definingPolynomialData] + simp [definingPolynomialData, extensionDegree] + +/-- The executable polynomial-basis generator maps to the quotient root. -/ +theorem toSpec_root : + toSpec root = GF2_72.root := by + exact BinaryField.Extension.Concrete.toSpec_root Concrete.params + (data := definingPolynomialData) + (by unfold Concrete.params extensionDegree; norm_num) + +end ConcreteField + +end GF2_72 diff --git a/CompPoly/Fields/Binary/GF2_72/Prelude.lean b/CompPoly/Fields/Binary/GF2_72/Prelude.lean new file mode 100644 index 00000000..5a42cfcc --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/Prelude.lean @@ -0,0 +1,161 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Prelude +import Mathlib.Tactic.ComputeDegree + +/-! +# GF(2^72) Prelude + +Defining constants and small executable metadata for the direct binary extension +with candidate primitive polynomial + +`X^72 + X^6 + X^4 + X^3 + X^2 + X + 1`. + +Irreducibility and primitive-order certificates are added in later `GF2_72` +modules before this polynomial is used to construct public field instances. +-/ + +namespace GF2_72 + +open Polynomial + +noncomputable section + +/-- Extension degree for `GF(2^72)`. -/ +def extensionDegree : Nat := + 72 + +/-- Raw executable carrier width for `GF(2^72)`. -/ +abbrev B72 : Type := + BitVec extensionDegree + +/-- Field cardinality of `GF(2^72)`. -/ +def fieldSize : Nat := + BinaryField.Extension.fieldSize extensionDegree + +/-- Multiplicative group order of `GF(2^72)`. -/ +def multiplicativeGroupOrder : Nat := + BinaryField.Extension.multiplicativeGroupOrder extensionDegree + +/-- Low-degree tail `X^6 + X^4 + X^3 + X^2 + X + 1`. -/ +def definingTail : Polynomial (ZMod 2) := + X ^ 6 + X ^ 4 + X ^ 3 + X ^ 2 + X + 1 + +/-- Candidate primitive polynomial bitmask: `X^72 + X^6 + X^4 + X^3 + X^2 + X + 1`. -/ +def definingBitmask : Nat := + 0x100000000000000005f + +/-- Exponents with nonzero coefficients in the full defining polynomial. -/ +def definingPolynomialExponents : List Nat := + [0, 1, 2, 3, 4, 6, 72] + +/-- The tail has natural degree `6`. -/ +lemma definingTail_natDegree : + definingTail.natDegree = 6 := by + unfold definingTail + compute_degree! + +/-- The tail is monic. -/ +lemma definingTail_monic : + definingTail.Monic := by + unfold definingTail + monicity! + +/-- Metadata for the direct binary extension polynomial. -/ +def definingPolynomialData : BinaryField.Extension.DefiningPolynomialData where + degree := extensionDegree + tail := definingTail + tailDegree := 6 + bitmask := definingBitmask + tail_natDegree := definingTail_natDegree + tailDegree_lt_degree := by + unfold extensionDegree + omega + +/-- Candidate defining polynomial for `GF(2^72)`. -/ +def definingPolynomial : Polynomial (ZMod 2) := + BinaryField.Extension.polynomial definingPolynomialData + +/-- Expanded form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_X_pow_add_tail : + definingPolynomial = X ^ 72 + definingTail := by + rfl + +/-- Expanded sparse form of the candidate defining polynomial. -/ +lemma definingPolynomial_eq_sparse : + definingPolynomial = X ^ 72 + X ^ 6 + X ^ 4 + X ^ 3 + X ^ 2 + X + 1 := by + unfold definingPolynomial BinaryField.Extension.polynomial definingPolynomialData definingTail + extensionDegree + ring + +/-- The candidate defining polynomial is monic of degree `72`. -/ +lemma definingPolynomial_isMonicOfDegree : + IsMonicOfDegree definingPolynomial extensionDegree := + BinaryField.Extension.polynomial_isMonicOfDegree definingPolynomialData + +/-- The candidate defining polynomial has natural degree `72`. -/ +lemma definingPolynomial_natDegree : + definingPolynomial.natDegree = extensionDegree := + BinaryField.Extension.polynomial_natDegree definingPolynomialData + +/-- The candidate defining polynomial is monic. -/ +lemma definingPolynomial_monic : + definingPolynomial.Monic := + BinaryField.Extension.polynomial_monic definingPolynomialData + +/-- The candidate defining polynomial is nonzero. -/ +lemma definingPolynomial_ne_zero : + definingPolynomial ≠ 0 := + BinaryField.Extension.polynomial_ne_zero definingPolynomialData + +/-- The candidate defining polynomial has degree `72`. -/ +lemma definingPolynomial_degree : + definingPolynomial.degree = extensionDegree := + BinaryField.Extension.polynomial_degree definingPolynomialData + +/-- Bit-vector encoding of the candidate defining polynomial. -/ +def P_val : BitVec (2 * extensionDegree) := + (1 <<< 72) ^^^ (1 <<< 6) ^^^ (1 <<< 4) ^^^ (1 <<< 3) ^^^ + (1 <<< 2) ^^^ (1 <<< 1) ^^^ 1 + +/-- The `BitVec` encoding denotes the candidate defining polynomial. -/ +lemma definingPolynomial_eq_P_val : + definingPolynomial = BinaryField.toPoly P_val := by + rw [definingPolynomial_eq_sparse] + unfold P_val extensionDegree + repeat rw [BinaryField.toPoly_xor] + rw [BinaryField.Extension.toPoly_one_shiftLeft 72 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 6 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 4 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 3 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 2 (by omega)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 1 (by omega)] + rw [(show (1 : BitVec 144) = 1 <<< 0 by simp)] + rw [BinaryField.Extension.toPoly_one_shiftLeft 0 (by omega)] + simp only [pow_zero, pow_one] + +/-- The exponent list denotes the candidate defining polynomial. -/ +lemma sparsePolynomial_definingPolynomialExponents : + BinaryField.Extension.sparsePolynomial definingPolynomialExponents = definingPolynomial := by + rw [definingPolynomial_eq_sparse] + simp [definingPolynomialExponents, BinaryField.Extension.sparsePolynomial] + ring_nf + +/-- Smooth subgroup refinement schedule for `2^72 - 1`. -/ +def smoothRootSchedule : Array Nat := + #[3, 3, 3, 5, 7, 13, 17, 19, 37, 73, 109, 241, 433, 38737] + +/-- The GF72 smooth schedule refines the multiplicative group down to singleton cosets. -/ +lemma smoothRootSchedule_fold_eq_one : + smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (fieldSize - 1) = 1 := by + unfold smoothRootSchedule fieldSize BinaryField.Extension.fieldSize extensionDegree + decide + +end + +end GF2_72 diff --git a/CompPoly/Fields/Binary/GF2_72/Primitive.lean b/CompPoly/Fields/Binary/GF2_72/Primitive.lean new file mode 100644 index 00000000..2c168451 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/Primitive.lean @@ -0,0 +1,247 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_72.XPowTwoPowGcdCertificate +import CompPoly.Fields.Binary.GF2_72.PrimitivePowerCertificate +import Mathlib.GroupTheory.OrderOfElement +import CompPoly.Fields.Binary.GF2_72.Impl + +/-! +# GF(2^72) Primitive-Order Scaffold + +Small primitive-order metadata and Rabin irreducibility certificate for the +`GF(2^72)` candidate. +-/ + +namespace GF2_72 + +set_option maxRecDepth 100000 + +/-- Distinct prime factors of `2^72 - 1`. -/ +def primitivePrimeFactors : List Nat := + [3, 5, 7, 13, 17, 19, 37, 73, 109, 241, 433, 38737] + +/-- Factorization of the multiplicative-group order `2^72 - 1`. -/ +lemma multiplicativeGroupOrder_factorization : + multiplicativeGroupOrder = + 3 ^ 3 * 5 * 7 * 13 * 17 * 19 * 37 * 73 * 109 * 241 * 433 * 38737 := by + unfold multiplicativeGroupOrder BinaryField.Extension.multiplicativeGroupOrder + BinaryField.Extension.fieldSize extensionDegree + norm_num + +/-- The GF72 candidate polynomial passes Rabin's irreducibility test. -/ +theorem definingPolynomial_irreducible : Irreducible definingPolynomial := + BinaryField.Extension.irreducible_of_rabin_72_passed_over_GF2 + definingPolynomial + (by simpa [extensionDegree] using definingPolynomial_natDegree) + X_pow_2_pow_72_add_X_dvd + rabin_gcd_condition_36 + rabin_gcd_condition_24 + +/-- Register the certified irreducibility fact for quotient-field instances. -/ +instance instIrreducibleDefiningPolynomial : Fact (Irreducible definingPolynomial) := + ⟨definingPolynomial_irreducible⟩ + +/-- Local kernel-safe primality certificate for the largest GF72 group-order factor. -/ +private theorem prime_38737 : Nat.Prime 38737 := by + rw [Nat.prime_def_le_sqrt] + constructor + · norm_num + · intro m hm2 hmsqrt hdvd + have hm_le_sq : m * m ≤ 38737 := (Nat.le_sqrt.mp hmsqrt) + have hm_le : m ≤ 196 := by + by_contra h + have hm197 : 197 ≤ m := by omega + have hsq : 197 * 197 ≤ m * m := Nat.mul_le_mul hm197 hm197 + omega + interval_cases m <;> norm_num at hdvd + +/-- Prime divisors of `fieldSize - 1` are exactly the certified prime factors. -/ +private lemma prime_dvd_fieldSize_sub_one_cases {p : Nat} + (hp : p.Prime) (hdvd : p ∣ fieldSize - 1) : + p = 3 ∨ p = 5 ∨ p = 7 ∨ p = 13 ∨ p = 17 ∨ p = 19 ∨ p = 37 ∨ + p = 73 ∨ p = 109 ∨ p = 241 ∨ p = 433 ∨ p = 38737 := by + have hpdvd : p ∣ multiplicativeGroupOrder := by + simpa [multiplicativeGroupOrder, BinaryField.Extension.multiplicativeGroupOrder] using hdvd + rw [multiplicativeGroupOrder_factorization] at hpdvd + rcases hp.dvd_mul.mp hpdvd with hpdvd | h38737 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h433 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h241 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h109 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h73 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h37 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h19 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h17 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h13 + · rcases hp.dvd_mul.mp hpdvd with hpdvd | h7 + · rcases hp.dvd_mul.mp hpdvd with h3pow | h5 + · left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 3)).mp + (hp.dvd_of_dvd_pow h3pow) + · right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 5)).mp + h5 + · right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 7)).mp + h7 + · right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 13)).mp + h13 + · right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 17)).mp + h17 + · right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 19)).mp + h19 + · right + right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 37)).mp + h37 + · right + right + right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 73)).mp + h73 + · right + right + right + right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 109)).mp + h109 + · right + right + right + right + right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 241)).mp + h241 + · right + right + right + right + right + right + right + right + right + right + left + exact + (Nat.prime_dvd_prime_iff_eq hp (by decide : Nat.Prime 433)).mp + h433 + · right + right + right + right + right + right + right + right + right + right + right + exact + (Nat.prime_dvd_prime_iff_eq hp prime_38737).mp + h38737 + +/-- Polynomial-basis generator used by smooth root contexts. -/ +def primitiveRoot : ConcreteField := + ConcreteField.root + +/-- The polynomial-basis generator is nonzero. -/ +theorem primitiveRoot_ne_zero : primitiveRoot ≠ (0 : ConcreteField) := by + unfold primitiveRoot ConcreteField.root BinaryField.Extension.Concrete.root + change BinaryField.Extension.Concrete.ofNat Concrete.params 2 ≠ + BinaryField.Extension.Concrete.zero Concrete.params + intro h + have hnat := congrArg (BinaryField.Extension.Concrete.toNat Concrete.params) h + rw [BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num)] at hnat + have hzero : + BinaryField.Extension.Concrete.toNat Concrete.params + (BinaryField.Extension.Concrete.zero Concrete.params) = 0 := by + unfold BinaryField.Extension.Concrete.zero + exact BinaryField.Extension.Concrete.toNat_ofNat_of_lt Concrete.params + (n := 0) (by unfold Concrete.params extensionDegree; norm_num) + rw [hzero] at hnat + norm_num at hnat + +/-- The polynomial-basis generator has full multiplicative order. -/ +theorem primitiveRoot_order : orderOf primitiveRoot = fieldSize - 1 := by + let fieldInst : Field ConcreteField := ConcreteField.instFieldConcreteField + letI : Field ConcreteField := fieldInst + refine orderOf_eq_of_pow_and_pow_div_prime (n := fieldSize - 1) ?_ ?_ ?_ + · unfold fieldSize BinaryField.Extension.fieldSize extensionDegree + norm_num + · have hcard : Fintype.card ConcreteField = fieldSize := by + simpa [fieldSize] using ConcreteField.card + have hfermat := FiniteField.pow_card_sub_one_eq_one + (K := ConcreteField) primitiveRoot primitiveRoot_ne_zero + simpa [hcard] using hfermat + · intro p hp hdvd + rcases prime_dvd_fieldSize_sub_one_cases hp hdvd with + rfl | rfl | rfl | rfl | rfl | rfl | rfl | + rfl | rfl | rfl | rfl | rfl + · simpa [primitiveRoot] using root_pow_div_3_ne_one + · simpa [primitiveRoot] using root_pow_div_5_ne_one + · simpa [primitiveRoot] using root_pow_div_7_ne_one + · simpa [primitiveRoot] using root_pow_div_13_ne_one + · simpa [primitiveRoot] using root_pow_div_17_ne_one + · simpa [primitiveRoot] using root_pow_div_19_ne_one + · simpa [primitiveRoot] using root_pow_div_37_ne_one + · simpa [primitiveRoot] using root_pow_div_73_ne_one + · simpa [primitiveRoot] using root_pow_div_109_ne_one + · simpa [primitiveRoot] using root_pow_div_241_ne_one + · simpa [primitiveRoot] using root_pow_div_433_ne_one + · simpa [primitiveRoot] using root_pow_div_38737_ne_one + +end GF2_72 diff --git a/CompPoly/Fields/Binary/GF2_72/PrimitivePowerCertificate.lean b/CompPoly/Fields/Binary/GF2_72/PrimitivePowerCertificate.lean new file mode 100644 index 00000000..4e046ecb --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/PrimitivePowerCertificate.lean @@ -0,0 +1,903 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Extension.Primitive +import CompPoly.Fields.Binary.GF2_72.Impl +import Mathlib.Tactic.NormNum + +/-! +# GF2^72 Primitive-Power Certificates + +Generated structural power-chain certificates for the polynomial-basis +root. These certify the nontrivial prime-divisor powers used to prove +that the root has full multiplicative order. +-/ + +namespace GF2_72 + +set_option maxRecDepth 100000 + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (5, 32), (10, 1024), (21, 2097152), (42, 4398046511104), (85, 778240), + (170, 297762029568), (341, 629648263902669048800), (682, 2314885530812057736287), + (1365, 642718545241939572651), (2730, 2310128888793660555686), (5461, 2966963499902521487087), + (10922, 3417511223790470124711), (21845, 1976089556281110081009), + (43690, 4106857358440160357825), (87381, 4585563550768443466552), + (174762, 107482907152008133646), (349525, 771340202810785445782), + (699050, 807993976565104407720), (1398101, 3945355089304793164894), + (2796202, 2285692006871531019701), (5592405, 2430979370338066920061), + (11184810, 3545247919825117743855), (22369621, 3581759661250254547894), + (44739242, 1870919973443038605078), (89478485, 2690168626175824481647), + (178956970, 2916350689491914921140), (357913941, 2660383131885226872219), + (715827882, 2864173612134235088724), (1431655765, 318623878356765079267), + (2863311530, 558781217928335313446), (5726623061, 3287683413682412639440), + (11453246122, 3010003852481623943261), (22906492245, 1640354053626950994017), + (45812984490, 4368877296123220838162), (91625968981, 2920131072972511418794), + (183251937962, 3783358767639327975046), (366503875925, 1410316593866197463562), + (733007751850, 4195884339531072568692), (1466015503701, 927346740425685999618), + (2932031007402, 2199626927935845442308), (5864062014805, 2604217842644328793689), + (11728124029610, 3601618468823477626960), (23456248059221, 1935053235279697833178), + (46912496118442, 2943919999381124206148), (93824992236885, 482044936833432367165), + (187649984473770, 1341814955350962074894), (375299968947541, 4262198346168004751305), + (750599937895082, 525953847064437206195), (1501199875790165, 484596589046986989546), + (3002399751580330, 473409648602223614311), (6004799503160661, 905286320478882630866), + (12009599006321322, 652215278182308811012), (24019198012642645, 1665933802935011532806), + (48038396025285290, 3204591275613207336903), (96076792050570581, 2295569072990571757457), + (192153584101141162, 3562853410292892494766), (384307168202282325, 4281154288829470302442), + (768614336404564650, 489224522320767910697), (1537228672809129301, 3419385555397025443458), + (3074457345618258602, 4460341547467848742949), (6148914691236517205, 84942359538230424448), + (12297829382473034410, 400607830634165505043), (24595658764946068821, 3529231678746926632364), + (49191317529892137642, 4206342715193052290590), (98382635059784275285, 1068221074289426488682), + (196765270119568550570, 914847369538282783639), (393530540239137101141, 2030957681136303139604), + (787061080478274202282, 2638539828441743125420), + (1574122160956548404565, 3210600187528640721213)] + +/-- Residue of `root ^ ((fieldSize - 1) / 3)`. -/ +def rootPowDiv3Residue : Nat := + 3210600187528640721213 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 3) rootPowDiv3Chain rootPowDiv3Residue = true := by + rfl + +private theorem root_pow_div_3_certified : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue ∧ + rootPowDiv3Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 3) + (cert := rootPowDiv3Chain) (expected := rootPowDiv3Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_3_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 3)`. -/ +theorem root_pow_div_3_eq : + ConcreteField.root ^ ((fieldSize - 1) / 3) = + ConcreteField.ofNat rootPowDiv3Residue := + root_pow_div_3_certified.1 + +/-- The `3`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_3_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 3) ≠ (1 : ConcreteField) := by + rw [root_pow_div_3_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv3Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv3Residue] using root_pow_div_3_certified.2) + (by unfold rootPowDiv3Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (6, 64), (12, 4096), (25, 33554432), (51, 2251799813685248), + (102, 102005473280), (204, 393146233070934818911), (409, 3345012031482463527594), + (819, 3787731449953003274419), (1638, 1810927434439143910296), (3276, 3710763063660141080432), + (6553, 4272042430681068648452), (13107, 3275131709201203979172), + (26214, 4188046951919213731422), (52428, 156100347982649973893), + (104857, 2465058654098313129786), (209715, 3012834047527009072555), + (419430, 4374665900473274643639), (838860, 1757015727120005802948), + (1677721, 3874278064797835335679), (3355443, 4064192895667230112974), + (6710886, 1926674657547409104261), (13421772, 2579482576897132125746), + (26843545, 3196690429724380839053), (53687091, 3919783896718061221529), + (107374182, 786418963900103395699), (214748364, 862384257885126953562), + (429496729, 4106087896128327062928), (858993459, 2068322326726246424348), + (1717986918, 3653705379718624229839), (3435973836, 988705427276458341368), + (6871947673, 3796829819813059052024), (13743895347, 2044919867708306156900), + (27487790694, 4028247425687185951567), (54975581388, 2009107593411119085124), + (109951162777, 2783599936426981035297), (219902325555, 3342758844428460161159), + (439804651110, 3320064566870178414039), (879609302220, 3290456519802153548408), + (1759218604441, 1853002163323273373251), (3518437208883, 2867004025557652388405), + (7036874417766, 2835510979507926262623), (14073748835532, 4069589643159970575236), + (28147497671065, 2256245653980762855010), (56294995342131, 2544636857609129576681), + (112589990684262, 2427568367090111520864), (225179981368524, 2732845508439576203373), + (450359962737049, 984665879524528395745), (900719925474099, 1473222616836080967962), + (1801439850948198, 3063706906564526401447), (3602879701896396, 4363311301080648406743), + (7205759403792793, 2894915456875197112200), (14411518807585587, 2672921429674960752827), + (28823037615171174, 4021843274432696867560), (57646075230342348, 1931724724226933471965), + (115292150460684697, 536066595313503811619), (230584300921369395, 1085371457130817129036), + (461168601842738790, 604004642912735439340), (922337203685477580, 2232533516945475112848), + (1844674407370955161, 2566261889033418333409), (3689348814741910323, 3205559258895210188577), + (7378697629483820646, 4638794759134530026831), (14757395258967641292, 1198071732609564136772), + (29514790517935282585, 3699474724986579025601), (59029581035870565171, 1864068285755552029016), + (118059162071741130342, 2594818571024701368704), + (236118324143482260684, 2700407517638746311905), + (472236648286964521369, 3365598770390568122399), + (944473296573929042739, 4272404638160481358519)] + +/-- Residue of `root ^ ((fieldSize - 1) / 5)`. -/ +def rootPowDiv5Residue : Nat := + 4272404638160481358519 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 5) rootPowDiv5Chain rootPowDiv5Residue = true := by + rfl + +private theorem root_pow_div_5_certified : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue ∧ + rootPowDiv5Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 5) + (cert := rootPowDiv5Chain) (expected := rootPowDiv5Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_5_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 5)`. -/ +theorem root_pow_div_5_eq : + ConcreteField.root ^ ((fieldSize - 1) / 5) = + ConcreteField.ofNat rootPowDiv5Residue := + root_pow_div_5_certified.1 + +/-- The `5`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_5_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 5) ≠ (1 : ConcreteField) := by + rw [root_pow_div_5_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv5Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv5Residue] using root_pow_div_5_certified.2) + (by unfold rootPowDiv5Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 7)`. -/ +def rootPowDiv7Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (9, 512), (18, 262144), (36, 68719476736), (73, 190), + (146, 17748), (292, 269553936), (585, 144117395722732032), (1170, 73788520026343832576), + (2340, 404675448206099820544), (4681, 2766042917131863982270), (9362, 2928156716728758385977), + (18724, 2532659034930058883139), (37449, 732496769887392455671), + (74898, 2026107453962662949818), (149796, 4030433427635477409703), + (299593, 2127969505917844785494), (599186, 2774143536899257336340), + (1198372, 2575467953543891588941), (2396745, 2645493324744923110265), + (4793490, 2490570419072043542944), (9586980, 2462789340535965980589), + (19173961, 808883181838327260231), (38347922, 1087522919971245576553), + (76695844, 676352756821636901166), (153391689, 2240115173752685472968), + (306783378, 3576333816066102730096), (613566756, 2160389409671155174301), + (1227133513, 255099882527886285531), (2454267026, 39793438455629845978), + (4908534052, 21648457496867768983), (9817068105, 640904662861192877362), + (19634136210, 1940339903292195743608), (39268272420, 3833336215085377940864), + (78536544841, 4242924165909706840410), (157073089682, 251121063271761037081), + (314146179364, 1221648732973074491009), (628292358729, 4150139415961209272997), + (1256584717458, 467167954415572892044), (2513169434916, 1357775095662465296348), + (5026338869833, 4412343608778554026879), (10052677739666, 1443973132875825761243), + (20105355479332, 3086992807039024880905), (40210710958665, 4483530371208730048929), + (80421421917330, 1589164699641885703295), (160842843834660, 3150464083487704661993), + (321685687669321, 4685357375582080016569), (643371375338642, 8670653918158597968), + (1286742750677284, 1480387452556941302832), (2573485501354569, 3922374778194164196705), + (5146971002709138, 2040862497257196733235), (10293942005418276, 3805715139386193490313), + (20587884010836553, 3801310164289550115288), (41175768021673106, 996997695194503387437), + (82351536043346212, 1010844037157658140637), (164703072086692425, 4376377091213014901410), + (329406144173384850, 505727578085254240921), (658812288346769700, 533144776616670630769), + (1317624576693539401, 1077124714455731067708), (2635249153387078802, 917553435342627137052), + (5270498306774157604, 1808781066372526240015), (10540996613548315209, 2855943190392996908429), + (21081993227096630418, 3794227069936034006303), (42163986454193260836, 2185776858162287779735), + (84327972908386521673, 3202312226482975212269), (168655945816773043346, 4394710973601975531503), + (337311891633546086692, 1758813688846670358763), + (674623783267092173385, 4612114286642244937099)] + +/-- Residue of `root ^ ((fieldSize - 1) / 7)`. -/ +def rootPowDiv7Residue : Nat := + 4612114286642244937099 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 7)`. -/ +theorem root_pow_div_7_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 7) rootPowDiv7Chain rootPowDiv7Residue = true := by + rfl + +private theorem root_pow_div_7_certified : + ConcreteField.root ^ ((fieldSize - 1) / 7) = + ConcreteField.ofNat rootPowDiv7Residue ∧ + rootPowDiv7Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 7) + (cert := rootPowDiv7Chain) (expected := rootPowDiv7Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_7_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 7)`. -/ +theorem root_pow_div_7_eq : + ConcreteField.root ^ ((fieldSize - 1) / 7) = + ConcreteField.ofNat rootPowDiv7Residue := + root_pow_div_7_certified.1 + +/-- The `7`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_7_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 7) ≠ (1 : ConcreteField) := by + rw [root_pow_div_7_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv7Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv7Residue] using root_pow_div_7_certified.2) + (by unfold rootPowDiv7Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 13)`. -/ +def rootPowDiv13Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (9, 512), (19, 524288), (39, 549755813888), (78, 6080), + (157, 36347904), (315, 2261182303961088), (630, 1185221321236355209152), + (1260, 4230496847750076125564), (2520, 1636836588609123709709), (5041, 2244731954433916198075), + (10082, 3940230368712534434794), (20164, 883847622587772281173), + (40329, 1549532574088231205380), (80659, 4120722314034360414567), + (161319, 3874217178798316429832), (322638, 1962944841048034737330), + (645277, 2901990613797346397391), (1290555, 894522466911385594609), + (2581110, 928517387021550002350), (5162220, 635974600035122705419), + (10324440, 2291847172935516921401), (20648881, 789346593752040134181), + (41297762, 1987506892937596704514), (82595524, 3762104780320968221463), + (165191049, 1914466324988424148208), (330382099, 3265679203912883955015), + (660764199, 4403873361091442432873), (1321528398, 1740524555266210484083), + (2643056797, 2254671245452565380429), (5286113595, 73229533190104424995), + (10572227190, 77340761381735694550), (21144454380, 386526816736684718071), + (42288908760, 570936718171077125465), (84577817521, 490427485831691509956), + (169155635042, 1714307257611518431235), (338311270084, 3415412616914489884966), + (676622540169, 4200551064809424695221), (1353245080339, 496614061745639757862), + (2706490160679, 479477212737544556558), (5412980321358, 249915167856619689931), + (10825960642717, 2588970457254246850186), (21651921285435, 853869327079623364757), + (43303842570870, 1167671881006945755741), (86607685141740, 1863677103982161526642), + (173215370283480, 2594872159289058272308), (346430740566961, 2599657794157326249949), + (692861481133922, 3601031606004782340127), (1385722962267844, 611207884548451884932), + (2771445924535689, 1664123638497896615398), (5542891849071379, 4011621224775421829585), + (11085783698142759, 4641457525131538833208), (22171567396285518, 1584243748340702393550), + (44343134792571037, 4682597502179207974313), (88686269585142075, 642392186654617394880), + (177372539170284150, 1114760881062328741244), (354745078340568300, 892401224508107978320), + (709490156681136600, 1886309345637538437535), (1418980313362273201, 499314823297870389869), + (2837960626724546402, 552397768312876805537), (5675921253449092804, 525247853921429926081), + (11351842506898185609, 2698674895660532288482), (22703685013796371219, 3522996473979214303125), + (45407370027592742439, 4281242117851753006527), (90814740055185484878, 1675564203063754248807), + (181629480110370969757, 4645625108042567841483), (363258960220741939515, 219836341700585861358)] + +/-- Residue of `root ^ ((fieldSize - 1) / 13)`. -/ +def rootPowDiv13Residue : Nat := + 219836341700585861358 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 13)`. -/ +theorem root_pow_div_13_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 13) rootPowDiv13Chain rootPowDiv13Residue = true := by + rfl + +private theorem root_pow_div_13_certified : + ConcreteField.root ^ ((fieldSize - 1) / 13) = + ConcreteField.ofNat rootPowDiv13Residue ∧ + rootPowDiv13Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 13) + (cert := rootPowDiv13Chain) (expected := rootPowDiv13Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_13_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 13)`. -/ +theorem root_pow_div_13_eq : + ConcreteField.root ^ ((fieldSize - 1) / 13) = + ConcreteField.ofNat rootPowDiv13Residue := + root_pow_div_13_certified.1 + +/-- The `13`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_13_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 13) ≠ (1 : ConcreteField) := by + rw [root_pow_div_13_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv13Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv13Residue] using root_pow_div_13_certified.2) + (by unfold rootPowDiv13Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (7, 128), (15, 32768), (30, 1073741824), (60, 1152921504606846976), + (120, 26740122787512320), (240, 6305330757632), (481, 2951625981731371971526), + (963, 2213610125192619272211), (1927, 3018494866642772274645), (3855, 4469395483835140048281), + (7710, 1244698072960919245548), (15420, 3341348028458160623567), + (30840, 3097791291176101184219), (61680, 3128189970779501498039), + (123361, 1606722018807531752751), (246723, 1715993964791464970221), + (493447, 2257324379054761142107), (986895, 661441589676952452789), + (1973790, 1925751008235290030049), (3947580, 3754240616897926609457), + (7895160, 2133302780100864134508), (15790320, 3673277905107310531612), + (31580641, 1386701116202898926818), (63161283, 3832632597595806085353), + (126322567, 3763346159692834412352), (252645135, 4259072312525991351908), + (505290270, 1656684147614612163554), (1010580540, 3110380194374472043287), + (2021161080, 4349008291845807285207), (4042322160, 1455306745641010807688), + (8084644321, 1855490896457675060647), (16169288643, 955141347178167460621), + (32338577287, 1453465055157123372506), (64677154575, 3656222577351762648585), + (129354309150, 2080767350216029609616), (258708618300, 3601880787710623897280), + (517417236600, 666583455689473898273), (1034834473200, 755485732218314070653), + (2069668946401, 4670200658507569078234), (4139337892803, 15876983795858598994), + (8278675785607, 591339180749789597552), (16557351571215, 3883806395088037726304), + (33114703142430, 802039019306389992014), (66229406284860, 1081712183264856525495), + (132458812569720, 682167326470061339018), (264917625139440, 1930514418493236059751), + (529835250278881, 1015722620581423867859), (1059670500557763, 1273259525039053199916), + (2119341001115527, 4307171534819211840185), (4238682002231055, 1138339570468151088928), + (8477364004462110, 2087505945904517088547), (16954728008924220, 2718242073876188069018), + (33909456017848440, 2866733958036655861894), (67818912035696880, 3798198800519072463194), + (135637824071393761, 3780625860049033985354), (271275648142787523, 3667338869880319341738), + (542551296285575047, 1830726230521838239860), (1085102592571150095, 3291356868539326140039), + (2170205185142300190, 4468281945475789819064), (4340410370284600380, 340986066899811788674), + (8680820740569200760, 579379472084826074663), (17361641481138401520, 535449500202858710377), + (34723282962276803041, 2859003155688338768130), (69446565924553606083, 470149462821648898347), + (138893131849107212167, 462826014408353701676), (277786263698214424335, 2823846243031826827398)] + +/-- Residue of `root ^ ((fieldSize - 1) / 17)`. -/ +def rootPowDiv17Residue : Nat := + 2823846243031826827398 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 17) rootPowDiv17Chain rootPowDiv17Residue = true := by + rfl + +private theorem root_pow_div_17_certified : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue ∧ + rootPowDiv17Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 17) + (cert := rootPowDiv17Chain) (expected := rootPowDiv17Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_17_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 17)`. -/ +theorem root_pow_div_17_eq : + ConcreteField.root ^ ((fieldSize - 1) / 17) = + ConcreteField.ofNat rootPowDiv17Residue := + root_pow_div_17_certified.1 + +/-- The `17`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_17_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 17) ≠ (1 : ConcreteField) := by + rw [root_pow_div_17_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv17Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv17Residue] using root_pow_div_17_certified.2) + (by unfold rootPowDiv17Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 19)`. -/ +def rootPowDiv19Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (6, 64), (13, 8192), (26, 67108864), (53, 9007199254740992), + (107, 3264175144960), (215, 2361183241434822794790), (431, 2361183241471911264429), + (862, 2366084358770977161276), (1724, 3542204375399841264845), (3449, 1229602556102637431358), + (6898, 3029566897012108589175), (13797, 4007765099379997840823), + (27594, 2003683346154975424820), (55188, 4048474095036191269571), + (110376, 2305235802187437875368), (220752, 2659088353002863833520), + (441505, 3358062084143936482747), (883011, 3831169272751724927185), + (1766022, 1812462134498653746739), (3532045, 3402399895259690819851), + (7064090, 3057584783851878189175), (14128181, 2286993374396197838569), + (28256363, 2568756771272821306405), (56512727, 281694122424563306905), + (113025455, 2447598732635137146972), (226050910, 3923949854703432499889), + (452101820, 1972045939841461530371), (904203641, 986762045121611397771), + (1808407282, 645245651128942948361), (3616814565, 2081321528758311902780), + (7233629130, 3652994339550404007795), (14467258260, 1874150633787246230471), + (28934516520, 2544343687590360027225), (57869033040, 2723009802403488465795), + (115738066081, 3509579285732903021175), (231476132163, 4329898074993376188623), + (462952264326, 197992254865505263048), (925904528653, 3061576840384902855904), + (1851809057306, 3209541947157813835710), (3703618114613, 4507527001399369884307), + (7407236229227, 2507278136660977382134), (14814472458455, 27676147119200009813), + (29628944916911, 2547031635894094593754), (59257889833822, 3613908845288382605686), + (118515779667644, 2165482586629003294601), (237031559335289, 3049844775121317351291), + (474063118670578, 3486339959821911265364), (948126237341157, 1785193182895401161243), + (1896252474682314, 4059613818067560524778), (3792504949364628, 1943924311305540075322), + (7585009898729256, 2635568456913969772808), (15170019797458512, 2700082843406666625486), + (30340039594917025, 2932697392477234176309), (60680079189834051, 3404910862534452570617), + (121360158379668102, 3274485858942436571808), (242720316759336205, 1855134149000767007741), + (485440633518672410, 3724425749407374414002), (970881267037344821, 3645146475081863928530), + (1941762534074689643, 1362397987226008435572), (3883525068149379287, 4272218732742574444167), + (7767050136298758575, 1052264133205398261838), (15534100272597517150, 675492342246973332491), + (31068200545195034300, 768339251050221238709), (62136401090390068601, 2353390112281374257850), + (124272802180780137202, 3634426120105259961751), + (248545604361560274405, 4351018077087098563312)] + +/-- Residue of `root ^ ((fieldSize - 1) / 19)`. -/ +def rootPowDiv19Residue : Nat := + 4351018077087098563312 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 19)`. -/ +theorem root_pow_div_19_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 19) rootPowDiv19Chain rootPowDiv19Residue = true := by + rfl + +private theorem root_pow_div_19_certified : + ConcreteField.root ^ ((fieldSize - 1) / 19) = + ConcreteField.ofNat rootPowDiv19Residue ∧ + rootPowDiv19Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 19) + (cert := rootPowDiv19Chain) (expected := rootPowDiv19Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_19_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 19)`. -/ +theorem root_pow_div_19_eq : + ConcreteField.root ^ ((fieldSize - 1) / 19) = + ConcreteField.ofNat rootPowDiv19Residue := + root_pow_div_19_certified.1 + +/-- The `19`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_19_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 19) ≠ (1 : ConcreteField) := by + rw [root_pow_div_19_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv19Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv19Residue] using root_pow_div_19_certified.2) + (by unfold rootPowDiv19Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 37)`. -/ +def rootPowDiv37Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (6, 64), (13, 8192), (27, 134217728), (55, 36028797018963968), + (110, 26113401159680), (221, 12026464), (442, 75957570638848), (885, 629495141652941725374), + (1771, 4629734933399175989486), (3542, 1211360772498686494341), (7084, 4152674278312464705266), + (14169, 2815162684972988871540), (28339, 3268368306558090704283), + (56679, 3617794766155373607249), (113359, 4157448622063441299462), + (226719, 445007586785234468722), (453438, 530351000332211039624), + (906876, 1410253880318268363532), (1813753, 1896199189450856204633), + (3627506, 4091603498164797253069), (7255012, 1945638175906098217904), + (14510024, 3740925668716686369724), (29020049, 4387903675678138519332), + (58040098, 505878184573648425549), (116080197, 945807371337832435612), + (232160394, 648136856105628393331), (464320788, 1945206432139635799014), + (928641577, 1175803993447794911767), (1857283155, 3578758546735492403658), + (3714566310, 1871845855256816782198), (7429132620, 2835886794439942280228), + (14858265240, 4074200723706883557842), (29716530480, 1040452308799596307766), + (59433060960, 1855166817235171380411), (118866121921, 3463932035508956900565), + (237732243843, 1978612449081647807271), (475464487686, 3761091295827328246681), + (950928975373, 1434997970630972414392), (1901857950747, 1272415469099776689607), + (3803715901495, 1942540857553565592333), (7607431802990, 3756139194461028715873), + (15214863605981, 3675590949631968914232), (30429727211962, 919086830002275441553), + (60859454423925, 3773538812270455943650), (121718908847851, 1308546945525807542098), + (243437817695702, 3258034295158774258740), (486875635391404, 4483894159782597118110), + (973751270782809, 816751706456337316850), (1947502541565619, 2193138518987373009358), + (3895005083131239, 2611816134811056934895), (7790010166262479, 119012047651946172177), + (15580020332524959, 2567775859688079449698), (31160040665049918, 2709538699094099158410), + (62320081330099836, 2866981434612505601910), (124640162660199673, 3307668121182439048819), + (249280325320399346, 4172902354144616040164), (498560650640798692, 543635877984754261342), + (997121301281597384, 242964855553506757559), (1994242602563194769, 267215806767054499572), + (3988485205126389538, 1241161781894938120643), (7976970410252779077, 1185592629603193884523), + (15953940820505558154, 4156692115112340604473), (31907881641011116308, 223355669142817146063), + (63815763282022232617, 816311715047527306092), (127631526564044465235, 4664847228717303843520)] + +/-- Residue of `root ^ ((fieldSize - 1) / 37)`. -/ +def rootPowDiv37Residue : Nat := + 4664847228717303843520 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 37)`. -/ +theorem root_pow_div_37_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 37) rootPowDiv37Chain rootPowDiv37Residue = true := by + rfl + +private theorem root_pow_div_37_certified : + ConcreteField.root ^ ((fieldSize - 1) / 37) = + ConcreteField.ofNat rootPowDiv37Residue ∧ + rootPowDiv37Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 37) + (cert := rootPowDiv37Chain) (expected := rootPowDiv37Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_37_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 37)`. -/ +theorem root_pow_div_37_eq : + ConcreteField.root ^ ((fieldSize - 1) / 37) = + ConcreteField.ofNat rootPowDiv37Residue := + root_pow_div_37_certified.1 + +/-- The `37`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_37_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 37) ≠ (1 : ConcreteField) := by + rw [root_pow_div_37_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv37Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv37Residue] using root_pow_div_37_certified.2) + (by unfold rootPowDiv37Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 73)`. -/ +def rootPowDiv73Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (7, 128), (14, 16384), (28, 268435456), (56, 72057594037927936), + (112, 104453604638720), (224, 96211712), (448, 4861284520886272), (897, 563623020418398), + (1795, 2961432755225699159446), (3591, 4584963192000752199059), (7182, 9710670542352362247), + (14364, 1186613441617560922009), (28728, 4132195121417852161345), + (57456, 461259039842688130447), (114912, 1362343776401031914265), + (229824, 4254081345524149607134), (459649, 462876124573225117170), + (919299, 2676405672900782560400), (1838599, 2925843750266241632101), + (3677198, 2903028536867869458211), (7354396, 2610207836477721041892), + (14708792, 2425640190108063755597), (29417584, 2737581812970207035084), + (58835168, 2852457778826628169634), (117670336, 4075558406469177090566), + (235340673, 4432856560931278765330), (470681347, 860315345828554762418), + (941362695, 3951600861890657463342), (1882725390, 784574297549520705174), + (3765450780, 2267690643121137246075), (7530901560, 2748519635898663062085), + (15061803120, 2870923524764806369251), (30123606240, 3725497300517707173755), + (60247212480, 1837492007825301427707), (120494424961, 2707758387782161029973), + (240988849923, 2747911594093918578681), (481977699847, 394600075781436162151), + (963955399694, 270638669698365626678), (1927910799388, 1297036657739799458920), + (3855821598776, 3330547951712650138688), (7711643197552, 4574126903451764253805), + (15423286395104, 1305396158781827043596), (30846572790208, 4511031117697941748751), + (61693145580417, 254005214511159399478), (123386291160835, 829555133416032456438), + (246772582321671, 1601266565257217712110), (493545164643342, 4419015091849722923860), + (987090329286684, 1370000382406872824670), (1974180658573368, 3097387150663513640532), + (3948361317146736, 4367649416065756592973), (7896722634293472, 279184034244705596959), + (15793445268586944, 112080376476105113926), (31586890537173889, 68064149899447398166), + (63173781074347779, 789313448237344229870), (126347562148695559, 4574526143473135684688), + (252695124297391118, 1324729437508024778638), (505390248594782236, 4441355188827915593620), + (1010780497189564472, 1309877757314074650445), (2021560994379128944, 2983906438554780766289), + (4043121988758257888, 3413311152024022471136), (8086243977516515776, 4221657009909059130818), + (16172487955033031553, 3457492748029662424684), (32344975910066063107, 4352070557128133288699), + (64689951820132126215, 3540240399773847885582)] + +/-- Residue of `root ^ ((fieldSize - 1) / 73)`. -/ +def rootPowDiv73Residue : Nat := + 3540240399773847885582 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 73)`. -/ +theorem root_pow_div_73_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 73) rootPowDiv73Chain rootPowDiv73Residue = true := by + rfl + +private theorem root_pow_div_73_certified : + ConcreteField.root ^ ((fieldSize - 1) / 73) = + ConcreteField.ofNat rootPowDiv73Residue ∧ + rootPowDiv73Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 73) + (cert := rootPowDiv73Chain) (expected := rootPowDiv73Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_73_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 73)`. -/ +theorem root_pow_div_73_eq : + ConcreteField.root ^ ((fieldSize - 1) / 73) = + ConcreteField.ofNat rootPowDiv73Residue := + root_pow_div_73_certified.1 + +/-- The `73`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_73_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 73) ≠ (1 : ConcreteField) := by + rw [root_pow_div_73_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv73Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv73Residue] using root_pow_div_73_certified.2) + (by unfold rootPowDiv73Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 109)`. -/ +def rootPowDiv109Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (9, 512), (18, 262144), (37, 137438953472), (75, 760), + (150, 283968), (300, 69005807616), (601, 144680345676021950), (1202, 73788520015539026260), + (2404, 90310683347768058128), (4809, 798847329127933018624), (9619, 2320634688993637520864), + (19239, 2514687439998200961983), (38479, 692437161589722132431), + (76959, 4054907473838538472052), (153919, 4637696053372969823172), + (307838, 1267533478858858935826), (615677, 3565791749365873880399), + (1231355, 3545652001587878043982), (2462710, 665249984660811573290), + (4925421, 4016786553866688233774), (9850842, 1934053149094241030742), + (19701684, 3758987295835318837352), (39403369, 3797921932745779794722), + (78806739, 1860389953852276632490), (157613478, 2612749157834765028552), + (315226957, 79790921610585491643), (630453915, 807718033490046149420), + (1260907830, 1086061780028032402460), (2521815660, 2084412574891610909676), + (5043631320, 2418128236182018591568), (10087262640, 3623784998713351747181), + (20174525280, 971955112698968262652), (40349050560, 2194565615093473726368), + (80698101121, 140408026074313851801), (161396202242, 1582158520590205743217), + (322792404484, 3535466922630999168333), (645584808969, 1217734919589514893697), + (1291169617938, 4209100367821348604386), (2582339235877, 2829340970312123465802), + (5164678471755, 465175167411435384845), (10329356943510, 158752680480150080813), + (20658713887020, 1595844324688048048481), (41317427774041, 3968151704312252018915), + (82634855548082, 2339713784021984726535), (165269711096164, 2455303574597759056970), + (330539422192329, 2975995364443193189203), (661078844384659, 1489572165478639215511), + (1322157688769319, 4059277453034457467179), (2644315377538639, 1492461093273987820950), + (5288630755077279, 4501338126034057602729), (10577261510154559, 256679088699849780512), + (21154523020309118, 1593993916161075582499), (42309046040618237, 3967869347203641957643), + (84618092081236475, 1716599129016835753256), (169236184162472950, 4670147895954303870511), + (338472368324945901, 2960449597137482547286), (676944736649891802, 3100603474750093968117), + (1353889473299783604, 3446445970190085146300), (2707778946599567209, 3723140974958984460357), + (5415557893199134419, 4385307910943211560902), (10831115786398268838, 1464855923172082307001), + (21662231572796537677, 1882513374980928360125), (43324463145593075355, 3462956930425191352197)] + +/-- Residue of `root ^ ((fieldSize - 1) / 109)`. -/ +def rootPowDiv109Residue : Nat := + 3462956930425191352197 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 109)`. -/ +theorem root_pow_div_109_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 109) rootPowDiv109Chain rootPowDiv109Residue = true := by + rfl + +private theorem root_pow_div_109_certified : + ConcreteField.root ^ ((fieldSize - 1) / 109) = + ConcreteField.ofNat rootPowDiv109Residue ∧ + rootPowDiv109Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 109) + (cert := rootPowDiv109Chain) (expected := rootPowDiv109Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_109_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 109)`. -/ +theorem root_pow_div_109_eq : + ConcreteField.root ^ ((fieldSize - 1) / 109) = + ConcreteField.ofNat rootPowDiv109Residue := + root_pow_div_109_certified.1 + +/-- The `109`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_109_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 109) ≠ (1 : ConcreteField) := by + rw [root_pow_div_109_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv109Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv109Residue] using root_pow_div_109_certified.2) + (by unfold rootPowDiv109Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 241)`. -/ +def rootPowDiv241Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (8, 256), (16, 65536), (33, 8589934592), + (67, 147573952589676412928), (135, 876220343501203701760), (271, 4095861731506880774334), + (543, 4585758533139092766772), (1087, 178635704587419292034), (2175, 2501512780284736593110), + (4350, 3851157704398006543654), (8701, 4512886572123396735082), (17403, 2617515154217014387882), + (34807, 3190862259748955442995), (69615, 2292876005253787037551), + (139230, 2368524799677024403126), (278460, 3621441758731375391958), + (556920, 2174553519327459303925), (1113840, 2488877189627238581165), + (2227680, 3920950420489314163347), (4455360, 810707409118884732644), + (8910720, 792147843276770524863), (17821441, 1758641087930419116978), + (35642882, 4579687529759018140951), (71285764, 328718059294958208091), + (142571528, 209627394169878723509), (285143056, 1603058954966598709438), + (570286113, 4087400380638421578313), (1140572227, 3854475371193330872408), + (2281144455, 4548170699237532117594), (4562288911, 96810702657754282860), + (9124577823, 801598548757765911640), (18249155647, 1769700672235665660990), + (36498311295, 3876319881977029146127), (72996622590, 876039423971175622171), + (145993245181, 4649527616733289428812), (291986490363, 2550984347481246070394), + (583972980727, 2498655437590436137299), (1167945961455, 65069250749385495183), + (2335891922910, 1571762328282404417125), (4671783845820, 3449124460750840043826), + (9343567691640, 2988036454590443003654), (18687135383280, 3118370548386029122906), + (37374270766560, 4404899618966855689530), (74748541533120, 500041119609794681509), + (149497083066240, 1658431971714980800258), (298994166132481, 1652729214384995199889), + (597988332264962, 3483662876981169111089), (1195976664529924, 4452810806574978194111), + (2391953329059848, 406659608570972694491), (4783906658119696, 568194097866301343433), + (9567813316239393, 3251008112012158710204), (19135626632478787, 1411809316118057736059), + (38271253264957575, 1852677203085806923275), (76542506529915151, 3279718428626818689485), + (153085013059830303, 4244068271519720780385), (306170026119660607, 326319274657394007224), + (612340052239321215, 3331647086894715815320), (1224680104478642430, 4572692076427785223313), + (2449360208957284861, 3191906240571644478334), (4898720417914569723, 3963504746312681992653), + (9797440835829139447, 1571779427312081768056), (19594881671658278895, 4684808507442451414847)] + +/-- Residue of `root ^ ((fieldSize - 1) / 241)`. -/ +def rootPowDiv241Residue : Nat := + 4684808507442451414847 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 241)`. -/ +theorem root_pow_div_241_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 241) rootPowDiv241Chain rootPowDiv241Residue = true := by + rfl + +private theorem root_pow_div_241_certified : + ConcreteField.root ^ ((fieldSize - 1) / 241) = + ConcreteField.ofNat rootPowDiv241Residue ∧ + rootPowDiv241Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 241) + (cert := rootPowDiv241Chain) (expected := rootPowDiv241Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_241_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 241)`. -/ +theorem root_pow_div_241_eq : + ConcreteField.root ^ ((fieldSize - 1) / 241) = + ConcreteField.ofNat rootPowDiv241Residue := + root_pow_div_241_certified.1 + +/-- The `241`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_241_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 241) ≠ (1 : ConcreteField) := by + rw [root_pow_div_241_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv241Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv241Residue] using root_pow_div_241_certified.2) + (by unfold rootPowDiv241Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 433)`. -/ +def rootPowDiv433Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (2, 4), (4, 16), (9, 512), (18, 262144), (37, 137438953472), (75, 760), + (151, 567936), (302, 276023230464), (605, 2314885530816351200), (1210, 395192499409868156), + (2421, 2951481687324009602310), (4843, 2215917392620854760979), (9686, 3864910758127394341125), + (19373, 4502413466794368745440), (38746, 1322495301166375554866), + (77492, 4161299696785663245543), (154985, 3296291945416869803982), + (309971, 1420346409814147025485), (619943, 1262206598537941136291), + (1239886, 3332275895429762972010), (2479773, 2061845094934567431029), + (4959546, 4113927262245707885966), (9919093, 1669764564152218878866), + (19838186, 4297983480335249081815), (39676372, 218412507727886770616), + (79352744, 126857260574517554911), (158705488, 1509897381286872406266), + (317410977, 1747321213733408433937), (634821955, 3877800159967371688675), + (1269643911, 4516772557106435113622), (2539287823, 2652760353301564486250), + (5078575647, 2629439233137731744021), (10157151295, 124345895086820281951), + (20314302591, 767109484623854462666), (40628605183, 3942637969511886307344), + (81257210366, 2361034888861296673214), (162514420733, 749543324795183460529), + (325028841467, 4707185675530571374532), (650057682934, 1181905048922969494653), + (1300115365869, 1331197861738993928349), (2600230731738, 4183964151419403630978), + (5200461463476, 445850456722192168266), (10400922926952, 250490127505138442552), + (20801845853905, 2626003308866762598624), (41603691707810, 3893252862767409157533), + (83207383415621, 1741966707635721258336), (166414766831242, 3400887082298537882579), + (332829533662484, 3052987973131469983627), (665659067324969, 2250143104480490582601), + (1331318134649938, 3648708879267356413965), (2662636269299877, 1942872099306177098302), + (5325272538599755, 3536574563902219069327), (10650545077199510, 3340438786038309040535), + (21301090154399020, 3318922864786860285684), (42602180308798040, 3308960900871327043197), + (85204360617596081, 4398220485231501748575), (170408721235192162, 282001662430777439108), + (340817442470384325, 2585376674092072934142), (681634884940768650, 2406231771807454229317), + (1363269769881537301, 2560904020429558227809), (2726539539763074603, 2609421348692579496921), + (5453079079526149207, 2450899289667973113689), (10906158159052298415, 217819503687932091783)] + +/-- Residue of `root ^ ((fieldSize - 1) / 433)`. -/ +def rootPowDiv433Residue : Nat := + 217819503687932091783 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 433)`. -/ +theorem root_pow_div_433_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 433) rootPowDiv433Chain rootPowDiv433Residue = true := by + rfl + +private theorem root_pow_div_433_certified : + ConcreteField.root ^ ((fieldSize - 1) / 433) = + ConcreteField.ofNat rootPowDiv433Residue ∧ + rootPowDiv433Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 433) + (cert := rootPowDiv433Chain) (expected := rootPowDiv433Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_433_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 433)`. -/ +theorem root_pow_div_433_eq : + ConcreteField.root ^ ((fieldSize - 1) / 433) = + ConcreteField.ofNat rootPowDiv433Residue := + root_pow_div_433_certified.1 + +/-- The `433`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_433_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 433) ≠ (1 : ConcreteField) := by + rw [root_pow_div_433_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv433Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv433Residue] using root_pow_div_433_certified.2) + (by unfold rootPowDiv433Residue; norm_num) + +/-- Structural power chain for `root ^ ((fieldSize - 1) / 38737)`. -/ +def rootPowDiv38737Chain : List (Nat × Nat) := + [(0, 1), (1, 2), (3, 8), (6, 64), (13, 8192), (27, 134217728), (54, 18014398509481984), + (108, 6528350289920), (216, 375827), (433, 148354630154), (866, 78417877378472870200), + (1732, 109955391387482780992), (3464, 385726527410386807884), (6929, 3539799255437628874400), + (13859, 1807786492782711595715), (27718, 3992374729643737366054), + (55437, 2243665993340995109386), (110875, 806719127951078774153), + (221750, 1968083648281024636669), (443500, 2877598070540130990621), + (887000, 4014855784035615021615), (1774000, 2003559355686063636744), + (3548001, 2772610258447612073823), (7096003, 1136449126379535583447), + (14192007, 1371047095872242544500), (28384015, 3688868878582957562119), + (56768031, 4197355298377057584520), (113536063, 3401914857368164229116), + (227072127, 1937139997211708258275), (454144255, 2934482542561582992045), + (908288511, 934890357601568245439), (1816577023, 3779120388033720505394), + (3633154047, 2036524050944255914868), (7266308095, 2881852198158079712217), + (14532616191, 1075117802783372458887), (29065232383, 4313317375315378681740), + (58130464767, 1163900829485895838234), (116260929534, 1845109520114375310379), + (232521859068, 4020333230252722152410), (465043718137, 4016248997101821805556), + (930087436274, 767675856011929145649), (1860174872548, 808831061056227913917), + (3720349745097, 1573222477844258277220), (7440699490195, 4710830237896774107609), + (14881398980391, 49562123326766955518), (29762797960782, 81477718364566749899), + (59525595921565, 2431013655800055340146), (119051191843131, 2513542055562451067413), + (238102383686263, 2453651414770199859425), (476204767372526, 2373527945221294463375), + (952409534745052, 3542328496675377852123), (1904819069490105, 4282140643303339139950), + (3809638138980210, 1393047085942734075882), (7619276277960420, 3374728666230530135412), + (15238552555920841, 1286412167778067069125), (30477105111841683, 4166318550440293432483), + (60954210223683367, 3257650589931020553128), (121908420447366735, 4209294365954897904347)] + +/-- Residue of `root ^ ((fieldSize - 1) / 38737)`. -/ +def rootPowDiv38737Residue : Nat := + 4209294365954897904347 + +/-- Kernel check for `root ^ ((fieldSize - 1) / 38737)`. -/ +theorem root_pow_div_38737_check : + BinaryField.Extension.Concrete.checkPowNatChain Concrete.params 2 + ((fieldSize - 1) / 38737) rootPowDiv38737Chain rootPowDiv38737Residue = true := by + rfl + +private theorem root_pow_div_38737_certified : + ConcreteField.root ^ ((fieldSize - 1) / 38737) = + ConcreteField.ofNat rootPowDiv38737Residue ∧ + rootPowDiv38737Residue < 2 ^ extensionDegree := by + simpa [ConcreteField.root, ConcreteField.ofNat, BinaryField.Extension.Concrete.root, + Concrete.params] using + (BinaryField.Extension.Concrete.pow_eq_of_checkPowNatChain + Concrete.params (a := 2) (target := (fieldSize - 1) / 38737) + (cert := rootPowDiv38737Chain) (expected := rootPowDiv38737Residue) + (by unfold Concrete.params extensionDegree; norm_num) + (by unfold Concrete.params extensionDegree; norm_num) + root_pow_div_38737_check) + +/-- Certified residue of `root ^ ((fieldSize - 1) / 38737)`. -/ +theorem root_pow_div_38737_eq : + ConcreteField.root ^ ((fieldSize - 1) / 38737) = + ConcreteField.ofNat rootPowDiv38737Residue := + root_pow_div_38737_certified.1 + +/-- The `38737`-prime divisor power of the root is nontrivial. -/ +theorem root_pow_div_38737_ne_one : + ConcreteField.root ^ ((fieldSize - 1) / 38737) ≠ (1 : ConcreteField) := by + rw [root_pow_div_38737_eq] + change BinaryField.Extension.Concrete.ofNat Concrete.params + rootPowDiv38737Residue ≠ BinaryField.Extension.Concrete.one Concrete.params + exact BinaryField.Extension.Concrete.ofNat_ne_one_of_lt Concrete.params + (by unfold Concrete.params extensionDegree; norm_num) + (by simpa [rootPowDiv38737Residue] using root_pow_div_38737_certified.2) + (by unfold rootPowDiv38737Residue; norm_num) + +end GF2_72 diff --git a/CompPoly/Fields/Binary/GF2_72/RootContexts.lean b/CompPoly/Fields/Binary/GF2_72/RootContexts.lean new file mode 100644 index 00000000..b4de5aa0 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/RootContexts.lean @@ -0,0 +1,249 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_72.Primitive +import CompPoly.Fields.Binary.Extension.Enumeration +import CompPoly.Univariate.Roots.Context +import CompPoly.Univariate.Roots.Shoup.Basic +import CompPoly.Univariate.Roots.SmoothSubgroup +import Mathlib.FieldTheory.Finite.Trace + +/-! +# GF(2^72) Root-Search Contexts + +Certified finite-field context for the executable `GF(2^72)` carrier. +-/ + +namespace GF2_72 + +open CompPoly +open CompPoly.CPolynomial.Roots.FiniteField + +private theorem exists_basis_trace_ne {K L ι : Type*} [Field K] [Field L] [Algebra K L] + [FiniteDimensional K L] [Algebra.IsSeparable K L] + (b : Module.Basis ι K L) {x : L} (hx : x ≠ 0) : + ∃ i, Algebra.trace K L (b i * x) ≠ 0 := by + have hnd := (traceForm_nondegenerate K L).1 x + by_contra hnone + push Not at hnone + have hzero : (Algebra.traceForm K L) x = 0 := by + apply b.ext + intro i + rw [Algebra.traceForm_apply] + simpa [mul_comm] using hnone i + exact hx (hnd (by + intro y + rw [hzero] + rfl)) + +/-- Finite-field context for the executable `GF(2^72)` carrier. -/ +def finiteFieldContext : + CompPoly.CPolynomial.Roots.FiniteField.FiniteFieldContext ConcreteField where + q := fieldSize + finite := by infer_instance + card_eq := by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card + frobenius_fixed := by + intro a + have hcard : Fintype.card ConcreteField = fieldSize := by + exact ConcreteField.card + simpa [hcard] using FiniteField.pow_card a + +/-- Lazy complete enumeration for `GF(2^72)`. -/ +def fieldEnumeration : + CompPoly.CPolynomial.Roots.FiniteField.FieldEnumeration ConcreteField := + BinaryField.Extension.Concrete.fieldEnumeration Concrete.params + +namespace ConcreteField + +local instance fieldInst : Field ConcreteField := + instFieldConcreteField + +local instance commRingInst : CommRing ConcreteField := + fieldInst.toCommRing + +noncomputable local instance algebraInst : Algebra (ZMod 2) ConcreteField := + instAlgebraConcreteField + +/-- Algebraic trace value embedded back into executable `GF(2^72)`. -/ +noncomputable def algebraicTraceValue (z : ConcreteField) : ConcreteField := + algebraMap (ZMod 2) ConcreteField (Algebra.trace (ZMod 2) ConcreteField z) + +/-- The executable GF72 carrier has dimension `72` over `GF(2)`. -/ +theorem finrank_eq_extensionDegree : + Module.finrank (ZMod 2) ConcreteField = extensionDegree := by + have h := FiniteField.pow_finrank_eq_card (p := 2) (k := ConcreteField) + rw [card] at h + exact Nat.pow_right_injective (by norm_num : 1 < 2) h + +/-- The algebraic trace equals the Shoup Frobenius power sum. -/ +theorem algebraicTraceValue_eq_powerSum (z : ConcreteField) : + algebraicTraceValue z = tracePowerSum 2 extensionDegree z := by + unfold algebraicTraceValue + have htrace := FiniteField.algebraMap_trace_eq_sum_pow (ZMod 2) ConcreteField z + rw [finrank_eq_extensionDegree] at htrace + rw [htrace] + rw [tracePowerSum_eq_sum_range] + simp + +/-- The GF72 trace lands in the embedded `GF(2)` constants. -/ +theorem algebraicTraceValue_mem_base (z : ConcreteField) : + algebraicTraceValue z ∈ baseConstants.toList := by + unfold algebraicTraceValue baseConstants BinaryField.Extension.Concrete.baseConstants + let t : ZMod 2 := Algebra.trace (ZMod 2) ConcreteField z + change algebraMap (ZMod 2) ConcreteField t ∈ + [BinaryField.Extension.Concrete.zero Concrete.params, + BinaryField.Extension.Concrete.one Concrete.params] + have ht : ∀ u : ZMod 2, u = 0 ∨ u = 1 := by + intro u + fin_cases u + · left + rfl + · right + rfl + rcases ht t with ht0 | ht1 + · rw [ht0, map_zero] + left + · rw [ht1, map_one] + right + left + +/-- The transported quotient power basis for executable `GF(2^72)`. -/ +noncomputable def polynomialPowerBasis : PowerBasis (ZMod 2) ConcreteField := + (AdjoinRoot.powerBasis (BinaryField.Extension.polynomial_ne_zero definingPolynomialData)).map + toSpecAlgEquiv.symm + +@[simp] +theorem polynomialPowerBasis_dim_eq : + polynomialPowerBasis.dim = extensionDegree := by + simp [polynomialPowerBasis, BinaryField.Extension.polynomial_natDegree, + definingPolynomialData, extensionDegree] + +/-- The executable polynomial basis as a Lean basis. -/ +noncomputable def polynomialBasisBasis : + Module.Basis (Fin extensionDegree) (ZMod 2) ConcreteField := + polynomialPowerBasis.basis.reindex (finCongr polynomialPowerBasis_dim_eq) + +set_option maxRecDepth 10000 in +theorem polynomialBasisBasis_apply (i : Fin extensionDegree) : + polynomialBasisBasis i = root ^ i.val := by + unfold polynomialBasisBasis polynomialPowerBasis + rw [Module.Basis.reindex_apply] + change toSpecAlgEquiv.symm + (AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i)) = root ^ i.val + rw [show + AdjoinRoot.powerBasisAux (BinaryField.Extension.polynomial_ne_zero definingPolynomialData) + ((finCongr polynomialPowerBasis_dim_eq).symm i) = + (BinaryField.Extension.root definingPolynomialData) ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val by + simp [AdjoinRoot.powerBasisAux, BinaryField.Extension.root]] + rw [map_pow] + change toSpecAlgEquiv.symm GF2_72.root ^ + ((finCongr polynomialPowerBasis_dim_eq).symm i).val = root ^ i.val + have hrootSymm : toSpecAlgEquiv.symm GF2_72.root = root := by + rw [AlgEquiv.symm_apply_eq] + exact toSpec_root.symm + rw [hrootSymm] + congr 1 + +/-- Each Lean polynomial-basis vector is present in the executable basis array. -/ +theorem polynomialBasisBasis_mem (i : Fin extensionDegree) : + polynomialBasisBasis i ∈ polynomialBasis.toList := by + rw [polynomialBasisBasis_apply] + rw [← Array.mem_def] + rw [polynomialBasis, BinaryField.Extension.Concrete.polynomialBasis, Array.mem_ofFn] + exact ⟨i, rfl⟩ + +/-- The executable polynomial basis separates distinct elements by GF72 trace coordinates. -/ +theorem algebraicTraceValue_separates {a b : ConcreteField} (hne : a ≠ b) : + ∃ beta, beta ∈ polynomialBasis.toList ∧ algebraicTraceValue (beta * (a - b)) ≠ 0 := by + have hx : a - b ≠ 0 := sub_ne_zero.mpr hne + rcases exists_basis_trace_ne polynomialBasisBasis hx with ⟨i, htrace⟩ + refine ⟨polynomialBasisBasis i, polynomialBasisBasis_mem i, ?_⟩ + unfold algebraicTraceValue + intro hzero + apply htrace + have hz' : + algebraMap (ZMod 2) ConcreteField + (Algebra.trace (ZMod 2) ConcreteField (polynomialBasisBasis i * (a - b))) = + algebraMap (ZMod 2) ConcreteField 0 := by + rw [map_zero] + exact hzero + exact (FaithfulSMul.algebraMap_injective (ZMod 2) ConcreteField) hz' + +end ConcreteField + +/-- Shoup trace splitter context for `GF(2^72)`. -/ +def shoupTraceContext : + CPolynomial.Roots.FiniteField.SmallPrimeTraceContext ConcreteField where + toFiniteFieldContext := finiteFieldContext + p := 2 + k := extensionDegree + p_prime := Nat.prime_two + q_eq := by + simp [finiteFieldContext, fieldSize, BinaryField.Extension.fieldSize] + baseConstants := ConcreteField.baseConstants + baseConstants_size := ConcreteField.baseConstants_size + basis := ConcreteField.polynomialBasis + basis_size := ConcreteField.polynomialBasis_size + traceValue := tracePowerSum 2 extensionDegree + traceValue_eq_powerSum := fun _ ↦ rfl + traceValue_mem_base := by + intro z + rw [← ConcreteField.algebraicTraceValue_eq_powerSum] + exact ConcreteField.algebraicTraceValue_mem_base z + trace_separates := by + intro a b hne + rcases ConcreteField.algebraicTraceValue_separates hne with ⟨beta, hbeta, htrace⟩ + refine ⟨beta, hbeta, ?_⟩ + rwa [← ConcreteField.algebraicTraceValue_eq_powerSum] + +/-- Smooth cyclic splitter context for `GF(2^72)` with the supplied leaf evaluator. -/ +def smoothCyclicRootContextWith + (leafEvaluator : CPolynomial.BatchEvalContext ConcreteField) : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + CPolynomial.Roots.FiniteField.smoothCyclicRootContextOf + fieldSize + primitiveRoot + smoothRootSchedule + leafEvaluator + (CPolynomial.Roots.FiniteField.smoothSplitterInput + fieldSize primitiveRoot smoothRootSchedule) + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + smoothRootSchedule_fold_eq_one + (by + intro M D p factor h + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_sound + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule h) + (by + intro M D p a _hvalid hp hroot + exact CPolynomial.Roots.FiniteField.smoothLinearFactorsAlgorithmWith_complete + M D leafEvaluator fieldSize primitiveRoot smoothRootSchedule + (by + rw [Nat.card_eq_fintype_card] + exact ConcreteField.card) + primitiveRoot_order + (by decide) + hp hroot) + +/-- Smooth cyclic splitter context for `GF(2^72)` using Horner leaf evaluation. -/ +def smoothHornerRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith (CPolynomial.BatchEvalContext.horner ConcreteField) + +/-- Smooth cyclic splitter context for `GF(2^72)` using subproduct-tree leaf evaluation. -/ +def smoothSubproductRootContext : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext ConcreteField := + smoothCyclicRootContextWith + (CPolynomial.BatchEvalContext.subproduct ConcreteField + CPolynomial.MulContext.naive CPolynomial.ModContext.naive) + +end GF2_72 diff --git a/CompPoly/Fields/Binary/GF2_72/XPowTwoPowGcdCertificate.lean b/CompPoly/Fields/Binary/GF2_72/XPowTwoPowGcdCertificate.lean new file mode 100644 index 00000000..05f36d17 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/XPowTwoPowGcdCertificate.lean @@ -0,0 +1,1340 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_72.XPowTwoPowModCertificate + +/-! +# GF(2^72) Rabin GCD Certificate + +Kernel-safe Euclidean-division certificates for the two Rabin gcd checks of +`X^72 + X^6 + X^4 + X^3 + X^2 + X + 1`. +-/ + +namespace GF2_72 + +open Polynomial + +set_option maxRecDepth 2200 + +private abbrev B144 : Type := BitVec (2 * extensionDegree) + +def gcdPVal : B144 := BitVec.ofNat (2 * extensionDegree) 4722366482869645213791 + +/-- Numeric 144-bit encoding of the GF72 defining polynomial. -/ +lemma definingPolynomial_eq_gcdPVal : + definingPolynomial = BinaryField.toPoly gcdPVal := by + rw [definingPolynomial_eq_P_val] + have h : P_val = gcdPVal := by + decide + rw [h] + +/-- Any GF72-width polynomial is already reduced modulo the defining polynomial. -/ +lemma toPoly_mod_definingPolynomial_eq_self (v : B72) : + BinaryField.toPoly v % definingPolynomial = BinaryField.toPoly v := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + exact BinaryField.toPoly_degree_lt_w + (w := extensionDegree) (h_w_pos := by unfold extensionDegree; omega) v + +/-- Soundness wrapper specialized to 144-bit Euclidean-division certificates. -/ +private theorem verify_div_step {a q b r : B144} + (h : BinaryField.Extension.checkDivStep (2 * extensionDegree) a q b r = true) : + BinaryField.toPoly a = BinaryField.toPoly q * BinaryField.toPoly b + + BinaryField.toPoly r := by + exact BinaryField.Extension.checkDivStep_correct a q b r h + +private theorem toPoly_ne_zero {v : B144} (h : v ≠ 0) : + BinaryField.toPoly v ≠ 0 := + (BinaryField.toPoly_ne_zero_iff_ne_zero v).mpr h + +/-- Initial Rabin gcd remainder for exponent `36`. -/ +def gcd36_b1Val : B144 := BitVec.ofNat (2 * extensionDegree) 3130559789706947830732 + +lemma gcd36_b1Val_eq_zeroExtend : + gcd36_b1Val = BitVec.zeroExtend (2 * extensionDegree) (r36Val ^^^ r0Val) := by + decide + +def gcd36_a1Val : B144 := gcdPVal +def gcd36_q1Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r1Val : B144 := BitVec.ofNat (2 * extensionDegree) 1538753096544250447815 + +def gcd36_a2Val : B144 := gcd36_b1Val +def gcd36_b2Val : B144 := gcd36_r1Val +def gcd36_q2Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r2Val : B144 := BitVec.ofNat (2 * extensionDegree) 283746144541738871874 + +def gcd36_a3Val : B144 := gcd36_b2Val +def gcd36_b3Val : B144 := gcd36_r2Val +def gcd36_q3Val : B144 := BitVec.ofNat (2 * extensionDegree) 15 +def gcd36_r3Val : B144 := BitVec.ofNat (2 * extensionDegree) 78472190197577408537 + +def gcd36_a4Val : B144 := gcd36_b3Val +def gcd36_b4Val : B144 := gcd36_r3Val +def gcd36_q4Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd36_r4Val : B144 := BitVec.ofNat (2 * extensionDegree) 67070847363661368425 + +def gcd36_a5Val : B144 := gcd36_b4Val +def gcd36_b5Val : B144 := gcd36_r4Val +def gcd36_q5Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd36_r5Val : B144 := BitVec.ofNat (2 * extensionDegree) 11986811782157104290 + +def gcd36_a6Val : B144 := gcd36_b5Val +def gcd36_b6Val : B144 := gcd36_r5Val +def gcd36_q6Val : B144 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd36_r6Val : B144 := BitVec.ofNat (2 * extensionDegree) 8583360565896361893 + +def gcd36_a7Val : B144 := gcd36_b6Val +def gcd36_b7Val : B144 := gcd36_r6Val +def gcd36_q7Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd36_r7Val : B144 := BitVec.ofNat (2 * extensionDegree) 4574527822564666445 + +def gcd36_a8Val : B144 := gcd36_b7Val +def gcd36_b8Val : B144 := gcd36_r7Val +def gcd36_q8Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r8Val : B144 := BitVec.ofNat (2 * extensionDegree) 714314599271132991 + +def gcd36_a9Val : B144 := gcd36_b8Val +def gcd36_b9Val : B144 := gcd36_r8Val +def gcd36_q9Val : B144 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd36_r9Val : B144 := BitVec.ofNat (2 * extensionDegree) 209059452027970032 + +def gcd36_a10Val : B144 := gcd36_b9Val +def gcd36_b10Val : B144 := gcd36_r9Val +def gcd36_q10Val : B144 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd36_r10Val : B144 := BitVec.ofNat (2 * extensionDegree) 42101374778624271 + +def gcd36_a11Val : B144 := gcd36_b10Val +def gcd36_b11Val : B144 := gcd36_r10Val +def gcd36_q11Val : B144 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd36_r11Val : B144 := BitVec.ofNat (2 * extensionDegree) 10523856223456451 + +def gcd36_a12Val : B144 := gcd36_b11Val +def gcd36_b12Val : B144 := gcd36_r11Val +def gcd36_q12Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd36_r12Val : B144 := BitVec.ofNat (2 * extensionDegree) 34544141695491 + +def gcd36_a13Val : B144 := gcd36_b12Val +def gcd36_b13Val : B144 := gcd36_r12Val +def gcd36_q13Val : B144 := BitVec.ofNat (2 * extensionDegree) 873 +def gcd36_r13Val : B144 := BitVec.ofNat (2 * extensionDegree) 17103716524920 + +def gcd36_a14Val : B144 := gcd36_b13Val +def gcd36_b14Val : B144 := gcd36_r13Val +def gcd36_q14Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r14Val : B144 := BitVec.ofNat (2 * extensionDegree) 508528835827 + +def gcd36_a15Val : B144 := gcd36_b14Val +def gcd36_b15Val : B144 := gcd36_r14Val +def gcd36_q15Val : B144 := BitVec.ofNat (2 * extensionDegree) 39 +def gcd36_r15Val : B144 := BitVec.ofNat (2 * extensionDegree) 6987680705 + +def gcd36_a16Val : B144 := gcd36_b15Val +def gcd36_b16Val : B144 := gcd36_r15Val +def gcd36_q16Val : B144 := BitVec.ofNat (2 * extensionDegree) 87 +def gcd36_r16Val : B144 := BitVec.ofNat (2 * extensionDegree) 533382116 + +def gcd36_a17Val : B144 := gcd36_b16Val +def gcd36_b17Val : B144 := gcd36_r16Val +def gcd36_q17Val : B144 := BitVec.ofNat (2 * extensionDegree) 23 +def gcd36_r17Val : B144 := BitVec.ofNat (2 * extensionDegree) 61341245 + +def gcd36_a18Val : B144 := gcd36_b17Val +def gcd36_b18Val : B144 := gcd36_r17Val +def gcd36_q18Val : B144 := BitVec.ofNat (2 * extensionDegree) 9 +def gcd36_r18Val : B144 := BitVec.ofNat (2 * extensionDegree) 22203441 + +def gcd36_a19Val : B144 := gcd36_b18Val +def gcd36_b19Val : B144 := gcd36_r18Val +def gcd36_q19Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd36_r19Val : B144 := BitVec.ofNat (2 * extensionDegree) 5286510 + +def gcd36_a20Val : B144 := gcd36_b19Val +def gcd36_b20Val : B144 := gcd36_r19Val +def gcd36_q20Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd36_r20Val : B144 := BitVec.ofNat (2 * extensionDegree) 1074569 + +def gcd36_a21Val : B144 := gcd36_b20Val +def gcd36_b21Val : B144 := gcd36_r20Val +def gcd36_q21Val : B144 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd36_r21Val : B144 := BitVec.ofNat (2 * extensionDegree) 88515 + +def gcd36_a22Val : B144 := gcd36_b21Val +def gcd36_b22Val : B144 := gcd36_r21Val +def gcd36_q22Val : B144 := BitVec.ofNat (2 * extensionDegree) 20 +def gcd36_r22Val : B144 := BitVec.ofNat (2 * extensionDegree) 40629 + +def gcd36_a23Val : B144 := gcd36_b22Val +def gcd36_b23Val : B144 := gcd36_r22Val +def gcd36_q23Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r23Val : B144 := BitVec.ofNat (2 * extensionDegree) 25769 + +def gcd36_a24Val : B144 := gcd36_b23Val +def gcd36_b24Val : B144 := gcd36_r23Val +def gcd36_q24Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd36_r24Val : B144 := BitVec.ofNat (2 * extensionDegree) 13134 + +def gcd36_a25Val : B144 := gcd36_b24Val +def gcd36_b25Val : B144 := gcd36_r24Val +def gcd36_q25Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r25Val : B144 := BitVec.ofNat (2 * extensionDegree) 565 + +def gcd36_a26Val : B144 := gcd36_b25Val +def gcd36_b26Val : B144 := gcd36_r25Val +def gcd36_q26Val : B144 := BitVec.ofNat (2 * extensionDegree) 24 +def gcd36_r26Val : B144 := BitVec.ofNat (2 * extensionDegree) 438 + +def gcd36_a27Val : B144 := gcd36_b26Val +def gcd36_b27Val : B144 := gcd36_r26Val +def gcd36_q27Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd36_r27Val : B144 := BitVec.ofNat (2 * extensionDegree) 239 + +def gcd36_a28Val : B144 := gcd36_b27Val +def gcd36_b28Val : B144 := gcd36_r27Val +def gcd36_q28Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r28Val : B144 := BitVec.ofNat (2 * extensionDegree) 104 + +def gcd36_a29Val : B144 := gcd36_b28Val +def gcd36_b29Val : B144 := gcd36_r28Val +def gcd36_q29Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r29Val : B144 := BitVec.ofNat (2 * extensionDegree) 63 + +def gcd36_a30Val : B144 := gcd36_b29Val +def gcd36_b30Val : B144 := gcd36_r29Val +def gcd36_q30Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r30Val : B144 := BitVec.ofNat (2 * extensionDegree) 22 + +def gcd36_a31Val : B144 := gcd36_b30Val +def gcd36_b31Val : B144 := gcd36_r30Val +def gcd36_q31Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd36_r31Val : B144 := BitVec.ofNat (2 * extensionDegree) 5 + +def gcd36_a32Val : B144 := gcd36_b31Val +def gcd36_b32Val : B144 := gcd36_r31Val +def gcd36_q32Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd36_r32Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 + +def gcd36_a33Val : B144 := gcd36_b32Val +def gcd36_b33Val : B144 := gcd36_r32Val +def gcd36_q33Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r33Val : B144 := BitVec.ofNat (2 * extensionDegree) 1 + +def gcd36_a34Val : B144 := gcd36_b33Val +def gcd36_b34Val : B144 := gcd36_r33Val +def gcd36_q34Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd36_r34Val : B144 := BitVec.ofNat (2 * extensionDegree) 0 + +/-- Reduce the exponent `36` Rabin gcd to the generated Euclidean trace. -/ +lemma gcd36_start_reduction : + EuclideanDomain.gcd (X ^ (2 ^ 36) + X) definingPolynomial = + EuclideanDomain.gcd definingPolynomial (BinaryField.toPoly gcd36_b1Val) := by + rw [ZMod2Poly.euclidean_gcd_comm] + rw [EuclideanDomain.gcd_val] + conv_lhs => + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_36_mod_eq] + rw [r36] + rw [toPoly_mod_definingPolynomial_eq_self r36Val, X_mod_definingPolynomial] + rw [← r0_eq_X] + rw [r0] + rw [← BinaryField.toPoly_xor] + rw [toPoly_mod_definingPolynomial_eq_self (r36Val ^^^ r0Val)] + rw [← BinaryField.Extension.toPoly_zeroExtend + (show extensionDegree ≤ 2 * extensionDegree by unfold extensionDegree; norm_num) + (r36Val ^^^ r0Val)] + rw [← gcd36_b1Val_eq_zeroExtend] + rw [ZMod2Poly.euclidean_gcd_comm] + +lemma gcd36_step_1 : + BinaryField.toPoly gcd36_a1Val = + BinaryField.toPoly gcd36_q1Val * BinaryField.toPoly gcd36_b1Val + + BinaryField.toPoly gcd36_r1Val := by + exact verify_div_step (a := gcd36_a1Val) (q := gcd36_q1Val) + (b := gcd36_b1Val) (r := gcd36_r1Val) (by rfl) + +lemma gcd36_step_2 : + BinaryField.toPoly gcd36_a2Val = + BinaryField.toPoly gcd36_q2Val * BinaryField.toPoly gcd36_b2Val + + BinaryField.toPoly gcd36_r2Val := by + exact verify_div_step (a := gcd36_a2Val) (q := gcd36_q2Val) + (b := gcd36_b2Val) (r := gcd36_r2Val) (by rfl) + +lemma gcd36_step_3 : + BinaryField.toPoly gcd36_a3Val = + BinaryField.toPoly gcd36_q3Val * BinaryField.toPoly gcd36_b3Val + + BinaryField.toPoly gcd36_r3Val := by + exact verify_div_step (a := gcd36_a3Val) (q := gcd36_q3Val) + (b := gcd36_b3Val) (r := gcd36_r3Val) (by rfl) + +lemma gcd36_step_4 : + BinaryField.toPoly gcd36_a4Val = + BinaryField.toPoly gcd36_q4Val * BinaryField.toPoly gcd36_b4Val + + BinaryField.toPoly gcd36_r4Val := by + exact verify_div_step (a := gcd36_a4Val) (q := gcd36_q4Val) + (b := gcd36_b4Val) (r := gcd36_r4Val) (by rfl) + +lemma gcd36_step_5 : + BinaryField.toPoly gcd36_a5Val = + BinaryField.toPoly gcd36_q5Val * BinaryField.toPoly gcd36_b5Val + + BinaryField.toPoly gcd36_r5Val := by + exact verify_div_step (a := gcd36_a5Val) (q := gcd36_q5Val) + (b := gcd36_b5Val) (r := gcd36_r5Val) (by rfl) + +lemma gcd36_step_6 : + BinaryField.toPoly gcd36_a6Val = + BinaryField.toPoly gcd36_q6Val * BinaryField.toPoly gcd36_b6Val + + BinaryField.toPoly gcd36_r6Val := by + exact verify_div_step (a := gcd36_a6Val) (q := gcd36_q6Val) + (b := gcd36_b6Val) (r := gcd36_r6Val) (by rfl) + +lemma gcd36_step_7 : + BinaryField.toPoly gcd36_a7Val = + BinaryField.toPoly gcd36_q7Val * BinaryField.toPoly gcd36_b7Val + + BinaryField.toPoly gcd36_r7Val := by + exact verify_div_step (a := gcd36_a7Val) (q := gcd36_q7Val) + (b := gcd36_b7Val) (r := gcd36_r7Val) (by rfl) + +lemma gcd36_step_8 : + BinaryField.toPoly gcd36_a8Val = + BinaryField.toPoly gcd36_q8Val * BinaryField.toPoly gcd36_b8Val + + BinaryField.toPoly gcd36_r8Val := by + exact verify_div_step (a := gcd36_a8Val) (q := gcd36_q8Val) + (b := gcd36_b8Val) (r := gcd36_r8Val) (by rfl) + +lemma gcd36_step_9 : + BinaryField.toPoly gcd36_a9Val = + BinaryField.toPoly gcd36_q9Val * BinaryField.toPoly gcd36_b9Val + + BinaryField.toPoly gcd36_r9Val := by + exact verify_div_step (a := gcd36_a9Val) (q := gcd36_q9Val) + (b := gcd36_b9Val) (r := gcd36_r9Val) (by rfl) + +lemma gcd36_step_10 : + BinaryField.toPoly gcd36_a10Val = + BinaryField.toPoly gcd36_q10Val * BinaryField.toPoly gcd36_b10Val + + BinaryField.toPoly gcd36_r10Val := by + exact verify_div_step (a := gcd36_a10Val) (q := gcd36_q10Val) + (b := gcd36_b10Val) (r := gcd36_r10Val) (by rfl) + +lemma gcd36_step_11 : + BinaryField.toPoly gcd36_a11Val = + BinaryField.toPoly gcd36_q11Val * BinaryField.toPoly gcd36_b11Val + + BinaryField.toPoly gcd36_r11Val := by + exact verify_div_step (a := gcd36_a11Val) (q := gcd36_q11Val) + (b := gcd36_b11Val) (r := gcd36_r11Val) (by rfl) + +lemma gcd36_step_12 : + BinaryField.toPoly gcd36_a12Val = + BinaryField.toPoly gcd36_q12Val * BinaryField.toPoly gcd36_b12Val + + BinaryField.toPoly gcd36_r12Val := by + exact verify_div_step (a := gcd36_a12Val) (q := gcd36_q12Val) + (b := gcd36_b12Val) (r := gcd36_r12Val) (by rfl) + +lemma gcd36_step_13 : + BinaryField.toPoly gcd36_a13Val = + BinaryField.toPoly gcd36_q13Val * BinaryField.toPoly gcd36_b13Val + + BinaryField.toPoly gcd36_r13Val := by + exact verify_div_step (a := gcd36_a13Val) (q := gcd36_q13Val) + (b := gcd36_b13Val) (r := gcd36_r13Val) (by rfl) + +lemma gcd36_step_14 : + BinaryField.toPoly gcd36_a14Val = + BinaryField.toPoly gcd36_q14Val * BinaryField.toPoly gcd36_b14Val + + BinaryField.toPoly gcd36_r14Val := by + exact verify_div_step (a := gcd36_a14Val) (q := gcd36_q14Val) + (b := gcd36_b14Val) (r := gcd36_r14Val) (by rfl) + +lemma gcd36_step_15 : + BinaryField.toPoly gcd36_a15Val = + BinaryField.toPoly gcd36_q15Val * BinaryField.toPoly gcd36_b15Val + + BinaryField.toPoly gcd36_r15Val := by + exact verify_div_step (a := gcd36_a15Val) (q := gcd36_q15Val) + (b := gcd36_b15Val) (r := gcd36_r15Val) (by rfl) + +lemma gcd36_step_16 : + BinaryField.toPoly gcd36_a16Val = + BinaryField.toPoly gcd36_q16Val * BinaryField.toPoly gcd36_b16Val + + BinaryField.toPoly gcd36_r16Val := by + exact verify_div_step (a := gcd36_a16Val) (q := gcd36_q16Val) + (b := gcd36_b16Val) (r := gcd36_r16Val) (by rfl) + +lemma gcd36_step_17 : + BinaryField.toPoly gcd36_a17Val = + BinaryField.toPoly gcd36_q17Val * BinaryField.toPoly gcd36_b17Val + + BinaryField.toPoly gcd36_r17Val := by + exact verify_div_step (a := gcd36_a17Val) (q := gcd36_q17Val) + (b := gcd36_b17Val) (r := gcd36_r17Val) (by rfl) + +lemma gcd36_step_18 : + BinaryField.toPoly gcd36_a18Val = + BinaryField.toPoly gcd36_q18Val * BinaryField.toPoly gcd36_b18Val + + BinaryField.toPoly gcd36_r18Val := by + exact verify_div_step (a := gcd36_a18Val) (q := gcd36_q18Val) + (b := gcd36_b18Val) (r := gcd36_r18Val) (by rfl) + +lemma gcd36_step_19 : + BinaryField.toPoly gcd36_a19Val = + BinaryField.toPoly gcd36_q19Val * BinaryField.toPoly gcd36_b19Val + + BinaryField.toPoly gcd36_r19Val := by + exact verify_div_step (a := gcd36_a19Val) (q := gcd36_q19Val) + (b := gcd36_b19Val) (r := gcd36_r19Val) (by rfl) + +lemma gcd36_step_20 : + BinaryField.toPoly gcd36_a20Val = + BinaryField.toPoly gcd36_q20Val * BinaryField.toPoly gcd36_b20Val + + BinaryField.toPoly gcd36_r20Val := by + exact verify_div_step (a := gcd36_a20Val) (q := gcd36_q20Val) + (b := gcd36_b20Val) (r := gcd36_r20Val) (by rfl) + +lemma gcd36_step_21 : + BinaryField.toPoly gcd36_a21Val = + BinaryField.toPoly gcd36_q21Val * BinaryField.toPoly gcd36_b21Val + + BinaryField.toPoly gcd36_r21Val := by + exact verify_div_step (a := gcd36_a21Val) (q := gcd36_q21Val) + (b := gcd36_b21Val) (r := gcd36_r21Val) (by rfl) + +lemma gcd36_step_22 : + BinaryField.toPoly gcd36_a22Val = + BinaryField.toPoly gcd36_q22Val * BinaryField.toPoly gcd36_b22Val + + BinaryField.toPoly gcd36_r22Val := by + exact verify_div_step (a := gcd36_a22Val) (q := gcd36_q22Val) + (b := gcd36_b22Val) (r := gcd36_r22Val) (by rfl) + +lemma gcd36_step_23 : + BinaryField.toPoly gcd36_a23Val = + BinaryField.toPoly gcd36_q23Val * BinaryField.toPoly gcd36_b23Val + + BinaryField.toPoly gcd36_r23Val := by + exact verify_div_step (a := gcd36_a23Val) (q := gcd36_q23Val) + (b := gcd36_b23Val) (r := gcd36_r23Val) (by rfl) + +lemma gcd36_step_24 : + BinaryField.toPoly gcd36_a24Val = + BinaryField.toPoly gcd36_q24Val * BinaryField.toPoly gcd36_b24Val + + BinaryField.toPoly gcd36_r24Val := by + exact verify_div_step (a := gcd36_a24Val) (q := gcd36_q24Val) + (b := gcd36_b24Val) (r := gcd36_r24Val) (by rfl) + +lemma gcd36_step_25 : + BinaryField.toPoly gcd36_a25Val = + BinaryField.toPoly gcd36_q25Val * BinaryField.toPoly gcd36_b25Val + + BinaryField.toPoly gcd36_r25Val := by + exact verify_div_step (a := gcd36_a25Val) (q := gcd36_q25Val) + (b := gcd36_b25Val) (r := gcd36_r25Val) (by rfl) + +lemma gcd36_step_26 : + BinaryField.toPoly gcd36_a26Val = + BinaryField.toPoly gcd36_q26Val * BinaryField.toPoly gcd36_b26Val + + BinaryField.toPoly gcd36_r26Val := by + exact verify_div_step (a := gcd36_a26Val) (q := gcd36_q26Val) + (b := gcd36_b26Val) (r := gcd36_r26Val) (by rfl) + +lemma gcd36_step_27 : + BinaryField.toPoly gcd36_a27Val = + BinaryField.toPoly gcd36_q27Val * BinaryField.toPoly gcd36_b27Val + + BinaryField.toPoly gcd36_r27Val := by + exact verify_div_step (a := gcd36_a27Val) (q := gcd36_q27Val) + (b := gcd36_b27Val) (r := gcd36_r27Val) (by rfl) + +lemma gcd36_step_28 : + BinaryField.toPoly gcd36_a28Val = + BinaryField.toPoly gcd36_q28Val * BinaryField.toPoly gcd36_b28Val + + BinaryField.toPoly gcd36_r28Val := by + exact verify_div_step (a := gcd36_a28Val) (q := gcd36_q28Val) + (b := gcd36_b28Val) (r := gcd36_r28Val) (by rfl) + +lemma gcd36_step_29 : + BinaryField.toPoly gcd36_a29Val = + BinaryField.toPoly gcd36_q29Val * BinaryField.toPoly gcd36_b29Val + + BinaryField.toPoly gcd36_r29Val := by + exact verify_div_step (a := gcd36_a29Val) (q := gcd36_q29Val) + (b := gcd36_b29Val) (r := gcd36_r29Val) (by rfl) + +lemma gcd36_step_30 : + BinaryField.toPoly gcd36_a30Val = + BinaryField.toPoly gcd36_q30Val * BinaryField.toPoly gcd36_b30Val + + BinaryField.toPoly gcd36_r30Val := by + exact verify_div_step (a := gcd36_a30Val) (q := gcd36_q30Val) + (b := gcd36_b30Val) (r := gcd36_r30Val) (by rfl) + +lemma gcd36_step_31 : + BinaryField.toPoly gcd36_a31Val = + BinaryField.toPoly gcd36_q31Val * BinaryField.toPoly gcd36_b31Val + + BinaryField.toPoly gcd36_r31Val := by + exact verify_div_step (a := gcd36_a31Val) (q := gcd36_q31Val) + (b := gcd36_b31Val) (r := gcd36_r31Val) (by rfl) + +lemma gcd36_step_32 : + BinaryField.toPoly gcd36_a32Val = + BinaryField.toPoly gcd36_q32Val * BinaryField.toPoly gcd36_b32Val + + BinaryField.toPoly gcd36_r32Val := by + exact verify_div_step (a := gcd36_a32Val) (q := gcd36_q32Val) + (b := gcd36_b32Val) (r := gcd36_r32Val) (by rfl) + +lemma gcd36_step_33 : + BinaryField.toPoly gcd36_a33Val = + BinaryField.toPoly gcd36_q33Val * BinaryField.toPoly gcd36_b33Val + + BinaryField.toPoly gcd36_r33Val := by + exact verify_div_step (a := gcd36_a33Val) (q := gcd36_q33Val) + (b := gcd36_b33Val) (r := gcd36_r33Val) (by rfl) + +lemma gcd36_step_34 : + BinaryField.toPoly gcd36_a34Val = + BinaryField.toPoly gcd36_q34Val * BinaryField.toPoly gcd36_b34Val + + BinaryField.toPoly gcd36_r34Val := by + exact verify_div_step (a := gcd36_a34Val) (q := gcd36_q34Val) + (b := gcd36_b34Val) (r := gcd36_r34Val) (by rfl) + +/-- Rabin gcd condition for exponent `36`. -/ +lemma rabin_gcd_condition_36 : + EuclideanDomain.gcd (X ^ (2 ^ 36) + X) definingPolynomial = 1 := by + rw [gcd36_start_reduction] + rw [definingPolynomial_eq_gcdPVal] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a1Val) + (BinaryField.toPoly gcd36_b1Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b1Val) (by decide)) + gcd36_step_1] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a2Val) + (BinaryField.toPoly gcd36_b2Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b2Val) (by decide)) + gcd36_step_2] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a3Val) + (BinaryField.toPoly gcd36_b3Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b3Val) (by decide)) + gcd36_step_3] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a4Val) + (BinaryField.toPoly gcd36_b4Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b4Val) (by decide)) + gcd36_step_4] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a5Val) + (BinaryField.toPoly gcd36_b5Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b5Val) (by decide)) + gcd36_step_5] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a6Val) + (BinaryField.toPoly gcd36_b6Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b6Val) (by decide)) + gcd36_step_6] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a7Val) + (BinaryField.toPoly gcd36_b7Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b7Val) (by decide)) + gcd36_step_7] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a8Val) + (BinaryField.toPoly gcd36_b8Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b8Val) (by decide)) + gcd36_step_8] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a9Val) + (BinaryField.toPoly gcd36_b9Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b9Val) (by decide)) + gcd36_step_9] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a10Val) + (BinaryField.toPoly gcd36_b10Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b10Val) (by decide)) + gcd36_step_10] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a11Val) + (BinaryField.toPoly gcd36_b11Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b11Val) (by decide)) + gcd36_step_11] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a12Val) + (BinaryField.toPoly gcd36_b12Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b12Val) (by decide)) + gcd36_step_12] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a13Val) + (BinaryField.toPoly gcd36_b13Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b13Val) (by decide)) + gcd36_step_13] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a14Val) + (BinaryField.toPoly gcd36_b14Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b14Val) (by decide)) + gcd36_step_14] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a15Val) + (BinaryField.toPoly gcd36_b15Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b15Val) (by decide)) + gcd36_step_15] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a16Val) + (BinaryField.toPoly gcd36_b16Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b16Val) (by decide)) + gcd36_step_16] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a17Val) + (BinaryField.toPoly gcd36_b17Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b17Val) (by decide)) + gcd36_step_17] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a18Val) + (BinaryField.toPoly gcd36_b18Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b18Val) (by decide)) + gcd36_step_18] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a19Val) + (BinaryField.toPoly gcd36_b19Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b19Val) (by decide)) + gcd36_step_19] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a20Val) + (BinaryField.toPoly gcd36_b20Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b20Val) (by decide)) + gcd36_step_20] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a21Val) + (BinaryField.toPoly gcd36_b21Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b21Val) (by decide)) + gcd36_step_21] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a22Val) + (BinaryField.toPoly gcd36_b22Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b22Val) (by decide)) + gcd36_step_22] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a23Val) + (BinaryField.toPoly gcd36_b23Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b23Val) (by decide)) + gcd36_step_23] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a24Val) + (BinaryField.toPoly gcd36_b24Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b24Val) (by decide)) + gcd36_step_24] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a25Val) + (BinaryField.toPoly gcd36_b25Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b25Val) (by decide)) + gcd36_step_25] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a26Val) + (BinaryField.toPoly gcd36_b26Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b26Val) (by decide)) + gcd36_step_26] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a27Val) + (BinaryField.toPoly gcd36_b27Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b27Val) (by decide)) + gcd36_step_27] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a28Val) + (BinaryField.toPoly gcd36_b28Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b28Val) (by decide)) + gcd36_step_28] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a29Val) + (BinaryField.toPoly gcd36_b29Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b29Val) (by decide)) + gcd36_step_29] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a30Val) + (BinaryField.toPoly gcd36_b30Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b30Val) (by decide)) + gcd36_step_30] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a31Val) + (BinaryField.toPoly gcd36_b31Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b31Val) (by decide)) + gcd36_step_31] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a32Val) + (BinaryField.toPoly gcd36_b32Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b32Val) (by decide)) + gcd36_step_32] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a33Val) + (BinaryField.toPoly gcd36_b33Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b33Val) (by decide)) + gcd36_step_33] + change EuclideanDomain.gcd (BinaryField.toPoly gcd36_a34Val) + (BinaryField.toPoly gcd36_b34Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd36_b34Val) (by decide)) + gcd36_step_34] + change EuclideanDomain.gcd + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 1 : B144)) + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 0 : B144)) = 1 + rw [BinaryField.toPoly_one_eq_one + (w := 2 * extensionDegree) (h_w_pos := by unfold extensionDegree; omega)] + rw [BinaryField.toPoly_zero_eq_zero] + exact BinaryField.gcd_one_zero + +/-- Initial Rabin gcd remainder for exponent `24`. -/ +def gcd24_b1Val : B144 := BitVec.ofNat (2 * extensionDegree) 3489030642769216307906 + +lemma gcd24_b1Val_eq_zeroExtend : + gcd24_b1Val = BitVec.zeroExtend (2 * extensionDegree) (r24Val ^^^ r0Val) := by + decide + +def gcd24_a1Val : B144 := gcdPVal +def gcd24_q1Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r1Val : B144 := BitVec.ofNat (2 * extensionDegree) 2255694802668787402203 + +def gcd24_a2Val : B144 := gcd24_b1Val +def gcd24_b2Val : B144 := gcd24_r1Val +def gcd24_q2Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r2Val : B144 := BitVec.ofNat (2 * extensionDegree) 958947153640194935983 + +def gcd24_a3Val : B144 := gcd24_b2Val +def gcd24_b3Val : B144 := gcd24_r2Val +def gcd24_q3Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r3Val : B144 := BitVec.ofNat (2 * extensionDegree) 547650258810799266949 + +def gcd24_a4Val : B144 := gcd24_b3Val +def gcd24_b4Val : B144 := gcd24_r3Val +def gcd24_q4Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r4Val : B144 := BitVec.ofNat (2 * extensionDegree) 158835636821578069413 + +def gcd24_a5Val : B144 := gcd24_b4Val +def gcd24_b5Val : B144 := gcd24_r4Val +def gcd24_q5Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r5Val : B144 := BitVec.ofNat (2 * extensionDegree) 75297387224129651306 + +def gcd24_a6Val : B144 := gcd24_b5Val +def gcd24_b6Val : B144 := gcd24_r5Val +def gcd24_q6Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r6Val : B144 := BitVec.ofNat (2 * extensionDegree) 13089034321561137521 + +def gcd24_a7Val : B144 := gcd24_b6Val +def gcd24_b7Val : B144 := gcd24_r6Val +def gcd24_q7Val : B144 := BitVec.ofNat (2 * extensionDegree) 11 +def gcd24_r7Val : B144 := BitVec.ofNat (2 * extensionDegree) 7436583959422376561 + +def gcd24_a8Val : B144 := gcd24_b7Val +def gcd24_b8Val : B144 := gcd24_r7Val +def gcd24_q8Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r8Val : B144 := BitVec.ofNat (2 * extensionDegree) 2087842304207036386 + +def gcd24_a9Val : B144 := gcd24_b8Val +def gcd24_b9Val : B144 := gcd24_r8Val +def gcd24_q9Val : B144 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd24_r9Val : B144 := BitVec.ofNat (2 * extensionDegree) 588716151435590171 + +def gcd24_a10Val : B144 := gcd24_b9Val +def gcd24_b10Val : B144 := gcd24_r9Val +def gcd24_q10Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r10Val : B144 := BitVec.ofNat (2 * extensionDegree) 325701505080725967 + +def gcd24_a11Val : B144 := gcd24_b10Val +def gcd24_b11Val : B144 := gcd24_r10Val +def gcd24_q11Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r11Val : B144 := BitVec.ofNat (2 * extensionDegree) 81546028633905541 + +def gcd24_a12Val : B144 := gcd24_b11Val +def gcd24_b12Val : B144 := gcd24_r11Val +def gcd24_q12Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r12Val : B144 := BitVec.ofNat (2 * extensionDegree) 1065917591123931 + +def gcd24_a13Val : B144 := gcd24_b12Val +def gcd24_b13Val : B144 := gcd24_r12Val +def gcd24_q13Val : B144 := BitVec.ofNat (2 * extensionDegree) 215 +def gcd24_r13Val : B144 := BitVec.ofNat (2 * extensionDegree) 203854716794996 + +def gcd24_a14Val : B144 := gcd24_b13Val +def gcd24_b14Val : B144 := gcd24_r13Val +def gcd24_q14Val : B144 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd24_r14Val : B144 := BitVec.ofNat (2 * extensionDegree) 103504542623459 + +def gcd24_a15Val : B144 := gcd24_b14Val +def gcd24_b15Val : B144 := gcd24_r14Val +def gcd24_q15Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r15Val : B144 := BitVec.ofNat (2 * extensionDegree) 5641725228466 + +def gcd24_a16Val : B144 := gcd24_b15Val +def gcd24_b16Val : B144 := gcd24_r15Val +def gcd24_q16Val : B144 := BitVec.ofNat (2 * extensionDegree) 19 +def gcd24_r16Val : B144 := BitVec.ofNat (2 * extensionDegree) 3679243789077 + +def gcd24_a17Val : B144 := gcd24_b16Val +def gcd24_b17Val : B144 := gcd24_r16Val +def gcd24_q17Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r17Val : B144 := BitVec.ofNat (2 * extensionDegree) 861091270797 + +def gcd24_a18Val : B144 := gcd24_b17Val +def gcd24_b18Val : B144 := gcd24_r17Val +def gcd24_q18Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r18Val : B144 := BitVec.ofNat (2 * extensionDegree) 521036144929 + +def gcd24_a19Val : B144 := gcd24_b18Val +def gcd24_b19Val : B144 := gcd24_r18Val +def gcd24_q19Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r19Val : B144 := BitVec.ofNat (2 * extensionDegree) 252821328591 + +def gcd24_a20Val : B144 := gcd24_b19Val +def gcd24_b20Val : B144 := gcd24_r19Val +def gcd24_q20Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r20Val : B144 := BitVec.ofNat (2 * extensionDegree) 55474521279 + +def gcd24_a21Val : B144 := gcd24_b20Val +def gcd24_b21Val : B144 := gcd24_r20Val +def gcd24_q21Val : B144 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd24_r21Val : B144 := BitVec.ofNat (2 * extensionDegree) 24124671116 + +def gcd24_a22Val : B144 := gcd24_b21Val +def gcd24_b22Val : B144 := gcd24_r21Val +def gcd24_q22Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r22Val : B144 := BitVec.ofNat (2 * extensionDegree) 9875081515 + +def gcd24_a23Val : B144 := gcd24_b22Val +def gcd24_b23Val : B144 := gcd24_r22Val +def gcd24_q23Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r23Val : B144 := BitVec.ofNat (2 * extensionDegree) 4374845146 + +def gcd24_a24Val : B144 := gcd24_b23Val +def gcd24_b24Val : B144 := gcd24_r23Val +def gcd24_q24Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r24Val : B144 := BitVec.ofNat (2 * extensionDegree) 1159488671 + +def gcd24_a25Val : B144 := gcd24_b24Val +def gcd24_b25Val : B144 := gcd24_r24Val +def gcd24_q25Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r25Val : B144 := BitVec.ofNat (2 * extensionDegree) 280183974 + +def gcd24_a26Val : B144 := gcd24_b25Val +def gcd24_b26Val : B144 := gcd24_r25Val +def gcd24_q26Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r26Val : B144 := BitVec.ofNat (2 * extensionDegree) 131167751 + +def gcd24_a27Val : B144 := gcd24_b26Val +def gcd24_b27Val : B144 := gcd24_r26Val +def gcd24_q27Val : B144 := BitVec.ofNat (2 * extensionDegree) 6 +def gcd24_r27Val : B144 := BitVec.ofNat (2 * extensionDegree) 5533876 + +def gcd24_a28Val : B144 := gcd24_b27Val +def gcd24_b28Val : B144 := gcd24_r27Val +def gcd24_q28Val : B144 := BitVec.ofNat (2 * extensionDegree) 24 +def gcd24_r28Val : B144 := BitVec.ofNat (2 * extensionDegree) 3537127 + +def gcd24_a29Val : B144 := gcd24_b28Val +def gcd24_b29Val : B144 := gcd24_r28Val +def gcd24_q29Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r29Val : B144 := BitVec.ofNat (2 * extensionDegree) 686493 + +def gcd24_a30Val : B144 := gcd24_b29Val +def gcd24_b30Val : B144 := gcd24_r29Val +def gcd24_q30Val : B144 := BitVec.ofNat (2 * extensionDegree) 7 +def gcd24_r30Val : B144 := BitVec.ofNat (2 * extensionDegree) 169012 + +def gcd24_a31Val : B144 := gcd24_b30Val +def gcd24_b31Val : B144 := gcd24_r30Val +def gcd24_q31Val : B144 := BitVec.ofNat (2 * extensionDegree) 4 +def gcd24_r31Val : B144 := BitVec.ofNat (2 * extensionDegree) 10573 + +def gcd24_a32Val : B144 := gcd24_b31Val +def gcd24_b32Val : B144 := gcd24_r31Val +def gcd24_q32Val : B144 := BitVec.ofNat (2 * extensionDegree) 16 +def gcd24_r32Val : B144 := BitVec.ofNat (2 * extensionDegree) 228 + +def gcd24_a33Val : B144 := gcd24_b32Val +def gcd24_b33Val : B144 := gcd24_r32Val +def gcd24_q33Val : B144 := BitVec.ofNat (2 * extensionDegree) 119 +def gcd24_r33Val : B144 := BitVec.ofNat (2 * extensionDegree) 49 + +def gcd24_a34Val : B144 := gcd24_b33Val +def gcd24_b34Val : B144 := gcd24_r33Val +def gcd24_q34Val : B144 := BitVec.ofNat (2 * extensionDegree) 5 +def gcd24_r34Val : B144 := BitVec.ofNat (2 * extensionDegree) 17 + +def gcd24_a35Val : B144 := gcd24_b34Val +def gcd24_b35Val : B144 := gcd24_r34Val +def gcd24_q35Val : B144 := BitVec.ofNat (2 * extensionDegree) 3 +def gcd24_r35Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 + +def gcd24_a36Val : B144 := gcd24_b35Val +def gcd24_b36Val : B144 := gcd24_r35Val +def gcd24_q36Val : B144 := BitVec.ofNat (2 * extensionDegree) 8 +def gcd24_r36Val : B144 := BitVec.ofNat (2 * extensionDegree) 1 + +def gcd24_a37Val : B144 := gcd24_b36Val +def gcd24_b37Val : B144 := gcd24_r36Val +def gcd24_q37Val : B144 := BitVec.ofNat (2 * extensionDegree) 2 +def gcd24_r37Val : B144 := BitVec.ofNat (2 * extensionDegree) 0 + +/-- Reduce the exponent `24` Rabin gcd to the generated Euclidean trace. -/ +lemma gcd24_start_reduction : + EuclideanDomain.gcd (X ^ (2 ^ 24) + X) definingPolynomial = + EuclideanDomain.gcd definingPolynomial (BinaryField.toPoly gcd24_b1Val) := by + rw [ZMod2Poly.euclidean_gcd_comm] + rw [EuclideanDomain.gcd_val] + conv_lhs => + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_24_mod_eq] + rw [r24] + rw [toPoly_mod_definingPolynomial_eq_self r24Val, X_mod_definingPolynomial] + rw [← r0_eq_X] + rw [r0] + rw [← BinaryField.toPoly_xor] + rw [toPoly_mod_definingPolynomial_eq_self (r24Val ^^^ r0Val)] + rw [← BinaryField.Extension.toPoly_zeroExtend + (show extensionDegree ≤ 2 * extensionDegree by unfold extensionDegree; norm_num) + (r24Val ^^^ r0Val)] + rw [← gcd24_b1Val_eq_zeroExtend] + rw [ZMod2Poly.euclidean_gcd_comm] + +lemma gcd24_step_1 : + BinaryField.toPoly gcd24_a1Val = + BinaryField.toPoly gcd24_q1Val * BinaryField.toPoly gcd24_b1Val + + BinaryField.toPoly gcd24_r1Val := by + exact verify_div_step (a := gcd24_a1Val) (q := gcd24_q1Val) + (b := gcd24_b1Val) (r := gcd24_r1Val) (by rfl) + +lemma gcd24_step_2 : + BinaryField.toPoly gcd24_a2Val = + BinaryField.toPoly gcd24_q2Val * BinaryField.toPoly gcd24_b2Val + + BinaryField.toPoly gcd24_r2Val := by + exact verify_div_step (a := gcd24_a2Val) (q := gcd24_q2Val) + (b := gcd24_b2Val) (r := gcd24_r2Val) (by rfl) + +lemma gcd24_step_3 : + BinaryField.toPoly gcd24_a3Val = + BinaryField.toPoly gcd24_q3Val * BinaryField.toPoly gcd24_b3Val + + BinaryField.toPoly gcd24_r3Val := by + exact verify_div_step (a := gcd24_a3Val) (q := gcd24_q3Val) + (b := gcd24_b3Val) (r := gcd24_r3Val) (by rfl) + +lemma gcd24_step_4 : + BinaryField.toPoly gcd24_a4Val = + BinaryField.toPoly gcd24_q4Val * BinaryField.toPoly gcd24_b4Val + + BinaryField.toPoly gcd24_r4Val := by + exact verify_div_step (a := gcd24_a4Val) (q := gcd24_q4Val) + (b := gcd24_b4Val) (r := gcd24_r4Val) (by rfl) + +lemma gcd24_step_5 : + BinaryField.toPoly gcd24_a5Val = + BinaryField.toPoly gcd24_q5Val * BinaryField.toPoly gcd24_b5Val + + BinaryField.toPoly gcd24_r5Val := by + exact verify_div_step (a := gcd24_a5Val) (q := gcd24_q5Val) + (b := gcd24_b5Val) (r := gcd24_r5Val) (by rfl) + +lemma gcd24_step_6 : + BinaryField.toPoly gcd24_a6Val = + BinaryField.toPoly gcd24_q6Val * BinaryField.toPoly gcd24_b6Val + + BinaryField.toPoly gcd24_r6Val := by + exact verify_div_step (a := gcd24_a6Val) (q := gcd24_q6Val) + (b := gcd24_b6Val) (r := gcd24_r6Val) (by rfl) + +lemma gcd24_step_7 : + BinaryField.toPoly gcd24_a7Val = + BinaryField.toPoly gcd24_q7Val * BinaryField.toPoly gcd24_b7Val + + BinaryField.toPoly gcd24_r7Val := by + exact verify_div_step (a := gcd24_a7Val) (q := gcd24_q7Val) + (b := gcd24_b7Val) (r := gcd24_r7Val) (by rfl) + +lemma gcd24_step_8 : + BinaryField.toPoly gcd24_a8Val = + BinaryField.toPoly gcd24_q8Val * BinaryField.toPoly gcd24_b8Val + + BinaryField.toPoly gcd24_r8Val := by + exact verify_div_step (a := gcd24_a8Val) (q := gcd24_q8Val) + (b := gcd24_b8Val) (r := gcd24_r8Val) (by rfl) + +lemma gcd24_step_9 : + BinaryField.toPoly gcd24_a9Val = + BinaryField.toPoly gcd24_q9Val * BinaryField.toPoly gcd24_b9Val + + BinaryField.toPoly gcd24_r9Val := by + exact verify_div_step (a := gcd24_a9Val) (q := gcd24_q9Val) + (b := gcd24_b9Val) (r := gcd24_r9Val) (by rfl) + +lemma gcd24_step_10 : + BinaryField.toPoly gcd24_a10Val = + BinaryField.toPoly gcd24_q10Val * BinaryField.toPoly gcd24_b10Val + + BinaryField.toPoly gcd24_r10Val := by + exact verify_div_step (a := gcd24_a10Val) (q := gcd24_q10Val) + (b := gcd24_b10Val) (r := gcd24_r10Val) (by rfl) + +lemma gcd24_step_11 : + BinaryField.toPoly gcd24_a11Val = + BinaryField.toPoly gcd24_q11Val * BinaryField.toPoly gcd24_b11Val + + BinaryField.toPoly gcd24_r11Val := by + exact verify_div_step (a := gcd24_a11Val) (q := gcd24_q11Val) + (b := gcd24_b11Val) (r := gcd24_r11Val) (by rfl) + +lemma gcd24_step_12 : + BinaryField.toPoly gcd24_a12Val = + BinaryField.toPoly gcd24_q12Val * BinaryField.toPoly gcd24_b12Val + + BinaryField.toPoly gcd24_r12Val := by + exact verify_div_step (a := gcd24_a12Val) (q := gcd24_q12Val) + (b := gcd24_b12Val) (r := gcd24_r12Val) (by rfl) + +lemma gcd24_step_13 : + BinaryField.toPoly gcd24_a13Val = + BinaryField.toPoly gcd24_q13Val * BinaryField.toPoly gcd24_b13Val + + BinaryField.toPoly gcd24_r13Val := by + exact verify_div_step (a := gcd24_a13Val) (q := gcd24_q13Val) + (b := gcd24_b13Val) (r := gcd24_r13Val) (by rfl) + +lemma gcd24_step_14 : + BinaryField.toPoly gcd24_a14Val = + BinaryField.toPoly gcd24_q14Val * BinaryField.toPoly gcd24_b14Val + + BinaryField.toPoly gcd24_r14Val := by + exact verify_div_step (a := gcd24_a14Val) (q := gcd24_q14Val) + (b := gcd24_b14Val) (r := gcd24_r14Val) (by rfl) + +lemma gcd24_step_15 : + BinaryField.toPoly gcd24_a15Val = + BinaryField.toPoly gcd24_q15Val * BinaryField.toPoly gcd24_b15Val + + BinaryField.toPoly gcd24_r15Val := by + exact verify_div_step (a := gcd24_a15Val) (q := gcd24_q15Val) + (b := gcd24_b15Val) (r := gcd24_r15Val) (by rfl) + +lemma gcd24_step_16 : + BinaryField.toPoly gcd24_a16Val = + BinaryField.toPoly gcd24_q16Val * BinaryField.toPoly gcd24_b16Val + + BinaryField.toPoly gcd24_r16Val := by + exact verify_div_step (a := gcd24_a16Val) (q := gcd24_q16Val) + (b := gcd24_b16Val) (r := gcd24_r16Val) (by rfl) + +lemma gcd24_step_17 : + BinaryField.toPoly gcd24_a17Val = + BinaryField.toPoly gcd24_q17Val * BinaryField.toPoly gcd24_b17Val + + BinaryField.toPoly gcd24_r17Val := by + exact verify_div_step (a := gcd24_a17Val) (q := gcd24_q17Val) + (b := gcd24_b17Val) (r := gcd24_r17Val) (by rfl) + +lemma gcd24_step_18 : + BinaryField.toPoly gcd24_a18Val = + BinaryField.toPoly gcd24_q18Val * BinaryField.toPoly gcd24_b18Val + + BinaryField.toPoly gcd24_r18Val := by + exact verify_div_step (a := gcd24_a18Val) (q := gcd24_q18Val) + (b := gcd24_b18Val) (r := gcd24_r18Val) (by rfl) + +lemma gcd24_step_19 : + BinaryField.toPoly gcd24_a19Val = + BinaryField.toPoly gcd24_q19Val * BinaryField.toPoly gcd24_b19Val + + BinaryField.toPoly gcd24_r19Val := by + exact verify_div_step (a := gcd24_a19Val) (q := gcd24_q19Val) + (b := gcd24_b19Val) (r := gcd24_r19Val) (by rfl) + +lemma gcd24_step_20 : + BinaryField.toPoly gcd24_a20Val = + BinaryField.toPoly gcd24_q20Val * BinaryField.toPoly gcd24_b20Val + + BinaryField.toPoly gcd24_r20Val := by + exact verify_div_step (a := gcd24_a20Val) (q := gcd24_q20Val) + (b := gcd24_b20Val) (r := gcd24_r20Val) (by rfl) + +lemma gcd24_step_21 : + BinaryField.toPoly gcd24_a21Val = + BinaryField.toPoly gcd24_q21Val * BinaryField.toPoly gcd24_b21Val + + BinaryField.toPoly gcd24_r21Val := by + exact verify_div_step (a := gcd24_a21Val) (q := gcd24_q21Val) + (b := gcd24_b21Val) (r := gcd24_r21Val) (by rfl) + +lemma gcd24_step_22 : + BinaryField.toPoly gcd24_a22Val = + BinaryField.toPoly gcd24_q22Val * BinaryField.toPoly gcd24_b22Val + + BinaryField.toPoly gcd24_r22Val := by + exact verify_div_step (a := gcd24_a22Val) (q := gcd24_q22Val) + (b := gcd24_b22Val) (r := gcd24_r22Val) (by rfl) + +lemma gcd24_step_23 : + BinaryField.toPoly gcd24_a23Val = + BinaryField.toPoly gcd24_q23Val * BinaryField.toPoly gcd24_b23Val + + BinaryField.toPoly gcd24_r23Val := by + exact verify_div_step (a := gcd24_a23Val) (q := gcd24_q23Val) + (b := gcd24_b23Val) (r := gcd24_r23Val) (by rfl) + +lemma gcd24_step_24 : + BinaryField.toPoly gcd24_a24Val = + BinaryField.toPoly gcd24_q24Val * BinaryField.toPoly gcd24_b24Val + + BinaryField.toPoly gcd24_r24Val := by + exact verify_div_step (a := gcd24_a24Val) (q := gcd24_q24Val) + (b := gcd24_b24Val) (r := gcd24_r24Val) (by rfl) + +lemma gcd24_step_25 : + BinaryField.toPoly gcd24_a25Val = + BinaryField.toPoly gcd24_q25Val * BinaryField.toPoly gcd24_b25Val + + BinaryField.toPoly gcd24_r25Val := by + exact verify_div_step (a := gcd24_a25Val) (q := gcd24_q25Val) + (b := gcd24_b25Val) (r := gcd24_r25Val) (by rfl) + +lemma gcd24_step_26 : + BinaryField.toPoly gcd24_a26Val = + BinaryField.toPoly gcd24_q26Val * BinaryField.toPoly gcd24_b26Val + + BinaryField.toPoly gcd24_r26Val := by + exact verify_div_step (a := gcd24_a26Val) (q := gcd24_q26Val) + (b := gcd24_b26Val) (r := gcd24_r26Val) (by rfl) + +lemma gcd24_step_27 : + BinaryField.toPoly gcd24_a27Val = + BinaryField.toPoly gcd24_q27Val * BinaryField.toPoly gcd24_b27Val + + BinaryField.toPoly gcd24_r27Val := by + exact verify_div_step (a := gcd24_a27Val) (q := gcd24_q27Val) + (b := gcd24_b27Val) (r := gcd24_r27Val) (by rfl) + +lemma gcd24_step_28 : + BinaryField.toPoly gcd24_a28Val = + BinaryField.toPoly gcd24_q28Val * BinaryField.toPoly gcd24_b28Val + + BinaryField.toPoly gcd24_r28Val := by + exact verify_div_step (a := gcd24_a28Val) (q := gcd24_q28Val) + (b := gcd24_b28Val) (r := gcd24_r28Val) (by rfl) + +lemma gcd24_step_29 : + BinaryField.toPoly gcd24_a29Val = + BinaryField.toPoly gcd24_q29Val * BinaryField.toPoly gcd24_b29Val + + BinaryField.toPoly gcd24_r29Val := by + exact verify_div_step (a := gcd24_a29Val) (q := gcd24_q29Val) + (b := gcd24_b29Val) (r := gcd24_r29Val) (by rfl) + +lemma gcd24_step_30 : + BinaryField.toPoly gcd24_a30Val = + BinaryField.toPoly gcd24_q30Val * BinaryField.toPoly gcd24_b30Val + + BinaryField.toPoly gcd24_r30Val := by + exact verify_div_step (a := gcd24_a30Val) (q := gcd24_q30Val) + (b := gcd24_b30Val) (r := gcd24_r30Val) (by rfl) + +lemma gcd24_step_31 : + BinaryField.toPoly gcd24_a31Val = + BinaryField.toPoly gcd24_q31Val * BinaryField.toPoly gcd24_b31Val + + BinaryField.toPoly gcd24_r31Val := by + exact verify_div_step (a := gcd24_a31Val) (q := gcd24_q31Val) + (b := gcd24_b31Val) (r := gcd24_r31Val) (by rfl) + +lemma gcd24_step_32 : + BinaryField.toPoly gcd24_a32Val = + BinaryField.toPoly gcd24_q32Val * BinaryField.toPoly gcd24_b32Val + + BinaryField.toPoly gcd24_r32Val := by + exact verify_div_step (a := gcd24_a32Val) (q := gcd24_q32Val) + (b := gcd24_b32Val) (r := gcd24_r32Val) (by rfl) + +lemma gcd24_step_33 : + BinaryField.toPoly gcd24_a33Val = + BinaryField.toPoly gcd24_q33Val * BinaryField.toPoly gcd24_b33Val + + BinaryField.toPoly gcd24_r33Val := by + exact verify_div_step (a := gcd24_a33Val) (q := gcd24_q33Val) + (b := gcd24_b33Val) (r := gcd24_r33Val) (by rfl) + +lemma gcd24_step_34 : + BinaryField.toPoly gcd24_a34Val = + BinaryField.toPoly gcd24_q34Val * BinaryField.toPoly gcd24_b34Val + + BinaryField.toPoly gcd24_r34Val := by + exact verify_div_step (a := gcd24_a34Val) (q := gcd24_q34Val) + (b := gcd24_b34Val) (r := gcd24_r34Val) (by rfl) + +lemma gcd24_step_35 : + BinaryField.toPoly gcd24_a35Val = + BinaryField.toPoly gcd24_q35Val * BinaryField.toPoly gcd24_b35Val + + BinaryField.toPoly gcd24_r35Val := by + exact verify_div_step (a := gcd24_a35Val) (q := gcd24_q35Val) + (b := gcd24_b35Val) (r := gcd24_r35Val) (by rfl) + +lemma gcd24_step_36 : + BinaryField.toPoly gcd24_a36Val = + BinaryField.toPoly gcd24_q36Val * BinaryField.toPoly gcd24_b36Val + + BinaryField.toPoly gcd24_r36Val := by + exact verify_div_step (a := gcd24_a36Val) (q := gcd24_q36Val) + (b := gcd24_b36Val) (r := gcd24_r36Val) (by rfl) + +lemma gcd24_step_37 : + BinaryField.toPoly gcd24_a37Val = + BinaryField.toPoly gcd24_q37Val * BinaryField.toPoly gcd24_b37Val + + BinaryField.toPoly gcd24_r37Val := by + exact verify_div_step (a := gcd24_a37Val) (q := gcd24_q37Val) + (b := gcd24_b37Val) (r := gcd24_r37Val) (by rfl) + +/-- Rabin gcd condition for exponent `24`. -/ +lemma rabin_gcd_condition_24 : + EuclideanDomain.gcd (X ^ (2 ^ 24) + X) definingPolynomial = 1 := by + rw [gcd24_start_reduction] + rw [definingPolynomial_eq_gcdPVal] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a1Val) + (BinaryField.toPoly gcd24_b1Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b1Val) (by decide)) + gcd24_step_1] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a2Val) + (BinaryField.toPoly gcd24_b2Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b2Val) (by decide)) + gcd24_step_2] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a3Val) + (BinaryField.toPoly gcd24_b3Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b3Val) (by decide)) + gcd24_step_3] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a4Val) + (BinaryField.toPoly gcd24_b4Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b4Val) (by decide)) + gcd24_step_4] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a5Val) + (BinaryField.toPoly gcd24_b5Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b5Val) (by decide)) + gcd24_step_5] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a6Val) + (BinaryField.toPoly gcd24_b6Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b6Val) (by decide)) + gcd24_step_6] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a7Val) + (BinaryField.toPoly gcd24_b7Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b7Val) (by decide)) + gcd24_step_7] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a8Val) + (BinaryField.toPoly gcd24_b8Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b8Val) (by decide)) + gcd24_step_8] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a9Val) + (BinaryField.toPoly gcd24_b9Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b9Val) (by decide)) + gcd24_step_9] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a10Val) + (BinaryField.toPoly gcd24_b10Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b10Val) (by decide)) + gcd24_step_10] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a11Val) + (BinaryField.toPoly gcd24_b11Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b11Val) (by decide)) + gcd24_step_11] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a12Val) + (BinaryField.toPoly gcd24_b12Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b12Val) (by decide)) + gcd24_step_12] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a13Val) + (BinaryField.toPoly gcd24_b13Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b13Val) (by decide)) + gcd24_step_13] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a14Val) + (BinaryField.toPoly gcd24_b14Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b14Val) (by decide)) + gcd24_step_14] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a15Val) + (BinaryField.toPoly gcd24_b15Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b15Val) (by decide)) + gcd24_step_15] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a16Val) + (BinaryField.toPoly gcd24_b16Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b16Val) (by decide)) + gcd24_step_16] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a17Val) + (BinaryField.toPoly gcd24_b17Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b17Val) (by decide)) + gcd24_step_17] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a18Val) + (BinaryField.toPoly gcd24_b18Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b18Val) (by decide)) + gcd24_step_18] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a19Val) + (BinaryField.toPoly gcd24_b19Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b19Val) (by decide)) + gcd24_step_19] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a20Val) + (BinaryField.toPoly gcd24_b20Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b20Val) (by decide)) + gcd24_step_20] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a21Val) + (BinaryField.toPoly gcd24_b21Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b21Val) (by decide)) + gcd24_step_21] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a22Val) + (BinaryField.toPoly gcd24_b22Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b22Val) (by decide)) + gcd24_step_22] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a23Val) + (BinaryField.toPoly gcd24_b23Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b23Val) (by decide)) + gcd24_step_23] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a24Val) + (BinaryField.toPoly gcd24_b24Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b24Val) (by decide)) + gcd24_step_24] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a25Val) + (BinaryField.toPoly gcd24_b25Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b25Val) (by decide)) + gcd24_step_25] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a26Val) + (BinaryField.toPoly gcd24_b26Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b26Val) (by decide)) + gcd24_step_26] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a27Val) + (BinaryField.toPoly gcd24_b27Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b27Val) (by decide)) + gcd24_step_27] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a28Val) + (BinaryField.toPoly gcd24_b28Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b28Val) (by decide)) + gcd24_step_28] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a29Val) + (BinaryField.toPoly gcd24_b29Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b29Val) (by decide)) + gcd24_step_29] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a30Val) + (BinaryField.toPoly gcd24_b30Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b30Val) (by decide)) + gcd24_step_30] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a31Val) + (BinaryField.toPoly gcd24_b31Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b31Val) (by decide)) + gcd24_step_31] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a32Val) + (BinaryField.toPoly gcd24_b32Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b32Val) (by decide)) + gcd24_step_32] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a33Val) + (BinaryField.toPoly gcd24_b33Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b33Val) (by decide)) + gcd24_step_33] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a34Val) + (BinaryField.toPoly gcd24_b34Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b34Val) (by decide)) + gcd24_step_34] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a35Val) + (BinaryField.toPoly gcd24_b35Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b35Val) (by decide)) + gcd24_step_35] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a36Val) + (BinaryField.toPoly gcd24_b36Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b36Val) (by decide)) + gcd24_step_36] + change EuclideanDomain.gcd (BinaryField.toPoly gcd24_a37Val) + (BinaryField.toPoly gcd24_b37Val) = 1 + rw [BinaryField.gcd_eq_gcd_next_step + (hb := by exact toPoly_ne_zero (v := gcd24_b37Val) (by decide)) + gcd24_step_37] + change EuclideanDomain.gcd + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 1 : B144)) + (BinaryField.toPoly (BitVec.ofNat (2 * extensionDegree) 0 : B144)) = 1 + rw [BinaryField.toPoly_one_eq_one + (w := 2 * extensionDegree) (h_w_pos := by unfold extensionDegree; omega)] + rw [BinaryField.toPoly_zero_eq_zero] + exact BinaryField.gcd_one_zero + +end GF2_72 diff --git a/CompPoly/Fields/Binary/GF2_72/XPowTwoPowModCertificate.lean b/CompPoly/Fields/Binary/GF2_72/XPowTwoPowModCertificate.lean new file mode 100644 index 00000000..679ef246 --- /dev/null +++ b/CompPoly/Fields/Binary/GF2_72/XPowTwoPowModCertificate.lean @@ -0,0 +1,1455 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_72.Prelude +import Mathlib.Tactic.NormNum + +/-! +# GF(2^72) Modular Frobenius Certificate + +Kernel-safe certificate data for repeated squaring of `X` modulo +`X^72 + X^6 + X^4 + X^3 + X^2 + X + 1`. +-/ + +namespace GF2_72 + +open Polynomial + +set_option maxRecDepth 1800 + +/-- Certificate exponents fit in the doubled-width checker. -/ +lemma certificateExponents_bound : + ∀ exponent ∈ definingPolynomialExponents, + extensionDegree + exponent ≤ 2 * extensionDegree := by + unfold definingPolynomialExponents extensionDegree + decide + +/-- Soundness wrapper specialized to the GF72 defining polynomial. -/ +private theorem verify_square_step {rPrev q rNext : B72} + (h : + BinaryField.Extension.checkSquareStep extensionDegree definingPolynomialExponents + rPrev q rNext = true) : + (BinaryField.toPoly rPrev) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q) * + definingPolynomial + BinaryField.toPoly rNext := by + rw [← sparsePolynomial_definingPolynomialExponents] + exact BinaryField.Extension.checkSquareStep_correct certificateExponents_bound + rPrev q rNext h + +def r0Val : B72 := BitVec.ofNat extensionDegree 2 +noncomputable def r0 : Polynomial (ZMod 2) := BinaryField.toPoly r0Val +def q1Val : B72 := BitVec.ofNat extensionDegree 0 +def r1Val : B72 := BitVec.ofNat extensionDegree 4 +noncomputable def r1 : Polynomial (ZMod 2) := BinaryField.toPoly r1Val +def q2Val : B72 := BitVec.ofNat extensionDegree 0 +def r2Val : B72 := BitVec.ofNat extensionDegree 16 +noncomputable def r2 : Polynomial (ZMod 2) := BinaryField.toPoly r2Val +def q3Val : B72 := BitVec.ofNat extensionDegree 0 +def r3Val : B72 := BitVec.ofNat extensionDegree 256 +noncomputable def r3 : Polynomial (ZMod 2) := BinaryField.toPoly r3Val +def q4Val : B72 := BitVec.ofNat extensionDegree 0 +def r4Val : B72 := BitVec.ofNat extensionDegree 65536 +noncomputable def r4 : Polynomial (ZMod 2) := BinaryField.toPoly r4Val +def q5Val : B72 := BitVec.ofNat extensionDegree 0 +def r5Val : B72 := BitVec.ofNat extensionDegree 4294967296 +noncomputable def r5 : Polynomial (ZMod 2) := BinaryField.toPoly r5Val +def q6Val : B72 := BitVec.ofNat extensionDegree 0 +def r6Val : B72 := BitVec.ofNat extensionDegree 18446744073709551616 +noncomputable def r6 : Polynomial (ZMod 2) := BinaryField.toPoly r6Val +def q7Val : B72 := BitVec.ofNat extensionDegree 72057594037927936 +def r7Val : B72 := BitVec.ofNat extensionDegree 6845471433603153920 +noncomputable def r7 : Polynomial (ZMod 2) := BinaryField.toPoly r7Val +def q8Val : B72 := BitVec.ofNat extensionDegree 4878533092442112 +def r8Val : B72 := BitVec.ofNat extensionDegree 413226156532170752 +noncomputable def r8 : Polynomial (ZMod 2) := BinaryField.toPoly r8Val +def q9Val : B72 := BitVec.ofNat extensionDegree 18989392659712 +def r9Val : B72 := BitVec.ofNat extensionDegree 1611820433285888 +noncomputable def r9 : Polynomial (ZMod 2) := BinaryField.toPoly r9Val +def q10Val : B72 := BitVec.ofNat extensionDegree 289751381 +def r10Val : B72 := BitVec.ofNat extensionDegree 18807051086675938323 +noncomputable def r10 : Polynomial (ZMod 2) := BinaryField.toPoly r10Val +def q11Val : B72 := BitVec.ofNat extensionDegree 72076285735665937 +def r11Val : B72 := BitVec.ofNat extensionDegree 20344160300016032682 +noncomputable def r11 : Polynomial (ZMod 2) := BinaryField.toPoly r11Val +def q12Val : B72 := BitVec.ofNat extensionDegree 72413909093794816 +def r12Val : B72 := BitVec.ofNat extensionDegree 24160046184937879620 +noncomputable def r12 : Polynomial (ZMod 2) := BinaryField.toPoly r12Val +def q13Val : B72 := BitVec.ofNat extensionDegree 76654721968193877 +def r13Val : B72 := BitVec.ofNat extensionDegree 1569119138488411003907 +noncomputable def r13 : Polynomial (ZMod 2) := BinaryField.toPoly r13Val +def q14Val : B72 := BitVec.ofNat extensionDegree 314819722171325092945 +def r14Val : B72 := BitVec.ofNat extensionDegree 3541649682034312126058 +noncomputable def r14 : Polynomial (ZMod 2) := BinaryField.toPoly r14Val +def q15Val : B72 := BitVec.ofNat extensionDegree 1278974254379984490759 +def r15Val : B72 := BitVec.ofNat extensionDegree 3251311924210382781145 +noncomputable def r15 : Polynomial (ZMod 2) := BinaryField.toPoly r15Val +def q16Val : B72 := BitVec.ofNat extensionDegree 1272829845785367625794 +def r16Val : B72 := BitVec.ofNat extensionDegree 4170253627233633338943 +noncomputable def r16 : Polynomial (ZMod 2) := BinaryField.toPoly r16Val +def q17Val : B72 := BitVec.ofNat extensionDegree 1549815015503304934675 +def r17Val : B72 := BitVec.ofNat extensionDegree 1719681249437118489412 +noncomputable def r17 : Polynomial (ZMod 2) := BinaryField.toPoly r17Val +def q18Val : B72 := BitVec.ofNat extensionDegree 319432793287714488580 +def r18Val : B72 := BitVec.ofNat extensionDegree 4652786303952967536236 +noncomputable def r18 : Polynomial (ZMod 2) := BinaryField.toPoly r18Val +def q19Val : B72 := BitVec.ofNat extensionDegree 1573739336015940699463 +def r19Val : B72 := BitVec.ofNat extensionDegree 1478126619366554525965 +noncomputable def r19 : Polynomial (ZMod 2) := BinaryField.toPoly r19Val +def q20Val : B72 := BitVec.ofNat extensionDegree 313595776269665189972 +def r20Val : B72 := BitVec.ofNat extensionDegree 4685561974316730077981 +noncomputable def r20 : Polynomial (ZMod 2) := BinaryField.toPoly r20Val +def q21Val : B72 := BitVec.ofNat extensionDegree 1574026085286826562566 +def r21Val : B72 := BitVec.ofNat extensionDegree 1187222074360253205651 +noncomputable def r21 : Polynomial (ZMod 2) := BinaryField.toPoly r21Val +def q22Val : B72 := BitVec.ofNat extensionDegree 295152778215155647504 +def r22Val : B72 := BitVec.ofNat extensionDegree 4151795348459105155317 +noncomputable def r22 : Polynomial (ZMod 2) := BinaryField.toPoly r22Val +def q23Val : B72 := BitVec.ofNat extensionDegree 1549598842657823784963 +def r23Val : B72 := BitVec.ofNat extensionDegree 1697919908360916588016 +noncomputable def r23 : Polynomial (ZMod 2) := BinaryField.toPoly r23Val +def q24Val : B72 := BitVec.ofNat extensionDegree 319359332716840501312 +def r24Val : B72 := BitVec.ofNat extensionDegree 3489030642769216307904 +noncomputable def r24 : Polynomial (ZMod 2) := BinaryField.toPoly r24Val +def q25Val : B72 := BitVec.ofNat extensionDegree 1278663149695465162050 +def r25Val : B72 := BitVec.ofNat extensionDegree 2977882712000778822782 +noncomputable def r25 : Polynomial (ZMod 2) := BinaryField.toPoly r25Val +def q26Val : B72 := BitVec.ofNat extensionDegree 1254456376552044368151 +def r26Val : B72 := BitVec.ofNat extensionDegree 3468765417458721472057 +noncomputable def r26 : Polynomial (ZMod 2) := BinaryField.toPoly r26Val +def q27Val : B72 := BitVec.ofNat extensionDegree 1278590023720523350087 +def r27Val : B72 := BitVec.ofNat extensionDegree 3029090404854303347484 +noncomputable def r27 : Polynomial (ZMod 2) := BinaryField.toPoly r27Val +def q28Val : B72 := BitVec.ofNat extensionDegree 1255532944587805180930 +def r28Val : B72 := BitVec.ofNat extensionDegree 3184690916186109492718 +noncomputable def r28 : Polynomial (ZMod 2) := BinaryField.toPoly r28Val +def q29Val : B72 := BitVec.ofNat extensionDegree 1260162362516421559574 +def r29Val : B72 := BitVec.ofNat extensionDegree 4614274996138367300454 +noncomputable def r29 : Polynomial (ZMod 2) := BinaryField.toPoly r29Val +def q30Val : B72 := BitVec.ofNat extensionDegree 1572874294419497685331 +def r30Val : B72 := BitVec.ofNat extensionDegree 35468416960185543109 +noncomputable def r30 : Polynomial (ZMod 2) := BinaryField.toPoly r30Val +def q31Val : B72 := BitVec.ofNat extensionDegree 95789475577463056 +def r31Val : B72 := BitVec.ofNat extensionDegree 1554795468997690985185 +noncomputable def r31 : Polynomial (ZMod 2) := BinaryField.toPoly r31Val +def q32Val : B72 := BitVec.ofNat extensionDegree 314752145831273693457 +def r32Val : B72 := BitVec.ofNat extensionDegree 3442957893003051011758 +noncomputable def r32 : Polynomial (ZMod 2) := BinaryField.toPoly r32Val +def q33Val : B72 := BitVec.ofNat extensionDegree 1277744415663286469655 +def r33Val : B72 := BitVec.ofNat extensionDegree 3037641326116103650361 +noncomputable def r33 : Polynomial (ZMod 2) := BinaryField.toPoly r33Val +def q34Val : B72 := BitVec.ofNat extensionDegree 1255550734979292202307 +def r34Val : B72 := BitVec.ofNat extensionDegree 4296054234300685300064 +noncomputable def r34 : Polynomial (ZMod 2) := BinaryField.toPoly r34Val +def q35Val : B72 := BitVec.ofNat extensionDegree 1554161837903129612375 +def r35Val : B72 := BitVec.ofNat extensionDegree 1694149529007371646893 +noncomputable def r35 : Polynomial (ZMod 2) := BinaryField.toPoly r35Val +def q36Val : B72 := BitVec.ofNat extensionDegree 318589445805879660609 +def r36Val : B72 := BitVec.ofNat extensionDegree 3130559789706947830734 +noncomputable def r36 : Polynomial (ZMod 2) := BinaryField.toPoly r36Val +def q37Val : B72 := BitVec.ofNat extensionDegree 1259081781112693920775 +def r37Val : B72 := BitVec.ofNat extensionDegree 3239562686252049161673 +noncomputable def r37 : Polynomial (ZMod 2) := BinaryField.toPoly r37Val +def q38Val : B72 := BitVec.ofNat extensionDegree 1260521877804813665555 +def r38Val : B72 := BitVec.ofNat extensionDegree 3505302527931368322640 +noncomputable def r38 : Polynomial (ZMod 2) := BinaryField.toPoly r38Val +def q39Val : B72 := BitVec.ofNat extensionDegree 1278878198025809121542 +def r39Val : B72 := BitVec.ofNat extensionDegree 4521488180441319309250 +noncomputable def r39 : Polynomial (ZMod 2) := BinaryField.toPoly r39Val +def q40Val : B72 := BitVec.ofNat extensionDegree 1569198594868588593174 +def r40Val : B72 := BitVec.ofNat extensionDegree 1326966826223816053814 +noncomputable def r40 : Polynomial (ZMod 2) := BinaryField.toPoly r40Val +def q41Val : B72 := BitVec.ofNat extensionDegree 296684852085055095121 +def r41Val : B72 := BitVec.ofNat extensionDegree 4533308491928150689915 +noncomputable def r41 : Polynomial (ZMod 2) := BinaryField.toPoly r41Val +def q42Val : B72 := BitVec.ofNat extensionDegree 1569220743431970690119 +def r42Val : B72 := BitVec.ofNat extensionDegree 1618225819261431680792 +noncomputable def r42 : Polynomial (ZMod 2) := BinaryField.toPoly r42Val +def q43Val : B72 := BitVec.ofNat extensionDegree 315127352055692263505 +def r43Val : B72 := BitVec.ofNat extensionDegree 3220177768041290208047 +noncomputable def r43 : Polynomial (ZMod 2) := BinaryField.toPoly r43Val +def q44Val : B72 := BitVec.ofNat extensionDegree 1260449731150014923846 +def r44Val : B72 := BitVec.ofNat extensionDegree 4705057462860647280215 +noncomputable def r44 : Polynomial (ZMod 2) := BinaryField.toPoly r44Val +def q45Val : B72 := BitVec.ofNat extensionDegree 1574098235561762358291 +def r45Val : B72 := BitVec.ofNat extensionDegree 74026302004270557188 +noncomputable def r45 : Polynomial (ZMod 2) := BinaryField.toPoly r45Val +def q46Val : B72 := BitVec.ofNat extensionDegree 1152927075247587605 +def r46Val : B72 := BitVec.ofNat extensionDegree 325502509438125235139 +noncomputable def r46 : Polynomial (ZMod 2) := BinaryField.toPoly r46Val +def q47Val : B72 := BitVec.ofNat extensionDegree 18537960726598063429 +def r47Val : B72 := BitVec.ofNat extensionDegree 191234362992622736870 +noncomputable def r47 : Polynomial (ZMod 2) := BinaryField.toPoly r47Val +def q48Val : B72 := BitVec.ofNat extensionDegree 4904790891481552213 +def r48Val : B72 := BitVec.ofNat extensionDegree 418071519968302617607 +noncomputable def r48 : Polynomial (ZMod 2) := BinaryField.toPoly r48Val +def q49Val : B72 := BitVec.ofNat extensionDegree 19907108082992562193 +def r49Val : B72 := BitVec.ofNat extensionDegree 274084459838985455034 +noncomputable def r49 : Polynomial (ZMod 2) := BinaryField.toPoly r49Val +def q50Val : B72 := BitVec.ofNat extensionDegree 6075713532089946112 +def r50Val : B72 := BitVec.ofNat extensionDegree 1292382422485861954884 +noncomputable def r50 : Polynomial (ZMod 2) := BinaryField.toPoly r50Val +def q51Val : B72 := BitVec.ofNat extensionDegree 296589150605577359697 +def r51Val : B72 := BitVec.ofNat extensionDegree 3257940939094932041087 +noncomputable def r51 : Polynomial (ZMod 2) := BinaryField.toPoly r51Val +def q52Val : B72 := BitVec.ofNat extensionDegree 1272843726019972109382 +def r52Val : B72 := BitVec.ofNat extensionDegree 3067313949868545445719 +noncomputable def r52 : Polynomial (ZMod 2) := BinaryField.toPoly r52Val +def q53Val : B72 := BitVec.ofNat extensionDegree 1255824275858331616279 +def r53Val : B72 := BitVec.ofNat extensionDegree 3110433760704286730616 +noncomputable def r53 : Polynomial (ZMod 2) := BinaryField.toPoly r53Val +def q54Val : B72 := BitVec.ofNat extensionDegree 1259008668329681420631 +def r54Val : B72 := BitVec.ofNat extensionDegree 3220653686454149339629 +noncomputable def r54 : Polynomial (ZMod 2) := BinaryField.toPoly r54Val +def q55Val : B72 := BitVec.ofNat extensionDegree 1260449754150887243799 +def r55Val : B72 := BitVec.ofNat extensionDegree 3141323391939143962684 +noncomputable def r55 : Polynomial (ZMod 2) := BinaryField.toPoly r55Val +def q56Val : B72 := BitVec.ofNat extensionDegree 1259283092053833093462 +def r56Val : B72 := BitVec.ofNat extensionDegree 3518570059334577469858 +noncomputable def r56 : Polynomial (ZMod 2) := BinaryField.toPoly r56Val +def q57Val : B72 := BitVec.ofNat extensionDegree 1278897690184410022982 +def r57Val : B72 := BitVec.ofNat extensionDegree 3253235212430044622342 +noncomputable def r57 : Polynomial (ZMod 2) := BinaryField.toPoly r57Val +def q58Val : B72 := BitVec.ofNat extensionDegree 1272830202323503763719 +def r58Val : B72 := BitVec.ofNat extensionDegree 4247770651586826956425 +noncomputable def r58 : Polynomial (ZMod 2) := BinaryField.toPoly r58Val +def q59Val : B72 := BitVec.ofNat extensionDegree 1550972176656822964550 +def r59Val : B72 := BitVec.ofNat extensionDegree 1713003137558216833347 +noncomputable def r59 : Polynomial (ZMod 2) := BinaryField.toPoly r59Val +def q60Val : B72 := BitVec.ofNat extensionDegree 319382144506514395456 +def r60Val : B72 := BitVec.ofNat extensionDegree 4601483157117523159237 +noncomputable def r60 : Polynomial (ZMod 2) := BinaryField.toPoly r60Val +def q61Val : B72 := BitVec.ofNat extensionDegree 1572662905337307993430 +def r61Val : B72 := BitVec.ofNat extensionDegree 11133510495665426659 +noncomputable def r61 : Polynomial (ZMod 2) := BinaryField.toPoly r61Val +def q62Val : B72 := BitVec.ofNat extensionDegree 18370915222179920 +def r62Val : B72 := BitVec.ofNat extensionDegree 1554613509840805197365 +noncomputable def r62 : Polynomial (ZMod 2) := BinaryField.toPoly r62Val +def q63Val : B72 := BitVec.ofNat extensionDegree 314752096627780244549 +def r63Val : B72 := BitVec.ofNat extensionDegree 3171733379247955992562 +noncomputable def r63 : Polynomial (ZMod 2) := BinaryField.toPoly r63Val +def q64Val : B72 := BitVec.ofNat extensionDegree 1259374496666217370951 +def r64Val : B72 := BitVec.ofNat extensionDegree 4623221518268876869721 +noncomputable def r64 : Polynomial (ZMod 2) := BinaryField.toPoly r64Val +def q65Val : B72 := BitVec.ofNat extensionDegree 1572892302962938938694 +def r65Val : B72 := BitVec.ofNat extensionDegree 1586395291251679044675 +noncomputable def r65 : Polynomial (ZMod 2) := BinaryField.toPoly r65Val +def q66Val : B72 := BitVec.ofNat extensionDegree 314843647476348485653 +def r66Val : B72 := BitVec.ofNat extensionDegree 4722168397052766065878 +noncomputable def r66 : Polynomial (ZMod 2) := BinaryField.toPoly r66Val +def q67Val : B72 := BitVec.ofNat extensionDegree 1574122156260718543174 +def r67Val : B72 := BitVec.ofNat extensionDegree 1573737922988940990486 +noncomputable def r67 : Polynomial (ZMod 2) := BinaryField.toPoly r67Val +def q68Val : B72 := BitVec.ofNat extensionDegree 314824413426311582800 +def r68Val : B72 := BitVec.ofNat extensionDegree 3148250137596607356708 +noncomputable def r68 : Polynomial (ZMod 2) := BinaryField.toPoly r68Val +def q69Val : B72 := BitVec.ofNat extensionDegree 1259297728769815547926 +def r69Val : B72 := BitVec.ofNat extensionDegree 3148244345300759605282 +noncomputable def r69 : Polynomial (ZMod 2) := BinaryField.toPoly r69Val +def q70Val : B72 := BitVec.ofNat extensionDegree 1259297728765238793539 +def r70Val : B72 := BitVec.ofNat extensionDegree 3148250326712598921253 +noncomputable def r70 : Polynomial (ZMod 2) := BinaryField.toPoly r70Val +def q71Val : B72 := BitVec.ofNat extensionDegree 1259297728769820022083 +def r71Val : B72 := BitVec.ofNat extensionDegree 4722366482800925737008 +noncomputable def r71 : Polynomial (ZMod 2) := BinaryField.toPoly r71Val +def q72Val : B72 := BitVec.ofNat extensionDegree 1574122160956548404550 +def r72Val : B72 := BitVec.ofNat extensionDegree 2 +noncomputable def r72 : Polynomial (ZMod 2) := BinaryField.toPoly r72Val +/-- The initial remainder denotes `X`. -/ +lemma r0_eq_X : r0 = X := by + rw [r0, r0Val, extensionDegree] + have h : (BitVec.ofNat 72 2 : BitVec 72) = (1 <<< 1 : BitVec 72) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 72) 1 (by decide) + +/-- The final remainder denotes `X`. -/ +lemma r72_eq_X : r72 = X := by + rw [r72, r72Val, extensionDegree] + have h : (BitVec.ofNat 72 2 : BitVec 72) = (1 <<< 1 : BitVec 72) := by + decide + rw [h] + simpa only [pow_one] using + BinaryField.Extension.toPoly_one_shiftLeft (w := 72) 1 (by decide) + +lemma step_1 : + r0 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + r1 := by + change (BinaryField.toPoly r0Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q1Val) * + definingPolynomial + BinaryField.toPoly r1Val + exact verify_square_step (rPrev := r0Val) (q := q1Val) + (rNext := r1Val) (by rfl) + +lemma step_2 : + r1 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + r2 := by + change (BinaryField.toPoly r1Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q2Val) * + definingPolynomial + BinaryField.toPoly r2Val + exact verify_square_step (rPrev := r1Val) (q := q2Val) + (rNext := r2Val) (by rfl) + +lemma step_3 : + r2 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + r3 := by + change (BinaryField.toPoly r2Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q3Val) * + definingPolynomial + BinaryField.toPoly r3Val + exact verify_square_step (rPrev := r2Val) (q := q3Val) + (rNext := r3Val) (by rfl) + +lemma step_4 : + r3 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + r4 := by + change (BinaryField.toPoly r3Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q4Val) * + definingPolynomial + BinaryField.toPoly r4Val + exact verify_square_step (rPrev := r3Val) (q := q4Val) + (rNext := r4Val) (by rfl) + +lemma step_5 : + r4 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + r5 := by + change (BinaryField.toPoly r4Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q5Val) * + definingPolynomial + BinaryField.toPoly r5Val + exact verify_square_step (rPrev := r4Val) (q := q5Val) + (rNext := r5Val) (by rfl) + +lemma step_6 : + r5 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + r6 := by + change (BinaryField.toPoly r5Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q6Val) * + definingPolynomial + BinaryField.toPoly r6Val + exact verify_square_step (rPrev := r5Val) (q := q6Val) + (rNext := r6Val) (by rfl) + +lemma step_7 : + r6 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + r7 := by + change (BinaryField.toPoly r6Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q7Val) * + definingPolynomial + BinaryField.toPoly r7Val + exact verify_square_step (rPrev := r6Val) (q := q7Val) + (rNext := r7Val) (by rfl) + +lemma step_8 : + r7 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + r8 := by + change (BinaryField.toPoly r7Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q8Val) * + definingPolynomial + BinaryField.toPoly r8Val + exact verify_square_step (rPrev := r7Val) (q := q8Val) + (rNext := r8Val) (by rfl) + +lemma step_9 : + r8 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + r9 := by + change (BinaryField.toPoly r8Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q9Val) * + definingPolynomial + BinaryField.toPoly r9Val + exact verify_square_step (rPrev := r8Val) (q := q9Val) + (rNext := r9Val) (by rfl) + +lemma step_10 : + r9 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + r10 := by + change (BinaryField.toPoly r9Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q10Val) * + definingPolynomial + BinaryField.toPoly r10Val + exact verify_square_step (rPrev := r9Val) (q := q10Val) + (rNext := r10Val) (by rfl) + +lemma step_11 : + r10 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + r11 := by + change (BinaryField.toPoly r10Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q11Val) * + definingPolynomial + BinaryField.toPoly r11Val + exact verify_square_step (rPrev := r10Val) (q := q11Val) + (rNext := r11Val) (by rfl) + +lemma step_12 : + r11 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + r12 := by + change (BinaryField.toPoly r11Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q12Val) * + definingPolynomial + BinaryField.toPoly r12Val + exact verify_square_step (rPrev := r11Val) (q := q12Val) + (rNext := r12Val) (by rfl) + +lemma step_13 : + r12 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + r13 := by + change (BinaryField.toPoly r12Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q13Val) * + definingPolynomial + BinaryField.toPoly r13Val + exact verify_square_step (rPrev := r12Val) (q := q13Val) + (rNext := r13Val) (by rfl) + +lemma step_14 : + r13 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + r14 := by + change (BinaryField.toPoly r13Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q14Val) * + definingPolynomial + BinaryField.toPoly r14Val + exact verify_square_step (rPrev := r13Val) (q := q14Val) + (rNext := r14Val) (by rfl) + +lemma step_15 : + r14 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + r15 := by + change (BinaryField.toPoly r14Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q15Val) * + definingPolynomial + BinaryField.toPoly r15Val + exact verify_square_step (rPrev := r14Val) (q := q15Val) + (rNext := r15Val) (by rfl) + +lemma step_16 : + r15 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + r16 := by + change (BinaryField.toPoly r15Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q16Val) * + definingPolynomial + BinaryField.toPoly r16Val + exact verify_square_step (rPrev := r15Val) (q := q16Val) + (rNext := r16Val) (by rfl) + +lemma step_17 : + r16 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + r17 := by + change (BinaryField.toPoly r16Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q17Val) * + definingPolynomial + BinaryField.toPoly r17Val + exact verify_square_step (rPrev := r16Val) (q := q17Val) + (rNext := r17Val) (by rfl) + +lemma step_18 : + r17 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + r18 := by + change (BinaryField.toPoly r17Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q18Val) * + definingPolynomial + BinaryField.toPoly r18Val + exact verify_square_step (rPrev := r17Val) (q := q18Val) + (rNext := r18Val) (by rfl) + +lemma step_19 : + r18 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + r19 := by + change (BinaryField.toPoly r18Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q19Val) * + definingPolynomial + BinaryField.toPoly r19Val + exact verify_square_step (rPrev := r18Val) (q := q19Val) + (rNext := r19Val) (by rfl) + +lemma step_20 : + r19 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + r20 := by + change (BinaryField.toPoly r19Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q20Val) * + definingPolynomial + BinaryField.toPoly r20Val + exact verify_square_step (rPrev := r19Val) (q := q20Val) + (rNext := r20Val) (by rfl) + +lemma step_21 : + r20 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + r21 := by + change (BinaryField.toPoly r20Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q21Val) * + definingPolynomial + BinaryField.toPoly r21Val + exact verify_square_step (rPrev := r20Val) (q := q21Val) + (rNext := r21Val) (by rfl) + +lemma step_22 : + r21 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + r22 := by + change (BinaryField.toPoly r21Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q22Val) * + definingPolynomial + BinaryField.toPoly r22Val + exact verify_square_step (rPrev := r21Val) (q := q22Val) + (rNext := r22Val) (by rfl) + +lemma step_23 : + r22 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + r23 := by + change (BinaryField.toPoly r22Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q23Val) * + definingPolynomial + BinaryField.toPoly r23Val + exact verify_square_step (rPrev := r22Val) (q := q23Val) + (rNext := r23Val) (by rfl) + +lemma step_24 : + r23 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + r24 := by + change (BinaryField.toPoly r23Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q24Val) * + definingPolynomial + BinaryField.toPoly r24Val + exact verify_square_step (rPrev := r23Val) (q := q24Val) + (rNext := r24Val) (by rfl) + +lemma step_25 : + r24 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + r25 := by + change (BinaryField.toPoly r24Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q25Val) * + definingPolynomial + BinaryField.toPoly r25Val + exact verify_square_step (rPrev := r24Val) (q := q25Val) + (rNext := r25Val) (by rfl) + +lemma step_26 : + r25 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + r26 := by + change (BinaryField.toPoly r25Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q26Val) * + definingPolynomial + BinaryField.toPoly r26Val + exact verify_square_step (rPrev := r25Val) (q := q26Val) + (rNext := r26Val) (by rfl) + +lemma step_27 : + r26 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + r27 := by + change (BinaryField.toPoly r26Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q27Val) * + definingPolynomial + BinaryField.toPoly r27Val + exact verify_square_step (rPrev := r26Val) (q := q27Val) + (rNext := r27Val) (by rfl) + +lemma step_28 : + r27 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + r28 := by + change (BinaryField.toPoly r27Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q28Val) * + definingPolynomial + BinaryField.toPoly r28Val + exact verify_square_step (rPrev := r27Val) (q := q28Val) + (rNext := r28Val) (by rfl) + +lemma step_29 : + r28 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + r29 := by + change (BinaryField.toPoly r28Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q29Val) * + definingPolynomial + BinaryField.toPoly r29Val + exact verify_square_step (rPrev := r28Val) (q := q29Val) + (rNext := r29Val) (by rfl) + +lemma step_30 : + r29 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + r30 := by + change (BinaryField.toPoly r29Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q30Val) * + definingPolynomial + BinaryField.toPoly r30Val + exact verify_square_step (rPrev := r29Val) (q := q30Val) + (rNext := r30Val) (by rfl) + +lemma step_31 : + r30 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + r31 := by + change (BinaryField.toPoly r30Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q31Val) * + definingPolynomial + BinaryField.toPoly r31Val + exact verify_square_step (rPrev := r30Val) (q := q31Val) + (rNext := r31Val) (by rfl) + +lemma step_32 : + r31 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + r32 := by + change (BinaryField.toPoly r31Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q32Val) * + definingPolynomial + BinaryField.toPoly r32Val + exact verify_square_step (rPrev := r31Val) (q := q32Val) + (rNext := r32Val) (by rfl) + +lemma step_33 : + r32 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q33Val) * + definingPolynomial + r33 := by + change (BinaryField.toPoly r32Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q33Val) * + definingPolynomial + BinaryField.toPoly r33Val + exact verify_square_step (rPrev := r32Val) (q := q33Val) + (rNext := r33Val) (by rfl) + +lemma step_34 : + r33 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q34Val) * + definingPolynomial + r34 := by + change (BinaryField.toPoly r33Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q34Val) * + definingPolynomial + BinaryField.toPoly r34Val + exact verify_square_step (rPrev := r33Val) (q := q34Val) + (rNext := r34Val) (by rfl) + +lemma step_35 : + r34 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q35Val) * + definingPolynomial + r35 := by + change (BinaryField.toPoly r34Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q35Val) * + definingPolynomial + BinaryField.toPoly r35Val + exact verify_square_step (rPrev := r34Val) (q := q35Val) + (rNext := r35Val) (by rfl) + +lemma step_36 : + r35 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q36Val) * + definingPolynomial + r36 := by + change (BinaryField.toPoly r35Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q36Val) * + definingPolynomial + BinaryField.toPoly r36Val + exact verify_square_step (rPrev := r35Val) (q := q36Val) + (rNext := r36Val) (by rfl) + +lemma step_37 : + r36 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q37Val) * + definingPolynomial + r37 := by + change (BinaryField.toPoly r36Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q37Val) * + definingPolynomial + BinaryField.toPoly r37Val + exact verify_square_step (rPrev := r36Val) (q := q37Val) + (rNext := r37Val) (by rfl) + +lemma step_38 : + r37 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q38Val) * + definingPolynomial + r38 := by + change (BinaryField.toPoly r37Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q38Val) * + definingPolynomial + BinaryField.toPoly r38Val + exact verify_square_step (rPrev := r37Val) (q := q38Val) + (rNext := r38Val) (by rfl) + +lemma step_39 : + r38 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q39Val) * + definingPolynomial + r39 := by + change (BinaryField.toPoly r38Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q39Val) * + definingPolynomial + BinaryField.toPoly r39Val + exact verify_square_step (rPrev := r38Val) (q := q39Val) + (rNext := r39Val) (by rfl) + +lemma step_40 : + r39 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q40Val) * + definingPolynomial + r40 := by + change (BinaryField.toPoly r39Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q40Val) * + definingPolynomial + BinaryField.toPoly r40Val + exact verify_square_step (rPrev := r39Val) (q := q40Val) + (rNext := r40Val) (by rfl) + +lemma step_41 : + r40 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q41Val) * + definingPolynomial + r41 := by + change (BinaryField.toPoly r40Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q41Val) * + definingPolynomial + BinaryField.toPoly r41Val + exact verify_square_step (rPrev := r40Val) (q := q41Val) + (rNext := r41Val) (by rfl) + +lemma step_42 : + r41 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q42Val) * + definingPolynomial + r42 := by + change (BinaryField.toPoly r41Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q42Val) * + definingPolynomial + BinaryField.toPoly r42Val + exact verify_square_step (rPrev := r41Val) (q := q42Val) + (rNext := r42Val) (by rfl) + +lemma step_43 : + r42 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q43Val) * + definingPolynomial + r43 := by + change (BinaryField.toPoly r42Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q43Val) * + definingPolynomial + BinaryField.toPoly r43Val + exact verify_square_step (rPrev := r42Val) (q := q43Val) + (rNext := r43Val) (by rfl) + +lemma step_44 : + r43 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q44Val) * + definingPolynomial + r44 := by + change (BinaryField.toPoly r43Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q44Val) * + definingPolynomial + BinaryField.toPoly r44Val + exact verify_square_step (rPrev := r43Val) (q := q44Val) + (rNext := r44Val) (by rfl) + +lemma step_45 : + r44 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q45Val) * + definingPolynomial + r45 := by + change (BinaryField.toPoly r44Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q45Val) * + definingPolynomial + BinaryField.toPoly r45Val + exact verify_square_step (rPrev := r44Val) (q := q45Val) + (rNext := r45Val) (by rfl) + +lemma step_46 : + r45 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q46Val) * + definingPolynomial + r46 := by + change (BinaryField.toPoly r45Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q46Val) * + definingPolynomial + BinaryField.toPoly r46Val + exact verify_square_step (rPrev := r45Val) (q := q46Val) + (rNext := r46Val) (by rfl) + +lemma step_47 : + r46 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q47Val) * + definingPolynomial + r47 := by + change (BinaryField.toPoly r46Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q47Val) * + definingPolynomial + BinaryField.toPoly r47Val + exact verify_square_step (rPrev := r46Val) (q := q47Val) + (rNext := r47Val) (by rfl) + +lemma step_48 : + r47 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q48Val) * + definingPolynomial + r48 := by + change (BinaryField.toPoly r47Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q48Val) * + definingPolynomial + BinaryField.toPoly r48Val + exact verify_square_step (rPrev := r47Val) (q := q48Val) + (rNext := r48Val) (by rfl) + +lemma step_49 : + r48 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q49Val) * + definingPolynomial + r49 := by + change (BinaryField.toPoly r48Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q49Val) * + definingPolynomial + BinaryField.toPoly r49Val + exact verify_square_step (rPrev := r48Val) (q := q49Val) + (rNext := r49Val) (by rfl) + +lemma step_50 : + r49 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q50Val) * + definingPolynomial + r50 := by + change (BinaryField.toPoly r49Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q50Val) * + definingPolynomial + BinaryField.toPoly r50Val + exact verify_square_step (rPrev := r49Val) (q := q50Val) + (rNext := r50Val) (by rfl) + +lemma step_51 : + r50 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q51Val) * + definingPolynomial + r51 := by + change (BinaryField.toPoly r50Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q51Val) * + definingPolynomial + BinaryField.toPoly r51Val + exact verify_square_step (rPrev := r50Val) (q := q51Val) + (rNext := r51Val) (by rfl) + +lemma step_52 : + r51 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q52Val) * + definingPolynomial + r52 := by + change (BinaryField.toPoly r51Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q52Val) * + definingPolynomial + BinaryField.toPoly r52Val + exact verify_square_step (rPrev := r51Val) (q := q52Val) + (rNext := r52Val) (by rfl) + +lemma step_53 : + r52 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q53Val) * + definingPolynomial + r53 := by + change (BinaryField.toPoly r52Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q53Val) * + definingPolynomial + BinaryField.toPoly r53Val + exact verify_square_step (rPrev := r52Val) (q := q53Val) + (rNext := r53Val) (by rfl) + +lemma step_54 : + r53 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q54Val) * + definingPolynomial + r54 := by + change (BinaryField.toPoly r53Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q54Val) * + definingPolynomial + BinaryField.toPoly r54Val + exact verify_square_step (rPrev := r53Val) (q := q54Val) + (rNext := r54Val) (by rfl) + +lemma step_55 : + r54 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q55Val) * + definingPolynomial + r55 := by + change (BinaryField.toPoly r54Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q55Val) * + definingPolynomial + BinaryField.toPoly r55Val + exact verify_square_step (rPrev := r54Val) (q := q55Val) + (rNext := r55Val) (by rfl) + +lemma step_56 : + r55 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q56Val) * + definingPolynomial + r56 := by + change (BinaryField.toPoly r55Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q56Val) * + definingPolynomial + BinaryField.toPoly r56Val + exact verify_square_step (rPrev := r55Val) (q := q56Val) + (rNext := r56Val) (by rfl) + +lemma step_57 : + r56 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q57Val) * + definingPolynomial + r57 := by + change (BinaryField.toPoly r56Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q57Val) * + definingPolynomial + BinaryField.toPoly r57Val + exact verify_square_step (rPrev := r56Val) (q := q57Val) + (rNext := r57Val) (by rfl) + +lemma step_58 : + r57 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q58Val) * + definingPolynomial + r58 := by + change (BinaryField.toPoly r57Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q58Val) * + definingPolynomial + BinaryField.toPoly r58Val + exact verify_square_step (rPrev := r57Val) (q := q58Val) + (rNext := r58Val) (by rfl) + +lemma step_59 : + r58 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q59Val) * + definingPolynomial + r59 := by + change (BinaryField.toPoly r58Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q59Val) * + definingPolynomial + BinaryField.toPoly r59Val + exact verify_square_step (rPrev := r58Val) (q := q59Val) + (rNext := r59Val) (by rfl) + +lemma step_60 : + r59 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q60Val) * + definingPolynomial + r60 := by + change (BinaryField.toPoly r59Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q60Val) * + definingPolynomial + BinaryField.toPoly r60Val + exact verify_square_step (rPrev := r59Val) (q := q60Val) + (rNext := r60Val) (by rfl) + +lemma step_61 : + r60 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q61Val) * + definingPolynomial + r61 := by + change (BinaryField.toPoly r60Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q61Val) * + definingPolynomial + BinaryField.toPoly r61Val + exact verify_square_step (rPrev := r60Val) (q := q61Val) + (rNext := r61Val) (by rfl) + +lemma step_62 : + r61 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q62Val) * + definingPolynomial + r62 := by + change (BinaryField.toPoly r61Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q62Val) * + definingPolynomial + BinaryField.toPoly r62Val + exact verify_square_step (rPrev := r61Val) (q := q62Val) + (rNext := r62Val) (by rfl) + +lemma step_63 : + r62 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q63Val) * + definingPolynomial + r63 := by + change (BinaryField.toPoly r62Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q63Val) * + definingPolynomial + BinaryField.toPoly r63Val + exact verify_square_step (rPrev := r62Val) (q := q63Val) + (rNext := r63Val) (by rfl) + +lemma step_64 : + r63 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q64Val) * + definingPolynomial + r64 := by + change (BinaryField.toPoly r63Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q64Val) * + definingPolynomial + BinaryField.toPoly r64Val + exact verify_square_step (rPrev := r63Val) (q := q64Val) + (rNext := r64Val) (by rfl) + +lemma step_65 : + r64 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q65Val) * + definingPolynomial + r65 := by + change (BinaryField.toPoly r64Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q65Val) * + definingPolynomial + BinaryField.toPoly r65Val + exact verify_square_step (rPrev := r64Val) (q := q65Val) + (rNext := r65Val) (by rfl) + +lemma step_66 : + r65 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q66Val) * + definingPolynomial + r66 := by + change (BinaryField.toPoly r65Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q66Val) * + definingPolynomial + BinaryField.toPoly r66Val + exact verify_square_step (rPrev := r65Val) (q := q66Val) + (rNext := r66Val) (by rfl) + +lemma step_67 : + r66 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q67Val) * + definingPolynomial + r67 := by + change (BinaryField.toPoly r66Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q67Val) * + definingPolynomial + BinaryField.toPoly r67Val + exact verify_square_step (rPrev := r66Val) (q := q67Val) + (rNext := r67Val) (by rfl) + +lemma step_68 : + r67 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q68Val) * + definingPolynomial + r68 := by + change (BinaryField.toPoly r67Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q68Val) * + definingPolynomial + BinaryField.toPoly r68Val + exact verify_square_step (rPrev := r67Val) (q := q68Val) + (rNext := r68Val) (by rfl) + +lemma step_69 : + r68 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q69Val) * + definingPolynomial + r69 := by + change (BinaryField.toPoly r68Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q69Val) * + definingPolynomial + BinaryField.toPoly r69Val + exact verify_square_step (rPrev := r68Val) (q := q69Val) + (rNext := r69Val) (by rfl) + +lemma step_70 : + r69 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q70Val) * + definingPolynomial + r70 := by + change (BinaryField.toPoly r69Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q70Val) * + definingPolynomial + BinaryField.toPoly r70Val + exact verify_square_step (rPrev := r69Val) (q := q70Val) + (rNext := r70Val) (by rfl) + +lemma step_71 : + r70 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q71Val) * + definingPolynomial + r71 := by + change (BinaryField.toPoly r70Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q71Val) * + definingPolynomial + BinaryField.toPoly r71Val + exact verify_square_step (rPrev := r70Val) (q := q71Val) + (rNext := r71Val) (by rfl) + +lemma step_72 : + r71 ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q72Val) * + definingPolynomial + r72 := by + change (BinaryField.toPoly r71Val) ^ 2 = + BinaryField.toPoly (BitVec.zeroExtend (2 * extensionDegree) q72Val) * + definingPolynomial + BinaryField.toPoly r72Val + exact verify_square_step (rPrev := r71Val) (q := q72Val) + (rNext := r72Val) (by rfl) + +/-- The degree-one polynomial `X` is already reduced modulo the GF72 polynomial. -/ +lemma X_mod_definingPolynomial : + X % definingPolynomial = X := by + rw [Polynomial.mod_eq_self_iff (hq0 := by exact definingPolynomial_ne_zero)] + rw [definingPolynomial_degree] + unfold extensionDegree + norm_num [degree_X] + +lemma X_pow_2_pow_0_mod_eq : + X ^ (2 ^ 0) % definingPolynomial = r0 % definingPolynomial := by + rw [pow_zero, pow_one, r0_eq_X] + +lemma X_pow_2_pow_1_mod_eq : + X ^ (2 ^ 1) % definingPolynomial = r1 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 0) X_pow_2_pow_0_mod_eq step_1 + +lemma X_pow_2_pow_2_mod_eq : + X ^ (2 ^ 2) % definingPolynomial = r2 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 1) X_pow_2_pow_1_mod_eq step_2 + +lemma X_pow_2_pow_3_mod_eq : + X ^ (2 ^ 3) % definingPolynomial = r3 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 2) X_pow_2_pow_2_mod_eq step_3 + +lemma X_pow_2_pow_4_mod_eq : + X ^ (2 ^ 4) % definingPolynomial = r4 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 3) X_pow_2_pow_3_mod_eq step_4 + +lemma X_pow_2_pow_5_mod_eq : + X ^ (2 ^ 5) % definingPolynomial = r5 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 4) X_pow_2_pow_4_mod_eq step_5 + +lemma X_pow_2_pow_6_mod_eq : + X ^ (2 ^ 6) % definingPolynomial = r6 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 5) X_pow_2_pow_5_mod_eq step_6 + +lemma X_pow_2_pow_7_mod_eq : + X ^ (2 ^ 7) % definingPolynomial = r7 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 6) X_pow_2_pow_6_mod_eq step_7 + +lemma X_pow_2_pow_8_mod_eq : + X ^ (2 ^ 8) % definingPolynomial = r8 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 7) X_pow_2_pow_7_mod_eq step_8 + +lemma X_pow_2_pow_9_mod_eq : + X ^ (2 ^ 9) % definingPolynomial = r9 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 8) X_pow_2_pow_8_mod_eq step_9 + +lemma X_pow_2_pow_10_mod_eq : + X ^ (2 ^ 10) % definingPolynomial = r10 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 9) X_pow_2_pow_9_mod_eq step_10 + +lemma X_pow_2_pow_11_mod_eq : + X ^ (2 ^ 11) % definingPolynomial = r11 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 10) X_pow_2_pow_10_mod_eq step_11 + +lemma X_pow_2_pow_12_mod_eq : + X ^ (2 ^ 12) % definingPolynomial = r12 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 11) X_pow_2_pow_11_mod_eq step_12 + +lemma X_pow_2_pow_13_mod_eq : + X ^ (2 ^ 13) % definingPolynomial = r13 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 12) X_pow_2_pow_12_mod_eq step_13 + +lemma X_pow_2_pow_14_mod_eq : + X ^ (2 ^ 14) % definingPolynomial = r14 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 13) X_pow_2_pow_13_mod_eq step_14 + +lemma X_pow_2_pow_15_mod_eq : + X ^ (2 ^ 15) % definingPolynomial = r15 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 14) X_pow_2_pow_14_mod_eq step_15 + +lemma X_pow_2_pow_16_mod_eq : + X ^ (2 ^ 16) % definingPolynomial = r16 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 15) X_pow_2_pow_15_mod_eq step_16 + +lemma X_pow_2_pow_17_mod_eq : + X ^ (2 ^ 17) % definingPolynomial = r17 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 16) X_pow_2_pow_16_mod_eq step_17 + +lemma X_pow_2_pow_18_mod_eq : + X ^ (2 ^ 18) % definingPolynomial = r18 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 17) X_pow_2_pow_17_mod_eq step_18 + +lemma X_pow_2_pow_19_mod_eq : + X ^ (2 ^ 19) % definingPolynomial = r19 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 18) X_pow_2_pow_18_mod_eq step_19 + +lemma X_pow_2_pow_20_mod_eq : + X ^ (2 ^ 20) % definingPolynomial = r20 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 19) X_pow_2_pow_19_mod_eq step_20 + +lemma X_pow_2_pow_21_mod_eq : + X ^ (2 ^ 21) % definingPolynomial = r21 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 20) X_pow_2_pow_20_mod_eq step_21 + +lemma X_pow_2_pow_22_mod_eq : + X ^ (2 ^ 22) % definingPolynomial = r22 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 21) X_pow_2_pow_21_mod_eq step_22 + +lemma X_pow_2_pow_23_mod_eq : + X ^ (2 ^ 23) % definingPolynomial = r23 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 22) X_pow_2_pow_22_mod_eq step_23 + +lemma X_pow_2_pow_24_mod_eq : + X ^ (2 ^ 24) % definingPolynomial = r24 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 23) X_pow_2_pow_23_mod_eq step_24 + +lemma X_pow_2_pow_25_mod_eq : + X ^ (2 ^ 25) % definingPolynomial = r25 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 24) X_pow_2_pow_24_mod_eq step_25 + +lemma X_pow_2_pow_26_mod_eq : + X ^ (2 ^ 26) % definingPolynomial = r26 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 25) X_pow_2_pow_25_mod_eq step_26 + +lemma X_pow_2_pow_27_mod_eq : + X ^ (2 ^ 27) % definingPolynomial = r27 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 26) X_pow_2_pow_26_mod_eq step_27 + +lemma X_pow_2_pow_28_mod_eq : + X ^ (2 ^ 28) % definingPolynomial = r28 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 27) X_pow_2_pow_27_mod_eq step_28 + +lemma X_pow_2_pow_29_mod_eq : + X ^ (2 ^ 29) % definingPolynomial = r29 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 28) X_pow_2_pow_28_mod_eq step_29 + +lemma X_pow_2_pow_30_mod_eq : + X ^ (2 ^ 30) % definingPolynomial = r30 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 29) X_pow_2_pow_29_mod_eq step_30 + +lemma X_pow_2_pow_31_mod_eq : + X ^ (2 ^ 31) % definingPolynomial = r31 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 30) X_pow_2_pow_30_mod_eq step_31 + +lemma X_pow_2_pow_32_mod_eq : + X ^ (2 ^ 32) % definingPolynomial = r32 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 31) X_pow_2_pow_31_mod_eq step_32 + +lemma X_pow_2_pow_33_mod_eq : + X ^ (2 ^ 33) % definingPolynomial = r33 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 32) X_pow_2_pow_32_mod_eq step_33 + +lemma X_pow_2_pow_34_mod_eq : + X ^ (2 ^ 34) % definingPolynomial = r34 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 33) X_pow_2_pow_33_mod_eq step_34 + +lemma X_pow_2_pow_35_mod_eq : + X ^ (2 ^ 35) % definingPolynomial = r35 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 34) X_pow_2_pow_34_mod_eq step_35 + +lemma X_pow_2_pow_36_mod_eq : + X ^ (2 ^ 36) % definingPolynomial = r36 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 35) X_pow_2_pow_35_mod_eq step_36 + +lemma X_pow_2_pow_37_mod_eq : + X ^ (2 ^ 37) % definingPolynomial = r37 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 36) X_pow_2_pow_36_mod_eq step_37 + +lemma X_pow_2_pow_38_mod_eq : + X ^ (2 ^ 38) % definingPolynomial = r38 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 37) X_pow_2_pow_37_mod_eq step_38 + +lemma X_pow_2_pow_39_mod_eq : + X ^ (2 ^ 39) % definingPolynomial = r39 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 38) X_pow_2_pow_38_mod_eq step_39 + +lemma X_pow_2_pow_40_mod_eq : + X ^ (2 ^ 40) % definingPolynomial = r40 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 39) X_pow_2_pow_39_mod_eq step_40 + +lemma X_pow_2_pow_41_mod_eq : + X ^ (2 ^ 41) % definingPolynomial = r41 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 40) X_pow_2_pow_40_mod_eq step_41 + +lemma X_pow_2_pow_42_mod_eq : + X ^ (2 ^ 42) % definingPolynomial = r42 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 41) X_pow_2_pow_41_mod_eq step_42 + +lemma X_pow_2_pow_43_mod_eq : + X ^ (2 ^ 43) % definingPolynomial = r43 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 42) X_pow_2_pow_42_mod_eq step_43 + +lemma X_pow_2_pow_44_mod_eq : + X ^ (2 ^ 44) % definingPolynomial = r44 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 43) X_pow_2_pow_43_mod_eq step_44 + +lemma X_pow_2_pow_45_mod_eq : + X ^ (2 ^ 45) % definingPolynomial = r45 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 44) X_pow_2_pow_44_mod_eq step_45 + +lemma X_pow_2_pow_46_mod_eq : + X ^ (2 ^ 46) % definingPolynomial = r46 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 45) X_pow_2_pow_45_mod_eq step_46 + +lemma X_pow_2_pow_47_mod_eq : + X ^ (2 ^ 47) % definingPolynomial = r47 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 46) X_pow_2_pow_46_mod_eq step_47 + +lemma X_pow_2_pow_48_mod_eq : + X ^ (2 ^ 48) % definingPolynomial = r48 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 47) X_pow_2_pow_47_mod_eq step_48 + +lemma X_pow_2_pow_49_mod_eq : + X ^ (2 ^ 49) % definingPolynomial = r49 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 48) X_pow_2_pow_48_mod_eq step_49 + +lemma X_pow_2_pow_50_mod_eq : + X ^ (2 ^ 50) % definingPolynomial = r50 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 49) X_pow_2_pow_49_mod_eq step_50 + +lemma X_pow_2_pow_51_mod_eq : + X ^ (2 ^ 51) % definingPolynomial = r51 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 50) X_pow_2_pow_50_mod_eq step_51 + +lemma X_pow_2_pow_52_mod_eq : + X ^ (2 ^ 52) % definingPolynomial = r52 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 51) X_pow_2_pow_51_mod_eq step_52 + +lemma X_pow_2_pow_53_mod_eq : + X ^ (2 ^ 53) % definingPolynomial = r53 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 52) X_pow_2_pow_52_mod_eq step_53 + +lemma X_pow_2_pow_54_mod_eq : + X ^ (2 ^ 54) % definingPolynomial = r54 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 53) X_pow_2_pow_53_mod_eq step_54 + +lemma X_pow_2_pow_55_mod_eq : + X ^ (2 ^ 55) % definingPolynomial = r55 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 54) X_pow_2_pow_54_mod_eq step_55 + +lemma X_pow_2_pow_56_mod_eq : + X ^ (2 ^ 56) % definingPolynomial = r56 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 55) X_pow_2_pow_55_mod_eq step_56 + +lemma X_pow_2_pow_57_mod_eq : + X ^ (2 ^ 57) % definingPolynomial = r57 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 56) X_pow_2_pow_56_mod_eq step_57 + +lemma X_pow_2_pow_58_mod_eq : + X ^ (2 ^ 58) % definingPolynomial = r58 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 57) X_pow_2_pow_57_mod_eq step_58 + +lemma X_pow_2_pow_59_mod_eq : + X ^ (2 ^ 59) % definingPolynomial = r59 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 58) X_pow_2_pow_58_mod_eq step_59 + +lemma X_pow_2_pow_60_mod_eq : + X ^ (2 ^ 60) % definingPolynomial = r60 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 59) X_pow_2_pow_59_mod_eq step_60 + +lemma X_pow_2_pow_61_mod_eq : + X ^ (2 ^ 61) % definingPolynomial = r61 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 60) X_pow_2_pow_60_mod_eq step_61 + +lemma X_pow_2_pow_62_mod_eq : + X ^ (2 ^ 62) % definingPolynomial = r62 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 61) X_pow_2_pow_61_mod_eq step_62 + +lemma X_pow_2_pow_63_mod_eq : + X ^ (2 ^ 63) % definingPolynomial = r63 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 62) X_pow_2_pow_62_mod_eq step_63 + +lemma X_pow_2_pow_64_mod_eq : + X ^ (2 ^ 64) % definingPolynomial = r64 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 63) X_pow_2_pow_63_mod_eq step_64 + +lemma X_pow_2_pow_65_mod_eq : + X ^ (2 ^ 65) % definingPolynomial = r65 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 64) X_pow_2_pow_64_mod_eq step_65 + +lemma X_pow_2_pow_66_mod_eq : + X ^ (2 ^ 66) % definingPolynomial = r66 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 65) X_pow_2_pow_65_mod_eq step_66 + +lemma X_pow_2_pow_67_mod_eq : + X ^ (2 ^ 67) % definingPolynomial = r67 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 66) X_pow_2_pow_66_mod_eq step_67 + +lemma X_pow_2_pow_68_mod_eq : + X ^ (2 ^ 68) % definingPolynomial = r68 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 67) X_pow_2_pow_67_mod_eq step_68 + +lemma X_pow_2_pow_69_mod_eq : + X ^ (2 ^ 69) % definingPolynomial = r69 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 68) X_pow_2_pow_68_mod_eq step_69 + +lemma X_pow_2_pow_70_mod_eq : + X ^ (2 ^ 70) % definingPolynomial = r70 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 69) X_pow_2_pow_69_mod_eq step_70 + +lemma X_pow_2_pow_71_mod_eq : + X ^ (2 ^ 71) % definingPolynomial = r71 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 70) X_pow_2_pow_70_mod_eq step_71 + +lemma X_pow_2_pow_72_mod_eq : + X ^ (2 ^ 72) % definingPolynomial = r72 % definingPolynomial := by + exact BinaryField.Extension.chain_step + (P := definingPolynomial) definingPolynomial_ne_zero + (k := 71) X_pow_2_pow_71_mod_eq step_72 + +/-- Rabin trace-condition remainder for the GF72 candidate polynomial. -/ +lemma X_pow_2_pow_72_add_X_mod_eq_zero : + (X ^ (2 ^ 72) + X) % definingPolynomial = 0 := by + rw [CanonicalEuclideanDomain.add_mod_eq (hn := definingPolynomial_ne_zero)] + rw [X_pow_2_pow_72_mod_eq, r72_eq_X, X_mod_definingPolynomial] + simp only [CharTwo.add_self_eq_zero, EuclideanDomain.zero_mod] + +/-- Rabin trace divisibility condition for the GF72 candidate polynomial. -/ +lemma X_pow_2_pow_72_add_X_dvd : + definingPolynomial ∣ X ^ (2 ^ 72) + X := by + rw [← EuclideanDomain.mod_eq_zero] + exact X_pow_2_pow_72_add_X_mod_eq_zero + +end GF2_72 diff --git a/CompPoly/Fields/README.md b/CompPoly/Fields/README.md index ef884b31..63d28eed 100644 --- a/CompPoly/Fields/README.md +++ b/CompPoly/Fields/README.md @@ -24,6 +24,8 @@ This directory contains formally verified field infrastructure used in zero-know The `Binary/` subtree provides characteristic-2 field infrastructure used by GHASH and additive-NTT workflows: - `Binary/BF128Ghash/*` — GF(2^128) model, implementation, and certificates. +- `Binary/Extension/*` — shared direct polynomial-basis binary-extension helpers, quotient/specification support, executable bit-vector operations, and primitive-order proof helpers. +- `Binary/GF2_32/*`, `Binary/GF2_48/*`, `Binary/GF2_64/*`, `Binary/GF2_72/*` — GF(2^32), GF(2^48), GF(2^64), and GF(2^72) direct-extension scaffolding, defining polynomials, quotient/specification surfaces, executable bit-vector operations, primitive-power certificates, and finite-field smooth/Shoup root-search contexts. - `Binary/AdditiveNTT/*` — additive-NTT domain/algorithm/correctness stack. - `Binary/Tower/*` — abstract/concrete binary tower-field constructions and supporting lemmas. diff --git a/CompPoly/Univariate/Roots.lean b/CompPoly/Univariate/Roots.lean index 761c2d0c..97a33272 100644 --- a/CompPoly/Univariate/Roots.lean +++ b/CompPoly/Univariate/Roots.lean @@ -6,6 +6,7 @@ Authors: Valerii Huhnin import CompPoly.Univariate.Roots.Correctness import CompPoly.Univariate.Roots.Enumeration +import CompPoly.Univariate.Roots.Shoup import CompPoly.Univariate.Roots.SmoothSubgroup /-! diff --git a/CompPoly/Univariate/Roots/Shoup.lean b/CompPoly/Univariate/Roots/Shoup.lean new file mode 100644 index 00000000..12dd0616 --- /dev/null +++ b/CompPoly/Univariate/Roots/Shoup.lean @@ -0,0 +1,15 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Univariate.Roots.Shoup.Basic +import CompPoly.Univariate.Roots.Shoup.Correctness +import CompPoly.Univariate.Roots.Shoup.FrobeniusLinear + +/-! +# Shoup-Style Small-Characteristic Root Splitting + +Public module for the Shoup-style trace splitter. +-/ diff --git a/CompPoly/Univariate/Roots/Shoup/Basic.lean b/CompPoly/Univariate/Roots/Shoup/Basic.lean new file mode 100644 index 00000000..ae01c6ae --- /dev/null +++ b/CompPoly/Univariate/Roots/Shoup/Basic.lean @@ -0,0 +1,439 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Univariate.Roots.RootProduct +import CompPoly.Univariate.Roots.Splitter +import CompPoly.Univariate.ToPoly.Core + +/-! +# Shoup-Style Small-Characteristic Linear-Factor Splitting + +Executable trace-coordinate splitter for finite-field root products over fields +presented as `GF(p^k)` with small base characteristic `p`. The splitter refines a +valid root product by `k` trace coordinates and the `p` embedded base constants; +it does not enumerate all `p^k` field elements, following the small-characteristic +Frobenius-map factoring method of von zur Gathen and Shoup [vzGS92]. + +## References + +* [J. von zur Gathen and Victor Shoup, *Computing Frobenius maps and factoring + polynomials*, Computational Complexity 2, 187-224, 1992][vzGS92] +-/ + +namespace CompPoly + +namespace CPolynomial + +namespace Roots + +namespace FiniteField + +/-- Trace power sum `z + z^p + ... + z^(p^(k-1))`. -/ +def tracePowerSum {F : Type*} [Field F] (p k : Nat) (z : F) : F := + (List.range k).foldl (fun acc i ↦ acc + z ^ (p ^ i)) 0 + +/-- The list-fold trace power sum is the corresponding finite range sum. -/ +theorem tracePowerSum_eq_sum_range {F : Type*} [Field F] (p k : Nat) (z : F) : + tracePowerSum p k z = ∑ i ∈ Finset.range k, z ^ (p ^ i) := by + unfold tracePowerSum + induction k with + | zero => + simp + | succ k ih => + rw [List.range_succ, List.foldl_append] + simp [ih, Finset.sum_range_succ] + +/-- +Executable and proof data for a Shoup-style small-characteristic trace splitter. + +The field-theoretic facts are carried by the context so the generic executable +splitter can stay representation-independent. Concrete fields can discharge the +trace-image and separating-basis obligations using their own basis libraries. +-/ +structure SmallPrimeTraceContext (F : Type*) [Field F] [BEq F] [LawfulBEq F] + extends FiniteFieldContext F where + p : Nat + k : Nat + p_prime : Nat.Prime p + q_eq : q = p ^ k + baseConstants : Array F + baseConstants_size : baseConstants.size = p + basis : Array F + basis_size : basis.size = k + traceValue : F → F + traceValue_eq_powerSum : ∀ z, traceValue z = tracePowerSum p k z + traceValue_mem_base : ∀ z, traceValue z ∈ baseConstants.toList + trace_separates : + ∀ {a b : F}, a ≠ b → + ∃ beta, beta ∈ basis.toList ∧ traceValue (beta * (a - b)) ≠ 0 + +/-- +Input predicate for the Shoup splitter. + +Completeness is only claimed for nonzero products of distinct field-linear +factors, represented here by divisibility into `X^q - X`. This is the contract +satisfied by the finite-field root product, not by arbitrary input polynomials. +-/ +def shoupSplitterInput {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) (p : CPolynomial F) : Prop := + p ≠ 0 ∧ + p.toPoly ∣ ((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X) + +/-- Modular powers `X^(p^i) mod modulus` for `0 ≤ i < k`. -/ +def modularXPowersWith {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (modulus : CPolynomial F) (p k : Nat) : Array (CPolynomial F) := + Array.ofFn fun i : Fin k ↦ xPowModWith M D modulus (p ^ i.val) + +/-- `Trace(beta * X) mod modulus`, using precomputed modular Frobenius powers. -/ +def traceCoordinatePolynomialFromPowers {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) (beta : F) + (powers : Array (CPolynomial F)) : + CPolynomial F := + (List.range ctx.k).foldl + (fun acc i ↦ + acc + CPolynomial.C (beta ^ (ctx.p ^ i)) * powers.getD i 0) + 0 + +/-- `Trace(beta * X) mod modulus`, built from the modular Frobenius powers. -/ +def traceCoordinatePolynomialWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (modulus : CPolynomial F) (beta : F) : + CPolynomial F := + (List.range ctx.k).foldl + (fun acc i ↦ + acc + CPolynomial.C (beta ^ (ctx.p ^ i)) * + xPowModWith M D modulus (ctx.p ^ i)) + 0 + +private theorem traceCoordinatePolynomialFromPowers_modularXPowersWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (modulus : CPolynomial F) (beta : F) : + traceCoordinatePolynomialFromPowers ctx beta + (modularXPowersWith M D modulus ctx.p ctx.k) = + traceCoordinatePolynomialWith M D ctx modulus beta := by + unfold traceCoordinatePolynomialFromPowers traceCoordinatePolynomialWith modularXPowersWith + have hget : ∀ i, i ∈ List.range ctx.k → + Array.getD + (Array.ofFn fun i : Fin ctx.k ↦ xPowModWith M D modulus (ctx.p ^ i.val)) + i 0 = + xPowModWith M D modulus (ctx.p ^ i) := by + intro i hi + have hi' : i < ctx.k := List.mem_range.mp hi + unfold Array.getD + simp [hi'] + have hfold : ∀ (xs : List Nat) (acc : CPolynomial F), + (∀ i, i ∈ xs → + Array.getD + (Array.ofFn fun i : Fin ctx.k ↦ xPowModWith M D modulus (ctx.p ^ i.val)) + i 0 = + xPowModWith M D modulus (ctx.p ^ i)) → + List.foldl + (fun acc i ↦ acc + CPolynomial.C (beta ^ ctx.p ^ i) * + Array.getD + (Array.ofFn fun i : Fin ctx.k ↦ xPowModWith M D modulus (ctx.p ^ i.val)) + i 0) + acc xs = + List.foldl + (fun acc i ↦ acc + CPolynomial.C (beta ^ ctx.p ^ i) * + xPowModWith M D modulus (ctx.p ^ i)) + acc xs := by + intro xs + induction xs with + | nil => + intro acc _hxs + simp + | cons i xs ih => + intro acc hxs + simp only [List.foldl_cons] + rw [hxs i (by simp)] + apply ih + intro j hj + exact hxs j (by simp [hj]) + exact hfold (List.range ctx.k) 0 hget + +/-- Drop zero/unit children and keep the remaining monic gcd child. -/ +def pushNontrivialChild {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (children : Array (CPolynomial F)) (child : CPolynomial F) : + Array (CPolynomial F) := + if child == 0 || child == 1 then children else children.push child + +/-- Refine one current factor by one trace coordinate and all base constants. -/ +def shoupRefineFactorWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) (u : CPolynomial F) : + Array (CPolynomial F) := + let u := CPolynomial.monicNormalize u + if u == 0 || u == 1 then + #[] + else if isRepresentedLinearFactor u then + #[u] + else + let tracePoly := traceCoordinatePolynomialWith M D ctx u beta + ctx.baseConstants.foldl + (fun children c ↦ + let child := CPolynomial.monicNormalize + (CPolynomial.gcdMonic u (tracePoly - CPolynomial.C c)) + pushNontrivialChild children child) + #[] + +/-- Refine all current factors by one trace coordinate. -/ +def shoupRefineFactorsWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) (factors : Array (CPolynomial F)) : + Array (CPolynomial F) := + factors.foldl + (fun out factor ↦ out ++ shoupRefineFactorWith M D ctx beta factor) + #[] + +abbrev ShoupTracePowerCache (F : Type*) [Field F] [BEq F] [LawfulBEq F] := + List (CPolynomial F × Array (CPolynomial F)) + +private def lookupTracePowers {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (u : CPolynomial F) : + ShoupTracePowerCache F → Option (Array (CPolynomial F)) + | [] => none + | (v, powers) :: rest => + if u == v then + some powers + else + lookupTracePowers u rest + +private def tracePowersWithCache {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (u : CPolynomial F) + (cache : ShoupTracePowerCache F) : + Array (CPolynomial F) × ShoupTracePowerCache F := + match lookupTracePowers u cache with + | some powers => (powers, cache) + | none => + let powers := modularXPowersWith M D u ctx.p ctx.k + (powers, (u, powers) :: cache) + +private def shoupRefineFactorCachedWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) + (cache : ShoupTracePowerCache F) (u : CPolynomial F) : + ShoupTracePowerCache F × Array (CPolynomial F) := + let u := CPolynomial.monicNormalize u + if u == 0 || u == 1 then + (cache, #[]) + else if isRepresentedLinearFactor u then + (cache, #[u]) + else + let (powers, cache) := tracePowersWithCache M D ctx u cache + let tracePoly := traceCoordinatePolynomialFromPowers ctx beta powers + let children := + ctx.baseConstants.foldl + (fun children c ↦ + let child := CPolynomial.monicNormalize + (CPolynomial.gcdMonic u (tracePoly - CPolynomial.C c)) + pushNontrivialChild children child) + #[] + (cache, children) + +private def shoupRefineFactorsCachedWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) + (cache : ShoupTracePowerCache F) (factors : Array (CPolynomial F)) : + ShoupTracePowerCache F × Array (CPolynomial F) := + factors.foldl + (fun state factor ↦ + let (cache, out) := state + let (cache, children) := shoupRefineFactorCachedWith M D ctx beta cache factor + (cache, out ++ children)) + (cache, #[]) + +private def shoupRefineBasisCachedWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (basis : List F) + (cache : ShoupTracePowerCache F) (factors : Array (CPolynomial F)) : + Array (CPolynomial F) := + (basis.foldl + (fun state beta ↦ + let (cache, factors) := state + shoupRefineFactorsCachedWith M D ctx beta cache factors) + (cache, factors)).2 + +private def shoupSplitCandidatesCachedWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (p : CPolynomial F) : + Array (CPolynomial F) := + let p := CPolynomial.monicNormalize p + if p == 0 || p == 1 then + #[] + else if isRepresentedLinearFactor p then + #[p] + else + shoupRefineBasisCachedWith M D ctx ctx.basis.toList [] #[p] + +/-- Final linear-only filter for the splitter interface's unconditional soundness field. -/ +def representedLinearFactorsOnly {F : Type*} [Field F] [BEq F] + (factors : Array (CPolynomial F)) : Array (CPolynomial F) := + factors.foldl + (fun out factor ↦ + if isRepresentedLinearFactor factor then out.push factor else out) + #[] + +private theorem representedLinearFactorsOnly_go_sound {F : Type*} + [Field F] [BEq F] [LawfulBEq F] : + ∀ (factors : List (CPolynomial F)) (out : Array (CPolynomial F)), + (∀ {factor : CPolynomial F}, factor ∈ out → IsLinearFactor factor) → + ∀ {factor : CPolynomial F}, + factor ∈ + factors.foldl + (fun out factor ↦ + if isRepresentedLinearFactor factor then out.push factor else out) + out → + IsLinearFactor factor := by + intro factors + induction factors with + | nil => + intro out hout factor h + exact hout h + | cons x xs ih => + intro out hout factor h + simp only [List.foldl_cons] at h + by_cases hlin : isRepresentedLinearFactor x = true + · simp [hlin] at h + exact ih (out.push x) (by + intro factor hmem + simp at hmem + rcases hmem with hmem | hfactor + · exact hout hmem + · subst factor + exact isRepresentedLinearFactor_sound hlin) h + · simp [hlin] at h + exact ih out hout h + +/-- The final Shoup filter only keeps represented linear factors. -/ +theorem representedLinearFactorsOnly_sound {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + {factors : Array (CPolynomial F)} {factor : CPolynomial F} + (h : factor ∈ (representedLinearFactorsOnly factors).toList) : + IsLinearFactor factor := by + unfold representedLinearFactorsOnly at h + rcases factors with ⟨factors⟩ + exact representedLinearFactorsOnly_go_sound factors #[] (by + intro factor hmem + simp at hmem) (by + simpa using h) + +private theorem mem_representedLinearFactorsOnly_foldl_of_mem_out {F : Type*} + [Field F] [BEq F] [LawfulBEq F] : + ∀ (factors : List (CPolynomial F)) (out : Array (CPolynomial F)) + {factor : CPolynomial F}, + factor ∈ out → + factor ∈ + (factors.foldl + (fun out factor ↦ + if isRepresentedLinearFactor factor then out.push factor else out) + out) := by + intro factors + induction factors with + | nil => + intro out factor hmem + exact hmem + | cons x xs ih => + intro out factor hmem + simp only [List.foldl_cons] + by_cases hxlin : isRepresentedLinearFactor x = true + · simp [hxlin] + exact ih (out.push x) (by simp [hmem]) + · simp [hxlin] + exact ih out hmem + +private theorem mem_representedLinearFactorsOnly_foldl_of_mem_input {F : Type*} + [Field F] [BEq F] [LawfulBEq F] : + ∀ (factors : List (CPolynomial F)) (out : Array (CPolynomial F)) + {factor : CPolynomial F}, + factor ∈ factors → + isRepresentedLinearFactor factor = true → + factor ∈ + (factors.foldl + (fun out factor ↦ + if isRepresentedLinearFactor factor then out.push factor else out) + out) := by + intro factors + induction factors with + | nil => + intro out factor hmem _hlin + simp at hmem + | cons x xs ih => + intro out factor hmem hlin + simp only [List.foldl_cons] + simp at hmem + rcases hmem with hhead | htail + · subst factor + simp [hlin] + exact mem_representedLinearFactorsOnly_foldl_of_mem_out xs (out.push x) (by simp) + · by_cases hxlin : isRepresentedLinearFactor x = true + · simp [hxlin] + exact ih (out.push x) htail hlin + · simp [hxlin] + exact ih out htail hlin + +/-- The final linear-factor filter keeps represented factors that were already present. -/ +theorem representedLinearFactorsOnly_mem_of_mem {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + {factors : Array (CPolynomial F)} {factor : CPolynomial F} + (hmem : factor ∈ factors.toList) + (hlin : isRepresentedLinearFactor factor = true) : + factor ∈ (representedLinearFactorsOnly factors).toList := by + unfold representedLinearFactorsOnly + rcases factors with ⟨factors⟩ + simpa using mem_representedLinearFactorsOnly_foldl_of_mem_input factors #[] hmem hlin + +/-- Trace-coordinate refinement candidates before the final linear-only filter. -/ +@[implemented_by shoupSplitCandidatesCachedWith] +def shoupSplitCandidatesWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (p : CPolynomial F) : + Array (CPolynomial F) := + let p := CPolynomial.monicNormalize p + if p == 0 || p == 1 then + #[] + else if isRepresentedLinearFactor p then + #[p] + else + ctx.basis.foldl + (fun factors beta ↦ shoupRefineFactorsWith M D ctx beta factors) + #[p] + +/-- Shoup trace-coordinate splitting, returning only represented linear factors. -/ +def shoupSplitLinearFactorsWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (p : CPolynomial F) : + Array (CPolynomial F) := + representedLinearFactorsOnly (shoupSplitCandidatesWith M D ctx p) + +/-- Soundness of the final Shoup linear-factor array. -/ +theorem shoupSplitLinearFactorsWith_sound {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p factor : CPolynomial F} + (h : factor ∈ (shoupSplitLinearFactorsWith M D ctx p).toList) : + IsLinearFactor factor := by + exact representedLinearFactorsOnly_sound h + +end FiniteField + +end Roots + +end CPolynomial + +end CompPoly diff --git a/CompPoly/Univariate/Roots/Shoup/Correctness.lean b/CompPoly/Univariate/Roots/Shoup/Correctness.lean new file mode 100644 index 00000000..2bb89691 --- /dev/null +++ b/CompPoly/Univariate/Roots/Shoup/Correctness.lean @@ -0,0 +1,1390 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Univariate.Roots.Correctness +import CompPoly.Univariate.Roots.Shoup.Basic +import CompPoly.Univariate.Roots.Shoup.FrobeniusLinear +import Mathlib.Algebra.CharP.CharAndCard + +/-! +# Correctness Surface for Shoup-Style Trace Splitting + +This file states the proof obligations for the executable Shoup trace splitter. +The main completeness contract is intentionally limited to valid root products: +nonzero divisors of `X^q - X`, as produced by the finite-field root-product +construction. +-/ + +namespace CompPoly + +namespace CPolynomial + +namespace Roots + +namespace FiniteField + +/-- Evaluation of a Shoup modular power at a root of the modulus. -/ +theorem eval_shoupModularXPowerWith_eq_pow {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {modulus : CPolynomial F} {a : F} + (hroot : CPolynomial.eval a modulus = 0) (i : Nat) : + CPolynomial.eval a (xPowModWith M D modulus (ctx.p ^ i)) = a ^ (ctx.p ^ i) := by + exact eval_xPowModWith_eq_pow M D hroot (ctx.p ^ i) + +/-- Trace-coordinate polynomial evaluation at a root of the modulus. -/ +theorem eval_traceCoordinatePolynomialWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {modulus : CPolynomial F} {a beta : F} + (hroot : CPolynomial.eval a modulus = 0) : + CPolynomial.eval a (traceCoordinatePolynomialWith M D ctx modulus beta) = + ctx.traceValue (beta * a) := by + have evalAdd : + ∀ p q : CPolynomial F, + CPolynomial.eval a (p + q) = CPolynomial.eval a p + CPolynomial.eval a q := by + intro p q + rw [CPolynomial.eval_toPoly, CPolynomial.toPoly_add, Polynomial.eval_add, + ← CPolynomial.eval_toPoly, ← CPolynomial.eval_toPoly] + have evalZero : CPolynomial.eval a (0 : CPolynomial F) = 0 := by + rw [CPolynomial.eval_toPoly, CPolynomial.toPoly_zero, Polynomial.eval_zero] + rw [ctx.traceValue_eq_powerSum] + unfold traceCoordinatePolynomialWith tracePowerSum + have hgo : ∀ (xs : List Nat) (acc : CPolynomial F) (accVal : F), + CPolynomial.eval a acc = accVal → + CPolynomial.eval a + (xs.foldl + (fun acc i ↦ + acc + CPolynomial.C (beta ^ (ctx.p ^ i)) * + xPowModWith M D modulus (ctx.p ^ i)) + acc) = + xs.foldl (fun acc i ↦ acc + (beta * a) ^ (ctx.p ^ i)) accVal := by + intro xs + induction xs with + | nil => + intro acc accVal hacc + simpa using hacc + | cons i is ih => + intro acc accVal hacc + simp only [List.foldl_cons] + apply ih + rw [evalAdd, CPolynomial.eval_mul, CPolynomial.eval_C, + eval_xPowModWith_eq_pow M D hroot, hacc] + rw [mul_pow] + exact hgo (List.range ctx.k) 0 0 evalZero + +/-- A Shoup trace context has the advertised base characteristic. -/ +private theorem smallPrimeTraceContext_charP {F : Type*} + [Field F] [BEq F] [LawfulBEq F] (ctx : SmallPrimeTraceContext F) : + CharP F ctx.p := by + letI : Finite F := ctx.finite + letI : Fintype F := Fintype.ofFinite F + letI : Fact ctx.p.Prime := ⟨ctx.p_prime⟩ + have hcard : Fintype.card F = ctx.p ^ ctx.k := by + rw [← Nat.card_eq_fintype_card, ctx.card_eq, ctx.q_eq] + exact charP_of_card_eq_prime_pow hcard + +/-- The trace power-sum is additive for subtraction. -/ +theorem traceValue_sub {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) (x y : F) : + ctx.traceValue (x - y) = ctx.traceValue x - ctx.traceValue y := by + letI : CharP F ctx.p := smallPrimeTraceContext_charP ctx + letI : ExpChar F ctx.p := ExpChar.prime ctx.p_prime + rw [ctx.traceValue_eq_powerSum, ctx.traceValue_eq_powerSum, ctx.traceValue_eq_powerSum] + unfold tracePowerSum + have hgo : ∀ (xs : List Nat) (accx accy : F), + xs.foldl (fun acc i ↦ acc + (x - y) ^ (ctx.p ^ i)) (accx - accy) = + xs.foldl (fun acc i ↦ acc + x ^ (ctx.p ^ i)) accx - + xs.foldl (fun acc i ↦ acc + y ^ (ctx.p ^ i)) accy := by + intro xs + induction xs with + | nil => + intro accx accy + simp + | cons i is ih => + intro accx accy + simp only [List.foldl_cons] + have hstep : accx - accy + (x - y) ^ (ctx.p ^ i) = + (accx + x ^ (ctx.p ^ i)) - (accy + y ^ (ctx.p ^ i)) := by + rw [sub_pow_expChar_pow] + ring + rw [hstep] + exact ih (accx + x ^ (ctx.p ^ i)) (accy + y ^ (ctx.p ^ i)) + simpa using hgo (List.range ctx.k) 0 0 + +/-- Trace coordinates convert equal bucket values into zero trace on differences. -/ +theorem traceValue_mul_sub_eq_zero_of_eq {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) {beta a b : F} + (htrace : ctx.traceValue (beta * a) = ctx.traceValue (beta * b)) : + ctx.traceValue (beta * (a - b)) = 0 := by + rw [mul_sub, traceValue_sub ctx, htrace, sub_self] + +/-- Matching every trace coordinate in the separating basis forces equality. -/ +theorem eq_of_traceValue_eq_on_basis {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) {a b : F} + (htrace : ∀ beta, beta ∈ ctx.basis.toList → + ctx.traceValue (beta * a) = ctx.traceValue (beta * b)) : + a = b := by + by_contra hne + rcases ctx.trace_separates hne with ⟨beta, hbeta, hsep⟩ + exact hsep (traceValue_mul_sub_eq_zero_of_eq ctx (htrace beta hbeta)) + +/-- The trace-coordinate gcd bucket preserves roots whose trace coordinate matches the bucket. -/ +theorem shoup_gcdBucket_root {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {u : CPolynomial F} {a beta c : F} + (hroot : CPolynomial.eval a u = 0) + (htrace : ctx.traceValue (beta * a) = c) : + CPolynomial.eval a + (CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c))) = 0 := by + let witness := traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c + have hwitnessRoot : CPolynomial.eval a witness = 0 := by + dsimp [witness] + rw [CPolynomial.eval_sub, eval_traceCoordinatePolynomialWith M D ctx hroot, + CPolynomial.eval_C, htrace] + ring + exact monicNormalize_root_of_root (gcdMonic_root_of_left_right hroot hwitnessRoot) + +/-- Roots of a trace-coordinate gcd bucket are roots of the parent in that bucket. -/ +theorem shoup_gcdBucket_root_iff {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {u : CPolynomial F} {a beta c : F} + (hu : u ≠ 0) : + CPolynomial.eval a + (CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c))) = 0 ↔ + CPolynomial.eval a u = 0 ∧ ctx.traceValue (beta * a) = c := by + letI : DecidableEq F := instDecidableEqOfLawfulBEq + let witness := traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c + have hgcdNe : CPolynomial.gcdMonic u witness ≠ 0 := gcdMonic_ne_zero_of_left hu + rw [monicNormalize_root_iff hgcdNe, gcdMonic_root_iff_left_right] + constructor + · intro h + rcases h with ⟨hroot, hwitness⟩ + refine ⟨hroot, ?_⟩ + dsimp [witness] at hwitness + rw [CPolynomial.eval_sub, eval_traceCoordinatePolynomialWith M D ctx hroot, + CPolynomial.eval_C] at hwitness + exact sub_eq_zero.mp hwitness + · intro h + rcases h with ⟨hroot, htrace⟩ + refine ⟨hroot, ?_⟩ + dsimp [witness] + rw [CPolynomial.eval_sub, eval_traceCoordinatePolynomialWith M D ctx hroot, + CPolynomial.eval_C, htrace] + ring + +private theorem monicNormalize_toPoly_dvd_self {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (p : CPolynomial F) : + (CPolynomial.monicNormalize p).toPoly ∣ p.toPoly := by + rw [CPolynomial.monicNormalize_toPoly_eq_normalize] + exact (normalize_associated p.toPoly).dvd + +private theorem gcdMonic_toPoly_dvd_left {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (p q : CPolynomial F) : + (CPolynomial.gcdMonic p q).toPoly ∣ p.toPoly := by + rw [CPolynomial.gcdMonic_toPoly_eq_normalize_gcd] + exact (normalize_associated (EuclideanDomain.gcd p.toPoly q.toPoly)).dvd.trans + (EuclideanDomain.gcd_dvd_left p.toPoly q.toPoly) + +private theorem pushNontrivialChild_mem_of_ne_zero_ne_one {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + {children : Array (CPolynomial F)} {child : CPolynomial F} + (h0 : child ≠ 0) (h1 : child ≠ 1) : + child ∈ (pushNontrivialChild children child).toList := by + unfold pushNontrivialChild + have hskip : ¬ (child == 0 || child == 1) = true := by + intro h + have hcases : child = 0 ∨ child = 1 := by + simpa using h + rcases hcases with hzero | hone + · exact h0 hzero + · exact h1 hone + rw [if_neg hskip] + simp + +private theorem pushNontrivialChild_mem_of_mem {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + {children : Array (CPolynomial F)} {child factor : CPolynomial F} + (hmem : factor ∈ children.toList) : + factor ∈ (pushNontrivialChild children child).toList := by + unfold pushNontrivialChild + by_cases hskip : (child == 0 || child == 1) = true + · rw [if_pos hskip] + exact hmem + · rw [if_neg hskip] + simp [hmem] + +private theorem mem_pushNontrivialChild {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + {children : Array (CPolynomial F)} {child factor : CPolynomial F} + (hmem : factor ∈ (pushNontrivialChild children child).toList) : + factor ∈ children.toList ∨ factor = child := by + unfold pushNontrivialChild at hmem + by_cases hskip : (child == 0 || child == 1) = true + · rw [if_pos hskip] at hmem + exact Or.inl hmem + · rw [if_neg hskip] at hmem + simp at hmem + rcases hmem with hmem | hfactor + · exact Or.inl (by simpa using hmem) + · exact Or.inr hfactor + +private theorem shoupRefineBaseConstants_root {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) {u : CPolynomial F} {a : F} + (hu : u ≠ 0) (hroot : CPolynomial.eval a u = 0) : + ∀ (constants : List F) (acc : Array (CPolynomial F)), + (∃ factor, factor ∈ acc.toList ∧ factor ≠ 0 ∧ CPolynomial.eval a factor = 0) ∨ + ctx.traceValue (beta * a) ∈ constants → + ∃ factor, + factor ∈ + (constants.foldl + (fun children c ↦ + let child := CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c)) + pushNontrivialChild children child) + acc).toList ∧ + factor ≠ 0 ∧ + CPolynomial.eval a factor = 0 := by + intro constants + induction constants with + | nil => + intro acc h + rcases h with hacc | hmem + · exact hacc + · simp at hmem + | cons c cs ih => + intro acc h + simp only [List.foldl_cons] + apply ih + rcases h with hacc | hmem + · left + rcases hacc with ⟨factor, hfactor, hfactorNe, hrootFactor⟩ + refine ⟨factor, pushNontrivialChild_mem_of_mem hfactor, hfactorNe, hrootFactor⟩ + · simp at hmem + rcases hmem with htarget | htail + · left + subst c + let child := CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - + CPolynomial.C (ctx.traceValue (beta * a)))) + have hchildRoot : CPolynomial.eval a child = 0 := by + dsimp [child] + exact shoup_gcdBucket_root M D ctx hroot rfl + have hgcdNe : CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - + CPolynomial.C (ctx.traceValue (beta * a))) ≠ 0 := + gcdMonic_ne_zero_of_left hu + have hchildNe : child ≠ 0 := monicNormalize_ne_zero_of_ne_zero hgcdNe + have hchildNotOne : child ≠ 1 := by + intro hone + rw [hone] at hchildRoot + rw [eval_one a] at hchildRoot + exact (one_ne_zero hchildRoot).elim + refine ⟨child, ?_, hchildNe, hchildRoot⟩ + exact pushNontrivialChild_mem_of_ne_zero_ne_one hchildNe hchildNotOne + · right + exact htail + +private theorem shoupRefineBaseConstants_dvd {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) {u : CPolynomial F} : + ∀ (constants : List F) (acc : Array (CPolynomial F)), + (∀ factor, factor ∈ acc.toList → factor.toPoly ∣ u.toPoly) → + ∀ factor, + factor ∈ + (constants.foldl + (fun children c ↦ + let child := CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c)) + pushNontrivialChild children child) + acc).toList → + factor.toPoly ∣ u.toPoly := by + letI : DecidableEq F := instDecidableEqOfLawfulBEq + intro constants + induction constants with + | nil => + intro acc hacc factor hmem + exact hacc factor hmem + | cons c cs ih => + intro acc hacc factor hmem + simp only [List.foldl_cons] at hmem + apply ih (pushNontrivialChild acc + (CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c)))) + · intro factor hfactor + rcases mem_pushNontrivialChild hfactor with hold | hnew + · exact hacc factor hold + · subst factor + exact (monicNormalize_toPoly_dvd_self + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c))).trans + (gcdMonic_toPoly_dvd_left u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c)) + · exact hmem + +private theorem shoupRefineFactorWith_root {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) {u : CPolynomial F} {a : F} + (hu : u ≠ 0) (hroot : CPolynomial.eval a u = 0) : + ∃ factor, + factor ∈ (shoupRefineFactorWith M D ctx beta u).toList ∧ + factor ≠ 0 ∧ + CPolynomial.eval a factor = 0 := by + unfold shoupRefineFactorWith + let u' := CPolynomial.monicNormalize u + have hu' : u' ≠ 0 := monicNormalize_ne_zero_of_ne_zero hu + have hroot' : CPolynomial.eval a u' = 0 := (monicNormalize_root_iff hu).2 hroot + by_cases hzero : (u' == 0 || u' == 1) = true + · have hcases : u' = 0 ∨ u' = 1 := by + simpa [u'] using hzero + rcases hcases with h0 | h1 + · exact (hu' h0).elim + · rw [h1] at hroot' + rw [eval_one a] at hroot' + exact (one_ne_zero hroot').elim + · rw [if_neg hzero] + by_cases hlin : isRepresentedLinearFactor u' = true + · rw [if_pos hlin] + refine ⟨u', ?_, hu', hroot'⟩ + simp [u'] + · rw [if_neg hlin] + rw [← Array.foldl_toList] + exact shoupRefineBaseConstants_root M D ctx beta hu' hroot' + ctx.baseConstants.toList #[] (Or.inr (ctx.traceValue_mem_base (beta * a))) + +private theorem shoupRefineFactorWith_dvd {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) {u factor : CPolynomial F} + (hmem : factor ∈ (shoupRefineFactorWith M D ctx beta u).toList) : + factor.toPoly ∣ u.toPoly := by + letI : DecidableEq F := instDecidableEqOfLawfulBEq + unfold shoupRefineFactorWith at hmem + let u' := CPolynomial.monicNormalize u + by_cases hzero : (u' == 0 || u' == 1) = true + · rw [if_pos hzero] at hmem + simp at hmem + · rw [if_neg hzero] at hmem + by_cases hlin : isRepresentedLinearFactor u' = true + · rw [if_pos hlin] at hmem + simp at hmem + subst factor + exact monicNormalize_toPoly_dvd_self u + · rw [if_neg hlin] at hmem + rw [← Array.foldl_toList] at hmem + have hdivU' : factor.toPoly ∣ u'.toPoly := + shoupRefineBaseConstants_dvd M D ctx beta ctx.baseConstants.toList #[] + (by + intro factor hfactor + simp at hfactor) + factor hmem + exact hdivU'.trans (monicNormalize_toPoly_dvd_self u) + +private theorem shoupRefineFactorsWith_root {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) + {factors : Array (CPolynomial F)} {a : F} + (hroot : + ∃ factor, + factor ∈ factors.toList ∧ factor ≠ 0 ∧ CPolynomial.eval a factor = 0) : + ∃ factor, + factor ∈ (shoupRefineFactorsWith M D ctx beta factors).toList ∧ + factor ≠ 0 ∧ + CPolynomial.eval a factor = 0 := by + unfold shoupRefineFactorsWith + rcases factors with ⟨factorList⟩ + rw [← Array.foldl_toList] + have hgo : ∀ (xs : List (CPolynomial F)) (acc : Array (CPolynomial F)), + (∃ factor, + factor ∈ acc.toList ∧ factor ≠ 0 ∧ CPolynomial.eval a factor = 0) ∨ + (∃ factor, + factor ∈ xs ∧ factor ≠ 0 ∧ CPolynomial.eval a factor = 0) → + ∃ factor, + factor ∈ + (xs.foldl + (fun out factor ↦ out ++ shoupRefineFactorWith M D ctx beta factor) + acc).toList ∧ + factor ≠ 0 ∧ + CPolynomial.eval a factor = 0 := by + intro xs + induction xs with + | nil => + intro acc h + rcases h with hacc | htail + · exact hacc + · rcases htail with ⟨factor, hmem, _⟩ + simp at hmem + | cons x xs ih => + intro acc h + simp only [List.foldl_cons] + apply ih + rcases h with hacc | htail + · left + rcases hacc with ⟨factor, hmem, hne, hrootFactor⟩ + refine ⟨factor, ?_, hne, hrootFactor⟩ + simpa using Array.mem_append_left + (shoupRefineFactorWith M D ctx beta x) (by simpa using hmem) + · rcases htail with ⟨factor, hmem, hne, hrootFactor⟩ + simp at hmem + rcases hmem with hhead | htail + · subst factor + left + rcases shoupRefineFactorWith_root M D ctx beta hne hrootFactor with + ⟨child, hchildMem, hchildNe, hchildRoot⟩ + refine ⟨child, ?_, hchildNe, hchildRoot⟩ + simpa using Array.mem_append_right acc (by simpa using hchildMem) + · right + exact ⟨factor, htail, hne, hrootFactor⟩ + exact hgo factorList #[] (Or.inr (by simpa using hroot)) + +private theorem shoupRefineFactorsWith_dvd {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) + {p factor : CPolynomial F} {factors : Array (CPolynomial F)} + (hparents : ∀ parent, parent ∈ factors.toList → parent.toPoly ∣ p.toPoly) + (hmem : factor ∈ (shoupRefineFactorsWith M D ctx beta factors).toList) : + factor.toPoly ∣ p.toPoly := by + unfold shoupRefineFactorsWith at hmem + rcases factors with ⟨factorList⟩ + rw [← Array.foldl_toList] at hmem + have hgo : ∀ (xs : List (CPolynomial F)) (out : Array (CPolynomial F)), + (∀ child, child ∈ out.toList → child.toPoly ∣ p.toPoly) → + (∀ parent, parent ∈ xs → parent.toPoly ∣ p.toPoly) → + ∀ child, + child ∈ + (xs.foldl + (fun out factor ↦ out ++ shoupRefineFactorWith M D ctx beta factor) + out).toList → + child.toPoly ∣ p.toPoly := by + intro xs + induction xs with + | nil => + intro out hout _ child hchild + exact hout child hchild + | cons x xs ih => + intro out hout hxs child hchild + simp only [List.foldl_cons] at hchild + apply ih (out ++ shoupRefineFactorWith M D ctx beta x) + · intro child hmemChild + simp at hmemChild + rcases hmemChild with hleft | hright + · exact hout child (by simpa using hleft) + · exact (shoupRefineFactorWith_dvd M D ctx beta (by simpa using hright)).trans + (hxs x (by simp)) + · intro parent hparent + exact hxs parent (by simp [hparent]) + · exact hchild + exact hgo factorList #[] + (by + intro child hchild + simp at hchild) + (by + intro parent hparent + exact hparents parent (by simpa using hparent)) + factor hmem + +private theorem shoupRefineBasisWith_root {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) : + ∀ (basis : List F) (factors : Array (CPolynomial F)) {a : F}, + (∃ factor, + factor ∈ factors.toList ∧ factor ≠ 0 ∧ CPolynomial.eval a factor = 0) → + ∃ factor, + factor ∈ + (basis.foldl + (fun factors beta ↦ shoupRefineFactorsWith M D ctx beta factors) + factors).toList ∧ + factor ≠ 0 ∧ + CPolynomial.eval a factor = 0 := by + intro basis + induction basis with + | nil => + intro factors a hroot + exact hroot + | cons beta rest ih => + intro factors a hroot + simp only [List.foldl_cons] + exact ih (shoupRefineFactorsWith M D ctx beta factors) + (shoupRefineFactorsWith_root M D ctx beta hroot) + +private theorem shoupRefineBasisWith_dvd {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p : CPolynomial F} : + ∀ (basis : List F) (factors : Array (CPolynomial F)) {factor : CPolynomial F}, + (∀ parent, parent ∈ factors.toList → parent.toPoly ∣ p.toPoly) → + factor ∈ + (basis.foldl + (fun factors beta ↦ shoupRefineFactorsWith M D ctx beta factors) + factors).toList → + factor.toPoly ∣ p.toPoly := by + intro basis + induction basis with + | nil => + intro factors factor hparents hmem + exact hparents factor hmem + | cons beta rest ih => + intro factors factor hparents hmem + simp only [List.foldl_cons] at hmem + apply ih (shoupRefineFactorsWith M D ctx beta factors) + · intro parent hparent + exact shoupRefineFactorsWith_dvd M D ctx beta hparents hparent + · exact hmem + +private theorem representedLinearFactor_root_unique {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + {p : CPolynomial F} {a b : F} + (hlin : isRepresentedLinearFactor p = true) + (ha : CPolynomial.eval a p = 0) (hb : CPolynomial.eval b p = 0) : + b = a := by + have ca := representedLinearFactor_candidate_of_root hlin ha + have cb := representedLinearFactor_candidate_of_root hlin hb + have haeq : p.coeff 1 * a = -p.coeff 0 := by + have h := ca.2 + rw [add_eq_zero_iff_eq_neg] at h + rw [h] + simp + have hbeq : p.coeff 1 * b = -p.coeff 0 := by + have h := cb.2 + rw [add_eq_zero_iff_eq_neg] at h + rw [h] + simp + have hsub : p.coeff 1 * (b - a) = 0 := by + rw [mul_sub, hbeq, haeq, sub_self] + have hbmina : b - a = 0 := (mul_eq_zero.mp hsub).resolve_left ca.1.2 + exact sub_eq_zero.mp hbmina + +private theorem monicNormalize_zero {F : Type*} + [Field F] [BEq F] [LawfulBEq F] : + CPolynomial.monicNormalize (0 : CPolynomial F) = 0 := by + unfold CPolynomial.monicNormalize CPolynomial.Raw.monicNormalize CPolynomial.ofArray + apply Subtype.ext + change + (if ((0 : CPolynomial F).val : CPolynomial.Raw F).trim == 0 then + (0 : CPolynomial.Raw F) + else + ((0 : CPolynomial F).val : CPolynomial.Raw F).trim.leadingCoeff⁻¹ • + ((0 : CPolynomial F).val : CPolynomial.Raw F).trim).trim = + (0 : CPolynomial.Raw F) + rw [if_pos] + · exact CPolynomial.Raw.zero_canonical + · change (((0 : CPolynomial.Raw F).trim) == 0) = true + rw [CPolynomial.Raw.zero_canonical] + rfl + +private def rootsAgreeOn {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) (coords : List F) (factor : CPolynomial F) : + Prop := + ∀ a b : F, CPolynomial.eval a factor = 0 → CPolynomial.eval b factor = 0 → + ∀ beta, beta ∈ coords → + ctx.traceValue (beta * a) = ctx.traceValue (beta * b) + +private theorem rootsAgreeOn_of_root_unique {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) (coords : List F) {factor : CPolynomial F} + (hunique : ∀ {a b : F}, CPolynomial.eval a factor = 0 → + CPolynomial.eval b factor = 0 → b = a) : + rootsAgreeOn ctx coords factor := by + intro a b hrootA hrootB beta _hbeta + have hba : b = a := hunique hrootA hrootB + subst b + rfl + +private theorem rootsAgreeOn_monicNormalize {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) (coords : List F) {u : CPolynomial F} + (hu : u ≠ 0) (huAgree : rootsAgreeOn ctx coords u) : + rootsAgreeOn ctx coords (CPolynomial.monicNormalize u) := by + intro a b hrootA hrootB beta hbeta + exact huAgree a b ((monicNormalize_root_iff hu).1 hrootA) + ((monicNormalize_root_iff hu).1 hrootB) beta hbeta + +private theorem shoupRefineBaseConstants_rootsAgreeOn {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) {u : CPolynomial F} + (hu : u ≠ 0) {coords : List F} + (huAgree : rootsAgreeOn ctx coords u) : + ∀ (constants : List F) (acc : Array (CPolynomial F)), + (∀ factor, factor ∈ acc.toList → + rootsAgreeOn ctx (coords ++ [beta]) factor) → + ∀ factor, + factor ∈ + (constants.foldl + (fun children c ↦ + let child := CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c)) + pushNontrivialChild children child) + acc).toList → + rootsAgreeOn ctx (coords ++ [beta]) factor := by + intro constants + induction constants with + | nil => + intro acc hacc factor hmem + exact hacc factor hmem + | cons c cs ih => + intro acc hacc factor hmem + simp only [List.foldl_cons] at hmem + apply ih (pushNontrivialChild acc + (CPolynomial.monicNormalize + (CPolynomial.gcdMonic u + (traceCoordinatePolynomialWith M D ctx u beta - CPolynomial.C c)))) + · intro factor hfactor + rcases mem_pushNontrivialChild hfactor with hold | hnew + · exact hacc factor hold + · subst factor + intro a b hrootA hrootB gamma hgamma + rw [List.mem_append] at hgamma + rcases hgamma with hgamma | hgamma + · exact huAgree + a b + ((shoup_gcdBucket_root_iff M D ctx hu).1 hrootA).1 + ((shoup_gcdBucket_root_iff M D ctx hu).1 hrootB).1 + gamma hgamma + · simp at hgamma + subst gamma + exact (((shoup_gcdBucket_root_iff M D ctx hu).1 hrootA).2).trans + (((shoup_gcdBucket_root_iff M D ctx hu).1 hrootB).2).symm + · exact hmem + +private theorem shoupRefineFactorWith_rootsAgreeOn {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) {u factor : CPolynomial F} + {coords : List F} + (huAgree : rootsAgreeOn ctx coords u) + (hmem : factor ∈ (shoupRefineFactorWith M D ctx beta u).toList) : + rootsAgreeOn ctx (coords ++ [beta]) factor := by + unfold shoupRefineFactorWith at hmem + let u' := CPolynomial.monicNormalize u + by_cases hzero : (u' == 0 || u' == 1) = true + · rw [if_pos hzero] at hmem + simp at hmem + · rw [if_neg hzero] at hmem + by_cases hlin : isRepresentedLinearFactor u' = true + · rw [if_pos hlin] at hmem + simp at hmem + subst factor + exact rootsAgreeOn_of_root_unique ctx (coords ++ [beta]) + (fun hrootA hrootB ↦ + representedLinearFactor_root_unique hlin hrootA hrootB) + · rw [if_neg hlin] at hmem + rw [← Array.foldl_toList] at hmem + have hu' : u' ≠ 0 := by + intro hz + have hskip : (u' == 0 || u' == 1) = true := by + simp [hz] + exact hzero hskip + have hu : u ≠ 0 := by + intro hz + subst u + exact hu' (by simpa [u'] using (monicNormalize_zero : CPolynomial.monicNormalize + (0 : CPolynomial F) = 0)) + have huAgree' : rootsAgreeOn ctx coords u' := + rootsAgreeOn_monicNormalize ctx coords hu huAgree + exact shoupRefineBaseConstants_rootsAgreeOn M D ctx beta hu' + huAgree' ctx.baseConstants.toList #[] (by + intro factor hfactor + simp at hfactor) factor hmem + +private theorem shoupRefineFactorsWith_rootsAgreeOn {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) (beta : F) + {coords : List F} {factors : Array (CPolynomial F)} {factor : CPolynomial F} + (hparents : ∀ parent, parent ∈ factors.toList → + rootsAgreeOn ctx coords parent) + (hmem : factor ∈ (shoupRefineFactorsWith M D ctx beta factors).toList) : + rootsAgreeOn ctx (coords ++ [beta]) factor := by + unfold shoupRefineFactorsWith at hmem + rcases factors with ⟨factorList⟩ + rw [← Array.foldl_toList] at hmem + have hgo : ∀ (xs : List (CPolynomial F)) (out : Array (CPolynomial F)), + (∀ child, child ∈ out.toList → + rootsAgreeOn ctx (coords ++ [beta]) child) → + (∀ parent, parent ∈ xs → rootsAgreeOn ctx coords parent) → + ∀ child, + child ∈ + (xs.foldl + (fun out factor ↦ out ++ shoupRefineFactorWith M D ctx beta factor) + out).toList → + rootsAgreeOn ctx (coords ++ [beta]) child := by + intro xs + induction xs with + | nil => + intro out hout _ child hchild + exact hout child hchild + | cons x xs ih => + intro out hout hxs child hchild + simp only [List.foldl_cons] at hchild + apply ih (out ++ shoupRefineFactorWith M D ctx beta x) + · intro child hmemChild + simp at hmemChild + rcases hmemChild with hleft | hright + · exact hout child (by simpa using hleft) + · exact shoupRefineFactorWith_rootsAgreeOn M D ctx beta + (hxs x (by simp)) (by simpa using hright) + · intro parent hparent + exact hxs parent (by simp [hparent]) + · exact hchild + exact hgo factorList #[] + (by + intro child hchild + simp at hchild) + (by + intro parent hparent + exact hparents parent (by simpa using hparent)) + factor hmem + +private theorem shoupRefineBasisWith_rootsAgreeOn {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) : + ∀ (basis coords : List F) (factors : Array (CPolynomial F)) {factor : CPolynomial F}, + (∀ parent, parent ∈ factors.toList → rootsAgreeOn ctx coords parent) → + factor ∈ + (basis.foldl + (fun factors beta ↦ shoupRefineFactorsWith M D ctx beta factors) + factors).toList → + rootsAgreeOn ctx (coords ++ basis) factor := by + intro basis + induction basis with + | nil => + intro coords factors factor hparents hmem + simpa using hparents factor hmem + | cons beta rest ih => + intro coords factors factor hparents hmem + simp only [List.foldl_cons] at hmem + have hstep : + ∀ parent, parent ∈ (shoupRefineFactorsWith M D ctx beta factors).toList → + rootsAgreeOn ctx (coords ++ [beta]) parent := by + intro parent hparent + exact shoupRefineFactorsWith_rootsAgreeOn M D ctx beta hparents hparent + have hfinal := ih (coords ++ [beta]) + (shoupRefineFactorsWith M D ctx beta factors) hstep hmem + simpa [List.append_assoc] using hfinal + +theorem shoupSplitCandidatesWith_root {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p : CPolynomial F} {a : F} + (hp : p ≠ 0) (hroot : CPolynomial.eval a p = 0) : + ∃ factor, + factor ∈ (shoupSplitCandidatesWith M D ctx p).toList ∧ + factor ≠ 0 ∧ + CPolynomial.eval a factor = 0 := by + unfold shoupSplitCandidatesWith + let p' := CPolynomial.monicNormalize p + have hp' : p' ≠ 0 := monicNormalize_ne_zero_of_ne_zero hp + have hroot' : CPolynomial.eval a p' = 0 := (monicNormalize_root_iff hp).2 hroot + by_cases hzero : (p' == 0 || p' == 1) = true + · have hcases : p' = 0 ∨ p' = 1 := by + simpa [p'] using hzero + rcases hcases with h0 | h1 + · exact (hp' h0).elim + · rw [h1] at hroot' + rw [eval_one a] at hroot' + exact (one_ne_zero hroot').elim + · rw [if_neg hzero] + by_cases hlin : isRepresentedLinearFactor p' = true + · rw [if_pos hlin] + refine ⟨p', ?_, hp', hroot'⟩ + simp [p'] + · rw [if_neg hlin] + rw [← Array.foldl_toList] + exact shoupRefineBasisWith_root M D ctx ctx.basis.toList #[p'] + ⟨p', by simp [p'], hp', hroot'⟩ + +theorem shoupSplitCandidatesWith_dvd_input {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p factor : CPolynomial F} + (hmem : factor ∈ (shoupSplitCandidatesWith M D ctx p).toList) : + factor.toPoly ∣ p.toPoly := by + letI : DecidableEq F := instDecidableEqOfLawfulBEq + unfold shoupSplitCandidatesWith at hmem + let p' := CPolynomial.monicNormalize p + by_cases hzero : (p' == 0 || p' == 1) = true + · rw [if_pos hzero] at hmem + simp at hmem + · rw [if_neg hzero] at hmem + by_cases hlin : isRepresentedLinearFactor p' = true + · rw [if_pos hlin] at hmem + simp at hmem + subst factor + exact monicNormalize_toPoly_dvd_self p + · rw [if_neg hlin] at hmem + rw [← Array.foldl_toList] at hmem + exact shoupRefineBasisWith_dvd M D ctx ctx.basis.toList #[p'] + (by + intro parent hparent + simp at hparent + subst parent + exact monicNormalize_toPoly_dvd_self p) + hmem + +/- The remaining algorithmic invariant: two field roots of the same final Shoup +candidate have equal trace coordinates for every basis element, hence are equal. -/ +private theorem shoupSplitCandidatesWith_root_unique {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p factor : CPolynomial F} {a b : F} + (hmem : factor ∈ (shoupSplitCandidatesWith M D ctx p).toList) + (hrootA : CPolynomial.eval a factor = 0) + (hrootB : CPolynomial.eval b factor = 0) : + b = a := by + unfold shoupSplitCandidatesWith at hmem + let p' := CPolynomial.monicNormalize p + by_cases hzero : (p' == 0 || p' == 1) = true + · rw [if_pos hzero] at hmem + simp at hmem + · rw [if_neg hzero] at hmem + by_cases hlin : isRepresentedLinearFactor p' = true + · rw [if_pos hlin] at hmem + simp at hmem + subst factor + exact representedLinearFactor_root_unique hlin hrootA hrootB + · rw [if_neg hlin] at hmem + rw [← Array.foldl_toList] at hmem + have hagree : rootsAgreeOn ctx ctx.basis.toList factor := by + have hbasis := shoupRefineBasisWith_rootsAgreeOn M D ctx + ctx.basis.toList [] #[p'] (by + intro parent hparent + simp at hparent + subst parent + intro x y hrootX hrootY beta hbeta + simp at hbeta) hmem + simpa using hbasis + exact (eq_of_traceValue_eq_on_basis ctx + (fun beta hbeta ↦ hagree a b hrootA hrootB beta hbeta)).symm + +/-- +Remaining Shoup linearization obligation. + +The checked lemmas above show that candidates divide the valid root product and +that valid divisors of `X^q - X` with a unique field root are represented +linear. The remaining algorithmic proof is `shoupSplitCandidatesWith_root_unique`. +-/ +private theorem shoupSplitCandidatesWith_valid_factor_represented {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p factor : CPolynomial F} {a : F} + (hvalid : shoupSplitterInput ctx p) + (hmem : factor ∈ (shoupSplitCandidatesWith M D ctx p).toList) + (hfactorNe : factor ≠ 0) + (hfactorRoot : CPolynomial.eval a factor = 0) : + isRepresentedLinearFactor factor = true := by + exact isRepresentedLinearFactor_of_dvd_frobenius_unique_root ctx hfactorNe + ((shoupSplitCandidatesWith_dvd_input M D ctx hmem).trans hvalid.2) + hfactorRoot (fun b hrootB ↦ + shoupSplitCandidatesWith_root_unique M D ctx hmem hfactorRoot hrootB) + +/-- The Shoup splitter is complete for valid root-product inputs. -/ +theorem shoupSplitLinearFactorsWith_complete {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p : CPolynomial F} {a : F} + (hvalid : shoupSplitterInput ctx p) + (hp : p ≠ 0) (hroot : CPolynomial.eval a p = 0) : + ∃ factor, + factor ∈ (shoupSplitLinearFactorsWith M D ctx p).toList ∧ + IsLinearRootFactorCandidate factor a := by + rcases shoupSplitCandidatesWith_root M D ctx hp hroot with + ⟨factor, hmem, hfactorNe, hfactorRoot⟩ + have hlin : isRepresentedLinearFactor factor = true := + shoupSplitCandidatesWith_valid_factor_represented M D ctx hvalid hmem + hfactorNe hfactorRoot + refine ⟨factor, ?_, representedLinearFactor_candidate_of_root hlin hfactorRoot⟩ + unfold shoupSplitLinearFactorsWith + exact representedLinearFactorsOnly_mem_of_mem hmem hlin + +/-- Adapt the Shoup trace splitter to the generic linear-factor-product interface. -/ +def shoupLinearFactorProductSplitterWith {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) : + LinearFactorProductSplitter F where + splitLinearFactors := fun _q p ↦ shoupSplitLinearFactorsWith M D ctx p + validInput := fun _q p ↦ shoupSplitterInput ctx p + sound := by + intro _q p factor h + exact shoupSplitLinearFactorsWith_sound M D ctx h + complete := by + intro _q p a hvalid hp hroot + exact shoupSplitLinearFactorsWith_complete M D ctx hvalid hp hroot + +/-- Shoup trace splitter using the default raw multiplication and remainder backends. -/ +def shoupLinearFactorProductSplitter {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) : + LinearFactorProductSplitter F := + shoupLinearFactorProductSplitterWith CPolynomial.Raw.MulContext.naive + CPolynomial.Raw.ModContext.naive ctx + +/-- The Shoup splitter only emits represented linear factors. -/ +theorem shoupLinearFactorProductSplitterWith_sound {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {q : Nat} {p factor : CPolynomial F} + (h : factor ∈ + ((shoupLinearFactorProductSplitterWith M D ctx).splitLinearFactors q p).toList) : + IsLinearFactor factor := by + exact (shoupLinearFactorProductSplitterWith M D ctx).sound q p factor h + +/-- The Shoup splitter is complete for valid root-product inputs. -/ +theorem shoupLinearFactorProductSplitterWith_complete {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {q : Nat} {p : CPolynomial F} {a : F} + (hvalid : (shoupLinearFactorProductSplitterWith M D ctx).validInput q p) + (hp : p ≠ 0) (hroot : CPolynomial.eval a p = 0) : + ∃ factor, + factor ∈ + ((shoupLinearFactorProductSplitterWith M D ctx).splitLinearFactors q p).toList ∧ + IsLinearRootFactorCandidate factor a := by + exact (shoupLinearFactorProductSplitterWith M D ctx).complete q p a hvalid hp hroot + +private theorem raw_monicNormalize_trim {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (p : CPolynomial.Raw F) : + (CPolynomial.Raw.monicNormalize p).trim = CPolynomial.Raw.monicNormalize p := by + unfold CPolynomial.Raw.monicNormalize + let q := p.trim + by_cases hzero : q == (0 : CPolynomial.Raw F) + · have hzeroEq : q = 0 := by + simpa using hzero + have hpzeroEq : p.trim = (#[] : CPolynomial.Raw F) := by + simpa [q] using hzeroEq + simp [hpzeroEq, CPolynomial.Raw.Trim.canonical_empty] + · have hzeroNe : q ≠ (0 : CPolynomial.Raw F) := by + intro hq + exact hzero (by simp [hq]) + have hpzeroNe : ¬p.trim = (#[] : CPolynomial.Raw F) := by + intro hp + exact hzeroNe (by simpa [q] using hp) + simp [hpzeroNe] + change (CPolynomial.Raw.mk + (Array.map (fun r ↦ (p.trim).leadingCoeff⁻¹ * r) p.trim)).trim = + CPolynomial.Raw.mk (Array.map (fun r ↦ (p.trim).leadingCoeff⁻¹ * r) p.trim) + apply CPolynomial.Raw.Trim.non_zero_map (fun r ↦ q.leadingCoeff⁻¹ * r) + · intro r hr + apply mul_eq_zero.mp at hr + rcases hr with hinv | hr + · have hlead0 : q.leadingCoeff = 0 := by + exact inv_eq_zero.mp hinv + have hcanon : q.trim = q := by + simpa [q] using CPolynomial.Raw.Trim.trim_twice p + have hcrit := (CPolynomial.Raw.Trim.trim_eq_iff_size_eq_zero_or_getLastD_ne_zero + (p := q)).mp hcanon + rcases hcrit with hsize | hlast + · have hqempty : q = (#[] : CPolynomial.Raw F) := by + apply Array.eq_empty_of_size_eq_zero + exact hsize + exact False.elim (hzero (by simp [hqempty])) + · unfold CPolynomial.Raw.leadingCoeff at hlead0 + rw [hcanon] at hlead0 + exact (hlast hlead0).elim + · exact hr + · simpa [q] using CPolynomial.Raw.Trim.trim_twice p + +private theorem raw_monicNormalize_trim_arg {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (p : CPolynomial.Raw F) : + CPolynomial.Raw.monicNormalize p.trim = CPolynomial.Raw.monicNormalize p := by + unfold CPolynomial.Raw.monicNormalize + rw [CPolynomial.Raw.Trim.trim_twice] + +private theorem raw_monicNormalize_toPoly_eq_normalize {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (p : CPolynomial.Raw F) : + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize p)).toPoly = + normalize (CPolynomial.ofArray p).toPoly := by + have h := CPolynomial.monicNormalize_toPoly_eq_normalize (CPolynomial.ofArray p) + unfold CPolynomial.monicNormalize at h + unfold CPolynomial.ofArray at h + rw [raw_monicNormalize_trim_arg] at h + exact h + +private theorem raw_monicNormalize_toPoly_monic {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + {p : CPolynomial.Raw F} (hp : p.trim ≠ 0) : + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize p)).toPoly.Monic := by + rw [raw_monicNormalize_toPoly_eq_normalize] + have hpC : CPolynomial.ofArray p ≠ 0 := by + intro h + have hval := congrArg Subtype.val h + unfold CPolynomial.ofArray at hval + exact hp (by simpa using hval) + have hpPoly : (CPolynomial.ofArray p).toPoly ≠ 0 := + (CPolynomial.toPoly_eq_zero_iff (CPolynomial.ofArray p)).not.mpr hpC + exact Polynomial.monic_normalize hpPoly + +private theorem raw_modContext_toPoly_eq_modByMonic {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (D : CPolynomial.Raw.ModContext F) {p q : CPolynomial.Raw F} + (hpTrim : p.trim = p) (hqTrim : q.trim = q) + (hqMonic : (CPolynomial.ofArray q).monic) : + (CPolynomial.ofArray (D.modByMonic p q)).toPoly = + (CPolynomial.ofArray p).toPoly %ₘ (CPolynomial.ofArray q).toPoly := by + rw [D.modByMonic_eq_modByMonic p q hpTrim hqTrim] + have hpval : (CPolynomial.ofArray p).val = p := by + unfold CPolynomial.ofArray + exact hpTrim + have hqval : (CPolynomial.ofArray q).val = q := by + unfold CPolynomial.ofArray + exact hqTrim + have h := CPolynomial.modByMonic_toPoly_eq_modByMonic + (CPolynomial.ofArray p) (CPolynomial.ofArray q) hqMonic + simpa [CPolynomial.modByMonic, hpval, hqval, CPolynomial.ofArray_toPoly] using h + +private theorem raw_mulModWith_toPoly_eq_modByMonic {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + {modulus p q : CPolynomial.Raw F} (hmod : modulus.trim ≠ 0) : + (CPolynomial.ofArray (CPolynomial.Raw.mulModWith M D modulus p q)).toPoly = + ((CPolynomial.ofArray p).toPoly * (CPolynomial.ofArray q).toPoly) %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly := by + unfold CPolynomial.Raw.mulModWith + have hzero : ¬modulus.trim == (0 : CPolynomial.Raw F) := by + intro h + exact hmod (LawfulBEq.eq_of_beq h) + rw [if_neg hzero] + have hproductTrim : (M.mul p q).trim = M.mul p q := by + rw [M.mul_eq_mul] + exact CPolynomial.Raw.mul_is_trimmed p q + have hqMonic : (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).monic := + (CPolynomial.monic_toPoly_iff _).mpr (raw_monicNormalize_toPoly_monic hmod) + rw [raw_modContext_toPoly_eq_modByMonic D hproductTrim + (raw_monicNormalize_trim modulus) hqMonic] + rw [M.mul_eq_mul, CPolynomial.ofArray_toPoly, CPolynomial.ofArray_toPoly, + CPolynomial.Raw.toPoly_mul] + rw [CPolynomial.ofArray_toPoly, CPolynomial.ofArray_toPoly] + +private theorem polynomial_modByMonic_idem {F : Type*} [Field F] + {p q : Polynomial F} (hq : q.Monic) : + (p %ₘ q) %ₘ q = p %ₘ q := by + refine Polynomial.modByMonic_eq_of_dvd_sub hq ?_ + refine ⟨-(p /ₘ q), ?_⟩ + calc + p %ₘ q - p = p %ₘ q - (p %ₘ q + q * (p /ₘ q)) := by + rw [Polynomial.modByMonic_add_div p] + _ = q * -(p /ₘ q) := by + ring + +private theorem polynomial_mul_modByMonic_congr {F : Type*} [Field F] + {a b c d m : Polynomial F} + (ha : a %ₘ m = b %ₘ m) (hc : c %ₘ m = d %ₘ m) : + (a * c) %ₘ m = (b * d) %ₘ m := by + calc + (a * c) %ₘ m = (a %ₘ m * (c %ₘ m)) %ₘ m := by + rw [Polynomial.mul_modByMonic] + _ = (b %ₘ m * (d %ₘ m)) %ₘ m := by + rw [ha, hc] + _ = (b * d) %ₘ m := by + exact (Polynomial.mul_modByMonic b d m).symm + +private theorem polynomial_pow_modByMonic_congr {F : Type*} [Field F] + {a b m : Polynomial F} (h : a %ₘ m = b %ₘ m) : + ∀ n, a ^ n %ₘ m = b ^ n %ₘ m := by + intro n + induction n with + | zero => simp + | succ n ih => + rw [pow_succ, pow_succ] + exact polynomial_mul_modByMonic_congr ih h + +private theorem raw_powModBinaryAuxWith_toPoly_modByMonic {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + {modulus acc current : CPolynomial.Raw F} (hmod : modulus.trim ≠ 0) : + ∀ n, + (CPolynomial.ofArray + (CPolynomial.Raw.powModBinaryAuxWith M D modulus n acc current)).toPoly %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly = + ((CPolynomial.ofArray acc).toPoly * (CPolynomial.ofArray current).toPoly ^ n) %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly := by + intro n + induction n using Nat.strongRecOn generalizing acc current with + | ind n ih => + cases n with + | zero => + rw [CPolynomial.Raw.powModBinaryAuxWith, pow_zero] + congr 1 + ring + | succ n => + rw [CPolynomial.Raw.powModBinaryAuxWith] + let m := (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly + let acc' := + if (n + 1) % 2 == 1 then + CPolynomial.Raw.mulModWith M D modulus acc current + else + acc + let current' := CPolynomial.Raw.mulModWith M D modulus current current + have ih' := ih ((n + 1) / 2) + (Nat.div_lt_self (Nat.succ_pos n) (by decide)) + (acc := acc') (current := current') + change + (CPolynomial.ofArray + (CPolynomial.Raw.powModBinaryAuxWith M D modulus + ((n + 1) / 2) acc' current')).toPoly %ₘ + m = + ((CPolynomial.ofArray acc).toPoly * + (CPolynomial.ofArray current).toPoly ^ (n + 1)) %ₘ m + rw [ih'] + have hcurrent : + (CPolynomial.ofArray current').toPoly %ₘ m = + ((CPolynomial.ofArray current).toPoly * + (CPolynomial.ofArray current).toPoly) %ₘ m := by + dsimp [current', m] + rw [raw_mulModWith_toPoly_eq_modByMonic M D hmod] + exact polynomial_modByMonic_idem (raw_monicNormalize_toPoly_monic hmod) + by_cases hodd : (n + 1) % 2 == 1 + · have hacc : + (CPolynomial.ofArray acc').toPoly %ₘ m = + ((CPolynomial.ofArray acc).toPoly * + (CPolynomial.ofArray current).toPoly) %ₘ m := by + dsimp [acc', m] + rw [if_pos hodd] + rw [raw_mulModWith_toPoly_eq_modByMonic M D hmod] + exact polynomial_modByMonic_idem (raw_monicNormalize_toPoly_monic hmod) + have hpow : + ((CPolynomial.ofArray current).toPoly * + (CPolynomial.ofArray current).toPoly) ^ ((n + 1) / 2) = + (CPolynomial.ofArray current).toPoly ^ n := by + rw [mul_pow, ← pow_add] + congr 1 + have hoddNat : (n + 1) % 2 = 1 := by + simpa using hodd + omega + have hcurrentPow : + (CPolynomial.ofArray current').toPoly ^ ((n + 1) / 2) %ₘ m = + (CPolynomial.ofArray current).toPoly ^ n %ₘ m := by + have h := polynomial_pow_modByMonic_congr hcurrent ((n + 1) / 2) + rwa [hpow] at h + calc + ((CPolynomial.ofArray acc').toPoly * + (CPolynomial.ofArray current').toPoly ^ ((n + 1) / 2)) %ₘ m = + (((CPolynomial.ofArray acc).toPoly * + (CPolynomial.ofArray current).toPoly) * + (CPolynomial.ofArray current).toPoly ^ n) %ₘ m := by + exact polynomial_mul_modByMonic_congr hacc hcurrentPow + _ = ((CPolynomial.ofArray acc).toPoly * + (CPolynomial.ofArray current).toPoly ^ (n + 1)) %ₘ m := by + rw [pow_succ] + ring_nf + · have hacc : + (CPolynomial.ofArray acc').toPoly %ₘ m = + (CPolynomial.ofArray acc).toPoly %ₘ m := by + dsimp [acc'] + rw [if_neg hodd] + have hpow : + ((CPolynomial.ofArray current).toPoly * + (CPolynomial.ofArray current).toPoly) ^ ((n + 1) / 2) = + (CPolynomial.ofArray current).toPoly ^ (n + 1) := by + rw [mul_pow, ← pow_add] + congr 1 + have hoddNat : (n + 1) % 2 = 0 := by + simpa using hodd + omega + have hcurrentPow : + (CPolynomial.ofArray current').toPoly ^ ((n + 1) / 2) %ₘ m = + (CPolynomial.ofArray current).toPoly ^ (n + 1) %ₘ m := by + have h := polynomial_pow_modByMonic_congr hcurrent ((n + 1) / 2) + rwa [hpow] at h + exact polynomial_mul_modByMonic_congr hacc hcurrentPow + +private theorem raw_powModWith_X_toPoly_modByMonic {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + {modulus : CPolynomial.Raw F} (hmod : modulus.trim ≠ 0) (q : Nat) : + (CPolynomial.ofArray + (CPolynomial.Raw.powModWith M D modulus CPolynomial.Raw.X q)).toPoly %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly = + ((Polynomial.X : Polynomial F) ^ q) %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly := by + unfold CPolynomial.Raw.powModWith + have hzero : ¬modulus.trim == (0 : CPolynomial.Raw F) := by + intro h + exact hmod (LawfulBEq.eq_of_beq h) + rw [if_neg hzero] + let m := (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly + let oneMod := D.modByMonic (1 : CPolynomial.Raw F) (CPolynomial.Raw.monicNormalize modulus) + change + (CPolynomial.ofArray + (CPolynomial.Raw.powModBinaryAuxWith M D modulus q oneMod CPolynomial.Raw.X)).toPoly %ₘ + m = + ((Polynomial.X : Polynomial F) ^ q) %ₘ m + rw [raw_powModBinaryAuxWith_toPoly_modByMonic M D hmod] + have hOneTrim : (1 : CPolynomial.Raw F).trim = 1 := by + change CPolynomial.Raw.trim (#[] |>.push (1 : F)) = (#[] |>.push (1 : F)) + apply CPolynomial.Raw.Trim.push_trim + simp + have hone : + (CPolynomial.ofArray oneMod).toPoly %ₘ m = + (1 : Polynomial F) %ₘ m := by + dsimp [oneMod, m] + rw [raw_modContext_toPoly_eq_modByMonic D hOneTrim + (raw_monicNormalize_trim modulus) + ((CPolynomial.monic_toPoly_iff _).mpr (raw_monicNormalize_toPoly_monic hmod))] + rw [CPolynomial.ofArray_toPoly, CPolynomial.Raw.toPoly_one] + exact polynomial_modByMonic_idem (raw_monicNormalize_toPoly_monic hmod) + have hX : + (CPolynomial.ofArray CPolynomial.Raw.X).toPoly ^ q %ₘ m = + ((Polynomial.X : Polynomial F) ^ q) %ₘ m := by + rw [CPolynomial.ofArray_toPoly, CPolynomial.Raw.toPoly_X] + have hmul := polynomial_mul_modByMonic_congr hone hX + simpa [one_mul] using hmul + +private theorem raw_xModWith_toPoly_modByMonic {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (D : CPolynomial.Raw.ModContext F) + {modulus : CPolynomial.Raw F} (hmod : modulus.trim ≠ 0) : + (CPolynomial.ofArray (CPolynomial.Raw.xModWith D modulus)).toPoly %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly = + (Polynomial.X : Polynomial F) %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly := by + unfold CPolynomial.Raw.xModWith + have hzero : ¬modulus.trim == (0 : CPolynomial.Raw F) := by + intro h + exact hmod (LawfulBEq.eq_of_beq h) + rw [if_neg hzero] + let m := (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly + have hXTrim : (CPolynomial.Raw.X : CPolynomial.Raw F).trim = CPolynomial.Raw.X := by + exact CPolynomial.Raw.X_canonical + rw [raw_modContext_toPoly_eq_modByMonic D hXTrim + (raw_monicNormalize_trim modulus) + ((CPolynomial.monic_toPoly_iff _).mpr (raw_monicNormalize_toPoly_monic hmod))] + rw [CPolynomial.ofArray_toPoly, CPolynomial.Raw.toPoly_X] + exact polynomial_modByMonic_idem (raw_monicNormalize_toPoly_monic hmod) + +private theorem raw_xPowSubXModWith_toPoly_modByMonic {F : Type*} + [Field F] [BEq F] [LawfulBEq F] [DecidableEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + {modulus : CPolynomial.Raw F} (hmod : modulus.trim ≠ 0) (q : Nat) : + (CPolynomial.ofArray + (CPolynomial.Raw.xPowSubXModWith M D q modulus)).toPoly %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly = + (((Polynomial.X : Polynomial F) ^ q - Polynomial.X) %ₘ + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize modulus)).toPoly) := by + unfold CPolynomial.Raw.xPowSubXModWith + rw [CPolynomial.ofArray_toPoly, CPolynomial.Raw.toPoly_sub, Polynomial.sub_modByMonic] + rw [← CPolynomial.ofArray_toPoly + (CPolynomial.Raw.powModWith M D modulus CPolynomial.Raw.X q), + ← CPolynomial.ofArray_toPoly (CPolynomial.Raw.xModWith D modulus)] + rw [raw_powModWith_X_toPoly_modByMonic M D hmod q, + raw_xModWith_toPoly_modByMonic D hmod] + rw [Polynomial.sub_modByMonic] + +/-- The finite-field root product divides the finite-field Frobenius polynomial. + +This is the modular-gcd bridge: the executable root product uses the congruent +modular witness `(X^q mod p) - (X mod p)` instead of materializing `X^q - X`. +-/ +theorem finiteFieldRootProductWith_dvd_frobenius {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p : CPolynomial F} (_hp : p ≠ 0) : + (finiteFieldRootProductWith M D ctx.toFiniteFieldContext p).toPoly ∣ + ((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X) := by + letI : DecidableEq F := instDecidableEqOfLawfulBEq + rw [finiteFieldRootProductWith_toPoly_eq_normalize_gcd M D ctx.toFiniteFieldContext _hp] + apply dvd_trans (normalize_associated _).dvd + let pMonic := CPolynomial.monicNormalize p + let witness := + (CPolynomial.ofArray + (CPolynomial.Raw.xPowSubXModWith M D ctx.q pMonic.val)).toPoly + have hgLeft : EuclideanDomain.gcd pMonic.toPoly witness ∣ pMonic.toPoly := + EuclideanDomain.gcd_dvd_left _ _ + have hgRight : EuclideanDomain.gcd pMonic.toPoly witness ∣ witness := + EuclideanDomain.gcd_dvd_right _ _ + have hpPoly : p.toPoly ≠ 0 := + (CPolynomial.toPoly_eq_zero_iff p).not.mpr _hp + have hpMonicPoly : pMonic.toPoly.Monic := by + dsimp [pMonic] + rw [CPolynomial.monicNormalize_toPoly_eq_normalize] + exact Polynomial.monic_normalize hpPoly + have hpMonicNe : pMonic ≠ 0 := monicNormalize_ne_zero_of_ne_zero _hp + have hmod : pMonic.val.trim ≠ 0 := by + intro htrim + apply hpMonicNe + apply CPolynomial.ext + rw [CPolynomial.trim_eq] at htrim + simpa using htrim + have hnormModulus : + (CPolynomial.ofArray (CPolynomial.Raw.monicNormalize pMonic.val)).toPoly = + pMonic.toPoly := by + rw [raw_monicNormalize_toPoly_eq_normalize] + rw [CPolynomial.ofArray_toPoly] + exact hpMonicPoly.normalize_eq_self + have hwitnessMod : + witness %ₘ pMonic.toPoly = + (((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X) %ₘ pMonic.toPoly) := by + dsimp [witness] + have h := raw_xPowSubXModWith_toPoly_modByMonic M D hmod ctx.q + rwa [hnormModulus] at h + have hpMonic : + pMonic.toPoly ∣ (Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X - witness := by + rw [← Polynomial.modByMonic_eq_zero_iff_dvd hpMonicPoly] + rw [Polynomial.sub_modByMonic] + rw [← hwitnessMod] + simp + simpa [sub_eq_add_neg, add_assoc, add_left_comm, add_comm] using + dvd_add (hgLeft.trans hpMonic) hgRight + +/-- Finite-field root products satisfy the Shoup splitter's valid-input predicate. -/ +theorem finiteFieldRootProductWith_shoupSplitterInput {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p : CPolynomial F} (hp : p ≠ 0) : + shoupSplitterInput ctx (finiteFieldRootProductWith M D ctx.toFiniteFieldContext p) := by + exact ⟨finiteFieldRootProductWith_ne_zero_of_ne_zero M D ctx.toFiniteFieldContext hp, + finiteFieldRootProductWith_dvd_frobenius M D ctx hp⟩ + +/-- Default-backend finite-field root products satisfy the Shoup valid-input predicate. -/ +theorem finiteFieldRootProduct_shoupSplitterInput {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) {p : CPolynomial F} (hp : p ≠ 0) : + shoupSplitterInput ctx (finiteFieldRootProduct ctx.toFiniteFieldContext p) := by + exact finiteFieldRootProductWith_shoupSplitterInput + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive ctx hp + +/-- Alias emphasizing the root-product precondition used by Shoup completeness. -/ +theorem rootProduct_satisfies_shoupSplitterInput {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (M : CPolynomial.Raw.MulContext F) (D : CPolynomial.Raw.ModContext F) + (ctx : SmallPrimeTraceContext F) {p : CPolynomial F} (hp : p ≠ 0) : + (shoupLinearFactorProductSplitterWith M D ctx).validInput ctx.q + (finiteFieldRootProductWith M D ctx.toFiniteFieldContext p) := by + exact finiteFieldRootProductWith_shoupSplitterInput M D ctx hp + +end FiniteField + +end Roots + +end CPolynomial + +end CompPoly diff --git a/CompPoly/Univariate/Roots/Shoup/FrobeniusLinear.lean b/CompPoly/Univariate/Roots/Shoup/FrobeniusLinear.lean new file mode 100644 index 00000000..b53ff9e4 --- /dev/null +++ b/CompPoly/Univariate/Roots/Shoup/FrobeniusLinear.lean @@ -0,0 +1,124 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Univariate.Roots.Shoup.Basic +import Mathlib.Algebra.CharP.CharAndCard + +/-! +# Frobenius Divisors with One Root are Linear + +This file contains the field-theoretic bridge used by the Shoup trace splitter: +a nonzero divisor of `X^q - X` over `GF(q)` with exactly one field root is a +represented nonconstant linear factor. +-/ + +namespace CompPoly + +namespace CPolynomial + +namespace Roots + +namespace FiniteField + +/-- +A nonzero divisor of `X^q - X` with exactly one field root is represented as a +linear factor. +-/ +theorem isRepresentedLinearFactor_of_dvd_frobenius_unique_root {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (ctx : SmallPrimeTraceContext F) {factor : CPolynomial F} {a : F} + (hfactorNe : factor ≠ 0) + (hdvd : factor.toPoly ∣ ((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X)) + (hroot : CPolynomial.eval a factor = 0) + (hunique : ∀ b, CPolynomial.eval b factor = 0 → b = a) : + isRepresentedLinearFactor factor = true := by + letI : DecidableEq F := instDecidableEqOfLawfulBEq + letI : Finite F := ctx.finite + letI : Fintype F := Fintype.ofFinite F + have hqcard : ctx.q = Fintype.card F := by + rw [← ctx.card_eq, Nat.card_eq_fintype_card] + have hfactorPolyNe : factor.toPoly ≠ 0 := + (CPolynomial.toPoly_eq_zero_iff factor).not.mpr hfactorNe + have hfrobNe : ((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X) ≠ 0 := by + rw [hqcard] + exact FiniteField.X_pow_card_sub_X_ne_zero F Fintype.one_lt_card + have hsplitFrob : Polynomial.Splits + ((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X) := by + rw [hqcard] + rw [Polynomial.splits_iff_card_roots] + rw [FiniteField.roots_X_pow_card_sub_X] + rw [← Finset.card_def, Finset.card_univ] + rw [FiniteField.X_pow_card_sub_X_natDegree_eq F Fintype.one_lt_card] + have hsplitFactor : Polynomial.Splits factor.toPoly := + hsplitFrob.of_dvd hfrobNe hdvd + have hrootsLe : factor.toPoly.roots ≤ + (((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X).roots) := + Polynomial.roots.le_of_dvd hfrobNe hdvd + have hfrobRoots : (((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X).roots) = + (Finset.univ : Finset F).val := by + rw [hqcard] + exact FiniteField.roots_X_pow_card_sub_X F + have hfrobNodup : + (((Polynomial.X : Polynomial F) ^ ctx.q - Polynomial.X).roots).Nodup := by + rw [hfrobRoots] + exact Finset.nodup _ + have hfactorRootsNodup : factor.toPoly.roots.Nodup := + Multiset.nodup_of_le hrootsLe hfrobNodup + have haMem : a ∈ factor.toPoly.roots := by + rw [Polynomial.mem_roots hfactorPolyNe] + simpa [Polynomial.IsRoot, CPolynomial.eval_toPoly] using hroot + have htoFinset : factor.toPoly.roots.toFinset = {a} := by + ext b + constructor + · intro hb + rw [Finset.mem_singleton] + apply hunique b + have hbroot : b ∈ factor.toPoly.roots := by + simpa using (Multiset.mem_toFinset.mp hb) + rw [Polynomial.mem_roots hfactorPolyNe] at hbroot + simpa [Polynomial.IsRoot, CPolynomial.eval_toPoly] using hbroot + · intro hb + rw [Finset.mem_singleton] at hb + subst b + exact Multiset.mem_toFinset.mpr haMem + have hrootsCard : factor.toPoly.roots.card = 1 := by + have hcardFin : factor.toPoly.roots.toFinset.card = factor.toPoly.roots.card := + Multiset.toFinset_card_of_nodup hfactorRootsNodup + rw [← hcardFin, htoFinset] + simp + have hnatPoly : factor.toPoly.natDegree = 1 := by + simpa [hrootsCard] using hsplitFactor.natDegree_eq_card_roots + have hnat : factor.natDegree = 1 := by + rw [CPolynomial.natDegree_toPoly] + exact hnatPoly + have hsize : factor.val.size ≤ 2 := by + cases hs : factor.val.size with + | zero => + have hzero : factor = 0 := by + apply CPolynomial.ext + exact Array.eq_empty_of_size_eq_zero hs + exact (hfactorNe hzero).elim + | succ n => + have hn : n = 1 := by + have hnatVal : factor.natDegree = n := by + simp [CPolynomial.natDegree, hs] + omega + omega + have hcoeff : factor.coeff 1 ≠ 0 := by + have hlead := CPolynomial.leadingCoeff_ne_zero hfactorNe + rw [CPolynomial.leadingCoeff_eq_coeff_natDegree, hnat] at hlead + exact hlead + unfold isRepresentedLinearFactor + simp [hsize] + simpa [CPolynomial.coeff, CPolynomial.Raw.coeff] using hcoeff + +end FiniteField + +end Roots + +end CPolynomial + +end CompPoly diff --git a/bench/CompPolyBench/Univariate.lean b/bench/CompPolyBench/Univariate.lean index 5c565202..43c4f988 100644 --- a/bench/CompPolyBench/Univariate.lean +++ b/bench/CompPolyBench/Univariate.lean @@ -9,6 +9,7 @@ import CompPolyBench.Univariate.BatchEval import CompPolyBench.Univariate.ManyEval import CompPolyBench.Univariate.NTT.FastMul import CompPolyBench.Univariate.NTT.FastMulLow +import CompPolyBench.Univariate.Roots.Binary import CompPolyBench.Univariate.Roots.FiniteField /-! @@ -21,13 +22,15 @@ namespace CompPolyBench def univariateGroupInfos : List BenchGroupInfo := univariateBasicGroupInfos ++ univariateBatchEvalGroupInfos ++ univariateManyEvalGroupInfos ++ univariateNttFastMulGroupInfos ++ - univariateNttFastMulLowGroupInfos ++ univariateFiniteFieldRootGroupInfos + univariateNttFastMulLowGroupInfos ++ univariateBinaryRootGroupInfos ++ + univariateFiniteFieldRootGroupInfos /-- Runnable univariate benchmark tasks. -/ def univariateTasks : List BenchTask := univariateBasicTasks ++ univariateBatchEvalTasks ++ univariateManyEvalTasks ++ univariateNttFastMulTasks ++ - univariateNttFastMulLowTasks ++ univariateFiniteFieldRootTasks + univariateNttFastMulLowTasks ++ univariateBinaryRootTasks ++ + univariateFiniteFieldRootTasks /-- Run selected univariate benchmarks. -/ def runUnivariate (preset : BenchPreset) (selection : BenchSelection) (gen : StdGen) : diff --git a/bench/CompPolyBench/Univariate/Roots/Binary.lean b/bench/CompPolyBench/Univariate/Roots/Binary.lean new file mode 100644 index 00000000..120957a3 --- /dev/null +++ b/bench/CompPolyBench/Univariate/Roots/Binary.lean @@ -0,0 +1,321 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPolyBench.Common +import CompPoly.Fields.Binary.GF2_32 +import CompPoly.Fields.Binary.GF2_48 +import CompPoly.Fields.Binary.GF2_64 +import CompPoly.Fields.Binary.GF2_72 +import CompPoly.Univariate.Roots + +/-! +# Binary-Field Root Benchmarks + +Univariate root-search benchmarks over selected executable binary-extension +fields, comparing Shoup trace splitting and smooth cyclic splitting. +-/ + +open CompPoly + +namespace CompPolyBench + +private def binaryRootGF32PowerCount : Nat := + 4 + +private def binaryRootGF48PowerCount : Nat := + 8 + +private def binaryRootGF64PowerCount : Nat := + 3 + +private def binaryRootGF72PowerCount : Nat := + 3 + +private def binaryRootGF32DeepCollisionStride : Nat := + 255 + +private def binaryRootGF64DeepCollisionStride : Nat := + 65535 + +private def binaryRootWorkloadDegree (powerCount : Nat) : Nat := + powerCount + 3 + +private def binaryRootWorkloadDistinctRoots (powerCount : Nat) : Nat := + powerCount + 2 + +private def binaryRootWorkloadShape (powerCount : Nat) (rootPattern : String) : String := + s!"degree={binaryRootWorkloadDegree powerCount}, " ++ + s!"{binaryRootWorkloadDistinctRoots powerCount} distinct roots, " ++ + "zero root, repeated primitive-generator root, " ++ rootPattern + +private def binaryRootConsecutiveWorkloadShape (powerCount : Nat) : String := + binaryRootWorkloadShape powerCount + s!"nonzero exponents 1 through {powerCount + 1}" + +private def binaryRootStrideCollisionWorkloadShape (powerCount stride : Nat) : String := + binaryRootWorkloadShape powerCount s!"nonzero exponents congruent to 1 mod {stride}" + +/- +Each binary-root workload uses a field-specific default input shape for every +preset. Presets only scale measured iteration counts. Counts are row-specific +where needed so total row runtimes stay closer within each field group. Large +counts target balanced row totals; medium is roughly large / 7, and small is +roughly max (large / 35) 1, rounded to nice values. +-/ +private def binaryRootGF48ShoupMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 21 3 1 + +private def binaryRootGF48SmoothMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 500 70 15 + +private def binaryRootGF72ShoupMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 21 3 1 + +private def binaryRootGF72SmoothMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 600 90 20 + +private def binaryRootGF32HardShoupMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 420 60 12 + +private def binaryRootGF32HardSmoothMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 315 45 9 + +private def binaryRootGF64HardShoupMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 35 5 1 + +private def binaryRootGF64HardSmoothMeasuredIterations (preset : BenchPreset) : Nat := + preset.selectNat 21 3 1 + +private def primitivePowerRoots {F : Type*} [Pow F Nat] (firstExponent count : Nat) + (generator : F) : + List F := + (List.range count).map fun i ↦ generator ^ (firstExponent + i) + +private def primitiveStrideRoots {F : Type*} [Pow F Nat] + (firstExponent stride count : Nat) (generator : F) : + List F := + (List.range count).map fun i ↦ generator ^ (firstExponent + stride * i) + +private def productOfLinearRoots {F : Type*} + [Field F] [BEq F] [LawfulBEq F] (roots : List F) : CPolynomial F := + roots.foldl + (fun p root ↦ p * CPolynomial.linearFactor root) + (CPolynomial.C (1 : F)) + +private def binaryRootConsecutiveWorkloadPolynomial {F : Type*} + [Field F] [BEq F] [LawfulBEq F] (powerCount : Nat) (generator : F) : + CPolynomial F := + let powers := primitivePowerRoots 2 powerCount generator + productOfLinearRoots ((0 : F) :: generator :: generator :: powers) + +private def binaryRootStrideCollisionWorkloadPolynomial {F : Type*} + [Field F] [BEq F] [LawfulBEq F] + (powerCount stride : Nat) (generator : F) : + CPolynomial F := + let powers := primitiveStrideRoots (stride + 1) stride powerCount generator + productOfLinearRoots ((0 : F) :: generator :: generator :: powers) + +private def insertSortedNat (x : Nat) : List Nat → List Nat + | [] => [x] + | y :: ys => + if x ≤ y then + x :: y :: ys + else + y :: insertSortedNat x ys + +private def sortNatList (xs : List Nat) : List Nat := + xs.foldr insertSortedNat [] + +private def checksumNatList (xs : List Nat) : Nat := + xs.foldl (fun acc x ↦ mixChecksum acc x) 0 + +private def checksumNormalizedRoots {F : Type*} (toNat : F → Nat) (roots : Array F) : Nat := + checksumNatList (sortNatList (roots.toList.map toNat)) + +private def rootsWith {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (ctx : CPolynomial.Roots.FiniteField.FiniteFieldContext F) + (splitter : CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F) + (p : CPolynomial F) : Array F := + CPolynomial.Roots.FiniteField.rootsInFiniteFieldWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive ctx splitter p + +private def shoupSplitter {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (ctx : CPolynomial.Roots.FiniteField.SmallPrimeTraceContext F) : + CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CPolynomial.Roots.FiniteField.shoupLinearFactorProductSplitterWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive ctx + +private def smoothSplitter {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (ctx : CPolynomial.Roots.FiniteField.SmoothCyclicRootContext F) : + CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive ctx + +private def runBinaryRootGroup {F : Type} [Field F] [BEq F] [LawfulBEq F] + (groupKey title fieldLabel : String) (toNat : F → Nat) + (workloadPolynomial : F → CPolynomial F) (inputShape : String) + (finiteCtx : CPolynomial.Roots.FiniteField.FiniteFieldContext F) + (traceCtx : CPolynomial.Roots.FiniteField.SmallPrimeTraceContext F) + (smoothHornerCtx smoothSubproductCtx : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext F) + (shoupMeasuredIterations smoothMeasuredIterations : + BenchPreset → Nat) + (generator : F) (preset : BenchPreset) (gen : StdGen) : + IO (BenchGroup × StdGen) := do + let p := workloadPolynomial generator + let warmup := preset.selectNat 1 0 0 + let shoupMeasured := shoupMeasuredIterations preset + let smoothHornerMeasured := smoothMeasuredIterations preset + let smoothSubproductMeasured := smoothMeasuredIterations preset + let checksumIterations := groupChecksumIterations shoupMeasured [ + smoothHornerMeasured, smoothSubproductMeasured + ] + let shoupRow ← runTimed + (groupKey ++ "-shoup") "CPolynomial" + "Shoup trace" + fieldLabel inputShape preset warmup shoupMeasured + (fun _ ↦ rootsWith finiteCtx (shoupSplitter traceCtx) p) + (checksumNormalizedRoots toNat) checksumIterations + let smoothHornerRow ← runTimed + (groupKey ++ "-smooth-horner") "CPolynomial" + "smooth cyclic, Horner" + fieldLabel inputShape preset warmup smoothHornerMeasured + (fun _ ↦ rootsWith finiteCtx (smoothSplitter smoothHornerCtx) p) + (checksumNormalizedRoots toNat) checksumIterations + let smoothSubproductRow ← runTimed + (groupKey ++ "-smooth-subproduct") "CPolynomial" + "smooth cyclic, subproduct" + fieldLabel inputShape preset warmup smoothSubproductMeasured + (fun _ ↦ rootsWith finiteCtx (smoothSplitter smoothSubproductCtx) p) + (checksumNormalizedRoots toNat) checksumIterations + pure ({ + groupKey := groupKey + title := title + records := #[shoupRow, smoothHornerRow, smoothSubproductRow] + }, gen) + +private def runBinaryRootSubproductComparisonGroup {F : Type} + [Field F] [BEq F] [LawfulBEq F] + (groupKey title fieldLabel : String) (toNat : F → Nat) + (workloadPolynomial : F → CPolynomial F) (inputShape : String) + (finiteCtx : CPolynomial.Roots.FiniteField.FiniteFieldContext F) + (traceCtx : CPolynomial.Roots.FiniteField.SmallPrimeTraceContext F) + (smoothSubproductCtx : + CPolynomial.Roots.FiniteField.SmoothCyclicRootContext F) + (shoupMeasuredIterations smoothMeasuredIterations : + BenchPreset → Nat) + (generator : F) (preset : BenchPreset) (gen : StdGen) : + IO (BenchGroup × StdGen) := do + let p := workloadPolynomial generator + let warmup := preset.selectNat 1 0 0 + let shoupMeasured := shoupMeasuredIterations preset + let smoothSubproductMeasured := smoothMeasuredIterations preset + let checksumIterations := groupChecksumIterations shoupMeasured [ + smoothSubproductMeasured + ] + let shoupRow ← runTimed + (groupKey ++ "-shoup") "CPolynomial" + "Shoup trace" + fieldLabel inputShape preset warmup shoupMeasured + (fun _ ↦ rootsWith finiteCtx (shoupSplitter traceCtx) p) + (checksumNormalizedRoots toNat) checksumIterations + let smoothSubproductRow ← runTimed + (groupKey ++ "-smooth-subproduct") "CPolynomial" + "smooth cyclic, subproduct" + fieldLabel inputShape preset warmup smoothSubproductMeasured + (fun _ ↦ rootsWith finiteCtx (smoothSplitter smoothSubproductCtx) p) + (checksumNormalizedRoots toNat) checksumIterations + pure ({ + groupKey := groupKey + title := title + records := #[shoupRow, smoothSubproductRow] + }, gen) + +/-- Benchmark group metadata for binary-field root search. -/ +def univariateBinaryRootGroupInfos : List BenchGroupInfo := [ + ⟨"univariate-roots-binary-gf2-48", + "Univariate binary-field root search (GF(2^48))"⟩, + ⟨"univariate-roots-binary-gf2-72", + "Univariate binary-field root search (GF(2^72))"⟩, + ⟨"univariate-roots-binary-gf2-32", + "Univariate binary-field root search (GF(2^32))"⟩, + ⟨"univariate-roots-binary-gf2-64", + "Univariate binary-field root search (GF(2^64))"⟩ +] + +private def runGF32BinaryRoots (preset : BenchPreset) (gen : StdGen) : + IO (BenchGroup × StdGen) := + runBinaryRootSubproductComparisonGroup "univariate-roots-binary-gf2-32" + "Univariate binary-field root search (GF(2^32))" + "GF(2^32)" GF2_32.ConcreteField.toNat + (binaryRootStrideCollisionWorkloadPolynomial + binaryRootGF32PowerCount binaryRootGF32DeepCollisionStride) + (binaryRootStrideCollisionWorkloadShape + binaryRootGF32PowerCount binaryRootGF32DeepCollisionStride) + GF2_32.finiteFieldContext GF2_32.shoupTraceContext + GF2_32.smoothSubproductRootContext + binaryRootGF32HardShoupMeasuredIterations + binaryRootGF32HardSmoothMeasuredIterations + GF2_32.primitiveRoot preset gen + +private def runGF48BinaryRoots (preset : BenchPreset) (gen : StdGen) : + IO (BenchGroup × StdGen) := + runBinaryRootGroup "univariate-roots-binary-gf2-48" + "Univariate binary-field root search (GF(2^48))" + "GF(2^48)" GF2_48.ConcreteField.toNat + (binaryRootConsecutiveWorkloadPolynomial binaryRootGF48PowerCount) + (binaryRootConsecutiveWorkloadShape binaryRootGF48PowerCount) + GF2_48.finiteFieldContext GF2_48.shoupTraceContext + GF2_48.smoothHornerRootContext GF2_48.smoothSubproductRootContext + binaryRootGF48ShoupMeasuredIterations + binaryRootGF48SmoothMeasuredIterations + GF2_48.primitiveRoot preset gen + +private def runGF72BinaryRoots (preset : BenchPreset) (gen : StdGen) : + IO (BenchGroup × StdGen) := + runBinaryRootGroup "univariate-roots-binary-gf2-72" + "Univariate binary-field root search (GF(2^72))" + "GF(2^72)" GF2_72.ConcreteField.toNat + (binaryRootConsecutiveWorkloadPolynomial binaryRootGF72PowerCount) + (binaryRootConsecutiveWorkloadShape binaryRootGF72PowerCount) + GF2_72.finiteFieldContext GF2_72.shoupTraceContext + GF2_72.smoothHornerRootContext GF2_72.smoothSubproductRootContext + binaryRootGF72ShoupMeasuredIterations + binaryRootGF72SmoothMeasuredIterations + GF2_72.primitiveRoot preset gen + +private def runGF64BinaryRoots (preset : BenchPreset) (gen : StdGen) : + IO (BenchGroup × StdGen) := + runBinaryRootSubproductComparisonGroup "univariate-roots-binary-gf2-64" + "Univariate binary-field root search (GF(2^64))" + "GF(2^64)" GF2_64.ConcreteField.toNat + (binaryRootStrideCollisionWorkloadPolynomial + binaryRootGF64PowerCount binaryRootGF64DeepCollisionStride) + (binaryRootStrideCollisionWorkloadShape + binaryRootGF64PowerCount binaryRootGF64DeepCollisionStride) + GF2_64.finiteFieldContext GF2_64.shoupTraceContext + GF2_64.smoothSubproductRootContext + binaryRootGF64HardShoupMeasuredIterations + binaryRootGF64HardSmoothMeasuredIterations + GF2_64.primitiveRoot preset gen + +/-- Runnable binary-field root benchmark tasks. -/ +def univariateBinaryRootTasks : List BenchTask := [ + BenchTask.fromGroupRunner (univariateBinaryRootGroupInfos.getD 0 + ⟨"univariate-roots-binary-gf2-48", ""⟩) + runGF48BinaryRoots, + BenchTask.fromGroupRunner (univariateBinaryRootGroupInfos.getD 1 + ⟨"univariate-roots-binary-gf2-72", ""⟩) + runGF72BinaryRoots, + BenchTask.fromGroupRunner (univariateBinaryRootGroupInfos.getD 2 + ⟨"univariate-roots-binary-gf2-32", ""⟩) + runGF32BinaryRoots, + BenchTask.fromGroupRunner (univariateBinaryRootGroupInfos.getD 3 + ⟨"univariate-roots-binary-gf2-64", ""⟩) + runGF64BinaryRoots +] + +end CompPolyBench diff --git a/docs/wiki/binary-fields-and-ntt.md b/docs/wiki/binary-fields-and-ntt.md index 958477d6..bc2f2af2 100644 --- a/docs/wiki/binary-fields-and-ntt.md +++ b/docs/wiki/binary-fields-and-ntt.md @@ -17,12 +17,45 @@ CompPoly/Fields/ Fast.lean Binary/ Common.lean + Extension/ + Prelude.lean + Basic.lean + Impl.lean + Primitive.lean BF128Ghash/ Prelude.lean Basic.lean Impl.lean XPowTwoPowGcdCertificate.lean XPowTwoPowModCertificate.lean + GF2_32/ + Prelude.lean + Basic.lean + Impl.lean + Primitive.lean + PrimitivePowerCertificate.lean + RootContexts.lean + GF2_48/ + Prelude.lean + Basic.lean + Impl.lean + Primitive.lean + PrimitivePowerCertificate.lean + RootContexts.lean + GF2_64/ + Prelude.lean + Basic.lean + Impl.lean + Primitive.lean + PrimitivePowerCertificate.lean + RootContexts.lean + GF2_72/ + Prelude.lean + Basic.lean + Impl.lean + Primitive.lean + PrimitivePowerCertificate.lean + RootContexts.lean Tower/ Abstract/* Concrete/* @@ -70,6 +103,33 @@ The GHASH model lives under `Binary/BF128Ghash/`. Use this area when the task is specifically about `GF(2^128)`, GHASH, or the certificate-based proof strategy for binary-field arithmetic. +## Direct Extension Surface + +The direct polynomial-basis substrate lives under `Binary/Extension/` and is used +for binary fields whose extension degree is not covered by the power-of-two tower +family. + +- [`../../CompPoly/Fields/Binary/Extension/Prelude.lean`](../../CompPoly/Fields/Binary/Extension/Prelude.lean) + contains defining-polynomial metadata, bitmask helpers, and Nat-level + carry-less certificate checkers. +- [`../../CompPoly/Fields/Binary/Extension/Basic.lean`](../../CompPoly/Fields/Binary/Extension/Basic.lean) + contains the generic quotient/specification surface, with field and cardinality + instances conditional on irreducibility certificates. +- [`../../CompPoly/Fields/Binary/Extension/Impl.lean`](../../CompPoly/Fields/Binary/Extension/Impl.lean) + contains the shared executable `BitVec` carrier and operations for direct + polynomial-basis fields. +- [`../../CompPoly/Fields/Binary/Extension/Primitive.lean`](../../CompPoly/Fields/Binary/Extension/Primitive.lean) + contains Rabin irreducibility shells and small primitive-order helpers for the + concrete direct-extension fields. +- `Binary/GF2_32/`, `Binary/GF2_48/`, `Binary/GF2_64/`, and `Binary/GF2_72/` + instantiate the substrate with the candidate defining polynomials, + quotient/specification surfaces, executable bit-vector operations, + primitive-power certificates, smooth root-search schedules, + Horner/subproduct smooth root contexts, and Shoup trace contexts. +- [`../../CompPoly/Bivariate/GuruswamiSudan/Root/FieldRoots/FiniteField.lean`](../../CompPoly/Bivariate/GuruswamiSudan/Root/FieldRoots/FiniteField.lean) + adapts the certified smooth and Shoup root contexts to the GS-facing + `FieldRootContext` API. + ## Binary Tower Surface The tower development splits into abstract theory, concrete constructions, and @@ -109,6 +169,9 @@ Algorithm changes often cascade into `Intermediate`, `Impl`, and `Correctness`. ## Where To Start By Task - Shared BitVec or characteristic-2 helper lemma: `Binary/Common.lean` +- Direct polynomial-basis extension helper or GF32/GF48/GF64/GF72 quotient + surface: `Binary/Extension/`, `Binary/GF2_32/`, `Binary/GF2_48/`, + `Binary/GF2_64/`, or `Binary/GF2_72/` - GHASH field model or certificate proof: `Binary/BF128Ghash/` - General tower-field structure or extension lemmas: `Binary/Tower/` - Additive-NTT basis, domain, or correctness proof: `Binary/AdditiveNTT/` @@ -120,3 +183,6 @@ Algorithm changes often cascade into `Intermediate`, `Impl`, and `Correctness`. `Equiv` / `Impl` - For additive NTT: `Domain` -> `NovelPolynomialBasis` -> `Intermediate` -> `Algorithm` -> `Impl` -> `Correctness` +- For direct extensions: `Extension/Prelude` -> `Extension/Basic` -> + `Extension/Impl` -> `Extension/Primitive` plus the matching concrete + `GF2_*` modules. diff --git a/tests/CompPolyTests.lean b/tests/CompPolyTests.lean index 0321cad5..a1ed9f10 100644 --- a/tests/CompPolyTests.lean +++ b/tests/CompPolyTests.lean @@ -23,6 +23,18 @@ import CompPolyTests.Bivariate.WeightedDegree import CompPolyTests.Data.MvPolynomial.Notation import CompPolyTests.Fields.Binary.AdditiveNTT.NovelPolynomialBasis import CompPolyTests.Fields.Binary.BF128Ghash.Prelude +import CompPolyTests.Fields.Binary.GF2_32.Basic +import CompPolyTests.Fields.Binary.GF2_32.Impl +import CompPolyTests.Fields.Binary.GF2_32.RootContexts +import CompPolyTests.Fields.Binary.GF2_48.Basic +import CompPolyTests.Fields.Binary.GF2_48.Impl +import CompPolyTests.Fields.Binary.GF2_48.RootContexts +import CompPolyTests.Fields.Binary.GF2_64.Basic +import CompPolyTests.Fields.Binary.GF2_64.Impl +import CompPolyTests.Fields.Binary.GF2_64.RootContexts +import CompPolyTests.Fields.Binary.GF2_72.Basic +import CompPolyTests.Fields.Binary.GF2_72.Impl +import CompPolyTests.Fields.Binary.GF2_72.RootContexts import CompPolyTests.Fields.KoalaBear.Fast import CompPolyTests.Fields.PrattCertificate import CompPolyTests.LinearAlgebra.Dense @@ -41,4 +53,6 @@ import CompPolyTests.Univariate.NTT.Inverse import CompPolyTests.Univariate.Raw import CompPolyTests.Univariate.Roots.Enumeration import CompPolyTests.Univariate.Roots.FiniteField +import CompPolyTests.Univariate.Roots.Binary +import CompPolyTests.Univariate.Roots.Shoup import CompPolyTests.Univariate.ToPoly diff --git a/tests/CompPolyTests/Fields/Binary/GF2_32/Basic.lean b/tests/CompPolyTests/Fields/Binary/GF2_32/Basic.lean new file mode 100644 index 00000000..1d1e5f1b --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_32/Basic.lean @@ -0,0 +1,44 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_32 + +/-! + # GF(2^32) Basic Tests + + Compile-time checks for the direct-extension specification surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_32.Basic + +example : GF2_32.definingPolynomial.natDegree = GF2_32.extensionDegree := + GF2_32.definingPolynomial_natDegree + +example : GF2_32.definingPolynomial.Monic := + GF2_32.definingPolynomial_monic + +example : GF2_32.definingPolynomial ≠ 0 := + GF2_32.definingPolynomial_ne_zero + +example : + Polynomial.eval₂ (algebraMap (ZMod 2) GF2_32.SpecField) GF2_32.root + GF2_32.definingPolynomial = 0 := + GF2_32.root_satisfies_definingPolynomial + +example : + BinaryField.Extension.sparsePolynomial GF2_32.definingPolynomialExponents = + GF2_32.definingPolynomial := + GF2_32.sparsePolynomial_definingPolynomialExponents + +#guard GF2_32.smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (GF2_32.fieldSize - 1) == 1 + +#guard GF2_32.primitivePrimeFactors == [3, 5, 17, 257, 65537] + +example : + GF2_32.multiplicativeGroupOrder = 3 * 5 * 17 * 257 * 65537 := + GF2_32.multiplicativeGroupOrder_factorization + +end CompPolyTests.Fields.Binary.GF2_32.Basic diff --git a/tests/CompPolyTests/Fields/Binary/GF2_32/Impl.lean b/tests/CompPolyTests/Fields/Binary/GF2_32/Impl.lean new file mode 100644 index 00000000..c762e395 --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_32/Impl.lean @@ -0,0 +1,157 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_32 + +/-! + # GF(2^32) Executable Tests + + Regression checks for the raw `BitVec` executable carrier. These tests cover + the certified computation layer and the field typeclass surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_32.Impl + +private abbrev F := GF2_32.ConcreteField + +private def alpha : F := + GF2_32.ConcreteField.root + +private def tailFromPowers : F := + GF2_32.ConcreteField.add + (GF2_32.ConcreteField.add + (GF2_32.ConcreteField.add + ((GF2_32.ConcreteField.pow alpha 22)) + (GF2_32.ConcreteField.pow alpha 2)) + (GF2_32.ConcreteField.pow alpha 1)) + 1 + +#guard GF2_32.ConcreteField.toNat (GF2_32.ConcreteField.ofNat (2 ^ 32 + 5)) == 5 + +#guard GF2_32.ConcreteField.toNat + (GF2_32.ConcreteField.add (GF2_32.ConcreteField.ofNat 0x1234) + (GF2_32.ConcreteField.ofNat 0x00f0)) == 0x12c4 + +#guard GF2_32.ConcreteField.toNat + (GF2_32.ConcreteField.mul (GF2_32.ConcreteField.ofNat 3) + (GF2_32.ConcreteField.ofNat 5)) == 15 + +#guard GF2_32.ConcreteField.pow alpha 32 == tailFromPowers + +#guard GF2_32.ConcreteField.toNat (GF2_32.ConcreteField.pow alpha 32) == 4194311 + +#guard GF2_32.ConcreteField.toNat (GF2_32.ConcreteField.traceValue 1) == 0 + +example : + Fintype.card F = 2 ^ GF2_32.extensionDegree := + GF2_32.ConcreteField.card + +example : GF2_32.ConcreteField.polynomialBasis.size = GF2_32.extensionDegree := + GF2_32.ConcreteField.polynomialBasis_size + +example : GF2_32.ConcreteField.baseConstants.size = 2 := + GF2_32.ConcreteField.baseConstants_size + +example : AddCommGroup F := + inferInstance + +noncomputable example : Field F := + inferInstance + +noncomputable example : CharP F 2 := + inferInstance + +noncomputable example : Algebra (ZMod 2) F := + inferInstance + +example : GF2_32.finiteFieldContext.q = GF2_32.fieldSize := + rfl + +example : Nat.card F = GF2_32.fieldSize := + GF2_32.finiteFieldContext.card_eq + +noncomputable example (a : F) : a ^ GF2_32.finiteFieldContext.q = a := + GF2_32.finiteFieldContext.frobenius_fixed a + +example : + orderOf GF2_32.primitiveRoot = GF2_32.fieldSize - 1 := + GF2_32.primitiveRoot_order + +example : + GF2_32.smoothHornerRootContext.q = GF2_32.fieldSize := + rfl + +example : + GF2_32.smoothHornerRootContext.generator = GF2_32.primitiveRoot := + rfl + +example : + GF2_32.smoothSubproductRootContext.q = GF2_32.fieldSize := + rfl + +example : + GF2_32.smoothSubproductRootContext.generator = GF2_32.primitiveRoot := + rfl + +example : GF2_32.shoupTraceContext.p = 2 := + rfl + +example : GF2_32.shoupTraceContext.k = GF2_32.extensionDegree := + rfl + +example : + GF2_32.shoupTraceContext.baseConstants.size = GF2_32.shoupTraceContext.p := + GF2_32.shoupTraceContext.baseConstants_size + +example : + GF2_32.shoupTraceContext.basis.size = GF2_32.shoupTraceContext.k := + GF2_32.shoupTraceContext.basis_size + +noncomputable example (z : F) : + GF2_32.shoupTraceContext.traceValue z = + CompPoly.CPolynomial.Roots.FiniteField.tracePowerSum 2 GF2_32.extensionDegree z := + GF2_32.shoupTraceContext.traceValue_eq_powerSum z + +noncomputable example (z : F) : + GF2_32.shoupTraceContext.traceValue z ∈ + GF2_32.shoupTraceContext.baseConstants.toList := + GF2_32.shoupTraceContext.traceValue_mem_base z + +noncomputable example {a b : F} (hne : a ≠ b) : + ∃ beta, beta ∈ GF2_32.shoupTraceContext.basis.toList ∧ + GF2_32.shoupTraceContext.traceValue (beta * (a - b)) ≠ 0 := + GF2_32.shoupTraceContext.trace_separates hne + +example : Function.Injective GF2_32.ConcreteField.toSpec := + GF2_32.ConcreteField.toSpec_injective + +example : + GF2_32.ConcreteField.toSpec GF2_32.ConcreteField.root = GF2_32.root := + GF2_32.ConcreteField.toSpec_root + +example : + GF2_32.ConcreteField.toSpec (0 : F) = 0 := + GF2_32.ConcreteField.toSpec_zero + +example : + GF2_32.ConcreteField.toSpec (1 : F) = 1 := + GF2_32.ConcreteField.toSpec_one + +example (a b : F) : + GF2_32.ConcreteField.toSpec (a + b) = + GF2_32.ConcreteField.toSpec a + GF2_32.ConcreteField.toSpec b := + GF2_32.ConcreteField.toSpec_add a b + +example (a b : F) : + GF2_32.ConcreteField.toSpec (a - b) = + GF2_32.ConcreteField.toSpec a - GF2_32.ConcreteField.toSpec b := + GF2_32.ConcreteField.toSpec_sub a b + +example (a b : F) : + GF2_32.ConcreteField.toSpec (a * b) = + GF2_32.ConcreteField.toSpec a * GF2_32.ConcreteField.toSpec b := + GF2_32.ConcreteField.toSpec_mul a b + +end CompPolyTests.Fields.Binary.GF2_32.Impl diff --git a/tests/CompPolyTests/Fields/Binary/GF2_32/RootContexts.lean b/tests/CompPolyTests/Fields/Binary/GF2_32/RootContexts.lean new file mode 100644 index 00000000..9b1b02eb --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_32/RootContexts.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_32 +import CompPoly.Univariate.Roots.Shoup + +/-! +# GF(2^32) Root-Context Tests + +Focused compile-time checks for the certified finite-field, Shoup, and smooth +root-search contexts over executable `GF(2^32)`. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_32.RootContexts + +private abbrev F := GF2_32.ConcreteField + +example : + GF2_32.finiteFieldContext.q = GF2_32.fieldSize := + rfl + +example : + GF2_32.shoupTraceContext.toFiniteFieldContext.q = GF2_32.fieldSize := + rfl + +example : + GF2_32.smoothHornerRootContext.q = GF2_32.fieldSize := + rfl + +example : + GF2_32.smoothSubproductRootContext.q = GF2_32.fieldSize := + rfl + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.shoupLinearFactorProductSplitter + GF2_32.shoupTraceContext + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CompPoly.CPolynomial.Raw.MulContext.naive CompPoly.CPolynomial.Raw.ModContext.naive + GF2_32.smoothSubproductRootContext + +end CompPolyTests.Fields.Binary.GF2_32.RootContexts diff --git a/tests/CompPolyTests/Fields/Binary/GF2_48/Basic.lean b/tests/CompPolyTests/Fields/Binary/GF2_48/Basic.lean new file mode 100644 index 00000000..89e70b68 --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_48/Basic.lean @@ -0,0 +1,45 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_48 + +/-! + # GF(2^48) Basic Tests + + Compile-time checks for the direct-extension specification surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_48.Basic + +example : GF2_48.definingPolynomial.natDegree = GF2_48.extensionDegree := + GF2_48.definingPolynomial_natDegree + +example : GF2_48.definingPolynomial.Monic := + GF2_48.definingPolynomial_monic + +example : GF2_48.definingPolynomial ≠ 0 := + GF2_48.definingPolynomial_ne_zero + +example : + Polynomial.eval₂ (algebraMap (ZMod 2) GF2_48.SpecField) GF2_48.root + GF2_48.definingPolynomial = 0 := + GF2_48.root_satisfies_definingPolynomial + +example : + BinaryField.Extension.sparsePolynomial GF2_48.definingPolynomialExponents = + GF2_48.definingPolynomial := + GF2_48.sparsePolynomial_definingPolynomialExponents + +#guard GF2_48.smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (GF2_48.fieldSize - 1) == 1 + +#guard GF2_48.primitivePrimeFactors == [3, 5, 7, 13, 17, 97, 241, 257, 673] + +example : + GF2_48.multiplicativeGroupOrder = + 3 ^ 2 * 5 * 7 * 13 * 17 * 97 * 241 * 257 * 673 := + GF2_48.multiplicativeGroupOrder_factorization + +end CompPolyTests.Fields.Binary.GF2_48.Basic diff --git a/tests/CompPolyTests/Fields/Binary/GF2_48/Impl.lean b/tests/CompPolyTests/Fields/Binary/GF2_48/Impl.lean new file mode 100644 index 00000000..9f0e65ac --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_48/Impl.lean @@ -0,0 +1,157 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_48 + +/-! + # GF(2^48) Executable Tests + + Regression checks for the raw `BitVec` executable carrier. These tests cover + the certified computation layer and the field typeclass surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_48.Impl + +private abbrev F := GF2_48.ConcreteField + +private def alpha : F := + GF2_48.ConcreteField.root + +private def tailFromPowers : F := + GF2_48.ConcreteField.add + (GF2_48.ConcreteField.add + (GF2_48.ConcreteField.add + (GF2_48.ConcreteField.pow alpha 9) + (GF2_48.ConcreteField.pow alpha 7)) + (GF2_48.ConcreteField.pow alpha 4)) + 1 + +#guard GF2_48.ConcreteField.toNat (GF2_48.ConcreteField.ofNat (2 ^ 48 + 5)) == 5 + +#guard GF2_48.ConcreteField.toNat + (GF2_48.ConcreteField.add (GF2_48.ConcreteField.ofNat 0x1234) + (GF2_48.ConcreteField.ofNat 0x00f0)) == 0x12c4 + +#guard GF2_48.ConcreteField.toNat + (GF2_48.ConcreteField.mul (GF2_48.ConcreteField.ofNat 3) + (GF2_48.ConcreteField.ofNat 5)) == 15 + +#guard GF2_48.ConcreteField.pow alpha 48 == tailFromPowers + +#guard GF2_48.ConcreteField.toNat (GF2_48.ConcreteField.pow alpha 48) == 657 + +#guard GF2_48.ConcreteField.toNat (GF2_48.ConcreteField.traceValue 1) == 0 + +example : + Fintype.card F = 2 ^ GF2_48.extensionDegree := + GF2_48.ConcreteField.card + +example : GF2_48.ConcreteField.polynomialBasis.size = GF2_48.extensionDegree := + GF2_48.ConcreteField.polynomialBasis_size + +example : GF2_48.ConcreteField.baseConstants.size = 2 := + GF2_48.ConcreteField.baseConstants_size + +example : AddCommGroup F := + inferInstance + +noncomputable example : Field F := + inferInstance + +noncomputable example : CharP F 2 := + inferInstance + +noncomputable example : Algebra (ZMod 2) F := + inferInstance + +example : GF2_48.finiteFieldContext.q = GF2_48.fieldSize := + rfl + +example : Nat.card F = GF2_48.fieldSize := + GF2_48.finiteFieldContext.card_eq + +noncomputable example (a : F) : a ^ GF2_48.finiteFieldContext.q = a := + GF2_48.finiteFieldContext.frobenius_fixed a + +example : + orderOf GF2_48.primitiveRoot = GF2_48.fieldSize - 1 := + GF2_48.primitiveRoot_order + +example : + GF2_48.smoothHornerRootContext.q = GF2_48.fieldSize := + rfl + +example : + GF2_48.smoothHornerRootContext.generator = GF2_48.primitiveRoot := + rfl + +example : + GF2_48.smoothSubproductRootContext.q = GF2_48.fieldSize := + rfl + +example : + GF2_48.smoothSubproductRootContext.generator = GF2_48.primitiveRoot := + rfl + +example : GF2_48.shoupTraceContext.p = 2 := + rfl + +example : GF2_48.shoupTraceContext.k = GF2_48.extensionDegree := + rfl + +example : + GF2_48.shoupTraceContext.baseConstants.size = GF2_48.shoupTraceContext.p := + GF2_48.shoupTraceContext.baseConstants_size + +example : + GF2_48.shoupTraceContext.basis.size = GF2_48.shoupTraceContext.k := + GF2_48.shoupTraceContext.basis_size + +noncomputable example (z : F) : + GF2_48.shoupTraceContext.traceValue z = + CompPoly.CPolynomial.Roots.FiniteField.tracePowerSum 2 GF2_48.extensionDegree z := + GF2_48.shoupTraceContext.traceValue_eq_powerSum z + +noncomputable example (z : F) : + GF2_48.shoupTraceContext.traceValue z ∈ + GF2_48.shoupTraceContext.baseConstants.toList := + GF2_48.shoupTraceContext.traceValue_mem_base z + +noncomputable example {a b : F} (hne : a ≠ b) : + ∃ beta, beta ∈ GF2_48.shoupTraceContext.basis.toList ∧ + GF2_48.shoupTraceContext.traceValue (beta * (a - b)) ≠ 0 := + GF2_48.shoupTraceContext.trace_separates hne + +example : Function.Injective GF2_48.ConcreteField.toSpec := + GF2_48.ConcreteField.toSpec_injective + +example : + GF2_48.ConcreteField.toSpec GF2_48.ConcreteField.root = GF2_48.root := + GF2_48.ConcreteField.toSpec_root + +example : + GF2_48.ConcreteField.toSpec (0 : F) = 0 := + GF2_48.ConcreteField.toSpec_zero + +example : + GF2_48.ConcreteField.toSpec (1 : F) = 1 := + GF2_48.ConcreteField.toSpec_one + +example (a b : F) : + GF2_48.ConcreteField.toSpec (a + b) = + GF2_48.ConcreteField.toSpec a + GF2_48.ConcreteField.toSpec b := + GF2_48.ConcreteField.toSpec_add a b + +example (a b : F) : + GF2_48.ConcreteField.toSpec (a - b) = + GF2_48.ConcreteField.toSpec a - GF2_48.ConcreteField.toSpec b := + GF2_48.ConcreteField.toSpec_sub a b + +example (a b : F) : + GF2_48.ConcreteField.toSpec (a * b) = + GF2_48.ConcreteField.toSpec a * GF2_48.ConcreteField.toSpec b := + GF2_48.ConcreteField.toSpec_mul a b + +end CompPolyTests.Fields.Binary.GF2_48.Impl diff --git a/tests/CompPolyTests/Fields/Binary/GF2_48/RootContexts.lean b/tests/CompPolyTests/Fields/Binary/GF2_48/RootContexts.lean new file mode 100644 index 00000000..554b7e65 --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_48/RootContexts.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_48 +import CompPoly.Univariate.Roots.Shoup + +/-! +# GF(2^48) Root-Context Tests + +Focused compile-time checks for the certified finite-field, Shoup, and smooth +root-search contexts over executable `GF(2^48)`. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_48.RootContexts + +private abbrev F := GF2_48.ConcreteField + +example : + GF2_48.finiteFieldContext.q = GF2_48.fieldSize := + rfl + +example : + GF2_48.shoupTraceContext.toFiniteFieldContext.q = GF2_48.fieldSize := + rfl + +example : + GF2_48.smoothHornerRootContext.q = GF2_48.fieldSize := + rfl + +example : + GF2_48.smoothSubproductRootContext.q = GF2_48.fieldSize := + rfl + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.shoupLinearFactorProductSplitter + GF2_48.shoupTraceContext + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CompPoly.CPolynomial.Raw.MulContext.naive CompPoly.CPolynomial.Raw.ModContext.naive + GF2_48.smoothSubproductRootContext + +end CompPolyTests.Fields.Binary.GF2_48.RootContexts diff --git a/tests/CompPolyTests/Fields/Binary/GF2_64/Basic.lean b/tests/CompPolyTests/Fields/Binary/GF2_64/Basic.lean new file mode 100644 index 00000000..6f836180 --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_64/Basic.lean @@ -0,0 +1,44 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_64 + +/-! + # GF(2^64) Basic Tests + + Compile-time checks for the direct-extension specification surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_64.Basic + +example : GF2_64.definingPolynomial.natDegree = GF2_64.extensionDegree := + GF2_64.definingPolynomial_natDegree + +example : GF2_64.definingPolynomial.Monic := + GF2_64.definingPolynomial_monic + +example : GF2_64.definingPolynomial ≠ 0 := + GF2_64.definingPolynomial_ne_zero + +example : + Polynomial.eval₂ (algebraMap (ZMod 2) GF2_64.SpecField) GF2_64.root + GF2_64.definingPolynomial = 0 := + GF2_64.root_satisfies_definingPolynomial + +example : + BinaryField.Extension.sparsePolynomial GF2_64.definingPolynomialExponents = + GF2_64.definingPolynomial := + GF2_64.sparsePolynomial_definingPolynomialExponents + +#guard GF2_64.smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (GF2_64.fieldSize - 1) == 1 + +#guard GF2_64.primitivePrimeFactors == [3, 5, 17, 257, 641, 65537, 6700417] + +example : + GF2_64.multiplicativeGroupOrder = 3 * 5 * 17 * 257 * 641 * 65537 * 6700417 := + GF2_64.multiplicativeGroupOrder_factorization + +end CompPolyTests.Fields.Binary.GF2_64.Basic diff --git a/tests/CompPolyTests/Fields/Binary/GF2_64/Impl.lean b/tests/CompPolyTests/Fields/Binary/GF2_64/Impl.lean new file mode 100644 index 00000000..3d3a3f84 --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_64/Impl.lean @@ -0,0 +1,157 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_64 + +/-! + # GF(2^64) Executable Tests + + Regression checks for the raw `BitVec` executable carrier. These tests cover + the certified computation layer and the field typeclass surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_64.Impl + +private abbrev F := GF2_64.ConcreteField + +private def alpha : F := + GF2_64.ConcreteField.root + +private def tailFromPowers : F := + GF2_64.ConcreteField.add + (GF2_64.ConcreteField.add + (GF2_64.ConcreteField.add + ((GF2_64.ConcreteField.pow alpha 4)) + (GF2_64.ConcreteField.pow alpha 3)) + (GF2_64.ConcreteField.pow alpha 1)) + 1 + +#guard GF2_64.ConcreteField.toNat (GF2_64.ConcreteField.ofNat (2 ^ 64 + 5)) == 5 + +#guard GF2_64.ConcreteField.toNat + (GF2_64.ConcreteField.add (GF2_64.ConcreteField.ofNat 0x1234) + (GF2_64.ConcreteField.ofNat 0x00f0)) == 0x12c4 + +#guard GF2_64.ConcreteField.toNat + (GF2_64.ConcreteField.mul (GF2_64.ConcreteField.ofNat 3) + (GF2_64.ConcreteField.ofNat 5)) == 15 + +#guard GF2_64.ConcreteField.pow alpha 64 == tailFromPowers + +#guard GF2_64.ConcreteField.toNat (GF2_64.ConcreteField.pow alpha 64) == 27 + +#guard GF2_64.ConcreteField.toNat (GF2_64.ConcreteField.traceValue 1) == 0 + +example : + Fintype.card F = 2 ^ GF2_64.extensionDegree := + GF2_64.ConcreteField.card + +example : GF2_64.ConcreteField.polynomialBasis.size = GF2_64.extensionDegree := + GF2_64.ConcreteField.polynomialBasis_size + +example : GF2_64.ConcreteField.baseConstants.size = 2 := + GF2_64.ConcreteField.baseConstants_size + +example : AddCommGroup F := + inferInstance + +noncomputable example : Field F := + inferInstance + +noncomputable example : CharP F 2 := + inferInstance + +noncomputable example : Algebra (ZMod 2) F := + inferInstance + +example : GF2_64.finiteFieldContext.q = GF2_64.fieldSize := + rfl + +example : Nat.card F = GF2_64.fieldSize := + GF2_64.finiteFieldContext.card_eq + +noncomputable example (a : F) : a ^ GF2_64.finiteFieldContext.q = a := + GF2_64.finiteFieldContext.frobenius_fixed a + +example : + orderOf GF2_64.primitiveRoot = GF2_64.fieldSize - 1 := + GF2_64.primitiveRoot_order + +example : + GF2_64.smoothHornerRootContext.q = GF2_64.fieldSize := + rfl + +example : + GF2_64.smoothHornerRootContext.generator = GF2_64.primitiveRoot := + rfl + +example : + GF2_64.smoothSubproductRootContext.q = GF2_64.fieldSize := + rfl + +example : + GF2_64.smoothSubproductRootContext.generator = GF2_64.primitiveRoot := + rfl + +example : GF2_64.shoupTraceContext.p = 2 := + rfl + +example : GF2_64.shoupTraceContext.k = GF2_64.extensionDegree := + rfl + +example : + GF2_64.shoupTraceContext.baseConstants.size = GF2_64.shoupTraceContext.p := + GF2_64.shoupTraceContext.baseConstants_size + +example : + GF2_64.shoupTraceContext.basis.size = GF2_64.shoupTraceContext.k := + GF2_64.shoupTraceContext.basis_size + +noncomputable example (z : F) : + GF2_64.shoupTraceContext.traceValue z = + CompPoly.CPolynomial.Roots.FiniteField.tracePowerSum 2 GF2_64.extensionDegree z := + GF2_64.shoupTraceContext.traceValue_eq_powerSum z + +noncomputable example (z : F) : + GF2_64.shoupTraceContext.traceValue z ∈ + GF2_64.shoupTraceContext.baseConstants.toList := + GF2_64.shoupTraceContext.traceValue_mem_base z + +noncomputable example {a b : F} (hne : a ≠ b) : + ∃ beta, beta ∈ GF2_64.shoupTraceContext.basis.toList ∧ + GF2_64.shoupTraceContext.traceValue (beta * (a - b)) ≠ 0 := + GF2_64.shoupTraceContext.trace_separates hne + +example : Function.Injective GF2_64.ConcreteField.toSpec := + GF2_64.ConcreteField.toSpec_injective + +example : + GF2_64.ConcreteField.toSpec GF2_64.ConcreteField.root = GF2_64.root := + GF2_64.ConcreteField.toSpec_root + +example : + GF2_64.ConcreteField.toSpec (0 : F) = 0 := + GF2_64.ConcreteField.toSpec_zero + +example : + GF2_64.ConcreteField.toSpec (1 : F) = 1 := + GF2_64.ConcreteField.toSpec_one + +example (a b : F) : + GF2_64.ConcreteField.toSpec (a + b) = + GF2_64.ConcreteField.toSpec a + GF2_64.ConcreteField.toSpec b := + GF2_64.ConcreteField.toSpec_add a b + +example (a b : F) : + GF2_64.ConcreteField.toSpec (a - b) = + GF2_64.ConcreteField.toSpec a - GF2_64.ConcreteField.toSpec b := + GF2_64.ConcreteField.toSpec_sub a b + +example (a b : F) : + GF2_64.ConcreteField.toSpec (a * b) = + GF2_64.ConcreteField.toSpec a * GF2_64.ConcreteField.toSpec b := + GF2_64.ConcreteField.toSpec_mul a b + +end CompPolyTests.Fields.Binary.GF2_64.Impl diff --git a/tests/CompPolyTests/Fields/Binary/GF2_64/RootContexts.lean b/tests/CompPolyTests/Fields/Binary/GF2_64/RootContexts.lean new file mode 100644 index 00000000..6c109cef --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_64/RootContexts.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_64 +import CompPoly.Univariate.Roots.Shoup + +/-! +# GF(2^64) Root-Context Tests + +Focused compile-time checks for the certified finite-field, Shoup, and smooth +root-search contexts over executable `GF(2^64)`. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_64.RootContexts + +private abbrev F := GF2_64.ConcreteField + +example : + GF2_64.finiteFieldContext.q = GF2_64.fieldSize := + rfl + +example : + GF2_64.shoupTraceContext.toFiniteFieldContext.q = GF2_64.fieldSize := + rfl + +example : + GF2_64.smoothHornerRootContext.q = GF2_64.fieldSize := + rfl + +example : + GF2_64.smoothSubproductRootContext.q = GF2_64.fieldSize := + rfl + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.shoupLinearFactorProductSplitter + GF2_64.shoupTraceContext + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CompPoly.CPolynomial.Raw.MulContext.naive CompPoly.CPolynomial.Raw.ModContext.naive + GF2_64.smoothSubproductRootContext + +end CompPolyTests.Fields.Binary.GF2_64.RootContexts diff --git a/tests/CompPolyTests/Fields/Binary/GF2_72/Basic.lean b/tests/CompPolyTests/Fields/Binary/GF2_72/Basic.lean new file mode 100644 index 00000000..23447b17 --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_72/Basic.lean @@ -0,0 +1,46 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_72 + +/-! + # GF(2^72) Basic Tests + + Compile-time checks for the direct-extension specification surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_72.Basic + +example : GF2_72.definingPolynomial.natDegree = GF2_72.extensionDegree := + GF2_72.definingPolynomial_natDegree + +example : GF2_72.definingPolynomial.Monic := + GF2_72.definingPolynomial_monic + +example : GF2_72.definingPolynomial ≠ 0 := + GF2_72.definingPolynomial_ne_zero + +example : + Polynomial.eval₂ (algebraMap (ZMod 2) GF2_72.SpecField) GF2_72.root + GF2_72.definingPolynomial = 0 := + GF2_72.root_satisfies_definingPolynomial + +example : + BinaryField.Extension.sparsePolynomial GF2_72.definingPolynomialExponents = + GF2_72.definingPolynomial := + GF2_72.sparsePolynomial_definingPolynomialExponents + +#guard GF2_72.smoothRootSchedule.toList.foldl (fun order ell ↦ order / ell) + (GF2_72.fieldSize - 1) == 1 + +#guard GF2_72.primitivePrimeFactors == + [3, 5, 7, 13, 17, 19, 37, 73, 109, 241, 433, 38737] + +example : + GF2_72.multiplicativeGroupOrder = + 3 ^ 3 * 5 * 7 * 13 * 17 * 19 * 37 * 73 * 109 * 241 * 433 * 38737 := + GF2_72.multiplicativeGroupOrder_factorization + +end CompPolyTests.Fields.Binary.GF2_72.Basic diff --git a/tests/CompPolyTests/Fields/Binary/GF2_72/Impl.lean b/tests/CompPolyTests/Fields/Binary/GF2_72/Impl.lean new file mode 100644 index 00000000..67e2411c --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_72/Impl.lean @@ -0,0 +1,161 @@ +/- +Copyright (c) 2026 CompPoly. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ +import CompPoly.Fields.Binary.GF2_72 + +/-! + # GF(2^72) Executable Tests + + Regression checks for the raw `BitVec` executable carrier. These tests cover + the certified computation layer and the field typeclass surface. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_72.Impl + +private abbrev F := GF2_72.ConcreteField + +private def alpha : F := + GF2_72.ConcreteField.root + +private def tailFromPowers : F := + GF2_72.ConcreteField.add + (GF2_72.ConcreteField.add + (GF2_72.ConcreteField.add + (GF2_72.ConcreteField.add + (GF2_72.ConcreteField.add + (GF2_72.ConcreteField.pow alpha 6) + (GF2_72.ConcreteField.pow alpha 4)) + (GF2_72.ConcreteField.pow alpha 3)) + (GF2_72.ConcreteField.pow alpha 2)) + alpha) + 1 + +#guard GF2_72.ConcreteField.toNat (GF2_72.ConcreteField.ofNat (2 ^ 72 + 5)) == 5 + +#guard GF2_72.ConcreteField.toNat + (GF2_72.ConcreteField.add (GF2_72.ConcreteField.ofNat 0x1234) + (GF2_72.ConcreteField.ofNat 0x00f0)) == 0x12c4 + +#guard GF2_72.ConcreteField.toNat + (GF2_72.ConcreteField.mul (GF2_72.ConcreteField.ofNat 3) + (GF2_72.ConcreteField.ofNat 5)) == 15 + +#guard GF2_72.ConcreteField.pow alpha 72 == tailFromPowers + +#guard GF2_72.ConcreteField.toNat (GF2_72.ConcreteField.pow alpha 72) == 95 + +#guard GF2_72.ConcreteField.toNat (GF2_72.ConcreteField.traceValue 1) == 0 + +example : + Fintype.card F = 2 ^ GF2_72.extensionDegree := + GF2_72.ConcreteField.card + +example : GF2_72.ConcreteField.polynomialBasis.size = GF2_72.extensionDegree := + GF2_72.ConcreteField.polynomialBasis_size + +example : GF2_72.ConcreteField.baseConstants.size = 2 := + GF2_72.ConcreteField.baseConstants_size + +example : AddCommGroup F := + inferInstance + +noncomputable example : Field F := + inferInstance + +noncomputable example : CharP F 2 := + inferInstance + +noncomputable example : Algebra (ZMod 2) F := + inferInstance + +example : GF2_72.finiteFieldContext.q = GF2_72.fieldSize := + rfl + +example : Nat.card F = GF2_72.fieldSize := + GF2_72.finiteFieldContext.card_eq + +noncomputable example (a : F) : a ^ GF2_72.finiteFieldContext.q = a := + GF2_72.finiteFieldContext.frobenius_fixed a + +example : + orderOf GF2_72.primitiveRoot = GF2_72.fieldSize - 1 := + GF2_72.primitiveRoot_order + +example : + GF2_72.smoothHornerRootContext.q = GF2_72.fieldSize := + rfl + +example : + GF2_72.smoothHornerRootContext.generator = GF2_72.primitiveRoot := + rfl + +example : + GF2_72.smoothSubproductRootContext.q = GF2_72.fieldSize := + rfl + +example : + GF2_72.smoothSubproductRootContext.generator = GF2_72.primitiveRoot := + rfl + +example : GF2_72.shoupTraceContext.p = 2 := + rfl + +example : GF2_72.shoupTraceContext.k = GF2_72.extensionDegree := + rfl + +example : + GF2_72.shoupTraceContext.baseConstants.size = GF2_72.shoupTraceContext.p := + GF2_72.shoupTraceContext.baseConstants_size + +example : + GF2_72.shoupTraceContext.basis.size = GF2_72.shoupTraceContext.k := + GF2_72.shoupTraceContext.basis_size + +noncomputable example (z : F) : + GF2_72.shoupTraceContext.traceValue z = + CompPoly.CPolynomial.Roots.FiniteField.tracePowerSum 2 GF2_72.extensionDegree z := + GF2_72.shoupTraceContext.traceValue_eq_powerSum z + +noncomputable example (z : F) : + GF2_72.shoupTraceContext.traceValue z ∈ + GF2_72.shoupTraceContext.baseConstants.toList := + GF2_72.shoupTraceContext.traceValue_mem_base z + +noncomputable example {a b : F} (hne : a ≠ b) : + ∃ beta, beta ∈ GF2_72.shoupTraceContext.basis.toList ∧ + GF2_72.shoupTraceContext.traceValue (beta * (a - b)) ≠ 0 := + GF2_72.shoupTraceContext.trace_separates hne + +example : Function.Injective GF2_72.ConcreteField.toSpec := + GF2_72.ConcreteField.toSpec_injective + +example : + GF2_72.ConcreteField.toSpec GF2_72.ConcreteField.root = GF2_72.root := + GF2_72.ConcreteField.toSpec_root + +example : + GF2_72.ConcreteField.toSpec (0 : F) = 0 := + GF2_72.ConcreteField.toSpec_zero + +example : + GF2_72.ConcreteField.toSpec (1 : F) = 1 := + GF2_72.ConcreteField.toSpec_one + +example (a b : F) : + GF2_72.ConcreteField.toSpec (a + b) = + GF2_72.ConcreteField.toSpec a + GF2_72.ConcreteField.toSpec b := + GF2_72.ConcreteField.toSpec_add a b + +example (a b : F) : + GF2_72.ConcreteField.toSpec (a - b) = + GF2_72.ConcreteField.toSpec a - GF2_72.ConcreteField.toSpec b := + GF2_72.ConcreteField.toSpec_sub a b + +example (a b : F) : + GF2_72.ConcreteField.toSpec (a * b) = + GF2_72.ConcreteField.toSpec a * GF2_72.ConcreteField.toSpec b := + GF2_72.ConcreteField.toSpec_mul a b + +end CompPolyTests.Fields.Binary.GF2_72.Impl diff --git a/tests/CompPolyTests/Fields/Binary/GF2_72/RootContexts.lean b/tests/CompPolyTests/Fields/Binary/GF2_72/RootContexts.lean new file mode 100644 index 00000000..128e972e --- /dev/null +++ b/tests/CompPolyTests/Fields/Binary/GF2_72/RootContexts.lean @@ -0,0 +1,48 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_72 +import CompPoly.Univariate.Roots.Shoup + +/-! +# GF(2^72) Root-Context Tests + +Focused compile-time checks for the certified finite-field, Shoup, and smooth +root-search contexts over executable `GF(2^72)`. +-/ + +namespace CompPolyTests.Fields.Binary.GF2_72.RootContexts + +private abbrev F := GF2_72.ConcreteField + +example : + GF2_72.finiteFieldContext.q = GF2_72.fieldSize := + rfl + +example : + GF2_72.shoupTraceContext.toFiniteFieldContext.q = GF2_72.fieldSize := + rfl + +example : + GF2_72.smoothHornerRootContext.q = GF2_72.fieldSize := + rfl + +example : + GF2_72.smoothSubproductRootContext.q = GF2_72.fieldSize := + rfl + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.shoupLinearFactorProductSplitter + GF2_72.shoupTraceContext + +noncomputable example : + CompPoly.CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F := + CompPoly.CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CompPoly.CPolynomial.Raw.MulContext.naive CompPoly.CPolynomial.Raw.ModContext.naive + GF2_72.smoothSubproductRootContext + +end CompPolyTests.Fields.Binary.GF2_72.RootContexts diff --git a/tests/CompPolyTests/Univariate/Roots/Binary.lean b/tests/CompPolyTests/Univariate/Roots/Binary.lean new file mode 100644 index 00000000..2f53808b --- /dev/null +++ b/tests/CompPolyTests/Univariate/Roots/Binary.lean @@ -0,0 +1,78 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.GF2_48 +import CompPoly.Fields.Binary.GF2_72 +import CompPoly.Univariate.Roots + +/-! +# Binary-Field Univariate Root Tests + +Instantiation checks for the executable univariate finite-field root backend over +`GF(2^48)` and `GF(2^72)` with Shoup and smooth splitters. +-/ + +namespace CompPolyTests.Univariate.Roots.Binary + +open CompPoly + +private abbrev F48 := GF2_48.ConcreteField +private abbrev F72 := GF2_72.ConcreteField + +private def rootsWith {F : Type*} [Field F] [BEq F] [LawfulBEq F] + (ctx : CPolynomial.Roots.FiniteField.FiniteFieldContext F) + (splitter : CPolynomial.Roots.FiniteField.LinearFactorProductSplitter F) + (p : CPolynomial F) : Array F := + CPolynomial.Roots.FiniteField.rootsInFiniteFieldWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive ctx splitter p + +noncomputable example (p : CPolynomial F48) : + Array F48 := + rootsWith GF2_48.finiteFieldContext + (CPolynomial.Roots.FiniteField.shoupLinearFactorProductSplitter + GF2_48.shoupTraceContext) + p + +noncomputable example (p : CPolynomial F48) : + Array F48 := + rootsWith GF2_48.finiteFieldContext + (CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive + GF2_48.smoothHornerRootContext) + p + +noncomputable example (p : CPolynomial F48) : + Array F48 := + rootsWith GF2_48.finiteFieldContext + (CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive + GF2_48.smoothSubproductRootContext) + p + +noncomputable example (p : CPolynomial F72) : + Array F72 := + rootsWith GF2_72.finiteFieldContext + (CPolynomial.Roots.FiniteField.shoupLinearFactorProductSplitter + GF2_72.shoupTraceContext) + p + +noncomputable example (p : CPolynomial F72) : + Array F72 := + rootsWith GF2_72.finiteFieldContext + (CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive + GF2_72.smoothHornerRootContext) + p + +noncomputable example (p : CPolynomial F72) : + Array F72 := + rootsWith GF2_72.finiteFieldContext + (CPolynomial.Roots.FiniteField.smoothLinearFactorProductSplitterWith + CPolynomial.Raw.MulContext.naive CPolynomial.Raw.ModContext.naive + GF2_72.smoothSubproductRootContext) + p + +end CompPolyTests.Univariate.Roots.Binary diff --git a/tests/CompPolyTests/Univariate/Roots/Shoup.lean b/tests/CompPolyTests/Univariate/Roots/Shoup.lean new file mode 100644 index 00000000..b8c42488 --- /dev/null +++ b/tests/CompPolyTests/Univariate/Roots/Shoup.lean @@ -0,0 +1,184 @@ +/- +Copyright (c) 2026 CompPoly Contributors. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. +Authors: Valerii Huhnin +-/ + +import CompPoly.Fields.Binary.Tower.Impl +import CompPoly.Univariate.Roots.Shoup +import Mathlib.Algebra.Field.ZMod + +/-! +# Shoup-Style Univariate Root Tests + +Focused executable coverage for the small-characteristic trace splitter over +`ZMod 2`, the degree-one binary-field case. +-/ + +namespace CompPolyTests + +open CompPoly +open CompPoly.CPolynomial.Roots.FiniteField + +namespace Univariate.Roots.Shoup + +abbrev F2 := ZMod 2 + +instance : Fact (Nat.Prime 2) := + ⟨by decide⟩ + +private def f2ShoupCtx : SmallPrimeTraceContext F2 where + q := 2 + finite := by infer_instance + card_eq := by + simp [F2, Nat.card_eq_fintype_card, ZMod.card] + frobenius_fixed := by decide + p := 2 + k := 1 + p_prime := by decide + q_eq := by decide + baseConstants := #[(0 : F2), 1] + baseConstants_size := by rfl + basis := #[(1 : F2)] + basis_size := by rfl + traceValue := id + traceValue_eq_powerSum := by + intro z + simp [tracePowerSum] + traceValue_mem_base := by decide + trace_separates := by + intro a b hne + refine ⟨(1 : F2), by simp, ?_⟩ + simpa only [one_mul, id_eq] using (sub_ne_zero.mpr hne) + +private def f2ShoupSplitter : LinearFactorProductSplitter F2 := + shoupLinearFactorProductSplitter f2ShoupCtx + +private def rootsInF2 (p : CPolynomial F2) : Array F2 := + rootsInFiniteField f2ShoupCtx.toFiniteFieldContext f2ShoupSplitter p + +private def f2NoRootQuadratic : CPolynomial F2 := + CPolynomial.ofArray #[(1 : F2), 1, 1] + +private def f2AllRoots : CPolynomial F2 := + CPolynomial.linearFactor (0 : F2) * CPolynomial.linearFactor (1 : F2) + +private def f2RepeatedRoots : CPolynomial F2 := + CPolynomial.linearFactor (0 : F2) * + CPolynomial.linearFactor (0 : F2) * + CPolynomial.linearFactor (1 : F2) + +private def f2PartialRoots : CPolynomial F2 := + CPolynomial.linearFactor (0 : F2) * f2NoRootQuadratic + +private def f2ZeroRootOnly : CPolynomial F2 := + CPolynomial.linearFactor (0 : F2) + +private def allRootsOut : Array F2 := + rootsInF2 f2AllRoots + +#guard allRootsOut.contains (0 : F2) +#guard allRootsOut.contains (1 : F2) +#guard allRootsOut.size == 2 + +private def repeatedRootsOut : Array F2 := + rootsInF2 f2RepeatedRoots + +#guard repeatedRootsOut.contains (0 : F2) +#guard repeatedRootsOut.contains (1 : F2) +#guard repeatedRootsOut.size == 2 + +private def zeroRootOut : Array F2 := + rootsInF2 f2ZeroRootOnly + +#guard zeroRootOut.contains (0 : F2) +#guard zeroRootOut.size == 1 + +#guard (rootsInF2 f2NoRootQuadratic).isEmpty + +private def partialRootsOut : Array F2 := + rootsInF2 f2PartialRoots + +#guard partialRootsOut.contains (0 : F2) +#guard !(partialRootsOut.contains (1 : F2)) +#guard partialRootsOut.size == 1 + +abbrev BT0 := ConcreteBinaryTower.ConcreteBTField 0 + +private theorem bt0_card : Nat.card BT0 = 2 := by + rw [Nat.card_eq_fintype_card] + simpa [BT0] using + (ConcreteBinaryTower.getBTFResult 0).fieldFintypeCard + +private def bt0ShoupCtx : SmallPrimeTraceContext BT0 where + q := 2 + finite := by infer_instance + card_eq := bt0_card + frobenius_fixed := by + intro a + have h := FiniteField.pow_card a + simpa [bt0_card] using h + p := 2 + k := 1 + p_prime := by decide + q_eq := by decide + baseConstants := #[(0 : BT0), 1] + baseConstants_size := by rfl + basis := #[(1 : BT0)] + basis_size := by rfl + traceValue := id + traceValue_eq_powerSum := by + intro z + simp [tracePowerSum] + traceValue_mem_base := by decide + trace_separates := by + intro a b hne + refine ⟨(1 : BT0), by simp, ?_⟩ + simpa only [one_mul, id_eq] using (sub_ne_zero.mpr hne) + +private def bt0ShoupSplitter : LinearFactorProductSplitter BT0 := + shoupLinearFactorProductSplitter bt0ShoupCtx + +private def rootsInBT0 (p : CPolynomial BT0) : Array BT0 := + rootsInFiniteField bt0ShoupCtx.toFiniteFieldContext bt0ShoupSplitter p + +private def bt0NoRootQuadratic : CPolynomial BT0 := + CPolynomial.ofArray #[(1 : BT0), 1, 1] + +private def bt0AllRoots : CPolynomial BT0 := + CPolynomial.linearFactor (0 : BT0) * CPolynomial.linearFactor (1 : BT0) + +private def bt0RepeatedRoots : CPolynomial BT0 := + CPolynomial.linearFactor (0 : BT0) * + CPolynomial.linearFactor (0 : BT0) * + CPolynomial.linearFactor (1 : BT0) + +private def bt0PartialRoots : CPolynomial BT0 := + CPolynomial.linearFactor (0 : BT0) * bt0NoRootQuadratic + +private def bt0AllRootsOut : Array BT0 := + rootsInBT0 bt0AllRoots + +#guard bt0AllRootsOut.contains (0 : BT0) +#guard bt0AllRootsOut.contains (1 : BT0) +#guard bt0AllRootsOut.size == 2 + +private def bt0RepeatedRootsOut : Array BT0 := + rootsInBT0 bt0RepeatedRoots + +#guard bt0RepeatedRootsOut.contains (0 : BT0) +#guard bt0RepeatedRootsOut.contains (1 : BT0) +#guard bt0RepeatedRootsOut.size == 2 + +#guard (rootsInBT0 bt0NoRootQuadratic).isEmpty + +private def bt0PartialRootsOut : Array BT0 := + rootsInBT0 bt0PartialRoots + +#guard bt0PartialRootsOut.contains (0 : BT0) +#guard !(bt0PartialRootsOut.contains (1 : BT0)) +#guard bt0PartialRootsOut.size == 1 + +end Univariate.Roots.Shoup + +end CompPolyTests