go-circom-prover-verifier/parsers.go
parsers.goRaw
1package gocircomprover
2
3import (
4 "bytes"
5 "encoding/hex"
6 "encoding/json"
7 "fmt"
8 "math/big"
9 "strconv"
10 "strings"
11
12 bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
13)
14
15// ProvingKeyString is the equivalent to the ProvingKey struct in string representation
16type ProvingKeyString struct {
17 A [][]string `json:"A"`
18 B2 [][][]string `json:"B2"`
19 B1 [][]string `json:"B1"`
20 C [][]string `json:"C"`
21 NVars int `json:"nVars"`
22 NPublic int `json:"nPublic"`
23 VkAlpha1 []string `json:"vk_alfa_1"`
24 VkDelta1 []string `json:"vk_delta_1"`
25 VkBeta1 []string `json:"vk_beta_1"`
26 VkBeta2 [][]string `json:"vk_beta_2"`
27 VkDelta2 [][]string `json:"vk_delta_2"`
28 HExps [][]string `json:"hExps"`
29 DomainSize int `json:"domainSize"`
30 PolsA []map[string]string `json:"polsA"`
31 PolsB []map[string]string `json:"polsB"`
32 PolsC []map[string]string `json:"polsC"`
33}
34
35// WitnessString contains the Witness in string representation
36type WitnessString []string
37
38// ProofString is the equivalent to the Proof struct in string representation
39type ProofString struct {
40 A [3]string `json:"pi_a"`
41 B [3][2]string `json:"pi_b"`
42 C [3]string `json:"pi_c"`
43 Protocol string `json:"protocol"`
44}
45
46// ParseWitness parses the json []byte data into the Witness struct
47func ParseWitness(wJson []byte) (Witness, error) {
48 var ws WitnessString
49 err := json.Unmarshal(wJson, &ws)
50 if err != nil {
51 return nil, err
52 }
53
54 var w Witness
55 for i := 0; i < len(ws); i++ {
56 bi, err := stringToBigInt(ws[i])
57 if err != nil {
58 return nil, err
59 }
60 w = append(w, bi)
61 }
62 return w, nil
63}
64
65// ParseProvingKey parses the json []byte data into the ProvingKey struct
66func ParseProvingKey(pkJson []byte) (*ProvingKey, error) {
67 var pkStr ProvingKeyString
68 err := json.Unmarshal(pkJson, &pkStr)
69 if err != nil {
70 return nil, err
71 }
72 pk, err := provingKeyStringToProvingKey(pkStr)
73 return pk, err
74}
75
76func provingKeyStringToProvingKey(ps ProvingKeyString) (*ProvingKey, error) {
77 var p ProvingKey
78 var err error
79
80 p.A, err = arrayStringToG1(ps.A)
81 if err != nil {
82 return nil, err
83 }
84 p.B2, err = arrayStringToG2(ps.B2)
85 if err != nil {
86 return nil, err
87 }
88 p.B1, err = arrayStringToG1(ps.B1)
89 if err != nil {
90 return nil, err
91 }
92 p.C, err = arrayStringToG1(ps.C)
93 if err != nil {
94 return nil, err
95 }
96
97 p.NVars = ps.NVars
98 p.NPublic = ps.NPublic
99
100 p.VkAlpha1, err = stringToG1(ps.VkAlpha1)
101 if err != nil {
102 return nil, err
103 }
104
105 p.VkDelta1, err = stringToG1(ps.VkDelta1)
106 if err != nil {
107 return nil, err
108 }
109
110 p.VkBeta1, err = stringToG1(ps.VkBeta1)
111 if err != nil {
112 return nil, err
113 }
114 p.VkBeta2, err = stringToG2(ps.VkBeta2)
115 if err != nil {
116 return nil, err
117 }
118 p.VkDelta2, err = stringToG2(ps.VkDelta2)
119 if err != nil {
120 return nil, err
121 }
122
123 p.HExps, err = arrayStringToG1(ps.HExps)
124 if err != nil {
125 return nil, err
126 }
127
128 p.DomainSize = ps.DomainSize
129
130 p.PolsA, err = polsStringToBigInt(ps.PolsA)
131 if err != nil {
132 return nil, err
133 }
134 p.PolsB, err = polsStringToBigInt(ps.PolsB)
135 if err != nil {
136 return nil, err
137 }
138 p.PolsC, err = polsStringToBigInt(ps.PolsC)
139 if err != nil {
140 return nil, err
141 }
142
143 return &p, nil
144}
145
146// polsStringToBigInt is for taking string polynomials and converting it to *big.Int polynomials
147func polsStringToBigInt(s []map[string]string) ([]map[int]*big.Int, error) {
148 var o []map[int]*big.Int
149 for i := 0; i < len(s); i++ {
150 // var oi map[int]*big.Int
151 oi := make(map[int]*big.Int)
152 for j, v := range s[i] {
153 si, err := stringToBigInt(v)
154 if err != nil {
155 return o, err
156 }
157 // oi = append(oi, si)
158 jInt, err := strconv.Atoi(j)
159 if err != nil {
160 return o, err
161 }
162 oi[jInt] = si
163 }
164 o = append(o, oi)
165 }
166 return o, nil
167}
168
169// ArrayBigIntToString converts an []*big.Int into []string, used to output the Public Signals
170func ArrayBigIntToString(bi []*big.Int) []string {
171 var s []string
172 for i := 0; i < len(bi); i++ {
173 s = append(s, bi[i].String())
174 }
175 return s
176}
177
178func arrayStringToBigInt(s []string) ([]*big.Int, error) {
179 var o []*big.Int
180 for i := 0; i < len(s); i++ {
181 si, err := stringToBigInt(s[i])
182 if err != nil {
183 return o, nil
184 }
185 o = append(o, si)
186 }
187 return o, nil
188}
189
190func stringToBigInt(s string) (*big.Int, error) {
191 base := 10
192 if bytes.HasPrefix([]byte(s), []byte("0x")) {
193 base = 16
194 s = strings.TrimPrefix(s, "0x")
195 }
196 n, ok := new(big.Int).SetString(s, base)
197 if !ok {
198 return nil, fmt.Errorf("Can not parse string to *big.Int: %s", s)
199 }
200 return n, nil
201}
202
203func addZPadding(b []byte) []byte {
204 var z [32]byte
205 var r []byte
206 r = append(r, z[len(b):]...) // add padding on the left
207 r = append(r, b...)
208 return r[:32]
209}
210
211func stringToBytes(s string) ([]byte, error) {
212 if s == "1" {
213 s = "0"
214 }
215 bi, ok := new(big.Int).SetString(s, 10)
216 if !ok {
217 return nil, fmt.Errorf("error parsing bigint stringToBytes")
218 }
219 b := bi.Bytes()
220 if len(b) != 32 {
221 b = addZPadding(b)
222 }
223 return b, nil
224
225}
226
227func arrayStringToG1(h [][]string) ([]*bn256.G1, error) {
228 var o []*bn256.G1
229 for i := 0; i < len(h); i++ {
230 hi, err := stringToG1(h[i])
231 if err != nil {
232 return o, err
233 }
234 o = append(o, hi)
235 }
236 return o, nil
237}
238
239func arrayStringToG2(h [][][]string) ([]*bn256.G2, error) {
240 var o []*bn256.G2
241 for i := 0; i < len(h); i++ {
242 hi, err := stringToG2(h[i])
243 if err != nil {
244 return o, err
245 }
246 o = append(o, hi)
247 }
248 return o, nil
249}
250
251func stringToG1(h []string) (*bn256.G1, error) {
252 if len(h) <= 2 {
253 return nil, fmt.Errorf("not enought data for stringToG1")
254 }
255 h = h[:2]
256 hexa := false
257 if len(h[0]) > 1 {
258 if "0x" == h[0][:2] {
259 hexa = true
260 }
261 }
262 in := ""
263
264 var b []byte
265 var err error
266 if hexa {
267 for i := range h {
268 in += strings.TrimPrefix(h[i], "0x")
269 }
270 b, err = hex.DecodeString(in)
271 if err != nil {
272 return nil, err
273 }
274 } else {
275 // TODO TMP
276 // TODO use stringToBytes()
277 if h[0] == "1" {
278 h[0] = "0"
279 }
280 if h[1] == "1" {
281 h[1] = "0"
282 }
283 bi0, ok := new(big.Int).SetString(h[0], 10)
284 if !ok {
285 return nil, fmt.Errorf("error parsing stringToG1")
286 }
287 bi1, ok := new(big.Int).SetString(h[1], 10)
288 if !ok {
289 return nil, fmt.Errorf("error parsing stringToG1")
290 }
291 b0 := bi0.Bytes()
292 b1 := bi1.Bytes()
293 if len(b0) != 32 {
294 b0 = addZPadding(b0)
295 }
296 if len(b1) != 32 {
297 b1 = addZPadding(b1)
298 }
299
300 b = append(b, b0...)
301 b = append(b, b1...)
302 }
303 p := new(bn256.G1)
304 _, err = p.Unmarshal(b)
305
306 return p, err
307}
308
309func stringToG2(h [][]string) (*bn256.G2, error) {
310 if len(h) <= 2 {
311 return nil, fmt.Errorf("not enought data for stringToG2")
312 }
313 h = h[:2]
314 hexa := false
315 if len(h[0][0]) > 1 {
316 if "0x" == h[0][0][:2] {
317 hexa = true
318 }
319 }
320 in := ""
321 var b []byte
322 var err error
323 if hexa {
324 for i := 0; i < len(h); i++ {
325 for j := 0; j < len(h[i]); j++ {
326 in += strings.TrimPrefix(h[i][j], "0x")
327 }
328 }
329 b, err = hex.DecodeString(in)
330 if err != nil {
331 return nil, err
332 }
333 } else {
334 // TODO TMP
335 bH, err := stringToBytes(h[0][1])
336 if err != nil {
337 return nil, err
338 }
339 b = append(b, bH...)
340 bH, err = stringToBytes(h[0][0])
341 if err != nil {
342 return nil, err
343 }
344 b = append(b, bH...)
345 bH, err = stringToBytes(h[1][1])
346 if err != nil {
347 return nil, err
348 }
349 b = append(b, bH...)
350 bH, err = stringToBytes(h[1][0])
351 if err != nil {
352 return nil, err
353 }
354 b = append(b, bH...)
355 }
356
357 p := new(bn256.G2)
358 _, err = p.Unmarshal(b)
359 return p, err
360}
361
362// ProofToJson outputs the Proof i Json format
363func ProofToJson(p *Proof) ([]byte, error) {
364 var ps ProofString
365
366 a := p.A.Marshal()
367 ps.A[0] = new(big.Int).SetBytes(a[:32]).String()
368 ps.A[1] = new(big.Int).SetBytes(a[32:64]).String()
369 ps.A[2] = "1"
370
371 b := p.B.Marshal()
372 ps.B[0][1] = new(big.Int).SetBytes(b[:32]).String()
373 ps.B[0][0] = new(big.Int).SetBytes(b[32:64]).String()
374 ps.B[1][1] = new(big.Int).SetBytes(b[64:96]).String()
375 ps.B[1][0] = new(big.Int).SetBytes(b[96:128]).String()
376 ps.B[2][0] = "1"
377 ps.B[2][1] = "0"
378
379 c := p.C.Marshal()
380 ps.C[0] = new(big.Int).SetBytes(c[:32]).String()
381 ps.C[1] = new(big.Int).SetBytes(c[32:64]).String()
382 ps.C[2] = "1"
383
384 ps.Protocol = "groth"
385
386 return json.Marshal(ps)
387}