perf: optimize hash-to-G1 in the highly 2-adic Fp case#830
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR optimizes the generated G1SqrtRatio used by hash-to-curve for curves with highly 2-adic base fields (q ≡ 1 mod 8, Sarkar path) by avoiding a redundant exponentiation on the non-QR branch. It does so by performing a Legendre-symbol check up front to select the correct input to exponentiate.
Changes:
- In the Sarkar-based
SqrtRatiopath, determine QR/QNR viaLegendre()before exponentiation and perform exactly oneExpBySqrtExpon the chosen input. - Remove the prior “exp → derive residuosity from xM → maybe exp again” pattern (and its associated squaring chain used for residuosity detection).
- Regenerate affected curve-specific
hash_to_curve/g1.goimplementations (BLS12-377, BLS24-315).
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| internal/generator/hash_to_curve/template/pkg_sswu.go.tmpl | Updates the Sarkar SqrtRatio template to use a Legendre pre-check and a single exponentiation. |
| ecc/bls12-377/hash_to_curve/g1.go | Regenerated output applying the optimized G1SqrtRatio logic for BLS12-377. |
| ecc/bls24-315/hash_to_curve/g1.go | Regenerated output applying the optimized G1SqrtRatio logic for BLS24-315. |
Tabaie
approved these changes
Apr 2, 2026
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.
Description
G1SqrtRatioin hash-to-curve for curves with highly 2-adic base fields (q ≡ 1 mod 8) by using a cheap Legendre symbol check to avoid a redundant exponentiation on the non-QR branch.HashToG1(62.9 µs → 59.4 µs), zero-cost for QR inputs.Changes
Template (
internal/generator/hash_to_curve/template/pkg_sswu.go.tmpl):SqrtRatio(q ≡ 1 mod 8 path), replaced the "exponentiate first, check QR after, re-exponentiate if QNR" pattern with aLegendre()call upfront to determine the QR/QNR branch before any exponentiation.ExpBySqrtExpcall for non-QR inputs (~50% of random inputs), saving one full ~330-bit exponentiation per non-QR case.Legendre()function uses Pornin's binary GCD, which is ~10× cheaper than the exponentiation it replaces.Generated files (from template):
ecc/bls12-377/hash_to_curve/g1.go— BLS12-377 G1 (ν₂(q-1) = 46)ecc/bls24-315/hash_to_curve/g1.go— BLS24-315 G1Type of change
Key Decisions
SqrtRatioin hash-to-curve, NOT toSqrtSarkarinelement.go. The latter would add overhead for QR inputs (the common case forSqrt) since the existing code discovers residuosity "for free" as a byproduct of the exponentiation. Users who want early non-QR rejection can callLegendre()themselves beforeSqrt().SarkarEnabled). The q ≡ 3 mod 4 and q ≡ 5 mod 8 paths already use single-exponentiation + CMOV patterns that don't have this waste.SqrtRatiouses the generic RFC 9380 algorithm (not Sarkar), which doesn't exhibit the double-exponentiation pattern.How has this been tested?
TestG1SqrtRatiopasses for BLS12-377 and BLS24-315TestHashToG1passes for BLS12-377How has this been benchmarked?
BLS12-377
HashToG1(Apple M5, single-threaded):Checklist:
golangci-lintdoes not output errors locallyNote
Medium Risk
Touches performance-critical finite-field/EC hash-to-curve math; while the change is localized, incorrect QR/QNR detection or Legendre timing characteristics could affect correctness or side-channel expectations.
Overview
Optimizes Sarkar-based
G1SqrtRatiofor high 2-adicity base fields by switching QR/QNR detection to an upfrontLegendre()check, so the code performs oneExpBySqrtExpon the correct input instead of exponentiating and potentially re-exponentiating on the non-residue branch.Updates the generator template and regenerates the affected curves (
bls12-377andbls24-315) to use this new flow, preserving the same output contract while reducing work for ~50% non-QR cases.Written by Cursor Bugbot for commit 696981a. This will update automatically on new commits. Configure here.