github.com/hellobchain/newcryptosm@v0.0.0-20221019060107-edb949a317e9/sm2/sm2_amd64.go (about)

     1  // This file contains the Go wrapper for the constant-time, 64-bit assembly
     2  // implementation of SM2. The optimizations performed here are described in
     3  // detail in:
     4  // S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with
     5  //                          256-bit primes"
     6  // http://link.springer.com/article/10.1007%2Fs13389-014-0090-x
     7  // https://eprint.iacr.org/2013/816.pdf
     8  
     9  //go:build amd64
    10  // +build amd64
    11  
    12  package sm2
    13  
    14  import (
    15  	"crypto/elliptic"
    16  	"math/big"
    17  	"sync"
    18  )
    19  
    20  type (
    21  	sm2Curve struct {
    22  		*elliptic.CurveParams
    23  	}
    24  
    25  	sm2Point struct {
    26  		xyz [12]uint64
    27  	}
    28  )
    29  
    30  var (
    31  	sm2            sm2Curve
    32  	sm2Precomputed *[43][32 * 8]uint64
    33  	sm2precomputeOnce sync.Once
    34  )
    35  
    36  func initSM2() {
    37  	sm2.CurveParams = &elliptic.CurveParams{Name: "SM2"}
    38  	sm2.P, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF", 16)
    39  	sm2.N, _ = new(big.Int).SetString("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123", 16)
    40  	sm2.B, _ = new(big.Int).SetString("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93", 16)
    41  	sm2.Gx, _ = new(big.Int).SetString("32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16)
    42  	sm2.Gy, _ = new(big.Int).SetString("BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16)
    43  	sm2.BitSize = 256
    44  	return
    45  }
    46  
    47  func (curve sm2Curve) Params() *elliptic.CurveParams {
    48  	return curve.CurveParams
    49  }
    50  
    51  // Functions implemented in sm2_asm_amd64.s
    52  // Montgomery multiplication modulo sm2
    53  //go:noescape
    54  func sm2Mul(res, in1, in2 []uint64)
    55  
    56  // Montgomery square modulo sm2, repeated n times (n >= 1)
    57  //go:noescape
    58  func sm2Sqr(res, in []uint64, n int)
    59  
    60  // Montgomery multiplication by 1
    61  //go:noescape
    62  func sm2FromMont(res, in []uint64)
    63  
    64  // iff cond == 1  val <- -val
    65  //go:noescape
    66  func sm2NegCond(val []uint64, cond int)
    67  
    68  // if cond == 0 res <- b; else res <- a
    69  //go:noescape
    70  func sm2MovCond(res, a, b []uint64, cond int)
    71  
    72  // Endianness swap
    73  //go:noescape
    74  func sm2BigToLittle(res []uint64, in []byte)
    75  
    76  //go:noescape
    77  func sm2LittleToBig(res []byte, in []uint64)
    78  
    79  // Constant time table access
    80  //go:noescape
    81  func sm2Select(point, table []uint64, idx int)
    82  
    83  //go:noescape
    84  func sm2SelectBase(point, table []uint64, idx int)
    85  
    86  // Montgomery multiplication modulo Ord(G)
    87  //go:noescape
    88  func sm2OrdMul(res, in1, in2 []uint64)
    89  
    90  // Montgomery square modulo Ord(G), repeated n times
    91  //go:noescape
    92  func sm2OrdSqr(res, in []uint64, n int)
    93  
    94  // Point add with in2 being affine point
    95  // If sign == 1 -> in2 = -in2
    96  // If sel == 0 -> res = in1
    97  // if zero == 0 -> res = in2
    98  //go:noescape
    99  func sm2PointAddAffineAsm(res, in1, in2 []uint64, sign, sel, zero int)
   100  
   101  // Point add. Returns one if the two input points were equal and zero
   102  // otherwise. (Note that, due to the way that the equations work out, some
   103  // representations of ∞ are considered equal to everything by this function.)
   104  //go:noescape
   105  func sm2PointAddAsm(res, in1, in2 []uint64) int
   106  
   107  // Point double
   108  //go:noescape
   109  func sm2PointDoubleAsm(res, in []uint64)
   110  
   111  func (curve sm2Curve) Inverse(k *big.Int) *big.Int {
   112  	if k.Sign() < 0 {
   113  		// This should never happen.
   114  		k = new(big.Int).Neg(k)
   115  	}
   116  
   117  	if k.Cmp(sm2.N) >= 0 {
   118  		// This should never happen.
   119  		k = new(big.Int).Mod(k, sm2.N)
   120  	}
   121  
   122  	// table will store precomputed powers of x. The four words at index
   123  	// 4×i store x^(i+1).
   124  	var table [4 * 15]uint64
   125  
   126  	x := make([]uint64, 4)
   127  	fromBig(x[:], k)
   128  	// This code operates in the Montgomery domain where R = 2^256 mod n
   129  	// and n is the order of the scalar field. (See initSM2 for the
   130  	// value.) Elements in the Montgomery domain take the form a×R and
   131  	// multiplication of x and y in the calculates (x × y × R^-1) mod n. RR
   132  	// is R×R mod n thus the Montgomery multiplication x and RR gives x×R,
   133  	// i.e. converts x into the Montgomery domain.
   134  	RR := []uint64{0x901192af7c114f20, 0x3464504ade6fa2fa, 0x620fc84c3affe0d4, 0x1eb5e412a22b3d3b}
   135  	sm2OrdMul(table[:4], x, RR)
   136  
   137  	// Prepare the table, no need in constant time access, because the
   138  	// power is not a secret. (Entry 0 is never used.)
   139  	for i := 2; i < 16; i += 2 {
   140  		sm2OrdSqr(table[4*(i-1):], table[4*((i/2)-1):], 1)
   141  		sm2OrdMul(table[4*i:], table[4*(i-1):], table[:4])
   142  	}
   143  
   144  	x[0] = table[4*14+0] // f
   145  	x[1] = table[4*14+1]
   146  	x[2] = table[4*14+2]
   147  	x[3] = table[4*14+3]
   148  
   149  	sm2OrdSqr(x, x, 4)
   150  	sm2OrdMul(x, x, table[4*14:4*14+4]) // ff
   151  	t := make([]uint64, 4, 4)
   152  	t[0] = x[0]
   153  	t[1] = x[1]
   154  	t[2] = x[2]
   155  	t[3] = x[3]
   156  
   157  	sm2OrdSqr(x, x, 8)
   158  	sm2OrdMul(x, x, t) // ffff
   159  
   160  	sm2OrdSqr(x, x, 8)
   161  	sm2OrdMul(x, x, t) // ffffff
   162  	t[0] = x[0]
   163  	t[1] = x[1]
   164  	t[2] = x[2]
   165  	t[3] = x[3]
   166  
   167  	sm2OrdSqr(x, x, 4)
   168  	sm2OrdMul(x, x, table[4*14:4*14+4]) // fffffff
   169  
   170  	sm2OrdSqr(x, x, 4)
   171  	sm2OrdMul(x, x, table[4*13:4*13+4]) // fffffffe
   172  
   173  	for i := 0; i < 4; i++ {
   174  		sm2OrdSqr(x, x, 24)
   175  		sm2OrdMul(x, x, t) // fffffffe_ffffff fffffffe_ffffffff_ffff fffffffe_ffffffff_ffffffff_ff fffffffe_ffffffff_ffffffff_ffffffff
   176  	}
   177  
   178  	// Remaining 32 windows
   179  	expLo := [32]byte{0x7, 0x2, 0x0, 0x3, 0xd, 0xf, 0x6, 0xb, 0x2, 0x1, 0xc, 0x6, 0x0, 0x5, 0x2, 0xb, 0x5, 0x3, 0xb, 0xb, 0xf, 0x4, 0x0, 0x9, 0x3, 0x9, 0xd, 0x5, 0x4, 0x1, 0x2, 0x1}
   180  	for i := 0; i < 32; i++ {
   181  		sm2OrdSqr(x, x, 4)
   182  		if expLo[i] != 0 {
   183  			sm2OrdMul(x, x, table[4*(expLo[i]-1):])
   184  		}
   185  	}
   186  
   187  	// Multiplying by one in the Montgomery domain converts a Montgomery
   188  	// value out of the domain.
   189  	one := []uint64{1, 0, 0, 0}
   190  	sm2OrdMul(x, x, one)
   191  
   192  	xOut := make([]byte, 32)
   193  	sm2LittleToBig(xOut, x)
   194  	return new(big.Int).SetBytes(xOut)
   195  }
   196  
   197  // fromBig converts a *big.Int into a format used by this code.
   198  func fromBig(out []uint64, big *big.Int) {
   199  	for i := range out {
   200  		out[i] = 0
   201  	}
   202  
   203  	for i, v := range big.Bits() {
   204  		out[i] = uint64(v)
   205  	}
   206  }
   207  
   208  // sm2GetScalar endian-swaps the big-endian scalar value from in and writes it
   209  // to out. If the scalar is equal or greater than the order of the group, it's
   210  // reduced modulo that order.
   211  func sm2GetScalar(out []uint64, in []byte) {
   212  	n := new(big.Int).SetBytes(in)
   213  
   214  	if n.Cmp(sm2.N) >= 0 {
   215  		n.Mod(n, sm2.N)
   216  	}
   217  	fromBig(out, n)
   218  }
   219  
   220  // sm2Mul operates in a Montgomery domain with R = 2^256 mod p, where p is the
   221  // underlying field of the curve. (See initSM2 for the value.) Thus rr here is
   222  // R×R mod p. See comment in Inverse about how this is used.
   223  var sm2rr = []uint64{0x0000000200000003, 0x00000002ffffffff, 0x0000000100000001, 0x0000000400000002}
   224  
   225  func maybeReduceModP(in *big.Int) *big.Int {
   226  	if in.Cmp(sm2.P) < 0 {
   227  		return in
   228  	}
   229  	return new(big.Int).Mod(in, sm2.P)
   230  }
   231  
   232  func (curve sm2Curve) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
   233  	scalarReversed := make([]uint64, 4)
   234  	var r1, r2 sm2Point
   235  	sm2GetScalar(scalarReversed, baseScalar)
   236  	r1IsInfinity := scalarIsZero(scalarReversed)
   237  	r1.sm2BaseMult(scalarReversed)
   238  
   239  	sm2GetScalar(scalarReversed, scalar)
   240  	r2IsInfinity := scalarIsZero(scalarReversed)
   241  	fromBig(r2.xyz[0:4], maybeReduceModP(bigX))
   242  	fromBig(r2.xyz[4:8], maybeReduceModP(bigY))
   243  	sm2Mul(r2.xyz[0:4], r2.xyz[0:4], sm2rr[:])
   244  	sm2Mul(r2.xyz[4:8], r2.xyz[4:8], sm2rr[:])
   245  
   246  	// This sets r2's Z value to 1, in the Montgomery domain.
   247  	r2.xyz[8] = 0x0000000000000001
   248  	r2.xyz[9] = 0x00000000ffffffff
   249  	r2.xyz[10] = 0x0000000000000000
   250  	r2.xyz[11] = 0x0000000100000000
   251  
   252  	r2.sm2ScalarMult(scalarReversed)
   253  
   254  	var sum, double sm2Point
   255  	pointsEqual := sm2PointAddAsm(sum.xyz[:], r1.xyz[:], r2.xyz[:])
   256  	sm2PointDoubleAsm(double.xyz[:], r1.xyz[:])
   257  	sum.CopyConditional(&double, pointsEqual)
   258  	sum.CopyConditional(&r1, r2IsInfinity)
   259  	sum.CopyConditional(&r2, r1IsInfinity)
   260  
   261  	return sum.sm2PointToAffine()
   262  }
   263  
   264  func (curve sm2Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {
   265  	scalarReversed := make([]uint64, 4)
   266  	sm2GetScalar(scalarReversed, scalar)
   267  
   268  	var r sm2Point
   269  	r.sm2BaseMult(scalarReversed)
   270  	return r.sm2PointToAffine()
   271  }
   272  
   273  func (curve sm2Curve) ScalarMult(bigX, bigY *big.Int, scalar []byte) (x, y *big.Int) {
   274  	scalarReversed := make([]uint64, 4)
   275  	sm2GetScalar(scalarReversed, scalar)
   276  
   277  	var r sm2Point
   278  	fromBig(r.xyz[0:4], maybeReduceModP(bigX))
   279  	fromBig(r.xyz[4:8], maybeReduceModP(bigY))
   280  	sm2Mul(r.xyz[0:4], r.xyz[0:4], sm2rr[:])
   281  	sm2Mul(r.xyz[4:8], r.xyz[4:8], sm2rr[:])
   282  	// This sets r2's Z value to 1, in the Montgomery domain.
   283  	r.xyz[8] = 0x0000000000000001
   284  	r.xyz[9] = 0x00000000ffffffff
   285  	r.xyz[10] = 0x0000000000000000
   286  	r.xyz[11] = 0x0000000100000000
   287  
   288  	r.sm2ScalarMult(scalarReversed)
   289  	return r.sm2PointToAffine()
   290  }
   291  
   292  // uint64IsZero returns 1 if x is zero and zero otherwise.
   293  func uint64IsZero(x uint64) int {
   294  	x = ^x
   295  	x &= x >> 32
   296  	x &= x >> 16
   297  	x &= x >> 8
   298  	x &= x >> 4
   299  	x &= x >> 2
   300  	x &= x >> 1
   301  	return int(x & 1)
   302  }
   303  
   304  // scalarIsZero returns 1 if scalar represents the zero value, and zero
   305  // otherwise.
   306  func scalarIsZero(scalar []uint64) int {
   307  	return uint64IsZero(scalar[0] | scalar[1] | scalar[2] | scalar[3])
   308  }
   309  
   310  func (p *sm2Point) sm2PointToAffine() (x, y *big.Int) {
   311  	zInv := make([]uint64, 4)
   312  	zInvSq := make([]uint64, 4)
   313  	sm2Inverse(zInv, p.xyz[8:12])
   314  	sm2Sqr(zInvSq, zInv, 1)
   315  	sm2Mul(zInv, zInv, zInvSq)
   316  
   317  	sm2Mul(zInvSq, p.xyz[0:4], zInvSq)
   318  	sm2Mul(zInv, p.xyz[4:8], zInv)
   319  
   320  	sm2FromMont(zInvSq, zInvSq)
   321  	sm2FromMont(zInv, zInv)
   322  
   323  	xOut := make([]byte, 32)
   324  	yOut := make([]byte, 32)
   325  	sm2LittleToBig(xOut, zInvSq)
   326  	sm2LittleToBig(yOut, zInv)
   327  
   328  	return new(big.Int).SetBytes(xOut), new(big.Int).SetBytes(yOut)
   329  }
   330  
   331  // CopyConditional copies overwrites p with src if v == 1, and leaves p
   332  // unchanged if v == 0.
   333  func (p *sm2Point) CopyConditional(src *sm2Point, v int) {
   334  	pMask := uint64(v) - 1
   335  	srcMask := ^pMask
   336  
   337  	for i, n := range p.xyz {
   338  		p.xyz[i] = (n & pMask) | (src.xyz[i] & srcMask)
   339  	}
   340  }
   341  
   342  // sm2Inverse sets out to in^-1 mod p.
   343  func sm2Inverse(out, in []uint64) {
   344  	var stack [6 * 4]uint64
   345  	p2 := stack[4*0 : 4*0+4]
   346  	p4 := stack[4*1 : 4*1+4]
   347  	p8 := stack[4*2 : 4*2+4]
   348  	p16 := stack[4*3 : 4*3+4]
   349  	p32 := stack[4*4 : 4*4+4]
   350  
   351  	sm2Sqr(out, in, 1)
   352  	sm2Mul(p2, out, in) // 3*p
   353  
   354  	sm2Sqr(out, p2, 2)
   355  	sm2Mul(p4, out, p2) // f*p
   356  
   357  	sm2Sqr(out, p4, 4)
   358  	sm2Mul(p8, out, p4) // ff*p
   359  
   360  	sm2Sqr(out, p8, 8)
   361  	sm2Mul(p16, out, p8) // ffff*p
   362  
   363  	sm2Sqr(out, p16, 8)
   364  	sm2Mul(out, out, p8) //ffffff*p
   365  
   366  	sm2Sqr(out, out, 4)
   367  	sm2Mul(out, out, p4) // fffffff*p
   368  
   369  	sm2Sqr(out, out, 2)
   370  	sm2Mul(out, out, p2) // fffffff*p
   371  
   372  	sm2Sqr(out, out, 1)
   373  	sm2Mul(out, out, in)
   374  
   375  	sm2Sqr(out, out, 1) //fffffffe*p
   376  
   377  	sm2Mul(p32, out, in) // ffffffff*p
   378  
   379  	for j := 0; j < 4; j++ {
   380  		sm2Sqr(out, out, 32)
   381  		sm2Mul(out, out, p32)
   382  	}
   383  
   384  	sm2Sqr(out, out, 64)
   385  	sm2Mul(out, out, p32)
   386  
   387  	sm2Sqr(out, out, 16)
   388  	sm2Mul(out, out, p16)
   389  
   390  	sm2Sqr(out, out, 8)
   391  	sm2Mul(out, out, p8)
   392  
   393  	sm2Sqr(out, out, 4)
   394  	sm2Mul(out, out, p4)
   395  
   396  	sm2Sqr(out, out, 2)
   397  	sm2Mul(out, out, p2)
   398  
   399  	sm2Sqr(out, out, 2)
   400  	sm2Mul(out, out, in)
   401  }
   402  
   403  func (p *sm2Point) sm2StorePoint(r *[16 * 4 * 3]uint64, index int) {
   404  	copy(r[index*12:], p.xyz[:])
   405  }
   406  
   407  func boothW5(in uint) (int, int) {
   408  	var s uint = ^((in >> 5) - 1)
   409  	var d uint = (1 << 6) - in - 1
   410  	d = (d & s) | (in & (^s))
   411  	d = (d >> 1) + (d & 1)
   412  	return int(d), int(s & 1)
   413  }
   414  func boothW6(in uint) (int, int) {
   415  	var s uint = ^((in >> 6) - 1)
   416  	var d uint = (1 << 7) - in - 1
   417  	d = (d & s) | (in & (^s))
   418  	d = (d >> 1) + (d & 1)
   419  	return int(d), int(s & 1)
   420  }
   421  
   422  func boothW7(in uint) (int, int) {
   423  	var s uint = ^((in >> 7) - 1)
   424  	var d uint = (1 << 8) - in - 1
   425  	d = (d & s) | (in & (^s))
   426  	d = (d >> 1) + (d & 1)
   427  	return int(d), int(s & 1)
   428  }
   429  
   430  func sm2InitTable() {
   431  	sm2Precomputed = new([43][32 * 8]uint64)
   432  
   433  	basePoint := []uint64{
   434  		0x61328990f418029e, 0x3e7981eddca6c050, 0xd6a1ed99ac24c3c3, 0x91167a5ee1c13b05,
   435  		0xc1354e593c2d0ddd, 0xc1f5e5788d3295fa, 0x8d4cfb066e2a48f8, 0x63cd65d481d735bd,
   436  		0x0000000000000001, 0x00000000ffffffff, 0x0000000000000000, 0x0000000100000000,
   437  	}
   438  	t1 := make([]uint64, 12)
   439  	t2 := make([]uint64, 12)
   440  	copy(t2, basePoint)
   441  
   442  	zInv := make([]uint64, 4)
   443  	zInvSq := make([]uint64, 4)
   444  	for j := 0; j < 32; j++ {
   445  		copy(t1, t2)
   446  		for i := 0; i < 43; i++ {
   447  			// The window size is 6 so we need to double 6 times.
   448  			if i != 0 {
   449  				for k := 0; k < 6; k++ {
   450  					sm2PointDoubleAsm(t1, t1)
   451  				}
   452  			}
   453  			// Convert the point to affine form. (Its values are
   454  			// still in Montgomery form however.)
   455  			sm2Inverse(zInv, t1[8:12])
   456  			sm2Sqr(zInvSq, zInv, 1)
   457  			sm2Mul(zInv, zInv, zInvSq)
   458  
   459  			sm2Mul(t1[:4], t1[:4], zInvSq)
   460  			sm2Mul(t1[4:8], t1[4:8], zInv)
   461  
   462  			copy(t1[8:12], basePoint[8:12])
   463  			// Update the table entry
   464  			copy(sm2Precomputed[i][j*8:], t1[:8])
   465  		}
   466  		if j == 0 {
   467  			sm2PointDoubleAsm(t2, basePoint)
   468  		} else {
   469  			sm2PointAddAsm(t2, t2, basePoint)
   470  		}
   471  	}
   472  }
   473  
   474  func (p *sm2Point) sm2BaseMult(scalar []uint64) {
   475  	sm2precomputeOnce.Do(sm2InitTable)
   476  
   477  	wvalue := (scalar[0] << 1) & 0x7f
   478  	sel, sign := boothW6(uint(wvalue))
   479  	sm2SelectBase(p.xyz[0:8], sm2Precomputed[0][0:], sel)
   480  	sm2NegCond(p.xyz[4:8], sign)
   481  
   482  	// (This is one, in the Montgomery domain.)
   483  	p.xyz[8] = 0x0000000000000001
   484  	p.xyz[9] = 0x00000000ffffffff
   485  	p.xyz[10] = 0x0000000000000000
   486  	p.xyz[11] = 0x0000000100000000
   487  
   488  	var t0 sm2Point
   489  	// (This is one, in the Montgomery domain.)
   490  	t0.xyz[8] = 0x0000000000000001
   491  	t0.xyz[9] = 0x00000000ffffffff
   492  	t0.xyz[10] = 0x0000000000000000
   493  	t0.xyz[11] = 0x0000000100000000
   494  
   495  	index := uint(5)
   496  	zero := sel
   497  
   498  	for i := 1; i < 43; i++ {
   499  		if index < 192 {
   500  			wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x7f
   501  		} else {
   502  			wvalue = (scalar[index/64] >> (index % 64)) & 0x7f
   503  		}
   504  		index += 6
   505  		sel, sign = boothW6(uint(wvalue))
   506  		sm2SelectBase(t0.xyz[0:8], sm2Precomputed[i][0:], sel)
   507  		sm2PointAddAffineAsm(p.xyz[0:12], p.xyz[0:12], t0.xyz[0:8], sign, sel, zero)
   508  		zero |= sel
   509  	}
   510  }
   511  
   512  func (p *sm2Point) sm2ScalarMult(scalar []uint64) {
   513  	// precomp is a table of precomputed points that stores powers of p
   514  	// from p^1 to p^16.
   515  	var precomp [16 * 4 * 3]uint64
   516  	var t0, t1, t2, t3 sm2Point
   517  
   518  	// Prepare the table
   519  	p.sm2StorePoint(&precomp, 0) // 1
   520  
   521  	sm2PointDoubleAsm(t0.xyz[:], p.xyz[:])
   522  	sm2PointDoubleAsm(t1.xyz[:], t0.xyz[:])
   523  	sm2PointDoubleAsm(t2.xyz[:], t1.xyz[:])
   524  	sm2PointDoubleAsm(t3.xyz[:], t2.xyz[:])
   525  	t0.sm2StorePoint(&precomp, 1)  // 2
   526  	t1.sm2StorePoint(&precomp, 3)  // 4
   527  	t2.sm2StorePoint(&precomp, 7)  // 8
   528  	t3.sm2StorePoint(&precomp, 15) // 16
   529  
   530  	sm2PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
   531  	sm2PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
   532  	sm2PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
   533  	t0.sm2StorePoint(&precomp, 2) // 3
   534  	t1.sm2StorePoint(&precomp, 4) // 5
   535  	t2.sm2StorePoint(&precomp, 8) // 9
   536  
   537  	sm2PointDoubleAsm(t0.xyz[:], t0.xyz[:])
   538  	sm2PointDoubleAsm(t1.xyz[:], t1.xyz[:])
   539  	t0.sm2StorePoint(&precomp, 5) // 6
   540  	t1.sm2StorePoint(&precomp, 9) // 10
   541  
   542  	sm2PointAddAsm(t2.xyz[:], t0.xyz[:], p.xyz[:])
   543  	sm2PointAddAsm(t1.xyz[:], t1.xyz[:], p.xyz[:])
   544  	t2.sm2StorePoint(&precomp, 6)  // 7
   545  	t1.sm2StorePoint(&precomp, 10) // 11
   546  
   547  	sm2PointDoubleAsm(t0.xyz[:], t0.xyz[:])
   548  	sm2PointDoubleAsm(t2.xyz[:], t2.xyz[:])
   549  	t0.sm2StorePoint(&precomp, 11) // 12
   550  	t2.sm2StorePoint(&precomp, 13) // 14
   551  
   552  	sm2PointAddAsm(t0.xyz[:], t0.xyz[:], p.xyz[:])
   553  	sm2PointAddAsm(t2.xyz[:], t2.xyz[:], p.xyz[:])
   554  	t0.sm2StorePoint(&precomp, 12) // 13
   555  	t2.sm2StorePoint(&precomp, 14) // 15
   556  
   557  	// Start scanning the window from top bit
   558  	index := uint(254)
   559  	var sel, sign int
   560  
   561  	wvalue := (scalar[index/64] >> (index % 64)) & 0x3f
   562  	sel, _ = boothW5(uint(wvalue))
   563  
   564  	sm2Select(p.xyz[0:12], precomp[0:], sel)
   565  	zero := sel
   566  
   567  	for index > 4 {
   568  		index -= 5
   569  		sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   570  		sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   571  		sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   572  		sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   573  		sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   574  
   575  		if index < 192 {
   576  			wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x3f
   577  		} else {
   578  			wvalue = (scalar[index/64] >> (index % 64)) & 0x3f
   579  		}
   580  
   581  		sel, sign = boothW5(uint(wvalue))
   582  
   583  		sm2Select(t0.xyz[0:], precomp[0:], sel)
   584  		sm2NegCond(t0.xyz[4:8], sign)
   585  		sm2PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
   586  		sm2MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
   587  		sm2MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
   588  		zero |= sel
   589  	}
   590  
   591  	sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   592  	sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   593  	sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   594  	sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   595  	sm2PointDoubleAsm(p.xyz[:], p.xyz[:])
   596  
   597  	wvalue = (scalar[0] << 1) & 0x3f
   598  	sel, sign = boothW5(uint(wvalue))
   599  
   600  	sm2Select(t0.xyz[0:], precomp[0:], sel)
   601  	sm2NegCond(t0.xyz[4:8], sign)
   602  	sm2PointAddAsm(t1.xyz[:], p.xyz[:], t0.xyz[:])
   603  	sm2MovCond(t1.xyz[0:12], t1.xyz[0:12], p.xyz[0:12], sel)
   604  	sm2MovCond(p.xyz[0:12], t1.xyz[0:12], t0.xyz[0:12], zero)
   605  }
   606  
   607  var initOnce sync.Once
   608  
   609  // SM2 returns a Curve which implements SM2
   610  // The cryptographic operations are implemented using constant-time algorithms.
   611  func SM2() elliptic.Curve {
   612  	initOnce.Do(initSM2)
   613  	return sm2
   614  }