Skip to content

Conversation

@yelhousni
Copy link
Collaborator

@yelhousni yelhousni commented Jan 29, 2026

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 k doubleStep more efficiently as manyDoubleSteps(k) following "Efficient Scalar Multiplications on Elliptic Curves without Repeated Doublings and Their Practical Performance" (Alg. 1) by Sakai and Sakurai. Then we merge manyDoubleSteps(k) with doubleAndAddStep (from #797) in manyDoubleStepsAndAdd(k) by batching their respective inverse computations.
Following Table 1 in the paper, and benchmarking the cost ratio of inverse and multiplication in Fp2 for each curve, we choose k=3 as the crossover point to use manyDoubleSteps. For BLS24, it is faster to use a loop-based version with doubleStep and doubleAndAddStep.

Type of change

  • New feature (non-breaking change which adds functionality)

How has this been tested?

Refactored test into TestFixedPairing.

How has this been benchmarked?

Curve Old (µs) New (µs) Speedup
BLS12-381 220.5 142.3 35.5%
BLS12-377 217.7 157.4 27.7%
BN254 118.1 108.1 8.5%
BW6-761 2758.4 1273.6 53.8%
  • BN254 loop counter does not have many consecutive zeros.
  • BLS24 do not use manyDoubleSteps but only doubleAndAddStep (not implemented before).
  • BW6-633 shows similar results but it is less optimized

Checklist:

  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • I have added tests that prove my fix is effective or that my feature works
  • I did not modify files generated from templates
  • golangci-lint does not output errors locally
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Note

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, and bn254 by adding manyDoubleSteps (batching consecutive doublings with one inversion) and manyDoublesAndAdd (fusing those doublings with the subsequent add using a single batch inversion), then rewriting PrecomputeLines to exploit long runs of zeros in each curve’s loop counter.

Extends similar precompute optimizations to the BW6 curves by replacing the loop-based PrecomputeLines with explicit, run-length–batched sequences (using manyDoubleSteps/manyDoublesAndAdd and adding local batch inversion helpers), and upgrades bls24-315/bls24-317 precomputation to use a newly added ELM-based doubleAndAddStep for ±Q cases.

Refactors and expands tests: removes standalone pairing_compatibility_test.go files, moves reference implementations into the main pairing test files/templates, splits pairing vs exponentiation/torus tests, and adds property tests that compare Pair vs PairFixedQ, optimized vs reference PrecomputeLines, and (where implemented) manyDoubleSteps vs repeated doubleStep.

Written by Cursor Bugbot for commit 84f88aa. This will update automatically on new commits. Configure here.

@yelhousni yelhousni added this to the v0.19.N milestone Jan 29, 2026
@yelhousni yelhousni requested review from Copilot and ivokub January 29, 2026 23:29
@yelhousni yelhousni added type: perf dep: linea Issues affecting downstream Linea labels Jan 29, 2026
Copy link
Contributor

Copilot AI left a 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 manyDoubleSteps function for bn254, bls12-381, bls12-377, bw6-761, bw6-633 curves
  • Adds doubleAndAddStep function 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)

@gbotrel gbotrel requested a review from YaoJGalteland January 30, 2026 18:22
@yelhousni yelhousni self-assigned this Jan 30, 2026
Copy link
Collaborator

@ivokub ivokub left a 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.

@yelhousni
Copy link
Collaborator Author

manyDouble and manyDoubleAndAdd

Actually it's manyDoubleStep and manyDoubleAndAddSteps which make sense only for pairing-friendly curves, not any curve which would use the affine point template. But we can still add them and clarify this in a comment.

@yelhousni
Copy link
Collaborator Author

LoopCounterSequences

I'll create an issue for this and a future PR.

@yelhousni
Copy link
Collaborator Author

yelhousni commented Feb 9, 2026

manyDouble and manyDoubleAndAdd

Actually it's manyDoubleStep and manyDoubleAndAddSteps which make sense only for pairing-friendly curves, not any curve which would use the affine point template. But we can still add them and clarify this in a comment.

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.
I'll create an issue for when we would like a pure refactoring PR in the future: #800

Copy link
Collaborator

@ivokub ivokub left a 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!

@yelhousni yelhousni merged commit 243aa47 into master Feb 10, 2026
14 checks passed
@yelhousni yelhousni deleted the perf/fixed-pairing branch February 10, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dep: linea Issues affecting downstream Linea type: perf

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants