arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/bn128/g2.go
bn128/g2.goRaw
  1package bn128
  2
  3import (
  4	"math/big"
  5
  6	"github.com/arnaucube/go-snark/fields"
  7)
  8
  9type G2 struct {
 10	F fields.Fq2
 11	G [3][2]*big.Int
 12}
 13
 14func NewG2(f fields.Fq2, g [2][2]*big.Int) G2 {
 15	var g2 G2
 16	g2.F = f
 17	g2.G = [3][2]*big.Int{
 18		g[0],
 19		g[1],
 20		g2.F.One(),
 21	}
 22	return g2
 23}
 24
 25func (g2 G2) Zero() [3][2]*big.Int {
 26	return [3][2]*big.Int{g2.F.Zero(), g2.F.One(), g2.F.Zero()}
 27}
 28func (g2 G2) IsZero(p [3][2]*big.Int) bool {
 29	return g2.F.IsZero(p[2])
 30}
 31
 32func (g2 G2) Add(p1, p2 [3][2]*big.Int) [3][2]*big.Int {
 33
 34	// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
 35	// https://github.com/zcash/zcash/blob/master/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp#L208
 36	// http://hyperelliptic.org/EFD/g2p/auto-code/shortw/jacobian-0/addition/add-2007-bl.op3
 37
 38	if g2.IsZero(p1) {
 39		return p2
 40	}
 41	if g2.IsZero(p2) {
 42		return p1
 43	}
 44
 45	x1 := p1[0]
 46	y1 := p1[1]
 47	z1 := p1[2]
 48	x2 := p2[0]
 49	y2 := p2[1]
 50	z2 := p2[2]
 51
 52	z1z1 := g2.F.Square(z1)
 53	z2z2 := g2.F.Square(z2)
 54
 55	u1 := g2.F.Mul(x1, z2z2)
 56	u2 := g2.F.Mul(x2, z1z1)
 57
 58	t0 := g2.F.Mul(z2, z2z2)
 59	s1 := g2.F.Mul(y1, t0)
 60
 61	t1 := g2.F.Mul(z1, z1z1)
 62	s2 := g2.F.Mul(y2, t1)
 63
 64	h := g2.F.Sub(u2, u1)
 65	t2 := g2.F.Add(h, h)
 66	i := g2.F.Square(t2)
 67	j := g2.F.Mul(h, i)
 68	t3 := g2.F.Sub(s2, s1)
 69	r := g2.F.Add(t3, t3)
 70	v := g2.F.Mul(u1, i)
 71	t4 := g2.F.Square(r)
 72	t5 := g2.F.Add(v, v)
 73	t6 := g2.F.Sub(t4, j)
 74	x3 := g2.F.Sub(t6, t5)
 75	t7 := g2.F.Sub(v, x3)
 76	t8 := g2.F.Mul(s1, j)
 77	t9 := g2.F.Add(t8, t8)
 78	t10 := g2.F.Mul(r, t7)
 79
 80	y3 := g2.F.Sub(t10, t9)
 81
 82	t11 := g2.F.Add(z1, z2)
 83	t12 := g2.F.Square(t11)
 84	t13 := g2.F.Sub(t12, z1z1)
 85	t14 := g2.F.Sub(t13, z2z2)
 86	z3 := g2.F.Mul(t14, h)
 87
 88	return [3][2]*big.Int{x3, y3, z3}
 89}
 90
 91func (g2 G2) Neg(p [3][2]*big.Int) [3][2]*big.Int {
 92	return [3][2]*big.Int{
 93		p[0],
 94		g2.F.Neg(p[1]),
 95		p[2],
 96	}
 97}
 98
 99func (g2 G2) Sub(a, b [3][2]*big.Int) [3][2]*big.Int {
100	return g2.Add(a, g2.Neg(b))
101}
102
103func (g2 G2) Double(p [3][2]*big.Int) [3][2]*big.Int {
104
105	// https://en.wikibooks.org/wiki/Cryptography/Prime_Curve/Jacobian_Coordinates
106	// http://hyperelliptic.org/EFD/g2p/auto-code/shortw/jacobian-0/doubling/dbl-2009-l.op3
107	// https://github.com/zcash/zcash/blob/master/src/snark/libsnark/algebra/curves/alt_bn128/alt_bn128_g2.cpp#L325
108
109	if g2.IsZero(p) {
110		return p
111	}
112
113	a := g2.F.Square(p[0])
114	b := g2.F.Square(p[1])
115	c := g2.F.Square(b)
116
117	t0 := g2.F.Add(p[0], b)
118	t1 := g2.F.Square(t0)
119	t2 := g2.F.Sub(t1, a)
120	t3 := g2.F.Sub(t2, c)
121
122	d := g2.F.Double(t3)
123	e := g2.F.Add(g2.F.Add(a, a), a)
124	f := g2.F.Square(e)
125
126	t4 := g2.F.Double(d)
127	x3 := g2.F.Sub(f, t4)
128
129	t5 := g2.F.Sub(d, x3)
130	twoC := g2.F.Add(c, c)
131	fourC := g2.F.Add(twoC, twoC)
132	t6 := g2.F.Add(fourC, fourC)
133	t7 := g2.F.Mul(e, t5)
134	y3 := g2.F.Sub(t7, t6)
135
136	t8 := g2.F.Mul(p[1], p[2])
137	z3 := g2.F.Double(t8)
138
139	return [3][2]*big.Int{x3, y3, z3}
140}
141
142func (g2 G2) MulScalar(p [3][2]*big.Int, e *big.Int) [3][2]*big.Int {
143	// https://en.wikipedia.org/wiki/Elliptic_curve_point_multiplication#Double-and-add
144
145	q := [3][2]*big.Int{g2.F.Zero(), g2.F.Zero(), g2.F.Zero()}
146	d := g2.F.F.Copy(e) // d := e
147	r := p
148
149	/*
150		here are three possible implementations:
151	*/
152
153	/* index decreasing: */
154	for i := d.BitLen() - 1; i >= 0; i-- {
155		q = g2.Double(q)
156		if d.Bit(i) == 1 {
157			q = g2.Add(q, r)
158		}
159	}
160
161	/* index increasing: */
162	// for i := 0; i <= d.BitLen(); i++ {
163	// 	if d.Bit(i) == 1 {
164	// 		q = g2.Add(q, r)
165	// 	}
166	// 	r = g2.Double(r)
167	// }
168
169	// foundone := false
170	// for i := d.BitLen(); i >= 0; i-- {
171	// 	if foundone {
172	// 		q = g2.Double(q)
173	// 	}
174	// 	if d.Bit(i) == 1 {
175	// 		foundone = true
176	// 		q = g2.Add(q, r)
177	// 	}
178	// }
179
180	return q
181}
182
183func (g2 G2) Affine(p [3][2]*big.Int) [3][2]*big.Int {
184	if g2.IsZero(p) {
185		return g2.Zero()
186	}
187
188	zinv := g2.F.Inverse(p[2])
189	zinv2 := g2.F.Square(zinv)
190	x := g2.F.Mul(p[0], zinv2)
191
192	zinv3 := g2.F.Mul(zinv2, zinv)
193	y := g2.F.Mul(p[1], zinv3)
194
195	return [3][2]*big.Int{
196		g2.F.Affine(x),
197		g2.F.Affine(y),
198		g2.F.One(),
199	}
200}
201
202func (g2 G2) Equal(p1, p2 [3][2]*big.Int) bool {
203	if g2.IsZero(p1) {
204		return g2.IsZero(p2)
205	}
206	if g2.IsZero(p2) {
207		return g2.IsZero(p1)
208	}
209
210	z1z1 := g2.F.Square(p1[2])
211	z2z2 := g2.F.Square(p2[2])
212
213	u1 := g2.F.Mul(p1[0], z2z2)
214	u2 := g2.F.Mul(p2[0], z1z1)
215
216	z1cub := g2.F.Mul(p1[2], z1z1)
217	z2cub := g2.F.Mul(p2[2], z2z2)
218
219	s1 := g2.F.Mul(p1[1], z2cub)
220	s2 := g2.F.Mul(p2[1], z1cub)
221
222	return g2.F.Equal(u1, u2) && g2.F.Equal(s1, s2)
223}