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