You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5 jaren geleden
5 jaren geleden
5 jaren geleden
5 jaren geleden
5 jaren geleden
5 jaren geleden
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. package sike
  2. // Stores isogeny 3 curve constants
  3. type isogeny3 struct {
  4. K1 Fp2
  5. K2 Fp2
  6. }
  7. // Stores isogeny 4 curve constants
  8. type isogeny4 struct {
  9. isogeny3
  10. K3 Fp2
  11. }
  12. // Helper function for RightToLeftLadder(). Returns A+2C / 4.
  13. func calcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2) {
  14. var tmp Fp2
  15. // 2C
  16. add(&tmp, &cparams.C, &cparams.C)
  17. // A+2C
  18. add(&ret, &cparams.A, &tmp)
  19. // 1/4C
  20. add(&tmp, &tmp, &tmp)
  21. inv(&tmp, &tmp)
  22. // A+2C/4C
  23. mul(&ret, &ret, &tmp)
  24. return
  25. }
  26. // Converts values in x.A and x.B to Montgomery domain
  27. // x.A = x.A * R mod p
  28. // x.B = x.B * R mod p
  29. // Performs v = v*R^2*R^(-1) mod p, for both x.A and x.B
  30. func toMontDomain(x *Fp2) {
  31. var aRR FpX2
  32. // convert to montgomery domain
  33. fpMul(&aRR, &x.A, &pR2) // = a*R*R
  34. fpMontRdc(&x.A, &aRR) // = a*R mod p
  35. fpMul(&aRR, &x.B, &pR2)
  36. fpMontRdc(&x.B, &aRR)
  37. }
  38. // Converts values in x.A and x.B from Montgomery domain
  39. // a = x.A mod p
  40. // b = x.B mod p
  41. //
  42. // After returning from the call x is not modified.
  43. func fromMontDomain(x *Fp2, out *Fp2) {
  44. var aR FpX2
  45. // convert from montgomery domain
  46. copy(aR[:], x.A[:])
  47. fpMontRdc(&out.A, &aR) // = a mod p in [0, 2p)
  48. fpRdcP(&out.A) // = a mod p in [0, p)
  49. for i := range aR {
  50. aR[i] = 0
  51. }
  52. copy(aR[:], x.B[:])
  53. fpMontRdc(&out.B, &aR)
  54. fpRdcP(&out.B)
  55. }
  56. // Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result
  57. // is returned in 'j'. Implementation corresponds to Algorithm 9 from SIKE.
  58. func Jinvariant(cparams *ProjectiveCurveParameters, j *Fp2) {
  59. var t0, t1 Fp2
  60. sqr(j, &cparams.A) // j = A^2
  61. sqr(&t1, &cparams.C) // t1 = C^2
  62. add(&t0, &t1, &t1) // t0 = t1 + t1
  63. sub(&t0, j, &t0) // t0 = j - t0
  64. sub(&t0, &t0, &t1) // t0 = t0 - t1
  65. sub(j, &t0, &t1) // t0 = t0 - t1
  66. sqr(&t1, &t1) // t1 = t1^2
  67. mul(j, j, &t1) // j = j * t1
  68. add(&t0, &t0, &t0) // t0 = t0 + t0
  69. add(&t0, &t0, &t0) // t0 = t0 + t0
  70. sqr(&t1, &t0) // t1 = t0^2
  71. mul(&t0, &t0, &t1) // t0 = t0 * t1
  72. add(&t0, &t0, &t0) // t0 = t0 + t0
  73. add(&t0, &t0, &t0) // t0 = t0 + t0
  74. inv(j, j) // j = 1/j
  75. mul(j, &t0, j) // j = t0 * j
  76. }
  77. // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function
  78. // recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE.
  79. func RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2) {
  80. var t0, t1 Fp2
  81. add(&t1, xp, xq) // t1 = Xp + Xq
  82. mul(&t0, xp, xq) // t0 = Xp * Xq
  83. mul(&curve.A, xr, &t1) // A = X(q-p) * t1
  84. add(&curve.A, &curve.A, &t0) // A = A + t0
  85. mul(&t0, &t0, xr) // t0 = t0 * X(q-p)
  86. sub(&curve.A, &curve.A, &Params.OneFp2) // A = A - 1
  87. add(&t0, &t0, &t0) // t0 = t0 + t0
  88. add(&t1, &t1, xr) // t1 = t1 + X(q-p)
  89. add(&t0, &t0, &t0) // t0 = t0 + t0
  90. sqr(&curve.A, &curve.A) // A = A^2
  91. inv(&t0, &t0) // t0 = 1/t0
  92. mul(&curve.A, &curve.A, &t0) // A = A * t0
  93. sub(&curve.A, &curve.A, &t1) // A = A - t1
  94. }
  95. // Computes equivalence (A:C) ~ (A+2C : A-2C)
  96. func ToEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
  97. var coef CurveCoefficientsEquiv
  98. var c2 Fp2
  99. add(&c2, &cparams.C, &cparams.C)
  100. // A24p = A+2*C
  101. add(&coef.A, &cparams.A, &c2)
  102. // A24m = A-2*C
  103. sub(&coef.C, &cparams.A, &c2)
  104. return coef
  105. }
  106. // Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
  107. func FromEquiv3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
  108. add(&cparams.A, &coefEq.A, &coefEq.C)
  109. // cparams.A = 2*(A+2C+A-2C) = 4A
  110. add(&cparams.A, &cparams.A, &cparams.A)
  111. // cparams.C = (A+2C-A+2C) = 4C
  112. sub(&cparams.C, &coefEq.A, &coefEq.C)
  113. return
  114. }
  115. // Computes equivalence (A:C) ~ (A+2C : 4C)
  116. func ToEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
  117. var coefEq CurveCoefficientsEquiv
  118. add(&coefEq.C, &cparams.C, &cparams.C)
  119. // A24p = A+2C
  120. add(&coefEq.A, &cparams.A, &coefEq.C)
  121. // C24 = 4*C
  122. add(&coefEq.C, &coefEq.C, &coefEq.C)
  123. return coefEq
  124. }
  125. // Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
  126. func FromEquiv4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
  127. // cparams.C = (4C)*1/2=2C
  128. mul(&cparams.C, &coefEq.C, &Params.HalfFp2)
  129. // cparams.A = A+2C - 2C = A
  130. sub(&cparams.A, &coefEq.A, &cparams.C)
  131. // cparams.C = 2C * 1/2 = C
  132. mul(&cparams.C, &cparams.C, &Params.HalfFp2)
  133. return
  134. }
  135. // Combined coordinate doubling and differential addition. Takes projective points
  136. // P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E.
  137. // Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE
  138. func xDbladd(P, Q, QmP *ProjectivePoint, a24 *Fp2) (dblP, PaQ ProjectivePoint) {
  139. var t0, t1, t2 Fp2
  140. xQmP, zQmP := &QmP.X, &QmP.Z
  141. xPaQ, zPaQ := &PaQ.X, &PaQ.Z
  142. x2P, z2P := &dblP.X, &dblP.Z
  143. xP, zP := &P.X, &P.Z
  144. xQ, zQ := &Q.X, &Q.Z
  145. add(&t0, xP, zP) // t0 = Xp+Zp
  146. sub(&t1, xP, zP) // t1 = Xp-Zp
  147. sqr(x2P, &t0) // 2P.X = t0^2
  148. sub(&t2, xQ, zQ) // t2 = Xq-Zq
  149. add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq
  150. mul(&t0, &t0, &t2) // t0 = t0 * t2
  151. mul(z2P, &t1, &t1) // 2P.Z = t1 * t1
  152. mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q
  153. sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z
  154. mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z
  155. mul(xPaQ, a24, &t2) // Xp+q = A24 * t2
  156. sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1
  157. add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
  158. add(xPaQ, &t0, &t1) // Xp+q = t0 + t1
  159. mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2
  160. sqr(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2
  161. sqr(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2
  162. mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
  163. mul(xPaQ, zQmP, xPaQ) // Xp+q = Zq-p * Xp+q
  164. return
  165. }
  166. // Given the curve parameters, xP = x(P), computes xP = x([2^k]P)
  167. // Safe to overlap xP, x2P.
  168. func Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
  169. var t0, t1 Fp2
  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, &params.C, &t0) // Z2p = C24 * t0
  177. mul(x, z, &t1) // X2p = Z2p * t1
  178. sub(&t1, &t1, &t0) // t1 = t1 - t0
  179. mul(&t0, &params.A, &t1) // t0 = A24+ * t1
  180. add(z, z, &t0) // Z2p = Z2p + t0
  181. mul(z, z, &t1) // Zp = Z2p * t1
  182. }
  183. }
  184. // Given the curve parameters, xP = x(P), and k >= 0, compute xP = x([3^k]P).
  185. //
  186. // Safe to overlap xP, xR.
  187. func Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
  188. var t0, t1, t2, t3, t4, t5, t6 Fp2
  189. x, z := &xP.X, &xP.Z
  190. for i := uint32(0); i < k; i++ {
  191. sub(&t0, x, z) // t0 = Xp - Zp
  192. sqr(&t2, &t0) // t2 = t0^2
  193. add(&t1, x, z) // t1 = Xp + Zp
  194. sqr(&t3, &t1) // t3 = t1^2
  195. add(&t4, &t1, &t0) // t4 = t1 + t0
  196. sub(&t0, &t1, &t0) // t0 = t1 - t0
  197. sqr(&t1, &t4) // t1 = t4^2
  198. sub(&t1, &t1, &t3) // t1 = t1 - t3
  199. sub(&t1, &t1, &t2) // t1 = t1 - t2
  200. mul(&t5, &t3, &params.A) // t5 = t3 * A24+
  201. mul(&t3, &t3, &t5) // t3 = t5 * t3
  202. mul(&t6, &t2, &params.C) // t6 = t2 * A24-
  203. mul(&t2, &t2, &t6) // t2 = t2 * t6
  204. sub(&t3, &t2, &t3) // t3 = t2 - t3
  205. sub(&t2, &t5, &t6) // t2 = t5 - t6
  206. mul(&t1, &t2, &t1) // t1 = t2 * t1
  207. add(&t2, &t3, &t1) // t2 = t3 + t1
  208. sqr(&t2, &t2) // t2 = t2^2
  209. mul(x, &t2, &t4) // X3p = t2 * t4
  210. sub(&t1, &t3, &t1) // t1 = t3 - t1
  211. sqr(&t1, &t1) // t1 = t1^2
  212. mul(z, &t1, &t0) // Z3p = t1 * t0
  213. }
  214. }
  215. // Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
  216. //
  217. // All xi, yi must be distinct.
  218. func Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2) {
  219. var x1x2, t Fp2
  220. mul(&x1x2, x1, x2) // x1*x2
  221. mul(&t, &x1x2, x3) // 1/(x1*x2*x3)
  222. inv(&t, &t)
  223. mul(y1, &t, x2) // 1/x1
  224. mul(y1, y1, x3)
  225. mul(y2, &t, x1) // 1/x2
  226. mul(y2, y2, x3)
  227. mul(y3, &t, &x1x2) // 1/x3
  228. }
  229. // ScalarMul3Pt is a right-to-left point multiplication that given the
  230. // x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P.
  231. // nbits must be smaller or equal to len(scalar).
  232. func ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint {
  233. var R0, R2, R1 ProjectivePoint
  234. aPlus2Over4 := calcAplus2Over4(cparams)
  235. R1 = *P
  236. R2 = *PmQ
  237. R0 = *Q
  238. // Iterate over the bits of the scalar, bottom to top
  239. prevBit := uint8(0)
  240. for i := uint(0); i < nbits; i++ {
  241. bit := (scalar[i>>3] >> (i & 7) & 1)
  242. swap := prevBit ^ bit
  243. prevBit = bit
  244. condSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap)
  245. R0, R2 = xDbladd(&R0, &R2, &R1, &aPlus2Over4)
  246. }
  247. condSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit)
  248. return R1
  249. }
  250. // Given a three-torsion point p = x(PB) on the curve E_(A:C), construct the
  251. // three-isogeny phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C').
  252. //
  253. // Input: (XP_3: ZP_3), where P_3 has exact order 3 on E_A/C
  254. // Output: * Curve coordinates (A' + 2C', A' - 2C') corresponding to E_A'/C' = A_E/C/<P3>
  255. // * isogeny phi with constants in F_p^2
  256. func (phi *isogeny3) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
  257. var t0, t1, t2, t3, t4 Fp2
  258. var coefEq CurveCoefficientsEquiv
  259. var K1, K2 = &phi.K1, &phi.K2
  260. sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3
  261. sqr(&t0, K1) // t0 = K1^2
  262. add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3
  263. sqr(&t1, K2) // t1 = K2^2
  264. add(&t2, &t0, &t1) // t2 = t0 + t1
  265. add(&t3, K1, K2) // t3 = K1 + K2
  266. sqr(&t3, &t3) // t3 = t3^2
  267. sub(&t3, &t3, &t2) // t3 = t3 - t2
  268. add(&t2, &t1, &t3) // t2 = t1 + t3
  269. add(&t3, &t3, &t0) // t3 = t3 + t0
  270. add(&t4, &t3, &t0) // t4 = t3 + t0
  271. add(&t4, &t4, &t4) // t4 = t4 + t4
  272. add(&t4, &t1, &t4) // t4 = t1 + t4
  273. mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4
  274. add(&t4, &t1, &t2) // t4 = t1 + t2
  275. add(&t4, &t4, &t4) // t4 = t4 + t4
  276. add(&t4, &t0, &t4) // t4 = t0 + t4
  277. mul(&t4, &t3, &t4) // t4 = t3 * t4
  278. sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m
  279. add(&coefEq.A, &coefEq.C, &t0) // A24p = A24m + t0
  280. return coefEq
  281. }
  282. // Given a 3-isogeny phi and a point pB = x(PB), compute x(QB), the x-coordinate
  283. // of the image QB = phi(PB) of PB under phi : E_(A:C) -> E_(A':C').
  284. //
  285. // The output xQ = x(Q) is then a point on the curve E_(A':C'); the curve
  286. // parameters are returned by the GenerateCurve function used to construct phi.
  287. func (phi *isogeny3) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
  288. var t0, t1, t2 Fp2
  289. var q ProjectivePoint
  290. var K1, K2 = &phi.K1, &phi.K2
  291. var px, pz = &p.X, &p.Z
  292. add(&t0, px, pz) // t0 = XQ + ZQ
  293. sub(&t1, px, pz) // t1 = XQ - ZQ
  294. mul(&t0, K1, &t0) // t2 = K1 * t0
  295. mul(&t1, K2, &t1) // t1 = K2 * t1
  296. add(&t2, &t0, &t1) // t2 = t0 + t1
  297. sub(&t0, &t1, &t0) // t0 = t1 - t0
  298. sqr(&t2, &t2) // t2 = t2 ^ 2
  299. sqr(&t0, &t0) // t0 = t0 ^ 2
  300. mul(&q.X, px, &t2) // XQ'= XQ * t2
  301. mul(&q.Z, pz, &t0) // ZQ'= ZQ * t0
  302. return q
  303. }
  304. // Given a four-torsion point p = x(PB) on the curve E_(A:C), construct the
  305. // four-isogeny phi : E_(A:C) -> E_(A:C)/<P_4> = E_(A':C').
  306. //
  307. // Input: (XP_4: ZP_4), where P_4 has exact order 4 on E_A/C
  308. // Output: * Curve coordinates (A' + 2C', 4C') corresponding to E_A'/C' = A_E/C/<P4>
  309. // * isogeny phi with constants in F_p^2
  310. func (phi *isogeny4) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
  311. var coefEq CurveCoefficientsEquiv
  312. var xp4, zp4 = &p.X, &p.Z
  313. var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
  314. sub(K2, xp4, zp4)
  315. add(K3, xp4, zp4)
  316. sqr(K1, zp4)
  317. add(K1, K1, K1)
  318. sqr(&coefEq.C, K1)
  319. add(K1, K1, K1)
  320. sqr(&coefEq.A, xp4)
  321. add(&coefEq.A, &coefEq.A, &coefEq.A)
  322. sqr(&coefEq.A, &coefEq.A)
  323. return coefEq
  324. }
  325. // Given a 4-isogeny phi and a point xP = x(P), compute x(Q), the x-coordinate
  326. // of the image Q = phi(P) of P under phi : E_(A:C) -> E_(A':C').
  327. //
  328. // Input: isogeny returned by GenerateCurve and point q=(Qx,Qz) from E0_A/C
  329. // Output: Corresponding point q from E1_A'/C', where E1 is 4-isogenous to E0
  330. func (phi *isogeny4) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
  331. var t0, t1 Fp2
  332. var q = *p
  333. var xq, zq = &q.X, &q.Z
  334. var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
  335. add(&t0, xq, zq)
  336. sub(&t1, xq, zq)
  337. mul(xq, &t0, K2)
  338. mul(zq, &t1, K3)
  339. mul(&t0, &t0, &t1)
  340. mul(&t0, &t0, K1)
  341. add(&t1, xq, zq)
  342. sub(zq, xq, zq)
  343. sqr(&t1, &t1)
  344. sqr(zq, zq)
  345. add(xq, &t0, &t1)
  346. sub(&t0, zq, &t0)
  347. mul(xq, xq, &t1)
  348. mul(zq, zq, &t0)
  349. return q
  350. }