go-snark/snark_test.go
snark_test.goRaw
1package snark
2
3import (
4 "bytes"
5 "fmt"
6 "math/big"
7 "strings"
8 "testing"
9 "time"
10
11 "github.com/arnaucube/go-snark/circuitcompiler"
12 "github.com/arnaucube/go-snark/groth16"
13 "github.com/arnaucube/go-snark/r1csqap"
14 "github.com/stretchr/testify/assert"
15)
16
17func TestGroth16MinimalFlow(t *testing.T) {
18 fmt.Println("testing Groth16 minimal flow")
19 // circuit function
20 // y = x^3 + x + 5
21 code := `
22 func main(private s0, public s1):
23 s2 = s0 * s0
24 s3 = s2 * s0
25 s4 = s3 + s0
26 s5 = s4 + 5
27 equals(s1, s5)
28 out = 1 * 1
29 `
30 fmt.Print("\ncode of the circuit:")
31
32 // parse the code
33 parser := circuitcompiler.NewParser(strings.NewReader(code))
34 circuit, err := parser.Parse()
35 assert.Nil(t, err)
36
37 b3 := big.NewInt(int64(3))
38 privateInputs := []*big.Int{b3}
39 b35 := big.NewInt(int64(35))
40 publicSignals := []*big.Int{b35}
41
42 // wittness
43 w, err := circuit.CalculateWitness(privateInputs, publicSignals)
44 assert.Nil(t, err)
45
46 // code to R1CS
47 fmt.Println("\ngenerating R1CS from code")
48 a, b, c := circuit.GenerateR1CS()
49 fmt.Println("\nR1CS:")
50 fmt.Println("a:", a)
51 fmt.Println("b:", b)
52 fmt.Println("c:", c)
53
54 // R1CS to QAP
55 // TODO zxQAP is not used and is an old impl, TODO remove
56 alphas, betas, gammas, _ := Utils.PF.R1CSToQAP(a, b, c)
57 fmt.Println("qap")
58 assert.Equal(t, 8, len(alphas))
59 assert.Equal(t, 8, len(alphas))
60 assert.Equal(t, 8, len(alphas))
61 assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
62
63 ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
64 assert.Equal(t, 7, len(ax))
65 assert.Equal(t, 7, len(bx))
66 assert.Equal(t, 7, len(cx))
67 assert.Equal(t, 13, len(px))
68
69 // ---
70 // from here is the GROTH16
71 // ---
72 // calculate trusted setup
73 fmt.Println("groth")
74 setup, err := groth16.GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
75 assert.Nil(t, err)
76 fmt.Println("\nt:", setup.Toxic.T)
77
78 hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
79 div, rem := Utils.PF.Div(px, setup.Pk.Z)
80 assert.Equal(t, hx, div)
81 assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
82
83 // hx==px/zx so px==hx*zx
84 assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
85
86 // check length of polynomials H(x) and Z(x)
87 assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
88
89 proof, err := groth16.GenerateProofs(*circuit, setup.Pk, w, px)
90 assert.Nil(t, err)
91
92 // fmt.Println("\n proofs:")
93 // fmt.Println(proof)
94
95 // fmt.Println("public signals:", proof.PublicSignals)
96 fmt.Println("\nsignals:", circuit.Signals)
97 fmt.Println("witness:", w)
98 b35Verif := big.NewInt(int64(35))
99 publicSignalsVerif := []*big.Int{b35Verif}
100 before := time.Now()
101 assert.True(t, groth16.VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
102 fmt.Println("verify proof time elapsed:", time.Since(before))
103
104 // check that with another public input the verification returns false
105 bOtherWrongPublic := big.NewInt(int64(34))
106 wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
107 assert.True(t, !groth16.VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
108}
109
110func TestZkFromFlatCircuitCode(t *testing.T) {
111 // compile circuit and get the R1CS
112
113 // circuit function
114 // y = x^3 + x + 5
115 code := `
116 func exp3(private a):
117 b = a * a
118 c = a * b
119 return c
120 func sum(private a, private b):
121 c = a + b
122 return c
123
124 func main(private s0, public s1):
125 s3 = exp3(s0)
126 s4 = sum(s3, s0)
127 s5 = s4 + 5
128 equals(s1, s5)
129 out = 1 * 1
130 `
131 // the same code without the functions calling, all in one func
132 // code := `
133 // func test(private s0, public s1):
134 // s2 = s0 * s0
135 // s3 = s2 * s0
136 // s4 = s3 + s0
137 // s5 = s4 + 5
138 // equals(s1, s5)
139 // out = 1 * 1
140 // `
141 fmt.Print("\ncode of the circuit:")
142 fmt.Println(code)
143
144 // parse the code
145 parser := circuitcompiler.NewParser(strings.NewReader(code))
146 circuit, err := parser.Parse()
147 assert.Nil(t, err)
148 // fmt.Println("\ncircuit data:", circuit)
149 // circuitJson, _ := json.Marshal(circuit)
150 // fmt.Println("circuit:", string(circuitJson))
151
152 b3 := big.NewInt(int64(3))
153 privateInputs := []*big.Int{b3}
154 b35 := big.NewInt(int64(35))
155 publicSignals := []*big.Int{b35}
156
157 // wittness
158 w, err := circuit.CalculateWitness(privateInputs, publicSignals)
159 assert.Nil(t, err)
160
161 // code to R1CS
162 fmt.Println("\ngenerating R1CS from code")
163 a, b, c := circuit.GenerateR1CS()
164 fmt.Println("\nR1CS:")
165 fmt.Println("a:", a)
166 fmt.Println("b:", b)
167 fmt.Println("c:", c)
168
169 // R1CS to QAP
170 // TODO zxQAP is not used and is an old impl, TODO remove
171 alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c)
172 fmt.Println("qap")
173 assert.Equal(t, 8, len(alphas))
174 assert.Equal(t, 8, len(alphas))
175 assert.Equal(t, 8, len(alphas))
176 assert.Equal(t, 7, len(zxQAP))
177 assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
178
179 ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
180 assert.Equal(t, 7, len(ax))
181 assert.Equal(t, 7, len(bx))
182 assert.Equal(t, 7, len(cx))
183 assert.Equal(t, 13, len(px))
184
185 hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP)
186 assert.Equal(t, 7, len(hxQAP))
187
188 // hx==px/zx so px==hx*zx
189 assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
190
191 // p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
192 abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
193 assert.Equal(t, abc, px)
194 hzQAP := Utils.PF.Mul(hxQAP, zxQAP)
195 assert.Equal(t, abc, hzQAP)
196
197 div, rem := Utils.PF.Div(px, zxQAP)
198 assert.Equal(t, hxQAP, div)
199 assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
200
201 // calculate trusted setup
202 setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
203 assert.Nil(t, err)
204 fmt.Println("\nt:", setup.Toxic.T)
205
206 // zx and setup.Pk.Z should be the same (currently not, the correct one is the calculation used inside GenerateTrustedSetup function), the calculation is repeated. TODO avoid repeating calculation
207 assert.Equal(t, zxQAP, setup.Pk.Z)
208
209 hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
210 assert.Equal(t, hx, hxQAP)
211 // assert.Equal(t, hxQAP, hx)
212 div, rem = Utils.PF.Div(px, setup.Pk.Z)
213 assert.Equal(t, hx, div)
214 assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
215
216 assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
217 // hx==px/zx so px==hx*zx
218 assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
219
220 // check length of polynomials H(x) and Z(x)
221 assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
222 assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
223
224 proof, err := GenerateProofs(*circuit, setup.Pk, w, px)
225 assert.Nil(t, err)
226
227 // fmt.Println("\n proofs:")
228 // fmt.Println(proof)
229
230 // fmt.Println("public signals:", proof.PublicSignals)
231 fmt.Println("\nsignals:", circuit.Signals)
232 fmt.Println("witness:", w)
233 b35Verif := big.NewInt(int64(35))
234 publicSignalsVerif := []*big.Int{b35Verif}
235 before := time.Now()
236 assert.True(t, VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
237 fmt.Println("verify proof time elapsed:", time.Since(before))
238
239 // check that with another public input the verification returns false
240 bOtherWrongPublic := big.NewInt(int64(34))
241 wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
242 assert.True(t, !VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
243}
244
245func TestZkMultiplication(t *testing.T) {
246 code := `
247 func main(private a, private b, public c):
248 d = a * b
249 equals(c, d)
250 out = 1 * 1
251 `
252 fmt.Println("code", code)
253
254 // parse the code
255 parser := circuitcompiler.NewParser(strings.NewReader(code))
256 circuit, err := parser.Parse()
257 assert.Nil(t, err)
258
259 b3 := big.NewInt(int64(3))
260 b4 := big.NewInt(int64(4))
261 privateInputs := []*big.Int{b3, b4}
262 b12 := big.NewInt(int64(12))
263 publicSignals := []*big.Int{b12}
264
265 // wittness
266 w, err := circuit.CalculateWitness(privateInputs, publicSignals)
267 assert.Nil(t, err)
268
269 // code to R1CS
270 fmt.Println("\ngenerating R1CS from code")
271 a, b, c := circuit.GenerateR1CS()
272 fmt.Println("\nR1CS:")
273 fmt.Println("a:", a)
274 fmt.Println("b:", b)
275 fmt.Println("c:", c)
276
277 // R1CS to QAP
278 // TODO zxQAP is not used and is an old impl. TODO remove
279 alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c)
280 assert.Equal(t, 6, len(alphas))
281 assert.Equal(t, 6, len(betas))
282 assert.Equal(t, 6, len(betas))
283 assert.Equal(t, 5, len(zxQAP))
284 assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
285
286 ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
287 assert.Equal(t, 4, len(ax))
288 assert.Equal(t, 4, len(bx))
289 assert.Equal(t, 4, len(cx))
290 assert.Equal(t, 7, len(px))
291
292 hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP)
293 assert.Equal(t, 3, len(hxQAP))
294
295 // hx==px/zx so px==hx*zx
296 assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
297
298 // p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
299 abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
300 assert.Equal(t, abc, px)
301 hzQAP := Utils.PF.Mul(hxQAP, zxQAP)
302 assert.Equal(t, abc, hzQAP)
303
304 div, rem := Utils.PF.Div(px, zxQAP)
305 assert.Equal(t, hxQAP, div)
306 assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
307
308 // calculate trusted setup
309 setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
310 assert.Nil(t, err)
311 // fmt.Println("\nt:", setup.Toxic.T)
312
313 // zx and setup.Pk.Z should be the same (currently not, the correct one is the calculation used inside GenerateTrustedSetup function), the calculation is repeated. TODO avoid repeating calculation
314 assert.Equal(t, zxQAP, setup.Pk.Z)
315
316 hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
317 assert.Equal(t, 3, len(hx))
318 assert.Equal(t, hx, hxQAP)
319
320 div, rem = Utils.PF.Div(px, setup.Pk.Z)
321 assert.Equal(t, hx, div)
322 assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
323
324 assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
325 // hx==px/zx so px==hx*zx
326 assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
327
328 // check length of polynomials H(x) and Z(x)
329 assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
330 assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
331
332 proof, err := GenerateProofs(*circuit, setup.Pk, w, px)
333 assert.Nil(t, err)
334
335 // fmt.Println("\n proofs:")
336 // fmt.Println(proof)
337
338 // fmt.Println("public signals:", proof.PublicSignals)
339 fmt.Println("\n", circuit.Signals)
340 fmt.Println("witness", w)
341 b12Verif := big.NewInt(int64(12))
342 publicSignalsVerif := []*big.Int{b12Verif}
343 before := time.Now()
344 assert.True(t, VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
345 fmt.Println("verify proof time elapsed:", time.Since(before))
346
347 // check that with another public input the verification returns false
348 bOtherWrongPublic := big.NewInt(int64(11))
349 wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
350 assert.True(t, !VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
351}
352
353func TestMinimalFlow(t *testing.T) {
354 // circuit function
355 // y = x^3 + x + 5
356 code := `
357 func main(private s0, public s1):
358 s2 = s0 * s0
359 s3 = s2 * s0
360 s4 = s3 + s0
361 s5 = s4 + 5
362 equals(s1, s5)
363 out = 1 * 1
364 `
365 fmt.Print("\ncode of the circuit:")
366 fmt.Println(code)
367
368 // parse the code
369 parser := circuitcompiler.NewParser(strings.NewReader(code))
370 circuit, err := parser.Parse()
371 assert.Nil(t, err)
372
373 b3 := big.NewInt(int64(3))
374 privateInputs := []*big.Int{b3}
375 b35 := big.NewInt(int64(35))
376 publicSignals := []*big.Int{b35}
377
378 // wittness
379 w, err := circuit.CalculateWitness(privateInputs, publicSignals)
380 assert.Nil(t, err)
381
382 // code to R1CS
383 fmt.Println("\ngenerating R1CS from code")
384 a, b, c := circuit.GenerateR1CS()
385 fmt.Println("\nR1CS:")
386 fmt.Println("a:", a)
387 fmt.Println("b:", b)
388 fmt.Println("c:", c)
389
390 // R1CS to QAP
391 // TODO zxQAP is not used and is an old impl, TODO remove
392 alphas, betas, gammas, _ := Utils.PF.R1CSToQAP(a, b, c)
393 fmt.Println("qap")
394 assert.Equal(t, 8, len(alphas))
395 assert.Equal(t, 8, len(alphas))
396 assert.Equal(t, 8, len(alphas))
397 assert.True(t, !bytes.Equal(alphas[1][1].Bytes(), big.NewInt(int64(0)).Bytes()))
398
399 ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
400 assert.Equal(t, 7, len(ax))
401 assert.Equal(t, 7, len(bx))
402 assert.Equal(t, 7, len(cx))
403 assert.Equal(t, 13, len(px))
404
405 // calculate trusted setup
406 setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
407 assert.Nil(t, err)
408 fmt.Println("\nt:", setup.Toxic.T)
409
410 hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
411 div, rem := Utils.PF.Div(px, setup.Pk.Z)
412 assert.Equal(t, hx, div)
413 assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(6))
414
415 // hx==px/zx so px==hx*zx
416 assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
417
418 // check length of polynomials H(x) and Z(x)
419 assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
420
421 proof, err := GenerateProofs(*circuit, setup.Pk, w, px)
422 assert.Nil(t, err)
423
424 // fmt.Println("\n proofs:")
425 // fmt.Println(proof)
426
427 // fmt.Println("public signals:", proof.PublicSignals)
428 fmt.Println("\nsignals:", circuit.Signals)
429 fmt.Println("witness:", w)
430 b35Verif := big.NewInt(int64(35))
431 publicSignalsVerif := []*big.Int{b35Verif}
432 before := time.Now()
433 assert.True(t, VerifyProof(setup.Vk, proof, publicSignalsVerif, true))
434 fmt.Println("verify proof time elapsed:", time.Since(before))
435
436 // check that with another public input the verification returns false
437 bOtherWrongPublic := big.NewInt(int64(34))
438 wrongPublicSignalsVerif := []*big.Int{bOtherWrongPublic}
439 assert.True(t, !VerifyProof(setup.Vk, proof, wrongPublicSignalsVerif, false))
440}