github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/crypto/edwards_25519_group.go (about)

     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  package crypto
     6  
     7  // Group elements are members of the elliptic curve -x^2 + y^2 = 1 + d * x^2 *
     8  // y^2 where d = -121665/121666.
     9  //
    10  // Several representations are used:
    11  //   ProjectiveGroupElement: (X:Y:Z) satisfying x=X/Z, y=Y/Z
    12  //   ExtendedGroupElement: (X:Y:Z:T) satisfying x=X/Z, y=Y/Z, XY=ZT
    13  //   CompletedGroupElement: ((X:Z),(Y:T)) satisfying x=X/Z, y=Y/T
    14  //   PreComputedGroupElement: (y+x,y-x,2dxy)
    15  
    16  type ProjectiveGroupElement struct {
    17  	X, Y, Z FieldElement
    18  }
    19  
    20  type ExtendedGroupElement struct {
    21  	X, Y, Z, T FieldElement
    22  }
    23  
    24  type CompletedGroupElement struct {
    25  	X, Y, Z, T FieldElement
    26  }
    27  
    28  type PreComputedGroupElement struct {
    29  	yPlusX, yMinusX, xy2d FieldElement
    30  }
    31  
    32  type CachedGroupElement struct {
    33  	yPlusX, yMinusX, Z, T2d FieldElement
    34  }
    35  
    36  func (c *CachedGroupElement) Zero() {
    37  	FeOne(&c.yPlusX)  //c.yPlusX.One()
    38  	FeOne(&c.yMinusX) //c.yMinusX.One()
    39  	FeOne(&c.Z)       //c.Z.One()
    40  	FeZero(&c.T2d)    //c.T2d.Zero()
    41  }
    42  
    43  func (p *ProjectiveGroupElement) Zero() {
    44  	FeZero(&p.X)
    45  	FeOne(&p.Y)
    46  	FeOne(&p.Z)
    47  }
    48  
    49  func (p *ProjectiveGroupElement) Double(r *CompletedGroupElement) {
    50  	var t0 FieldElement
    51  
    52  	FeSquare(&r.X, &p.X)
    53  	FeSquare(&r.Z, &p.Y)
    54  	FeSquare2(&r.T, &p.Z)
    55  	FeAdd(&r.Y, &p.X, &p.Y)
    56  	FeSquare(&t0, &r.Y)
    57  	FeAdd(&r.Y, &r.Z, &r.X)
    58  	FeSub(&r.Z, &r.Z, &r.X)
    59  	FeSub(&r.X, &t0, &r.Y)
    60  	FeSub(&r.T, &r.T, &r.Z)
    61  }
    62  
    63  func (p *ProjectiveGroupElement) ToBytes(s *Key) {
    64  	var recip, x, y FieldElement
    65  
    66  	FeInvert(&recip, &p.Z)
    67  	FeMul(&x, &p.X, &recip)
    68  	FeMul(&y, &p.Y, &recip)
    69  	FeToBytes(s, &y)
    70  	s[31] ^= FeIsNegative(&x) << 7
    71  }
    72  
    73  func (p *ExtendedGroupElement) Zero() {
    74  	FeZero(&p.X)
    75  	FeOne(&p.Y)
    76  	FeOne(&p.Z)
    77  	FeZero(&p.T)
    78  }
    79  
    80  func (p *ExtendedGroupElement) Double(r *CompletedGroupElement) {
    81  	var q ProjectiveGroupElement
    82  	p.ToProjective(&q)
    83  	q.Double(r)
    84  }
    85  
    86  func (p *ExtendedGroupElement) ToCached(r *CachedGroupElement) {
    87  	FeAdd(&r.yPlusX, &p.Y, &p.X)
    88  	FeSub(&r.yMinusX, &p.Y, &p.X)
    89  	FeCopy(&r.Z, &p.Z)
    90  	FeMul(&r.T2d, &p.T, &d2)
    91  }
    92  
    93  // build precomputed element for
    94  func (p *ExtendedGroupElement) ToPreComputed(r *PreComputedGroupElement) {
    95  	FeAdd(&r.yPlusX, &p.Y, &p.X)
    96  	FeSub(&r.yMinusX, &p.Y, &p.X)
    97  	FeMul(&r.xy2d, &p.X, &p.Y)
    98  	FeMul(&r.xy2d, &r.xy2d, &d2)
    99  }
   100  
   101  func (p *ExtendedGroupElement) ToProjective(r *ProjectiveGroupElement) {
   102  	FeCopy(&r.X, &p.X)
   103  	FeCopy(&r.Y, &p.Y)
   104  	FeCopy(&r.Z, &p.Z)
   105  }
   106  
   107  func (p *ExtendedGroupElement) ToBytes(s *Key) {
   108  	var recip, x, y FieldElement
   109  
   110  	FeInvert(&recip, &p.Z)
   111  	FeMul(&x, &p.X, &recip)
   112  	FeMul(&y, &p.Y, &recip)
   113  	FeToBytes(s, &y)
   114  	s[31] ^= FeIsNegative(&x) << 7
   115  }
   116  
   117  func (p *ExtendedGroupElement) FromBytes(s *Key) bool {
   118  	var u, v, v3, vxx, check FieldElement
   119  
   120  	// expanded FeFromBytes (with canonical check)
   121  	h0 := load4(s[:])
   122  	h1 := load3(s[4:]) << 6
   123  	h2 := load3(s[7:]) << 5
   124  	h3 := load3(s[10:]) << 3
   125  	h4 := load3(s[13:]) << 2
   126  	h5 := load4(s[16:])
   127  	h6 := load3(s[20:]) << 7
   128  	h7 := load3(s[23:]) << 5
   129  	h8 := load3(s[26:]) << 4
   130  	h9 := (load3(s[29:]) & 8388607) << 2
   131  
   132  	// Validate the number to be canonical
   133  	if h9 == 33554428 && h8 == 268435440 && h7 == 536870880 && h6 == 2147483520 &&
   134  		h5 == 4294967295 && h4 == 67108860 && h3 == 134217720 && h2 == 536870880 &&
   135  		h1 == 1073741760 && h0 >= 4294967277 {
   136  		return false
   137  	}
   138  
   139  	FeFromBytes(&p.Y, s)
   140  	FeOne(&p.Z)
   141  	FeSquare(&u, &p.Y)
   142  	FeMul(&v, &u, &d)
   143  	FeSub(&u, &u, &p.Z) // y = y^2-1
   144  	FeAdd(&v, &v, &p.Z) // v = dy^2+1
   145  
   146  	FeSquare(&v3, &v)
   147  	FeMul(&v3, &v3, &v) // v3 = v^3
   148  	FeSquare(&p.X, &v3)
   149  	FeMul(&p.X, &p.X, &v)
   150  	FeMul(&p.X, &p.X, &u) // x = uv^7
   151  
   152  	fePow22523(&p.X, &p.X) // x = (uv^7)^((q-5)/8)
   153  	FeMul(&p.X, &p.X, &v3)
   154  	FeMul(&p.X, &p.X, &u) // x = uv^3(uv^7)^((q-5)/8)
   155  
   156  	var tmpX, tmp2 Key
   157  
   158  	FeSquare(&vxx, &p.X)
   159  	FeMul(&vxx, &vxx, &v)
   160  	FeSub(&check, &vxx, &u) // vx^2-u
   161  	if FeIsNonZero(&check) == 1 {
   162  		FeAdd(&check, &vxx, &u) // vx^2+u
   163  		if FeIsNonZero(&check) == 1 {
   164  			return false
   165  		}
   166  		FeMul(&p.X, &p.X, &SqrtM1)
   167  
   168  		FeToBytes(&tmpX, &p.X)
   169  		for i, v := range tmpX {
   170  			tmp2[31-i] = v
   171  		}
   172  	}
   173  
   174  	if FeIsNegative(&p.X) != (s[31] >> 7) {
   175  		// If x = 0, the sign must be positive
   176  		if FeIsNonZero(&p.X) == 0 {
   177  			return false
   178  		}
   179  		FeNeg(&p.X, &p.X)
   180  	}
   181  
   182  	FeMul(&p.T, &p.X, &p.Y)
   183  	return true
   184  }
   185  
   186  func FeDivPowM1(out, u, v *FieldElement) {
   187  	var v3, uv7, t0 FieldElement
   188  
   189  	FeSquare(&v3, v)
   190  	FeMul(&v3, &v3, v) /* v3 = v^3 */
   191  	FeSquare(&uv7, &v3)
   192  	FeMul(&uv7, &uv7, v)
   193  	FeMul(&uv7, &uv7, u) /* uv7 = uv^7 */
   194  
   195  	fePow22523(&t0, &uv7)
   196  	/* t0 = (uv^7)^((q-5)/8) */
   197  	FeMul(&t0, &t0, &v3)
   198  	FeMul(out, &t0, u) /* u^(m+1)v^(-(m+1)) */
   199  }
   200  func (p *ProjectiveGroupElement) FromBytes(s *Key) {
   201  
   202  	// the original code processes it in a different way
   203  	// so we do it in 2 steps
   204  	// first parse using the original code, convert into 32 bit form
   205  	// then pack back to a 32 bytes
   206  	// now we use 64 bit code to parse
   207  	var tmps [32]byte
   208  	{
   209  		h0 := load4(s[:])
   210  		h1 := load3(s[4:]) << 6
   211  		h2 := load3(s[7:]) << 5
   212  		h3 := load3(s[10:]) << 3
   213  		h4 := load3(s[13:]) << 2
   214  		h5 := load4(s[16:])
   215  		h6 := load3(s[20:]) << 7
   216  		h7 := load3(s[23:]) << 5
   217  		h8 := load3(s[26:]) << 4
   218  		h9 := load3(s[29:]) << 2
   219  		var carry [10]int64
   220  		carry[9] = (h9 + int64(1<<24)) >> 25
   221  		h0 += carry[9] * 19
   222  		h9 -= carry[9] << 25
   223  		carry[1] = (h1 + int64(1<<24)) >> 25
   224  		h2 += carry[1]
   225  		h1 -= carry[1] << 25
   226  		carry[3] = (h3 + int64(1<<24)) >> 25
   227  		h4 += carry[3]
   228  		h3 -= carry[3] << 25
   229  		carry[5] = (h5 + int64(1<<24)) >> 25
   230  		h6 += carry[5]
   231  		h5 -= carry[5] << 25
   232  		carry[7] = (h7 + int64(1<<24)) >> 25
   233  		h8 += carry[7]
   234  		h7 -= carry[7] << 25
   235  
   236  		carry[0] = (h0 + int64(1<<25)) >> 26
   237  		h1 += carry[0]
   238  		h0 -= carry[0] << 26
   239  		carry[2] = (h2 + int64(1<<25)) >> 26
   240  		h3 += carry[2]
   241  		h2 -= carry[2] << 26
   242  		carry[4] = (h4 + int64(1<<25)) >> 26
   243  		h5 += carry[4]
   244  		h4 -= carry[4] << 26
   245  		carry[6] = (h6 + int64(1<<25)) >> 26
   246  		h7 += carry[6]
   247  		h6 -= carry[6] << 26
   248  		carry[8] = (h8 + int64(1<<25)) >> 26
   249  		h9 += carry[8]
   250  		h8 -= carry[8] << 26
   251  
   252  		var u FieldElement32
   253  		u[0] = int32(h0)
   254  		u[1] = int32(h1)
   255  		u[2] = int32(h2)
   256  		u[3] = int32(h3)
   257  		u[4] = int32(h4)
   258  		u[5] = int32(h5)
   259  		u[6] = int32(h6)
   260  		u[7] = int32(h7)
   261  		u[8] = int32(h8)
   262  		u[9] = int32(h9)
   263  
   264  		FeToBytes32(&tmps, &u)
   265  
   266  	}
   267  	var u, v, w, x, y, z FieldElement
   268  
   269  	// the preprocessed key is stored in tmps
   270  	var tmp_key Key
   271  	copy(tmp_key[:], tmps[:])
   272  	FeFromBytes(&u, &tmp_key)
   273  
   274  	FeSquare2(&v, &u) /* 2 * u^2 */
   275  	FeOne(&w)
   276  	FeAdd(&w, &v, &w) /* w = 2 * u^2 + 1 */
   277  	FeSquare(&x, &w)  /* w^2 */
   278  
   279  	FeMul(&y, &FeMa2, &v)    /* -2 * A^2 * u^2 */
   280  	FeAdd(&x, &x, &y)        /* x = w^2 - 2 * A^2 * u^2 */
   281  	FeDivPowM1(&p.X, &w, &x) /* (w / x)^(m + 1) */
   282  	FeSquare(&y, &p.X)
   283  	FeMul(&x, &y, &x)
   284  	FeSub(&y, &w, &x)
   285  	FeCopy(&z, &FeMa)
   286  	isNegative := false
   287  	var sign byte
   288  	if FeIsNonZero(&y) != 0 {
   289  		FeAdd(&y, &w, &x)
   290  		if FeIsNonZero(&y) != 0 {
   291  			isNegative = true
   292  		} else {
   293  			FeMul(&p.X, &p.X, &FeFffb1)
   294  		}
   295  	} else {
   296  		FeMul(&p.X, &p.X, &FeFffb2)
   297  	}
   298  	if isNegative {
   299  		FeMul(&x, &x, &FeSqrtM1)
   300  		FeSub(&y, &w, &x)
   301  		if FeIsNonZero(&y) != 0 {
   302  			FeAdd(&y, &w, &x)
   303  			FeMul(&p.X, &p.X, &FeFffb3)
   304  		} else {
   305  			FeMul(&p.X, &p.X, &FeFffb4)
   306  		}
   307  		/* p.X = sqrt(A * (A + 2) * w / x) */
   308  		/* z = -A */
   309  		sign = 1
   310  	} else {
   311  		FeMul(&p.X, &p.X, &u) /* u * sqrt(2 * A * (A + 2) * w / x) */
   312  		FeMul(&z, &z, &v)     /* -2 * A * u^2 */
   313  		sign = 0
   314  	}
   315  	if FeIsNegative(&p.X) != sign {
   316  		FeNeg(&p.X, &p.X)
   317  	}
   318  	FeAdd(&p.Z, &z, &w)
   319  	FeSub(&p.Y, &z, &w)
   320  	FeMul(&p.X, &p.X, &p.Z)
   321  
   322  }
   323  
   324  func (p *CompletedGroupElement) ToProjective(r *ProjectiveGroupElement) {
   325  	FeMul(&r.X, &p.X, &p.T)
   326  	FeMul(&r.Y, &p.Y, &p.Z)
   327  	FeMul(&r.Z, &p.Z, &p.T)
   328  }
   329  
   330  func (p *CompletedGroupElement) ToExtended(r *ExtendedGroupElement) {
   331  	FeMul(&r.X, &p.X, &p.T)
   332  	FeMul(&r.Y, &p.Y, &p.Z)
   333  	FeMul(&r.Z, &p.Z, &p.T)
   334  	FeMul(&r.T, &p.X, &p.Y)
   335  }
   336  
   337  func (p *PreComputedGroupElement) Zero() {
   338  	FeOne(&p.yPlusX)
   339  	FeOne(&p.yMinusX)
   340  	FeZero(&p.xy2d)
   341  }
   342  
   343  // exported version for ringct
   344  func GeAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) {
   345  	geAdd(r, p, q)
   346  }
   347  func geAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) {
   348  	var t0 FieldElement
   349  
   350  	FeAdd(&r.X, &p.Y, &p.X)
   351  	FeSub(&r.Y, &p.Y, &p.X)
   352  	FeMul(&r.Z, &r.X, &q.yPlusX)
   353  	FeMul(&r.Y, &r.Y, &q.yMinusX)
   354  	FeMul(&r.T, &q.T2d, &p.T)
   355  	FeMul(&r.X, &p.Z, &q.Z)
   356  	FeAdd(&t0, &r.X, &r.X)
   357  	FeSub(&r.X, &r.Z, &r.Y)
   358  	FeAdd(&r.Y, &r.Z, &r.Y)
   359  	FeAdd(&r.Z, &t0, &r.T)
   360  	FeSub(&r.T, &t0, &r.T)
   361  }
   362  func geMixedAdd(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) {
   363  	var t0 FieldElement
   364  
   365  	FeAdd(&r.X, &p.Y, &p.X)
   366  	FeSub(&r.Y, &p.Y, &p.X)
   367  	FeMul(&r.Z, &r.X, &q.yPlusX)
   368  	FeMul(&r.Y, &r.Y, &q.yMinusX)
   369  	FeMul(&r.T, &q.xy2d, &p.T)
   370  	FeAdd(&t0, &p.Z, &p.Z)
   371  	FeSub(&r.X, &r.Z, &r.Y)
   372  	FeAdd(&r.Y, &r.Z, &r.Y)
   373  	FeAdd(&r.Z, &t0, &r.T)
   374  	FeSub(&r.T, &t0, &r.T)
   375  }
   376  
   377  func geSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *CachedGroupElement) {
   378  	var t0 FieldElement
   379  
   380  	FeAdd(&r.X, &p.Y, &p.X)
   381  	FeSub(&r.Y, &p.Y, &p.X)
   382  	FeMul(&r.Z, &r.X, &q.yMinusX)
   383  	FeMul(&r.Y, &r.Y, &q.yPlusX)
   384  	FeMul(&r.T, &q.T2d, &p.T)
   385  	FeMul(&r.X, &p.Z, &q.Z)
   386  	FeAdd(&t0, &r.X, &r.X)
   387  	FeSub(&r.X, &r.Z, &r.Y)
   388  	FeAdd(&r.Y, &r.Z, &r.Y)
   389  	FeSub(&r.Z, &t0, &r.T)
   390  	FeAdd(&r.T, &t0, &r.T)
   391  }
   392  
   393  func geMixedSub(r *CompletedGroupElement, p *ExtendedGroupElement, q *PreComputedGroupElement) {
   394  	var t0 FieldElement
   395  
   396  	FeAdd(&r.X, &p.Y, &p.X)
   397  	FeSub(&r.Y, &p.Y, &p.X)
   398  	FeMul(&r.Z, &r.X, &q.yMinusX)
   399  	FeMul(&r.Y, &r.Y, &q.yPlusX)
   400  	FeMul(&r.T, &q.xy2d, &p.T)
   401  	FeAdd(&t0, &p.Z, &p.Z)
   402  	FeSub(&r.X, &r.Z, &r.Y)
   403  	FeAdd(&r.Y, &r.Z, &r.Y)
   404  	FeSub(&r.Z, &t0, &r.T)
   405  	FeAdd(&r.T, &t0, &r.T)
   406  }
   407  
   408  func slide(r *[256]int8, a *Key) {
   409  	for i := range r {
   410  		r[i] = int8(1 & (a[i>>3] >> uint(i&7)))
   411  	}
   412  
   413  	for i := range r {
   414  		if r[i] != 0 {
   415  			for b := 1; b <= 6 && i+b < 256; b++ {
   416  				if r[i+b] != 0 {
   417  					if r[i]+(r[i+b]<<uint(b)) <= 15 {
   418  						r[i] += r[i+b] << uint(b)
   419  						r[i+b] = 0
   420  					} else if r[i]-(r[i+b]<<uint(b)) >= -15 {
   421  						r[i] -= r[i+b] << uint(b)
   422  						for k := i + b; k < 256; k++ {
   423  							if r[k] == 0 {
   424  								r[k] = 1
   425  								break
   426  							}
   427  							r[k] = 0
   428  						}
   429  					} else {
   430  						break
   431  					}
   432  				}
   433  			}
   434  		}
   435  	}
   436  }
   437  
   438  // sets r = a*A + b*G
   439  // this is an optimised version, unoptimised version is 4 lines below
   440  func GeDoubleScalarMultVartime(r *ProjectiveGroupElement, a *Key, A *ExtendedGroupElement, b *Key) {
   441  	var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A
   442  	GePrecompute(&Ai, A)
   443  	GeDoubleScalarMultPrecompVartime2(r, a, &Ai, b, &GBASE_Cached)
   444  }
   445  
   446  // GeDoubleScalarMultVartime sets r = a*A + b*B
   447  // where a = a[0]+256*a[1]+...+256^31 a[31].
   448  // and b = b[0]+256*b[1]+...+256^31 b[31].
   449  // B is the Ed25519 base point (x,4/5) with x positive.
   450  /*
   451  func GeDoubleScalarMultVartime(r *ProjectiveGroupElement, a *Key, A *ExtendedGroupElement, b *Key) {
   452  	var aSlide, bSlide [256]int8
   453  	var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A
   454  	var t CompletedGroupElement
   455  	var u, A2 ExtendedGroupElement
   456  	var i int
   457  
   458  	slide(&aSlide, a)
   459  	slide(&bSlide, b)
   460  
   461  	A.ToCached(&Ai[0])
   462  	A.Double(&t)
   463  	t.ToExtended(&A2)
   464  
   465  	for i := 0; i < 7; i++ {
   466  		geAdd(&t, &A2, &Ai[i])
   467  		t.ToExtended(&u)
   468  		u.ToCached(&Ai[i+1])
   469  	}
   470  
   471  	r.Zero()
   472  
   473  	for i = 255; i >= 0; i-- {
   474  		if aSlide[i] != 0 || bSlide[i] != 0 {
   475  			break
   476  		}
   477  	}
   478  
   479  	for ; i >= 0; i-- {
   480  		r.Double(&t)
   481  
   482  		if aSlide[i] > 0 {
   483  			t.ToExtended(&u)
   484  			geAdd(&t, &u, &Ai[aSlide[i]/2])
   485  		} else if aSlide[i] < 0 {
   486  			t.ToExtended(&u)
   487  			geSub(&t, &u, &Ai[(-aSlide[i])/2])
   488  		}
   489  
   490  		if bSlide[i] > 0 {
   491  			t.ToExtended(&u)
   492  			geMixedAdd(&t, &u, &bi[bSlide[i]/2])
   493  		} else if bSlide[i] < 0 {
   494  			t.ToExtended(&u)
   495  			geMixedSub(&t, &u, &bi[(-bSlide[i])/2])
   496  		}
   497  
   498  		t.ToProjective(r)
   499  	}
   500  }
   501  */
   502  
   503  // equal returns 1 if b == c and 0 otherwise, assuming that b and c are
   504  // non-negative.
   505  func equal(b, c int32) int32 {
   506  	x := uint32(b ^ c)
   507  	x--
   508  	return int32(x >> 31)
   509  }
   510  
   511  // negative returns 1 if b < 0 and 0 otherwise.
   512  func negative(b int32) int32 {
   513  	return (b >> 31) & 1
   514  }
   515  
   516  func PreComputedGroupElementCMove(t, u *PreComputedGroupElement, b int32) {
   517  	FeCMove(&t.yPlusX, &u.yPlusX, b)
   518  	FeCMove(&t.yMinusX, &u.yMinusX, b)
   519  	FeCMove(&t.xy2d, &u.xy2d, b)
   520  }
   521  
   522  func selectPoint(t *PreComputedGroupElement, pos int32, b int32) {
   523  	var minusT PreComputedGroupElement
   524  	bNegative := negative(b)
   525  	bAbs := b - (((-bNegative) & b) << 1)
   526  
   527  	t.Zero()
   528  	for i := int32(0); i < 8; i++ {
   529  		PreComputedGroupElementCMove(t, &base[pos][i], equal(bAbs, i+1))
   530  	}
   531  	FeCopy(&minusT.yPlusX, &t.yMinusX)
   532  	FeCopy(&minusT.yMinusX, &t.yPlusX)
   533  	FeNeg(&minusT.xy2d, &t.xy2d)
   534  	PreComputedGroupElementCMove(t, &minusT, bNegative)
   535  }
   536  
   537  // GeScalarMultBase computes h = a*B, where
   538  //   a = a[0]+256*a[1]+...+256^31 a[31]
   539  //   B is the Ed25519 base point (x,4/5) with x positive.
   540  //
   541  // Preconditions:
   542  //   a[31] <= 127
   543  func GeScalarMultBase(h *ExtendedGroupElement, a *Key) {
   544  	var e [64]int8
   545  
   546  	for i, v := range a {
   547  		e[2*i] = int8(v & 15)
   548  		e[2*i+1] = int8((v >> 4) & 15)
   549  	}
   550  
   551  	// each e[i] is between 0 and 15 and e[63] is between 0 and 7.
   552  
   553  	carry := int8(0)
   554  	for i := 0; i < 63; i++ {
   555  		e[i] += carry
   556  		carry = (e[i] + 8) >> 4
   557  		e[i] -= carry << 4
   558  	}
   559  	e[63] += carry
   560  	// each e[i] is between -8 and 8.
   561  
   562  	h.Zero()
   563  	var t PreComputedGroupElement
   564  	var r CompletedGroupElement
   565  	for i := int32(1); i < 64; i += 2 {
   566  		selectPoint(&t, i/2, int32(e[i]))
   567  		geMixedAdd(&r, h, &t)
   568  		r.ToExtended(h)
   569  	}
   570  
   571  	var s ProjectiveGroupElement
   572  
   573  	h.Double(&r)
   574  	r.ToProjective(&s)
   575  	s.Double(&r)
   576  	r.ToProjective(&s)
   577  	s.Double(&r)
   578  	r.ToProjective(&s)
   579  	s.Double(&r)
   580  	r.ToExtended(h)
   581  
   582  	for i := int32(0); i < 64; i += 2 {
   583  		selectPoint(&t, i/2, int32(e[i]))
   584  		geMixedAdd(&r, h, &t)
   585  		r.ToExtended(h)
   586  	}
   587  }
   588  
   589  // r = 8 * t
   590  func GeMul8(r *CompletedGroupElement, t *ProjectiveGroupElement) {
   591  	var u ProjectiveGroupElement
   592  	t.Double(r)
   593  	r.ToProjective(&u)
   594  	u.Double(r)
   595  	r.ToProjective(&u)
   596  	u.Double(r)
   597  }
   598  
   599  // caches s into an array of CachedGroupElements for scalar multiplication later
   600  func GePrecompute(r *[8]CachedGroupElement, s *ExtendedGroupElement) {
   601  	var t CompletedGroupElement
   602  	var s2, u ExtendedGroupElement
   603  	s.ToCached(&r[0])
   604  	s.Double(&t)
   605  	t.ToExtended(&s2)
   606  	for i := 0; i < 7; i++ {
   607  		geAdd(&t, &s2, &r[i])
   608  		t.ToExtended(&u)
   609  		u.ToCached(&r[i+1])
   610  	}
   611  }
   612  
   613  // sets r = a*A + b*B
   614  // where Bi is the [8]CachedGroupElement consisting of
   615  // B,3B,5B,7B,9B,11B,13B,15B
   616  func GeDoubleScalarMultPrecompVartime2(r *ProjectiveGroupElement, a *Key, Ai *[8]CachedGroupElement, b *Key, Bi *[8]CachedGroupElement) {
   617  	var aSlide, bSlide [256]int8
   618  	//var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A
   619  	var t CompletedGroupElement
   620  	var u ExtendedGroupElement
   621  	var i int
   622  	slide(&aSlide, a)
   623  	slide(&bSlide, b)
   624  	//GePrecompute(&Ai, A)
   625  	r.Zero()
   626  	for i = 255; i >= 0; i-- {
   627  		if aSlide[i] != 0 || bSlide[i] != 0 {
   628  			break
   629  		}
   630  	}
   631  	for ; i >= 0; i-- {
   632  		r.Double(&t)
   633  		if aSlide[i] > 0 {
   634  			t.ToExtended(&u)
   635  			geAdd(&t, &u, &Ai[aSlide[i]/2])
   636  		} else if aSlide[i] < 0 {
   637  			t.ToExtended(&u)
   638  			geSub(&t, &u, &Ai[(-aSlide[i])/2])
   639  		}
   640  		if bSlide[i] > 0 {
   641  			t.ToExtended(&u)
   642  			geAdd(&t, &u, &Bi[bSlide[i]/2])
   643  		} else if bSlide[i] < 0 {
   644  			t.ToExtended(&u)
   645  			geSub(&t, &u, &Bi[(-bSlide[i])/2])
   646  		}
   647  		t.ToProjective(r)
   648  	}
   649  	return
   650  }
   651  
   652  // sets r = a*A + b*B
   653  // where Bi is the [8]CachedGroupElement consisting of
   654  // B,3B,5B,7B,9B,11B,13B,15B
   655  func GeDoubleScalarMultPrecompVartime(r *ProjectiveGroupElement, a *Key, A *ExtendedGroupElement, b *Key, Bi *[8]CachedGroupElement) {
   656  	var Ai [8]CachedGroupElement // A,3A,5A,7A,9A,11A,13A,15A
   657  	GePrecompute(&Ai, A)
   658  	GeDoubleScalarMultPrecompVartime2(r, a, &Ai, b, Bi)
   659  }
   660  
   661  func CachedGroupElementCMove(t, u *CachedGroupElement, b int32) {
   662  	if b == 0 {
   663  		return
   664  	}
   665  	FeCMove(&t.yPlusX, &u.yPlusX, b)
   666  	FeCMove(&t.yMinusX, &u.yMinusX, b)
   667  	FeCMove(&t.Z, &u.Z, b)
   668  	FeCMove(&t.T2d, &u.T2d, b)
   669  }