Skip to content

perf: optimize hash-to-G1 in the highly 2-adic Fp case#830

Merged
Tabaie merged 1 commit intomasterfrom
perf/hash-to-curve
Apr 2, 2026
Merged

perf: optimize hash-to-G1 in the highly 2-adic Fp case#830
Tabaie merged 1 commit intomasterfrom
perf/hash-to-curve

Conversation

@yelhousni
Copy link
Copy Markdown
Collaborator

@yelhousni yelhousni commented Apr 2, 2026

Description

  • Optimize G1SqrtRatio in 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.
  • ~5.5% speedup on BLS12-377 HashToG1 (62.9 µs → 59.4 µs), zero-cost for QR inputs.

Changes

Template (internal/generator/hash_to_curve/template/pkg_sswu.go.tmpl):

  • In the Sarkar-based SqrtRatio (q ≡ 1 mod 8 path), replaced the "exponentiate first, check QR after, re-exponentiate if QNR" pattern with a Legendre() call upfront to determine the QR/QNR branch before any exponentiation.
  • This eliminates the second ExpBySqrtExp call for non-QR inputs (~50% of random inputs), saving one full ~330-bit exponentiation per non-QR case.
  • The 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 G1

Type of change

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

Key Decisions

  • Only applied to SqrtRatio in hash-to-curve, NOT to SqrtSarkar in element.go. The latter would add overhead for QR inputs (the common case for Sqrt) since the existing code discovers residuosity "for free" as a byproduct of the exponentiation. Users who want early non-QR rejection can call Legendre() themselves before Sqrt().
  • Only affects the Sarkar path (q ≡ 1 mod 8, SarkarEnabled). The q ≡ 3 mod 4 and q ≡ 5 mod 8 paths already use single-exponentiation + CMOV patterns that don't have this waste.
  • G2 SqrtRatio uses the generic RFC 9380 algorithm (not Sarkar), which doesn't exhibit the double-exponentiation pattern.

How has this been tested?

  • TestG1SqrtRatio passes for BLS12-377 and BLS24-315
  • TestHashToG1 passes for BLS12-377

How has this been benchmarked?

BLS12-377 HashToG1 (Apple M5, single-threaded):

ns/op
Before 62,900
After 59,400
Speedup 5.5%

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

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 G1SqrtRatio for high 2-adicity base fields by switching QR/QNR detection to an upfront Legendre() check, so the code performs one ExpBySqrtExp on 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-377 and bls24-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.

@yelhousni yelhousni added this to the v0.19.N milestone Apr 2, 2026
@yelhousni yelhousni requested review from Copilot and gbotrel April 2, 2026 03:53
@yelhousni yelhousni self-assigned this Apr 2, 2026
@yelhousni yelhousni requested a review from Tabaie April 2, 2026 03:53
Copy link
Copy Markdown
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 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 SqrtRatio path, determine QR/QNR via Legendre() before exponentiation and perform exactly one ExpBySqrtExp on 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.go implementations (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 Tabaie merged commit e37cc7f into master Apr 2, 2026
17 checks passed
@Tabaie Tabaie deleted the perf/hash-to-curve branch April 2, 2026 20:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants