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}