Documentation

HexPolyFp.Quotient

def Hex.FpPoly.Quotient.Internal.evalCoeffList {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} :
List (g.Quotient hmonic hg_pos)g.Quotient hmonic hg_posg.Quotient hmonic hg_pos

Evaluate a low-to-high quotient-coefficient list at a quotient point.

The list [c₀, c₁, ...] denotes c₀ + β * (c₁ + β * (...)). This proof-facing evaluator is used by quotient-field root-count arguments where the coefficients already live in F_p[X] / (g).

Equations
Instances For
    @[simp]
    theorem Hex.FpPoly.Quotient.Internal.evalCoeffList_nil {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (β : g.Quotient hmonic hg_pos) :

    Evaluating the empty quotient-coefficient list gives zero.

    @[simp]
    theorem Hex.FpPoly.Quotient.Internal.evalCoeffList_cons {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (c : g.Quotient hmonic hg_pos) (cs : List (g.Quotient hmonic hg_pos)) (β : g.Quotient hmonic hg_pos) :
    evalCoeffList (c :: cs) β = c + β * evalCoeffList cs β

    Evaluating a nonempty quotient-coefficient list unfolds one Horner step.

    def Hex.FpPoly.Quotient.Internal.dividedDifferenceCoeffs {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} :
    List (g.Quotient hmonic hg_pos)g.Quotient hmonic hg_posList (g.Quotient hmonic hg_pos)

    Synthetic quotient coefficients for the divided difference of cs at the base point α.

    If P is represented by cs, this list represents the quotient (P(T) - P(α)) / (T - α). Its length is one less than the input list, which is the measure used by root-count induction.

    Equations
    Instances For
      @[simp]

      The divided-difference coefficient list of the empty list is empty.

      @[simp]

      A constant polynomial has empty divided-difference coefficient list.

      @[simp]
      theorem Hex.FpPoly.Quotient.Internal.dividedDifferenceCoeffs_cons_cons {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (c d : g.Quotient hmonic hg_pos) (cs : List (g.Quotient hmonic hg_pos)) (α : g.Quotient hmonic hg_pos) :

      The divided-difference coefficient recursion peels the constant term and evaluates the remaining tail at the base point.

      @[simp]
      theorem Hex.FpPoly.Quotient.Internal.dividedDifferenceCoeffs_length {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (cs : List (g.Quotient hmonic hg_pos)) (α : g.Quotient hmonic hg_pos) :

      The synthetic divided-difference coefficient list has one fewer entry.

      theorem Hex.FpPoly.Quotient.Internal.dividedDifferenceCoeffs_length_lt_of_ne_nil {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} {cs : List (g.Quotient hmonic hg_pos)} (hcs : cs []) (α : g.Quotient hmonic hg_pos) :

      The synthetic divided-difference coefficient list is strictly shorter for nonempty input.

      def Hex.FpPoly.Quotient.Internal.dividedDifference {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (cs : List (g.Quotient hmonic hg_pos)) (α β : g.Quotient hmonic hg_pos) :
      g.Quotient hmonic hg_pos

      Evaluate the divided difference of a quotient-coefficient polynomial between the base point α and target point β.

      Equations
      Instances For
        @[simp]
        theorem Hex.FpPoly.Quotient.Internal.dividedDifference_nil {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (α β : g.Quotient hmonic hg_pos) :

        The divided difference of the empty coefficient list is zero.

        @[simp]
        theorem Hex.FpPoly.Quotient.Internal.dividedDifference_cons {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (c d : g.Quotient hmonic hg_pos) (cs : List (g.Quotient hmonic hg_pos)) (α β : g.Quotient hmonic hg_pos) :
        dividedDifference (c :: d :: cs) α β = evalCoeffList (d :: cs) α + β * dividedDifference (d :: cs) α β

        A nonconstant divided difference unfolds as a Horner step over the synthetic coefficient tail.

        theorem Hex.FpPoly.Quotient.Internal.evalCoeffList_sub_evalCoeffList_eq_sub_mul_dividedDifference {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (cs : List (g.Quotient hmonic hg_pos)) (α β : g.Quotient hmonic hg_pos) :
        evalCoeffList cs β - evalCoeffList cs α = (β - α) * dividedDifference cs α β

        The quotient-coefficient divided difference satisfies the usual identity P(β) - P(α) = (β - α) * DD(P, α, β).

        noncomputable def Hex.FpPoly.Quotient.Internal.eval {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) (β : g.Quotient hmonic hg_pos) :
        g.Quotient hmonic hg_pos

        Evaluate an FpPoly at a quotient element by Horner iteration in the quotient.

        The coefficients are embedded as constant quotient classes. This is a project-side evaluation layer for root-counting arguments over F_p[X] / (g), without introducing a ring typeclass for the executable quotient representation.

        Equations
        • One or more equations did not get rendered due to their size.
        Instances For
          noncomputable def Hex.FpPoly.Quotient.Internal.evalQuotientCoeffs {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) :
          List (g.Quotient hmonic hg_pos)

          Stored FpPoly coefficients embedded as quotient constants, in low-to-high coefficient order.

          Equations
          Instances For
            @[simp]
            theorem Hex.FpPoly.Quotient.Internal.eval_zero {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (β : g.Quotient hmonic hg_pos) :
            eval 0 β = 0

            Evaluating the zero polynomial in the quotient gives zero.

            @[simp]
            theorem Hex.FpPoly.Quotient.Internal.eval_C {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (c : ZMod64 p) (β : g.Quotient hmonic hg_pos) :

            Evaluating a constant polynomial gives the corresponding constant quotient class.

            @[simp]
            theorem Hex.FpPoly.Quotient.Internal.eval_X {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (β : g.Quotient hmonic hg_pos) :

            Evaluating the polynomial indeterminate gives the input quotient element.

            Quotient evaluation of an FpPoly agrees with the proof-facing quotient-coefficient evaluator on the embedded stored coefficient list.

            noncomputable def Hex.FpPoly.Quotient.Internal.evalDividedDifference {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) (α β : g.Quotient hmonic hg_pos) :
            g.Quotient hmonic hg_pos

            FpPoly-specific divided-difference quotient evaluated between α and β, using the existing executable coefficient representation.

            Equations
            Instances For
              noncomputable def Hex.FpPoly.Quotient.Internal.evalDividedDifferenceCoeffs {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) (α : g.Quotient hmonic hg_pos) :
              List (g.Quotient hmonic hg_pos)

              Synthetic quotient coefficients for the FpPoly divided difference at α.

              Equations
              Instances For
                @[simp]

                Evaluating the executable divided difference is the quotient-coefficient evaluator applied to its synthetic coefficient list.

                @[simp]

                The executable divided-difference coefficient list has one fewer entry than the embedded coefficient list.

                The executable divided-difference coefficient list is strictly shorter whenever the embedded input coefficient list is nonempty.

                theorem Hex.FpPoly.Quotient.Internal.eval_sub_eval_eq_sub_mul_evalDividedDifference {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) (α β : g.Quotient hmonic hg_pos) :
                eval f β - eval f α = (β - α) * evalDividedDifference f α β

                FpPoly quotient evaluation satisfies the divided-difference identity.

                theorem Hex.FpPoly.Quotient.Internal.eval_eq_sub_mul_evalDividedDifference_of_eval_eq_zero {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) (α : g.Quotient hmonic hg_pos) ( : eval f α = 0) (β : g.Quotient hmonic hg_pos) :
                eval f β = (β - α) * evalDividedDifference f α β

                If α is a quotient root of f, every value of f factors by β - α through the executable-coefficient divided difference.

                theorem Hex.FpPoly.Quotient.Internal.eval_add {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f h : FpPoly p) (β : g.Quotient hmonic hg_pos) :
                eval (f + h) β = eval f β + eval h β

                Evaluation of a sum equals the sum of the evaluations.

                theorem Hex.FpPoly.Quotient.Internal.eval_sub {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f h : FpPoly p) (β : g.Quotient hmonic hg_pos) :
                eval (f - h) β = eval f β - eval h β

                Evaluation of a difference equals the difference of the evaluations.

                theorem Hex.FpPoly.Quotient.Internal.eval_C_mul {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (c : ZMod64 p) (f : FpPoly p) (β : g.Quotient hmonic hg_pos) :

                Evaluation of a constant multiple equals the reduced constant times the evaluation.

                theorem Hex.FpPoly.Quotient.Internal.eval_monomial {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (n : Nat) (c : ZMod64 p) (β : g.Quotient hmonic hg_pos) :

                Evaluating monomial n c yields the reduced constant C c times the n-th power of the evaluation point.

                theorem Hex.FpPoly.Quotient.Internal.mul_left_ne_zero_of_ne_zero {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) {a b : g.Quotient hmonic hg_pos} (ha : a 0) (hb : b 0) :
                a * b 0

                For a monic irreducible positive-degree modulus, the product of two nonzero quotient elements is nonzero.

                theorem Hex.FpPoly.Quotient.Internal.mul_left_injective {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) {a : g.Quotient hmonic hg_pos} (ha : a 0) {b₁ b₂ : g.Quotient hmonic hg_pos} (heq : a * b₁ = a * b₂) :
                b₁ = b₂

                Left multiplication by a nonzero quotient element is injective on the quotient under an irreducible modulus.

                The highest coefficient in a low-to-high quotient coefficient list is nonzero.

                This predicate is the syntactic degree witness used by root-count induction: such a list represents a nonzero quotient-coefficient polynomial of degree cs.length - 1.

                Equations
                Instances For
                  def Hex.FpPoly.Quotient.Internal.rootsOfCoeffList {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (cs : List (g.Quotient hmonic hg_pos)) :
                  List (g.Quotient hmonic hg_pos)

                  Roots of a quotient-coefficient polynomial inside the canonical quotient enumeration.

                  Equations
                  • One or more equations did not get rendered due to their size.
                  Instances For
                    @[simp]
                    theorem Hex.FpPoly.Quotient.Internal.mem_rootsOfCoeffList {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (cs : List (g.Quotient hmonic hg_pos)) (β : g.Quotient hmonic hg_pos) :

                    Membership in rootsOfCoeffList cs is exactly vanishing of the quotient-coefficient evaluator.

                    The quotient-coefficient root list has no duplicate roots.

                    A nonzero quotient-coefficient polynomial has at most its degree many roots in the duplicate-free quotient enumeration.

                    The coefficient list is low-to-high, and coeffListTopNonzero cs says the highest listed coefficient is nonzero, so the degree bound is cs.length - 1.

                    theorem Hex.FpPoly.Quotient.Internal.evalCoeffList_rootsIn_elements_length_le_degree {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) (cs : List (g.Quotient hmonic hg_pos)) (htop : coeffListTopNonzero cs) :
                    (List.filter (fun (β : g.Quotient hmonic hg_pos) => decide (evalCoeffList cs β = 0)) elements).length cs.length - 1

                    Direct root-count bound for the canonical elements filter form used by callers.

                    noncomputable def Hex.FpPoly.Quotient.Internal.rootsOfFpPoly {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) :
                    List (g.Quotient hmonic hg_pos)

                    Roots of an FpPoly quotient evaluation inside the canonical quotient enumeration.

                    Equations
                    Instances For
                      @[simp]
                      theorem Hex.FpPoly.Quotient.Internal.mem_rootsOfFpPoly {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (f : FpPoly p) (β : g.Quotient hmonic hg_pos) :
                      β rootsOfFpPoly f eval f β = 0

                      Membership in rootsOfFpPoly f is exactly vanishing of quotient evaluation of f.

                      The FpPoly quotient-evaluation root list has no duplicate roots.

                      A nonzero FpPoly has at most f.size - 1 quotient roots in the duplicate-free quotient enumeration, provided the modulus is irreducible.

                      theorem Hex.FpPoly.Quotient.Internal.eval_rootsIn_elements_length_le_degree {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) (f : FpPoly p) (hf : f 0) :
                      (List.filter (fun (β : g.Quotient hmonic hg_pos) => decide (eval f β = 0)) elements).length DensePoly.size f - 1

                      Direct root-count bound for the canonical elements filter form used by callers evaluating an FpPoly in the quotient.

                      theorem Hex.FpPoly.Quotient.Internal.nonzeroElements_map_mul_left_perm {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) {a : g.Quotient hmonic hg_pos} (ha : a 0) :
                      (List.map (fun (b : g.Quotient hmonic hg_pos) => a * b) nonzeroElements).Perm nonzeroElements

                      Multiplication by a nonzero quotient element permutes the nonzero enumeration. The list of nonzero elements multiplied on the left by a is a permutation of the original nonzero list.

                      The quotient is nontrivial: 1 and 0 are distinct quotient elements under a positive-degree modulus.

                      def Hex.FpPoly.Quotient.Internal.listProd {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (xs : List (g.Quotient hmonic hg_pos)) :
                      g.Quotient hmonic hg_pos

                      Product of a list of quotient elements (right fold).

                      Equations
                      Instances For
                        @[simp]

                        The product of an empty quotient list is one.

                        @[simp]
                        theorem Hex.FpPoly.Quotient.Internal.listProd_cons {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (x : g.Quotient hmonic hg_pos) (xs : List (g.Quotient hmonic hg_pos)) :
                        listProd (x :: xs) = x * listProd xs

                        The product of a cons list multiplies the head by the product of the tail.

                        theorem Hex.FpPoly.Quotient.Internal.listProd_append {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (xs ys : List (g.Quotient hmonic hg_pos)) :
                        listProd (xs ++ ys) = listProd xs * listProd ys

                        The product of an appended quotient list factors as the product of the two pieces.

                        theorem Hex.FpPoly.Quotient.Internal.listProd_perm {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} {xs ys : List (g.Quotient hmonic hg_pos)} (h : xs.Perm ys) :

                        The list product is invariant under List.Perm.

                        theorem Hex.FpPoly.Quotient.Internal.listProd_map_mul_left {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (a : g.Quotient hmonic hg_pos) (xs : List (g.Quotient hmonic hg_pos)) :
                        listProd (List.map (fun (b : g.Quotient hmonic hg_pos) => a * b) xs) = a ^ xs.length * listProd xs

                        Mapping a list by left-multiplication factors out as a power of the multiplier times the original list product.

                        theorem Hex.FpPoly.Quotient.Internal.listProd_ne_zero {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) {xs : List (g.Quotient hmonic hg_pos)} (hxs : ∀ (x : g.Quotient hmonic hg_pos), x xsx 0) :

                        The product of a list of nonzero quotient elements is nonzero, under a monic irreducible positive-degree modulus.

                        theorem Hex.FpPoly.Quotient.Internal.pow_pred_card_eq_one_of_ne_zero {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) {a : g.Quotient hmonic hg_pos} (ha : a 0) :
                        a ^ (p ^ DensePoly.natDegree g - 1) = 1

                        Finite-field exponent theorem for the quotient: every nonzero quotient element raised to the cardinality of the nonzero group equals 1.

                        Frobenius fixed-point theorem for the quotient: every element of the finite-field quotient F_p[X] / (g) is fixed by raising to the cardinality p ^ deg(g).

                        theorem Hex.FpPoly.Quotient.Internal.pow_pPow_add_mul_degree_eq {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) (a : g.Quotient hmonic hg_pos) (m q : Nat) :
                        a ^ p ^ (m + DensePoly.natDegree g * q) = a ^ p ^ m

                        Adding any multiple of the modulus degree to a Frobenius exponent does not change the quotient Frobenius iterate.

                        theorem Hex.FpPoly.Quotient.Internal.pow_pPow_mod_degree_eq_of_fixed {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) {a : g.Quotient hmonic hg_pos} {n : Nat} (hfixed : a ^ p ^ n = a) :
                        a ^ p ^ (n % DensePoly.natDegree g) = a

                        If a quotient element is fixed by the nth Frobenius iterate, then it is fixed by the remainder of n modulo the modulus degree.

                        theorem Hex.FpPoly.Quotient.Internal.deg_dvd_of_pow_pPowN_eq_self_universal {p : Nat} [ZMod64.Bounds p] [ZMod64.PrimeModulus p] {g : FpPoly p} {hmonic : DensePoly.Monic g} {hg_pos : 0 < DensePoly.natDegree g} (hg_irr : g.Irreducible) {n : Nat} (h : ∀ (β : g.Quotient hmonic hg_pos), β ^ p ^ n = β) :

                        If every element of the irreducible quotient is fixed by the nth Frobenius iterate, then the modulus degree divides n.

                        This is the quotient-side order theorem used by Rabin soundness: a nonzero remainder r = n % deg(g) would make every quotient element a root of T^(p^r) - T, contradicting the root-count bound because the quotient has p^deg(g) elements.