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 "github.com/succinctlabs/gnark-plonky2-verifier/types"
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/backend/plonk"
18 "github.com/consensys/gnark/constraint"
19 "github.com/consensys/gnark/frontend"
20 "github.com/consensys/gnark/frontend/cs/r1cs"
21 "github.com/consensys/gnark/frontend/cs/scs"
22 "github.com/consensys/gnark/profile"
23 "github.com/consensys/gnark/test"
24)
25
26func runBenchmark(plonky2Circuit string, proofSystem string, profileCircuit bool, dummy bool, saveArtifacts bool) {
27 commonCircuitData := types.DeserializeCommonCircuitData("testdata/" + plonky2Circuit + "/common_circuit_data.json")
28
29 proofWithPis := variables.DeserializeProofWithPublicInputs(types.ReadProofWithPublicInputs("testdata/" + plonky2Circuit + "/proof_with_public_inputs.json"))
30 verifierOnlyCircuitData := variables.DeserializeVerifierOnlyCircuitData(types.ReadVerifierOnlyCircuitData("testdata/" + plonky2Circuit + "/verifier_only_circuit_data.json"))
31
32 circuit := verifier.ExampleVerifierCircuit{
33 Proof: proofWithPis.Proof,
34 PublicInputs: proofWithPis.PublicInputs,
35 VerifierOnlyCircuitData: verifierOnlyCircuitData,
36 CommonCircuitData: commonCircuitData,
37 }
38
39 var p *profile.Profile
40 if profileCircuit {
41 p = profile.Start()
42 }
43
44 var builder frontend.NewBuilder
45 if proofSystem == "plonk" {
46 builder = scs.NewBuilder
47 } else if proofSystem == "groth16" {
48 builder = r1cs.NewBuilder
49 } else {
50 fmt.Println("Please provide a valid proof system to benchmark, we only support plonk and groth16")
51 os.Exit(1)
52 }
53
54 r1cs, err := frontend.Compile(ecc.BN254.ScalarField(), builder, &circuit)
55 if err != nil {
56 fmt.Println("error in building circuit", err)
57 os.Exit(1)
58 }
59
60 if profileCircuit {
61 p.Stop()
62 p.Top()
63 println("r1cs.GetNbCoefficients(): ", r1cs.GetNbCoefficients())
64 println("r1cs.GetNbConstraints(): ", r1cs.GetNbConstraints())
65 println("r1cs.GetNbSecretVariables(): ", r1cs.GetNbSecretVariables())
66 println("r1cs.GetNbPublicVariables(): ", r1cs.GetNbPublicVariables())
67 println("r1cs.GetNbInternalVariables(): ", r1cs.GetNbInternalVariables())
68 }
69
70 witness := verifier.ExampleVerifierCircuit{
71 Proof: proofWithPis.Proof,
72 PublicInputs: proofWithPis.PublicInputs,
73 VerifierOnlyCircuitData: verifierOnlyCircuitData,
74 CommonCircuitData: commonCircuitData,
75 }
76
77 if proofSystem == "plonk" {
78 plonkProof(r1cs, witness, dummy, saveArtifacts)
79 } else if proofSystem == "groth16" {
80 groth16Proof(r1cs, witness, dummy, saveArtifacts)
81 } else {
82 panic("Please provide a valid proof system to benchmark, we only support plonk and groth16")
83 }
84}
85
86func plonkProof(r1cs constraint.ConstraintSystem, assignment verifier.ExampleVerifierCircuit, dummy bool, saveArtifacts bool) {
87 var pk plonk.ProvingKey
88 var vk plonk.VerifyingKey
89 var err error
90
91 // Don't serialize the circuit for now, since it takes up too much memory
92 // if saveArtifacts {
93 // fR1CS, _ := os.Create("circuit")
94 // r1cs.WriteTo(fR1CS)
95 // fR1CS.Close()
96 // }
97
98 fmt.Println("Running circuit setup", time.Now())
99 if dummy {
100 panic("dummy setup not supported for plonk")
101 } else {
102 fmt.Println("Using real setup")
103 srs, err := test.NewKZGSRS(r1cs)
104 if err != nil {
105 panic(err)
106 }
107 pk, vk, err = plonk.Setup(r1cs, srs)
108 }
109 if err != nil {
110 fmt.Println(err)
111 os.Exit(1)
112 }
113
114 if saveArtifacts {
115 fPK, _ := os.Create("proving.key")
116 pk.WriteTo(fPK)
117 fPK.Close()
118
119 if vk != nil {
120 fVK, _ := os.Create("verifying.key")
121 vk.WriteTo(fVK)
122 fVK.Close()
123 }
124
125 fSolidity, _ := os.Create("proof.sol")
126 err = vk.ExportSolidity(fSolidity)
127 }
128
129 fmt.Println("Generating witness", time.Now())
130 witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
131 publicWitness, _ := witness.Public()
132 if saveArtifacts {
133 fWitness, _ := os.Create("witness")
134 witness.WriteTo(fWitness)
135 fWitness.Close()
136 }
137
138 fmt.Println("Creating proof", time.Now())
139 proof, err := plonk.Prove(r1cs, pk, witness)
140 if err != nil {
141 fmt.Println(err)
142 os.Exit(1)
143 }
144 if saveArtifacts {
145 fProof, _ := os.Create("proof.proof")
146 proof.WriteTo(fProof)
147 fProof.Close()
148 }
149
150 if vk == nil {
151 fmt.Println("vk is nil, means you're using dummy setup and we skip verification of proof")
152 return
153 }
154
155 fmt.Println("Verifying proof", time.Now())
156 err = plonk.Verify(proof, vk, publicWitness)
157 if err != nil {
158 fmt.Println(err)
159 os.Exit(1)
160 }
161
162 const fpSize = 4 * 8
163 var buf bytes.Buffer
164 proof.WriteRawTo(&buf)
165 proofBytes := buf.Bytes()
166 fmt.Printf("proofBytes: %v\n", proofBytes)
167}
168
169func groth16Proof(r1cs constraint.ConstraintSystem, assignment verifier.ExampleVerifierCircuit, dummy bool, saveArtifacts bool) {
170 var pk groth16.ProvingKey
171 var vk groth16.VerifyingKey
172 var err error
173
174 // Don't serialize the circuit for now, since it takes up too much memory
175 // if saveArtifacts {
176 // fR1CS, _ := os.Create("circuit")
177 // r1cs.WriteTo(fR1CS)
178 // fR1CS.Close()
179 // }
180
181 fmt.Println("Running circuit setup", time.Now())
182 if dummy {
183 fmt.Println("Using dummy setup")
184 pk, err = groth16.DummySetup(r1cs)
185 } else {
186 fmt.Println("Using real setup")
187 pk, vk, err = groth16.Setup(r1cs)
188 }
189 if err != nil {
190 fmt.Println(err)
191 os.Exit(1)
192 }
193
194 if saveArtifacts {
195 fPK, _ := os.Create("proving.key")
196 pk.WriteTo(fPK)
197 fPK.Close()
198
199 if vk != nil {
200 fVK, _ := os.Create("verifying.key")
201 vk.WriteTo(fVK)
202 fVK.Close()
203 }
204
205 fSolidity, _ := os.Create("proof.sol")
206 err = vk.ExportSolidity(fSolidity)
207 }
208
209 fmt.Println("Generating witness", time.Now())
210 witness, _ := frontend.NewWitness(&assignment, ecc.BN254.ScalarField())
211 publicWitness, _ := witness.Public()
212 if saveArtifacts {
213 fWitness, _ := os.Create("witness")
214 witness.WriteTo(fWitness)
215 fWitness.Close()
216 }
217
218 fmt.Println("Creating proof", time.Now())
219 proof, err := groth16.Prove(r1cs, pk, witness)
220 if err != nil {
221 fmt.Println(err)
222 os.Exit(1)
223 }
224 if saveArtifacts {
225 fProof, _ := os.Create("proof.proof")
226 proof.WriteTo(fProof)
227 fProof.Close()
228 }
229
230 if vk == nil {
231 fmt.Println("vk is nil, means you're using dummy setup and we skip verification of proof")
232 return
233 }
234
235 fmt.Println("Verifying proof", time.Now())
236 err = groth16.Verify(proof, vk, publicWitness)
237 if err != nil {
238 fmt.Println(err)
239 os.Exit(1)
240 }
241
242 const fpSize = 4 * 8
243 var buf bytes.Buffer
244 proof.WriteRawTo(&buf)
245 proofBytes := buf.Bytes()
246
247 var (
248 a [2]*big.Int
249 b [2][2]*big.Int
250 c [2]*big.Int
251 )
252
253 // proof.Ar, proof.Bs, proof.Krs
254 a[0] = new(big.Int).SetBytes(proofBytes[fpSize*0 : fpSize*1])
255 a[1] = new(big.Int).SetBytes(proofBytes[fpSize*1 : fpSize*2])
256 b[0][0] = new(big.Int).SetBytes(proofBytes[fpSize*2 : fpSize*3])
257 b[0][1] = new(big.Int).SetBytes(proofBytes[fpSize*3 : fpSize*4])
258 b[1][0] = new(big.Int).SetBytes(proofBytes[fpSize*4 : fpSize*5])
259 b[1][1] = new(big.Int).SetBytes(proofBytes[fpSize*5 : fpSize*6])
260 c[0] = new(big.Int).SetBytes(proofBytes[fpSize*6 : fpSize*7])
261 c[1] = new(big.Int).SetBytes(proofBytes[fpSize*7 : fpSize*8])
262
263 println("a[0] is ", a[0].String())
264 println("a[1] is ", a[1].String())
265
266 println("b[0][0] is ", b[0][0].String())
267 println("b[0][1] is ", b[0][1].String())
268 println("b[1][0] is ", b[1][0].String())
269 println("b[1][1] is ", b[1][1].String())
270
271 println("c[0] is ", c[0].String())
272 println("c[1] is ", c[1].String())
273
274}
275
276func main() {
277 plonky2Circuit := flag.String("plonky2-circuit", "", "plonky2 circuit to benchmark")
278 proofSystem := flag.String("proof-system", "groth16", "proof system to benchmark")
279 profileCircuit := flag.Bool("profile", true, "profile the circuit")
280 dummySetup := flag.Bool("dummy", true, "use dummy setup")
281 saveArtifacts := flag.Bool("save", false, "save circuit artifacts")
282
283 flag.Parse()
284
285 if plonky2Circuit == nil || *plonky2Circuit == "" {
286 fmt.Println("Please provide a plonky2 circuit to benchmark")
287 os.Exit(1)
288 }
289
290 if *proofSystem == "plonk" {
291 *dummySetup = false
292 }
293
294 fmt.Printf("Running benchmark for %s circuit with proof system %s\n", *plonky2Circuit, *proofSystem)
295 fmt.Printf("Profiling: %t, DummySetup: %t, SaveArtifacts: %t\n", *profileCircuit, *dummySetup, *saveArtifacts)
296
297 runBenchmark(*plonky2Circuit, *proofSystem, *profileCircuit, *dummySetup, *saveArtifacts)
298}