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