Comments (2)
The lines that panic was trying to compile the outer circuit:
ccs, err := frontend.Compile(ecc.BN254.ScalarField(), scs.NewBuilder, &outer)
if err != nil {
panic(err)
}
Which was trying to recursively create another witness for inner circuit verification within the Define() function of the outer circuit:
// recursively create the witness
witness, err := frontend.NewWitness(&w, ecc.BN254.ScalarField())
if err != nil {
panic(err)
}
from gnark.
Have a look at the full written PLONK recursion example: https://pkg.go.dev/github.com/consensys/[email protected]/std/recursion/plonk#example-package-Emulated
For the inner circuit witness assignment, we need to use recursive_plonk.Witness
(as you have in your example). However, we cannot call recursive_plonk.ValueOfWitness
in circuit as it expects as an input actual values (not variables what the outer circuit has).
Rather, you should use recursive_plonk.Witness
as a witness to the outer circuit and then assign it when creating outer circuit witness assignment. Full example:
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 recursive_plonk.WithCompleteArithmetic()
option. There were also a few other bugs, see diff vs your version.
from gnark.
Related Issues (20)
- bug: Go 1.22 alternates naming of anonymous functions HOT 5
- bug: Groth16Commitments is empty after trusted setup HOT 5
- feat: add solver option to define number of used parallel processes
- Convert int to frontend.Variable or vice versa HOT 2
- feat: MarshalSolidity() for groth16 proofs HOT 2
- bug: Decompressor fails with `level = GoodSnarkDecompression`
- in BLS12377/BW6761 recursive circuit, 1 more public variable in inner circuit will cause extra 2678 constrains in outer circuit, is it reasonable? HOT 1
- how to register a new hint HOT 1
- Generating witness from simple eddsa circuit give error "can't set fr.Element from type expr.LinearExpression". HOT 1
- EFS cleanup update
- refactor: Groth16 Solidity verifier improvements
- perf: merging Groth16 commitment PoK verification pairing check / supporting multiple Groth16 commitments
- perf: implement BGM17 modification for Groth16 verification key
- perf: allow providing coefficients for folding KZG proofs
- How to implement logical statements HOT 2
- How to implement a circuit with slices HOT 2
- feat: implement SAFE API for hash functions
- Question: How to verify if a public witness is associated with certain public inputs? HOT 10
- bug: Proving Failed if builder.config.CompressThreshold is modified HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gnark.