fix: GLV subscalar range checks#1778
Conversation
There was a problem hiding this comment.
Pull request overview
This PR addresses soundness in GLV/FakeGLV scalar multiplication by ensuring sub-scalar (hint output) widths are range-checked to the mathematically expected bit bounds, and it extends emulated generic hint plumbing to support caller-specified per-output bit range checks.
Changes:
- Add
WithHintOutputRangeCheckBitsto generic emulated hint calls and use it to enforce tighter (caller-defined) bit bounds on hint outputs. - Refactor limb packing / width enforcement to support packing elements at a specified bit width (
packLimbsWithWidth,enforceWidth(nbBits)). - Update multiple curve scalar-mul paths (native + emulated) to pass tight sub-scalar bounds into hints; add tests for the new range-check behavior and update benchmark stats.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| std/math/emulated/field.go | Refactors limb packing to support explicit bit-width packing and range checks. |
| std/math/emulated/field_assert.go | Refactors width enforcement to take an explicit bit width (nbBits). |
| std/math/emulated/field_hint.go | Adds generic-hint options, including per-output range-check bit configuration and output unpacking changes. |
| std/math/emulated/field_hint_test.go | Adds tests covering custom hint-output range checks and option validation. |
| std/algebra/native/twistededwards/hints.go | Removes duplicate / unused hint registration for scalar decomposition. |
| std/algebra/native/sw_grumpkin/hints.go | Switches Grumpkin GLV decomposition to generic hint + tight output bit checks. |
| std/algebra/native/sw_grumpkin/wrapper.go | Updates call sites for the Grumpkin scalar decomposition helper signature. |
| std/algebra/native/sw_grumpkin/g1.go | Updates GLV scalar-mul call sites to the new decomposition helper signature. |
| std/algebra/native/sw_bls12377/hints.go | Removes duplicate decompose-scalar hints from hint registration. |
| std/algebra/emulated/sw_emulated/point.go | Applies tight hint-output bounds for emulated GLV/FakeGLV decompositions (soundness-related). |
| std/algebra/emulated/sw_bw6761/hints.go | Removes duplicate emulated G1 decomposition hint. |
| std/algebra/emulated/sw_bw6761/g2.go | Applies tight hint-output bounds for 4-way decomposition outputs. |
| std/algebra/emulated/sw_bn254/g2.go | Applies tight hint-output bounds for 4-way decomposition outputs. |
| std/algebra/emulated/sw_bls12381/hints.go | Removes duplicate emulated G1 decomposition hint. |
| std/algebra/emulated/sw_bls12381/g2.go | Applies tight hint-output bounds for 4-way decomposition outputs. |
| internal/stats/latest_stats.csv | Updates latest constraint-count stats after the optimization/tightening. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 4728f06. Configure here.
yelhousni
left a comment
There was a problem hiding this comment.
LGTM. The bound tightening is mathematically sound — (BitLen+3)/4 + 2 covers γ₄·r^(1/4) and (BitLen+1)/2 covers γ₂·√r with comfortable slack. The WithHintOutputRangeCheckBits API is a clean generalization and the enforceWidth refactor preserves existing semantics. Test coverage (multi-limb, zero-bits, bad indices) is good.

Description
Fixes #1767
Also implements in generic hint calling in field emulation to define the range check amounts. I think this is also independently relevant elsewhere where we expect smaller outputs from the hint.
Type of change
How has this been tested?
Existing tests for scalarmul pass
Added tests for the reduced rangecheck edge cases in field emulation.
Checklist:
golangci-lintdoes not output errors locallyNote
Medium Risk
Changes in-circuit soundness assumptions for GLV/fake-GLV hints—incorrect bit bounds could admit malicious decompositions—though bounds match documented lattice limits and are covered by new tests.
Overview
Adds
WithHintOutputRangeCheckBitsto emulated generic hints so hint outputs can be range-checked and packed at a custom bit width (viapackLimbsWithWidth/ refactoredenforceWidth), instead of always using full modulus-width checks.GLV / fake-GLV scalar multiplication (emulated
sw_emulated, native G2 on BLS12-381/BN254/BW6-761, Grumpkin) now passes LLL/Hermite-sized bounds on decomposed sub-scalars (u1,u2,v1,v2,s1,s2, etc.) when callingNewHintGeneric, aligning constraints with proven decomposition sizes and reducing scalar-mul cost (reflected inlatest_stats.csv).Removes unused
decomposeScalarG1/decomposeScalarG2hint registrations where decomposition moved to shared emulated paths; Grumpkin’scallDecomposeScalardrops thesimpleflag and uses the generic hint API with 127-bit output checks.New
field_hint_testcoverage exercises custom range-check indexing, multi-limb widths, and validation errors.Reviewed by Cursor Bugbot for commit 852a650. Bugbot is set up for automated code reviews on this repo. Configure here.