dalek-ed25519-verified/verification/Proofs/P25519.lean
mrwulf b79375600f field layer: 14 proofs pass, fieldImplementation axiom-clean
Ported from the locally verified Hermes working copy; FeQ and Square2Spec
(dead files in the published replica) now compile and are in the check
manifest. check.sh gates: source integrity, stub audit, zero axiom
declarations under Proofs/, per-certificate axiom audit.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 14:17:44 +02:00

552 lines
36 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
═══════════════════════════════════════════════════════════════════════════════
Proofs/P25519.lean — primality of the Curve25519 base-field modulus
p = 2^255 19, via Lucas/Pratt certificates
═══════════════════════════════════════════════════════════════════════════════
WHAT THIS FILE PROVES
`p25519_prime : Nat.Prime (2 ^ 255 - 19)` — the 255-bit modulus of the field
F_p implemented by the Rust crate is a prime number. Axiom-free, with no
`native_decide`: every numeric fact is checked by the Lean KERNEL (`decide`)
through a purpose-built binary modular-exponentiation function (`powMod`).
WHY THE FIELD VERIFICATION NEEDS THIS FILE
* Mathlib only provides the `Field (ZMod P)` instance — i.e. "F_p really is a
field, with all field axioms" — from `Fact (Nat.Prime P)`. The main theorem
(Proofs/FieldMain.lean, `fieldImplementation`) states that the transpiled
Rust code implements exactly that field, so primality is a prerequisite for
even *stating* the result. Proofs/Field.lean consumes `p25519_prime` to
build `P_prime : Nat.Prime P` and the `Fact`/`NeZero` instances.
* Rust analog (indirect — this file contains no transpiled code):
`FieldElement::invert`, curve25519/solana-ed25519/src/field.rs:239-248,
computes x^(p2) and its doc comment justifies this with
"x^(p-2)·x = x^(p-1) = 1 (mod p)" — Fermat's little theorem, which is
only valid because p is prime. Proofs/InvertSpec.lean formalizes exactly
that argument and needs the primality proved here.
PLACE IN THE IMPORT GRAPH
Leaf: imports only mathlib (LucasPrimality, ZMod, norm_num-prime).
Imported by Proofs/Field.lean, and through it by Proofs/InvertSpec.lean and
Proofs/FieldMain.lean.
THE PROOF TECHNIQUE, FOR THE LAY READER (Lucas test / Pratt certificates)
How do you convince a proof CHECKER that a 255-bit number n is prime without
trial division up to 2^127? Use the classical Lucas test (the basis of
"Pratt certificates", the textbook proof that PRIMES ∈ NP):
if some witness g satisfies
(1) g^(n1) ≡ 1 (mod n) (Fermat condition)
(2) g^((n1)/q) ≢ 1 (mod n) for EVERY prime q dividing n1,
then n is prime.
Why this works: (1) says the multiplicative order of g modulo n divides n1;
if that order were a PROPER divisor of n1 it would divide (n1)/q for some
prime q | n1, contradicting (2). So g has order exactly n1 in the unit
group of Z/n. But that group has only φ(n) ≤ n1 elements, so an element of
order n1 can exist only if φ(n) = n1 — which happens precisely when n is
prime. Mathlib packages this as `lucas_primality`.
The catch: condition (2) needs the COMPLETE prime factorization of n1, and
each prime factor q must itself be certified prime — recursively, by the
same test. The recursion bottoms out at factors small enough for mathlib's
`norm_num` prime checker. The published factor tree used below (any
factoring tool reproduces it; the kernel re-verifies every product):
p 1 = 2^2 · 3 · 65147 · q1, p = 2^255 19
q1 = 740582127325613583022312264370627\
88676166966415465897661863160754340907 (236 bits)
q1 1 = 2 · 3 · 353 · 57467 · 132049 · 1923133 · q2 · q3
q2 = 31757755568855353
q2 1 = 2^3 · 3 · 31 · 107 · 223 · 4153 · 430751 (all small)
q3 = 75445702479781427272750846543864801
q3 1 = 2^5 · 3^2 · 5^2 · 75707 · q4 · q5
q4 = 72106336199
q4 1 = 2 · 13 · q6
q6 = 2773320623, q6 1 = 2 · 2437 · 569003 (all small)
q5 = 1919519569386763
q5 1 = 2 · 3 · 7 · 19 · 47^2 · 127 · q7
q7 = 8574133, q7 1 = 2^2 · 3 · 7 · 103 · 991 (all small)
The certificate theorems below appear leaves-first:
q7, q6, q4, q5, q2, q3, q1, and finally p itself.
WHY `powMod` EXISTS
Checking condition (1) for p means verifying a congruence with a 255-bit
exponent. `decide` on `(2 : ZMod n) ^ (n1) = 1` directly is hopeless: `^`
on `ZMod n` unfolds to n1 ≈ 2^255 repeated multiplications. Instead we
define square-and-multiply on raw `Nat` (`powModAux`), prove ONCE that it
computes `a ^ k % n` (`powModAux_eq`), and then every certificate condition
becomes a closed equation `powMod a k n = 1` (or `≠ 1`) between `Nat`
literals. Lean's kernel evaluates `Nat` literal arithmetic (·, %, /) with
GMP big-integer primitives, so each such `decide` costs ~256 squarings of
≤255-bit numbers — milliseconds, entirely inside the trusted kernel.
-/
import Mathlib.NumberTheory.LucasPrimality
import Mathlib.Data.ZMod.Basic
import Mathlib.Tactic.NormNum.Prime
-- Elaborating `decide` on the huge decimal literals below builds deep numeral
-- terms; raise the elaborator's recursion limit so they go through.
set_option maxRecDepth 8000
-- All helpers and per-node certificates live in their own namespace; only the
-- final `p25519_prime` (stated about `2 ^ 255 - 19` itself) is exported at top
-- level for Proofs/Field.lean.
namespace P25519
-- ─────────────────────────────────────────────────────────────────────────────
-- Kernel-checkable modular exponentiation
-- ─────────────────────────────────────────────────────────────────────────────
/-- Fuel-based binary modular exponentiation, kernel-reducible (GMP-fast `decide`).
MATH (for sufficient fuel; made precise by `powModAux_eq`):
`powModAux fuel a k n = a^k mod n`.
Algorithm: square-and-multiply, consuming the binary digits of `k` from the
low end —
k = 0 ↦ 1 mod n
k = 2m ↦ (a² mod n)^m mod n
k = 2m+1 ↦ ((a² mod n)^m mod n) · a mod n
Every intermediate is reduced mod n, so no value ever exceeds n² (≈510 bits
here) — this is what keeps kernel evaluation fast.
WHY THE `fuel` ARGUMENT: recursion is on `fuel` (plain structural recursion),
not on `k`. Recursing on `k/2 < k` would be well-founded recursion, which
Lean compiles to `WellFounded.fix` — a fixpoint the kernel cannot unfold
during `decide`. With fuel, the kernel just peels one constructor per step.
WHY NEEDED: this is the workhorse that lets the kernel verify 255-bit
Fermat-witness congruences in milliseconds (see file header). -/
def powModAux : Nat → Nat → Nat → Nat → Nat
| 0, _, _, n => 1 % n
| fuel + 1, a, k, n =>
if k = 0 then 1 % n
else if k % 2 = 1 then powModAux fuel (a * a % n) (k / 2) n * a % n
else powModAux fuel (a * a % n) (k / 2) n
/- Correctness of `powModAux`.
MATH (ASCII): forall fuel a k n, k < 2^fuel ==>
powModAux fuel a k n = a^k mod n
LaTeX: $\forall\,\mathit{fuel}\,a\,k\,n,\ k < 2^{\mathit{fuel}}
\Rightarrow \mathrm{powModAux}\ \mathit{fuel}\ a\ k\ n = a^k \bmod n$
The hypothesis `k < 2^fuel` says the fuel covers every binary digit of the
exponent, so the recursion never runs dry.
WHY NEEDED: turns each kernel computation `powMod a k n = …` into the
mathematical statement `a^k % n = …` that `lucas_primality` needs.
Proof: induction on `fuel`, mirroring the recursion of `powModAux`. -/
theorem powModAux_eq : ∀ (fuel a k n : ), k < 2 ^ fuel → powModAux fuel a k n = a ^ k % n := by
intro fuel
induction fuel with
| zero =>
-- base case: k < 2^0 = 1 forces k = 0, and both sides reduce to 1 % n
intro a k n hk
rw [pow_zero] at hk
have hk0 : k = 0 := by omega
subst hk0
simp [powModAux]
| succ f ih =>
intro a k n hk
by_cases hk0 : k = 0
-- k = 0: both sides are 1 % n by definition
· subst hk0; simp [powModAux]
-- k ≠ 0: the recursive call gets exponent k/2, which fits in f bits…
· have hk2 : k / 2 < 2 ^ f := by
rw [pow_succ] at hk
omega
-- …so the induction hypothesis describes it: (a²%n)^(k/2) % n
have hrec := ih (a * a % n) (k / 2) n hk2
have haa : a * a = a ^ 2 := (pow_two a).symm
simp only [powModAux, if_neg hk0]
-- split on the lowest bit of k and reassemble the exponent:
by_cases hodd : k % 2 = 1
-- odd k: (a²)^(k/2) · a = a^(2·(k/2)+1) = a^k (mods commute via Nat.pow_mod)
· rw [if_pos hodd, hrec, ← Nat.pow_mod, Nat.mod_mul_mod, haa, ← pow_mul, ← pow_succ,
show 2 * (k / 2) + 1 = k by omega]
-- even k: (a²)^(k/2) = a^(2·(k/2)) = a^k
· rw [if_neg hodd, hrec, ← Nat.pow_mod, haa, ← pow_mul,
show 2 * (k / 2) = k by omega]
/-- `powMod a k n = a ^ k % n` for all `k < 2 ^ 256`.
The fuel is fixed at 256: enough for any exponent below 2^256, in particular
for every exponent `(n1)/q` appearing in the certificates (n ≤ p < 2^255).
WHY NEEDED: the single entry point all certificate side-conditions are stated
through, so each becomes one GMP-fast kernel `decide`. -/
def powMod (a k n : ) : := powModAux 256 a k n
/- Bridge from the `Nat` computation into `ZMod n`, where `lucas_primality`
lives.
MATH: k < 2^256 ==> (a : ZMod n)^k = (powMod a k n : ZMod n)
i.e. casting `a` to Z/n and exponentiating there agrees with computing
`a^k mod n` over the naturals and casting the result. Follows from
`powModAux_eq` plus the fact that the cast Nat → ZMod n is a ring
homomorphism that kills `% n`.
WHY NEEDED: the two lemmas below (`pow_eq_one_of_powMod`,
`pow_ne_one_of_powMod`) are corollaries of this one. -/
theorem cast_pow_eq (a k n : ) (hk : k < 2 ^ 256) :
(a : ZMod n) ^ k = ((powMod a k n : ) : ZMod n) := by
rw [powMod, powModAux_eq 256 a k n hk, ZMod.natCast_mod, Nat.cast_pow]
/- Positive direction — discharges the FERMAT condition (1) of the Lucas test.
MATH: k < 2^256 and powMod a k n = 1 ==> (a : ZMod n)^k = 1.
The hypothesis `powMod a k n = 1` is a closed `Nat` equation the kernel
checks by `decide`; this lemma lifts it to the `ZMod n` equation that
`lucas_primality` consumes. -/
theorem pow_eq_one_of_powMod (a k n : ) (hk : k < 2 ^ 256) (h : powMod a k n = 1) :
(a : ZMod n) ^ k = 1 := by
rw [cast_pow_eq a k n hk, h, Nat.cast_one]
/- Negative direction — discharges the ORDER condition (2) of the Lucas test.
MATH: k < 2^256, 1 < n, powMod a k n ≠ 1, powMod a k n < n
==> (a : ZMod n)^k ≠ 1.
Subtlety: distinct naturals can become EQUAL in Z/n (they may differ by a
multiple of n), so `powMod a k n ≠ 1` alone is not enough. The extra
hypotheses pin both sides into the canonical range [0, n): the computed
residue is < n (true by construction, but cheaper to re-`decide` than to
prove generically) and 1 < n. Within that range the cast Nat → ZMod n is
injective (`ZMod.natCast_eq_natCast_iff'` + `Nat.mod_eq_of_lt`), so
inequality transfers.
WHY NEEDED: one application per prime factor q of n1, with
k = (n1)/q — this is what forces the witness to have full order n1. -/
theorem pow_ne_one_of_powMod (a k n : ) (hk : k < 2 ^ 256) (hn : 1 < n)
(h1 : powMod a k n ≠ 1) (h2 : powMod a k n < n) :
(a : ZMod n) ^ k ≠ 1 := by
-- replace the ZMod power by the cast of the computed Nat residue
rw [cast_pow_eq a k n hk]
intro hcon
-- equality of casts in ZMod n means equality of the residues mod n…
rw [show (1 : ZMod n) = ((1 : ) : ZMod n) by rw [Nat.cast_one],
ZMod.natCast_eq_natCast_iff'] at hcon
-- …and both residues are already < n, so they are equal as naturals
rw [Nat.mod_eq_of_lt h2, Nat.mod_eq_of_lt hn] at hcon
exact h1 hcon
-- ─────────────────────────────────────────────────────────────────────────────
-- The certificate chain, leaves first (factor tree in the file header).
--
-- Every theorem instantiates mathlib's
-- lucas_primality (n) (g : ZMod n) (h1) (h2) : Nat.Prime n
-- with a concrete witness g, discharging
-- h1 : g^(n1) = 1 in ZMod n via `pow_eq_one_of_powMod`
-- (its two `by decide`s check: n1 < 2^256, and the powMod equation)
-- h2 : ∀ q prime, q n1 → g^((n1)/q) ≠ 1 via `pow_ne_one_of_powMod`
-- (its four `by decide`s check: (n1)/q < 2^256, 1 < n,
-- powMod g ((n1)/q) n ≠ 1, and powMod … < n).
--
-- For h2 the published factorization of n1 is stated as a NESTED product
-- 2^e * (f1 * (f2 * (…))) and verified by one `decide` (a single big-number
-- multiplication). `rcases (Nat.Prime.dvd_mul hq).mp` then peels the factors
-- left to right: a prime q dividing the product divides the head factor or
-- the tail. Dividing the head pins q to a concrete prime via
-- `Nat.prime_dvd_prime_iff_eq` ("a prime divides a prime iff they are
-- equal"); for prime-power heads like 2^2 we first strip the exponent with
-- `hq.dvd_of_dvd_pow`. Head factors small enough are certified prime by
-- `norm_num`; large ones by the earlier theorems of this chain — that
-- reference IS the recursion of the Pratt certificate.
-- ─────────────────────────────────────────────────────────────────────────────
/- Leaf q7 of the factor tree: 8574133 is prime (needed for q5 below).
Witness g = 2; 8574133 1 = 2^2 · 3 · 7 · 103 · 991, all `norm_num`-small.
This first certificate is annotated line by line; the six that follow are
structurally identical. -/
theorem prime_8574133 : Nat.Prime 8574133 := by
-- pick the witness g = 2 and split into the two Lucas obligations
refine lucas_primality 8574133 ((2 : ) : ZMod 8574133) ?_ ?_
-- (1) Fermat: 2^(n1) ≡ 1 (mod n) — one kernel powMod computation
· exact pow_eq_one_of_powMod 2 (8574133 - 1) 8574133 (by decide) (by decide)
-- (2) full order: any prime q | n1 must leave 2^((n1)/q) ≢ 1 (mod n)
· intro q hq hqd
-- kernel-verified factorization of n1, nested for left-to-right peeling
have hfac : (8574133 : ) - 1 = 2 ^ 2 * (3 * (7 * (103 * (991)))) := by decide
rw [hfac] at hqd
-- q | 2^2 · rest: either q | 2^2 (then q = 2) or q divides the rest
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp (hq.dvd_of_dvd_pow h)
subst he
-- 2^((n1)/2) ≢ 1 (mod n), checked by the kernel
exact pow_ne_one_of_powMod 2 ((8574133 - 1) / 2) 8574133 (by decide) (by decide) (by decide) (by decide)
-- q | 3 · rest: peel the factor 3
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 3 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((8574133 - 1) / 3) 8574133 (by decide) (by decide) (by decide) (by decide)
-- peel the factor 7
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 7 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((8574133 - 1) / 7) 8574133 (by decide) (by decide) (by decide) (by decide)
-- peel the factor 103
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 103 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((8574133 - 1) / 103) 8574133 (by decide) (by decide) (by decide) (by decide)
-- only the last factor 991 remains
have he : q = 991 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp hqd
subst he
exact pow_ne_one_of_powMod 2 ((8574133 - 1) / 991) 8574133 (by decide) (by decide) (by decide) (by decide)
/- Leaf q6 of the factor tree: 2773320623 is prime (needed for q4 below).
Witness g = 5; 2773320623 1 = 2 · 2437 · 569003, all `norm_num`-small.
(g = 2 would fail here: 2 is a quadratic residue mod this prime, so
2^((n1)/2) ≡ 1 and the q = 2 order check breaks; hence the witness 5.) -/
theorem prime_2773320623 : Nat.Prime 2773320623 := by
refine lucas_primality 2773320623 ((5 : ) : ZMod 2773320623) ?_ ?_
-- Fermat condition, then one order check per prime factor of n1
· exact pow_eq_one_of_powMod 5 (2773320623 - 1) 2773320623 (by decide) (by decide)
· intro q hq hqd
have hfac : (2773320623 : ) - 1 = 2 * (2437 * (569003)) := by decide
rw [hfac] at hqd
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 5 ((2773320623 - 1) / 2) 2773320623 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2437 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 5 ((2773320623 - 1) / 2437) 2773320623 (by decide) (by decide) (by decide) (by decide)
have he : q = 569003 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp hqd
subst he
exact pow_ne_one_of_powMod 5 ((2773320623 - 1) / 569003) 2773320623 (by decide) (by decide) (by decide) (by decide)
/- Node q4 of the factor tree: 72106336199 is prime (needed for q3 below).
Witness g = 7; 72106336199 1 = 2 · 13 · 2773320623.
First RECURSIVE step of the Pratt certificate: the large factor q6 is
certified by `prime_2773320623` above instead of `norm_num`. -/
theorem prime_72106336199 : Nat.Prime 72106336199 := by
refine lucas_primality 72106336199 ((7 : ) : ZMod 72106336199) ?_ ?_
· exact pow_eq_one_of_powMod 7 (72106336199 - 1) 72106336199 (by decide) (by decide)
· intro q hq hqd
have hfac : (72106336199 : ) - 1 = 2 * (13 * (2773320623)) := by decide
rw [hfac] at hqd
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 7 ((72106336199 - 1) / 2) 72106336199 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 13 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 7 ((72106336199 - 1) / 13) 72106336199 (by decide) (by decide) (by decide) (by decide)
-- last factor: q6 = 2773320623, prime by the recursive certificate above
have he : q = 2773320623 := (Nat.prime_dvd_prime_iff_eq hq prime_2773320623).mp hqd
subst he
exact pow_ne_one_of_powMod 7 ((72106336199 - 1) / 2773320623) 72106336199 (by decide) (by decide) (by decide) (by decide)
/- Node q5 of the factor tree: 1919519569386763 is prime (needed for q3 below).
Witness g = 2; q5 1 = 2 · 3 · 7 · 19 · 47^2 · 127 · 8574133.
Note the prime-power factor 47^2: only ONE order check is needed per
distinct prime (the test divides n1 by q once), so the branch for 47
strips the square with `hq.dvd_of_dvd_pow` first. The large factor
q7 = 8574133 is certified by `prime_8574133`. -/
theorem prime_1919519569386763 : Nat.Prime 1919519569386763 := by
refine lucas_primality 1919519569386763 ((2 : ) : ZMod 1919519569386763) ?_ ?_
· exact pow_eq_one_of_powMod 2 (1919519569386763 - 1) 1919519569386763 (by decide) (by decide)
· intro q hq hqd
have hfac : (1919519569386763 : ) - 1 = 2 * (3 * (7 * (19 * (47 ^ 2 * (127 * (8574133)))))) := by decide
rw [hfac] at hqd
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((1919519569386763 - 1) / 2) 1919519569386763 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 3 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((1919519569386763 - 1) / 3) 1919519569386763 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 7 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((1919519569386763 - 1) / 7) 1919519569386763 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 19 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((1919519569386763 - 1) / 19) 1919519569386763 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 47 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp (hq.dvd_of_dvd_pow h)
subst he
exact pow_ne_one_of_powMod 2 ((1919519569386763 - 1) / 47) 1919519569386763 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 127 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((1919519569386763 - 1) / 127) 1919519569386763 (by decide) (by decide) (by decide) (by decide)
-- last factor: q7 = 8574133, prime by the recursive certificate above
have he : q = 8574133 := (Nat.prime_dvd_prime_iff_eq hq prime_8574133).mp hqd
subst he
exact pow_ne_one_of_powMod 2 ((1919519569386763 - 1) / 8574133) 1919519569386763 (by decide) (by decide) (by decide) (by decide)
/- Leaf q2 of the factor tree: 31757755568855353 is prime (needed for q1).
Witness g = 10; q2 1 = 2^3 · 3 · 31 · 107 · 223 · 4153 · 430751,
all `norm_num`-small — no recursion needed for this node. -/
theorem prime_31757755568855353 : Nat.Prime 31757755568855353 := by
refine lucas_primality 31757755568855353 ((10 : ) : ZMod 31757755568855353) ?_ ?_
· exact pow_eq_one_of_powMod 10 (31757755568855353 - 1) 31757755568855353 (by decide) (by decide)
· intro q hq hqd
have hfac : (31757755568855353 : ) - 1 = 2 ^ 3 * (3 * (31 * (107 * (223 * (4153 * (430751)))))) := by decide
rw [hfac] at hqd
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp (hq.dvd_of_dvd_pow h)
subst he
exact pow_ne_one_of_powMod 10 ((31757755568855353 - 1) / 2) 31757755568855353 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 3 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 10 ((31757755568855353 - 1) / 3) 31757755568855353 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 31 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 10 ((31757755568855353 - 1) / 31) 31757755568855353 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 107 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 10 ((31757755568855353 - 1) / 107) 31757755568855353 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 223 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 10 ((31757755568855353 - 1) / 223) 31757755568855353 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 4153 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 10 ((31757755568855353 - 1) / 4153) 31757755568855353 (by decide) (by decide) (by decide) (by decide)
have he : q = 430751 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp hqd
subst he
exact pow_ne_one_of_powMod 10 ((31757755568855353 - 1) / 430751) 31757755568855353 (by decide) (by decide) (by decide) (by decide)
/- Node q3 of the factor tree: the 116-bit 75445702479781427272750846543864801
is prime (needed for q1). Witness g = 7;
q3 1 = 2^5 · 3^2 · 5^2 · 75707 · q4 · q5 with the two large factors
q4 = 72106336199 and q5 = 1919519569386763 certified recursively above. -/
theorem prime_75445702479781427272750846543864801 : Nat.Prime 75445702479781427272750846543864801 := by
refine lucas_primality 75445702479781427272750846543864801 ((7 : ) : ZMod 75445702479781427272750846543864801) ?_ ?_
· exact pow_eq_one_of_powMod 7 (75445702479781427272750846543864801 - 1) 75445702479781427272750846543864801 (by decide) (by decide)
· intro q hq hqd
have hfac : (75445702479781427272750846543864801 : ) - 1 = 2 ^ 5 * (3 ^ 2 * (5 ^ 2 * (75707 * (72106336199 * (1919519569386763))))) := by decide
rw [hfac] at hqd
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp (hq.dvd_of_dvd_pow h)
subst he
exact pow_ne_one_of_powMod 7 ((75445702479781427272750846543864801 - 1) / 2) 75445702479781427272750846543864801 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 3 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp (hq.dvd_of_dvd_pow h)
subst he
exact pow_ne_one_of_powMod 7 ((75445702479781427272750846543864801 - 1) / 3) 75445702479781427272750846543864801 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 5 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp (hq.dvd_of_dvd_pow h)
subst he
exact pow_ne_one_of_powMod 7 ((75445702479781427272750846543864801 - 1) / 5) 75445702479781427272750846543864801 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 75707 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 7 ((75445702479781427272750846543864801 - 1) / 75707) 75445702479781427272750846543864801 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
-- factor q4 = 72106336199: prime by the recursive certificate above
· have he : q = 72106336199 := (Nat.prime_dvd_prime_iff_eq hq prime_72106336199).mp h
subst he
exact pow_ne_one_of_powMod 7 ((75445702479781427272750846543864801 - 1) / 72106336199) 75445702479781427272750846543864801 (by decide) (by decide) (by decide) (by decide)
-- last factor q5 = 1919519569386763: prime by the recursive certificate
have he : q = 1919519569386763 := (Nat.prime_dvd_prime_iff_eq hq prime_1919519569386763).mp hqd
subst he
exact pow_ne_one_of_powMod 7 ((75445702479781427272750846543864801 - 1) / 1919519569386763) 75445702479781427272750846543864801 (by decide) (by decide) (by decide) (by decide)
/- Node q1 of the factor tree: the 236-bit cofactor of p 1 is prime.
Witness g = 2;
q1 1 = 2 · 3 · 353 · 57467 · 132049 · 1923133 · q2 · q3,
with q2 = 31757755568855353 and q3 = 75445702479781427272750846543864801
certified recursively above. This is the last node below the root. -/
theorem prime_74058212732561358302231226437062788676166966415465897661863160754340907 : Nat.Prime 74058212732561358302231226437062788676166966415465897661863160754340907 := by
refine lucas_primality 74058212732561358302231226437062788676166966415465897661863160754340907 ((2 : ) : ZMod 74058212732561358302231226437062788676166966415465897661863160754340907) ?_ ?_
· exact pow_eq_one_of_powMod 2 (74058212732561358302231226437062788676166966415465897661863160754340907 - 1) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide)
· intro q hq hqd
have hfac : (74058212732561358302231226437062788676166966415465897661863160754340907 : ) - 1 = 2 * (3 * (353 * (57467 * (132049 * (1923133 * (31757755568855353 * (75445702479781427272750846543864801))))))) := by decide
rw [hfac] at hqd
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 2) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 3 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 3) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 353 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 353) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 57467 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 57467) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 132049 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 132049) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 1923133 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 1923133) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
-- factor q2: prime by the recursive certificate above
· have he : q = 31757755568855353 := (Nat.prime_dvd_prime_iff_eq hq prime_31757755568855353).mp h
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 31757755568855353) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
-- last factor q3: prime by the recursive certificate above
have he : q = 75445702479781427272750846543864801 := (Nat.prime_dvd_prime_iff_eq hq prime_75445702479781427272750846543864801).mp hqd
subst he
exact pow_ne_one_of_powMod 2 ((74058212732561358302231226437062788676166966415465897661863160754340907 - 1) / 75445702479781427272750846543864801) 74058212732561358302231226437062788676166966415465897661863160754340907 (by decide) (by decide) (by decide) (by decide)
/- ROOT of the factor tree: p = 2^255 19 itself, written out in decimal
(57896044618658097711785492504343953926634992332820282019728792003956564819949).
Witness g = 2 (2 is in fact a primitive root mod p);
p 1 = 2^2 · 3 · 65147 · q1, with the 236-bit q1 certified just above.
Each `powMod` check here exponentiates with a ~255-bit exponent modulo the
255-bit p — still milliseconds thanks to GMP-backed kernel `Nat` arithmetic. -/
theorem prime_57896044618658097711785492504343953926634992332820282019728792003956564819949 : Nat.Prime 57896044618658097711785492504343953926634992332820282019728792003956564819949 := by
refine lucas_primality 57896044618658097711785492504343953926634992332820282019728792003956564819949 ((2 : ) : ZMod 57896044618658097711785492504343953926634992332820282019728792003956564819949) ?_ ?_
· exact pow_eq_one_of_powMod 2 (57896044618658097711785492504343953926634992332820282019728792003956564819949 - 1) 57896044618658097711785492504343953926634992332820282019728792003956564819949 (by decide) (by decide)
· intro q hq hqd
have hfac : (57896044618658097711785492504343953926634992332820282019728792003956564819949 : ) - 1 = 2 ^ 2 * (3 * (65147 * (74058212732561358302231226437062788676166966415465897661863160754340907))) := by decide
rw [hfac] at hqd
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 2 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp (hq.dvd_of_dvd_pow h)
subst he
exact pow_ne_one_of_powMod 2 ((57896044618658097711785492504343953926634992332820282019728792003956564819949 - 1) / 2) 57896044618658097711785492504343953926634992332820282019728792003956564819949 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 3 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((57896044618658097711785492504343953926634992332820282019728792003956564819949 - 1) / 3) 57896044618658097711785492504343953926634992332820282019728792003956564819949 (by decide) (by decide) (by decide) (by decide)
rcases (Nat.Prime.dvd_mul hq).mp hqd with h | hqd
· have he : q = 65147 := (Nat.prime_dvd_prime_iff_eq hq (by norm_num)).mp h
subst he
exact pow_ne_one_of_powMod 2 ((57896044618658097711785492504343953926634992332820282019728792003956564819949 - 1) / 65147) 57896044618658097711785492504343953926634992332820282019728792003956564819949 (by decide) (by decide) (by decide) (by decide)
-- last factor q1: prime by the recursive certificate above
have he : q = 74058212732561358302231226437062788676166966415465897661863160754340907 := (Nat.prime_dvd_prime_iff_eq hq prime_74058212732561358302231226437062788676166966415465897661863160754340907).mp hqd
subst he
exact pow_ne_one_of_powMod 2 ((57896044618658097711785492504343953926634992332820282019728792003956564819949 - 1) / 74058212732561358302231226437062788676166966415465897661863160754340907) 57896044618658097711785492504343953926634992332820282019728792003956564819949 (by decide) (by decide) (by decide) (by decide)
end P25519
-- ─────────────────────────────────────────────────────────────────────────────
-- Exported result
-- ─────────────────────────────────────────────────────────────────────────────
/-- The Curve25519 field prime `2 ^ 255 - 19` is prime.
MATH (ASCII): Nat.Prime (2^255 - 19)
LaTeX: $2^{255} - 19$ is prime.
This is the only theorem of this file used downstream: Proofs/Field.lean turns
it into `P_prime : Nat.Prime P` (where `P` abbreviates the same number) and the
`Fact (Nat.Prime P)` instance, which activates mathlib's `Field (ZMod P)` —
the target structure of the main theorem `fieldImplementation`
(Proofs/FieldMain.lean) — and feeds Fermat's little theorem to the inverse
spec (Proofs/InvertSpec.lean), mirroring the comment on
`FieldElement::invert` in curve25519/solana-ed25519/src/field.rs:239-248. -/
theorem p25519_prime : Nat.Prime (2 ^ 255 - 19) := by
-- rewrite 2^255 19 into the decimal literal the root certificate is about
have h : (2 : ) ^ 255 - 19 = 57896044618658097711785492504343953926634992332820282019728792003956564819949 := by decide
rw [h]
exact P25519.prime_57896044618658097711785492504343953926634992332820282019728792003956564819949