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}