-
Notifications
You must be signed in to change notification settings - Fork 422
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
return a Flag on proof recursive verification, instead of Assert() #1429
Comments
I'm thinking that instead of returning a flag, it could simply return an |
That is very interesting proposal, and I think it would be worth it. It could actually enable a few use-cases for making rollups more gas-efficient using "optimistic zk-rollup" approach where the PLONK/Groth16 proofs are not always verified on-chain but the challengers could post proof-of-invalidity for some posted proofs. I recall someone has proposed the idea, but I cannot find it now. The issue is however, that the proof can fail in several places, so we would need to account for that. And for example when the proof verification fails early, then we need to swap the rest of proof checking to work on dummy variables so that we would have a solvable witness to be able to complete the circuit. I haven't checked the proposed change in detail, but just keep in mind. Another idea - you can provide the expected verification result (succcess/failure) as an argument, as it should be part of the witness anyway imo. And then inside the assertion method you use a hint to deduce what is the actual failure reason, and then implement the corresponding cases. We have done something very similar in |
In the example you have, in cases: _, err := something()
if err != nil {
valid = v.api.Mul(valid, 0)
} you don't have to add the assertions - such errors are circuit compile time errors (a la input length mismatch etc.), not solving time errors. So it is safe to do instead
|
Right! Well, that was only a very quick&dirty example to provide better understanding of the proposal. I do believe the big challenge is what you mention of |
And one more thing - essentially when doing a |
Pinging @yelhousni to loop in. |
So, I definitely recommend posting as a PR and then we could start working from that. And for simplicity I think Groth16 at first and later can figure out PLONK. |
In general, not having direct Assertions within the Gnark standard library would improve control-flow on the final circuit design. I.e, Circom uses this approach, and they do have control-flow with if/else statements and so on, which is quite useful. Of course, this is a big change to the design of the framework, so it's maybe something that can be worked slowly with time. Related #81 |
Indeed, it would be a big change. Our problem is that gnark is essentially Go API, but for such control flow changes we would have to have a DSL or do source code processing from AST etc. |
I'm not sure if I can do that. I can work at the Circuit API level, but modifying the Pairing Check requires some understanding that I might not have. Furthermore, I'm a bit lost on what part of the Gnark code is built with a Generator and which is manually coded, tbh. Are the algebra/pairing functions autogenerated somehow? Where is the source? |
I think for the in-circuit implementation we don't use autogenerated code. The interfaces and implementations are defined in https://github.com/Consensys/gnark/blob/master/std/algebra/interfaces.go and https://github.com/Consensys/gnark/tree/master/std/algebra (see For out-circuit computation it is good enough to compute |
Indeed |
Is your feature request related to a problem? Please describe.
We need to recursively verify multiple SNARK proofs, where some proofs may be intentionally invalid. For example, when aggregating up to 100 proofs with only 50 valid ones, or when only one among several circuit proofs must be valid, forcing immediate assertions via api.Assert limits flexibility.
Returning a verification flag (1 for valid, 0 for invalid) in intermediate functions would grant circuit developers finer control over which proofs to enforce.
Describe the solution you'd like.
Introduce a new method (e.g. ProofIsValid) in the std/recursion packages that returns a
frontend.Variable
flag indicating whether a proof is valid. This method should accumulate a boolean flag (starting at 1 and multiplying by 0 on any failed check) rather than calling assertions directly. The existing AssertProof method can then be implemented as a wrapper that calls ProofIsValid and asserts that the flag equals 1.Describe alternatives you've considered.
No viable alternatives offer the same level of flexibility. Current approaches force immediate failure with api.Assert, which doesn’t support conditional aggregation of proofs.
Additional context.
This design aligns with practices in other DSLs (such as Circom) and enables the circuit developer to decide later whether to trigger an assertion. It provides a more composable and modular approach in my opinion.
A non-working example implementation of the new Verifier.ProofIsValid() might look like this. This code does not work because the Pairing functions do only support Asserts, we would need to add other methods to receive the true/false flag.
The text was updated successfully, but these errors were encountered: