arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/snark_test.go
snark_test.goRaw
  1package snark
  2
  3import (
  4	"fmt"
  5	"math/big"
  6	"strings"
  7	"testing"
  8	"time"
  9
 10	"github.com/arnaucube/go-snark/circuitcompiler"
 11	"github.com/arnaucube/go-snark/r1csqap"
 12	"github.com/stretchr/testify/assert"
 13)
 14
 15func TestZkFromFlatCircuitCode(t *testing.T) {
 16
 17	// compile circuit and get the R1CS
 18	flatCode := `
 19	func test(x):
 20		aux = x*x
 21		y = aux*x
 22		z = x + y
 23		out = z + 5
 24	`
 25	fmt.Print("\nflat code of the circuit:")
 26	fmt.Println(flatCode)
 27
 28	// parse the code
 29	parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
 30	circuit, err := parser.Parse()
 31	assert.Nil(t, err)
 32	fmt.Println("\ncircuit data:", circuit)
 33
 34	b3 := big.NewInt(int64(3))
 35	inputs := []*big.Int{b3}
 36	// wittness
 37	w, err := circuit.CalculateWitness(inputs)
 38	assert.Nil(t, err)
 39	fmt.Println("\nwitness", w)
 40
 41	// flat code to R1CS
 42	fmt.Println("\ngenerating R1CS from flat code")
 43	a, b, c := circuit.GenerateR1CS()
 44	fmt.Println("\nR1CS:")
 45	fmt.Println("a:", a)
 46	fmt.Println("b:", b)
 47	fmt.Println("c:", c)
 48
 49	// R1CS to QAP
 50	alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c)
 51	fmt.Println("qap")
 52	fmt.Println(alphas)
 53	fmt.Println(betas)
 54	fmt.Println(gammas)
 55
 56	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
 57
 58	hx := Utils.PF.DivisorPolynomial(px, zx)
 59
 60	// hx==px/zx so px==hx*zx
 61	assert.Equal(t, px, Utils.PF.Mul(hx, zx))
 62
 63	// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
 64	abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
 65	assert.Equal(t, abc, px)
 66	hz := Utils.PF.Mul(hx, zx)
 67	assert.Equal(t, abc, hz)
 68
 69	div, rem := Utils.PF.Div(px, zx)
 70	assert.Equal(t, hx, div)
 71	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
 72
 73	// calculate trusted setup
 74	setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx)
 75	assert.Nil(t, err)
 76	fmt.Println("\nt:", setup.Toxic.T)
 77
 78	// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
 79	proof, err := GenerateProofs(*circuit, setup, hx, w)
 80	assert.Nil(t, err)
 81
 82	fmt.Println("\n proofs:")
 83	fmt.Println(proof)
 84	fmt.Println("public signals:", proof.PublicSignals)
 85	before := time.Now()
 86	assert.True(t, VerifyProof(*circuit, setup, proof, true))
 87	fmt.Println("verify proof time elapsed:", time.Since(before))
 88}
 89
 90func TestZkFromHardcodedR1CS(t *testing.T) {
 91	b0 := big.NewInt(int64(0))
 92	b1 := big.NewInt(int64(1))
 93	b3 := big.NewInt(int64(3))
 94	b5 := big.NewInt(int64(5))
 95	b9 := big.NewInt(int64(9))
 96	b27 := big.NewInt(int64(27))
 97	b30 := big.NewInt(int64(30))
 98	b35 := big.NewInt(int64(35))
 99	a := [][]*big.Int{
100		[]*big.Int{b0, b0, b1, b0, b0, b0},
101		[]*big.Int{b0, b0, b0, b1, b0, b0},
102		[]*big.Int{b0, b0, b1, b0, b1, b0},
103		[]*big.Int{b5, b0, b0, b0, b0, b1},
104	}
105	b := [][]*big.Int{
106		[]*big.Int{b0, b0, b1, b0, b0, b0},
107		[]*big.Int{b0, b0, b1, b0, b0, b0},
108		[]*big.Int{b1, b0, b0, b0, b0, b0},
109		[]*big.Int{b1, b0, b0, b0, b0, b0},
110	}
111	c := [][]*big.Int{
112		[]*big.Int{b0, b0, b0, b1, b0, b0},
113		[]*big.Int{b0, b0, b0, b0, b1, b0},
114		[]*big.Int{b0, b0, b0, b0, b0, b1},
115		[]*big.Int{b0, b1, b0, b0, b0, b0},
116	}
117	alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c)
118
119	// wittness = 1, 35, 3, 9, 27, 30
120	w := []*big.Int{b1, b35, b3, b9, b27, b30}
121	circuit := circuitcompiler.Circuit{
122		NVars:    6,
123		NPublic:  1,
124		NSignals: len(w),
125	}
126	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
127
128	hx := Utils.PF.DivisorPolynomial(px, zx)
129
130	// hx==px/zx so px==hx*zx
131	assert.Equal(t, px, Utils.PF.Mul(hx, zx))
132
133	// p(x) = a(x) * b(x) - c(x) == h(x) * z(x)
134	abc := Utils.PF.Sub(Utils.PF.Mul(ax, bx), cx)
135	assert.Equal(t, abc, px)
136	hz := Utils.PF.Mul(hx, zx)
137	assert.Equal(t, abc, hz)
138
139	div, rem := Utils.PF.Div(px, zx)
140	assert.Equal(t, hx, div)
141	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(4))
142
143	// calculate trusted setup
144	setup, err := GenerateTrustedSetup(len(w), circuit, alphas, betas, gammas, zx)
145	assert.Nil(t, err)
146
147	// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
148	proof, err := GenerateProofs(circuit, setup, hx, w)
149	assert.Nil(t, err)
150
151	assert.True(t, VerifyProof(circuit, setup, proof, true))
152}
153
154func TestZkMultiplication(t *testing.T) {
155
156	// compile circuit and get the R1CS
157	flatCode := `
158	func test(a, b):
159		out = a * b
160	`
161
162	// parse the code
163	parser := circuitcompiler.NewParser(strings.NewReader(flatCode))
164	circuit, err := parser.Parse()
165	assert.Nil(t, err)
166
167	b3 := big.NewInt(int64(3))
168	b4 := big.NewInt(int64(4))
169	inputs := []*big.Int{b3, b4}
170	// wittness
171	w, err := circuit.CalculateWitness(inputs)
172	assert.Nil(t, err)
173
174	// flat code to R1CS
175	a, b, c := circuit.GenerateR1CS()
176
177	// R1CS to QAP
178	alphas, betas, gammas, zx := Utils.PF.R1CSToQAP(a, b, c)
179
180	ax, bx, cx, px := Utils.PF.CombinePolynomials(w, alphas, betas, gammas)
181
182	hx := Utils.PF.DivisorPolynomial(px, zx)
183
184	// hx==px/zx so px==hx*zx
185	assert.Equal(t, px, Utils.PF.Mul(hx, zx))
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	hz := Utils.PF.Mul(hx, zx)
191	assert.Equal(t, abc, hz)
192
193	div, rem := Utils.PF.Div(px, zx)
194	assert.Equal(t, hx, div)
195	assert.Equal(t, rem, r1csqap.ArrayOfBigZeros(1))
196
197	// calculate trusted setup
198	setup, err := GenerateTrustedSetup(len(w), *circuit, alphas, betas, gammas, zx)
199	assert.Nil(t, err)
200
201	// piA = g1 * A(t), piB = g2 * B(t), piC = g1 * C(t), piH = g1 * H(t)
202	proof, err := GenerateProofs(*circuit, setup, hx, w)
203	assert.Nil(t, err)
204
205	assert.True(t, VerifyProof(*circuit, setup, proof, false))
206}