perf(backends/arkworks): batch normalization + rayon-parallel DoryRoutines - #25
Closed
0xAndoroid wants to merge 3 commits into
Closed
perf(backends/arkworks): batch normalization + rayon-parallel DoryRoutines#250xAndoroid wants to merge 3 commits into
0xAndoroid wants to merge 3 commits into
Conversation
…tines msm() converts bases to affine with a single batched inversion (normalize_batch) instead of one field inversion per point, for both G1 and G2. fixed_base_vector_scalar_mul, fixed_scalar_mul_bases_then_add, fixed_scalar_mul_vs_then_add, and fold_field_vectors run their per-element loops in parallel under the existing `parallel` feature, falling back to the previous serial loops otherwise. Group results are exact, so commitments, proofs, and transcripts are byte-identical to the previous routines. Unit tests pin every routine to a naive reference, including identity-point / zero-scalar edge cases. Ported from a16z/jolt#1714 (JoltG1Routines/JoltG2Routines).
into_inner() plus From impls in both directions between the wrappers and their inner arkworks types, so downstream consumers no longer need transmutes (the wrappers are repr(transparent), but per-element conversions cover the common cases safely).
…bases
Batch normalization is only a win when bases actually need an inversion.
Dory's setup generators (and hence the commit-path row MSMs and the
first-round e_beta MSMs, whose bases are setup slices) are already
affine-normalized (z = one), where into_affine short-circuits without
any inversion and normalize_batch pays ~6 field muls per point plus a
slice copy for nothing — a measurable commit regression at 2^26.
msm now scans z values (two field comparisons per point) and dispatches:
all z in {0, 1} -> per-element into_affine (no inversions at all);
otherwise -> one batched inversion for the whole slice. Folded vectors
mid reduce-round have arbitrary z and keep the batch path.
Collaborator
|
superseded by #27 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Ports the optimized Dory routines that Jolt runs in production (
JoltG1Routines/JoltG2Routinesfrom a16z/jolt#1714) upstream into the stockbackends::arkworksG1Routines/G2Routines, so everydory-pcsconsumer gets them.What changed
msm(G1 + G2): when bases are not already normalized, convert to affine with one batched inversion (normalize_batch) instead of one field inversion per point. Already-normalized bases (z= one — i.e. setup generators, which back the commit-path row MSMs and the first-rounde_betaMSMs) keep the inversion-free per-elementinto_affinepath; a two-comparison-per-pointzscan dispatches. Folded vectors mid reduce-round have arbitraryzand take the batch path — that's where the win is.fixed_base_vector_scalar_mul,fixed_scalar_mul_bases_then_add,fixed_scalar_mul_vs_then_add,fold_field_vectors(G1 + G2): per-element loops parallelized with rayon under the existingparallelfeature (same#[cfg]pattern asark_pairing.rs), serial fallback unchanged. G1/G2 bodies share private generic helpers.into_inner()+Fromimpls in both directions forArkFr↔Fr,ArkG1↔G1Projective,ArkG2↔G2Projective, so downstream consumers don't need transmutes for the common cases.Deliberately not ported: Jolt's GLV kernels (
jolt_optimizations::*, e.g.vector_add_scalar_mul_g1_online). They live in thea16z/arkworks-algebrafork, anddory-pcspublishes to crates.io (no git deps), so those call sites became plain rayon-parallel arkworks scalar muls. They remain a further ~speedup available downstream in Jolt.Correctness
Group results are exact, so commitments, proofs, and transcripts are byte-identical to the stock routines. New unit tests pin every routine to a naive
scale/addreference for G1 and G2, covering identity points, zero scalars, empty inputs, and both msm dispatch paths (mixed-zand all-normalized bases). Full suites pass on both CI feature matrices (backends,parallel,cache,disk-persistenceand+zk), run single-threaded locally: 76 + 133 tests.Heads-up (unrelated, pre-existing): running the suite multi-process can flake tests that call
setup::<BN254>(10)— that's the disk-persisted setup race #24, reproduced on stockmain.Benchmarks
cargo bench --bench arkworks_proof --features backends,cache,parallel -- --quick(official 2^26 size, nu = sigma = 13), Apple M4 (10 cores, 16 GB), quiet machine, back-to-back runs, fresh criterion baseline:prove_2^26_coefficientsverify_2^26_coefficientscommitcall at 2^26 (2 iters, one-shot harness)¹ Within this laptop's run-to-run variance band. Expected: the verifier never calls
DoryRoutines(its checks are pairings/GT ops), and commit-path MSM bases are already-normalized setup generators, where the dispatch keeps the byte-identical stock path. An earlier draft normalized unconditionally and regressed commit ~1.7× at 2^26 — that's what thez-scan dispatch (third commit) is for.The prove win comes from batch normalization of the folded (arbitrary-
z) round vectors plus parallel G1/G2 vector folds; it grows with core count (Jolt measured larger wins on many-core machines with the same structure, on top of its fork-only GLV kernels).Numbers were taken with criterion
--quickon a fanless laptop — treat them as directional; happy to rerun anything.