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