perf(ecsm): 7.7x faster witness generation#866
Open
diegokingston wants to merge 2 commits into
Open
Conversation
compute_witness: 20.8ms -> 2.7ms per ECSM ecall (measured, this machine, high-popcount scalar ~380 steps). Three changes: - Replay in hand-rolled Jacobian coordinates (dbl-2009-l / madd-2007-bl) over k256's public field arithmetic, with the crate's own Montgomery batch-inversion for z-normalization and slope denominators. Replaces k256's ProjectivePoint::batch_normalize, which measured ~5-6ms for the ~760 points of one witness -- no better than per-point to_affine. Intermediates are normalized before subtractions: k256's lazy-magnitude negate(1) is only correct below ~2p (same reason k256's own formulas call normalize_weak). Parity with the BigUint reference replay is covered by tests::curve_tests. - shifted_quotient: one div_rem instead of separate % and / (halves the 512/256-bit BigInt divisions, 6 -> 3 per step). - build_step loop runs on rayon (steps are independent witnesses). Verification: 15/15 ecsm tests, 8/8 prover ecsm tests (incl. full prove+verify of the ecsm guests and the forged-witness rejection tests). Adds examples/bench_witness.rs as the timing harness.
Collaborator
Author
|
/bench |
Benchmark — ethrex 20 transfers (median of 3)Table parallelism: auto (cores / 3)
Commit: 59acfe8 · Baseline: cached · Runner: self-hosted bench |
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
compute_witness(one ECSM ecall's witness): 20.8ms → 2.7ms measured (high-popcount scalar, ~380 steps). At 4 ecalls per ecrecover that's ~83ms → ~11ms host per recovery; ~8.3s → ~1.1s for a 100-signature block.Three changes:
ProjectivePoint::batch_normalize, which measured ~5-6ms for the ~760 points of one witness — no better than 760 individualto_affine()calls (its innerBatchInvertis fine at ~60µs; the total never gets the batching benefit).shifted_quotient: onediv_reminstead of separate%(divisibility assert) and/— halves the 512/256-bit BigInt divisions (6 → 3 per step).build_steploop on rayon — steps are independent witnesses.The subtle part (caught by the parity tests)
The first Jacobian version produced wrong points: k256's lazy-magnitude
negate(1)is only correct below ~2p, so subtraction chains over unnormalized intermediates miscompute (this is why k256's own formulas callnormalize_weakafter every add-chain). Fixed with strategicnormalize()on intermediates feeding subtractions, documented in the code. Parity with the BigUint reference replay is covered bytests::curve_tests.Verification
ecsmcrate tests (parity vs the reference replay).cargo run --release --example bench_witness -p ecsm.