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