Canonical nonnegative representative of z modulo m.
Computes Int.toNat (z % m); for 0 < m this is the unique value in [0, m)
congruent to z. Used coefficientwise by modP and reduceModPow to land
integer coefficients in the standard representative window before transport
to FpPoly or back into ZPoly.
Equations
- Hex.ZPoly.intModNat z m = (z % Int.ofNat m).toNat
Instances For
Windowed implementation of intModNat.
Modular addition of canonical operands lands in [0, 2m) and modular
subtraction in (-m, m), so on the modular hot path almost every coefficient
is within one modulus of its canonical representative. Testing for that costs a
bignum comparison and at most one bignum addition, where Int.emod costs a
full division; a value already in [0, m) is returned without allocating at
all. Only genuinely wide values -- products, and the descent from a doubled
precision -- pay for the division.
Proved equal to intModNat in intModNat_eq_impl.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Proof-backed compiled implementation of the canonical representative.
Canonical nonnegative representative of z modulo m, as an Int.
The Int-valued sibling of intModNat, for the coefficient arrays that
are Int-valued on both sides of a reduction.
Equations
- Hex.ZPoly.intEmod z m = Int.ofNat (Hex.ZPoly.intModNat z m)
Instances For
Windowed implementation of intEmod.
Routing through intModNat would cost a multi-limb copy on every coefficient,
in both directions: Int.toNat copies a big nonnegative Int into a Nat,
and the value is then immediately coerced back. Since Int.emod is already
nonnegative at a nonzero modulus, that round trip is pure allocation, and
allocation -- not division width -- is what the modular hot path is made of.
The two near-canonical windows are kept: modular addition of canonical operands
lands in [0, 2m) and modular subtraction in (-m, m), so a coefficient
already canonical is returned as itself, allocating nothing at all, and one
within a modulus below costs a single addition. A genuinely wide value -- the
long division's window, or the descent from a doubled precision -- pays for one
Int.emod and nothing else.
Proved equal to intEmod in intEmod_eq_impl.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Proof-backed compiled implementation of the Int-valued canonical
representative.
Reducing one summand first does not change the canonical representative of a difference: the windowed elimination may subtract the raw product where the specification subtracts its reduction.
Reduce the coefficients of an integer polynomial modulo p.
Equations
- Hex.ZPoly.modP p f = Hex.DensePoly.ofList (List.map (fun (i : Nat) => Hex.ZMod64.ofNat p (Hex.ZPoly.intModNat (Hex.DensePoly.coeff f i) p)) (List.range (Hex.DensePoly.size f)))
Instances For
Array-map implementation of coefficient reduction modulo p.
Equations
- Hex.ZPoly.modPImpl p f = Hex.FpPoly.ofCoeffs (Array.map (fun (coeff : Int) => Hex.ZMod64.ofNat p (Hex.ZPoly.intModNat coeff p)) (Hex.DensePoly.toArray f))
Instances For
The direct array map computes the reference modular image.
Reduce each coefficient to its canonical representative modulo p^k.
Equations
- f.reduceModPow p k = Hex.DensePoly.ofList (List.map (fun (i : Nat) => Int.ofNat (Hex.ZPoly.intModNat (Hex.DensePoly.coeff f i) (p ^ k))) (List.range (Hex.DensePoly.size f)))
Instances For
Array-map implementation of coefficient reduction modulo p^k.
Equations
- f.reduceModPowImpl p k = Hex.DensePoly.ofCoeffs (Array.map (fun (coeff : Int) => Hex.ZPoly.intEmod coeff (p ^ k)) (Hex.DensePoly.toArray f))
Instances For
The direct array map computes the reference prime-power reduction.
Proof-backed compiled implementation of prime-power coefficient reduction.
Coefficientwise characterisation of modP: the i-th coefficient of the reduction
is the ZMod64 image of the canonical representative of the original coefficient.
Reducing the zero polynomial modulo p preserves zero.
Coefficientwise characterisation of reduceModPow: each coefficient is replaced
by its canonical nonnegative representative in [0, p^k).
Reducing the zero polynomial modulo p^k preserves zero.
Reducing the integer one polynomial modulo a nontrivial power preserves one.
If a coefficient is already divisible by p^k, its reduceModPow image vanishes.
Coefficientwise reduction modulo p^k is congruent to the original polynomial.
Congruence is preserved by coefficientwise canonical reduction modulo p^k.
Alias oriented toward canonical reduction: congruent inputs have the same reduction.
Reducing twice to the same positive modulus is idempotent.
Canonical reduction modulo a positive power is idempotent.
The coefficient-range invariant of the modular kernels: every coefficient of
f is the canonical residue in [0, m).
This is the invariant a lift must carry in order to drop a canonicalisation:
reduceModPow_eq_self_of_canonical says it is exactly the hypothesis under
which reduceModPow is the identity.
Equations
- f.Canonical m = ∀ (i : Nat), 0 ≤ Hex.DensePoly.coeff f i ∧ Hex.DensePoly.coeff f i < ↑m
Instances For
Canonical reduction at a positive modulus produces canonical coefficients.
Canonical coefficients are fixed by reduceModPow.
This is the theorem that licenses deleting a redundant canonicalisation: a
reduction applied to data already reduced to [0, p ^ k) returns its input
unchanged, so removing it cannot change any result.
Congruent integer polynomials have the same reduction modulo p.
Reducing modulo p^(k+1) does not change the reduction modulo p.
Reducing modulo any positive power of p does not change the reduction modulo p.
Lift F_p coefficients to their standard nonnegative integer representatives.
Equations
- f.liftToZ = Hex.DensePoly.ofList (List.map (fun (i : Nat) => Int.ofNat (Hex.DensePoly.coeff f i).toNat) (List.range (Hex.DensePoly.size f)))
Instances For
Coefficientwise characterisation of liftToZ: each coefficient is the standard
nonnegative Nat representative of the corresponding ZMod64 element.
The canonical integer lift of the zero polynomial is zero.
Reducing the canonical lift back modulo p recovers the original coefficient data.
Reducing a canonical lift back modulo p recovers the original polynomial.
The canonical integer lift of a monic polynomial over F_p is monic, provided
the modulus is nontrivial. The 1 < p hypothesis is necessary because
1 : ZMod64 1 has representative zero.
A polynomial is congruent modulo p to the canonical integer lift of its reduction.
Reducing the integer 1 polynomial modulo p yields the FpPoly p
identity. Bottom-of-recursion case for the modP p rewrites used
by Hensel lifting modules.