Skip to main content

Example

Consider the following gnark circuit as an example:

package main

import (
"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/backend/groth16"
"github.com/consensys/gnark/frontend"
"github.com/consensys/gnark/frontend/cs/r1cs"
)

type Circuit struct {
X frontend.Variable
Y frontend.Variable
}

func (circuit *Circuit) Define(api frontend.API) error {
api.AssertIsEqual(circuit.X, circuit.Y)
return nil
}

func main() {
assignment := &Circuit{X: 1, Y: 1}

r1cs, _ := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &Circuit{})
witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
publicWitness, _ := witness.Public()
pk, vk, _ := groth16.Setup(r1cs)
proof, _ := groth16.Prove(r1cs, pk, witness)
err := groth16.Verify(proof, vk, publicWitness)
if err != nil {
panic(err)
}
}

To adapt this circuit for our compiler, we only need to modify the compilation and execution sections within the main function. Here's how:

package main

import (
"os"

"github.com/consensys/gnark-crypto/ecc"
"github.com/consensys/gnark/frontend"

"github.com/PolyhedraZK/ExpanderCompilerCollection/ecgo"
"github.com/PolyhedraZK/ExpanderCompilerCollection/ecgo/test"
)

type Circuit struct {
X frontend.Variable
Y frontend.Variable
}

func (circuit *Circuit) Define(api frontend.API) error {
api.AssertIsEqual(circuit.X, circuit.Y)
return nil
}

func main() {
assignment := &Circuit{X: 1, Y: 1}

circuit, _ := ecgo.Compile(ecc.BN254.ScalarField(), &Circuit{})
c := circuit.GetLayeredCircuit()
os.WriteFile("circuit.txt", c.Serialize(), 0o644)
inputSolver := circuit.GetInputSolver()
witness, _ := inputSolver.SolveInputAuto(assignment)
os.WriteFile("witness.txt", witness.Serialize(), 0o644)
if !test.CheckCircuit(c, witness) {
panic("verification failed")
}
}

Please note that the Prover's implementation resides in Expander. As such, the CheckCircuit function in this context merely evaluates the circuit once to confirm its correctness. To generate and verify the actual proof, supply circuit.txt and witness.txt to Expander.

In contrast to gnark, where the prover handles a portion of the witness generation, our compiler employs an InputSolver to perform this task. The InputSolver also supports serialization and deserialization. For more information, please consult the examples in MIMC and MIMC Deserialize.

For additional features, please refer to APIs.

For more examples, please visit examples.