Source file src/crypto/elliptic/p256_asm.go

     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  //go:build amd64 || arm64
    14  
    15  package elliptic
    16  
    17  import (
    18  	_ "embed"
    19  	"math/big"
    20  )
    21  
    22  //go:generate go run -tags=tablegen gen_p256_table.go
    23  
    24  //go:embed p256_asm_table.bin
    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  	// See FIPS 186-3, section D.2.3
    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  // 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 *[12]uint64, table string, 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 (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  	// (This is one, in the Montgomery domain.)
   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  	// (This is one, in the Montgomery domain.)
   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  	// precomp is a table of precomputed points that stores powers of p
   453  	// from p^1 to p^16.
   454  	var precomp [16 * 4 * 3]uint64
   455  	var t0, t1, t2, t3 p256Point
   456  
   457  	// Prepare the table
   458  	p.p256StorePoint(&precomp, 0) // 1
   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)  // 2
   465  	t1.p256StorePoint(&precomp, 3)  // 4
   466  	t2.p256StorePoint(&precomp, 7)  // 8
   467  	t3.p256StorePoint(&precomp, 15) // 16
   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) // 3
   473  	t1.p256StorePoint(&precomp, 4) // 5
   474  	t2.p256StorePoint(&precomp, 8) // 9
   475  
   476  	p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
   477  	p256PointDoubleAsm(t1.xyz[:], t1.xyz[:])
   478  	t0.p256StorePoint(&precomp, 5) // 6
   479  	t1.p256StorePoint(&precomp, 9) // 10
   480  
   481  	p256PointAddAsm(t2.xyz[:], t0.xyz[:], p.xyz[:])
   482  	p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
   483  	t2.p256StorePoint(&precomp, 6)  // 7
   484  	t1.p256StorePoint(&precomp, 10) // 11
   485  
   486  	p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
   487  	p256PointDoubleAsm(t2.xyz[:], t2.xyz[:])
   488  	t0.p256StorePoint(&precomp, 11) // 12
   489  	t2.p256StorePoint(&precomp, 13) // 14
   490  
   491  	p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
   492  	p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
   493  	t0.p256StorePoint(&precomp, 12) // 13
   494  	t2.p256StorePoint(&precomp, 14) // 15
   495  
   496  	// Start scanning the window from top bit
   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