go-bellman-verifier/verifier.go
verifier.goRaw
1package bellmanverifier
2
3import (
4 "bytes"
5 "encoding/hex"
6 "encoding/json"
7 "fmt"
8 "math/big"
9 "strings"
10
11 bn256 "github.com/ethereum/go-ethereum/crypto/bn256/cloudflare"
12)
13
14var q *big.Int
15
16func init() {
17 var err error
18 q, err = stringToBigInt("21888242871839275222246405745257275088548364400416034343698204186575808495617")
19 if err != nil {
20 panic(err)
21 }
22}
23
24// Vk is the Verification Key data structure
25type Vk struct {
26 Alpha *bn256.G1
27 Beta *bn256.G2
28 Gamma *bn256.G2
29 Delta *bn256.G2
30 GammaABC []*bn256.G1
31}
32
33// VkRaw is the Verification Key data structure in string format (from json)
34type VkRaw struct {
35 Alpha []string `json:"alpha_g1"`
36 Beta [][]string `json:"beta_g2"`
37 Gamma [][]string `json:"gamma_g2"`
38 Delta [][]string `json:"delta_g2"`
39 GammaABC [][]string `json:"ic"`
40}
41
42// Proof is the Groth16 Proof data structure
43type Proof struct {
44 A *bn256.G1
45 B *bn256.G2
46 C *bn256.G1
47}
48
49// ProofRaw is the Groth16 Proof data structure in string format (from json)
50type ProofRaw struct {
51 A []string `json:"a"`
52 B [][]string `json:"b"`
53 C []string `json:"c"`
54 Inputs []string `json:"inputs"`
55}
56
57func hexToG1(h []string) (*bn256.G1, error) {
58 in := ""
59 for i := range h {
60 in += strings.TrimPrefix(h[i], "0x")
61 }
62
63 b, err := hex.DecodeString(in)
64 if err != nil {
65 return nil, err
66 }
67 p := new(bn256.G1)
68 _, err = p.Unmarshal(b)
69
70 return p, err
71}
72
73func hexToG2Regular(h [][]string) (*bn256.G2, error) {
74 in := ""
75 for i := 0; i < len(h); i++ {
76 for j := 0; j < len(h[i]); j++ {
77 in += strings.TrimPrefix(h[i][j], "0x")
78 }
79 }
80
81 b, err := hex.DecodeString(in)
82 if err != nil {
83 return nil, err
84 }
85 p := new(bn256.G2)
86 _, err = p.Unmarshal(b)
87 return p, err
88}
89
90func hexToG2(h [][]string) (*bn256.G2, error) {
91 in := ""
92 in += strings.TrimPrefix(h[0][1], "0x") // note that values are switched
93 in += strings.TrimPrefix(h[0][0], "0x")
94 in += strings.TrimPrefix(h[1][1], "0x")
95 in += strings.TrimPrefix(h[1][0], "0x")
96
97 b, err := hex.DecodeString(in)
98 if err != nil {
99 return nil, err
100 }
101 p := new(bn256.G2)
102 _, err = p.Unmarshal(b)
103 return p, err
104}
105
106func stringToBigInt(s string) (*big.Int, error) {
107 base := 10
108 if bytes.HasPrefix([]byte(s), []byte("0x")) {
109 base = 16
110 s = strings.TrimPrefix(s, "0x")
111 }
112 n, ok := new(big.Int).SetString(s, base)
113 if !ok {
114 return nil, fmt.Errorf("Can not parse string to *big.Int: %s", s)
115 }
116 return n, nil
117}
118
119// ParsePublicRaw takes a json []byte and outputs the []*big.Int struct
120func ParsePublicRaw(pj []byte) ([]*big.Int, error) {
121 var pr []string
122 err := json.Unmarshal(pj, &pr)
123 if err != nil {
124 return nil, err
125 }
126 var public []*big.Int
127 for _, s := range pr {
128 sb, err := stringToBigInt(s)
129 if err != nil {
130 return nil, err
131 }
132 public = append(public, sb)
133 }
134 return public, nil
135}
136
137// ParseVkRaw takes a json []byte and outputs the *Vk struct
138func ParseVkRaw(vj []byte) (*Vk, error) {
139 var vr VkRaw
140 err := json.Unmarshal(vj, &vr)
141 if err != nil {
142 return nil, err
143 }
144 v, err := vkRawToVk(vr)
145 return v, err
146}
147
148// ParseProofRaw takes a json []byte and outputs the *Proof struct
149func ParseProofRaw(pj []byte) (*Proof, error) {
150 var pr ProofRaw
151 err := json.Unmarshal(pj, &pr)
152 if err != nil {
153 return nil, err
154 }
155 p, err := proofRawToProof(pr)
156 return p, err
157}
158
159func vkRawToVk(vr VkRaw) (*Vk, error) {
160 var v Vk
161 var err error
162 v.Alpha, err = hexToG1(vr.Alpha)
163 if err != nil {
164 return nil, err
165 }
166
167 v.Beta, err = hexToG2(vr.Beta)
168 if err != nil {
169 return nil, err
170 }
171
172 v.Gamma, err = hexToG2(vr.Gamma)
173 if err != nil {
174 return nil, err
175 }
176
177 v.Delta, err = hexToG2(vr.Delta)
178 if err != nil {
179 return nil, err
180 }
181
182 for i := 0; i < len(vr.GammaABC); i++ {
183 p, err := hexToG1(vr.GammaABC[i])
184 if err != nil {
185 return nil, err
186 }
187 v.GammaABC = append(v.GammaABC, p)
188 }
189
190 return &v, nil
191}
192
193func proofRawToProof(pr ProofRaw) (*Proof, error) {
194 var p Proof
195 var err error
196 p.A, err = hexToG1(pr.A)
197 if err != nil {
198 return nil, err
199 }
200
201 p.B, err = hexToG2(pr.B)
202 if err != nil {
203 return nil, err
204 }
205
206 p.C, err = hexToG1(pr.C)
207 if err != nil {
208 return nil, err
209 }
210
211 return &p, nil
212}
213
214// Verify performs the Groth16 zkSnark verification
215func Verify(vk *Vk, proof *Proof, inputs []*big.Int) bool {
216 if len(inputs)+1 != len(vk.GammaABC) {
217 fmt.Println("len(inputs)+1 != len(vk.GammaABC)")
218 return false
219 }
220 vkX := new(bn256.G1).ScalarBaseMult(big.NewInt(0))
221 for i := 0; i < len(inputs); i++ {
222 // check input inside field
223 if inputs[0].Cmp(q) != -1 {
224 return false
225 }
226 vkX = new(bn256.G1).Add(vkX, new(bn256.G1).ScalarMult(vk.GammaABC[i+1], inputs[i]))
227 }
228 vkX = new(bn256.G1).Add(vkX, vk.GammaABC[0])
229
230 g1 := []*bn256.G1{proof.A, vk.Alpha.Neg(vk.Alpha), vkX.Neg(vkX), proof.C.Neg(proof.C)}
231 g2 := []*bn256.G2{proof.B, vk.Beta, vk.Gamma, vk.Delta}
232 return bn256.PairingCheck(g1, g2)
233}