1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package elliptic
17
18 import (
19 "math/big"
20 )
21
22 type (
23 p256Curve struct {
24 *CurveParams
25 }
26
27 p256Point struct {
28 xyz [12]uint64
29 }
30 )
31
32 var p256 p256Curve
33
34 func initP256() {
35
36 p256.CurveParams = &CurveParams{Name: "P-256"}
37 p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10)
38 p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10)
39 p256.B, _ = new(big.Int).SetString("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16)
40 p256.Gx, _ = new(big.Int).SetString("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296", 16)
41 p256.Gy, _ = new(big.Int).SetString("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5", 16)
42 p256.BitSize = 256
43 }
44
45 func (curve p256Curve) Params() *CurveParams {
46 return curve.CurveParams
47 }
48
49
50
51
52 func p256Mul(res, in1, in2 []uint64)
53
54
55
56 func p256Sqr(res, in []uint64, n int)
57
58
59
60 func p256FromMont(res, in []uint64)
61
62
63
64 func p256NegCond(val []uint64, cond int)
65
66
67
68 func p256MovCond(res, a, b []uint64, cond int)
69
70
71
72 func p256BigToLittle(res []uint64, in []byte)
73
74
75 func p256LittleToBig(res []byte, in []uint64)
76
77
78
79 func p256Select(point, table []uint64, idx int)
80
81
82 func p256SelectBase(point, table []uint64, idx int)
83
84
85
86 func p256OrdMul(res, in1, in2 []uint64)
87
88
89
90 func p256OrdSqr(res, in []uint64, n int)
91
92
93
94
95
96
97 func p256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int)
98
99
100
101
102
103 func p256PointAddAsm(res, in1, in2 []uint64) int
104
105
106
107 func p256PointDoubleAsm(res, in []uint64)
108
109 func (curve p256Curve) Inverse(k *big.Int) *big.Int {
110 if k.Sign() < 0 {
111
112 k = new(big.Int).Neg(k)
113 }
114
115 if k.Cmp(p256.N) >= 0 {
116
117 k = new(big.Int).Mod(k, p256.N)
118 }
119
120
121 var table [4 * 9]uint64
122 var (
123 _1 = table[4*0 : 4*1]
124 _11 = table[4*1 : 4*2]
125 _101 = table[4*2 : 4*3]
126 _111 = table[4*3 : 4*4]
127 _1111 = table[4*4 : 4*5]
128 _10101 = table[4*5 : 4*6]
129 _101111 = table[4*6 : 4*7]
130 x = table[4*7 : 4*8]
131 t = table[4*8 : 4*9]
132 )
133
134 fromBig(x[:], k)
135
136
137
138
139
140
141
142 RR := []uint64{0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59, 0x66e12d94f3d95620}
143 p256OrdMul(_1, x, RR)
144 p256OrdSqr(x, _1, 1)
145 p256OrdMul(_11, x, _1)
146 p256OrdMul(_101, x, _11)
147 p256OrdMul(_111, x, _101)
148 p256OrdSqr(x, _101, 1)
149 p256OrdMul(_1111, _101, x)
150
151 p256OrdSqr(t, x, 1)
152 p256OrdMul(_10101, t, _1)
153 p256OrdSqr(x, _10101, 1)
154 p256OrdMul(_101111, _101, x)
155 p256OrdMul(x, _10101, x)
156 p256OrdSqr(t, x, 2)
157 p256OrdMul(t, t, _11)
158 p256OrdSqr(x, t, 8)
159 p256OrdMul(x, x, t)
160 p256OrdSqr(t, x, 16)
161 p256OrdMul(t, t, x)
162
163 p256OrdSqr(x, t, 64)
164 p256OrdMul(x, x, t)
165 p256OrdSqr(x, x, 32)
166 p256OrdMul(x, x, t)
167
168 sqrs := []uint8{
169 6, 5, 4, 5, 5,
170 4, 3, 3, 5, 9,
171 6, 2, 5, 6, 5,
172 4, 5, 5, 3, 10,
173 2, 5, 5, 3, 7, 6}
174 muls := [][]uint64{
175 _101111, _111, _11, _1111, _10101,
176 _101, _101, _101, _111, _101111,
177 _1111, _1, _1, _1111, _111,
178 _111, _111, _101, _11, _101111,
179 _11, _11, _11, _1, _10101, _1111}
180
181 for i, s := range sqrs {
182 p256OrdSqr(x, x, int(s))
183 p256OrdMul(x, x, muls[i])
184 }
185
186
187
188 one := []uint64{1, 0, 0, 0}
189 p256OrdMul(x, x, one)
190
191 xOut := make([]byte, 32)
192 p256LittleToBig(xOut, x)
193 return new(big.Int).SetBytes(xOut)
194 }
195
196
197 func fromBig(out []uint64, big *big.Int) {
198 for i := range out {
199 out[i] = 0
200 }
201
202 for i, v := range big.Bits() {
203 out[i] = uint64(v)
204 }
205 }
206
207
208
209
210 func p256GetScalar(out []uint64, in []byte) {
211 n := new(big.Int).SetBytes(in)
212
213 if n.Cmp(p256.N) >= 0 {
214 n.Mod(n, p256.N)
215 }
216 fromBig(out, n)
217 }
218
219
220
221
222 var rr = []uint64{0x0000000000000003, 0xfffffffbffffffff, 0xfffffffffffffffe, 0x00000004fffffffd}
223
224 func maybeReduceModP(in *big.Int) *big.Int {
225 if in.Cmp(p256.P) < 0 {
226 return in
227 }
228 return new(big.Int).Mod(in, p256.P)
229 }
230
231 func (curve p256Curve) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
232 scalarReversed := make([]uint64, 4)
233 var r1, r2 p256Point
234 p256GetScalar(scalarReversed, baseScalar)
235 r1IsInfinity := scalarIsZero(scalarReversed)
236 r1.p256BaseMult(scalarReversed)
237
238 p256GetScalar(scalarReversed, scalar)
239 r2IsInfinity := scalarIsZero(scalarReversed)
240 fromBig(r2.xyz[0:4], maybeReduceModP(bigX))
241 fromBig(r2.xyz[4:8], maybeReduceModP(bigY))
242 p256Mul(r2.xyz[0:4], r2.xyz[0:4], rr[:])
243 p256Mul(r2.xyz[4:8], r2.xyz[4:8], rr[:])
244
245
246 r2.xyz[8] = 0x0000000000000001
247 r2.xyz[9] = 0xffffffff00000000
248 r2.xyz[10] = 0xffffffffffffffff
249 r2.xyz[11] = 0x00000000fffffffe
250
251 r2.p256ScalarMult(scalarReversed)
252
253 var sum, double p256Point
254 pointsEqual := p256PointAddAsm(sum.xyz[:], r1.xyz[:], r2.xyz[:])
255 p256PointDoubleAsm(double.xyz[:], r1.xyz[:])
256 sum.CopyConditional(&double, pointsEqual)
257 sum.CopyConditional(&r1, r2IsInfinity)
258 sum.CopyConditional(&r2, r1IsInfinity)
259
260 return sum.p256PointToAffine()
261 }
262
263 func (curve p256Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
264 scalarReversed := make([]uint64, 4)
265 p256GetScalar(scalarReversed, scalar)
266
267 var r p256Point
268 r.p256BaseMult(scalarReversed)
269 return r.p256PointToAffine()
270 }
271
272 func (curve p256Curve) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
273 scalarReversed := make([]uint64, 4)
274 p256GetScalar(scalarReversed, scalar)
275
276 var r p256Point
277 fromBig(r.xyz[0:4], maybeReduceModP(bigX))
278 fromBig(r.xyz[4:8], maybeReduceModP(bigY))
279 p256Mul(r.xyz[0:4], r.xyz[0:4], rr[:])
280 p256Mul(r.xyz[4:8], r.xyz[4:8], rr[:])
281
282 r.xyz[8] = 0x0000000000000001
283 r.xyz[9] = 0xffffffff00000000
284 r.xyz[10] = 0xffffffffffffffff
285 r.xyz[11] = 0x00000000fffffffe
286
287 r.p256ScalarMult(scalarReversed)
288 return r.p256PointToAffine()
289 }
290
291
292 func uint64IsZero(x uint64) int {
293 x = ^x
294 x &= x >> 32
295 x &= x >> 16
296 x &= x >> 8
297 x &= x >> 4
298 x &= x >> 2
299 x &= x >> 1
300 return int(x & 1)
301 }
302
303
304
305 func scalarIsZero(scalar []uint64) int {
306 return uint64IsZero(scalar[0] | scalar[1] | scalar[2] | scalar[3])
307 }
308
309 func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
310 zInv := make([]uint64, 4)
311 zInvSq := make([]uint64, 4)
312 p256Inverse(zInv, p.xyz[8:12])
313 p256Sqr(zInvSq, zInv, 1)
314 p256Mul(zInv, zInv, zInvSq)
315
316 p256Mul(zInvSq, p.xyz[0:4], zInvSq)
317 p256Mul(zInv, p.xyz[4:8], zInv)
318
319 p256FromMont(zInvSq, zInvSq)
320 p256FromMont(zInv, zInv)
321
322 xOut := make([]byte, 32)
323 yOut := make([]byte, 32)
324 p256LittleToBig(xOut, zInvSq)
325 p256LittleToBig(yOut, zInv)
326
327 return new(big.Int).SetBytes(xOut), new(big.Int).SetBytes(yOut)
328 }
329
330
331
332 func (p *p256Point) CopyConditional(src *p256Point, v int) {
333 pMask := uint64(v) - 1
334 srcMask := ^pMask
335
336 for i, n := range p.xyz {
337 p.xyz[i] = (n & pMask) | (src.xyz[i] & srcMask)
338 }
339 }
340
341
342 func p256Inverse(out, in []uint64) {
343 var stack [6 * 4]uint64
344 p2 := stack[4*0 : 4*0+4]
345 p4 := stack[4*1 : 4*1+4]
346 p8 := stack[4*2 : 4*2+4]
347 p16 := stack[4*3 : 4*3+4]
348 p32 := stack[4*4 : 4*4+4]
349
350 p256Sqr(out, in, 1)
351 p256Mul(p2, out, in)
352
353 p256Sqr(out, p2, 2)
354 p256Mul(p4, out, p2)
355
356 p256Sqr(out, p4, 4)
357 p256Mul(p8, out, p4)
358
359 p256Sqr(out, p8, 8)
360 p256Mul(p16, out, p8)
361
362 p256Sqr(out, p16, 16)
363 p256Mul(p32, out, p16)
364
365 p256Sqr(out, p32, 32)
366 p256Mul(out, out, in)
367
368 p256Sqr(out, out, 128)
369 p256Mul(out, out, p32)
370
371 p256Sqr(out, out, 32)
372 p256Mul(out, out, p32)
373
374 p256Sqr(out, out, 16)
375 p256Mul(out, out, p16)
376
377 p256Sqr(out, out, 8)
378 p256Mul(out, out, p8)
379
380 p256Sqr(out, out, 4)
381 p256Mul(out, out, p4)
382
383 p256Sqr(out, out, 2)
384 p256Mul(out, out, p2)
385
386 p256Sqr(out, out, 2)
387 p256Mul(out, out, in)
388 }
389
390 func (p *p256Point) p256StorePoint(r *[16 * 4 * 3]uint64, index int) {
391 copy(r[index*12:], p.xyz[:])
392 }
393
394 func boothW5(in uint) (int, int) {
395 var s uint = ^((in >> 5) - 1)
396 var d uint = (1 << 6) - in - 1
397 d = (d & s) | (in & (^s))
398 d = (d >> 1) + (d & 1)
399 return int(d), int(s & 1)
400 }
401
402 func boothW6(in uint) (int, int) {
403 var s uint = ^((in >> 6) - 1)
404 var d uint = (1 << 7) - in - 1
405 d = (d & s) | (in & (^s))
406 d = (d >> 1) + (d & 1)
407 return int(d), int(s & 1)
408 }
409
410 func (p *p256Point) p256BaseMult(scalar []uint64) {
411 wvalue := (scalar[0] << 1) & 0x7f
412 sel, sign := boothW6(uint(wvalue))
413 p256SelectBase(p.xyz[0:8], p256Precomputed[0][0:], sel)
414 p256NegCond(p.xyz[4:8], sign)
415
416
417 p.xyz[8] = 0x0000000000000001
418 p.xyz[9] = 0xffffffff00000000
419 p.xyz[10] = 0xffffffffffffffff
420 p.xyz[11] = 0x00000000fffffffe
421
422 var t0 p256Point
423
424 t0.xyz[8] = 0x0000000000000001
425 t0.xyz[9] = 0xffffffff00000000
426 t0.xyz[10] = 0xffffffffffffffff
427 t0.xyz[11] = 0x00000000fffffffe
428
429 index := uint(5)
430 zero := sel
431
432 for i := 1; i < 43; i++ {
433 if index < 192 {
434 wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x7f
435 } else {
436 wvalue = (scalar[index/64] >> (index % 64)) & 0x7f
437 }
438 index += 6
439 sel, sign = boothW6(uint(wvalue))
440 p256SelectBase(t0.xyz[0:8], p256Precomputed[i][0:], sel)
441 p256PointAddAffineAsm(p.xyz[0:12], p.xyz[0:12], t0.xyz[0:8], sign, sel, zero)
442 zero |= sel
443 }
444 }
445
446 func (p *p256Point) p256ScalarMult(scalar []uint64) {
447
448
449 var precomp [16 * 4 * 3]uint64
450 var t0, t1, t2, t3 p256Point
451
452
453 p.p256StorePoint(&precomp, 0)
454
455 p256PointDoubleAsm(t0.xyz[:], p.xyz[:])
456 p256PointDoubleAsm(t1.xyz[:], t0.xyz[:])
457 p256PointDoubleAsm(t2.xyz[:], t1.xyz[:])
458 p256PointDoubleAsm(t3.xyz[:], t2.xyz[:])
459 t0.p256StorePoint(&precomp, 1)
460 t1.p256StorePoint(&precomp, 3)
461 t2.p256StorePoint(&precomp, 7)
462 t3.p256StorePoint(&precomp, 15)
463
464 p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
465 p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
466 p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
467 t0.p256StorePoint(&precomp, 2)
468 t1.p256StorePoint(&precomp, 4)
469 t2.p256StorePoint(&precomp, 8)
470
471 p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
472 p256PointDoubleAsm(t1.xyz[:], t1.xyz[:])
473 t0.p256StorePoint(&precomp, 5)
474 t1.p256StorePoint(&precomp, 9)
475
476 p256PointAddAsm(t2.xyz[:], t0.xyz[:], p.xyz[:])
477 p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
478 t2.p256StorePoint(&precomp, 6)
479 t1.p256StorePoint(&precomp, 10)
480
481 p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
482 p256PointDoubleAsm(t2.xyz[:], t2.xyz[:])
483 t0.p256StorePoint(&precomp, 11)
484 t2.p256StorePoint(&precomp, 13)
485
486 p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
487 p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
488 t0.p256StorePoint(&precomp, 12)
489 t2.p256StorePoint(&precomp, 14)
490
491
492 index := uint(254)
493 var sel, sign int
494
495 wvalue := (scalar[index/64] >> (index % 64)) & 0x3f
496 sel, _ = boothW5(uint(wvalue))
497
498 p256Select(p.xyz[0:12], precomp[0:], sel)
499 zero := sel
500
501 for index > 4 {
502 index -= 5
503 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
504 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
505 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
506 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
507 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
508
509 if index < 192 {
510 wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x3f
511 } else {
512 wvalue = (scalar[index/64] >> (index % 64)) & 0x3f
513 }
514
515 sel, sign = boothW5(uint(wvalue))
516
517 p256Select(t0.xyz[0:], precomp[0:], sel)
518 p256NegCond(t0.xyz[4:8], sign)
519 p256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
520 p256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
521 p256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
522 zero |= sel
523 }
524
525 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
526 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
527 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
528 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
529 p256PointDoubleAsm(p.xyz[:], p.xyz[:])
530
531 wvalue = (scalar[0] << 1) & 0x3f
532 sel, sign = boothW5(uint(wvalue))
533
534 p256Select(t0.xyz[0:], precomp[0:], sel)
535 p256NegCond(t0.xyz[4:8], sign)
536 p256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
537 p256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
538 p256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
539 }
540
View as plain text