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/wasm/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.G1T = setup.G1T
278	tsetup.G2T = setup.G2T
279
280	// store setup to json
281	jsonData, err := json.Marshal(tsetup)
282	panicErr(err)
283	// store setup into file
284	jsonFile, err := os.Create("trustedsetup.json")
285	panicErr(err)
286	defer jsonFile.Close()
287	jsonFile.Write(jsonData)
288	jsonFile.Close()
289	fmt.Println("Trusted Setup data written to ", jsonFile.Name())
290	if wasmFlag {
291		tsetupString := utils.SetupToString(tsetup)
292		jsonData, err := json.Marshal(tsetupString)
293		panicErr(err)
294		// store setup into file
295		jsonFile, err := os.Create("trustedsetupString.json")
296		panicErr(err)
297		defer jsonFile.Close()
298		jsonFile.Write(jsonData)
299		jsonFile.Close()
300	}
301	return nil
302}
303
304func GenerateProofs(context *cli.Context) error {
305	// open compiledcircuit.json
306	compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
307	panicErr(err)
308	var circuit circuitcompiler.Circuit
309	json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
310	panicErr(err)
311
312	// open trustedsetup.json
313	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
314	panicErr(err)
315	var trustedsetup snark.Setup
316	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
317	panicErr(err)
318
319	// read privateInputs file
320	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
321	panicErr(err)
322	// read publicInputs file
323	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
324	panicErr(err)
325	// parse inputs from inputsFile
326	var inputs circuitcompiler.Inputs
327	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
328	panicErr(err)
329	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
330	panicErr(err)
331
332	// calculate wittness
333	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
334	panicErr(err)
335	fmt.Println("witness", w)
336
337	// flat code to R1CS
338	a := circuit.R1CS.A
339	b := circuit.R1CS.B
340	c := circuit.R1CS.C
341	// R1CS to QAP
342	alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(a, b, c)
343	_, _, _, px := snark.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
344	hx := snark.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
345
346	fmt.Println(circuit)
347	fmt.Println(trustedsetup.G1T)
348	fmt.Println(hx)
349	fmt.Println(w)
350	proof, err := snark.GenerateProofs(circuit, trustedsetup, w, px)
351	panicErr(err)
352
353	fmt.Println("\n proofs:")
354	fmt.Println(proof)
355
356	// store proofs to json
357	jsonData, err := json.Marshal(proof)
358	panicErr(err)
359	// store proof into file
360	jsonFile, err := os.Create("proofs.json")
361	panicErr(err)
362	defer jsonFile.Close()
363	jsonFile.Write(jsonData)
364	jsonFile.Close()
365	fmt.Println("Proofs data written to ", jsonFile.Name())
366	return nil
367}
368
369func VerifyProofs(context *cli.Context) error {
370	// open proofs.json
371	proofsFile, err := ioutil.ReadFile("proofs.json")
372	panicErr(err)
373	var proof snark.Proof
374	json.Unmarshal([]byte(string(proofsFile)), &proof)
375	panicErr(err)
376
377	// open trustedsetup.json
378	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
379	panicErr(err)
380	var trustedsetup snark.Setup
381	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
382	panicErr(err)
383
384	// read publicInputs file
385	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
386	panicErr(err)
387	var publicSignals []*big.Int
388	err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
389	panicErr(err)
390
391	verified := snark.VerifyProof(trustedsetup, proof, publicSignals, true)
392	if !verified {
393		fmt.Println("ERROR: proofs not verified")
394	} else {
395		fmt.Println("Proofs verified")
396	}
397	return nil
398}
399
400func Groth16TrustedSetup(context *cli.Context) error {
401	// open compiledcircuit.json
402	compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
403	panicErr(err)
404	var circuit circuitcompiler.Circuit
405	json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
406	panicErr(err)
407
408	// read privateInputs file
409	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
410	panicErr(err)
411	// read publicInputs file
412	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
413	panicErr(err)
414
415	// parse inputs from inputsFile
416	var inputs circuitcompiler.Inputs
417	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
418	panicErr(err)
419	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
420	panicErr(err)
421
422	// calculate wittness
423	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
424	panicErr(err)
425
426	// R1CS to QAP
427	alphas, betas, gammas, _ := snark.Utils.PF.R1CSToQAP(circuit.R1CS.A, circuit.R1CS.B, circuit.R1CS.C)
428	fmt.Println("qap")
429	fmt.Println(alphas)
430	fmt.Println(betas)
431	fmt.Println(gammas)
432
433	// calculate trusted setup
434	setup, err := groth16.GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas)
435	panicErr(err)
436	fmt.Println("\nt:", setup.Toxic.T)
437
438	// remove setup.Toxic
439	var tsetup groth16.Setup
440	tsetup.Pk = setup.Pk
441	tsetup.Vk = setup.Vk
442
443	// store setup to json
444	jsonData, err := json.Marshal(tsetup)
445	panicErr(err)
446	// store setup into file
447	jsonFile, err := os.Create("trustedsetup.json")
448	panicErr(err)
449	defer jsonFile.Close()
450	jsonFile.Write(jsonData)
451	jsonFile.Close()
452	fmt.Println("Trusted Setup data written to ", jsonFile.Name())
453	return nil
454}
455
456func Groth16GenerateProofs(context *cli.Context) error {
457	// open compiledcircuit.json
458	compiledcircuitFile, err := ioutil.ReadFile("compiledcircuit.json")
459	panicErr(err)
460	var circuit circuitcompiler.Circuit
461	json.Unmarshal([]byte(string(compiledcircuitFile)), &circuit)
462	panicErr(err)
463
464	// open trustedsetup.json
465	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
466	panicErr(err)
467	var trustedsetup groth16.Setup
468	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
469	panicErr(err)
470
471	// read privateInputs file
472	privateInputsFile, err := ioutil.ReadFile("privateInputs.json")
473	panicErr(err)
474	// read publicInputs file
475	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
476	panicErr(err)
477	// parse inputs from inputsFile
478	var inputs circuitcompiler.Inputs
479	err = json.Unmarshal([]byte(string(privateInputsFile)), &inputs.Private)
480	panicErr(err)
481	err = json.Unmarshal([]byte(string(publicInputsFile)), &inputs.Public)
482	panicErr(err)
483
484	// calculate wittness
485	w, err := circuit.CalculateWitness(inputs.Private, inputs.Public)
486	panicErr(err)
487	fmt.Println("witness", w)
488
489	// flat code to R1CS
490	a := circuit.R1CS.A
491	b := circuit.R1CS.B
492	c := circuit.R1CS.C
493	// R1CS to QAP
494	alphas, betas, gammas, _ := groth16.Utils.PF.R1CSToQAP(a, b, c)
495	_, _, _, px := groth16.Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
496	hx := groth16.Utils.PF.DivisorPolynomial(px, trustedsetup.Pk.Z)
497
498	fmt.Println(circuit)
499	fmt.Println(trustedsetup.Pk.PowersTauDelta)
500	fmt.Println(hx)
501	fmt.Println(w)
502	proof, err := groth16.GenerateProofs(circuit, trustedsetup, w, px)
503	panicErr(err)
504
505	fmt.Println("\n proofs:")
506	fmt.Println(proof)
507
508	// store proofs to json
509	jsonData, err := json.Marshal(proof)
510	panicErr(err)
511	// store proof into file
512	jsonFile, err := os.Create("proofs.json")
513	panicErr(err)
514	defer jsonFile.Close()
515	jsonFile.Write(jsonData)
516	jsonFile.Close()
517	fmt.Println("Proofs data written to ", jsonFile.Name())
518	return nil
519}
520
521func Groth16VerifyProofs(context *cli.Context) error {
522	// open proofs.json
523	proofsFile, err := ioutil.ReadFile("proofs.json")
524	panicErr(err)
525	var proof groth16.Proof
526	json.Unmarshal([]byte(string(proofsFile)), &proof)
527	panicErr(err)
528
529	// open trustedsetup.json
530	trustedsetupFile, err := ioutil.ReadFile("trustedsetup.json")
531	panicErr(err)
532	var trustedsetup groth16.Setup
533	json.Unmarshal([]byte(string(trustedsetupFile)), &trustedsetup)
534	panicErr(err)
535
536	// read publicInputs file
537	publicInputsFile, err := ioutil.ReadFile("publicInputs.json")
538	panicErr(err)
539	var publicSignals []*big.Int
540	err = json.Unmarshal([]byte(string(publicInputsFile)), &publicSignals)
541	panicErr(err)
542
543	verified := groth16.VerifyProof(trustedsetup, proof, publicSignals, true)
544	if !verified {
545		fmt.Println("ERROR: proofs not verified")
546	} else {
547		fmt.Println("Proofs verified")
548	}
549	return nil
550}