...

Source file src/crypto/elliptic/p256_asm.go

Documentation: crypto/elliptic

		 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  // +build amd64 arm64
		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  	// See FIPS 186-3, section D.2.3
		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  // Functions implemented in p256_asm_*64.s
		50  // Montgomery multiplication modulo P256
		51  //go:noescape
		52  func p256Mul(res, in1, in2 []uint64)
		53  
		54  // Montgomery square modulo P256, repeated n times (n >= 1)
		55  //go:noescape
		56  func p256Sqr(res, in []uint64, n int)
		57  
		58  // Montgomery multiplication by 1
		59  //go:noescape
		60  func p256FromMont(res, in []uint64)
		61  
		62  // iff cond == 1	val <- -val
		63  //go:noescape
		64  func p256NegCond(val []uint64, cond int)
		65  
		66  // if cond == 0 res <- b; else res <- a
		67  //go:noescape
		68  func p256MovCond(res, a, b []uint64, cond int)
		69  
		70  // Endianness swap
		71  //go:noescape
		72  func p256BigToLittle(res []uint64, in []byte)
		73  
		74  //go:noescape
		75  func p256LittleToBig(res []byte, in []uint64)
		76  
		77  // Constant time table access
		78  //go:noescape
		79  func p256Select(point, table []uint64, idx int)
		80  
		81  //go:noescape
		82  func p256SelectBase(point, table []uint64, idx int)
		83  
		84  // Montgomery multiplication modulo Ord(G)
		85  //go:noescape
		86  func p256OrdMul(res, in1, in2 []uint64)
		87  
		88  // Montgomery square modulo Ord(G), repeated n times
		89  //go:noescape
		90  func p256OrdSqr(res, in []uint64, n int)
		91  
		92  // Point add with in2 being affine point
		93  // If sign == 1 -> in2 = -in2
		94  // If sel == 0 -> res = in1
		95  // if zero == 0 -> res = in2
		96  //go:noescape
		97  func p256PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int)
		98  
		99  // Point add. Returns one if the two input points were equal and zero
	 100  // otherwise. (Note that, due to the way that the equations work out, some
	 101  // representations of ∞ are considered equal to everything by this function.)
	 102  //go:noescape
	 103  func p256PointAddAsm(res, in1, in2 []uint64) int
	 104  
	 105  // Point double
	 106  //go:noescape
	 107  func p256PointDoubleAsm(res, in []uint64)
	 108  
	 109  func (curve p256Curve) Inverse(k *big.Int) *big.Int {
	 110  	if k.Sign() < 0 {
	 111  		// This should never happen.
	 112  		k = new(big.Int).Neg(k)
	 113  	}
	 114  
	 115  	if k.Cmp(p256.N) >= 0 {
	 116  		// This should never happen.
	 117  		k = new(big.Int).Mod(k, p256.N)
	 118  	}
	 119  
	 120  	// table will store precomputed powers of x.
	 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  	// This code operates in the Montgomery domain where R = 2^256 mod n
	 136  	// and n is the order of the scalar field. (See initP256 for the
	 137  	// value.) Elements in the Montgomery domain take the form a×R and
	 138  	// multiplication of x and y in the calculates (x × y × R^-1) mod n. RR
	 139  	// is R×R mod n thus the Montgomery multiplication x and RR gives x×R,
	 140  	// i.e. converts x into the Montgomery domain.
	 141  	// Window values borrowed from https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion
	 142  	RR := []uint64{0x83244c95be79eea2, 0x4699799c49bd6fa6, 0x2845b2392b6bec59, 0x66e12d94f3d95620}
	 143  	p256OrdMul(_1, x, RR)			// _1
	 144  	p256OrdSqr(x, _1, 1)			 // _10
	 145  	p256OrdMul(_11, x, _1)		 // _11
	 146  	p256OrdMul(_101, x, _11)	 // _101
	 147  	p256OrdMul(_111, x, _101)	// _111
	 148  	p256OrdSqr(x, _101, 1)		 // _1010
	 149  	p256OrdMul(_1111, _101, x) // _1111
	 150  
	 151  	p256OrdSqr(t, x, 1)					// _10100
	 152  	p256OrdMul(_10101, t, _1)		// _10101
	 153  	p256OrdSqr(x, _10101, 1)		 // _101010
	 154  	p256OrdMul(_101111, _101, x) // _101111
	 155  	p256OrdMul(x, _10101, x)		 // _111111 = x6
	 156  	p256OrdSqr(t, x, 2)					// _11111100
	 157  	p256OrdMul(t, t, _11)				// _11111111 = x8
	 158  	p256OrdSqr(x, t, 8)					// _ff00
	 159  	p256OrdMul(x, x, t)					// _ffff = x16
	 160  	p256OrdSqr(t, x, 16)				 // _ffff0000
	 161  	p256OrdMul(t, t, x)					// _ffffffff = x32
	 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  	// Multiplying by one in the Montgomery domain converts a Montgomery
	 187  	// value out of the domain.
	 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  // fromBig converts a *big.Int into a format used by this code.
	 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  // p256GetScalar endian-swaps the big-endian scalar value from in and writes it
	 208  // to out. If the scalar is equal or greater than the order of the group, it's
	 209  // reduced modulo that order.
	 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  // p256Mul operates in a Montgomery domain with R = 2^256 mod p, where p is the
	 220  // underlying field of the curve. (See initP256 for the value.) Thus rr here is
	 221  // R×R mod p. See comment in Inverse about how this is used.
	 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  	// This sets r2's Z value to 1, in the Montgomery domain.
	 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  	// This sets r2's Z value to 1, in the Montgomery domain.
	 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  // uint64IsZero returns 1 if x is zero and zero otherwise.
	 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  // scalarIsZero returns 1 if scalar represents the zero value, and zero
	 304  // otherwise.
	 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  // CopyConditional copies overwrites p with src if v == 1, and leaves p
	 331  // unchanged if v == 0.
	 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  // p256Inverse sets out to in^-1 mod p.
	 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) // 3*p
	 352  
	 353  	p256Sqr(out, p2, 2)
	 354  	p256Mul(p4, out, p2) // f*p
	 355  
	 356  	p256Sqr(out, p4, 4)
	 357  	p256Mul(p8, out, p4) // ff*p
	 358  
	 359  	p256Sqr(out, p8, 8)
	 360  	p256Mul(p16, out, p8) // ffff*p
	 361  
	 362  	p256Sqr(out, p16, 16)
	 363  	p256Mul(p32, out, p16) // ffffffff*p
	 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  	// (This is one, in the Montgomery domain.)
	 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  	// (This is one, in the Montgomery domain.)
	 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  	// precomp is a table of precomputed points that stores powers of p
	 448  	// from p^1 to p^16.
	 449  	var precomp [16 * 4 * 3]uint64
	 450  	var t0, t1, t2, t3 p256Point
	 451  
	 452  	// Prepare the table
	 453  	p.p256StorePoint(&precomp, 0) // 1
	 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)	// 2
	 460  	t1.p256StorePoint(&precomp, 3)	// 4
	 461  	t2.p256StorePoint(&precomp, 7)	// 8
	 462  	t3.p256StorePoint(&precomp, 15) // 16
	 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) // 3
	 468  	t1.p256StorePoint(&precomp, 4) // 5
	 469  	t2.p256StorePoint(&precomp, 8) // 9
	 470  
	 471  	p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
	 472  	p256PointDoubleAsm(t1.xyz[:], t1.xyz[:])
	 473  	t0.p256StorePoint(&precomp, 5) // 6
	 474  	t1.p256StorePoint(&precomp, 9) // 10
	 475  
	 476  	p256PointAddAsm(t2.xyz[:], t0.xyz[:], p.xyz[:])
	 477  	p256PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
	 478  	t2.p256StorePoint(&precomp, 6)	// 7
	 479  	t1.p256StorePoint(&precomp, 10) // 11
	 480  
	 481  	p256PointDoubleAsm(t0.xyz[:], t0.xyz[:])
	 482  	p256PointDoubleAsm(t2.xyz[:], t2.xyz[:])
	 483  	t0.p256StorePoint(&precomp, 11) // 12
	 484  	t2.p256StorePoint(&precomp, 13) // 14
	 485  
	 486  	p256PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
	 487  	p256PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
	 488  	t0.p256StorePoint(&precomp, 12) // 13
	 489  	t2.p256StorePoint(&precomp, 14) // 15
	 490  
	 491  	// Start scanning the window from top bit
	 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