arnaucube
arnaucube/go-bellman-verifierPublic Self-hosted repository
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}