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}