github.com/cloudflare/circl@v1.5.0/dh/sidh/internal/p751/curve.go (about) 1 // Code generated by go generate; DO NOT EDIT. 2 // This file was generated by robots. 3 4 package p751 5 6 import ( 7 "errors" 8 . "github.com/cloudflare/circl/dh/sidh/internal/common" 9 "math" 10 ) 11 12 // Stores isogeny 3 curve constants 13 type isogeny3 struct { 14 K1 Fp2 15 K2 Fp2 16 } 17 18 // Stores isogeny 4 curve constants 19 type isogeny4 struct { 20 isogeny3 21 K3 Fp2 22 } 23 24 // Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result 25 // is returned in jBytes buffer, encoded in little-endian format. Caller 26 // provided jBytes buffer has to be big enough to j-invariant value. In case 27 // of SIDH, buffer size must be at least size of shared secret. 28 // Implementation corresponds to Algorithm 9 from SIKE. 29 func Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) { 30 var t0, t1 Fp2 31 32 sqr(j, &cparams.A) // j = A^2 33 sqr(&t1, &cparams.C) // t1 = C^2 34 add(&t0, &t1, &t1) // t0 = t1 + t1 35 sub(&t0, j, &t0) // t0 = j - t0 36 sub(&t0, &t0, &t1) // t0 = t0 - t1 37 sub(j, &t0, &t1) // t0 = t0 - t1 38 sqr(&t1, &t1) // t1 = t1^2 39 mul(j, j, &t1) // j = j * t1 40 add(&t0, &t0, &t0) // t0 = t0 + t0 41 add(&t0, &t0, &t0) // t0 = t0 + t0 42 sqr(&t1, &t0) // t1 = t0^2 43 mul(&t0, &t0, &t1) // t0 = t0 * t1 44 add(&t0, &t0, &t0) // t0 = t0 + t0 45 add(&t0, &t0, &t0) // t0 = t0 + t0 46 inv(j, j) // j = 1/j 47 mul(j, &t0, j) // j = t0 * j 48 } 49 50 // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function 51 // recovers projective coordinate A of a curve. This is Algorithm 10 from SIKE. 52 func RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) { 53 var t0, t1 Fp2 54 55 add(&t1, xp, xq) // t1 = Xp + Xq 56 mul(&t0, xp, xq) // t0 = Xp * Xq 57 mul(&curve.A, xr, &t1) // A = X(q-p) * t1 58 add(&curve.A, &curve.A, &t0) // A = A + t0 59 mul(&t0, &t0, xr) // t0 = t0 * X(q-p) 60 sub(&curve.A, &curve.A, ¶ms.OneFp2) // A = A - 1 61 add(&t0, &t0, &t0) // t0 = t0 + t0 62 add(&t1, &t1, xr) // t1 = t1 + X(q-p) 63 add(&t0, &t0, &t0) // t0 = t0 + t0 64 sqr(&curve.A, &curve.A) // A = A^2 65 inv(&t0, &t0) // t0 = 1/t0 66 mul(&curve.A, &curve.A, &t0) // A = A * t0 67 sub(&curve.A, &curve.A, &t1) // A = A - t1 68 } 69 70 // Computes equivalence (A:C) ~ (A+2C : A-2C) 71 func CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv { 72 var coef CurveCoefficientsEquiv 73 var c2 Fp2 74 75 add(&c2, &cparams.C, &cparams.C) 76 // A24p = A+2*C 77 add(&coef.A, &cparams.A, &c2) 78 // A24m = A-2*C 79 sub(&coef.C, &cparams.A, &c2) 80 return coef 81 } 82 83 // Computes equivalence (A:C) ~ (A+2C : 4C) 84 func CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv { 85 var coefEq CurveCoefficientsEquiv 86 87 add(&coefEq.C, &cparams.C, &cparams.C) 88 // A24p = A+2C 89 add(&coefEq.A, &cparams.A, &coefEq.C) 90 // C24 = 4*C 91 add(&coefEq.C, &coefEq.C, &coefEq.C) 92 return coefEq 93 } 94 95 // Helper function for RightToLeftLadder(). Returns A+2C / 4. 96 func CalcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2) { 97 var tmp Fp2 98 99 // 2C 100 add(&tmp, &cparams.C, &cparams.C) 101 // A+2C 102 add(&ret, &cparams.A, &tmp) 103 // 1/4C 104 add(&tmp, &tmp, &tmp) 105 inv(&tmp, &tmp) 106 // A+2C/4C 107 mul(&ret, &ret, &tmp) 108 return 109 } 110 111 // Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C). 112 func RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) { 113 add(&cparams.A, &coefEq.A, &coefEq.C) 114 // cparams.A = 2*(A+2C+A-2C) = 4A 115 add(&cparams.A, &cparams.A, &cparams.A) 116 // cparams.C = (A+2C-A+2C) = 4C 117 sub(&cparams.C, &coefEq.A, &coefEq.C) 118 return 119 } 120 121 // Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C). 122 func RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) { 123 // cparams.C = (4C)*1/2=2C 124 mul(&cparams.C, &coefEq.C, ¶ms.HalfFp2) 125 // cparams.A = A+2C - 2C = A 126 sub(&cparams.A, &coefEq.A, &cparams.C) 127 // cparams.C = 2C * 1/2 = C 128 mul(&cparams.C, &cparams.C, ¶ms.HalfFp2) 129 } 130 131 // Combined coordinate doubling and differential addition. Takes projective points 132 // P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E. 133 // Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE 134 func xDbladd(P, Q, QmP *ProjectivePoint, a24 *Fp2) (dblP, PaQ ProjectivePoint) { 135 var t0, t1, t2 Fp2 136 137 xQmP, zQmP := &QmP.X, &QmP.Z 138 xPaQ, zPaQ := &PaQ.X, &PaQ.Z 139 x2P, z2P := &dblP.X, &dblP.Z 140 xP, zP := &P.X, &P.Z 141 xQ, zQ := &Q.X, &Q.Z 142 143 add(&t0, xP, zP) // t0 = Xp+Zp 144 sub(&t1, xP, zP) // t1 = Xp-Zp 145 sqr(x2P, &t0) // 2P.X = t0^2 146 sub(&t2, xQ, zQ) // t2 = Xq-Zq 147 add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq 148 mul(&t0, &t0, &t2) // t0 = t0 * t2 149 mul(z2P, &t1, &t1) // 2P.Z = t1 * t1 150 mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q 151 sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z 152 mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z 153 mul(xPaQ, a24, &t2) // Xp+q = A24 * t2 154 sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1 155 add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z 156 add(xPaQ, &t0, &t1) // Xp+q = t0 + t1 157 mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2 158 sqr(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2 159 sqr(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2 160 mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q 161 mul(xPaQ, zQmP, xPaQ) // Xp+q = Zq-p * Xp+q 162 return 163 } 164 165 // Given the curve parameters, xP = x(P), computes xP = x([2^k]P) 166 // Safe to overlap xP, x2P. 167 func Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) { 168 var t0, t1 Fp2 169 170 x, z := &xP.X, &xP.Z 171 for i := uint32(0); i < k; i++ { 172 sub(&t0, x, z) // t0 = Xp - Zp 173 add(&t1, x, z) // t1 = Xp + Zp 174 sqr(&t0, &t0) // t0 = t0 ^ 2 175 sqr(&t1, &t1) // t1 = t1 ^ 2 176 mul(z, ¶ms.C, &t0) // Z2p = C24 * t0 177 mul(x, z, &t1) // X2p = Z2p * t1 178 sub(&t1, &t1, &t0) // t1 = t1 - t0 179 mul(&t0, ¶ms.A, &t1) // t0 = A24+ * t1 180 add(z, z, &t0) // Z2p = Z2p + t0 181 mul(z, z, &t1) // Zp = Z2p * t1 182 } 183 } 184 185 // Given the curve parameters, xP = x(P), and k >= 0, compute xP = x([3^k]P). 186 // 187 // Safe to overlap xP, xR. 188 func Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) { 189 var t0, t1, t2, t3, t4, t5, t6 Fp2 190 191 x, z := &xP.X, &xP.Z 192 for i := uint32(0); i < k; i++ { 193 sub(&t0, x, z) // t0 = Xp - Zp 194 sqr(&t2, &t0) // t2 = t0^2 195 add(&t1, x, z) // t1 = Xp + Zp 196 sqr(&t3, &t1) // t3 = t1^2 197 add(&t4, &t1, &t0) // t4 = t1 + t0 198 sub(&t0, &t1, &t0) // t0 = t1 - t0 199 sqr(&t1, &t4) // t1 = t4^2 200 sub(&t1, &t1, &t3) // t1 = t1 - t3 201 sub(&t1, &t1, &t2) // t1 = t1 - t2 202 mul(&t5, &t3, ¶ms.A) // t5 = t3 * A24+ 203 mul(&t3, &t3, &t5) // t3 = t5 * t3 204 mul(&t6, &t2, ¶ms.C) // t6 = t2 * A24- 205 mul(&t2, &t2, &t6) // t2 = t2 * t6 206 sub(&t3, &t2, &t3) // t3 = t2 - t3 207 sub(&t2, &t5, &t6) // t2 = t5 - t6 208 mul(&t1, &t2, &t1) // t1 = t2 * t1 209 add(&t2, &t3, &t1) // t2 = t3 + t1 210 sqr(&t2, &t2) // t2 = t2^2 211 mul(x, &t2, &t4) // X3p = t2 * t4 212 sub(&t1, &t3, &t1) // t1 = t3 - t1 213 sqr(&t1, &t1) // t1 = t1^2 214 mul(z, &t1, &t0) // Z3p = t1 * t0 215 } 216 } 217 218 // Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3). 219 // 220 // All xi, yi must be distinct. 221 func Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2) { 222 var x1x2, t Fp2 223 224 mul(&x1x2, x1, x2) // x1*x2 225 mul(&t, &x1x2, x3) // 1/(x1*x2*x3) 226 inv(&t, &t) 227 mul(y1, &t, x2) // 1/x1 228 mul(y1, y1, x3) 229 mul(y2, &t, x1) // 1/x2 230 mul(y2, y2, x3) 231 mul(y3, &t, &x1x2) // 1/x3 232 } 233 234 // Scalarmul3Pt is a right-to-left point multiplication that given the 235 // x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P. 236 // nbits must be smaller or equal to len(scalar). 237 func ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint { 238 var R0, R2, R1 ProjectivePoint 239 aPlus2Over4 := CalcAplus2Over4(cparams) 240 R1 = *P 241 R2 = *PmQ 242 R0 = *Q 243 244 // Iterate over the bits of the scalar, bottom to top 245 prevBit := uint8(0) 246 for i := uint(0); i < nbits; i++ { 247 bit := (scalar[i>>3] >> (i & 7) & 1) 248 swap := prevBit ^ bit 249 prevBit = bit 250 cswap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap) 251 R0, R2 = xDbladd(&R0, &R2, &R1, &aPlus2Over4) 252 } 253 cswap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit) 254 return R1 255 } 256 257 // Given a three-torsion point p = x(PB) on the curve E_(A:C), construct the 258 // three-isogeny phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C'). 259 // 260 // Input: (XP_3: ZP_3), where P_3 has exact order 3 on E_A/C 261 // Output: 262 // - Curve coordinates (A' + 2C', A' - 2C') corresponding to E_A'/C' = A_E/C/<P3> 263 // - Isogeny phi with constants in F_p^2 264 func (phi *isogeny3) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv { 265 var t0, t1, t2, t3, t4 Fp2 266 var coefEq CurveCoefficientsEquiv 267 K1, K2 := &phi.K1, &phi.K2 268 269 sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3 270 sqr(&t0, K1) // t0 = K1^2 271 add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3 272 sqr(&t1, K2) // t1 = K2^2 273 add(&t2, &t0, &t1) // t2 = t0 + t1 274 add(&t3, K1, K2) // t3 = K1 + K2 275 sqr(&t3, &t3) // t3 = t3^2 276 sub(&t3, &t3, &t2) // t3 = t3 - t2 277 add(&t2, &t1, &t3) // t2 = t1 + t3 278 add(&t3, &t3, &t0) // t3 = t3 + t0 279 add(&t4, &t3, &t0) // t4 = t3 + t0 280 add(&t4, &t4, &t4) // t4 = t4 + t4 281 add(&t4, &t1, &t4) // t4 = t1 + t4 282 mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4 283 add(&t4, &t1, &t2) // t4 = t1 + t2 284 add(&t4, &t4, &t4) // t4 = t4 + t4 285 add(&t4, &t0, &t4) // t4 = t0 + t4 286 mul(&t4, &t3, &t4) // t4 = t3 * t4 287 sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m 288 add(&coefEq.A, &coefEq.C, &t0) // A24p = A24m + t0 289 return coefEq 290 } 291 292 // Given a 3-isogeny phi and a point pB = x(PB), compute x(QB), the x-coordinate 293 // of the image QB = phi(PB) of PB under phi : E_(A:C) -> E_(A':C'). 294 // 295 // The output xQ = x(Q) is then a point on the curve E_(A':C'); the curve 296 // parameters are returned by the GenerateCurve function used to construct phi. 297 func (phi *isogeny3) EvaluatePoint(p *ProjectivePoint) { 298 var t0, t1, t2 Fp2 299 K1, K2 := &phi.K1, &phi.K2 300 px, pz := &p.X, &p.Z 301 302 add(&t0, px, pz) // t0 = XQ + ZQ 303 sub(&t1, px, pz) // t1 = XQ - ZQ 304 mul(&t0, K1, &t0) // t2 = K1 * t0 305 mul(&t1, K2, &t1) // t1 = K2 * t1 306 add(&t2, &t0, &t1) // t2 = t0 + t1 307 sub(&t0, &t1, &t0) // t0 = t1 - t0 308 sqr(&t2, &t2) // t2 = t2 ^ 2 309 sqr(&t0, &t0) // t0 = t0 ^ 2 310 mul(px, px, &t2) // XQ'= XQ * t2 311 mul(pz, pz, &t0) // ZQ'= ZQ * t0 312 } 313 314 // Given a four-torsion point p = x(PB) on the curve E_(A:C), construct the 315 // four-isogeny phi : E_(A:C) -> E_(A:C)/<P_4> = E_(A':C'). 316 // 317 // Input: (XP_4: ZP_4), where P_4 has exact order 4 on E_A/C 318 // Output: 319 // - Curve coordinates (A' + 2C', 4C') corresponding to E_A'/C' = A_E/C/<P4> 320 // - Isogeny phi with constants in F_p^2 321 func (phi *isogeny4) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv { 322 var coefEq CurveCoefficientsEquiv 323 xp4, zp4 := &p.X, &p.Z 324 K1, K2, K3 := &phi.K1, &phi.K2, &phi.K3 325 326 sub(K2, xp4, zp4) 327 add(K3, xp4, zp4) 328 sqr(K1, zp4) 329 add(K1, K1, K1) 330 sqr(&coefEq.C, K1) 331 add(K1, K1, K1) 332 sqr(&coefEq.A, xp4) 333 add(&coefEq.A, &coefEq.A, &coefEq.A) 334 sqr(&coefEq.A, &coefEq.A) 335 return coefEq 336 } 337 338 // Given a 4-isogeny phi and a point xP = x(P), compute x(Q), the x-coordinate 339 // of the image Q = phi(P) of P under phi : E_(A:C) -> E_(A':C'). 340 // 341 // Input: Isogeny returned by GenerateCurve and point q=(Qx,Qz) from E0_A/C 342 // Output: Corresponding point q from E1_A'/C', where E1 is 4-isogenous to E0 343 func (phi *isogeny4) EvaluatePoint(p *ProjectivePoint) { 344 var t0, t1 Fp2 345 xq, zq := &p.X, &p.Z 346 K1, K2, K3 := &phi.K1, &phi.K2, &phi.K3 347 348 add(&t0, xq, zq) 349 sub(&t1, xq, zq) 350 mul(xq, &t0, K2) 351 mul(zq, &t1, K3) 352 mul(&t0, &t0, &t1) 353 mul(&t0, &t0, K1) 354 add(&t1, xq, zq) 355 sub(zq, xq, zq) 356 sqr(&t1, &t1) 357 sqr(zq, zq) 358 add(xq, &t0, &t1) 359 sub(&t0, zq, &t0) 360 mul(xq, xq, &t1) 361 mul(zq, zq, &t0) 362 } 363 364 // PublicKeyValidation preforms public key/ciphertext validation using the CLN test. 365 // CLN test: Check that P and Q are both of order 3^e3 and they generate the torsion E_A[3^e3] 366 // A countermeasure for remote timing attacks on SIKE; suggested by https://eprint.iacr.org/2022/054.pdf 367 // Any curve E_A (SIKE 434, 503, 751) that passes CLN test is supersingular. 368 // Input: The public key / ciphertext P, Q, PmQ. The projective coordinate A of the curve defined by (P, Q, PmQ) 369 // Outputs: Whether (P,Q,PmQ) follows the CLN test 370 func PublicKeyValidation(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint) error { 371 372 var PmQX, PmQZ Fp2 373 FromMontgomery(&PmQX, &PmQ.X) 374 FromMontgomery(&PmQZ, &PmQ.Z) 375 376 // PmQ is not point T or O 377 if (isZero(&PmQX) == 1) || (isZero(&PmQZ) == 1) { 378 return errors.New("curve: PmQ is invalid") 379 } 380 381 cparam := CalcCurveParamsEquiv3(cparams) 382 383 // Compute e_3 = log3(2^(nbits+1)) 384 var e3 uint32 385 e3_float := float64(int(nbits)+1) / math.Log2(3) 386 e3 = uint32(e3_float) 387 388 // Verify that P and Q generate E_A[3^e_3] by checking: [3^(e_3-1)]P != [+-3^(e_3-1)]Q 389 var test_P, test_Q ProjectivePoint 390 test_P = *P 391 test_Q = *Q 392 393 Pow3k(&test_P, &cparam, e3-1) 394 Pow3k(&test_Q, &cparam, e3-1) 395 396 var PZ, QZ Fp2 397 FromMontgomery(&PZ, &test_P.Z) 398 FromMontgomery(&QZ, &test_Q.Z) 399 400 // P, Q are not of full order 3^e_3 401 if (isZero(&PZ) == 1) || (isZero(&QZ) == 1) { 402 return errors.New("curve: ciphertext/public key are not of full order 3^e3") 403 } 404 405 // PX/PZ = affine(PX) 406 // QX/QZ = affine(QX) 407 // If PX/PZ = QX/QZ, we have P=+-Q 408 var PXQZ_PZQX_fromMont, PXQZ_PZQX, PXQZ, PZQX Fp2 409 mul(&PXQZ, &test_P.X, &test_Q.Z) 410 mul(&PZQX, &test_P.Z, &test_Q.X) 411 sub(&PXQZ_PZQX, &PXQZ, &PZQX) 412 FromMontgomery(&PXQZ_PZQX_fromMont, &PXQZ_PZQX) 413 414 // [3^(e_3-1)]P == [+-3^(e_3-1)]Q 415 if isZero(&PXQZ_PZQX_fromMont) == 1 { 416 return errors.New("curve: ciphertext/public key are not linearly independent") 417 } 418 419 // Check that Ord(P) = Ord(Q) = 3^(e_3) 420 Pow3k(&test_P, &cparam, 1) 421 Pow3k(&test_Q, &cparam, 1) 422 423 FromMontgomery(&PZ, &test_P.Z) 424 FromMontgomery(&QZ, &test_Q.Z) 425 426 // P, Q are not of correct order 3^e_3 427 if (isZero(&PZ) == 0) || (isZero(&QZ) == 0) { 428 return errors.New("curve: ciphertext/public key are not of correct order 3^e3") 429 } 430 return nil 431 }