github.com/consensys/gnark-crypto@v0.14.0/internal/generator/edwards/template/point.go.tmpl (about) 1 import ( 2 "crypto/subtle" 3 "io" 4 "math/big" 5 "math/bits" 6 7 "github.com/consensys/gnark-crypto/ecc/{{.Name}}/fr" 8 ) 9 10 // PointAffine point on a twisted Edwards curve 11 type PointAffine struct { 12 X, Y fr.Element 13 } 14 15 // PointProj point in projective coordinates 16 type PointProj struct { 17 X, Y, Z fr.Element 18 } 19 20 // PointExtended point in extended coordinates 21 type PointExtended struct { 22 X, Y, Z, T fr.Element 23 } 24 25 const ( 26 //following https://tools.ietf.org/html/rfc8032#section-3.1, 27 // an fr element x is negative if its binary encoding is 28 // lexicographically larger than -x. 29 mCompressedNegative = 0x80 30 mCompressedPositive = 0x00 31 mUnmask = 0x7f 32 33 // size in byte of a compressed point (point.Y --> fr.Element) 34 sizePointCompressed = fr.Bytes 35 ) 36 37 // Bytes returns the compressed point as a byte array 38 // Follows https://tools.ietf.org/html/rfc8032#section-3.1, 39 // as the twisted Edwards implementation is primarily used 40 // for eddsa. 41 func (p *PointAffine) Bytes() [sizePointCompressed]byte { 42 43 var res [sizePointCompressed]byte 44 var mask uint 45 46 y := p.Y.Bytes() 47 48 if p.X.LexicographicallyLargest() { 49 mask = mCompressedNegative 50 } else { 51 mask = mCompressedPositive 52 } 53 // p.Y must be in little endian 54 y[0] |= byte(mask) // msb of y 55 for i, j := 0, sizePointCompressed-1; i < j; i, j = i+1, j-1 { 56 y[i], y[j] = y[j], y[i] 57 } 58 subtle.ConstantTimeCopy(1, res[:], y[:]) 59 return res 60 } 61 62 // Marshal converts p to a byte slice 63 func (p *PointAffine) Marshal() []byte { 64 b := p.Bytes() 65 return b[:] 66 } 67 68 func computeX(y *fr.Element) (x fr.Element) { 69 initOnce.Do(initCurveParams) 70 71 var one, num, den fr.Element 72 one.SetOne() 73 num.Square(y) 74 den.Mul(&num, &curveParams.D) 75 num.Sub(&one, &num) 76 den.Sub(&curveParams.A, &den) 77 x.Div(&num, &den) 78 x.Sqrt(&x) 79 return 80 } 81 82 // SetBytes sets p from buf 83 // len(buf) >= sizePointCompressed 84 // buf contains the Y coordinate masked with a parity bit to recompute the X coordinate 85 // from the curve equation. See Bytes() and https://tools.ietf.org/html/rfc8032#section-3.1 86 // Returns the number of read bytes and an error if the buffer is too short. 87 func (p *PointAffine) SetBytes(buf []byte) (int, error) { 88 89 if len(buf) < sizePointCompressed { 90 return 0, io.ErrShortBuffer 91 } 92 bufCopy := make([]byte, sizePointCompressed) 93 subtle.ConstantTimeCopy(1, bufCopy, buf[:sizePointCompressed]) 94 for i, j := 0, sizePointCompressed-1; i < j; i, j = i+1, j-1 { 95 bufCopy[i], bufCopy[j] = bufCopy[j], bufCopy[i] 96 } 97 isLexicographicallyLargest := (mCompressedNegative&bufCopy[0])>>7 == 1 98 bufCopy[0] &= mUnmask 99 p.Y.SetBytes(bufCopy) 100 p.X = computeX(&p.Y) 101 if isLexicographicallyLargest { 102 if !p.X.LexicographicallyLargest() { 103 p.X.Neg(&p.X) 104 } 105 } else { 106 if p.X.LexicographicallyLargest() { 107 p.X.Neg(&p.X) 108 } 109 } 110 111 return sizePointCompressed, nil 112 } 113 114 // Unmarshal alias to SetBytes() 115 func (p *PointAffine) Unmarshal(b []byte) error { 116 _, err := p.SetBytes(b) 117 return err 118 } 119 120 // Set sets p to p1 and return it 121 func (p *PointAffine) Set(p1 *PointAffine) *PointAffine { 122 p.X.Set(&p1.X) 123 p.Y.Set(&p1.Y) 124 return p 125 } 126 127 // Equal returns true if p=p1 false otherwise 128 func (p *PointAffine) Equal(p1 *PointAffine) bool { 129 return p.X.Equal(&p1.X) && p.Y.Equal(&p1.Y) 130 } 131 132 // IsZero returns true if p=0 false otherwise 133 func (p *PointAffine) IsZero() bool { 134 var one fr.Element 135 one.SetOne() 136 return p.X.IsZero() && p.Y.Equal(&one) 137 } 138 139 // NewPointAffine creates a new instance of PointAffine 140 func NewPointAffine(x, y fr.Element) PointAffine { 141 return PointAffine{x, y} 142 } 143 144 // IsOnCurve checks if a point is on the twisted Edwards curve 145 func (p *PointAffine) IsOnCurve() bool { 146 initOnce.Do(initCurveParams) 147 148 var lhs, rhs, tmp fr.Element 149 150 tmp.Mul(&p.Y, &p.Y) 151 lhs.Mul(&p.X, &p.X) 152 mulByA(&lhs) 153 lhs.Add(&lhs, &tmp) 154 155 tmp.Mul(&p.X, &p.X). 156 Mul(&tmp, &p.Y). 157 Mul(&tmp, &p.Y). 158 Mul(&tmp, &curveParams.D) 159 rhs.SetOne().Add(&rhs, &tmp) 160 161 return lhs.Equal(&rhs) 162 } 163 164 // Neg sets p to -p1 and returns it 165 func (p *PointAffine) Neg(p1 *PointAffine) *PointAffine { 166 p.X.Neg(&p1.X) 167 p.Y = p1.Y 168 return p 169 } 170 171 // Add adds two points (x,y), (u,v) on a twisted Edwards curve with parameters a, d 172 // modifies p 173 func (p *PointAffine) Add(p1, p2 *PointAffine) *PointAffine { 174 initOnce.Do(initCurveParams) 175 176 var xu, yv, xv, yu, dxyuv, one, denx, deny fr.Element 177 pRes := new(PointAffine) 178 xv.Mul(&p1.X, &p2.Y) 179 yu.Mul(&p1.Y, &p2.X) 180 pRes.X.Add(&xv, &yu) 181 182 xu.Mul(&p1.X, &p2.X) 183 mulByA(&xu) 184 yv.Mul(&p1.Y, &p2.Y) 185 pRes.Y.Sub(&yv, &xu) 186 187 dxyuv.Mul(&xv, &yu).Mul(&dxyuv, &curveParams.D) 188 one.SetOne() 189 denx.Add(&one, &dxyuv) 190 deny.Sub(&one, &dxyuv) 191 192 p.X.Div(&pRes.X, &denx) 193 p.Y.Div(&pRes.Y, &deny) 194 195 return p 196 } 197 198 // Double doubles point (x,y) on a twisted Edwards curve with parameters a, d 199 // modifies p 200 func (p *PointAffine) Double(p1 *PointAffine) *PointAffine { 201 202 p.Set(p1) 203 var xx, yy, xy, denum, two fr.Element 204 205 xx.Square(&p.X) 206 yy.Square(&p.Y) 207 xy.Mul(&p.X, &p.Y) 208 mulByA(&xx) 209 denum.Add(&xx, &yy) 210 211 p.X.Double(&xy).Div(&p.X, &denum) 212 213 two.SetOne().Double(&two) 214 denum.Neg(&denum).Add(&denum, &two) 215 216 p.Y.Sub(&yy, &xx).Div(&p.Y, &denum) 217 218 return p 219 } 220 221 // FromProj sets p in affine from p in projective 222 func (p *PointAffine) FromProj(p1 *PointProj) *PointAffine { 223 var I fr.Element 224 I.Inverse(&p1.Z) 225 p.X.Mul(&p1.X, &I) 226 p.Y.Mul(&p1.Y, &I) 227 return p 228 } 229 230 // FromExtended sets p in affine from p in extended coordinates 231 func (p *PointAffine) FromExtended(p1 *PointExtended) *PointAffine { 232 var I fr.Element 233 I.Inverse(&p1.Z) 234 p.X.Mul(&p1.X, &I) 235 p.Y.Mul(&p1.Y, &I) 236 return p 237 } 238 239 // ScalarMultiplication scalar multiplication of a point 240 // p1 in affine coordinates with a scalar in big.Int 241 func (p *PointAffine) ScalarMultiplication(p1 *PointAffine, scalar *big.Int) *PointAffine { 242 243 var p1Extended, resExtended PointExtended 244 p1Extended.FromAffine(p1) 245 resExtended.ScalarMultiplication(&p1Extended, scalar) 246 p.FromExtended(&resExtended) 247 248 return p 249 } 250 251 // setInfinity sets p to O (0:1) 252 func (p *PointAffine) setInfinity() *PointAffine { 253 p.X.SetZero() 254 p.Y.SetOne() 255 return p 256 } 257 258 //-------- Projective coordinates 259 260 // Set sets p to p1 and return it 261 func (p *PointProj) Set(p1 *PointProj) *PointProj { 262 p.X.Set(&p1.X) 263 p.Y.Set(&p1.Y) 264 p.Z.Set(&p1.Z) 265 return p 266 } 267 268 // setInfinity sets p to O (0:1:1) 269 func (p *PointProj) setInfinity() *PointProj { 270 p.X.SetZero() 271 p.Y.SetOne() 272 p.Z.SetOne() 273 return p 274 } 275 276 // Equal returns true if p=p1 false otherwise 277 // If one point is on the affine chart Z=0 it returns false 278 func (p *PointProj) Equal(p1 *PointProj) bool { 279 // If one point is infinity, the other must also be infinity. 280 if p.Z.IsZero() { 281 return p1.Z.IsZero() 282 } 283 // If the other point is infinity, return false since we can't 284 // the following checks would be incorrect. 285 if p1.Z.IsZero() { 286 return false 287 } 288 289 var lhs, rhs fr.Element 290 lhs.Mul(&p.X, &p1.Z) 291 rhs.Mul(&p1.X, &p.Z) 292 if !lhs.Equal(&rhs) { 293 return false 294 } 295 lhs.Mul(&p.Y, &p1.Z) 296 rhs.Mul(&p1.Y, &p.Z) 297 298 return lhs.Equal(&rhs) 299 } 300 301 // IsZero returns true if p=0 false otherwise 302 func (p *PointProj) IsZero() bool { 303 return p.X.IsZero() && p.Y.Equal(&p.Z) 304 } 305 306 // Neg negates point (x,y) on a twisted Edwards curve with parameters a, d 307 // modifies p 308 func (p *PointProj) Neg(p1 *PointProj) *PointProj { 309 p.X.Neg(&p1.X) 310 p.Y = p1.Y 311 p.Z = p1.Z 312 return p 313 } 314 315 // FromAffine sets p in projective from p in affine 316 func (p *PointProj) FromAffine(p1 *PointAffine) *PointProj { 317 p.X.Set(&p1.X) 318 p.Y.Set(&p1.Y) 319 p.Z.SetOne() 320 return p 321 } 322 323 // MixedAdd adds a point in projective to a point in affine coordinates 324 // cf https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#addition-madd-2008-bbjlp 325 func (p *PointProj) MixedAdd(p1 *PointProj, p2 *PointAffine) *PointProj { 326 initOnce.Do(initCurveParams) 327 328 var B, C, D, E, F, G, H, I fr.Element 329 B.Square(&p1.Z) 330 C.Mul(&p1.X, &p2.X) 331 D.Mul(&p1.Y, &p2.Y) 332 E.Mul(&curveParams.D, &C).Mul(&E, &D) 333 F.Sub(&B, &E) 334 G.Add(&B, &E) 335 H.Add(&p1.X, &p1.Y) 336 I.Add(&p2.X, &p2.Y) 337 p.X.Mul(&H, &I). 338 Sub(&p.X, &C). 339 Sub(&p.X, &D). 340 Mul(&p.X, &p1.Z). 341 Mul(&p.X, &F) 342 mulByA(&C) 343 p.Y.Sub(&D, &C). 344 Mul(&p.Y, &p1.Z). 345 Mul(&p.Y, &G) 346 p.Z.Mul(&F, &G) 347 348 return p 349 } 350 351 // Double adds points in projective coordinates 352 // cf https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#doubling-dbl-2008-bbjlp 353 func (p *PointProj) Double(p1 *PointProj) *PointProj { 354 355 var B, C, D, E, F, H, J fr.Element 356 357 B.Add(&p1.X, &p1.Y).Square(&B) 358 C.Square(&p1.X) 359 D.Square(&p1.Y) 360 E.Set(&C) 361 mulByA(&E) 362 F.Add(&E, &D) 363 H.Square(&p1.Z) 364 J.Sub(&F, &H).Sub(&J, &H) 365 p.X.Sub(&B, &C). 366 Sub(&p.X, &D). 367 Mul(&p.X, &J) 368 p.Y.Sub(&E, &D).Mul(&p.Y, &F) 369 p.Z.Mul(&F, &J) 370 371 return p 372 } 373 374 // Add adds points in projective coordinates 375 // cf https://hyperelliptic.org/EFD/g1p/auto-twisted-projective.html#addition-add-2008-bbjlp 376 func (p *PointProj) Add(p1, p2 *PointProj) *PointProj { 377 initOnce.Do(initCurveParams) 378 379 var A, B, C, D, E, F, G, H, I fr.Element 380 A.Mul(&p1.Z, &p2.Z) 381 B.Square(&A) 382 C.Mul(&p1.X, &p2.X) 383 D.Mul(&p1.Y, &p2.Y) 384 E.Mul(&curveParams.D, &C).Mul(&E, &D) 385 F.Sub(&B, &E) 386 G.Add(&B, &E) 387 H.Add(&p1.X, &p1.Y) 388 I.Add(&p2.X, &p2.Y) 389 p.X.Mul(&H, &I). 390 Sub(&p.X, &C). 391 Sub(&p.X, &D). 392 Mul(&p.X, &A). 393 Mul(&p.X, &F) 394 mulByA(&C) 395 C.Neg(&C) 396 p.Y.Add(&D, &C). 397 Mul(&p.Y, &A). 398 Mul(&p.Y, &G) 399 p.Z.Mul(&F, &G) 400 401 return p 402 } 403 404 // scalarMulWindowed scalar multiplication of a point 405 // p1 in projective coordinates with a scalar in big.Int 406 // using the windowed double-and-add method. 407 func (p *PointProj) scalarMulWindowed(p1 *PointProj, scalar *big.Int) *PointProj { 408 var _scalar big.Int 409 _scalar.Set(scalar) 410 p.Set(p1) 411 if _scalar.Sign() == -1 { 412 _scalar.Neg(&_scalar) 413 p.Neg(p) 414 } 415 var resProj PointProj 416 resProj.setInfinity() 417 const wordSize = bits.UintSize 418 sWords := _scalar.Bits() 419 420 for i := len(sWords) - 1; i >= 0; i-- { 421 ithWord := sWords[i] 422 for k := 0; k < wordSize; k++ { 423 resProj.Double(&resProj) 424 kthBit := (ithWord >> (wordSize - 1 - k)) & 1 425 if kthBit == 1 { 426 resProj.Add(&resProj, p) 427 } 428 } 429 } 430 431 p.Set(&resProj) 432 return p 433 } 434 435 // ScalarMultiplication scalar multiplication of a point 436 // p1 in projective coordinates with a scalar in big.Int 437 func (p *PointProj) ScalarMultiplication(p1 *PointProj, scalar *big.Int) *PointProj { 438 {{- if .HasEndomorphism}} 439 return p.scalarMulGLV(p1, scalar) 440 {{- else }} 441 return p.scalarMulWindowed(p1, scalar) 442 {{- end}} 443 } 444 445 // ------- Extended coordinates 446 447 // Set sets p to p1 and return it 448 func (p *PointExtended) Set(p1 *PointExtended) *PointExtended { 449 p.X.Set(&p1.X) 450 p.Y.Set(&p1.Y) 451 p.T.Set(&p1.T) 452 p.Z.Set(&p1.Z) 453 return p 454 } 455 456 // IsZero returns true if p=0 false otherwise 457 func (p *PointExtended) IsZero() bool { 458 return p.X.IsZero() && p.Y.Equal(&p.Z) && p.T.IsZero() 459 } 460 461 // Equal returns true if p=p1 false otherwise 462 // If one point is on the affine chart Z=0 it returns false 463 func (p *PointExtended) Equal(p1 *PointExtended) bool { 464 if p.Z.IsZero() || p1.Z.IsZero() { 465 return false 466 } 467 var pAffine, p1Affine PointAffine 468 pAffine.FromExtended(p) 469 p1Affine.FromExtended(p1) 470 return pAffine.Equal(&p1Affine) 471 } 472 473 // Neg negates point (x,y) on a twisted Edwards curve with parameters a, d 474 // modifies p 475 func (p *PointExtended) Neg(p1 *PointExtended) *PointExtended { 476 p.X.Neg(&p1.X) 477 p.Y = p1.Y 478 p.Z = p1.Z 479 p.T.Neg(&p1.T) 480 return p 481 } 482 483 // FromAffine sets p in projective from p in affine 484 func (p *PointExtended) FromAffine(p1 *PointAffine) *PointExtended { 485 p.X.Set(&p1.X) 486 p.Y.Set(&p1.Y) 487 p.Z.SetOne() 488 p.T.Mul(&p1.X, &p1.Y) 489 return p 490 } 491 492 // Add adds points in extended coordinates 493 // See https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-add-2008-hwcd 494 func (p *PointExtended) Add(p1, p2 *PointExtended) *PointExtended { 495 var A, B, C, D, E, F, G, H, tmp fr.Element 496 A.Mul(&p1.X, &p2.X) 497 B.Mul(&p1.Y, &p2.Y) 498 C.Mul(&p1.T, &p2.T).Mul(&C, &curveParams.D) 499 D.Mul(&p1.Z, &p2.Z) 500 tmp.Add(&p1.X, &p1.Y) 501 E.Add(&p2.X, &p2.Y). 502 Mul(&E, &tmp). 503 Sub(&E, &A). 504 Sub(&E, &B) 505 F.Sub(&D, &C) 506 G.Add(&D, &C) 507 H.Set(&A) 508 mulByA(&H) 509 H.Sub(&B, &H) 510 511 p.X.Mul(&E, &F) 512 p.Y.Mul(&G, &H) 513 p.T.Mul(&E, &H) 514 p.Z.Mul(&F, &G) 515 516 return p 517 } 518 519 // MixedAdd adds a point in extended coordinates to a point in affine coordinates 520 // See https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#addition-madd-2008-hwcd-2 521 func (p *PointExtended) MixedAdd(p1 *PointExtended, p2 *PointAffine) *PointExtended { 522 var A, B, C, D, E, F, G, H, tmp fr.Element 523 524 A.Mul(&p2.X, &p1.Z) 525 B.Mul(&p2.Y, &p1.Z) 526 527 if p1.X.Equal(&A) && p1.Y.Equal(&B) { 528 p.MixedDouble(p1) 529 return p 530 } 531 532 A.Mul(&p1.X, &p2.X) 533 B.Mul(&p1.Y, &p2.Y) 534 C.Mul(&p1.Z, &p2.X). 535 Mul(&C, &p2.Y) 536 D.Set(&p1.T) 537 E.Add(&D, &C) 538 tmp.Sub(&p1.X, &p1.Y) 539 F.Add(&p2.X, &p2.Y). 540 Mul(&F, &tmp). 541 Add(&F, &B). 542 Sub(&F, &A) 543 G.Set(&A) 544 mulByA(&G) 545 G.Add(&G, &B) 546 H.Sub(&D, &C) 547 548 p.X.Mul(&E, &F) 549 p.Y.Mul(&G, &H) 550 p.T.Mul(&E, &H) 551 p.Z.Mul(&F, &G) 552 553 return p 554 } 555 556 // Double adds points in extended coordinates 557 // Dedicated doubling 558 {{- if or (eq .Name "bls12-378") (eq .Name "bw6-756")}} 559 // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-dbl-2008-hwcd 560 {{- else}} 561 // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-dbl-2008-hwcd 562 {{- end}} 563 func (p *PointExtended) Double(p1 *PointExtended) *PointExtended { 564 565 var A, B, C, D, E, F, G, H fr.Element 566 567 A.Square(&p1.X) 568 B.Square(&p1.Y) 569 C.Square(&p1.Z). 570 Double(&C) 571 D.Set(&A) 572 mulByA(&D) 573 E.Add(&p1.X, &p1.Y). 574 Square(&E). 575 Sub(&E, &A). 576 Sub(&E, &B) 577 G.Add(&D, &B) 578 F.Sub(&G, &C) 579 H.Sub(&D, &B) 580 581 p.X.Mul(&E, &F) 582 p.Y.Mul(&G, &H) 583 p.T.Mul(&H, &E) 584 p.Z.Mul(&F, &G) 585 586 return p 587 } 588 589 // MixedDouble adds points in extended coordinates 590 // Dedicated mixed doubling 591 {{- if or (eq .Name "bls12-378") (eq .Name "bw6-756")}} 592 // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended.html#doubling-mdbl-2008-hwcd 593 {{- else}} 594 // https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#doubling-mdbl-2008-hwcd 595 {{- end}} 596 func (p *PointExtended) MixedDouble(p1 *PointExtended) *PointExtended { 597 598 var A, B, D, E, G, H, two fr.Element 599 two.SetUint64(2) 600 601 A.Square(&p1.X) 602 B.Square(&p1.Y) 603 D.Set(&A) 604 mulByA(&D) 605 E.Add(&p1.X, &p1.Y). 606 Square(&E). 607 Sub(&E, &A). 608 Sub(&E, &B) 609 G.Add(&D, &B) 610 H.Sub(&D, &B) 611 612 p.X.Sub(&G, &two). 613 Mul(&p.X, &E) 614 p.Y.Mul(&G, &H) 615 p.T.Mul(&H, &E) 616 p.Z.Square(&G). 617 Sub(&p.Z, &G). 618 Sub(&p.Z, &G) 619 620 return p 621 } 622 623 // setInfinity sets p to O (0:1:1:0) 624 func (p *PointExtended) setInfinity() *PointExtended { 625 p.X.SetZero() 626 p.Y.SetOne() 627 p.Z.SetOne() 628 p.T.SetZero() 629 return p 630 } 631 632 // scalarMulWindowed scalar multiplication of a point 633 // p1 in extended coordinates with a scalar in big.Int 634 // using the windowed double-and-add method. 635 func (p *PointExtended) scalarMulWindowed(p1 *PointExtended, scalar *big.Int) *PointExtended { 636 var _scalar big.Int 637 _scalar.Set(scalar) 638 p.Set(p1) 639 if _scalar.Sign() == -1 { 640 _scalar.Neg(&_scalar) 641 p.Neg(p) 642 } 643 var resExtended PointExtended 644 resExtended.setInfinity() 645 const wordSize = bits.UintSize 646 sWords := _scalar.Bits() 647 648 for i := len(sWords) - 1; i >= 0; i-- { 649 ithWord := sWords[i] 650 for k := 0; k < wordSize; k++ { 651 resExtended.Double(&resExtended) 652 kthBit := (ithWord >> (wordSize - 1 - k)) & 1 653 if kthBit == 1 { 654 resExtended.Add(&resExtended, p) 655 } 656 } 657 } 658 659 p.Set(&resExtended) 660 return p 661 } 662 663 // ScalarMultiplication scalar multiplication of a point 664 // p1 in extended coordinates with a scalar in big.Int 665 func (p *PointExtended) ScalarMultiplication(p1 *PointExtended, scalar *big.Int) *PointExtended { 666 {{- if .HasEndomorphism}} 667 return p.scalarMulGLV(p1, scalar) 668 {{- else }} 669 return p.scalarMulWindowed(p1, scalar) 670 {{- end}} 671 }