crypto: Spell out the BN254 ate loop schedule digits - #1646
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1646 +/- ##
==========================================
- Coverage 97.72% 97.72% -0.01%
==========================================
Files 171 171
Lines 15629 15624 -5
Branches 3613 3613
==========================================
- Hits 15273 15268 -5
Misses 269 269
Partials 87 87
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
The Miller loop schedule was a uint128 of 2-bit groups, unpacked with a shift and two bit tests per iteration and paired with a separate length constant. Storing the digits as -1, 0 and 1 lets the loop range over them: the shift, the length constant and one of the two add branches go away. Instruction and branch counts are unchanged. The name claimed NAF, but the digits are only a semi-NAF: the non-adjacent form of 6x+2 leads with 1, 0, -1 where this leads with 1, 1, encoding the same value with the same 22 non-zero digits but one iteration less. Renamed accordingly.
chfast
force-pushed
the
crypto/naf-array
branch
from
August 11, 2026 14:18
9a9e031 to
37feca2
Compare
There was a problem hiding this comment.
Pull request overview
Replaces the packed BN254 Miller-loop schedule with explicit signed digits while preserving pairing behavior.
Changes:
- Adds a documented 64-digit semi-NAF schedule.
- Iterates directly over signed digits, simplifying branch logic.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
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.
The Miller loop schedule was a uint128 of 2-bit groups, unpacked with a shift and two bit tests per iteration and paired with a separate length constant. Storing the digits as -1, 0 and 1 lets the loop range over them, so the shift, the length constant and one of the two add branches go away.
The digits are not the non-adjacent form of 6x+2, which is worth knowing before anyone regenerates them: the NAF has 66 digits and leads with 1, 0, -1, while this schedule has 65 and leads with 1, 1. Same value, same 22 non-zero digits, one loop iteration less, so a plain NAF routine would add that iteration back. gnark-crypto's
LoopCounter [66]int8is the canonical NAF and pays it. Hence the rename to_DIGITSand the "semi-NAF" note in the comment.Within digits {-1, 0, 1} this schedule is optimal on both axes: 65 digits is the minimum length, since 64 digits reach only 2^64-1 < 6x+2, and 22 non-zero digits is the minimum weight, which is the NAF's. Wider digit sets do not help either: from w=3 up, every digit above 1 needs an extra full Fq12 multiplication by a precomputed f_d(P), because Miller's addition rule is f_{i+j} = f_i * f_j * l / v and f_1 is the only constant one. Measured against a deliberately wrong table with 5-NAF's shape, that ceiling is -9% instructions, while the Fq12 factors, the seven affine odd multiples and the seven per-pair f_d(P) constants cost about 2.7 times more than the ceiling saves.
Instructions and branches are unchanged, -0.01% and -0.18% on the ECPAIRING benchmark. Cycles could not resolve a difference on this machine under load: four runs gave -4.3%, -1.3%, -3.2% and +1.1%.
The digits were checked by reconstructing 6x+2 from them, and every single-digit mutation of the table, as well as a change of its length, is caught by the existing pairing tests.
This touches the same function as #1544, so whichever lands second needs a rebase.