Skip to content

Implement Flag-Based Verification for Recursive SNARK Proofs & In-Circuit Signatures #1432

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from

Conversation

lucasmenendez
Copy link
Contributor

Description

This PR addresses issue #1429 by introducing a more flexible mechanism for recursive proof verification. Instead of immediately asserting proof validity (via api.Assert), the new approach returns a flag—1 for valid and 0 for invalid—that can be conditionally enforced later. This design allows developers to aggregate multiple proofs (even when some are intentionally invalid) and decide which ones must be fully verified.

Key changes include

  • ProofIsValid: A new method for the in-circuit Groth16 proof verifier that returns a verification flag instead of asserting immediately.
  • SignIsValid: A similar method for ECDSA in-circuit signatures, returning the result of the assertion rather than forcing it.
  • In-circuit Algebra Field Enhancements: New methods such as IsEqual, IsZero, and IsOnCurve to provide more nuanced in-circuit comparisons.
  • Pairing Interface Update: The in-circuit Pairing interface now includes a new IsEqual method that returns a flag, aligning with the behavior of ProofIsValid and SignIsValid.

This is an initial implementation that works well and passes all tests, paving the way for more comprehensive support for flexible, conditional proof verification.

Fixes #1429

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

How has this been tested?

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 (not needed)
  • 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

lucasmenendez and others added 6 commits July 18, 2025 16:42
…sEqual but it returns the result of the assertion instead to force it, pairings updated to implement the new method
…e as Verify but it returns the result of the assertion instead to force it
…s AssertProof but it returns the result of the assertion instead to force it
Co-authored-by: Ivo Kubjas <ivo.kubjas@consensys.net>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Comparison Methods Modify Input Parameters

The IsEqual methods for E12 and Pairing types incorrectly modify one of their input parameters by calling Sub on it. Specifically, E12.IsEqual modifies its receiver, while Pairing.IsEqual modifies its first argument. This violates the expected pure behavior of a comparison function and can lead to unexpected side effects.

std/algebra/native/fields_bls12377/e12.go#L165-L168

func (e *E12) IsEqual(api frontend.API, x, y *E12) frontend.Variable {
return e.Sub(api, *x, *y).IsZero(api)
}

std/algebra/native/sw_bls24315/pairing2.go#L503-L506

func (pr *Pairing) IsEqual(e1, e2 *GT) frontend.Variable {
return e1.Sub(pr.api, *e1, *e2).IsZero(pr.api)
}

Fix in CursorFix in Web


Bug: Pairing Method Has Duplicate Difference Checks

The Pairing.IsEqual method contains copy-paste errors in its difference calculations. Specifically, diff2 duplicates diff0 (both comparing x.C0.B0.A0 and y.C0.B0.A0), and diff8 duplicates diff6 (both comparing x.C1.B0.A0 and y.C1.B0.A0). This results in an incomplete equality check, potentially causing the method to return true for unequal GT elements.

std/algebra/native/sw_bls12377/pairing2.go#L329-L341

func (c *Pairing) IsEqual(x, y *GT) frontend.Variable {
diff0 := c.api.Sub(&x.C0.B0.A0, &y.C0.B0.A0)
diff1 := c.api.Sub(&x.C0.B0.A1, &y.C0.B0.A1)
diff2 := c.api.Sub(&x.C0.B0.A0, &y.C0.B0.A0)
diff3 := c.api.Sub(&x.C0.B1.A1, &y.C0.B1.A1)
diff4 := c.api.Sub(&x.C0.B1.A0, &y.C0.B1.A0)
diff5 := c.api.Sub(&x.C0.B1.A1, &y.C0.B1.A1)
diff6 := c.api.Sub(&x.C1.B0.A0, &y.C1.B0.A0)
diff7 := c.api.Sub(&x.C1.B0.A1, &y.C1.B0.A1)
diff8 := c.api.Sub(&x.C1.B0.A0, &y.C1.B0.A0)
diff9 := c.api.Sub(&x.C1.B1.A1, &y.C1.B1.A1)
diff10 := c.api.Sub(&x.C1.B1.A0, &y.C1.B1.A0)
diff11 := c.api.Sub(&x.C1.B1.A1, &y.C1.B1.A1)

Fix in CursorFix in Web


Was this report helpful? Give feedback by reacting with 👍 or 👎

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

return a Flag on proof recursive verification, instead of Assert()
2 participants