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/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}