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