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