gnark-plonky2-verifier/benchmark.go
benchmark.goRaw
1package main
2
3import (
4 "bytes"
5 "flag"
6 "fmt"
7 "math/big"
8 "os"
9 "time"
10
11 gl "github.com/succinctlabs/gnark-plonky2-verifier/goldilocks"
12 "github.com/succinctlabs/gnark-plonky2-verifier/variables"
13 "github.com/succinctlabs/gnark-plonky2-verifier/verifier"
14
15 "github.com/consensys/gnark-crypto/ecc"
16 "github.com/consensys/gnark/backend/groth16"
17 "github.com/consensys/gnark/constraint"
18 "github.com/consensys/gnark/frontend"
19 "github.com/consensys/gnark/frontend/cs/r1cs"
20 "github.com/consensys/gnark/profile"
21)
22
23type BenchmarkPlonky2VerifierCircuit struct {
24 Proof variables.Proof
25 PublicInputs []gl.Variable `gnark:",public"`
26
27 verifierChip *verifier.VerifierChip `gnark:"-"`
28 plonky2CircuitName string `gnark:"-"`
29}
30
31func (circuit *BenchmarkPlonky2VerifierCircuit) Define(api frontend.API) error {
32 circuitDirname := "./verifier/data/" + circuit.plonky2CircuitName + "/"
33 commonCircuitData := verifier.DeserializeCommonCircuitData(circuitDirname + "common_circuit_data.json")
34 verifierOnlyCircuitData := verifier.DeserializeVerifierOnlyCircuitData(circuitDirname + "verifier_only_circuit_data.json")
35
36 circuit.verifierChip = verifier.NewVerifierChip(api, commonCircuitData)
37
38 circuit.verifierChip.Verify(circuit.Proof, circuit.PublicInputs, verifierOnlyCircuitData, commonCircuitData)
39
40 return nil
41}
42
43func compileCircuit(plonky2Circuit string, profileCircuit bool, serialize bool, outputSolidity bool, dummy bool) (constraint.ConstraintSystem, groth16.ProvingKey, groth16.VerifyingKey) {
44 circuit := BenchmarkPlonky2VerifierCircuit{
45 plonky2CircuitName: plonky2Circuit,
46 }
47 proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
48 circuit.Proof = proofWithPis.Proof
49 circuit.PublicInputs = proofWithPis.PublicInputs
50
51 var p *profile.Profile
52 if profileCircuit {
53 p = profile.Start()
54 }
55 r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), r1cs.NewBuilder, &circuit)
56 if err != nil {
57 fmt.Println("error in building circuit", err)
58 os.Exit(1)
59 }
60
61 if profileCircuit {
62 p.Stop()
63 p.Top()
64 println("r1cs.GetNbCoefficients(): ", r1cs.GetNbCoefficients())
65 println("r1cs.GetNbConstraints(): ", r1cs.GetNbConstraints())
66 println("r1cs.GetNbSecretVariables(): ", r1cs.GetNbSecretVariables())
67 println("r1cs.GetNbPublicVariables(): ", r1cs.GetNbPublicVariables())
68 println("r1cs.GetNbInternalVariables(): ", r1cs.GetNbInternalVariables())
69 }
70
71 // Don't serialize the circuit for now, since it takes up too much memory
72 /*
73 if serialize {
74 fR1CS, _ := os.Create("circuit")
75 r1cs.WriteTo(fR1CS)
76 fR1CS.Close()
77 }
78 */
79 var pk groth16.ProvingKey
80 var vk groth16.VerifyingKey
81
82 fmt.Println("Running circuit setup", time.Now())
83 if dummy {
84 fmt.Println("Using dummy setup")
85 pk, err = groth16.DummySetup(r1cs)
86 } else {
87 fmt.Println("Using real setup")
88 pk, vk, err = groth16.Setup(r1cs)
89 }
90 if err != nil {
91 fmt.Println(err)
92 os.Exit(1)
93 }
94
95 if serialize {
96 fPK, _ := os.Create("proving.key")
97 pk.WriteTo(fPK)
98 fPK.Close()
99
100 fVK, _ := os.Create("verifying.key")
101 vk.WriteTo(fVK)
102 fVK.Close()
103 }
104
105 if outputSolidity {
106 fSolidity, _ := os.Create("proof.sol")
107 err = vk.ExportSolidity(fSolidity)
108 }
109
110 return r1cs, pk, vk
111}
112
113func createProof(plonky2Circuit string, r1cs constraint.ConstraintSystem, pk groth16.ProvingKey, vk groth16.VerifyingKey, serialize bool) groth16.Proof {
114 proofWithPis := verifier.DeserializeProofWithPublicInputs("./verifier/data/" + plonky2Circuit + "/proof_with_public_inputs.json")
115
116 // Witness
117 assignment := &BenchmarkPlonky2VerifierCircuit{
118 Proof: proofWithPis.Proof,
119 PublicInputs: proofWithPis.PublicInputs,
120 }
121
122 fmt.Println("Generating witness", time.Now())
123 witness, _ := frontend.NewWitness(assignment, ecc.BN254.ScalarField())
124 publicWitness, _ := witness.Public()
125 if serialize {
126 fWitness, _ := os.Create("witness")
127 witness.WriteTo(fWitness)
128 fWitness.Close()
129 }
130
131 fmt.Println("Creating proof", time.Now())
132 proof, err := groth16.Prove(r1cs, pk, witness)
133 if err != nil {
134 fmt.Println(err)
135 os.Exit(1)
136 }
137 if serialize {
138 fProof, _ := os.Create("proof.proof")
139 proof.WriteTo(fProof)
140 fProof.Close()
141 }
142
143 if vk == nil {
144 fmt.Println("vk is nil, means you're using dummy setup and we skip verification step")
145 return proof
146 }
147
148 fmt.Println("Verifying proof", time.Now())
149 err = groth16.Verify(proof, vk, publicWitness)
150 if err != nil {
151 fmt.Println(err)
152 os.Exit(1)
153 }
154
155 const fpSize = 4 * 8
156 var buf bytes.Buffer
157 proof.WriteRawTo(&buf)
158 proofBytes := buf.Bytes()
159
160 var (
161 a [2]*big.Int
162 b [2][2]*big.Int
163 c [2]*big.Int
164 )
165
166 // proof.Ar, proof.Bs, proof.Krs
167 a[0] = new(big.Int).SetBytes(proofBytes[fpSize*0 : fpSize*1])
168 a[1] = new(big.Int).SetBytes(proofBytes[fpSize*1 : fpSize*2])
169 b[0][0] = new(big.Int).SetBytes(proofBytes[fpSize*2 : fpSize*3])
170 b[0][1] = new(big.Int).SetBytes(proofBytes[fpSize*3 : fpSize*4])
171 b[1][0] = new(big.Int).SetBytes(proofBytes[fpSize*4 : fpSize*5])
172 b[1][1] = new(big.Int).SetBytes(proofBytes[fpSize*5 : fpSize*6])
173 c[0] = new(big.Int).SetBytes(proofBytes[fpSize*6 : fpSize*7])
174 c[1] = new(big.Int).SetBytes(proofBytes[fpSize*7 : fpSize*8])
175
176 println("a[0] is ", a[0].String())
177 println("a[1] is ", a[1].String())
178
179 println("b[0][0] is ", b[0][0].String())
180 println("b[0][1] is ", b[0][1].String())
181 println("b[1][0] is ", b[1][0].String())
182 println("b[1][1] is ", b[1][1].String())
183
184 println("c[0] is ", c[0].String())
185 println("c[1] is ", c[1].String())
186
187 return proof
188}
189
190func main() {
191 plonky2Circuit := flag.String("plonky2-circuit", "", "plonky2 circuit to benchmark")
192 profileCircuit := flag.Bool("profile", false, "profile the circuit")
193 serialize := flag.Bool("serialize", false, "serialize the circuit")
194 outputSolidity := flag.Bool("solidity", false, "output solidity code for the circuit")
195
196 flag.Parse()
197
198 if plonky2Circuit == nil || *plonky2Circuit == "" {
199 fmt.Println("Please provide a plonky2 circuit to benchmark")
200 os.Exit(1)
201 }
202
203 r1cs, pk, vk := compileCircuit(*plonky2Circuit, *profileCircuit, *serialize, *outputSolidity, true)
204 createProof(*plonky2Circuit, r1cs, pk, vk, *serialize)
205}