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