arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/cli/main.go
cli/main.goRaw
  1package main
  2
  3import (
  4	"bufio"
  5	"bytes"
  6	"encoding/json"
  7	"errors"
  8	"fmt"
  9	"io/ioutil"
 10	"log"
 11	"math/big"
 12	"os"
 13
 14	snark "github.com/arnaucube/go-snark"
 15	"github.com/arnaucube/go-snark/circuitcompiler"
 16	"github.com/arnaucube/go-snark/groth16"
 17	"github.com/arnaucube/go-snark/r1csqap"
 18	"github.com/arnaucube/go-snark/utils"
 19	"github.com/urfave/cli"
 20)
 21
 22func panicErr(err error) {
 23	if err != nil {
 24		panic(err)
 25	}
 26}
 27
 28var commands = []cli.Command{
 29	{
 30		Name:    "compile",
 31		Aliases: []string{},
 32		Usage:   "compile a circuit",
 33		Action:  CompileCircuit,
 34	},
 35	{
 36		Name:    "trustedsetup",
 37		Aliases: []string{},
 38		Usage:   "generate trusted setup for a circuit",
 39		Action:  TrustedSetup,
 40	},
 41	{
 42		Name:    "genproofs",
 43		Aliases: []string{},
 44		Usage:   "generate the snark proofs",
 45		Action:  GenerateProofs,
 46	},
 47	{
 48		Name:    "verify",
 49		Aliases: []string{},
 50		Usage:   "verify the snark proofs",
 51		Action:  VerifyProofs,
 52	},
 53	{
 54		Name:    "groth16",
 55		Aliases: []string{},
 56		Usage:   "use groth16 protocol",
 57		Subcommands: []cli.Command{
 58			{
 59				Name:    "trustedsetup",
 60				Aliases: []string{},
 61				Usage:   "generate trusted setup for a circuit",
 62				Action:  Groth16TrustedSetup,
 63			},
 64			{
 65				Name:    "genproofs",
 66				Aliases: []string{},
 67				Usage:   "generate the snark proofs",
 68				Action:  Groth16GenerateProofs,
 69			},
 70			{
 71				Name:    "verify",
 72				Aliases: []string{},
 73				Usage:   "verify the snark proofs",
 74				Action:  Groth16VerifyProofs,
 75			},
 76		},
 77	},
 78}
 79
 80func main() {
 81	app := cli.NewApp()
 82	app.Name = "go-snarks-cli"
 83	app.Version = "0.0.3-alpha"
 84	app.Flags = []cli.Flag{
 85		cli.StringFlag{Name: "config"},
 86	}
 87	app.Commands = commands
 88
 89	err := app.Run(os.Args)
 90	if err != nil {
 91		log.Fatal(err)
 92	}
 93}
 94
 95func CompileCircuit(context *cli.Context) error {
 96	fmt.Println("cli")
 97
 98	circuitPath := context.Args().Get(0)
 99
100	wasmFlag := false
101	if context.Args().Get(1) == "wasm" {
102		wasmFlag = true
103	}
104
105	// read circuit file
106	circuitFile, err := os.Open(circuitPath)
107	panicErr(err)
108
109	// parse circuit code
110	parser := circuitcompiler.NewParser(bufio.NewReader(circuitFile))
111	circuit, err := parser.Parse()
112	panicErr(err)
113	fmt.Println("\ncircuit data:", circuit)
114
115	// read privateInputs file
116	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
117	panicErr(err)
118	// read publicInputs file
119	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
120	panicErr(err)
121
122	// parse inputs from inputsFile
123	var inputs circuitcompiler.Inputs
124	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
125	panicErr(err)
126	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
127	panicErr(err)
128
129	// calculate wittness
130	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
131	panicErr(err)
132	fmt.Println("\nwitness", w)
133
134	// flat code to R1CS
135	fmt.Println("\ngenerating R1CS from flat code")
136	a, b, c := circuit.GenerateR1CS()
137	fmt.Println("\nR1CS:")
138	fmt.Println("a:", a)
139	fmt.Println("b:", b)
140	fmt.Println("c:", c)
141
142	// R1CS to QAP
143	alphas, betas, gammas, zx := snark.Utils.PF.R1CSToQAP(a, b, c)
144	fmt.Println("qap")
145	fmt.Println(alphas)
146	fmt.Println(betas)
147	fmt.Println(gammas)
148
149	ax, bx, cx, px := snark.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
150
151	hx := snark.Utils.PF.DivisorPolynomial(px, zx)
152
153	// hx==px/zx so px==hx*zx
154	// assert.Equal(t, px, snark.Utils.PF.Mul(hx, zx))
155	if !r1csqap.BigArraysEqual(px, snark.Utils.PF.Mul(hx, zx)) {
156		panic(errors.New("px != hx*zx"))
157	}
158
159	// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
160	abc := snark.Utils.PF.Sub(snark.Utils.PF.Mul(ax, bx), cx)
161	// assert.Equal(t, abc, px)
162	if !r1csqap.BigArraysEqual(abc, px) {
163		panic(errors.New("abc != px"))
164	}
165	hz := snark.Utils.PF.Mul(hx, zx)
166	if !r1csqap.BigArraysEqual(abc, hz) {
167		panic(errors.New("abc != hz"))
168	}
169	// assert.Equal(t, abc, hz)
170
171	div, rem := snark.Utils.PF.Div(px, zx)
172	if !r1csqap.BigArraysEqual(hx, div) {
173		panic(errors.New("hx != div"))
174	}
175	// assert.Equal(t, hx, div)
176	// assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
177	for _, r := range rem {
178		if !bytes.Equal(r.Bytes(), big.NewInt(int64(0)).Bytes()) {
179			panic(errors.New("error:error:  px/zx rem not equal to zeros"))
180		}
181	}
182
183	// store circuit to json
184	jsonData, err := json.Marshal(circuit)
185	panicErr(err)
186	// store setup into file
187	jsonFile, err := os.Create("compiledcircuit.json")
188	panicErr(err)
189	defer jsonFile.Close()
190	jsonFile.Write(jsonData)
191	jsonFile.Close()
192	fmt.Println("Compiled Circuit data written to ", jsonFile.Name())
193
194	if wasmFlag {
195		circuitString := utils.CircuitToString(*circuit)
196		jsonData, err := json.Marshal(circuitString)
197		panicErr(err)
198		// store setup into file
199		jsonFile, err := os.Create("compiledcircuitString.json")
200		panicErr(err)
201		defer jsonFile.Close()
202		jsonFile.Write(jsonData)
203		jsonFile.Close()
204	}
205
206	// store px
207	jsonData, err = json.Marshal(px)
208	panicErr(err)
209	// store setup into file
210	jsonFile, err = os.Create("px.json")
211	panicErr(err)
212	defer jsonFile.Close()
213	jsonFile.Write(jsonData)
214	jsonFile.Close()
215	fmt.Println("Px data written to ", jsonFile.Name())
216	if wasmFlag {
217		pxString := utils.ArrayBigIntToString(px)
218		jsonData, err = json.Marshal(pxString)
219		panicErr(err)
220		// store setup into file
221		jsonFile, err = os.Create("pxString.json")
222		panicErr(err)
223		defer jsonFile.Close()
224		jsonFile.Write(jsonData)
225		jsonFile.Close()
226	}
227
228	return nil
229}
230
231func TrustedSetup(context *cli.Context) error {
232	wasmFlag := false
233	if context.Args().Get(0) == "wasm" {
234		wasmFlag = true
235	}
236	// open compiledcircuit.json
237	compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
238	panicErr(err)
239	var circuit circuitcompiler.Circuit
240	json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
241	panicErr(err)
242
243	// read privateInputs file
244	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
245	panicErr(err)
246	// read publicInputs file
247	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
248	panicErr(err)
249
250	// parse inputs from inputsFile
251	var inputs circuitcompiler.Inputs
252	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
253	panicErr(err)
254	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
255	panicErr(err)
256
257	// calculate wittness
258	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
259	panicErr(err)
260
261	// R1CS to QAP
262	alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(circuit.R1CS.A, circuit.R1CS.B, circuit.R1CS.C)
263	fmt.Println("qap")
264	fmt.Println(alphas)
265	fmt.Println(betas)
266	fmt.Println(gammas)
267
268	// calculate trusted setup
269	setup, err := snark.GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas)
270	panicErr(err)
271	fmt.Println("\nt:", setup.Toxic.T)
272
273	// remove setup.Toxic
274	var tsetup snark.Setup
275	tsetup.Pk = setup.Pk
276	tsetup.Vk = setup.Vk
277	tsetup.Pk.G1T = setup.Pk.G1T
278
279	// store setup to json
280	jsonData, err := json.Marshal(tsetup)
281	panicErr(err)
282	// store setup into file
283	jsonFile, err := os.Create("trustedsetup.json")
284	panicErr(err)
285	defer jsonFile.Close()
286	jsonFile.Write(jsonData)
287	jsonFile.Close()
288	fmt.Println("Trusted Setup data written to ", jsonFile.Name())
289	if wasmFlag {
290		tsetupString := utils.SetupToString(tsetup)
291		jsonData, err := json.Marshal(tsetupString)
292		panicErr(err)
293		// store setup into file
294		jsonFile, err := os.Create("trustedsetupString.json")
295		panicErr(err)
296		defer jsonFile.Close()
297		jsonFile.Write(jsonData)
298		jsonFile.Close()
299	}
300	return nil
301}
302
303func GenerateProofs(context *cli.Context) error {
304	// open compiledcircuit.json
305	compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
306	panicErr(err)
307	var circuit circuitcompiler.Circuit
308	json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
309	panicErr(err)
310
311	// open trustedsetup.json
312	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
313	panicErr(err)
314	var trustedsetup snark.Setup
315	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
316	panicErr(err)
317
318	// read privateInputs file
319	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
320	panicErr(err)
321	// read publicInputs file
322	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
323	panicErr(err)
324	// parse inputs from inputsFile
325	var inputs circuitcompiler.Inputs
326	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
327	panicErr(err)
328	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
329	panicErr(err)
330
331	// calculate wittness
332	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
333	panicErr(err)
334	fmt.Println("witness", w)
335
336	// flat code to R1CS
337	a := circuit.R1CS.A
338	b := circuit.R1CS.B
339	c := circuit.R1CS.C
340	// R1CS to QAP
341	alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(a, b, c)
342	_, _, _, px := snark.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
343	hx := snark.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
344
345	fmt.Println(circuit)
346	fmt.Println(trustedsetup.Pk.G1T)
347	fmt.Println(hx)
348	fmt.Println(w)
349	proof, err := snark.GenerateProofs(circuit, trustedsetup.Pk, w, px)
350	panicErr(err)
351
352	fmt.Println("\n proofs:")
353	fmt.Println(proof)
354
355	// store proofs to json
356	jsonData, err := json.Marshal(proof)
357	panicErr(err)
358	// store proof into file
359	jsonFile, err := os.Create("proofs.json")
360	panicErr(err)
361	defer jsonFile.Close()
362	jsonFile.Write(jsonData)
363	jsonFile.Close()
364	fmt.Println("Proofs data written to ", jsonFile.Name())
365	return nil
366}
367
368func VerifyProofs(context *cli.Context) error {
369	// open proofs.json
370	proofsFile, err := ioutil.ReadFile("proofs.json")
371	panicErr(err)
372	var proof snark.Proof
373	json.Unmarshal([]byte(string(proofsFile)), &proof)
374	panicErr(err)
375
376	// open trustedsetup.json
377	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
378	panicErr(err)
379	var trustedsetup snark.Setup
380	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
381	panicErr(err)
382
383	// read publicInputs file
384	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
385	panicErr(err)
386	var publicSignals []*big.Int
387	err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
388	panicErr(err)
389
390	verified := snark.VerifyProof(trustedsetup.Vk, proof, publicSignals, true)
391	if !verified {
392		fmt.Println("ERROR: proofs not verified")
393	} else {
394		fmt.Println("Proofs verified")
395	}
396	return nil
397}
398
399func Groth16TrustedSetup(context *cli.Context) error {
400	// open compiledcircuit.json
401	compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
402	panicErr(err)
403	var circuit circuitcompiler.Circuit
404	json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
405	panicErr(err)
406
407	// read privateInputs file
408	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
409	panicErr(err)
410	// read publicInputs file
411	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
412	panicErr(err)
413
414	// parse inputs from inputsFile
415	var inputs circuitcompiler.Inputs
416	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
417	panicErr(err)
418	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
419	panicErr(err)
420
421	// calculate wittness
422	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
423	panicErr(err)
424
425	// R1CS to QAP
426	alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(circuit.R1CS.A, circuit.R1CS.B, circuit.R1CS.C)
427	fmt.Println("qap")
428	fmt.Println(alphas)
429	fmt.Println(betas)
430	fmt.Println(gammas)
431
432	// calculate trusted setup
433	setup, err := groth16.GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas)
434	panicErr(err)
435	fmt.Println("\nt:", setup.Toxic.T)
436
437	// remove setup.Toxic
438	var tsetup groth16.Setup
439	tsetup.Pk = setup.Pk
440	tsetup.Vk = setup.Vk
441
442	// store setup to json
443	jsonData, err := json.Marshal(tsetup)
444	panicErr(err)
445	// store setup into file
446	jsonFile, err := os.Create("trustedsetup.json")
447	panicErr(err)
448	defer jsonFile.Close()
449	jsonFile.Write(jsonData)
450	jsonFile.Close()
451	fmt.Println("Trusted Setup data written to ", jsonFile.Name())
452	return nil
453}
454
455func Groth16GenerateProofs(context *cli.Context) error {
456	// open compiledcircuit.json
457	compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
458	panicErr(err)
459	var circuit circuitcompiler.Circuit
460	json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
461	panicErr(err)
462
463	// open trustedsetup.json
464	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
465	panicErr(err)
466	var trustedsetup groth16.Setup
467	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
468	panicErr(err)
469
470	// read privateInputs file
471	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
472	panicErr(err)
473	// read publicInputs file
474	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
475	panicErr(err)
476	// parse inputs from inputsFile
477	var inputs circuitcompiler.Inputs
478	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
479	panicErr(err)
480	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
481	panicErr(err)
482
483	// calculate wittness
484	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
485	panicErr(err)
486	fmt.Println("witness", w)
487
488	// flat code to R1CS
489	a := circuit.R1CS.A
490	b := circuit.R1CS.B
491	c := circuit.R1CS.C
492	// R1CS to QAP
493	alphas, betas, gammas, _ := groth16.Utils.PF.R1CSToQAP(a, b, c)
494	_, _, _, px := groth16.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
495	hx := groth16.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
496
497	fmt.Println(circuit)
498	fmt.Println(trustedsetup.Pk.PowersTauDelta)
499	fmt.Println(hx)
500	fmt.Println(w)
501	proof, err := groth16.GenerateProofs(circuit, trustedsetup.Pk, w, px)
502	panicErr(err)
503
504	fmt.Println("\n proofs:")
505	fmt.Println(proof)
506
507	// store proofs to json
508	jsonData, err := json.Marshal(proof)
509	panicErr(err)
510	// store proof into file
511	jsonFile, err := os.Create("proofs.json")
512	panicErr(err)
513	defer jsonFile.Close()
514	jsonFile.Write(jsonData)
515	jsonFile.Close()
516	fmt.Println("Proofs data written to ", jsonFile.Name())
517	return nil
518}
519
520func Groth16VerifyProofs(context *cli.Context) error {
521	// open proofs.json
522	proofsFile, err := ioutil.ReadFile("proofs.json")
523	panicErr(err)
524	var proof groth16.Proof
525	json.Unmarshal([]byte(string(proofsFile)), &proof)
526	panicErr(err)
527
528	// open trustedsetup.json
529	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
530	panicErr(err)
531	var trustedsetup groth16.Setup
532	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
533	panicErr(err)
534
535	// read publicInputs file
536	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
537	panicErr(err)
538	var publicSignals []*big.Int
539	err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
540	panicErr(err)
541
542	verified := groth16.VerifyProof(trustedsetup.Vk, proof, publicSignals, true)
543	if !verified {
544		fmt.Println("ERROR: proofs not verified")
545	} else {
546		fmt.Println("Proofs verified")
547	}
548	return nil
549}