Giter Site home page Giter Site logo

Comments (2)

weijiguo avatar weijiguo commented on August 20, 2024

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.

ivokub avatar ivokub commented on August 20, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.