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