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