Fast EC arithmetic: projective addition, Pippenger MSM, 8-limb Montgomery fields - #13
Conversation
Adds `CompElliptic/Curves/Pasta/Fast/`: Vesta group arithmetic meant to be
computed with, not only reasoned about, in three tiers each proven equal to
the one above it.
* `Projective.lean` -- complete Renes-Costello-Batina addition on `(X:Y:Z)`
over 𝔽_q, with `toAffine_padd`/`valid_padd` against `SWPoint Vesta.curve`.
Completeness rests on Vesta having no 2-torsion.
* `Msm.lean` / `MsmProj.lean` -- windowed Pippenger MSM, proven equal to the
naive MSM, plus its all-projective instantiation (one inversion per MSM
instead of one per add).
* `NatKernel.lean` / `ProjectiveMontDefs.lean` -- zero-import transplants of
the same schedules onto ℕ representatives and onto eight-limb Montgomery
residues, with `NatKernelEquiv.lean` / `ProjectiveMontEquiv.lean` proving
every kernel operation computes its statement-surface counterpart.
`CompElliptic/Vendor/CompPoly/Montgomery/` vendors the eight-limb Montgomery
field from CompPoly `fast_multilimb_fields` (`b3850f0`) pending a pin bump past
CompPoly #258 + #274; namespaces are left at upstream's `Montgomery.*` so the
migration is an import-path rewrite. See the README there.
`FastFieldNative` is a new `precompileModules` library over the three zero-import
definition modules, so the Montgomery tier evaluates at native speed. Its
core-only invariant is what keeps native codegen off a mathlib closure;
`scripts/check_native_lane.sh` checks it.
Opt-in throughout: `import CompElliptic` does not pull any of this in.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The roadmap notes (CoordinateSystem relationship, generalizing Msm out of the Pasta tree) move to the PR description where suggestions belong. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ctly
The `Nat`-carrier kernel was historical: its specs existed first, so the
Montgomery kernel's correctness was transported through it. The vendored
Montgomery field ships `FastField.toField` and its `ringEquiv : FastField ≃+*
ZMod modulus`, so the limbs-to-𝔽_q bridge is one hop, and the meaning of the
Pippenger schedules already lives in `Msm.lean` / `MsmProj.lean`. Two tiers, not
three.
* `ProjectiveMontEquiv.lean` now relates `PM` to `Projective.PVes` directly,
along `RM p P := WFP p ∧ toPVesM p = P`. `toPVesM_padd` — the one commuting
square of substance, ~40 field operations of RCB pushed through the ring
homomorphism — is unchanged; the bucket-scatter, downsweep and window
inductions now land on `MsmProj.pscatterStep` / `paccStep` /
`pwindowValueFast`, and the ladder and the Horner recombination are proved
through `toGM = toAffine ∘ toPVesM` where the group law lives.
* `NatKernel.lean` and `NatKernelEquiv.lean` are deleted, and the `Nat` kernel
is dropped from the `FastFieldNative` lane (three core-only modules now, not
four), from `scripts/check_native_lane.sh`, and from the README.
Public statements are unchanged: `msmM_spec`, `pnsmulM_spec`, `toPVesM_padd`,
`toPVesM_pid`, `toPVesM_pneg` and the field-level cast lemmas keep their exact
shapes. Only the transport API (`RM`, `RM2`, `RA` and their closure lemmas),
which used to mention the `Nat` triples, is retargeted at `PVes`. `#print axioms`
on the specs stays [propext, Classical.choice, Quot.sound].
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
`PM.fft` and `PM.bitreverse` in `CompElliptic/Curves/Pasta/Fast/ProjectiveMontDefs.lean` had no spec here and no consumer: a group-point FFT belongs with a reference group DFT to be proven against, which this repository does not have. `pneg` stays -- it is part of the group API and has its spec in `toPVesM_pneg`. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review feedback: the lakefile lane comment, the `check_native_lane.sh` header and the module docstrings of `FastFieldNative.lean`, `Fast/Projective.lean`, `Fast/Msm.lean`, `Fast/MsmProj.lean`, `Fast/ProjectiveMontDefs.lean` and `Fast/ProjectiveMontEquiv.lean` were essays. Cut to what each thing is, the one invariant that is load-bearing (core-only import closure; the dynlib initializer name), and where the proofs live. `README.md`: the Fast/ entry now reads like its neighbours -- one plain sentence, no bold, no self-marking. No statement or proof changed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
4c2e7a9 to
53b3533
Compare
Pin CompElliptic to daira/CompElliptic#13's head (a descendant of the previously pinned rev; CompPoly and mathlib pins unchanged) and delete the vendored copies it replaces. Vendor/CompPoly keeps only the scalar FFT defs, which no pin provides until CompPoly#274 lands. The local precompile lane becomes Zcash.FastFieldNative: a lib named exactly like the pin's FastFieldNative collides silently (module names are global) and the local dylib never gets built. Fixture-check speedups verified at parity after the swap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add the seven headline correctness theorems of the fast Vesta arithmetic (projective addition, scalar ladder, Pippenger MSM, the raw-numeral spelling, and the Montgomery kernel) to TrustBoundary.lean at the standard-axioms tier, making the claim that nothing in the fast tier extends the trust base a build-time check rather than a prose claim. Completeness routes through no_onCurve_y_zero, a kernel decide, so no native_decide tier is reached. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
daira
left a comment
There was a problem hiding this comment.
Reviewed the full diff. Verdict: approve modulo the small items below. The trust discipline is exactly right throughout, and the two places where fast code could have quietly extended the trust base — native overrides and parallelism — both take the proven route instead.
One point worth stating up front, since it is the natural first question about a "proven fast arithmetic" PR: the correctness anchor is CompElliptic's pre-existing reference, not the PR's own definitions. toAffine_padd and smulFast_eq are stated against the existing complete affine group law on SWPoint Vesta.curve and its nsmul; the MSM specs are generic over [AddCommMonoid M], so at G they consume that same existing structure. Only the Montgomery tier is proven against the PR's own projective tier — which is in turn anchored as above. No Mathlib bridge is involved (unchanged from the rest of the repo).
What I verified
Projective.leanin full: the RCB closed forms ata = 0, b = 5, b3 = 15; theZ = 1core equivalence with all four case splits (distinctx, doubling, inverse, identity); completeness via the cube-root-of-−5arguments (Z_ne_zero_dist,Y_ne_zero_inv), which are the paper's exceptional-cases-force-2-torsion claim made concrete againstVesta.no_onCurve_y_zero; homogeneity lifting to general valid points; and thetoAffinehomomorphism intoSWPoint Vesta.curve. The offline Gröbner cofactors are re-verified in-kernel bylinear_combination/ring, so nothing rests on the search. Citation checks out (EUROCRYPT 2016; EFDadd-2015-rcb; the file states the polynomial form rather than the paper's operation schedule).padd_eq_paddFastis the proven counterpart ofimplemented_by— the fast raw-ℕspelling never becomes the statement surface, and the decision not to register it@[csimp]yet is justified by measurement and documented with the exact condition under which to flip it.parMap: the trust analysis in the docstring is correct —Taskis logically the one-field structure, the spawn/get round-trip is definitional, soparMap_eq_mapmakes parallelism purely an evaluation strategy inside the existingnative_decideboundary. The kernel's view is literallyList.map.Msm.lean/MsmProj.leanstatement surface:pippengerFast(Par)_eq_msmagainst the naive MSM, generic over[AddCommMonoid M];commitLagrangeFastWith_eqagainst the Pedersen spec; the projective interior viapsum/pwindowValuespecs.- The Montgomery tier's statement surface (
WF/montValalgebra,msmM_spec,pnsmulM_spec) and the vendoring discipline: deletion criterion pinned to CompPoly #258 + #274, per-file change table, upstream namespaces preserved, and thePasta.leanrewrite keeping a singleField (ZMod PALLAS_SCALAR_CARD)instance. - The precompile lane is opt-in (
import CompEllipticpulls none of it), the core-only invariant is real (codegen over a mathlib closure), andcheck_native_lane.shenforces the lane's import closure inductively.
Asks
- Build-enforce the axiom claim — done on the branch (898f088). The body says
#print axiomson every headline spec gives exactlypropext/Classical.choice/Quot.sound; that is now a build-time check:TrustBoundary.leanpinstoAffine_padd,smulFast_eq,pippengerFastPar_eq_msm,commitLagrangeFastWith_eq,padd_eq_paddFast,pnsmulM_spec, andmsmM_specat the standard tier, and the full build passes — confirming empirically that nothing in the fast tier reachesnative_decide(completeness routes throughno_onCurve_y_zero, a kerneldecide). - Wire
check_native_lane.shintoci.yml. The script exists but nothing runs it; the invariant it guards fails silently (a build that quietly becomes enormous), which is exactly the kind of thing CI should catch. One step next to the generated-fields freshness check. CI has not run on this branch— workflows now approved and running.- Nit,
padd_eq_paddFastdocstring: "makes every compiled call site … runs the fused raw-ℕform" → "run".
Posted with the assistance of Claude Fable 5.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
6d38e8f to
d8d4d1e
Compare
…tic#13 merged Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Two self-contained, temporarily-vendored trees under `Zcash/Vendor/`, each with a README stating its provenance and its deletion criterion: * `Zcash/Vendor/CompPoly/` — eight-limb (8 x 32-bit in `UInt64`) Montgomery arithmetic for 255-bit primes, vendored from the CompPoly branch `fast_multilimb_fields`, plus the radix-2 DIT scalar FFT developed here. Deleted once ironwood's CompPoly pin carries both CompPoly#258 (the field) and CompPoly#274 (the scalar FFT). * `Zcash/Vendor/CompElliptic/` — RCB complete projective Vesta addition, the bucket-method Pippenger MSM, the zero-import `Nat`-carrier kernel and its operation-for-operation equivalence proof, and the same kernel again on Montgomery residues. Developed here but generic; deleted once ironwood's CompElliptic pin provides it (daira/CompElliptic#13). Layering, mirroring the upstream dependency direction: `Vendor/CompElliptic/` may import `Vendor/CompPoly/`, never the reverse, so the two migrations stay independent. Neither tree imports Keygen, Soundness or Clean. The `*Defs.lean` modules are split out from their proofs and import nothing beyond Lean core, so they can be native-compiled without dragging a mathlib import closure through codegen. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…anch Closes out the fast-arithmetic arc. The branch already carried #111's content through 95baf6c via prior direct merges; main adds only the two commits that landed on the PR branch after that point: * caaf766 re-pins CompElliptic to the canonical daira/CompElliptic after daira/CompElliptic#13 merged (fd997734, was mitschabaude-bot @ 53b35333). The two revisions differ only in docstrings and a TrustBoundary.lean `assert_axioms` block for the Fast tier -- no definition or proof changes. * 308b6ac expands "CIOS" in the Zcash/Arithmetic/CommitLagrange.lean docstring. No conflicts. The lakefile/manifest automerge keeps this branch's Clean pin (18c8a6b9) and its FixtureCheck/CircuitCheck target layout while taking main's CompElliptic re-pin. Nothing else landed on main outside #111. Captured fixtures are byte-identical.
Human summary
This adds some very fast, certified curve arithmetic, motivated by the need in zcash/ironwood#99 to check correctness of dozens of size$2^{12}$ MSMs with
native_decide(for the verifying key pin). In a first iteration that took 1.5 hours to build, these additions got it down to < 1min.Interesting bits that I learned while doing this:
precompileModuleslets you compile modules and later import them normally in Lean. This is necessary for some stuff, like the Uint32-backed limb field arithmetic, which happens to be not very fast in Lean's interpreterAdditional AI summary
What is proven
Two tiers, the second proven equal to the first — and the first proven against the repository's pre-existing complete affine group law on
SWPoint Vesta.curve(itsnsmulfor the ladder; the MSM specs are generic over[AddCommMonoid M]and consume the same instance atG). No new reference semantics is introduced, and no Mathlib bridge is involved.Curves/Pasta/Fast/Projective.lean— Renes–Costello–Batina complete addition (add-2015-rcb,a = 0) on(X : Y : Z)over 𝔽_q:toAffine_paddagainstSWPoint Vesta.curve, closure, leaf bridges,pnsmulFast_spec. Completeness rests on Vesta having no 2-torsion (Vesta.no_onCurve_y_zero); the polynomial cofactors were found by an offline Gröbner search and are re-checked here byring, so they are re-derivable rather than trusted.Msm.lean/MsmProj.lean— windowed Pippenger,pippenger_eq_msm-proven equal to the naive MSM, generic over[AddCommMonoid M];MsmProjruns the interior in projective coordinates (measured at n = 2048: naive 242 s → projective scatter 4.3 s → windows-parallel 0.8 s).ProjectiveMontDefs.lean/ProjectiveMontEquiv.lean— the same schedules on eight-limb Montgomery residues, importing nothing beyond Lean core, with every kernel operation proven to compute the reference:toPVesM_padd/_pid/_pneg,pnsmulM_spec,msmM_spec. The bridge is one hop — the vendored field'stoFieldis a ring isomorphism ontoZMod q, so the coordinate map pushes through the RCB formulas, and the schedules are structural inductions against theirMsmProjtwins.No
sorry;#print axiomson every headline spec gives exactlypropext/Classical.choice/Quot.sound— nothing extends the trust base. This is a build-time check:CompElliptic/TrustBoundary.leanpins the seven headline specs (toAffine_padd,smulFast_eq,padd_eq_paddFast,pippengerFastPar_eq_msm,commitLagrangeFastWith_eq,pnsmulM_spec,msmM_spec) at the flaglessassert_axiomstier, so reachingnative_decideorsorryanywhere in the fast tier fails the build.Vendored CompPoly (
CompElliptic/Vendor/)The Montgomery tier needs eight-limb arithmetic not in the pinned CompPoly, so
Vendor/CompPoly/Montgomery/vendors branchfast_multilimb_fields@b3850f0, namespaces left at upstream'sMontgomery.*. Deletion criterion: the CompPoly pin advancing past CompPoly #258 + #274 — then the directory is deleted and the imports re-point; onlyPasta.leanwas rewritten (to reuse this repo's Pratt certificates, keeping a singleFieldinstance). Details inCompElliptic/Vendor/README.md.The precompile lane
lean_lib FastFieldNativeprecompiles the two zero-import definition modules so the arithmetic evaluates as compiled C rather than in the interpreter. Two invariants, both enforced byscripts/check_native_lane.shand commented in the lakefile: the lane's import closure must stay core-only (native codegen over a mathlib closure OOMs), and the root module must be named after the library (the dynlib initializer symbol is derived from the.soname). Opt-in —import CompEllipticpulls in none of it — and easy to drop wholesale if unwanted.Notes
CoordinateSysteminstance:PVesis a bare triple with proven commutation. When the planned abstraction lands, the reusable part here is the RCB completeness argument; the two should be reconciled.Msm.leanis curve-generic apart from itscommit_lagrangewrapper; it sits underCurves/Pasta/Fast/only to keep the tree in one place.Fastinterfaces are provisional — they are not guaranteed to remain public, and may be folded into the existing API or otherwise changed incompatibly (see theCoordinateSystemreconciliation, Reconcile the fast projective arithmetic with the CoordinateSystem abstraction #15).[Edited by @daira (assisted by Claude Fable 5): stated the correctness anchor (the pre-existing
SWPointaffine law) up front, noted the trust-boundary pin added on the branch, and added the API-stability note.]