Repository navigation
fix: rule out zero residue witness in BW6-761 AssertFinalExponentiationIsOne - #1871
Merged
Merged
Conversation
Signed-off-by: Ivo Kubjas <ivo.kubjas@consensys.com>
Signed-off-by: Ivo Kubjas <ivo.kubjas@consensys.com>
yelhousni
approved these changes
Oct 6, 2026
yelhousni
left a comment
Contributor
There was a problem hiding this comment.
Consistent with the prior fix: sw_bn254/pairing.go:175 and sw_bls12381/pairing.go:609 already call pr.Ext12.Inverse(residueWitness) with near-identical comments and native/sw_bls12377 is also covered. BW6-761 was the only missed site.
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
Pairing.AssertFinalExponentiationIsOnefor BW6-761 checksx == residueWitness^ΛwithresidueWitnessobtained from a hint, but did notconstrain the hint output to be non-zero. The relation is homogeneous in the
hint output: for a zero accumulator (
x = 0), the all-zero residue witnessdegenerates both exponentiation chains to 0 and
DivUnchecked(0, 0)onlyenforces
0 = quotient·0, leaving the quotient unconstrained. The finalassertion then reduces to
0 == 0and passes, accepting a zero accumulator eventhough 0 is not in the multiplicative target group and its final exponentiation
is not one.
This is the same bug class as
GHSA-3mvx-pp85-pm65,
fixed for BN254, BLS12-381 (emulated) and BLS12-377 (native) in b1fbb16 by
anchoring the residue witness to be invertible. The BW6-761 variant of the
gadget was missed. The fix mirrors it:
Ext6.InverseassertsresidueWitness·residueWitness⁻¹ == 1, unsatisfiable atresidueWitness == 0.Cost: one E6 inverse hint plus one E6 multiplication per call.
PairingCheckis not affected: a zeroresidueWitnessInvfreezes the Milleraccumulator at 0, so the
result == 1assertion can never pass.Type of change
How has this been tested?
TestFinalExponentiationIsOneRejectsZeroAccumulator:a zero accumulator must be rejected. The honest hint already returns the
all-zero residue witness for
x = 0, so the exploit path is exercisedend-to-end — the test fails before the fix (zero accumulator accepted)
and passes after.
go test -short ./std/algebra/emulated/sw_bw6761/...passes, includingthe existing completeness test
TestFinalExponentiationIsOneTestSolve(valid non-zero residue witnesses remain invertible).
gofmt/go vetclean on the changed package.How has this been benchmarked?
Not benchmarked: the change adds a fixed-cost soundness anchor (one E6
InverseperAssertFinalExponentiationIsOnecall); no algorithmic changes.Checklist:
golangci-lintdoes not output errors locally — not run: local binary isbuilt with go1.25 while the module targets Go 1.26; deferring to CI
Note
High Risk
This closes a proof soundness bug in pairing final-exponentiation checks that could wrongly accept a zero accumulator; the fix is localized but security-critical for circuits using this gadget.
Overview
Fixes a soundness gap in BW6-761 emulated
AssertFinalExponentiationIsOne: the hint-derivedresidueWitnesswas not forced to be non-zero, so for accumulator x = 0 an all-zero witness could satisfyx == residueWitness^Λvia degenerate exponentiation and unconstrainedDivUnchecked(0, 0).The change adds
Ext6.InverseonresidueWitness(invertibility anchorresidueWitness·residueWitness⁻¹ == 1), matching the prior fix on BN254/BLS curves that were missed for BW6-761. Cost is one E6 inverse per assertion call.Adds regression
TestFinalExponentiationIsOneRejectsZeroAccumulator, which feeds a zero GT directly into the assertion circuit and expects unsatisfiability.Reviewed by Cursor Bugbot for commit 347f228. Bugbot is set up for automated code reviews on this repo. Configure here.