arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/snark_test.go
snark_test.goRaw
  1package snark
  2
  3import (
  4	"encoding/json"
  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
 18	// compile circuit and get the R1CS
 19	flatCode := `
 20	func test(x):
 21		aux = x*x
 22		y = aux*x
 23		z = x + y
 24		out = z + 5
 25	`
 26	fmt.Print("\nflat code of the circuit:")
 27	fmt.Println(flatCode)
 28
 29	// parse the code
 30	parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
 31	circuit, err := parser.Parse()
 32	assert.Nil(t, err)
 33	fmt.Println("\ncircuit data:", circuit)
 34	circuitJson, _ := json.Marshal(circuit)
 35	fmt.Println("circuit:", string(circuitJson))
 36
 37	b3 := big.NewInt(int64(3))
 38	privateInputs := []*big.Int{b3}
 39	// wittness
 40	w, err := circuit.CalculateWitness(privateInputs)
 41	assert.Nil(t, err)
 42	fmt.Println("\nwitness", w)
 43
 44	// flat code to R1CS
 45	fmt.Println("\ngenerating R1CS from flat code")
 46	a, b, c := circuit.GenerateR1CS()
 47	fmt.Println("\nR1CS:")
 48	fmt.Println("a:", a)
 49	fmt.Println("b:", b)
 50	fmt.Println("c:", c)
 51
 52	// R1CS to QAP
 53	alphas, betas, gammas, zxQAP := Utils.PF.R1CSToQAP(a, b, c)
 54	fmt.Println("qap")
 55	fmt.Println("alphas", len(alphas))
 56	fmt.Println("alphas", alphas[0])
 57	fmt.Println("betas", len(betas))
 58	fmt.Println("gammas", len(gammas))
 59	fmt.Println("zx length", len(zxQAP))
 60
 61	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
 62	fmt.Println("ax length", len(ax))
 63	fmt.Println("bx length", len(bx))
 64	fmt.Println("cx length", len(cx))
 65	fmt.Println("px length", len(px))
 66
 67	hxQAP := Utils.PF.DivisorPolynomial(px, zxQAP)
 68	fmt.Println("hx length", len(hxQAP))
 69
 70	// hx==px/zx so px==hx*zx
 71	assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
 72
 73	// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
 74	abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
 75	assert.Equal(t, abc, px)
 76	hzQAP := Utils.PF.Mul(hxQAP, zxQAP)
 77	assert.Equal(t, abc, hzQAP)
 78
 79	div, rem := Utils.PF.Div(px, zxQAP)
 80	assert.Equal(t, hxQAP, div)
 81	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
 82
 83	// calculate trusted setup
 84	setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas)
 85	assert.Nil(t, err)
 86	fmt.Println("\nt:", setup.Toxic.T)
 87
 88	// 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
 89	// assert.Equal(t, zxQAP, setup.Pk.Z)
 90
 91	fmt.Println("hx pk.z", hxQAP)
 92	hx := Utils.PF.DivisorPolynomial(px, setup.Pk.Z)
 93	fmt.Println("hx pk.z", hx)
 94	// assert.Equal(t, hxQAP, hx)
 95	assert.Equal(t, px, Utils.PF.Mul(hxQAP, zxQAP))
 96	assert.Equal(t, px, Utils.PF.Mul(hx, setup.Pk.Z))
 97
 98	assert.Equal(t, len(hx), len(px)-len(setup.Pk.Z)+1)
 99	assert.Equal(t, len(hxQAP), len(px)-len(zxQAP)+1)
