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 }