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
 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}