100	// fmt.Println("pk.Z", len(setup.Pk.Z))
101	// fmt.Println("zxQAP", len(zxQAP))
102
103	// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
104	proof, err := GenerateProofs(*circuit, setup, w, px)
105	assert.Nil(t, err)
106
107	// fmt.Println("\n proofs:")
108	// fmt.Println(proof)
109
110	// fmt.Println("public signals:", proof.PublicSignals)
111	fmt.Println("\nwitness", w)
112	// b1 := big.NewInt(int64(1))
113	b35 := big.NewInt(int64(35))
114	// publicSignals := []*big.Int{b1, b35}
115	publicSignals := []*big.Int{b35}
116	before := time.Now()
117	assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true))
118	fmt.Println("verify proof time elapsed:", time.Since(before))
119}
120
121/*
122func TestZkMultiplication(t *testing.T) {
123
124	// compile circuit and get the R1CS
125	flatCode := `
126	func test(a, b):
127		out = a * b
128	`
129
130	// parse the code
131	parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
132	circuit, err := parser.Parse()
133	assert.Nil(t, err)
134
135	b3 := big.NewInt(int64(3))
136	b4 := big.NewInt(int64(4))
137	inputs := []*big.Int{b3, b4}
138	// wittness
139	w, err := circuit.CalculateWitness(inputs)
140	assert.Nil(t, err)
141
142	fmt.Println("circuit")
143	fmt.Println(circuit.NPublic)
144
145	// flat code to R1CS
146	a, b, c := circuit.GenerateR1CS()
147	fmt.Println("\nR1CS:")
148	fmt.Println("a:", a)
149	fmt.Println("b:", b)
150	fmt.Println("c:", c)
151
152	// R1CS to QAP
153	alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c)
154	fmt.Println("qap")
155	fmt.Println("alphas", alphas)
156	fmt.Println("betas", betas)
157	fmt.Println("gammas", gammas)
158
159	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
160
161	hx := Utils.PF.DivisorPolynomial(px, zx)
162
163	// hx==px/zx so px==hx*zx
164	assert.Equal(t, px, Utils.PF.Mul(hx, zx))
165
166	// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
167	abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
168	assert.Equal(t, abc, px)
169	hz := Utils.PF.Mul(hx, zx)
170	assert.Equal(t, abc, hz)
171
172	div, rem := Utils.PF.Div(px, zx)
173	assert.Equal(t, hx, div)
174	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(1))
175
176	// calculate trusted setup
177	setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx)
178	assert.Nil(t, err)
179
180	// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
181	proof, err := GenerateProofs(*circuit, setup, hx, w)
182	assert.Nil(t, err)
183
184	// assert.True(t, VerifyProof(*circuit, setup, proof, false))
185	b35 := big.NewInt(int64(35))
186	publicSignals := []*big.Int{b35}
187	assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true))
188}
189*/
190/*
191func TestZkFromHardcodedR1CS(t *testing.T) {
192	b0 := big.NewInt(int64(0))
193	b1 := big.NewInt(int64(1))
194	b3 := big.NewInt(int64(3))
195	b5 := big.NewInt(int64(5))
196	b9 := big.NewInt(int64(9))
197	b27 := big.NewInt(int64(27))
198	b30 := big.NewInt(int64(30))
199	b35 := big.NewInt(int64(35))
200	a := [][]*big.Int{
201		[]*big.Int{b0, b0, b1, b0, b0, b0},
202		[]*big.Int{b0, b0, b0, b1, b0, b0},
203		[]*big.Int{b0, b0, b1, b0, b1, b0},
204		[]*big.Int{b5, b0, b0, b0, b0, b1},
205	}
206	b := [][]*big.Int{
207		[]*big.Int{b0, b0, b1, b0, b0, b0},
208		[]*big.Int{b0, b0, b1, b0, b0, b0},
209		[]*big.Int{b1, b0, b0, b0, b0, b0},
210		[]*big.Int{b1, b0, b0, b0, b0, b0},
211	}
212	c := [][]*big.Int{
213		[]*big.Int{b0, b0, b0, b1, b0, b0},
214		[]*big.Int{b0, b0, b0, b0, b1, b0},
215		[]*big.Int{b0, b0, b0, b0, b0, b1},
216		[]*big.Int{b0, b1, b0, b0, b0, b0},
217	}
218	alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c)
219
220	// wittness = 1, 35, 3, 9, 27, 30
221	w := []*big.Int{b1, b35, b3, b9, b27, b30}
222	circuit := circuitcompiler.Circuit{
223		NVars:    6,
224		NPublic:  1,
225		NSignals: len(w),
226	}
227	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
228
229	hx := Utils.PF.DivisorPolynomial(px, zx)
230
231	// hx==px/zx so px==hx*zx
232	assert.Equal(t, px, Utils.PF.Mul(hx, zx))
233
234	// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
235	abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
236	assert.Equal(t, abc, px)
237	hz := Utils.PF.Mul(hx, zx)
238	assert.Equal(t, abc, hz)
239
240	div, rem := Utils.PF.Div(px, zx)
241	assert.Equal(t, hx, div)
242	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
243
244	// calculate trusted setup
245	setup, err := GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas, zx)
246	assert.Nil(t, err)
247
248	// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
249	proof, err := GenerateProofs(circuit, setup, hx, w)
250	assert.Nil(t, err)
251
252	// assert.True(t, VerifyProof(circuit, setup, proof, true))
253	publicSignals := []*big.Int{b35}
254	assert.True(t, VerifyProof(circuit, setup, proof, publicSignals, true))
255}
256
257func TestZkMultiplication(t *testing.T) {
258
259	// compile circuit and get the R1CS
260	flatCode := `
261	func test(a, b):
262		out = a * b
263	`
264
265	// parse the code
266	parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
267	circuit, err := parser.Parse()
268	assert.Nil(t, err)
269
270	b3 := big.NewInt(int64(3))
271	b4 := big.NewInt(int64(4))
272	inputs := []*big.Int{b3, b4}
273	// wittness
274	w, err := circuit.CalculateWitness(inputs)
275	assert.Nil(t, err)
276
277	// flat code to R1CS
278	a, b, c := circuit.GenerateR1CS()
279
280	// R1CS to QAP
281	alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c)
282
283	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
284
285	hx := Utils.PF.DivisorPolynomial(px, zx)
286
287	// hx==px/zx so px==hx*zx
288	assert.Equal(t, px, Utils.PF.Mul(hx, zx))
289
290	// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
291	abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
292	assert.Equal(t, abc, px)
293	hz := Utils.PF.Mul(hx, zx)
294	assert.Equal(t, abc, hz)
295
296	div, rem := Utils.PF.Div(px, zx)
297	assert.Equal(t, hx, div)
298	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(1))
299
300	// calculate trusted setup
301	setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx)
302	assert.Nil(t, err)
303
304	// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
305	proof, err := GenerateProofs(*circuit, setup, hx, w)
306	assert.Nil(t, err)
307
308	// assert.True(t, VerifyProof(*circuit, setup, proof, false))
309	b35 := big.NewInt(int64(35))
310	publicSignals := []*big.Int{b35}
311	assert.True(t, VerifyProof(*circuit, setup, proof, publicSignals, true))
312}
313*/