1
2
3
4
5 package elliptic
6
7 import "math/big"
8
9
10
11
12
13
14
15 type CurveParams struct {
16 P *big.Int
17 N *big.Int
18 B *big.Int
19 Gx, Gy *big.Int
20 BitSize int
21 Name string
22 }
23
24 func (curve *CurveParams) Params() *CurveParams {
25 return curve
26 }
27
28
29
30
31
32
33
34
35
36 func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
37 x3 := new(big.Int).Mul(x, x)
38 x3.Mul(x3, x)
39
40 threeX := new(big.Int).Lsh(x, 1)
41 threeX.Add(threeX, x)
42
43 x3.Sub(x3, threeX)
44 x3.Add(x3, curve.B)
45 x3.Mod(x3, curve.P)
46
47 return x3
48 }
49
50
51
52
53
54
55
56 func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
57
58
59 if specific, ok := matchesSpecificCurve(curve); ok {
60 return specific.IsOnCurve(x, y)
61 }
62
63 if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
64 y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
65 return false
66 }
67
68
69 y2 := new(big.Int).Mul(y, y)
70 y2.Mod(y2, curve.P)
71
72 return curve.polynomial(x).Cmp(y2) == 0
73 }
74
75
76
77
78 func zForAffine(x, y *big.Int) *big.Int {
79 z := new(big.Int)
80 if x.Sign() != 0 || y.Sign() != 0 {
81 z.SetInt64(1)
82 }
83 return z
84 }
85
86
87
88 func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
89 if z.Sign() == 0 {
90 return new(big.Int), new(big.Int)
91 }
92
93 zinv := new(big.Int).ModInverse(z, curve.P)
94 zinvsq := new(big.Int).Mul(zinv, zinv)
95
96 xOut = new(big.Int).Mul(x, zinvsq)
97 xOut.Mod(xOut, curve.P)
98 zinvsq.Mul(zinvsq, zinv)
99 yOut = new(big.Int).Mul(y, zinvsq)
100 yOut.Mod(yOut, curve.P)
101 return
102 }
103
104
105
106
107
108
109
110 func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
111
112
113 if specific, ok := matchesSpecificCurve(curve); ok {
114 return specific.Add(x1, y1, x2, y2)
115 }
116 panicIfNotOnCurve(curve, x1, y1)
117 panicIfNotOnCurve(curve, x2, y2)
118
119 z1 := zForAffine(x1, y1)
120 z2 := zForAffine(x2, y2)
121 return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
122 }
123
124
125
126 func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
127
128 x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
129 if z1.Sign() == 0 {
130 x3.Set(x2)
131 y3.Set(y2)
132 z3.Set(z2)
133 return x3, y3, z3
134 }
135 if z2.Sign() == 0 {
136 x3.Set(x1)
137 y3.Set(y1)
138 z3.Set(z1)
139 return x3, y3, z3
140 }
141
142 z1z1 := new(big.Int).Mul(z1, z1)
143 z1z1.Mod(z1z1, curve.P)
144 z2z2 := new(big.Int).Mul(z2, z2)
145 z2z2.Mod(z2z2, curve.P)
146
147 u1 := new(big.Int).Mul(x1, z2z2)
148 u1.Mod(u1, curve.P)
149 u2 := new(big.Int).Mul(x2, z1z1)
150 u2.Mod(u2, curve.P)
151 h := new(big.Int).Sub(u2, u1)
152 xEqual := h.Sign() == 0
153 if h.Sign() == -1 {
154 h.Add(h, curve.P)
155 }
156 i := new(big.Int).Lsh(h, 1)
157 i.Mul(i, i)
158 j := new(big.Int).Mul(h, i)
159
160 s1 := new(big.Int).Mul(y1, z2)
161 s1.Mul(s1, z2z2)
162 s1.Mod(s1, curve.P)
163 s2 := new(big.Int).Mul(y2, z1)
164 s2.Mul(s2, z1z1)
165 s2.Mod(s2, curve.P)
166 r := new(big.Int).Sub(s2, s1)
167 if r.Sign() == -1 {
168 r.Add(r, curve.P)
169 }
170 yEqual := r.Sign() == 0
171 if xEqual && yEqual {
172 return curve.doubleJacobian(x1, y1, z1)
173 }
174 r.Lsh(r, 1)
175 v := new(big.Int).Mul(u1, i)
176
177 x3.Set(r)
178 x3.Mul(x3, x3)
179 x3.Sub(x3, j)
180 x3.Sub(x3, v)
181 x3.Sub(x3, v)
182 x3.Mod(x3, curve.P)
183
184 y3.Set(r)
185 v.Sub(v, x3)
186 y3.Mul(y3, v)
187 s1.Mul(s1, j)
188 s1.Lsh(s1, 1)
189 y3.Sub(y3, s1)
190 y3.Mod(y3, curve.P)
191
192 z3.Add(z1, z2)
193 z3.Mul(z3, z3)
194 z3.Sub(z3, z1z1)
195 z3.Sub(z3, z2z2)
196 z3.Mul(z3, h)
197 z3.Mod(z3, curve.P)
198
199 return x3, y3, z3
200 }
201
202
203
204
205
206
207
208 func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
209
210
211 if specific, ok := matchesSpecificCurve(curve); ok {
212 return specific.Double(x1, y1)
213 }
214 panicIfNotOnCurve(curve, x1, y1)
215
216 z1 := zForAffine(x1, y1)
217 return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
218 }
219
220
221
222 func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
223
224 delta := new(big.Int).Mul(z, z)
225 delta.Mod(delta, curve.P)
226 gamma := new(big.Int).Mul(y, y)
227 gamma.Mod(gamma, curve.P)
228 alpha := new(big.Int).Sub(x, delta)
229 if alpha.Sign() == -1 {
230 alpha.Add(alpha, curve.P)
231 }
232 alpha2 := new(big.Int).Add(x, delta)
233 alpha.Mul(alpha, alpha2)
234 alpha2.Set(alpha)
235 alpha.Lsh(alpha, 1)
236 alpha.Add(alpha, alpha2)
237
238 beta := alpha2.Mul(x, gamma)
239
240 x3 := new(big.Int).Mul(alpha, alpha)
241 beta8 := new(big.Int).Lsh(beta, 3)
242 beta8.Mod(beta8, curve.P)
243 x3.Sub(x3, beta8)
244 if x3.Sign() == -1 {
245 x3.Add(x3, curve.P)
246 }
247 x3.Mod(x3, curve.P)
248
249 z3 := new(big.Int).Add(y, z)
250 z3.Mul(z3, z3)
251 z3.Sub(z3, gamma)
252 if z3.Sign() == -1 {
253 z3.Add(z3, curve.P)
254 }
255 z3.Sub(z3, delta)
256 if z3.Sign() == -1 {
257 z3.Add(z3, curve.P)
258 }
259 z3.Mod(z3, curve.P)
260
261 beta.Lsh(beta, 2)
262 beta.Sub(beta, x3)
263 if beta.Sign() == -1 {
264 beta.Add(beta, curve.P)
265 }
266 y3 := alpha.Mul(alpha, beta)
267
268 gamma.Mul(gamma, gamma)
269 gamma.Lsh(gamma, 3)
270 gamma.Mod(gamma, curve.P)
271
272 y3.Sub(y3, gamma)
273 if y3.Sign() == -1 {
274 y3.Add(y3, curve.P)
275 }
276 y3.Mod(y3, curve.P)
277
278 return x3, y3, z3
279 }
280
281
282
283
284
285
286
287 func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
288
289
290 if specific, ok := matchesSpecificCurve(curve); ok {
291 return specific.ScalarMult(Bx, By, k)
292 }
293 panicIfNotOnCurve(curve, Bx, By)
294
295 Bz := new(big.Int).SetInt64(1)
296 x, y, z := new(big.Int), new(big.Int), new(big.Int)
297
298 for _, byte := range k {
299 for bitNum := 0; bitNum < 8; bitNum++ {
300 x, y, z = curve.doubleJacobian(x, y, z)
301 if byte&0x80 == 0x80 {
302 x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
303 }
304 byte <<= 1
305 }
306 }
307
308 return curve.affineFromJacobian(x, y, z)
309 }
310
311
312
313
314
315
316
317 func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
318
319
320 if specific, ok := matchesSpecificCurve(curve); ok {
321 return specific.ScalarBaseMult(k)
322 }
323
324 return curve.ScalarMult(curve.Gx, curve.Gy, k)
325 }
326
327 func matchesSpecificCurve(params *CurveParams) (Curve, bool) {
328 for _, c := range []Curve{p224, p256, p384, p521} {
329 if params == c.Params() {
330 return c, true
331 }
332 }
333 return nil, false
334 }
335
View as plain text