Replies: 3 comments
-
The lines that panic was trying to compile the outer circuit:
Which was trying to recursively create another witness for inner circuit verification within the Define() function of the outer circuit:
|
Beta Was this translation helpful? Give feedback.
-
Have a look at the full written PLONK recursion example: https://pkg.go.dev/github.com/consensys/gnark@v0.9.2-0.20240311003704-732620b476b9/std/recursion/plonk#example-package-Emulated For the inner circuit witness assignment, we need to use Rather, you should use package main
import (
"fmt"
"testing"
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/plonk"
cs "github.com/consensys/gnark/constraint/bn254"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/scs"
"github.com/consensys/gnark/std/algebra/emulated/sw_bn254"
recursive_plonk "github.com/consensys/gnark/std/recursion/plonk"
"github.com/consensys/gnark/test/unsafekzg"
)
type innerCircuit struct {
X frontend.Variable
Y frontend.Variable `gnark:",public"`
}
func (c *innerCircuit) Define(api frontend.API) error {
api.AssertIsEqual(c.X, c.Y)
return nil
}
type outerCircuit struct {
VKey recursive_plonk.VerifyingKey[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine]
Proof recursive_plonk.Proof[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine]
InnerWitness recursive_plonk.Witness[sw_bn254.ScalarField]
}
func (c *outerCircuit) Define(api frontend.API) error {
verifier, err := recursive_plonk.NewVerifier[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine, sw_bn254.GTEl](api)
if err != nil {
panic(err)
}
return verifier.AssertProof(c.VKey, c.Proof, c.InnerWitness, recursive_plonk.WithCompleteArithmetic())
}
func testBody() {
inner := innerCircuit{}
ccsInner, _ := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &inner)
scsInner := ccsInner.(*cs.SparseR1CS)
srs, srsLagrange, err := unsafekzg.NewSRS(scsInner, unsafekzg.WithFSCache())
if err != nil {
panic(err)
}
pkInner, vkInner, err := plonk.Setup(ccsInner, srs, srsLagrange)
if err != nil {
panic(err)
}
wInner := innerCircuit{X: 5, Y: 5}
witnessInner, err := frontend.NewWitness(&wInner, ecc.BN254.ScalarField())
if err != nil {
panic(err)
}
proofInner, err := plonk.Prove(ccsInner, pkInner, witnessInner,
recursive_plonk.GetNativeProverOptions(ecc.BN254.ScalarField(), ecc.BN254.ScalarField()))
if err != nil {
panic(err)
}
witnessInnerPublic, err := witnessInner.Public()
if err != nil {
panic(err)
}
err = plonk.Verify(proofInner, vkInner, witnessInnerPublic,
recursive_plonk.GetNativeVerifierOptions(ecc.BN254.ScalarField(), ecc.BN254.ScalarField()))
if err != nil {
panic(err)
}
recursiveProof, err := recursive_plonk.ValueOfProof[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine](proofInner)
if err != nil {
panic(err)
}
recursiveVK, err := recursive_plonk.ValueOfVerifyingKey[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine](vkInner)
if err != nil {
panic(err)
}
outer := outerCircuit{
VKey: recursive_plonk.PlaceholderVerifyingKey[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine](ccsInner),
Proof: recursive_plonk.PlaceholderProof[sw_bn254.ScalarField, sw_bn254.G1Affine, sw_bn254.G2Affine](ccsInner),
InnerWitness: recursive_plonk.PlaceholderWitness[sw_bn254.ScalarField](ccsInner),
}
innerWitness, err := recursive_plonk.ValueOfWitness[sw_bn254.ScalarField](witnessInnerPublic)
if err != nil {
panic(err)
}
outerW := outerCircuit{
VKey: recursiveVK,
Proof: recursiveProof,
InnerWitness: innerWitness,
}
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &outer)
if err != nil {
panic(err)
}
srs2, srsLagrange2, err := unsafekzg.NewSRS(ccs, unsafekzg.WithFSCache())
if err != nil {
panic(err)
}
pk, vk, err := plonk.Setup(ccs, srs2, srsLagrange2)
if err != nil {
panic(err)
}
fmt.Println("proving ...")
outerWitess, err := frontend.NewWitness(&outerW, ecc.BN254.ScalarField())
if err != nil {
panic(err)
}
proof, err := plonk.Prove(ccs, pk, outerWitess,
recursive_plonk.GetNativeProverOptions(ecc.BN254.ScalarField(), ecc.BN254.ScalarField()))
if err != nil {
panic(err)
}
fmt.Println("verifying ...")
pubOuterWitness, err := outerWitess.Public()
if err != nil {
panic(err)
}
err = plonk.Verify(proof, vk, pubOuterWitness,
recursive_plonk.GetNativeVerifierOptions(ecc.BN254.ScalarField(), ecc.BN254.ScalarField()))
if err != nil {
panic(err)
}
}
func TestMain(t *testing.T) {
testBody()
} NB, the inner circuit is simple and brings out some edge cases which usually do not happen (for complex inner circuits, due to randomization). This requires using |
Beta Was this translation helpful? Give feedback.
-
Thank you Ivo for your time. We had actually tried creating a witness outside but encountered another issue when constraining the witness against the public input values for the outer circuit. But it is probably some issues at our end as we cannot reproduce it with a simple case. |
Beta Was this translation helpful? Give feedback.
-
Description
During recursive verification, sometimes we need to use the witness/public input values of the outer circuit to assemble a witness to be verified by the inner circuit. However, this does not work: the outer circuit cannot compile, reporting
can't set fr.Element from type expr.Term
Codes below:
Expected Behavior
That running the test should pass the outer circuit proving and verification.
Actual Behavior
Possible Fix
Maybe some data are kept during circuit parsing?
Steps to Reproduce
Run the above codes.
Context
We are trying to create a library called chainark, which could be used to prove a chain-like structure recursively, and provides a validity proof for each element in the chain, basing its validity on its valid linking to its predecessor and all the way back to the genesis element.
In this project, we need to assemble some witness values for the inner circuit within the Define() function of the outer circuit. And we encountered the reported issue. The above codes is much simplified just to illustrated the issue.
Your Environment
HEAD@master
, plus some commits from New Feature: compute the fingerprint of a Plonk verification key for recursive verification #1062, which shall not impact the issue.HEAD@master
, plus some commits from feat: added HashToG2 circuit for BLS12-381 gnark-crypto#481, which shall not impact the issue.Beta Was this translation helpful? Give feedback.
All reactions