-
Notifications
You must be signed in to change notification settings - Fork 225
perf: optimize pre-computation in fixed-argument pairings by batching double steps #798
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR optimizes fixed-argument pairing operations by implementing a batch doubling algorithm (manyDoubleSteps) that reduces the number of field inversions. The optimization applies to consecutive zero bits in the loop counter by computing k doublings with a single batch inversion instead of k individual inversions.
Changes:
- Implements
manyDoubleStepsfunction for bn254, bls12-381, bls12-377, bw6-761, bw6-633 curves - Adds
doubleAndAddStepfunction for bls24-315 and bls24-317 curves - Refactors test structure into separate test functions (TestPairing, TestFixedPairing, TestMillerLoop, TestExponentiation, TestTorusCompression)
- Moves reference implementations from separate compatibility test files into main test files
- Unrolls PrecomputeLines loops for better performance
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| internal/generator/pairing/template/tests/pairing.go.tmpl | Test refactoring and reference implementations |
| ecc/*/pairing.go | Implements manyDoubleSteps and unrolled PrecomputeLines |
| ecc/*/pairing_test.go | Reorganized tests with new structure |
| ecc/*/pairing_compatibility_test.go | Deleted (moved to main test file) |
ivokub
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! But I think the manyDouble and manyDoubleAndAdd could be defined in the affine point template instead. Right now having a manual implementation is error prone long term and it seems general enough to be possible to define in template? There is only the case where the twist is defined over base field vs extension.
I also would prefer if instead of the fully unrolled implementation we would use a loop definition. I think we can define the sequences in a loop and have a runtime test:
LoopCounter = [190]int8{0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
--->
LoopCounterSequences = {0, 1, 44, -1, 0, } ....
(and we check that when we expand LoopCounterSequences then it expands to the initial LoopCounter).
It is not particularly essential for now and we can postpone, but I think long-term improves maintainability (where we start making different changes here and there and then get mismatching implementations etc.). See if it makes sense and if not then can give an approval as well. The changes otherwise seem correct.
Actually it's |
I'll create an issue for this and a future PR. |
Actually doing a partial migration would leave the codebase in an inconsistent state where some pairing-specific methods (manyDoubleSteps, manyDoublesAndAdd) are templated while others (addMixedStep, doubleStep, addStep, doubleAndAddStep, etc.) remain hand-written. |
ivokub
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! Yes, I agree to resolve the two remarks (many... implementation and LoopSequence) in a separate PR.
Good to merge on my side!
Description
In fixed-argument pairing we use affine coordinates to pre-compute all the lines. The pre-computation loop iterates over a fixed constant with low-Hamming weight. For consecutive zeros, this PR computes
kdoubleStep more efficiently asmanyDoubleSteps(k)following "Efficient Scalar Multiplications on Elliptic Curves without Repeated Doublings and Their Practical Performance" (Alg. 1) by Sakai and Sakurai. Then we mergemanyDoubleSteps(k)withdoubleAndAddStep(from #797) inmanyDoubleStepsAndAdd(k)by batching their respective inverse computations.Following Table 1 in the paper, and benchmarking the cost ratio of inverse and multiplication in
Fp2for each curve, we choosek=3as the crossover point to usemanyDoubleSteps. For BLS24, it is faster to use a loop-based version withdoubleStepanddoubleAndAddStep.Type of change
How has this been tested?
Refactored test into
TestFixedPairing.How has this been benchmarked?
manyDoubleStepsbut onlydoubleAndAddStep(not implemented before).Checklist:
golangci-lintdoes not output errors locallyNote
High Risk
Touches core elliptic-curve pairing arithmetic and precomputed line generation across multiple curves; any subtle formula/indexing mistake could silently corrupt pairings despite added property tests.
Overview
Optimizes fixed-argument pairing precomputation across
bls12-377,bls12-381, andbn254by addingmanyDoubleSteps(batching consecutive doublings with one inversion) andmanyDoublesAndAdd(fusing those doublings with the subsequent add using a single batch inversion), then rewritingPrecomputeLinesto exploit long runs of zeros in each curve’s loop counter.Extends similar precompute optimizations to the BW6 curves by replacing the loop-based
PrecomputeLineswith explicit, run-length–batched sequences (usingmanyDoubleSteps/manyDoublesAndAddand adding local batch inversion helpers), and upgradesbls24-315/bls24-317precomputation to use a newly added ELM-baseddoubleAndAddStepfor±Qcases.Refactors and expands tests: removes standalone
pairing_compatibility_test.gofiles, moves reference implementations into the main pairing test files/templates, splits pairing vs exponentiation/torus tests, and adds property tests that comparePairvsPairFixedQ, optimized vs referencePrecomputeLines, and (where implemented)manyDoubleStepsvs repeateddoubleStep.Written by Cursor Bugbot for commit 84f88aa. This will update automatically on new commits. Configure here.