github.com/cloudflare/circl@v1.5.0/ecc/p384/point.go (about) 1 //go:build (!purego && arm64) || (!purego && amd64) 2 // +build !purego,arm64 !purego,amd64 3 4 package p384 5 6 import ( 7 "fmt" 8 "math/big" 9 ) 10 11 // affinePoint represents an affine point of the curve. The point at 12 // infinity is (0,0) leveraging that it is not an affine point. 13 type affinePoint struct{ x, y fp384 } 14 15 func newAffinePoint(x, y *big.Int) *affinePoint { 16 var P affinePoint 17 P.x.SetBigInt(x) 18 P.y.SetBigInt(y) 19 montEncode(&P.x, &P.x) 20 montEncode(&P.y, &P.y) 21 return &P 22 } 23 24 func zeroPoint() *affinePoint { return &affinePoint{} } 25 26 func (ap affinePoint) String() string { 27 if ap.isZero() { 28 return "inf" 29 } 30 return fmt.Sprintf("x: %v\ny: %v", ap.x, ap.y) 31 } 32 33 func (ap *affinePoint) isZero() bool { 34 zero := fp384{} 35 return ap.x == zero && ap.y == zero 36 } 37 38 func (ap *affinePoint) neg() { fp384Neg(&ap.y, &ap.y) } 39 40 func (ap *affinePoint) toInt() (x, y *big.Int) { 41 var x1, y1 fp384 42 montDecode(&x1, &ap.x) 43 montDecode(&y1, &ap.y) 44 return x1.BigInt(), y1.BigInt() 45 } 46 47 func (ap *affinePoint) toJacobian() *jacobianPoint { 48 var P jacobianPoint 49 if ap.isZero() { 50 montEncode(&P.x, &fp384{1}) 51 montEncode(&P.y, &fp384{1}) 52 } else { 53 P.x = ap.x 54 P.y = ap.y 55 montEncode(&P.z, &fp384{1}) 56 } 57 return &P 58 } 59 60 func (ap *affinePoint) toProjective() *projectivePoint { 61 var P projectivePoint 62 if ap.isZero() { 63 montEncode(&P.y, &fp384{1}) 64 } else { 65 P.x = ap.x 66 P.y = ap.y 67 montEncode(&P.z, &fp384{1}) 68 } 69 return &P 70 } 71 72 // OddMultiples calculates the points iP for i={1,3,5,7,..., 2^(n-1)-1} 73 // Ensure that 1 < n < 31, otherwise it returns an empty slice. 74 func (ap affinePoint) oddMultiples(n uint) []jacobianPoint { 75 var t []jacobianPoint 76 if n > 1 && n < 31 { 77 P := ap.toJacobian() 78 s := int32(1) << (n - 1) 79 t = make([]jacobianPoint, s) 80 t[0] = *P 81 _2P := *P 82 _2P.double() 83 for i := int32(1); i < s; i++ { 84 t[i].add(&t[i-1], &_2P) 85 } 86 } 87 return t 88 } 89 90 // p2Point is a point in P^2 91 type p2Point struct{ x, y, z fp384 } 92 93 func (P *p2Point) String() string { 94 return fmt.Sprintf("x: %v\ny: %v\nz: %v", P.x, P.y, P.z) 95 } 96 97 func (P *p2Point) neg() { fp384Neg(&P.y, &P.y) } 98 99 // condNeg if P is negated if b=1. 100 func (P *p2Point) cneg(b int) { 101 var mY fp384 102 fp384Neg(&mY, &P.y) 103 fp384Cmov(&P.y, &mY, b) 104 } 105 106 // cmov sets P to Q if b=1. 107 func (P *p2Point) cmov(Q *p2Point, b int) { 108 fp384Cmov(&P.x, &Q.x, b) 109 fp384Cmov(&P.y, &Q.y, b) 110 fp384Cmov(&P.z, &Q.z, b) 111 } 112 113 func (P *p2Point) toInt() (x, y, z *big.Int) { 114 var x1, y1, z1 fp384 115 montDecode(&x1, &P.x) 116 montDecode(&y1, &P.y) 117 montDecode(&z1, &P.z) 118 return x1.BigInt(), y1.BigInt(), z1.BigInt() 119 } 120 121 // jacobianPoint represents a point in Jacobian coordinates. The point at 122 // infinity is any point (x,y,0) such that x and y are different from 0. 123 type jacobianPoint struct{ p2Point } 124 125 func (P *jacobianPoint) isZero() bool { 126 zero := fp384{} 127 return P.x != zero && P.y != zero && P.z == zero 128 } 129 130 func (P *jacobianPoint) toAffine() *affinePoint { 131 var aP affinePoint 132 z, z2 := &fp384{}, &fp384{} 133 fp384Inv(z, &P.z) 134 fp384Sqr(z2, z) 135 fp384Mul(&aP.x, &P.x, z2) 136 fp384Mul(&aP.y, &P.y, z) 137 fp384Mul(&aP.y, &aP.y, z2) 138 return &aP 139 } 140 141 func (P *jacobianPoint) cmov(Q *jacobianPoint, b int) { P.p2Point.cmov(&Q.p2Point, b) } 142 143 // add calculates P=Q+R such that Q and R are different than the identity point, 144 // and Q!==R. This function cannot be used for doublings. 145 func (P *jacobianPoint) add(Q, R *jacobianPoint) { 146 if Q.isZero() { 147 *P = *R 148 return 149 } else if R.isZero() { 150 *P = *Q 151 return 152 } 153 154 // Cohen-Miyagi-Ono (1998) 155 // https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2 156 X1, Y1, Z1 := &Q.x, &Q.y, &Q.z 157 X2, Y2, Z2 := &R.x, &R.y, &R.z 158 Z1Z1, Z2Z2, U1, U2 := &fp384{}, &fp384{}, &fp384{}, &fp384{} 159 H, HH, HHH, RR := &fp384{}, &fp384{}, &fp384{}, &fp384{} 160 V, t4, t5, t6, t7, t8 := &fp384{}, &fp384{}, &fp384{}, &fp384{}, &fp384{}, &fp384{} 161 t0, t1, t2, t3, S1, S2 := &fp384{}, &fp384{}, &fp384{}, &fp384{}, &fp384{}, &fp384{} 162 fp384Sqr(Z1Z1, Z1) // Z1Z1 = Z1 ^ 2 163 fp384Sqr(Z2Z2, Z2) // Z2Z2 = Z2 ^ 2 164 fp384Mul(U1, X1, Z2Z2) // U1 = X1 * Z2Z2 165 fp384Mul(U2, X2, Z1Z1) // U2 = X2 * Z1Z1 166 fp384Mul(t0, Z2, Z2Z2) // t0 = Z2 * Z2Z2 167 fp384Mul(S1, Y1, t0) // S1 = Y1 * t0 168 fp384Mul(t1, Z1, Z1Z1) // t1 = Z1 * Z1Z1 169 fp384Mul(S2, Y2, t1) // S2 = Y2 * t1 170 fp384Sub(H, U2, U1) // H = U2 - U1 171 fp384Sqr(HH, H) // HH = H ^ 2 172 fp384Mul(HHH, H, HH) // HHH = H * HH 173 fp384Sub(RR, S2, S1) // r = S2 - S1 174 fp384Mul(V, U1, HH) // V = U1 * HH 175 fp384Sqr(t2, RR) // t2 = r ^ 2 176 fp384Add(t3, V, V) // t3 = V + V 177 fp384Sub(t4, t2, HHH) // t4 = t2 - HHH 178 fp384Sub(&P.x, t4, t3) // X3 = t4 - t3 179 fp384Sub(t5, V, &P.x) // t5 = V - X3 180 fp384Mul(t6, S1, HHH) // t6 = S1 * HHH 181 fp384Mul(t7, RR, t5) // t7 = r * t5 182 fp384Sub(&P.y, t7, t6) // Y3 = t7 - t6 183 fp384Mul(t8, Z2, H) // t8 = Z2 * H 184 fp384Mul(&P.z, Z1, t8) // Z3 = Z1 * t8 185 } 186 187 // mixadd calculates P=Q+R such that P and Q different than the identity point, 188 // and Q not in {P,-P, O}. 189 func (P *jacobianPoint) mixadd(Q *jacobianPoint, R *affinePoint) { 190 if Q.isZero() { 191 *P = *R.toJacobian() 192 return 193 } else if R.isZero() { 194 *P = *Q 195 return 196 } 197 198 z1z1, u2 := &fp384{}, &fp384{} 199 fp384Sqr(z1z1, &Q.z) 200 fp384Mul(u2, &R.x, z1z1) 201 202 s2 := &fp384{} 203 fp384Mul(s2, &R.y, &Q.z) 204 fp384Mul(s2, s2, z1z1) 205 if Q.x == *u2 { 206 if Q.y != *s2 { 207 *P = *(zeroPoint().toJacobian()) 208 return 209 } 210 *P = *Q 211 P.double() 212 return 213 } 214 215 h, r := &fp384{}, &fp384{} 216 fp384Sub(h, u2, &Q.x) 217 fp384Mul(&P.z, h, &Q.z) 218 fp384Sub(r, s2, &Q.y) 219 220 h2, h3 := &fp384{}, &fp384{} 221 fp384Sqr(h2, h) 222 fp384Mul(h3, h2, h) 223 h3y1 := &fp384{} 224 fp384Mul(h3y1, h3, &Q.y) 225 226 h2x1 := &fp384{} 227 fp384Mul(h2x1, h2, &Q.x) 228 229 fp384Sqr(&P.x, r) 230 fp384Sub(&P.x, &P.x, h3) 231 fp384Sub(&P.x, &P.x, h2x1) 232 fp384Sub(&P.x, &P.x, h2x1) 233 234 fp384Sub(&P.y, h2x1, &P.x) 235 fp384Mul(&P.y, &P.y, r) 236 fp384Sub(&P.y, &P.y, h3y1) 237 } 238 239 func (P *jacobianPoint) double() { 240 delta, gamma, alpha, alpha2 := &fp384{}, &fp384{}, &fp384{}, &fp384{} 241 fp384Sqr(delta, &P.z) 242 fp384Sqr(gamma, &P.y) 243 fp384Sub(alpha, &P.x, delta) 244 fp384Add(alpha2, &P.x, delta) 245 fp384Mul(alpha, alpha, alpha2) 246 *alpha2 = *alpha 247 fp384Add(alpha, alpha, alpha) 248 fp384Add(alpha, alpha, alpha2) 249 250 beta := &fp384{} 251 fp384Mul(beta, &P.x, gamma) 252 253 beta8 := &fp384{} 254 fp384Sqr(&P.x, alpha) 255 fp384Add(beta8, beta, beta) 256 fp384Add(beta8, beta8, beta8) 257 fp384Add(beta8, beta8, beta8) 258 fp384Sub(&P.x, &P.x, beta8) 259 260 fp384Add(&P.z, &P.y, &P.z) 261 fp384Sqr(&P.z, &P.z) 262 fp384Sub(&P.z, &P.z, gamma) 263 fp384Sub(&P.z, &P.z, delta) 264 265 fp384Add(beta, beta, beta) 266 fp384Add(beta, beta, beta) 267 fp384Sub(beta, beta, &P.x) 268 269 fp384Mul(&P.y, alpha, beta) 270 271 fp384Sqr(gamma, gamma) 272 fp384Add(gamma, gamma, gamma) 273 fp384Add(gamma, gamma, gamma) 274 fp384Add(gamma, gamma, gamma) 275 fp384Sub(&P.y, &P.y, gamma) 276 } 277 278 func (P *jacobianPoint) toProjective() *projectivePoint { 279 var hP projectivePoint 280 hP.y = P.y 281 fp384Mul(&hP.x, &P.x, &P.z) 282 fp384Sqr(&hP.z, &P.z) 283 fp384Mul(&hP.z, &hP.z, &P.z) 284 return &hP 285 } 286 287 // projectivePoint represents a point in projective homogeneous coordinates. 288 // The point at infinity is (0,y,0) such that y is different from 0. 289 type projectivePoint struct{ p2Point } 290 291 func (P *projectivePoint) isZero() bool { 292 zero := fp384{} 293 return P.x == zero && P.y != zero && P.z == zero 294 } 295 296 func (P *projectivePoint) toAffine() *affinePoint { 297 var aP affinePoint 298 z := &fp384{} 299 fp384Inv(z, &P.z) 300 fp384Mul(&aP.x, &P.x, z) 301 fp384Mul(&aP.y, &P.y, z) 302 return &aP 303 } 304 305 // add calculates P=Q+R using complete addition formula for prime groups. 306 func (P *projectivePoint) completeAdd(Q, R *projectivePoint) { 307 // Reference: 308 // "Complete addition formulas for prime order elliptic curves" by 309 // Costello-Renes-Batina. [Alg.4] (eprint.iacr.org/2015/1060). 310 X1, Y1, Z1 := &Q.x, &Q.y, &Q.z 311 X2, Y2, Z2 := &R.x, &R.y, &R.z 312 X3, Y3, Z3 := &fp384{}, &fp384{}, &fp384{} 313 t0, t1, t2, t3, t4 := &fp384{}, &fp384{}, &fp384{}, &fp384{}, &fp384{} 314 fp384Mul(t0, X1, X2) // 1. t0 ← X1 · X2 315 fp384Mul(t1, Y1, Y2) // 2. t1 ← Y1 · Y2 316 fp384Mul(t2, Z1, Z2) // 3. t2 ← Z1 · Z2 317 fp384Add(t3, X1, Y1) // 4. t3 ← X1 + Y1 318 fp384Add(t4, X2, Y2) // 5. t4 ← X2 + Y2 319 fp384Mul(t3, t3, t4) // 6. t3 ← t3 · t4 320 fp384Add(t4, t0, t1) // 7. t4 ← t0 + t1 321 fp384Sub(t3, t3, t4) // 8. t3 ← t3 − t4 322 fp384Add(t4, Y1, Z1) // 9. t4 ← Y1 + Z1 323 fp384Add(X3, Y2, Z2) // 10. X3 ← Y2 + Z2 324 fp384Mul(t4, t4, X3) // 11. t4 ← t4 · X3 325 fp384Add(X3, t1, t2) // 12. X3 ← t1 + t2 326 fp384Sub(t4, t4, X3) // 13. t4 ← t4 − X3 327 fp384Add(X3, X1, Z1) // 14. X3 ← X1 + Z1 328 fp384Add(Y3, X2, Z2) // 15. Y3 ← X2 + Z2 329 fp384Mul(X3, X3, Y3) // 16. X3 ← X3 · Y3 330 fp384Add(Y3, t0, t2) // 17. Y3 ← t0 + t2 331 fp384Sub(Y3, X3, Y3) // 18. Y3 ← X3 − Y3 332 fp384Mul(Z3, &bb, t2) // 19. Z3 ← b · t2 333 fp384Sub(X3, Y3, Z3) // 20. X3 ← Y3 − Z3 334 fp384Add(Z3, X3, X3) // 21. Z3 ← X3 + X3 335 fp384Add(X3, X3, Z3) // 22. X3 ← X3 + Z3 336 fp384Sub(Z3, t1, X3) // 23. Z3 ← t1 − X3 337 fp384Add(X3, t1, X3) // 24. X3 ← t1 + X3 338 fp384Mul(Y3, &bb, Y3) // 25. Y3 ← b · Y3 339 fp384Add(t1, t2, t2) // 26. t1 ← t2 + t2 340 fp384Add(t2, t1, t2) // 27. t2 ← t1 + t2 341 fp384Sub(Y3, Y3, t2) // 28. Y3 ← Y3 − t2 342 fp384Sub(Y3, Y3, t0) // 29. Y3 ← Y3 − t0 343 fp384Add(t1, Y3, Y3) // 30. t1 ← Y3 + Y3 344 fp384Add(Y3, t1, Y3) // 31. Y3 ← t1 + Y3 345 fp384Add(t1, t0, t0) // 32. t1 ← t0 + t0 346 fp384Add(t0, t1, t0) // 33. t0 ← t1 + t0 347 fp384Sub(t0, t0, t2) // 34. t0 ← t0 − t2 348 fp384Mul(t1, t4, Y3) // 35. t1 ← t4 · Y3 349 fp384Mul(t2, t0, Y3) // 36. t2 ← t0 · Y3 350 fp384Mul(Y3, X3, Z3) // 37. Y3 ← X3 · Z3 351 fp384Add(Y3, Y3, t2) // 38. Y3 ← Y3 + t2 352 fp384Mul(X3, t3, X3) // 39. X3 ← t3 · X3 353 fp384Sub(X3, X3, t1) // 40. X3 ← X3 − t1 354 fp384Mul(Z3, t4, Z3) // 41. Z3 ← t4 · Z3 355 fp384Mul(t1, t3, t0) // 42. t1 ← t3 · t0 356 fp384Add(Z3, Z3, t1) // 43. Z3 ← Z3 + t1 357 P.x, P.y, P.z = *X3, *Y3, *Z3 358 }