arnaucube
arnaucube/gnark-plonky2-verifierPublic Self-hosted repository
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}