fix: harden BN254 G2 SRS ingress#22858
Merged
Merged
Conversation
suyash67
commented
Apr 29, 2026
| const std::string& fallback_url); | ||
|
|
||
| g2::affine_element get_bn254_g2_data(const std::filesystem::path& path, bool allow_download = true); | ||
| g2::affine_element get_bn254_g2_data(const std::filesystem::path& path); |
Contributor
Author
There was a problem hiding this comment.
Question for @ludamad: this function was unimplemented before. I've implemented it to check if g2 point:
- is not a point at infinity
- is in the prime-ordered subgroup
- the sha256 matches with the canonical
$[x]_2$
Do we need to keep the boolean allow_download to allow g2 data to be downloaded if all of the above checks fail (like we do in g1 data)?
ledwards2225
approved these changes
Apr 29, 2026
ledwards2225
left a comment
Contributor
There was a problem hiding this comment.
LGTM. I think pairing this with my PR validating the actual trusted setup data would allow a paranoid user to confirm that everything is kosher but in practice this is probably the more useful line of defense
danielntmd
pushed a commit
to danielntmd/aztec-packages
that referenced
this pull request
May 6, 2026
BEGIN_COMMIT_OVERRIDE
fix(ci): default S3_BUILD_CACHE_AWS_PARAMS in cache_s3_transfer{,_to}
(AztecProtocol#22898)
chore: low-hanging chonk prover fixes from profiling (AztecProtocol#22855)
chore: fuse N `add_scaled` into one `parallel_for` (AztecProtocol#22893)
feat: Delayed merge implementation (AztecProtocol#22775)
chore: numeric audit response (AztecProtocol#22856)
fix: harden BN254 G2 SRS ingress (AztecProtocol#22858)
fix: remove unused hash_challenge variable in batch_merge.test.cpp
(AztecProtocol#22906)
fix(bbup): remove jq dependency (AztecProtocol#22912)
chore: fix g2 test failing on merge-train (AztecProtocol#22920)
fix(ci): error on disabled-cache in CI hash calculation (AztecProtocol#22904)
END_COMMIT_OVERRIDE
suyash67
added a commit
that referenced
this pull request
May 14, 2026
## Summary Addresses [findings](https://cantina.xyz/code/3dc4ffe5-40f6-4d08-926c-b17315a5bedb/findings) from the ecc/groups audit. ## Commits - **finding 1** — extend `batch_affine_double_impl` slope formula to include `a` for curves with `a ≠ 0` - **finding 2** — ~reject non-canonical x-coordinate encodings in `affine_element::from_compressed`~ (Opened its own [PR](#22908)) - **finding 3** — route ECDSA / Schnorr secret-nonce scalar mul through a new constant-time `element::mul_const_time` (Montgomery ladder + Coron blinding) - **finding 4** — handle `rhs = ∞` in mixed-coordinate `operator+=` - **finding 5** — zero `y` (and `z`) in `self_set_inf` so the infinity representation is canonical - **finding 6** — fix `pairing.FinalExponentiation` reference helper to iterate the full 256-bit exponent - **finding 7** — extend the G1/G2 SRS defenses from #22858 across the bb.js boundary: in `SrsInitSrs::execute`, SHA-256-verify every fully-present compressed-G1 chunk against `BN254_G1_CHUNK_HASHES` before decompression, pin `g1_points[0]` to the canonical generator and `g1_points[1]` to `τ·G` after parsing, and SHA-256-pin the 128-byte G2 input. The subgroup check, on-disk G2 hash pin, infinity rejection, and `is_in_prime_subgroup` implementation itself already landed in #22858. - **finding 8** — make `field::is_zero` constant-time ## Test plan - `ecc_tests` — pass (audit-related filter: 110 pass, 8 skipped, 0 failures) - `srs_tests` (`CrsFactory.*`) — pass - `bbapi_tests` — pass (30/30) - New regression tests in `affine_element.test.cpp`, `element.test.cpp`, `pairing.test.cpp`, `prime_field.test.cpp`
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.
Summary
Tightens the BN254 G2 SRS load path with four layered defenses, addressing an audit finding around G2 input validation.
add subgroup check on g2 points— implementsaffine_element::is_in_prime_subgroup()(textbook[r]·P == Ocheck) and applies it at every G2 entry point. Catches G2 inputs that lie in a cofactor subgroup of E'(Fq2) but happen to be on-curve.pin SHA-256 of g2 SRS bytes and verify on disk load— bakes the canonical Aztec[x]_2bytes (BN254_G2_ELEMENT_BYTES) and their SHA-256 (BN254_G2_ELEMENT_SHA256) into the binary as constants, mirroring the existing G1 chunk-hash mechanism.get_bn254_g2_datanow hash-compares the on-disk payload before deserialization, so a tamperedbn254_g2.datis rejected before its bytes can reach any verifier. Also implements the previously declaration-onlyget_bn254_g2_data.reject g2 = point at infinity— explicit gate against[x]_2 = O. Infinity is in every subgroup (so the subgroup check passes) ande(−W, O) = 1collapses the KZG pairing equation. Strictly redundant with the hash pin, but kept as defense-in-depth so any future loosening of the hash gate (e.g. a "custom SRS" flag) does not silently reopen the issue.reject off-curve points in is_in_prime_subgroup— guards the primitive itself: the Weierstrass group law is unsound for off-curve coordinates, which means the[r]·Ptrick can return a false positive on a point satisfyingy² = x³ + b'for someb' ≠ bwith a prime-r factor in its order. One squaring up front closes that gap and protects every existing and future caller.Threat model
The hash pin promotes the on-disk SRS bytes to the same trust level as the binary itself. Concretely, the attack vectors closed:
crs.aztec-cdn.foundationNone of these require the attacker to patch the verifier binary itself.
Test plan
srs_tests— allCrsFactory.*pass, including newBn254HardcodedG2IsInPrimeSubgroup,Bn254G2HashMatchesPinnedBytes,Bn254G2DataLoadsAndVerifies,Bn254G2CorruptionDetected,Bn254G2InfinityRejectedecc_tests— full suite (843 tests) passes, including newg2.IsInPrimeSubgroupAcceptsSubgroupPoints,g2.IsInPrimeSubgroupRejectsCofactorPoint,g2.IsInPrimeSubgroupRejectsOffCurvePoint(regression test for the off-curve guard) and the typedIsInPrimeSubgroupAcceptsSubgroupPointsninja srs_tests ecc_tests