github.com/fisco-bcos/crypto@v0.0.0-20200202032121-bd8ab0b5d4f1/elliptic/p256_asm.go (about) 1 // Copyright 2015 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file contains the Go wrapper for the constant-time, 64-bit assembly 6 // implementation of P256. The optimizations performed here are described in 7 // detail in: 8 // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with 9 // 256-bit primes" 10 // https://link.springer.com/article/10.1007%2Fs13389-014-0090-x 11 // https://eprint.iacr.org/2013/816.pdf 12 13 // +build amd64 arm64 14 15 package elliptic 16 17 import ( 18 "math/big" 19 "sync" 20 ) 21 22 type ( 23 p256Curve struct { 24 *CurveParams 25 } 26 27 p256Point struct { 28 xyz [12]uint64 29 } 30 ) 31 32 var ( 33 p256 p256Curve 34 p256Precomputed *[43][32 * 8]uint64 35 precomputeOnce sync.Once 36 ) 37 38 func initP256() { 39 // See FIPS 186-3, section D.2.3 40 p256.CurveParams = &CurveParams{Name: "P-256"} 41 p256.P, _ = new(big.Int).SetString("115792089210356248762697446949407573530086143415290314195533631308867097853951", 10) 42 p256.N, _ = new(big.Int).SetString("115792089210356248762697446949407573529996955224135760342422259061068512044369", 10) 43 p256.A, _ = new(big.Int).SetString("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16) 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 // Functions implemented in p256_asm_*64.s 55 // Montgomery multiplication modulo P256 56 //go:noescape 57 func p256Mul(res, in1, in2 []uint64) 58 59 // Montgomery square modulo P256, repeated n times (n >= 1) 60 //go:noescape 61 func p256Sqr(res, in []uint64, n int) 62 63 // Montgomery multiplication by 1 64 //go:noescape 65 func p256FromMont(res, in []uint64) 66 67 // iff cond == 1 val <- -val 68 //go:noescape 69 func p256NegCond(val []uint64, cond int) 70 71 // if cond == 0 res <- b; else res <- a 72 //go:noescape 73 func p256MovCond(res, a, b []uint64, cond int) 74 75 // Endianness swap 76 //go:noescape 77 func p256BigToLittle(res []uint64, in []byte) 78 79 //go:noescape 80 func p256LittleToBig(res []byte, in []uint64) 81 82 // Constant time table access 83 //go:noescape 84 func p256Select(point, table []uint64, idx int) 85 86 //go:noescape 87 func p256SelectBase(point, table []uint64, idx int) 88 89 // Montgomery multiplication modulo Ord(G) 90 //go:noescape 91 func p256OrdMul(res, in1, in2 []uint64) 92 93 // Montgomery square modulo Ord(G), repeated n times 94 //go:noescape 95 func p256OrdSqr(res, in []uint64, n int) 96 97 // Point add with in2 being affine point 98 // If sign == 1 -> in2 = -in2 99 // If sel == 0 -> res = in1 100 // if zero == 0 -> res = in2 101 //go:noescape 102 func p256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int) 103 104 // Point add. Returns one if the two input points were equal and zero 105 // otherwise. (Note that, due to the way that the equations work out, some 106 // representations of ∞ are considered equal to everything by this function.) 107 //go:noescape 108 func p256PointAddAsm(res, in1, in2 []uint64) int 109 110 // Point double 111 //go:noescape 112 func p256PointDoubleAsm(res, in []uint64) 113 114 func (curve p256Curve) Inverse(k *big.Int) *big.Int { 115 if k.Sign() < 0 { 116 // This should never happen. 117 k = new(big.Int).Neg(k) 118 } 119 120 if k.Cmp(p256.N) >= 0 { 121 // This should never happen. 122 k = new(big.Int).Mod(k, p256.N) 123 } 124 125 // table will store precomputed powers of x. 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 // This code operates in the Montgomery domain where R = 2^256 mod n 141 // and n is the order of the scalar field. (See initP256 for the 142 // value.) Elements in the Montgomery domain take the form a×R and 143 // multiplication of x and y in the calculates (x × y × R^-1) mod n. RR 144 // is R×R mod n thus the Montgomery multiplication x and RR gives x×R, 145 // i.e. converts x into the Montgomery domain. 146 // Window values borrowed from https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion 147 RR := []uint64{0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59, 0x66e12d94f3d95620} 148 p256OrdMul(_1, x, RR) // _1 149 p256OrdSqr(x, _1, 1) // _10 150 p256OrdMul(_11, x, _1) // _11 151 p256OrdMul(_101, x, _11) // _101 152 p256OrdMul(_111, x, _101) // _111 153 p256OrdSqr(x, _101, 1) // _1010 154 p256OrdMul(_1111, _101, x) // _1111 155 156 p256OrdSqr(t, x, 1) // _10100 157 p256OrdMul(_10101, t, _1) // _10101 158 p256OrdSqr(x, _10101, 1) // _101010 159 p256OrdMul(_101111, _101, x) // _101111 160 p256OrdMul(x, _10101, x) // _111111 = x6 161 p256OrdSqr(t, x, 2) // _11111100 162 p256OrdMul(t, t, _11) // _11111111 = x8 163 p256OrdSqr(x, t, 8) // _ff00 164 p256OrdMul(x, x, t) // _ffff = x16 165 p256OrdSqr(t, x, 16) // _ffff0000 166 p256OrdMul(t, t, x) // _ffffffff = x32 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 // Multiplying by one in the Montgomery domain converts a Montgomery 192 // value out of the domain. 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 // fromBig converts a *big.Int into a format used by this code. 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 // p256GetScalar endian-swaps the big-endian scalar value from in and writes it 213 // to out. If the scalar is equal or greater than the order of the group, it's 214 // reduced modulo that order. 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 // p256Mul operates in a Montgomery domain with R = 2^256 mod p, where p is the 225 // underlying field of the curve. (See initP256 for the value.) Thus rr here is 226 // R×R mod p. See comment in Inverse about how this is used. 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 // This sets r2's Z value to 1, in the Montgomery domain. 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 // This sets r2's Z value to 1, in the Montgomery domain. 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 // uint64IsZero returns 1 if x is zero and zero otherwise. 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 // scalarIsZero returns 1 if scalar represents the zero value, and zero 309 // otherwise. 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 // CopyConditional copies overwrites p with src if v == 1, and leaves p 336 // unchanged if v == 0. 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 // p256Inverse sets out to in^-1 mod p. 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) // 3*p 357 358 p256Sqr(out, p2, 2) 359 p256Mul(p4, out, p2) // f*p 360 361 p256Sqr(out, p4, 4) 362 p256Mul(p8, out, p4) // ff*p 363 364 p256Sqr(out, p8, 8) 365 p256Mul(p16, out, p8) // ffff*p 366 367 p256Sqr(out, p16, 16) 368 p256Mul(p32, out, p16) // ffffffff*p 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 initTable() { 416 p256Precomputed = new([43][32 * 8]uint64) 417 418 basePoint := []uint64{ 419 0x79e730d418a9143c, 0x75ba95fc5fedb601, 0x79fb732b77622510, 0x18905f76a53755c6, 420 0xddf25357ce95560a, 0x8b4ab8e4ba19e45c, 0xd2e88688dd21f325, 0x8571ff1825885d85, 421 0x0000000000000001, 0xffffffff00000000, 0xffffffffffffffff, 0x00000000fffffffe, 422 } 423 t1 := make([]uint64, 12) 424 t2 := make([]uint64, 12) 425 copy(t2, basePoint) 426 427 zInv := make([]uint64, 4) 428 zInvSq := make([]uint64, 4) 429 for j := 0; j < 32; j++ { 430 copy(t1, t2) 431 for i := 0; i < 43; i++ { 432 // The window size is 6 so we need to double 6 times. 433 if i != 0 { 434 for k := 0; k < 6; k++ { 435 p256PointDoubleAsm(t1, t1) 436 } 437 } 438 // Convert the point to affine form. (Its values are 439 // still in Montgomery form however.) 440 p256Inverse(zInv, t1[8:12]) 441 p256Sqr(zInvSq, zInv, 1) 442 p256Mul(zInv, zInv, zInvSq) 443 444 p256Mul(t1[:4], t1[:4], zInvSq) 445 p256Mul(t1[4:8], t1[4:8], zInv) 446 447 copy(t1[8:12], basePoint[8:12]) 448 // Update the table entry 449 copy(p256Precomputed[i][j*8:], t1[:8]) 450 } 451 if j == 0 { 452 p256PointDoubleAsm(t2, basePoint) 453 } else { 454 p256PointAddAsm(t2, t2, basePoint) 455 } 456 } 457 } 458 459 func (p *p256Point) p256BaseMult(scalar []uint64) { 460 precomputeOnce.Do(initTable) 461 462 wvalue := (scalar[0] << 1) & 0x7f 463 sel, sign := boothW6(uint(wvalue)) 464 p256SelectBase(p.xyz[0:8], p256Precomputed[0][0:], sel) 465 p256NegCond(p.xyz[4:8], sign) 466 467 // (This is one, in the Montgomery domain.) 468 p.xyz[8] = 0x0000000000000001 469 p.xyz[9] = 0xffffffff00000000 470 p.xyz[10] = 0xffffffffffffffff 471 p.xyz[11] = 0x00000000fffffffe 472 473 var t0 p256Point 474 // (This is one, in the Montgomery domain.) 475 t0.xyz[8] = 0x0000000000000001 476 t0.xyz[9] = 0xffffffff00000000 477 t0.xyz[10] = 0xffffffffffffffff 478 t0.xyz[11] = 0x00000000fffffffe 479 480 index := uint(5) 481 zero := sel 482 483 for i := 1; i < 43; i++ { 484 if index < 192 { 485 wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x7f 486 } else { 487 wvalue = (scalar[index/64] >> (index % 64)) & 0x7f 488 } 489 index += 6 490 sel, sign = boothW6(uint(wvalue)) 491 p256SelectBase(t0.xyz[0:8], p256Precomputed[i][0:], sel) 492 p256PointAddAffineAsm(p.xyz[0:12], p.xyz[0:12], t0.xyz[0:8], sign, sel, zero) 493 zero |= sel 494 } 495 } 496 497 func (p *p256Point) p256ScalarMult(scalar []uint64) { 498 // precomp is a table of precomputed points that stores powers of p 499 // from p^1 to p^16. 500 var precomp [16 * 4 * 3]uint64 501 var t0, t1, t2, t3 p256Point 502 503 // Prepare the table 504 p.p256StorePoint(&precomp, 0) // 1 505 506 p256PointDoubleAsm(t0.xyz[:], p.xyz[:]) 507 p256PointDoubleAsm(t1.xyz[:], t0.xyz[:]) 508 p256PointDoubleAsm(t2.xyz[:], t1.xyz[:]) 509 p256PointDoubleAsm(t3.xyz[:], t2.xyz[:]) 510 t0.p256StorePoint(&precomp, 1) // 2 511 t1.p256StorePoint(&precomp, 3) // 4 512 t2.p256StorePoint(&precomp, 7) // 8 513 t3.p256StorePoint(&precomp, 15) // 16 514 515 p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:]) 516 p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:]) 517 p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:]) 518 t0.p256StorePoint(&precomp, 2) // 3 519 t1.p256StorePoint(&precomp, 4) // 5 520 t2.p256StorePoint(&precomp, 8) // 9 521 522 p256PointDoubleAsm(t0.xyz[:], t0.xyz[:]) 523 p256PointDoubleAsm(t1.xyz[:], t1.xyz[:]) 524 t0.p256StorePoint(&precomp, 5) // 6 525 t1.p256StorePoint(&precomp, 9) // 10 526 527 p256PointAddAsm(t2.xyz[:], t0.xyz[:], p.xyz[:]) 528 p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:]) 529 t2.p256StorePoint(&precomp, 6) // 7 530 t1.p256StorePoint(&precomp, 10) // 11 531 532 p256PointDoubleAsm(t0.xyz[:], t0.xyz[:]) 533 p256PointDoubleAsm(t2.xyz[:], t2.xyz[:]) 534 t0.p256StorePoint(&precomp, 11) // 12 535 t2.p256StorePoint(&precomp, 13) // 14 536 537 p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:]) 538 p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:]) 539 t0.p256StorePoint(&precomp, 12) // 13 540 t2.p256StorePoint(&precomp, 14) // 15 541 542 // Start scanning the window from top bit 543 index := uint(254) 544 var sel, sign int 545 546 wvalue := (scalar[index/64] >> (index % 64)) & 0x3f 547 sel, _ = boothW5(uint(wvalue)) 548 549 p256Select(p.xyz[0:12], precomp[0:], sel) 550 zero := sel 551 552 for index > 4 { 553 index -= 5 554 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 555 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 556 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 557 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 558 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 559 560 if index < 192 { 561 wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x3f 562 } else { 563 wvalue = (scalar[index/64] >> (index % 64)) & 0x3f 564 } 565 566 sel, sign = boothW5(uint(wvalue)) 567 568 p256Select(t0.xyz[0:], precomp[0:], sel) 569 p256NegCond(t0.xyz[4:8], sign) 570 p256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:]) 571 p256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel) 572 p256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero) 573 zero |= sel 574 } 575 576 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 577 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 578 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 579 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 580 p256PointDoubleAsm(p.xyz[:], p.xyz[:]) 581 582 wvalue = (scalar[0] << 1) & 0x3f 583 sel, sign = boothW5(uint(wvalue)) 584 585 p256Select(t0.xyz[0:], precomp[0:], sel) 586 p256NegCond(t0.xyz[4:8], sign) 587 p256PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:]) 588 p256MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel) 589 p256MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero) 590 }