ZMod64 p is only valid when p is positive and strictly below 2^31.
This small-modulus invariant keeps every residue and the modulus in a UInt64,
makes the sum of two residues fit in a word without carry, and keeps the product
of two residues below 2^62, so the modular multiply reduces a single word (no
__uint128_t) and future convolution kernels can accumulate several products
before one reduction (Barrett/lazy). Every current and anticipated application
(Berlekamp-Zassenhaus, LLL, matrix work) uses small primes, so no needed
generality is lost.
The modulus is positive.
The modulus is strictly below
2^31.
Instances
The modulus is strictly below the machine-word size 2^64, so it and every
residue fit in a UInt64. Derived from the p < 2^31 bound.
The canonical Bounds 2, for the whole project.
Bounds has no general instance: the two conditions are decidable for a
literal, but instance search cannot run decide on the goal, so every modulus
needs its own witness. p = 2 is wanted almost everywhere (GF(2), the
FpPoly 2 pow-chain checkers, the Conway table), and it used to be re-declared
in each place: six public copies across five files, in HexBerlekamp,
HexConway, HexGF2Mathlib (three) and HexGFqMathlib. Any module importing
several saw that many equal-priority candidates, and further copies in test and
guard modules were captured into emitted proof terms, producing errors naming
constants nobody had written.
Declaring it here, alongside the class, gives every consumer one candidate
reachable by the import they already have. A module needing some other modulus
should use local instance, or a private theorem plus
attribute [local instance] to keep the name unexported too. Never
private instance: that leaves the instance visible to search in importing
modules while making its name unreferenceable there.
Residues mod p stored in a single machine word, with a proof of reduction.
- val : UInt64
The backing machine word holding the standard representative.
Proof that the stored word is already reduced below the modulus.
Instances For
Equality of residues is equality of the stored words: the reduction proof is irrelevant.
Equations
Equations
- Hex.ZMod64.instCoeOutNat = { coe := Hex.ZMod64.toNat }
Build a reduced residue by taking the Nat representative mod p.
The bound p < 2^64 ensures the reduced representative is stored faithfully in
the backing UInt64.
Equations
- Hex.ZMod64.ofNat p n = { val := UInt64.ofNatLT (Hex.ZMod64.normalize p n) ⋯, isLt := ⋯ }
Instances For
All canonical residues modulo p, listed in representative order.
Equations
- Hex.ZMod64.values p = List.map (fun (n : Nat) => Hex.ZMod64.ofNat p n) (List.range p)
Instances For
The zero residue class.
Equations
Instances For
The residue class of one.
Equations
Instances For
The modulus as a UInt64 word when p < 2^64.
Equations
- Hex.ZMod64.modulusWord p hp = UInt64.ofNatLT p ⋯
Instances For
The correction word 2^64 - p used when p < 2^64.
Equations
- Hex.ZMod64.complementWord p _hp = UInt64.ofNatLT (UInt64.word - p) ⋯
Instances For
Reduce branch of reduceOnce: subtracting the modulus word from a faithful
representative below 2 * p lands back in canonical range < p.
No-reduce branch of reduceOnce: a faithful representative already below the
modulus word is already canonical.
Canonicalise a machine word whose value is a faithful representative in
[0, 2*p) by one conditional subtraction of the modulus word.
Under the p < 2^31 bound add produces such a representative with no
machine-word wraparound, so this single reduce branch replaces the former
three-way carry analysis and keeps the runtime division-free.
Equations
- Hex.ZMod64.reduceOnce s hs = if h : Hex.ZMod64.modulusWord p ⋯ ≤ s then { val := s - Hex.ZMod64.modulusWord p ⋯, isLt := ⋯ } else { val := s, isLt := ⋯ }
Instances For
Add two reduced residues: the residue of the sum of canonical representatives.
This is the kernel-reduction-friendly specification: reducing it unfolds to a
single Nat addition and mod, so decide-style proofs walk a straight-line
computation. Compiled code instead runs the branchy machine-word implementation
addImpl, registered by the @[csimp] theorem add_eq_impl.
Instances For
Runtime implementation of Hex.ZMod64.add: one faithful machine-word
addition followed by a single conditional subtraction of the modulus
(reduceOnce), with no carry branch and no division. Its correctness proof is
the @[csimp] theorem add_eq_impl. Under p < 2^31 the sum
a.val + b.val never overflows the word.
Instances For
Subtract two residues: the residue of a.toNat + (p - b.toNat), the canonical
representative of the modular difference.
Like Hex.ZMod64.add, this is the kernel-reduction-friendly
specification; compiled code runs subImpl through the @[csimp] theorem
sub_eq_impl.
Instances For
Runtime implementation of Hex.ZMod64.sub: a single sign test picks the fast common path
a - b (already canonical when b ≤ a) or the corrected a + (p - b), with no
division and no wraparound reasoning. Its correctness proof is the @[csimp]
theorem sub_eq_impl. Under p < 2^31 neither branch overflows the word.
Equations
Instances For
Multiply two reduced residues and reduce the product mod p.
The trusted runtime contract is the lean_hex_zmod64_mul extern, whose C body
must agree with this pure Lean fallback.
Instances For
Raise a residue to a natural power using exponentiation by squaring.
The accumulator form keeps the executable path close to the intended downstream runtime usage while preserving a simple semantic contract.
Equations
- a.pow n = Hex.ZMod64.pow.go a Hex.ZMod64.one n
Instances For
Compute a modular inverse candidate via the integer extended-GCD helper from
hex-arith.
When a is coprime to p, this is the canonical inverse mod p; otherwise it
still exposes the executable Bezout-derived residue needed by later algebraic
layers. The trusted runtime contract is lean_hex_zmod64_inv, which runs the
same Euclidean remainder and cofactor recurrence directly in bounded word
arithmetic and returns the cofactor modulo p.
Equations
Instances For
Equations
- Hex.ZMod64.instZero = { zero := Hex.ZMod64.zero }
Equations
- Hex.ZMod64.instOne = { one := Hex.ZMod64.one }
Equations
- Hex.ZMod64.instAdd = { add := Hex.ZMod64.add }
Equations
- Hex.ZMod64.instSub = { sub := Hex.ZMod64.sub }
Equations
- Hex.ZMod64.instMul = { mul := Hex.ZMod64.mul }
Equations
- Hex.ZMod64.instPowNat = { pow := Hex.ZMod64.pow }
Equations
- Hex.ZMod64.instInv = { inv := Hex.ZMod64.inv }
The canonical representative of the zero residue is 0.
The canonical representative of the one residue is 1 % p.
Definition-level representative equation for the extended-GCD inverse candidate.
Most callers should prefer inv_mul_eq_one_of_coprime; this lemma exposes the
exact executable residue produced by inv. It is intentionally not tagged as a
default simplification rule, since unfolding inv exposes the extended-GCD
implementation body.