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