github.com/consensys/gnark-crypto@v0.14.0/ecc/stark-curve/g1.go (about) 1 // Copyright 2020 ConsenSys Software Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // FOO 16 17 package starkcurve 18 19 import ( 20 "math/big" 21 22 "github.com/consensys/gnark-crypto/ecc/stark-curve/fp" 23 "github.com/consensys/gnark-crypto/ecc/stark-curve/fr" 24 "github.com/consensys/gnark-crypto/internal/parallel" 25 ) 26 27 // G1Affine is a point in affine coordinates (x,y) 28 type G1Affine struct { 29 X, Y fp.Element 30 } 31 32 // G1Jac is a point in Jacobian coordinates (x=X/Z², y=Y/Z³) 33 type G1Jac struct { 34 X, Y, Z fp.Element 35 } 36 37 // g1JacExtended is a point in extended Jacobian coordinates (x=X/ZZ, y=Y/ZZZ, ZZ³=ZZZ²) 38 type g1JacExtended struct { 39 X, Y, ZZ, ZZZ fp.Element 40 } 41 42 // ------------------------------------------------------------------------------------------------- 43 // Affine coordinates 44 45 // Set sets p to a in affine coordinates. 46 func (p *G1Affine) Set(a *G1Affine) *G1Affine { 47 p.X, p.Y = a.X, a.Y 48 return p 49 } 50 51 // ScalarMultiplication computes and returns p = [s]a 52 // where p and a are affine points. 53 func (p *G1Affine) ScalarMultiplication(a *G1Affine, s *big.Int) *G1Affine { 54 var _p G1Jac 55 _p.FromAffine(a) 56 _p.mulWindowed(&_p, s) 57 p.FromJacobian(&_p) 58 return p 59 } 60 61 // ScalarMultiplicationBase computes and returns p = [s]g 62 // where g is the affine point generating the prime subgroup. 63 func (p *G1Affine) ScalarMultiplicationBase(s *big.Int) *G1Affine { 64 var _p G1Jac 65 _p.mulWindowed(&g1Gen, s) 66 p.FromJacobian(&_p) 67 return p 68 } 69 70 // Add adds two points in affine coordinates. 71 // It uses the Jacobian addition with a.Z=b.Z=1 and converts the result to affine coordinates. 72 // 73 // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-mmadd-2007-bl 74 func (p *G1Affine) Add(a, b *G1Affine) *G1Affine { 75 var p1, p2 G1Jac 76 p1.FromAffine(a) 77 p2.FromAffine(b) 78 p1.AddAssign(&p2) 79 p.FromJacobian(&p1) 80 return p 81 } 82 83 // Sub subtracts two points in affine coordinates. 84 // It uses a similar approach to Add, but negates the second point before adding. 85 func (p *G1Affine) Sub(a, b *G1Affine) *G1Affine { 86 var p1, p2 G1Jac 87 p1.FromAffine(a) 88 p2.FromAffine(b) 89 p1.SubAssign(&p2) 90 p.FromJacobian(&p1) 91 return p 92 } 93 94 // Equal tests if two points in affine coordinates are equal. 95 func (p *G1Affine) Equal(a *G1Affine) bool { 96 return p.X.Equal(&a.X) && p.Y.Equal(&a.Y) 97 } 98 99 // Neg sets p to the affine negative point -a = (a.X, -a.Y). 100 func (p *G1Affine) Neg(a *G1Affine) *G1Affine { 101 p.X = a.X 102 p.Y.Neg(&a.Y) 103 return p 104 } 105 106 // FromJacobian converts a point p1 from Jacobian to affine coordinates. 107 func (p *G1Affine) FromJacobian(p1 *G1Jac) *G1Affine { 108 109 var a, b fp.Element 110 111 if p1.Z.IsZero() { 112 p.X.SetZero() 113 p.Y.SetZero() 114 return p 115 } 116 117 a.Inverse(&p1.Z) 118 b.Square(&a) 119 p.X.Mul(&p1.X, &b) 120 p.Y.Mul(&p1.Y, &b).Mul(&p.Y, &a) 121 122 return p 123 } 124 125 // String returns the string representation E(x,y) of the affine point p or "O" if it is infinity. 126 func (p *G1Affine) String() string { 127 if p.IsInfinity() { 128 return "O" 129 } 130 return "E([" + p.X.String() + "," + p.Y.String() + "])" 131 } 132 133 // IsInfinity checks if the affine point p is infinity, which is encoded as (0,0). 134 // N.B.: (0,0) is not on the STARK curve (Y²=X³+X+B). 135 func (p *G1Affine) IsInfinity() bool { 136 return p.X.IsZero() && p.Y.IsZero() 137 } 138 139 // IsOnCurve returns true if the affine point p in on the curve. 140 func (p *G1Affine) IsOnCurve() bool { 141 var point G1Jac 142 point.FromAffine(p) 143 return point.IsOnCurve() // call this function to handle infinity point 144 } 145 146 // IsInSubGroup returns true if the affine point p is in the correct subgroup, false otherwise. 147 func (p *G1Affine) IsInSubGroup() bool { 148 var _p G1Jac 149 _p.FromAffine(p) 150 return _p.IsInSubGroup() 151 } 152 153 // ------------------------------------------------------------------------------------------------- 154 // Jacobian coordinates 155 156 // Set sets p to a in Jacobian coordinates. 157 func (p *G1Jac) Set(q *G1Jac) *G1Jac { 158 p.X, p.Y, p.Z = q.X, q.Y, q.Z 159 return p 160 } 161 162 // Equal tests if two points in Jacobian coordinates are equal. 163 func (p *G1Jac) Equal(a *G1Jac) bool { 164 165 if p.Z.IsZero() && a.Z.IsZero() { 166 return true 167 } 168 _p := G1Affine{} 169 _p.FromJacobian(p) 170 171 _a := G1Affine{} 172 _a.FromJacobian(a) 173 174 return _p.X.Equal(&_a.X) && _p.Y.Equal(&_a.Y) 175 } 176 177 // Neg sets p to the Jacobian negative point -q = (q.X, -q.Y, q.Z). 178 func (p *G1Jac) Neg(q *G1Jac) *G1Jac { 179 *p = *q 180 p.Y.Neg(&q.Y) 181 return p 182 } 183 184 // SubAssign sets p to p-a in Jacobian coordinates. 185 // It uses a similar approach to AddAssign, but negates the point a before adding. 186 func (p *G1Jac) SubAssign(a *G1Jac) *G1Jac { 187 var tmp G1Jac 188 tmp.Set(a) 189 tmp.Y.Neg(&tmp.Y) 190 p.AddAssign(&tmp) 191 return p 192 } 193 194 // AddAssign sets p to p+a in Jacobian coordinates. 195 // 196 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl 197 func (p *G1Jac) AddAssign(a *G1Jac) *G1Jac { 198 199 // p is infinity, return a 200 if p.Z.IsZero() { 201 p.Set(a) 202 return p 203 } 204 205 // a is infinity, return p 206 if a.Z.IsZero() { 207 return p 208 } 209 210 var Z1Z1, Z2Z2, U1, U2, S1, S2, H, I, J, r, V fp.Element 211 Z1Z1.Square(&a.Z) 212 Z2Z2.Square(&p.Z) 213 U1.Mul(&a.X, &Z2Z2) 214 U2.Mul(&p.X, &Z1Z1) 215 S1.Mul(&a.Y, &p.Z). 216 Mul(&S1, &Z2Z2) 217 S2.Mul(&p.Y, &a.Z). 218 Mul(&S2, &Z1Z1) 219 220 // if p == a, we double instead 221 if U1.Equal(&U2) && S1.Equal(&S2) { 222 return p.DoubleAssign() 223 } 224 225 H.Sub(&U2, &U1) 226 I.Double(&H). 227 Square(&I) 228 J.Mul(&H, &I) 229 r.Sub(&S2, &S1).Double(&r) 230 V.Mul(&U1, &I) 231 p.X.Square(&r). 232 Sub(&p.X, &J). 233 Sub(&p.X, &V). 234 Sub(&p.X, &V) 235 p.Y.Sub(&V, &p.X). 236 Mul(&p.Y, &r) 237 S1.Mul(&S1, &J).Double(&S1) 238 p.Y.Sub(&p.Y, &S1) 239 p.Z.Add(&p.Z, &a.Z) 240 p.Z.Square(&p.Z). 241 Sub(&p.Z, &Z1Z1). 242 Sub(&p.Z, &Z2Z2). 243 Mul(&p.Z, &H) 244 245 return p 246 } 247 248 // AddMixed sets p to p+a in Jacobian coordinates, where a.Z = 1. 249 // 250 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#addition-madd-2007-bl 251 func (p *G1Jac) AddMixed(a *G1Affine) *G1Jac { 252 253 //if a is infinity return p 254 if a.IsInfinity() { 255 return p 256 } 257 // p is infinity, return a 258 if p.Z.IsZero() { 259 p.X = a.X 260 p.Y = a.Y 261 p.Z.SetOne() 262 return p 263 } 264 265 var Z1Z1, U2, S2, H, HH, I, J, r, V fp.Element 266 Z1Z1.Square(&p.Z) 267 U2.Mul(&a.X, &Z1Z1) 268 S2.Mul(&a.Y, &p.Z). 269 Mul(&S2, &Z1Z1) 270 271 // if p == a, we double instead 272 if U2.Equal(&p.X) && S2.Equal(&p.Y) { 273 return p.DoubleAssign() 274 } 275 276 H.Sub(&U2, &p.X) 277 HH.Square(&H) 278 I.Double(&HH).Double(&I) 279 J.Mul(&H, &I) 280 r.Sub(&S2, &p.Y).Double(&r) 281 V.Mul(&p.X, &I) 282 p.X.Square(&r). 283 Sub(&p.X, &J). 284 Sub(&p.X, &V). 285 Sub(&p.X, &V) 286 J.Mul(&J, &p.Y).Double(&J) 287 p.Y.Sub(&V, &p.X). 288 Mul(&p.Y, &r) 289 p.Y.Sub(&p.Y, &J) 290 p.Z.Add(&p.Z, &H) 291 p.Z.Square(&p.Z). 292 Sub(&p.Z, &Z1Z1). 293 Sub(&p.Z, &HH) 294 295 return p 296 } 297 298 // Double sets p to [2]q in Jacobian coordinates. 299 // 300 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl 301 func (p *G1Jac) Double(q *G1Jac) *G1Jac { 302 p.Set(q) 303 p.DoubleAssign() 304 return p 305 } 306 307 // DoubleAssign doubles p in Jacobian coordinates. 308 // 309 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2007-bl 310 func (p *G1Jac) DoubleAssign() *G1Jac { 311 312 var XX, YY, YYYY, ZZ, S, M, T, ZZZZ fp.Element 313 314 XX.Square(&p.X) 315 YY.Square(&p.Y) 316 YYYY.Square(&YY) 317 ZZ.Square(&p.Z) 318 S.Add(&p.X, &YY) 319 S.Square(&S). 320 Sub(&S, &XX). 321 Sub(&S, &YYYY). 322 Double(&S) 323 M.Double(&XX).Add(&M, &XX) 324 ZZZZ.Square(&ZZ) 325 M.Add(&M, &ZZZZ) 326 p.Z.Add(&p.Z, &p.Y). 327 Square(&p.Z). 328 Sub(&p.Z, &YY). 329 Sub(&p.Z, &ZZ) 330 T.Square(&M) 331 p.X = T 332 T.Double(&S) 333 p.X.Sub(&p.X, &T) 334 p.Y.Sub(&S, &p.X). 335 Mul(&p.Y, &M) 336 YYYY.Double(&YYYY).Double(&YYYY).Double(&YYYY) 337 p.Y.Sub(&p.Y, &YYYY) 338 339 return p 340 } 341 342 // ScalarMultiplication computes and returns p = [s]a 343 // using a 2-bits windowed double-and-add method. 344 func (p *G1Jac) ScalarMultiplication(a *G1Jac, s *big.Int) *G1Jac { 345 return p.mulWindowed(a, s) 346 } 347 348 // String converts p to affine coordinates and returns its string representation E(x,y) or "O" if it is infinity. 349 func (p *G1Jac) String() string { 350 _p := G1Affine{} 351 _p.FromJacobian(p) 352 return _p.String() 353 } 354 355 // FromAffine converts a point a from affine to Jacobian coordinates. 356 func (p *G1Jac) FromAffine(Q *G1Affine) *G1Jac { 357 if Q.IsInfinity() { 358 p.Z.SetZero() 359 p.X.SetOne() 360 p.Y.SetOne() 361 return p 362 } 363 p.Z.SetOne() 364 p.X.Set(&Q.X) 365 p.Y.Set(&Q.Y) 366 return p 367 } 368 369 // IsOnCurve returns true if p in on the curve 370 // Y^2=X^3+X*Z^4+b*Z^6 371 func (p *G1Jac) IsOnCurve() bool { 372 var left, right, tmp, u fp.Element 373 left.Square(&p.Y) 374 right.Square(&p.X).Mul(&right, &p.X) 375 tmp.Square(&p.Z). 376 Square(&tmp) 377 u.Mul(&p.X, &tmp) 378 right.Add(&u, &right) 379 tmp.Mul(&tmp, &p.Z). 380 Mul(&tmp, &p.Z). 381 Mul(&tmp, &bCurveCoeff) 382 right.Add(&right, &tmp) 383 return left.Equal(&right) 384 } 385 386 // IsInSubGroup returns true if p is on the r-torsion, false otherwise. 387 // the curve is of prime order i.e. E(𝔽p) is the full group 388 // so we just check that the point is on the curve. 389 func (p *G1Jac) IsInSubGroup() bool { 390 391 return p.IsOnCurve() 392 393 } 394 395 // mulWindowed computes the 2-bits windowed double-and-add scalar 396 // multiplication p=[s]q in Jacobian coordinates. 397 func (p *G1Jac) mulWindowed(a *G1Jac, s *big.Int) *G1Jac { 398 399 var res G1Jac 400 var ops [3]G1Jac 401 402 res.Set(&g1Infinity) 403 ops[0].Set(a) 404 ops[1].Double(&ops[0]) 405 ops[2].Set(&ops[0]).AddAssign(&ops[1]) 406 407 b := s.Bytes() 408 for i := range b { 409 w := b[i] 410 mask := byte(0xc0) 411 for j := 0; j < 4; j++ { 412 res.DoubleAssign().DoubleAssign() 413 c := (w & mask) >> (6 - 2*j) 414 if c != 0 { 415 res.AddAssign(&ops[c-1]) 416 } 417 mask = mask >> 2 418 } 419 } 420 p.Set(&res) 421 422 return p 423 424 } 425 426 // JointScalarMultiplicationBase computes [s1]g+[s2]a using Straus-Shamir technique 427 // where g is the prime subgroup generator 428 func (p *G1Jac) JointScalarMultiplicationBase(a *G1Affine, s1, s2 *big.Int) *G1Jac { 429 430 var res, p1, p2 G1Jac 431 res.Set(&g1Infinity) 432 p1.Set(&g1Gen) 433 p2.FromAffine(a) 434 435 var table [15]G1Jac 436 437 var k1, k2 big.Int 438 if s1.Sign() == -1 { 439 k1.Neg(s1) 440 table[0].Neg(&p1) 441 } else { 442 k1.Set(s1) 443 table[0].Set(&p1) 444 } 445 if s2.Sign() == -1 { 446 k2.Neg(s2) 447 table[3].Neg(&p2) 448 } else { 449 k2.Set(s2) 450 table[3].Set(&p2) 451 } 452 453 // precompute table (2 bits sliding window) 454 table[1].Double(&table[0]) 455 table[2].Set(&table[1]).AddAssign(&table[0]) 456 table[4].Set(&table[3]).AddAssign(&table[0]) 457 table[5].Set(&table[3]).AddAssign(&table[1]) 458 table[6].Set(&table[3]).AddAssign(&table[2]) 459 table[7].Double(&table[3]) 460 table[8].Set(&table[7]).AddAssign(&table[0]) 461 table[9].Set(&table[7]).AddAssign(&table[1]) 462 table[10].Set(&table[7]).AddAssign(&table[2]) 463 table[11].Set(&table[7]).AddAssign(&table[3]) 464 table[12].Set(&table[11]).AddAssign(&table[0]) 465 table[13].Set(&table[11]).AddAssign(&table[1]) 466 table[14].Set(&table[11]).AddAssign(&table[2]) 467 468 var s [2]fr.Element 469 s[0] = s[0].SetBigInt(&k1).Bits() 470 s[1] = s[1].SetBigInt(&k2).Bits() 471 472 maxBit := k1.BitLen() 473 if k2.BitLen() > maxBit { 474 maxBit = k2.BitLen() 475 } 476 hiWordIndex := (maxBit - 1) / 64 477 478 for i := hiWordIndex; i >= 0; i-- { 479 mask := uint64(3) << 62 480 for j := 0; j < 32; j++ { 481 res.Double(&res).Double(&res) 482 b1 := (s[0][i] & mask) >> (62 - 2*j) 483 b2 := (s[1][i] & mask) >> (62 - 2*j) 484 if b1|b2 != 0 { 485 s := (b2<<2 | b1) 486 res.AddAssign(&table[s-1]) 487 } 488 mask = mask >> 2 489 } 490 } 491 492 p.Set(&res) 493 return p 494 495 } 496 497 // JointScalarMultiplication computes [s1]p1+[s2]p1 using Straus-Shamir technique 498 // where g is the prime subgroup generator 499 func (p *G1Jac) JointScalarMultiplication(p1, p2 *G1Jac, s1, s2 *big.Int) *G1Jac { 500 501 var res G1Jac 502 res.Set(&g1Infinity) 503 504 var table [15]G1Jac 505 506 var k1, k2 big.Int 507 if s1.Sign() == -1 { 508 k1.Neg(s1) 509 table[0].Neg(p1) 510 } else { 511 k1.Set(s1) 512 table[0].Set(p1) 513 } 514 if s2.Sign() == -1 { 515 k2.Neg(s2) 516 table[3].Neg(p2) 517 } else { 518 k2.Set(s2) 519 table[3].Set(p2) 520 } 521 522 // precompute table (2 bits sliding window) 523 table[1].Double(&table[0]) 524 table[2].Set(&table[1]).AddAssign(&table[0]) 525 table[4].Set(&table[3]).AddAssign(&table[0]) 526 table[5].Set(&table[3]).AddAssign(&table[1]) 527 table[6].Set(&table[3]).AddAssign(&table[2]) 528 table[7].Double(&table[3]) 529 table[8].Set(&table[7]).AddAssign(&table[0]) 530 table[9].Set(&table[7]).AddAssign(&table[1]) 531 table[10].Set(&table[7]).AddAssign(&table[2]) 532 table[11].Set(&table[7]).AddAssign(&table[3]) 533 table[12].Set(&table[11]).AddAssign(&table[0]) 534 table[13].Set(&table[11]).AddAssign(&table[1]) 535 table[14].Set(&table[11]).AddAssign(&table[2]) 536 537 var s [2]fr.Element 538 s[0] = s[0].SetBigInt(&k1).Bits() 539 s[1] = s[1].SetBigInt(&k2).Bits() 540 541 maxBit := k1.BitLen() 542 if k2.BitLen() > maxBit { 543 maxBit = k2.BitLen() 544 } 545 hiWordIndex := (maxBit - 1) / 64 546 547 for i := hiWordIndex; i >= 0; i-- { 548 mask := uint64(3) << 62 549 for j := 0; j < 32; j++ { 550 res.Double(&res).Double(&res) 551 b1 := (s[0][i] & mask) >> (62 - 2*j) 552 b2 := (s[1][i] & mask) >> (62 - 2*j) 553 if b1|b2 != 0 { 554 s := (b2<<2 | b1) 555 res.AddAssign(&table[s-1]) 556 } 557 mask = mask >> 2 558 } 559 } 560 561 p.Set(&res) 562 return p 563 564 } 565 566 // ------------------------------------------------------------------------------------------------- 567 // extended Jacobian coordinates 568 569 // Set sets p to a in extended Jacobian coordinates. 570 func (p *g1JacExtended) Set(a *g1JacExtended) *g1JacExtended { 571 p.X, p.Y, p.ZZ, p.ZZZ = a.X, a.Y, a.ZZ, a.ZZZ 572 return p 573 } 574 575 // fromJacExtended converts an extended Jacobian point to an affine point. 576 func (p *G1Affine) fromJacExtended(Q *g1JacExtended) *G1Affine { 577 if Q.ZZ.IsZero() { 578 p.X = fp.Element{} 579 p.Y = fp.Element{} 580 return p 581 } 582 p.X.Inverse(&Q.ZZ).Mul(&p.X, &Q.X) 583 p.Y.Inverse(&Q.ZZZ).Mul(&p.Y, &Q.Y) 584 return p 585 } 586 587 // fromJacExtended converts an extended Jacobian point to a Jacobian point. 588 func (p *G1Jac) fromJacExtended(Q *g1JacExtended) *G1Jac { 589 if Q.ZZ.IsZero() { 590 p.Set(&g1Infinity) 591 return p 592 } 593 p.X.Mul(&Q.ZZ, &Q.X).Mul(&p.X, &Q.ZZ) 594 p.Y.Mul(&Q.ZZZ, &Q.Y).Mul(&p.Y, &Q.ZZZ) 595 p.Z.Set(&Q.ZZZ) 596 return p 597 } 598 599 // add sets p to p+q in extended Jacobian coordinates. 600 // 601 // https://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-add-2008-s 602 func (p *g1JacExtended) add(q *g1JacExtended) *g1JacExtended { 603 //if q is infinity return p 604 if q.ZZ.IsZero() { 605 return p 606 } 607 // p is infinity, return q 608 if p.ZZ.IsZero() { 609 p.Set(q) 610 return p 611 } 612 613 var A, B, U1, U2, S1, S2 fp.Element 614 615 // p2: q, p1: p 616 U2.Mul(&q.X, &p.ZZ) 617 U1.Mul(&p.X, &q.ZZ) 618 A.Sub(&U2, &U1) 619 S2.Mul(&q.Y, &p.ZZZ) 620 S1.Mul(&p.Y, &q.ZZZ) 621 B.Sub(&S2, &S1) 622 623 if A.IsZero() { 624 if B.IsZero() { 625 return p.double(q) 626 627 } 628 p.ZZ = fp.Element{} 629 p.ZZZ = fp.Element{} 630 return p 631 } 632 633 var P, R, PP, PPP, Q, V fp.Element 634 P.Sub(&U2, &U1) 635 R.Sub(&S2, &S1) 636 PP.Square(&P) 637 PPP.Mul(&P, &PP) 638 Q.Mul(&U1, &PP) 639 V.Mul(&S1, &PPP) 640 641 p.X.Square(&R). 642 Sub(&p.X, &PPP). 643 Sub(&p.X, &Q). 644 Sub(&p.X, &Q) 645 p.Y.Sub(&Q, &p.X). 646 Mul(&p.Y, &R). 647 Sub(&p.Y, &V) 648 p.ZZ.Mul(&p.ZZ, &q.ZZ). 649 Mul(&p.ZZ, &PP) 650 p.ZZZ.Mul(&p.ZZZ, &q.ZZZ). 651 Mul(&p.ZZZ, &PPP) 652 653 return p 654 } 655 656 // double sets p to [2]q in Jacobian extended coordinates. 657 // 658 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 659 // N.B.: since we consider any point on Z=0 as the point at infinity 660 // this doubling formula works for infinity points as well. 661 func (p *g1JacExtended) double(q *g1JacExtended) *g1JacExtended { 662 var Z, U, V, W, S, XX, M fp.Element 663 664 U.Double(&q.Y) 665 V.Square(&U) 666 W.Mul(&U, &V) 667 S.Mul(&q.X, &V) 668 XX.Square(&q.X) 669 M.Double(&XX). 670 Add(&M, &XX) 671 Z.Square(&q.ZZ) 672 M.Add(&M, &Z) 673 U.Mul(&W, &q.Y) 674 675 p.X.Square(&M). 676 Sub(&p.X, &S). 677 Sub(&p.X, &S) 678 p.Y.Sub(&S, &p.X). 679 Mul(&p.Y, &M). 680 Sub(&p.Y, &U) 681 p.ZZ.Mul(&V, &q.ZZ) 682 p.ZZZ.Mul(&W, &q.ZZZ) 683 684 return p 685 } 686 687 // subMixed is the same as addMixed, but negates a.Y. 688 // 689 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s 690 func (p *g1JacExtended) subMixed(a *G1Affine) *g1JacExtended { 691 692 //if a is infinity return p 693 if a.IsInfinity() { 694 return p 695 } 696 // p is infinity, return a 697 if p.ZZ.IsZero() { 698 p.X = a.X 699 p.Y.Neg(&a.Y) 700 p.ZZ.SetOne() 701 p.ZZZ.SetOne() 702 return p 703 } 704 705 var P, R fp.Element 706 707 // p2: a, p1: p 708 P.Mul(&a.X, &p.ZZ) 709 P.Sub(&P, &p.X) 710 711 R.Mul(&a.Y, &p.ZZZ) 712 R.Neg(&R) 713 R.Sub(&R, &p.Y) 714 715 if P.IsZero() { 716 if R.IsZero() { 717 return p.doubleNegMixed(a) 718 719 } 720 p.ZZ = fp.Element{} 721 p.ZZZ = fp.Element{} 722 return p 723 } 724 725 var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element 726 727 PP.Square(&P) 728 PPP.Mul(&P, &PP) 729 Q.Mul(&p.X, &PP) 730 RR.Square(&R) 731 X3.Sub(&RR, &PPP) 732 Q2.Double(&Q) 733 p.X.Sub(&X3, &Q2) 734 Y3.Sub(&Q, &p.X).Mul(&Y3, &R) 735 R.Mul(&p.Y, &PPP) 736 p.Y.Sub(&Y3, &R) 737 p.ZZ.Mul(&p.ZZ, &PP) 738 p.ZZZ.Mul(&p.ZZZ, &PPP) 739 740 return p 741 742 } 743 744 // addMixed sets p to p+q in extended Jacobian coordinates, where a.ZZ=1. 745 // 746 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#addition-madd-2008-s 747 func (p *g1JacExtended) addMixed(a *G1Affine) *g1JacExtended { 748 749 //if a is infinity return p 750 if a.IsInfinity() { 751 return p 752 } 753 // p is infinity, return a 754 if p.ZZ.IsZero() { 755 p.X = a.X 756 p.Y = a.Y 757 p.ZZ.SetOne() 758 p.ZZZ.SetOne() 759 return p 760 } 761 762 var P, R fp.Element 763 764 // p2: a, p1: p 765 P.Mul(&a.X, &p.ZZ) 766 P.Sub(&P, &p.X) 767 768 R.Mul(&a.Y, &p.ZZZ) 769 R.Sub(&R, &p.Y) 770 771 if P.IsZero() { 772 if R.IsZero() { 773 return p.doubleMixed(a) 774 775 } 776 p.ZZ = fp.Element{} 777 p.ZZZ = fp.Element{} 778 return p 779 } 780 781 var PP, PPP, Q, Q2, RR, X3, Y3 fp.Element 782 783 PP.Square(&P) 784 PPP.Mul(&P, &PP) 785 Q.Mul(&p.X, &PP) 786 RR.Square(&R) 787 X3.Sub(&RR, &PPP) 788 Q2.Double(&Q) 789 p.X.Sub(&X3, &Q2) 790 Y3.Sub(&Q, &p.X).Mul(&Y3, &R) 791 R.Mul(&p.Y, &PPP) 792 p.Y.Sub(&Y3, &R) 793 p.ZZ.Mul(&p.ZZ, &PP) 794 p.ZZZ.Mul(&p.ZZZ, &PPP) 795 796 return p 797 798 } 799 800 // doubleNegMixed works the same as double, but negates q.Y. 801 func (p *g1JacExtended) doubleNegMixed(q *G1Affine) *g1JacExtended { 802 803 var Z, U, V, W, S, XX, M, S2, L fp.Element 804 805 U.Double(&q.Y) 806 U.Neg(&U) 807 V.Square(&U) 808 W.Mul(&U, &V) 809 S.Mul(&q.X, &V) 810 XX.Square(&q.X) 811 M.Double(&XX). 812 Add(&M, &XX) 813 Z.Square(&p.ZZ) 814 M.Add(&M, &Z) 815 S2.Double(&S) 816 L.Mul(&W, &q.Y) 817 818 p.X.Square(&M). 819 Sub(&p.X, &S2) 820 p.Y.Sub(&S, &p.X). 821 Mul(&p.Y, &M). 822 Add(&p.Y, &L) 823 p.ZZ.Set(&V) 824 p.ZZZ.Set(&W) 825 826 return p 827 } 828 829 // doubleMixed sets p to [2]a in Jacobian extended coordinates, where a.ZZ=1. 830 // 831 // http://www.hyperelliptic.org/EFD/g1p/auto-shortw-xyzz.html#doubling-dbl-2008-s-1 832 func (p *g1JacExtended) doubleMixed(q *G1Affine) *g1JacExtended { 833 834 var Z, U, V, W, S, XX, M, S2, L fp.Element 835 836 U.Double(&q.Y) 837 V.Square(&U) 838 W.Mul(&U, &V) 839 S.Mul(&q.X, &V) 840 XX.Square(&q.X) 841 M.Double(&XX). 842 Add(&M, &XX) 843 Z.Square(&p.ZZ) 844 M.Add(&M, &Z) 845 S2.Double(&S) 846 L.Mul(&W, &q.Y) 847 848 p.X.Square(&M). 849 Sub(&p.X, &S2) 850 p.Y.Sub(&S, &p.X). 851 Mul(&p.Y, &M). 852 Sub(&p.Y, &L) 853 p.ZZ.Set(&V) 854 p.ZZZ.Set(&W) 855 856 return p 857 } 858 859 // BatchJacobianToAffineG1 converts points in Jacobian coordinates to Affine coordinates 860 // performing a single field inversion using the Montgomery batch inversion trick. 861 func BatchJacobianToAffineG1(points []G1Jac) []G1Affine { 862 result := make([]G1Affine, len(points)) 863 zeroes := make([]bool, len(points)) 864 accumulator := fp.One() 865 866 // batch invert all points[].Z coordinates with Montgomery batch inversion trick 867 // (stores points[].Z^-1 in result[i].X to avoid allocating a slice of fr.Elements) 868 for i := 0; i < len(points); i++ { 869 if points[i].Z.IsZero() { 870 zeroes[i] = true 871 continue 872 } 873 result[i].X = accumulator 874 accumulator.Mul(&accumulator, &points[i].Z) 875 } 876 877 var accInverse fp.Element 878 accInverse.Inverse(&accumulator) 879 880 for i := len(points) - 1; i >= 0; i-- { 881 if zeroes[i] { 882 // do nothing, (X=0, Y=0) is infinity point in affine 883 continue 884 } 885 result[i].X.Mul(&result[i].X, &accInverse) 886 accInverse.Mul(&accInverse, &points[i].Z) 887 } 888 889 // batch convert to affine. 890 parallel.Execute(len(points), func(start, end int) { 891 for i := start; i < end; i++ { 892 if zeroes[i] { 893 // do nothing, (X=0, Y=0) is infinity point in affine 894 continue 895 } 896 var a, b fp.Element 897 a = result[i].X 898 b.Square(&a) 899 result[i].X.Mul(&points[i].X, &b) 900 result[i].Y.Mul(&points[i].Y, &b). 901 Mul(&result[i].Y, &a) 902 } 903 }) 904 905 return result 906 }