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