perf: speed up batch verification - #151
Open
sdbondi wants to merge 1 commit into
Open
Conversation
- Choose the final multiscalar multiplication strategy by estimated cost: precomputed Straus for small batches, plain Pippenger for large ones (~35% faster at 256 proofs) - Skip element-wise generator consistency comparisons when statements share the same underlying generator data (Arc pointer equality) - Fold the batch weight into per-proof constants and track d[i] * y^(nm-i) incrementally instead of materializing d, roughly halving scalar multiplications in the per-element loop - Defer proof point decompression until after mask recovery so RecoverOnly skips it entirely (~2.8x faster) - Combine the two mask recovery inversions into one per proof - Remove per-proof clones of commitments, d1, and minimum value promises - Add examples/verify_bench.rs timing harness Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Summary
Speeds up batch verification without changing what is accepted or rejected. Medians on an M-series MacBook, 64-bit proofs (harness included as
examples/verify_bench.rs):RecoverOnlyRecoverAndVerifyChanges
Choose the final multiscalar multiplication strategy by estimated cost. The final check always used the precomputed-Straus mixed MSM, whose per-point cost is constant (~51 curve additions per dynamic point). Each proof contributes ~16 dynamic points, so large batches ran far past the size where Pippenger (~33 additions per point, and falling with size) overtakes it. Verification now estimates both costs, mirroring the algorithm parameters in
curve25519-dalek, and picks the cheaper; small batches keep the precomputed path. Both strategies compute the same sum, so acceptance is unchanged.Skip redundant generator consistency comparisons. The batch consistency check compared generator vectors element-wise between statements — tens of thousands of point-equality checks for large batches of statements cloned from the same
RangeParameters. The precomputation tableArcis created exactly once alongside the generator vectors it is built from, soArc::ptr_eqproves the vectors identical; mismatches still fall back to the full element-wise comparison.Halve the scalar work in the per-element loop. The batch weight is folded into per-proof constants, and
d[i] * y^(nm−i)is tracked incrementally (one multiplication per element, with a correction at aggregation-block boundaries) instead of materializing thedvector — roughly 10 → 5 scalar multiplications per element, and one fewer O(mn) allocation per proof.RecoverOnlyskips verification-only work. Point decompression (3 + 2·rounds points per proof) ran before mask recovery even though recovery never touches the points. Decompression now happens after theRecoverOnlycontinue, which is where the ~2.8× recovery speedup comes from. Behavior note:RecoverOnlyno longer rejects proofs whose points are non-canonical encodings, since it no longer decompresses them; the structural length checks still run, and both verifying modes are unchanged.Mask recovery does one inversion per proof instead of two per proof per extension degree, by algebraically folding the
e²andz²·y^(nm+1)divisions intomask = (d1 − η − e·d − residue·e²) · (e²·z²·y^(nm+1))⁻¹.Removed per-proof clones of
commitments,d1, andminimum_value_promises.Testing
cargo lints clippy --all-targets --all-featuresis clean; theno_stdbuild (--no-default-features) checks; nightlycargo fmt --checkis clean.test_large_batch_invalid_proof_is_rejectedexercises rejection through the plain-MSM path (a 100-proof batch crosses the dispatch threshold).cargo run --release --example verify_bench.🤖 Generated with Claude Code