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.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}