arnaucube
arnaucube/go-snarkPublic Self-hosted repository
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}