Source file src/crypto/elliptic/p256_s390x.go

     1  // Copyright 2016 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  //go:build s390x
     6  
     7  package elliptic
     8  
     9  import (
    10  	"crypto/subtle"
    11  	"internal/cpu"
    12  	"math/big"
    13  	"unsafe"
    14  )
    15  
    16  const (
    17  	offsetS390xHasVX  = unsafe.Offsetof(cpu.S390X.HasVX)
    18  	offsetS390xHasVE1 = unsafe.Offsetof(cpu.S390X.HasVXE)
    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  //go:noescape
    37  func p256MulInternalTrampolineSetup()
    38  
    39  //go:noescape
    40  func p256SqrInternalTrampolineSetup()
    41  
    42  //go:noescape
    43  func p256MulInternalVX()
    44  
    45  //go:noescape
    46  func p256MulInternalVMSL()
    47  
    48  //go:noescape
    49  func p256SqrInternalVX()
    50  
    51  //go:noescape
    52  func p256SqrInternalVMSL()
    53  
    54  func initP256Arch() {
    55  	if cpu.S390X.HasVX {
    56  		p256 = p256CurveFast{p256Params}
    57  		initTable()
    58  		return
    59  	}
    60  
    61  	// No vector support, use pure Go implementation.
    62  	p256 = p256Curve{p256Params}
    63  	return
    64  }
    65  
    66  func (curve p256CurveFast) Params() *CurveParams {
    67  	return curve.CurveParams
    68  }
    69  
    70  // Functions implemented in p256_asm_s390x.s
    71  // Montgomery multiplication modulo P256
    72  //
    73  //go:noescape
    74  func p256SqrAsm(res, in1 []byte)
    75  
    76  //go:noescape
    77  func p256MulAsm(res, in1, in2 []byte)
    78  
    79  // Montgomery square modulo P256
    80  func p256Sqr(res, in []byte) {
    81  	p256SqrAsm(res, in)
    82  }
    83  
    84  // Montgomery multiplication by 1
    85  //
    86  //go:noescape
    87  func p256FromMont(res, in []byte)
    88  
    89  // iff cond == 1  val <- -val
    90  //
    91  //go:noescape
    92  func p256NegCond(val *p256Point, cond int)
    93  
    94  // if cond == 0 res <- b; else res <- a
    95  //
    96  //go:noescape
    97  func p256MovCond(res, a, b *p256Point, cond int)
    98  
    99  // Constant time table access
   100  //
   101  //go:noescape
   102  func p256Select(point *p256Point, table []p256Point, idx int)
   103  
   104  //go:noescape
   105  func p256SelectBase(point *p256Point, table []p256Point, idx int)
   106  
   107  // Montgomery multiplication modulo Ord(G)
   108  //
   109  //go:noescape
   110  func p256OrdMul(res, in1, in2 []byte)
   111  
   112  // Montgomery square modulo Ord(G), repeated n times
   113  func p256OrdSqr(res, in []byte, n int) {
   114  	copy(res, in)
   115  	for i := 0; i < n; i += 1 {
   116  		p256OrdMul(res, res, res)
   117  	}
   118  }
   119  
   120  // Point add with P2 being affine point
   121  // If sign == 1 -> P2 = -P2
   122  // If sel == 0 -> P3 = P1
   123  // if zero == 0 -> P3 = P2
   124  //
   125  //go:noescape
   126  func p256PointAddAffineAsm(P3, P1, P2 *p256Point, sign, sel, zero int)
   127  
   128  // Point add
   129  //
   130  //go:noescape
   131  func p256PointAddAsm(P3, P1, P2 *p256Point) int
   132  
   133  //go:noescape
   134  func p256PointDoubleAsm(P3, P1 *p256Point)
   135  
   136  func (curve p256CurveFast) Inverse(k *big.Int) *big.Int {
   137  	if k.Cmp(p256Params.N) >= 0 {
   138  		// This should never happen.
   139  		reducedK := new(big.Int).Mod(k, p256Params.N)
   140  		k = reducedK
   141  	}
   142  
   143  	// table will store precomputed powers of x. The 32 bytes at index
   144  	// i store x^(i+1).
   145  	var table [15][32]byte
   146  
   147  	x := fromBig(k)
   148  	// This code operates in the Montgomery domain where R = 2^256 mod n
   149  	// and n is the order of the scalar field. (See initP256 for the
   150  	// value.) Elements in the Montgomery domain take the form a×R and
   151  	// multiplication of x and y in the calculates (x × y × R^-1) mod n. RR
   152  	// is R×R mod n thus the Montgomery multiplication x and RR gives x×R,
   153  	// i.e. converts x into the Montgomery domain. Stored in BigEndian form
   154  	RR := []byte{0x66, 0xe1, 0x2d, 0x94, 0xf3, 0xd9, 0x56, 0x20, 0x28, 0x45, 0xb2, 0x39, 0x2b, 0x6b, 0xec, 0x59,
   155  		0x46, 0x99, 0x79, 0x9c, 0x49, 0xbd, 0x6f, 0xa6, 0x83, 0x24, 0x4c, 0x95, 0xbe, 0x79, 0xee, 0xa2}
   156  
   157  	p256OrdMul(table[0][:], x, RR)
   158  
   159  	// Prepare the table, no need in constant time access, because the
   160  	// power is not a secret. (Entry 0 is never used.)
   161  	for i := 2; i < 16; i += 2 {
   162  		p256OrdSqr(table[i-1][:], table[(i/2)-1][:], 1)
   163  		p256OrdMul(table[i][:], table[i-1][:], table[0][:])
   164  	}
   165  
   166  	copy(x, table[14][:]) // f
   167  
   168  	p256OrdSqr(x[0:32], x[0:32], 4)
   169  	p256OrdMul(x[0:32], x[0:32], table[14][:]) // ff
   170  	t := make([]byte, 32)
   171  	copy(t, x)
   172  
   173  	p256OrdSqr(x, x, 8)
   174  	p256OrdMul(x, x, t) // ffff
   175  	copy(t, x)
   176  
   177  	p256OrdSqr(x, x, 16)
   178  	p256OrdMul(x, x, t) // ffffffff
   179  	copy(t, x)
   180  
   181  	p256OrdSqr(x, x, 64) // ffffffff0000000000000000
   182  	p256OrdMul(x, x, t)  // ffffffff00000000ffffffff
   183  	p256OrdSqr(x, x, 32) // ffffffff00000000ffffffff00000000
   184  	p256OrdMul(x, x, t)  // ffffffff00000000ffffffffffffffff
   185  
   186  	// Remaining 32 windows
   187  	expLo := [32]byte{0xb, 0xc, 0xe, 0x6, 0xf, 0xa, 0xa, 0xd, 0xa, 0x7, 0x1, 0x7, 0x9, 0xe, 0x8, 0x4,
   188  		0xf, 0x3, 0xb, 0x9, 0xc, 0xa, 0xc, 0x2, 0xf, 0xc, 0x6, 0x3, 0x2, 0x5, 0x4, 0xf}
   189  	for i := 0; i < 32; i++ {
   190  		p256OrdSqr(x, x, 4)
   191  		p256OrdMul(x, x, table[expLo[i]-1][:])
   192  	}
   193  
   194  	// Multiplying by one in the Montgomery domain converts a Montgomery
   195  	// value out of the domain.
   196  	one := []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
   197  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
   198  	p256OrdMul(x, x, one)
   199  
   200  	return new(big.Int).SetBytes(x)
   201  }
   202  
   203  // fromBig converts a *big.Int into a format used by this code.
   204  func fromBig(big *big.Int) []byte {
   205  	// This could be done a lot more efficiently...
   206  	res := big.Bytes()
   207  	if 32 == len(res) {
   208  		return res
   209  	}
   210  	t := make([]byte, 32)
   211  	offset := 32 - len(res)
   212  	for i := len(res) - 1; i >= 0; i-- {
   213  		t[i+offset] = res[i]
   214  	}
   215  	return t
   216  }
   217  
   218  // p256GetMultiplier makes sure byte array will have 32 byte elements, If the scalar
   219  // is equal or greater than the order of the group, it's reduced modulo that order.
   220  func p256GetMultiplier(in []byte) []byte {
   221  	n := new(big.Int).SetBytes(in)
   222  
   223  	if n.Cmp(p256Params.N) >= 0 {
   224  		n.Mod(n, p256Params.N)
   225  	}
   226  	return fromBig(n)
   227  }
   228  
   229  // p256MulAsm operates in a Montgomery domain with R = 2^256 mod p, where p is the
   230  // underlying field of the curve. (See initP256 for the value.) Thus rr here is
   231  // R×R mod p. See comment in Inverse about how this is used.
   232  var rr = []byte{0x00, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe,
   233  	0xff, 0xff, 0xff, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
   234  
   235  // (This is one, in the Montgomery domain.)
   236  var one = []byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   237  	0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
   238  
   239  func maybeReduceModP(in *big.Int) *big.Int {
   240  	if in.Cmp(p256Params.P) < 0 {
   241  		return in
   242  	}
   243  	return new(big.Int).Mod(in, p256Params.P)
   244  }
   245  
   246  func (curve p256CurveFast) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
   247  	var r1, r2 p256Point
   248  	scalarReduced := p256GetMultiplier(baseScalar)
   249  	r1IsInfinity := scalarIsZero(scalarReduced)
   250  	r1.p256BaseMult(scalarReduced)
   251  
   252  	copy(r2.x[:], fromBig(maybeReduceModP(bigX)))
   253  	copy(r2.y[:], fromBig(maybeReduceModP(bigY)))
   254  	copy(r2.z[:], one)
   255  	p256MulAsm(r2.x[:], r2.x[:], rr[:])
   256  	p256MulAsm(r2.y[:], r2.y[:], rr[:])
   257  
   258  	scalarReduced = p256GetMultiplier(scalar)
   259  	r2IsInfinity := scalarIsZero(scalarReduced)
   260  	r2.p256ScalarMult(p256GetMultiplier(scalar))
   261  
   262  	var sum, double p256Point
   263  	pointsEqual := p256PointAddAsm(&sum, &r1, &r2)
   264  	p256PointDoubleAsm(&double, &r1)
   265  	p256MovCond(&sum, &double, &sum, pointsEqual)
   266  	p256MovCond(&sum, &r1, &sum, r2IsInfinity)
   267  	p256MovCond(&sum, &r2, &sum, r1IsInfinity)
   268  	return sum.p256PointToAffine()
   269  }
   270  
   271  func (curve p256CurveFast) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
   272  	var r p256Point
   273  	r.p256BaseMult(p256GetMultiplier(scalar))
   274  	return r.p256PointToAffine()
   275  }
   276  
   277  func (curve p256CurveFast) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
   278  	var r p256Point
   279  	copy(r.x[:], fromBig(maybeReduceModP(bigX)))
   280  	copy(r.y[:], fromBig(maybeReduceModP(bigY)))
   281  	copy(r.z[:], one)
   282  	p256MulAsm(r.x[:], r.x[:], rr[:])
   283  	p256MulAsm(r.y[:], r.y[:], rr[:])
   284  	r.p256ScalarMult(p256GetMultiplier(scalar))
   285  	return r.p256PointToAffine()
   286  }
   287  
   288  // scalarIsZero returns 1 if scalar represents the zero value, and zero
   289  // otherwise.
   290  func scalarIsZero(scalar []byte) int {
   291  	b := byte(0)
   292  	for _, s := range scalar {
   293  		b |= s
   294  	}
   295  	return subtle.ConstantTimeByteEq(b, 0)
   296  }
   297  
   298  func (p *p256Point) p256PointToAffine() (x, y *big.Int) {
   299  	zInv := make([]byte, 32)
   300  	zInvSq := make([]byte, 32)
   301  
   302  	p256Inverse(zInv, p.z[:])
   303  	p256Sqr(zInvSq, zInv)
   304  	p256MulAsm(zInv, zInv, zInvSq)
   305  
   306  	p256MulAsm(zInvSq, p.x[:], zInvSq)
   307  	p256MulAsm(zInv, p.y[:], zInv)
   308  
   309  	p256FromMont(zInvSq, zInvSq)
   310  	p256FromMont(zInv, zInv)
   311  
   312  	return new(big.Int).SetBytes(zInvSq), new(big.Int).SetBytes(zInv)
   313  }
   314  
   315  // p256Inverse sets out to in^-1 mod p.
   316  func p256Inverse(out, in []byte) {
   317  	var stack [6 * 32]byte
   318  	p2 := stack[32*0 : 32*0+32]
   319  	p4 := stack[32*1 : 32*1+32]
   320  	p8 := stack[32*2 : 32*2+32]
   321  	p16 := stack[32*3 : 32*3+32]
   322  	p32 := stack[32*4 : 32*4+32]
   323  
   324  	p256Sqr(out, in)
   325  	p256MulAsm(p2, out, in) // 3*p
   326  
   327  	p256Sqr(out, p2)
   328  	p256Sqr(out, out)
   329  	p256MulAsm(p4, out, p2) // f*p
   330  
   331  	p256Sqr(out, p4)
   332  	p256Sqr(out, out)
   333  	p256Sqr(out, out)
   334  	p256Sqr(out, out)
   335  	p256MulAsm(p8, out, p4) // ff*p
   336  
   337  	p256Sqr(out, p8)
   338  
   339  	for i := 0; i < 7; i++ {
   340  		p256Sqr(out, out)
   341  	}
   342  	p256MulAsm(p16, out, p8) // ffff*p
   343  
   344  	p256Sqr(out, p16)
   345  	for i := 0; i < 15; i++ {
   346  		p256Sqr(out, out)
   347  	}
   348  	p256MulAsm(p32, out, p16) // ffffffff*p
   349  
   350  	p256Sqr(out, p32)
   351  
   352  	for i := 0; i < 31; i++ {
   353  		p256Sqr(out, out)
   354  	}
   355  	p256MulAsm(out, out, in)
   356  
   357  	for i := 0; i < 32*4; i++ {
   358  		p256Sqr(out, out)
   359  	}
   360  	p256MulAsm(out, out, p32)
   361  
   362  	for i := 0; i < 32; i++ {
   363  		p256Sqr(out, out)
   364  	}
   365  	p256MulAsm(out, out, p32)
   366  
   367  	for i := 0; i < 16; i++ {
   368  		p256Sqr(out, out)
   369  	}
   370  	p256MulAsm(out, out, p16)
   371  
   372  	for i := 0; i < 8; i++ {
   373  		p256Sqr(out, out)
   374  	}
   375  	p256MulAsm(out, out, p8)
   376  
   377  	p256Sqr(out, out)
   378  	p256Sqr(out, out)
   379  	p256Sqr(out, out)
   380  	p256Sqr(out, out)
   381  	p256MulAsm(out, out, p4)
   382  
   383  	p256Sqr(out, out)
   384  	p256Sqr(out, out)
   385  	p256MulAsm(out, out, p2)
   386  
   387  	p256Sqr(out, out)
   388  	p256Sqr(out, out)
   389  	p256MulAsm(out, out, in)
   390  }
   391  
   392  func boothW5(in uint) (int, int) {
   393  	var s uint = ^((in >> 5) - 1)
   394  	var d uint = (1 << 6) - in - 1
   395  	d = (d & s) | (in & (^s))
   396  	d = (d >> 1) + (d & 1)
   397  	return int(d), int(s & 1)
   398  }
   399  
   400  func boothW7(in uint) (int, int) {
   401  	var s uint = ^((in >> 7) - 1)
   402  	var d uint = (1 << 8) - in - 1
   403  	d = (d & s) | (in & (^s))
   404  	d = (d >> 1) + (d & 1)
   405  	return int(d), int(s & 1)
   406  }
   407  
   408  func initTable() {
   409  	p256PreFast = new([37][64]p256Point) //z coordinate not used
   410  	basePoint := p256Point{
   411  		x: [32]byte{0x18, 0x90, 0x5f, 0x76, 0xa5, 0x37, 0x55, 0xc6, 0x79, 0xfb, 0x73, 0x2b, 0x77, 0x62, 0x25, 0x10,
   412  			0x75, 0xba, 0x95, 0xfc, 0x5f, 0xed, 0xb6, 0x01, 0x79, 0xe7, 0x30, 0xd4, 0x18, 0xa9, 0x14, 0x3c}, //(p256.x*2^256)%p
   413  		y: [32]byte{0x85, 0x71, 0xff, 0x18, 0x25, 0x88, 0x5d, 0x85, 0xd2, 0xe8, 0x86, 0x88, 0xdd, 0x21, 0xf3, 0x25,
   414  			0x8b, 0x4a, 0xb8, 0xe4, 0xba, 0x19, 0xe4, 0x5c, 0xdd, 0xf2, 0x53, 0x57, 0xce, 0x95, 0x56, 0x0a}, //(p256.y*2^256)%p
   415  		z: [32]byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
   416  			0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}, //(p256.z*2^256)%p
   417  	}
   418  
   419  	t1 := new(p256Point)
   420  	t2 := new(p256Point)
   421  	*t2 = basePoint
   422  
   423  	zInv := make([]byte, 32)
   424  	zInvSq := make([]byte, 32)
   425  	for j := 0; j < 64; j++ {
   426  		*t1 = *t2
   427  		for i := 0; i < 37; i++ {
   428  			// The window size is 7 so we need to double 7 times.
   429  			if i != 0 {
   430  				for k := 0; k < 7; k++ {
   431  					p256PointDoubleAsm(t1, t1)
   432  				}
   433  			}
   434  			// Convert the point to affine form. (Its values are
   435  			// still in Montgomery form however.)
   436  			p256Inverse(zInv, t1.z[:])
   437  			p256Sqr(zInvSq, zInv)
   438  			p256MulAsm(zInv, zInv, zInvSq)
   439  
   440  			p256MulAsm(t1.x[:], t1.x[:], zInvSq)
   441  			p256MulAsm(t1.y[:], t1.y[:], zInv)
   442  
   443  			copy(t1.z[:], basePoint.z[:])
   444  			// Update the table entry
   445  			copy(p256PreFast[i][j].x[:], t1.x[:])
   446  			copy(p256PreFast[i][j].y[:], t1.y[:])
   447  		}
   448  		if j == 0 {
   449  			p256PointDoubleAsm(t2, &basePoint)
   450  		} else {
   451  			p256PointAddAsm(t2, t2, &basePoint)
   452  		}
   453  	}
   454  }
   455  
   456  func (p *p256Point) p256BaseMult(scalar []byte) {
   457  	wvalue := (uint(scalar[31]) << 1) & 0xff
   458  	sel, sign := boothW7(uint(wvalue))
   459  	p256SelectBase(p, p256PreFast[0][:], sel)
   460  	p256NegCond(p, sign)
   461  
   462  	copy(p.z[:], one[:])
   463  	var t0 p256Point
   464  
   465  	copy(t0.z[:], one[:])
   466  
   467  	index := uint(6)
   468  	zero := sel
   469  
   470  	for i := 1; i < 37; i++ {
   471  		if index < 247 {
   472  			wvalue = ((uint(scalar[31-index/8]) >> (index % 8)) + (uint(scalar[31-index/8-1]) << (8 - (index % 8)))) & 0xff
   473  		} else {
   474  			wvalue = (uint(scalar[31-index/8]) >> (index % 8)) & 0xff
   475  		}
   476  		index += 7
   477  		sel, sign = boothW7(uint(wvalue))
   478  		p256SelectBase(&t0, p256PreFast[i][:], sel)
   479  		p256PointAddAffineAsm(p, p, &t0, sign, sel, zero)
   480  		zero |= sel
   481  	}
   482  }
   483  
   484  func (p *p256Point) p256ScalarMult(scalar []byte) {
   485  	// precomp is a table of precomputed points that stores powers of p
   486  	// from p^1 to p^16.
   487  	var precomp [16]p256Point
   488  	var t0, t1, t2, t3 p256Point
   489  
   490  	// Prepare the table
   491  	*&precomp[0] = *p
   492  
   493  	p256PointDoubleAsm(&t0, p)
   494  	p256PointDoubleAsm(&t1, &t0)
   495  	p256PointDoubleAsm(&t2, &t1)
   496  	p256PointDoubleAsm(&t3, &t2)
   497  	*&precomp[1] = t0  // 2
   498  	*&precomp[3] = t1  // 4
   499  	*&precomp[7] = t2  // 8
   500  	*&precomp[15] = t3 // 16
   501  
   502  	p256PointAddAsm(&t0, &t0, p)
   503  	p256PointAddAsm(&t1, &t1, p)
   504  	p256PointAddAsm(&t2, &t2, p)
   505  	*&precomp[2] = t0 // 3
   506  	*&precomp[4] = t1 // 5
   507  	*&precomp[8] = t2 // 9
   508  
   509  	p256PointDoubleAsm(&t0, &t0)
   510  	p256PointDoubleAsm(&t1, &t1)
   511  	*&precomp[5] = t0 // 6
   512  	*&precomp[9] = t1 // 10
   513  
   514  	p256PointAddAsm(&t2, &t0, p)
   515  	p256PointAddAsm(&t1, &t1, p)
   516  	*&precomp[6] = t2  // 7
   517  	*&precomp[10] = t1 // 11
   518  
   519  	p256PointDoubleAsm(&t0, &t0)
   520  	p256PointDoubleAsm(&t2, &t2)
   521  	*&precomp[11] = t0 // 12
   522  	*&precomp[13] = t2 // 14
   523  
   524  	p256PointAddAsm(&t0, &t0, p)
   525  	p256PointAddAsm(&t2, &t2, p)
   526  	*&precomp[12] = t0 // 13
   527  	*&precomp[14] = t2 // 15
   528  
   529  	// Start scanning the window from top bit
   530  	index := uint(254)
   531  	var sel, sign int
   532  
   533  	wvalue := (uint(scalar[31-index/8]) >> (index % 8)) & 0x3f
   534  	sel, _ = boothW5(uint(wvalue))
   535  	p256Select(p, precomp[:], sel)
   536  	zero := sel
   537  
   538  	for index > 4 {
   539  		index -= 5
   540  		p256PointDoubleAsm(p, p)
   541  		p256PointDoubleAsm(p, p)
   542  		p256PointDoubleAsm(p, p)
   543  		p256PointDoubleAsm(p, p)
   544  		p256PointDoubleAsm(p, p)
   545  
   546  		if index < 247 {
   547  			wvalue = ((uint(scalar[31-index/8]) >> (index % 8)) + (uint(scalar[31-index/8-1]) << (8 - (index % 8)))) & 0x3f
   548  		} else {
   549  			wvalue = (uint(scalar[31-index/8]) >> (index % 8)) & 0x3f
   550  		}
   551  
   552  		sel, sign = boothW5(uint(wvalue))
   553  
   554  		p256Select(&t0, precomp[:], sel)
   555  		p256NegCond(&t0, sign)
   556  		p256PointAddAsm(&t1, p, &t0)
   557  		p256MovCond(&t1, &t1, p, sel)
   558  		p256MovCond(p, &t1, &t0, zero)
   559  		zero |= sel
   560  	}
   561  
   562  	p256PointDoubleAsm(p, p)
   563  	p256PointDoubleAsm(p, p)
   564  	p256PointDoubleAsm(p, p)
   565  	p256PointDoubleAsm(p, p)
   566  	p256PointDoubleAsm(p, p)
   567  
   568  	wvalue = (uint(scalar[31]) << 1) & 0x3f
   569  	sel, sign = boothW5(uint(wvalue))
   570  
   571  	p256Select(&t0, precomp[:], sel)
   572  	p256NegCond(&t0, sign)
   573  	p256PointAddAsm(&t1, p, &t0)
   574  	p256MovCond(&t1, &t1, p, sel)
   575  	p256MovCond(p, &t1, &t0, zero)
   576  }
   577  

View as plain text