1
2
3
4
5
6
7
8 package elliptic
9
10 import (
11 "crypto/subtle"
12 "encoding/binary"
13 "math/big"
14 )
15
16
17
18
19
20
21 type p256CurveFast struct {
22 *CurveParams
23 }
24
25 type p256Point struct {
26 x [32]byte
27 y [32]byte
28 z [32]byte
29 }
30
31 var (
32 p256 Curve
33 p256PreFast *[37][64]p256Point
34 )
35
36 func initP256Arch() {
37 p256 = p256CurveFast{p256Params}
38 initTable()
39 return
40 }
41
42 func (curve p256CurveFast) Params() *CurveParams {
43 return curve.CurveParams
44 }
45
46
47
48
49
50 func p256MulAsm(res, in1, in2 []byte)
51
52
53
54 func p256Sqr(res, in []byte) {
55 p256MulAsm(res, in, in)
56 }
57
58
59
60
61 func p256FromMont(res, in []byte)
62
63
64
65
66 func p256NegCond(val *p256Point, cond int)
67
68
69
70
71 func p256MovCond(res, a, b *p256Point, cond int)
72
73
74
75
76 func p256Select(point *p256Point, table []p256Point, idx int)
77
78
79
80 func p256SelectBase(point *p256Point, table []p256Point, idx int)
81
82
83
84
85
86
87
88 func p256PointAddAffineAsm(res, in1, in2 *p256Point, sign, sel, zero int)
89
90
91
92
93 func p256PointAddAsm(res, in1, in2 *p256Point) int
94
95
96
97 func p256PointDoubleAsm(res, in *p256Point)
98
99
100
101
102
103 func fromBig(big *big.Int) []byte {
104
105 res := big.Bytes()
106 t := make([]byte, 32)
107 if len(res) < 32 {
108 copy(t[32-len(res):], res)
109 } else if len(res) == 32 {
110 copy(t, res)
111 } else {
112 copy(t, res[len(res)-32:])
113 }
114 p256ReverseBytes(t, t)
115 return t
116 }
117
118
119
120 func p256GetMultiplier(in []byte) []byte {
121 n := new(big.Int).SetBytes(in)
122
123 if n.Cmp(p256Params.N) >= 0 {
124 n.Mod(n, p256Params.N)
125 }
126 return fromBig(n)
127 }
128
129
130
131
132
133
134 var rr = []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00}
135
136
137 var one = []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00}
138
139 func maybeReduceModP(in *big.Int) *big.Int {
140 if in.Cmp(p256Params.P) < 0 {
141 return in
142 }
143 return new(big.Int).Mod(in, p256Params.P)
144 }
145
146
147 func p256ReverseBytes(res, in []byte) {
148
149 in = in[:32]
150 res = res[:32]
151
152
153 a := binary.BigEndian.Uint64(in[0:])
154 b := binary.BigEndian.Uint64(in[8:])
155 c := binary.BigEndian.Uint64(in[16:])
156 d := binary.BigEndian.Uint64(in[24:])
157
158
159 binary.LittleEndian.PutUint64(res[0:], d)
160 binary.LittleEndian.PutUint64(res[8:], c)
161 binary.LittleEndian.PutUint64(res[16:], b)
162 binary.LittleEndian.PutUint64(res[24:], a)
163 }
164
165 func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
166 var r1, r2 p256Point
167
168 scalarReduced := p256GetMultiplier(baseScalar)
169 r1IsInfinity := scalarIsZero(scalarReduced)
170 r1.p256BaseMult(scalarReduced)
171
172 copy(r2.x[:], fromBig(maybeReduceModP(bigX)))
173 copy(r2.y[:], fromBig(maybeReduceModP(bigY)))
174 copy(r2.z[:], one)
175 p256MulAsm(r2.x[:], r2.x[:], rr[:])
176 p256MulAsm(r2.y[:], r2.y[:], rr[:])
177
178 scalarReduced = p256GetMultiplier(scalar)
179 r2IsInfinity := scalarIsZero(scalarReduced)
180 r2.p256ScalarMult(scalarReduced)
181
182 var sum, double p256Point
183 pointsEqual := p256PointAddAsm(&sum, &r1, &r2)
184 p256PointDoubleAsm(&double, &r1)
185 p256MovCond(&sum, &double, &sum, pointsEqual)
186 p256MovCond(&sum, &r1, &sum, r2IsInfinity)
187 p256MovCond(&sum, &r2, &sum, r1IsInfinity)
188 return sum.p256PointToAffine()
189 }
190
191 func (curve p256CurveFast) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
192 var r p256Point
193 reducedScalar := p256GetMultiplier(scalar)
194 r.p256BaseMult(reducedScalar)
195 return r.p256PointToAffine()
196 }
197
198 func (curve p256CurveFast) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
199 scalarReduced := p256GetMultiplier(scalar)
200 var r p256Point
201 copy(r.x[:], fromBig(maybeReduceModP(bigX)))
202 copy(r.y[:], fromBig(maybeReduceModP(bigY)))
203 copy(r.z[:], one)
204 p256MulAsm(r.x[:], r.x[:], rr[:])
205 p256MulAsm(r.y[:], r.y[:], rr[:])
206 r.p256ScalarMult(scalarReduced)
207 return r.p256PointToAffine()
208 }
209
210 func scalarIsZero(scalar []byte) int {
211
212
213 b := byte(0)
214 for _, s := range scalar {
215 b |= s
216 }
217 return subtle.ConstantTimeByteEq(b, 0)
218 }
219
220 func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
221 zInv := make([]byte, 32)
222 zInvSq := make([]byte, 32)
223
224 p256Inverse(zInv, p.z[:])
225 p256Sqr(zInvSq, zInv)
226 p256MulAsm(zInv, zInv, zInvSq)
227
228 p256MulAsm(zInvSq, p.x[:], zInvSq)
229 p256MulAsm(zInv, p.y[:], zInv)
230
231 p256FromMont(zInvSq, zInvSq)
232 p256FromMont(zInv, zInv)
233
234
235
236
237 p256ReverseBytes(zInvSq, zInvSq)
238 p256ReverseBytes(zInv, zInv)
239 rx := new(big.Int).SetBytes(zInvSq)
240 ry := new(big.Int).SetBytes(zInv)
241 return rx, ry
242 }
243
244
245 func p256Inverse(out, in []byte) {
246 var stack [6 * 32]byte
247 p2 := stack[32*0 : 32*0+32]
248 p4 := stack[32*1 : 32*1+32]
249 p8 := stack[32*2 : 32*2+32]
250 p16 := stack[32*3 : 32*3+32]
251 p32 := stack[32*4 : 32*4+32]
252
253 p256Sqr(out, in)
254 p256MulAsm(p2, out, in)
255
256 p256Sqr(out, p2)
257 p256Sqr(out, out)
258 p256MulAsm(p4, out, p2)
259
260 p256Sqr(out, p4)
261 p256Sqr(out, out)
262 p256Sqr(out, out)
263 p256Sqr(out, out)
264 p256MulAsm(p8, out, p4)
265
266 p256Sqr(out, p8)
267
268 for i := 0; i < 7; i++ {
269 p256Sqr(out, out)
270 }
271 p256MulAsm(p16, out, p8)
272
273 p256Sqr(out, p16)
274 for i := 0; i < 15; i++ {
275 p256Sqr(out, out)
276 }
277 p256MulAsm(p32, out, p16)
278
279 p256Sqr(out, p32)
280
281 for i := 0; i < 31; i++ {
282 p256Sqr(out, out)
283 }
284 p256MulAsm(out, out, in)
285
286 for i := 0; i < 32*4; i++ {
287 p256Sqr(out, out)
288 }
289 p256MulAsm(out, out, p32)
290
291 for i := 0; i < 32; i++ {
292 p256Sqr(out, out)
293 }
294 p256MulAsm(out, out, p32)
295
296 for i := 0; i < 16; i++ {
297 p256Sqr(out, out)
298 }
299 p256MulAsm(out, out, p16)
300
301 for i := 0; i < 8; i++ {
302 p256Sqr(out, out)
303 }
304 p256MulAsm(out, out, p8)
305
306 p256Sqr(out, out)
307 p256Sqr(out, out)
308 p256Sqr(out, out)
309 p256Sqr(out, out)
310 p256MulAsm(out, out, p4)
311
312 p256Sqr(out, out)
313 p256Sqr(out, out)
314 p256MulAsm(out, out, p2)
315
316 p256Sqr(out, out)
317 p256Sqr(out, out)
318 p256MulAsm(out, out, in)
319 }
320
321 func boothW5(in uint) (int, int) {
322 var s uint = ^((in >> 5) - 1)
323 var d uint = (1 << 6) - in - 1
324 d = (d & s) | (in & (^s))
325 d = (d >> 1) + (d & 1)
326 return int(d), int(s & 1)
327 }
328
329 func boothW6(in uint) (int, int) {
330 var s uint = ^((in >> 6) - 1)
331 var d uint = (1 << 7) - in - 1
332 d = (d & s) | (in & (^s))
333 d = (d >> 1) + (d & 1)
334 return int(d), int(s & 1)
335 }
336
337 func boothW7(in uint) (int, int) {
338 var s uint = ^((in >> 7) - 1)
339 var d uint = (1 << 8) - in - 1
340 d = (d & s) | (in & (^s))
341 d = (d >> 1) + (d & 1)
342 return int(d), int(s & 1)
343 }
344
345 func initTable() {
346
347 p256PreFast = new([37][64]p256Point)
348
349
350
351 basePoint := p256Point{
352 x: [32]byte{0x3c, 0x14, 0xa9, 0x18, 0xd4, 0x30, 0xe7, 0x79, 0x01, 0xb6, 0xed, 0x5f, 0xfc, 0x95, 0xba, 0x75,
353 0x10, 0x25, 0x62, 0x77, 0x2b, 0x73, 0xfb, 0x79, 0xc6, 0x55, 0x37, 0xa5, 0x76, 0x5f, 0x90, 0x18},
354 y: [32]byte{0x0a, 0x56, 0x95, 0xce, 0x57, 0x53, 0xf2, 0xdd, 0x5c, 0xe4, 0x19, 0xba, 0xe4, 0xb8, 0x4a, 0x8b,
355 0x25, 0xf3, 0x21, 0xdd, 0x88, 0x86, 0xe8, 0xd2, 0x85, 0x5d, 0x88, 0x25, 0x18, 0xff, 0x71, 0x85},
356 z: [32]byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
357 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00},
358
359 }
360
361 t1 := new(p256Point)
362 t2 := new(p256Point)
363 *t2 = basePoint
364
365 zInv := make([]byte, 32)
366 zInvSq := make([]byte, 32)
367 for j := 0; j < 64; j++ {
368 *t1 = *t2
369 for i := 0; i < 37; i++ {
370
371 if i != 0 {
372 for k := 0; k < 7; k++ {
373 p256PointDoubleAsm(t1, t1)
374 }
375 }
376
377
378 p256Inverse(zInv, t1.z[:])
379 p256Sqr(zInvSq, zInv)
380 p256MulAsm(zInv, zInv, zInvSq)
381
382 p256MulAsm(t1.x[:], t1.x[:], zInvSq)
383 p256MulAsm(t1.y[:], t1.y[:], zInv)
384
385 copy(t1.z[:], basePoint.z[:])
386
387 copy(p256PreFast[i][j].x[:], t1.x[:])
388 copy(p256PreFast[i][j].y[:], t1.y[:])
389 }
390 if j == 0 {
391 p256PointDoubleAsm(t2, &basePoint)
392 } else {
393 p256PointAddAsm(t2, t2, &basePoint)
394 }
395 }
396 }
397
398 func (p *p256Point) p256BaseMult(scalar []byte) {
399
400 wvalue := (uint(scalar[0]) << 1) & 0xff
401 sel, sign := boothW7(uint(wvalue))
402 p256SelectBase(p, p256PreFast[0][:], sel)
403 p256NegCond(p, sign)
404
405 copy(p.z[:], one[:])
406 var t0 p256Point
407
408 copy(t0.z[:], one[:])
409
410 index := uint(6)
411 zero := sel
412 for i := 1; i < 37; i++ {
413
414
415 if index < 247 {
416 wvalue = ((uint(scalar[index/8]) >> (index % 8)) + (uint(scalar[index/8+1]) << (8 - (index % 8)))) & 0xff
417 } else {
418 wvalue = (uint(scalar[index/8]) >> (index % 8)) & 0xff
419 }
420 index += 7
421 sel, sign = boothW7(uint(wvalue))
422 p256SelectBase(&t0, p256PreFast[i][:], sel)
423 p256PointAddAffineAsm(p, p, &t0, sign, sel, zero)
424 zero |= sel
425 }
426 }
427
428 func (p *p256Point) p256ScalarMult(scalar []byte) {
429
430
431 var precomp [16]p256Point
432 var t0, t1, t2, t3 p256Point
433
434 *&precomp[0] = *p
435 p256PointDoubleAsm(&t0, p)
436 p256PointDoubleAsm(&t1, &t0)
437 p256PointDoubleAsm(&t2, &t1)
438 p256PointDoubleAsm(&t3, &t2)
439 *&precomp[1] = t0
440 *&precomp[3] = t1
441 *&precomp[7] = t2
442 *&precomp[15] = t3
443
444 p256PointAddAsm(&t0, &t0, p)
445 p256PointAddAsm(&t1, &t1, p)
446 p256PointAddAsm(&t2, &t2, p)
447
448 *&precomp[2] = t0
449 *&precomp[4] = t1
450 *&precomp[8] = t2
451
452 p256PointDoubleAsm(&t0, &t0)
453 p256PointDoubleAsm(&t1, &t1)
454 *&precomp[5] = t0
455 *&precomp[9] = t1
456
457 p256PointAddAsm(&t2, &t0, p)
458 p256PointAddAsm(&t1, &t1, p)
459 *&precomp[6] = t2
460 *&precomp[10] = t1
461
462 p256PointDoubleAsm(&t0, &t0)
463 p256PointDoubleAsm(&t2, &t2)
464 *&precomp[11] = t0
465 *&precomp[13] = t2
466
467 p256PointAddAsm(&t0, &t0, p)
468 p256PointAddAsm(&t2, &t2, p)
469 *&precomp[12] = t0
470 *&precomp[14] = t2
471
472
473 index := uint(254)
474 var sel, sign int
475
476
477 wvalue := (uint(scalar[index/8]) >> (index % 8)) & 0x3f
478 sel, _ = boothW5(uint(wvalue))
479 p256Select(p, precomp[:], sel)
480 zero := sel
481
482 for index > 4 {
483 index -= 5
484 p256PointDoubleAsm(p, p)
485 p256PointDoubleAsm(p, p)
486 p256PointDoubleAsm(p, p)
487 p256PointDoubleAsm(p, p)
488 p256PointDoubleAsm(p, p)
489
490
491 if index < 247 {
492 wvalue = ((uint(scalar[index/8]) >> (index % 8)) + (uint(scalar[index/8+1]) << (8 - (index % 8)))) & 0x3f
493 } else {
494 wvalue = (uint(scalar[index/8]) >> (index % 8)) & 0x3f
495 }
496
497 sel, sign = boothW5(uint(wvalue))
498
499 p256Select(&t0, precomp[:], sel)
500 p256NegCond(&t0, sign)
501 p256PointAddAsm(&t1, p, &t0)
502 p256MovCond(&t1, &t1, p, sel)
503 p256MovCond(p, &t1, &t0, zero)
504 zero |= sel
505 }
506
507 p256PointDoubleAsm(p, p)
508 p256PointDoubleAsm(p, p)
509 p256PointDoubleAsm(p, p)
510 p256PointDoubleAsm(p, p)
511 p256PointDoubleAsm(p, p)
512
513
514 wvalue = (uint(scalar[0]) << 1) & 0x3f
515 sel, sign = boothW5(uint(wvalue))
516
517 p256Select(&t0, precomp[:], sel)
518 p256NegCond(&t0, sign)
519 p256PointAddAsm(&t1, p, &t0)
520 p256MovCond(&t1, &t1, p, sel)
521 p256MovCond(p, &t1, &t0, zero)
522 }
523
View as plain text