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.
 
 
 

441 regels
15 KiB

  1. package internal
  2. type CurveOperations struct {
  3. Params *SidhParams
  4. }
  5. // Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result
  6. // is returned in jBytes buffer, encoded in little-endian format. Caller
  7. // provided jBytes buffer has to be big enough to j-invariant value. In case
  8. // of SIDH, buffer size must be at least size of shared secret.
  9. // Implementation corresponds to Algorithm 9 from SIKE.
  10. func (c *CurveOperations) Jinvariant(cparams *ProjectiveCurveParameters, jBytes []byte) {
  11. var j, t0, t1 Fp2Element
  12. op := c.Params.Op
  13. op.Square(&j, &cparams.A) // j = A^2
  14. op.Square(&t1, &cparams.C) // t1 = C^2
  15. op.Add(&t0, &t1, &t1) // t0 = t1 + t1
  16. op.Sub(&t0, &j, &t0) // t0 = j - t0
  17. op.Sub(&t0, &t0, &t1) // t0 = t0 - t1
  18. op.Sub(&j, &t0, &t1) // t0 = t0 - t1
  19. op.Square(&t1, &t1) // t1 = t1^2
  20. op.Mul(&j, &j, &t1) // j = j * t1
  21. op.Add(&t0, &t0, &t0) // t0 = t0 + t0
  22. op.Add(&t0, &t0, &t0) // t0 = t0 + t0
  23. op.Square(&t1, &t0) // t1 = t0^2
  24. op.Mul(&t0, &t0, &t1) // t0 = t0 * t1
  25. op.Add(&t0, &t0, &t0) // t0 = t0 + t0
  26. op.Add(&t0, &t0, &t0) // t0 = t0 + t0
  27. op.Inv(&j, &j) // j = 1/j
  28. op.Mul(&j, &t0, &j) // j = t0 * j
  29. c.Fp2ToBytes(jBytes, &j)
  30. }
  31. // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function
  32. // recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE.
  33. func (c *CurveOperations) RecoverCoordinateA(curve *ProjectiveCurveParameters, xp, xq, xr *Fp2Element) {
  34. var t0, t1 Fp2Element
  35. op := c.Params.Op
  36. op.Add(&t1, xp, xq) // t1 = Xp + Xq
  37. op.Mul(&t0, xp, xq) // t0 = Xp * Xq
  38. op.Mul(&curve.A, xr, &t1) // A = X(q-p) * t1
  39. op.Add(&curve.A, &curve.A, &t0) // A = A + t0
  40. op.Mul(&t0, &t0, xr) // t0 = t0 * X(q-p)
  41. op.Sub(&curve.A, &curve.A, &c.Params.OneFp2) // A = A - 1
  42. op.Add(&t0, &t0, &t0) // t0 = t0 + t0
  43. op.Add(&t1, &t1, xr) // t1 = t1 + X(q-p)
  44. op.Add(&t0, &t0, &t0) // t0 = t0 + t0
  45. op.Square(&curve.A, &curve.A) // A = A^2
  46. op.Inv(&t0, &t0) // t0 = 1/t0
  47. op.Mul(&curve.A, &curve.A, &t0) // A = A * t0
  48. op.Sub(&curve.A, &curve.A, &t1) // A = A - t1
  49. }
  50. // Computes equivalence (A:C) ~ (A+2C : A-2C)
  51. func (c *CurveOperations) CalcCurveParamsEquiv3(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
  52. var coef CurveCoefficientsEquiv
  53. var c2 Fp2Element
  54. var op = c.Params.Op
  55. op.Add(&c2, &cparams.C, &cparams.C)
  56. // A24p = A+2*C
  57. op.Add(&coef.A, &cparams.A, &c2)
  58. // A24m = A-2*C
  59. op.Sub(&coef.C, &cparams.A, &c2)
  60. return coef
  61. }
  62. // Computes equivalence (A:C) ~ (A+2C : 4C)
  63. func (c *CurveOperations) CalcCurveParamsEquiv4(cparams *ProjectiveCurveParameters) CurveCoefficientsEquiv {
  64. var coefEq CurveCoefficientsEquiv
  65. var op = c.Params.Op
  66. op.Add(&coefEq.C, &cparams.C, &cparams.C)
  67. // A24p = A+2C
  68. op.Add(&coefEq.A, &cparams.A, &coefEq.C)
  69. // C24 = 4*C
  70. op.Add(&coefEq.C, &coefEq.C, &coefEq.C)
  71. return coefEq
  72. }
  73. // Helper function for RightToLeftLadder(). Returns A+2C / 4.
  74. func (c *CurveOperations) CalcAplus2Over4(cparams *ProjectiveCurveParameters) (ret Fp2Element) {
  75. var tmp Fp2Element
  76. var op = c.Params.Op
  77. // 2C
  78. op.Add(&tmp, &cparams.C, &cparams.C)
  79. // A+2C
  80. op.Add(&ret, &cparams.A, &tmp)
  81. // 1/4C
  82. op.Add(&tmp, &tmp, &tmp)
  83. op.Inv(&tmp, &tmp)
  84. // A+2C/4C
  85. op.Mul(&ret, &ret, &tmp)
  86. return
  87. }
  88. // Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
  89. func (c *CurveOperations) RecoverCurveCoefficients3(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
  90. var op = c.Params.Op
  91. op.Add(&cparams.A, &coefEq.A, &coefEq.C)
  92. // cparams.A = 2*(A+2C+A-2C) = 4A
  93. op.Add(&cparams.A, &cparams.A, &cparams.A)
  94. // cparams.C = (A+2C-A+2C) = 4C
  95. op.Sub(&cparams.C, &coefEq.A, &coefEq.C)
  96. return
  97. }
  98. // Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
  99. func (c *CurveOperations) RecoverCurveCoefficients4(cparams *ProjectiveCurveParameters, coefEq *CurveCoefficientsEquiv) {
  100. var op = c.Params.Op
  101. // cparams.C = (4C)*1/2=2C
  102. op.Mul(&cparams.C, &coefEq.C, &c.Params.HalfFp2)
  103. // cparams.A = A+2C - 2C = A
  104. op.Sub(&cparams.A, &coefEq.A, &cparams.C)
  105. // cparams.C = 2C * 1/2 = C
  106. op.Mul(&cparams.C, &cparams.C, &c.Params.HalfFp2)
  107. return
  108. }
  109. // Combined coordinate doubling and differential addition. Takes projective points
  110. // P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E.
  111. // Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE
  112. func (c *CurveOperations) xDblAdd(P, Q, QmP *ProjectivePoint, a24 *Fp2Element) (dblP, PaQ ProjectivePoint) {
  113. var t0, t1, t2 Fp2Element
  114. var op = c.Params.Op
  115. xQmP, zQmP := &QmP.X, &QmP.Z
  116. xPaQ, zPaQ := &PaQ.X, &PaQ.Z
  117. x2P, z2P := &dblP.X, &dblP.Z
  118. xP, zP := &P.X, &P.Z
  119. xQ, zQ := &Q.X, &Q.Z
  120. op.Add(&t0, xP, zP) // t0 = Xp+Zp
  121. op.Sub(&t1, xP, zP) // t1 = Xp-Zp
  122. op.Square(x2P, &t0) // 2P.X = t0^2
  123. op.Sub(&t2, xQ, zQ) // t2 = Xq-Zq
  124. op.Add(xPaQ, xQ, zQ) // Xp+q = Xq+Zq
  125. op.Mul(&t0, &t0, &t2) // t0 = t0 * t2
  126. op.Mul(z2P, &t1, &t1) // 2P.Z = t1 * t1
  127. op.Mul(&t1, &t1, xPaQ) // t1 = t1 * Xp+q
  128. op.Sub(&t2, x2P, z2P) // t2 = 2P.X - 2P.Z
  129. op.Mul(x2P, x2P, z2P) // 2P.X = 2P.X * 2P.Z
  130. op.Mul(xPaQ, a24, &t2) // Xp+q = A24 * t2
  131. op.Sub(zPaQ, &t0, &t1) // Zp+q = t0 - t1
  132. op.Add(z2P, xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
  133. op.Add(xPaQ, &t0, &t1) // Xp+q = t0 + t1
  134. op.Mul(z2P, z2P, &t2) // 2P.Z = 2P.Z * t2
  135. op.Square(zPaQ, zPaQ) // Zp+q = Zp+q ^ 2
  136. op.Square(xPaQ, xPaQ) // Xp+q = Xp+q ^ 2
  137. op.Mul(zPaQ, xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
  138. op.Mul(xPaQ, zQmP, xPaQ) // Xp+q = Zq-p * Xp+q
  139. return
  140. }
  141. // Given the curve parameters, xP = x(P), computes xP = x([2^k]P)
  142. // Safe to overlap xP, x2P.
  143. func (c *CurveOperations) Pow2k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
  144. var t0, t1 Fp2Element
  145. var op = c.Params.Op
  146. x, z := &xP.X, &xP.Z
  147. for i := uint32(0); i < k; i++ {
  148. op.Sub(&t0, x, z) // t0 = Xp - Zp
  149. op.Add(&t1, x, z) // t1 = Xp + Zp
  150. op.Square(&t0, &t0) // t0 = t0 ^ 2
  151. op.Square(&t1, &t1) // t1 = t1 ^ 2
  152. op.Mul(z, &params.C, &t0) // Z2p = C24 * t0
  153. op.Mul(x, z, &t1) // X2p = Z2p * t1
  154. op.Sub(&t1, &t1, &t0) // t1 = t1 - t0
  155. op.Mul(&t0, &params.A, &t1) // t0 = A24+ * t1
  156. op.Add(z, z, &t0) // Z2p = Z2p + t0
  157. op.Mul(z, z, &t1) // Zp = Z2p * t1
  158. }
  159. }
  160. // Given the curve parameters, xP = x(P), and k >= 0, compute xP = x([3^k]P).
  161. //
  162. // Safe to overlap xP, xR.
  163. func (c *CurveOperations) Pow3k(xP *ProjectivePoint, params *CurveCoefficientsEquiv, k uint32) {
  164. var t0, t1, t2, t3, t4, t5, t6 Fp2Element
  165. var op = c.Params.Op
  166. x, z := &xP.X, &xP.Z
  167. for i := uint32(0); i < k; i++ {
  168. op.Sub(&t0, x, z) // t0 = Xp - Zp
  169. op.Square(&t2, &t0) // t2 = t0^2
  170. op.Add(&t1, x, z) // t1 = Xp + Zp
  171. op.Square(&t3, &t1) // t3 = t1^2
  172. op.Add(&t4, &t1, &t0) // t4 = t1 + t0
  173. op.Sub(&t0, &t1, &t0) // t0 = t1 - t0
  174. op.Square(&t1, &t4) // t1 = t4^2
  175. op.Sub(&t1, &t1, &t3) // t1 = t1 - t3
  176. op.Sub(&t1, &t1, &t2) // t1 = t1 - t2
  177. op.Mul(&t5, &t3, &params.A) // t5 = t3 * A24+
  178. op.Mul(&t3, &t3, &t5) // t3 = t5 * t3
  179. op.Mul(&t6, &t2, &params.C) // t6 = t2 * A24-
  180. op.Mul(&t2, &t2, &t6) // t2 = t2 * t6
  181. op.Sub(&t3, &t2, &t3) // t3 = t2 - t3
  182. op.Sub(&t2, &t5, &t6) // t2 = t5 - t6
  183. op.Mul(&t1, &t2, &t1) // t1 = t2 * t1
  184. op.Add(&t2, &t3, &t1) // t2 = t3 + t1
  185. op.Square(&t2, &t2) // t2 = t2^2
  186. op.Mul(x, &t2, &t4) // X3p = t2 * t4
  187. op.Sub(&t1, &t3, &t1) // t1 = t3 - t1
  188. op.Square(&t1, &t1) // t1 = t1^2
  189. op.Mul(z, &t1, &t0) // Z3p = t1 * t0
  190. }
  191. }
  192. // Set (y1, y2, y3) = (1/x1, 1/x2, 1/x3).
  193. //
  194. // All xi, yi must be distinct.
  195. func (c *CurveOperations) Fp2Batch3Inv(x1, x2, x3, y1, y2, y3 *Fp2Element) {
  196. var x1x2, t Fp2Element
  197. var op = c.Params.Op
  198. op.Mul(&x1x2, x1, x2) // x1*x2
  199. op.Mul(&t, &x1x2, x3) // 1/(x1*x2*x3)
  200. op.Inv(&t, &t)
  201. op.Mul(y1, &t, x2) // 1/x1
  202. op.Mul(y1, y1, x3)
  203. op.Mul(y2, &t, x1) // 1/x2
  204. op.Mul(y2, y2, x3)
  205. op.Mul(y3, &t, &x1x2) // 1/x3
  206. }
  207. // ScalarMul3Pt is a right-to-left point multiplication that given the
  208. // x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P.
  209. // nbits must be smaller or equal to len(scalar).
  210. func (c *CurveOperations) ScalarMul3Pt(cparams *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint, nbits uint, scalar []uint8) ProjectivePoint {
  211. var R0, R2, R1 ProjectivePoint
  212. var op = c.Params.Op
  213. aPlus2Over4 := c.CalcAplus2Over4(cparams)
  214. R1 = *P
  215. R2 = *PmQ
  216. R0 = *Q
  217. // Iterate over the bits of the scalar, bottom to top
  218. prevBit := uint8(0)
  219. for i := uint(0); i < nbits; i++ {
  220. bit := (scalar[i>>3] >> (i & 7) & 1)
  221. swap := prevBit ^ bit
  222. prevBit = bit
  223. op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, swap)
  224. R0, R2 = c.xDblAdd(&R0, &R2, &R1, &aPlus2Over4)
  225. }
  226. op.CondSwap(&R1.X, &R1.Z, &R2.X, &R2.Z, prevBit)
  227. return R1
  228. }
  229. // Convert the input to wire format.
  230. //
  231. // The output byte slice must be at least 2*bytelen(p) bytes long.
  232. func (c *CurveOperations) Fp2ToBytes(output []byte, fp2 *Fp2Element) {
  233. if len(output) < 2*c.Params.Bytelen {
  234. panic("output byte slice too short")
  235. }
  236. var a Fp2Element
  237. c.Params.Op.FromMontgomery(fp2, &a)
  238. // convert to bytes in little endian form
  239. for i := 0; i < c.Params.Bytelen; i++ {
  240. // set i = j*8 + k
  241. fp2 := i / 8
  242. k := uint64(i % 8)
  243. output[i] = byte(a.A[fp2] >> (8 * k))
  244. output[i+c.Params.Bytelen] = byte(a.B[fp2] >> (8 * k))
  245. }
  246. }
  247. // Read 2*bytelen(p) bytes into the given ExtensionFieldElement.
  248. //
  249. // It is an error to call this function if the input byte slice is less than 2*bytelen(p) bytes long.
  250. func (c *CurveOperations) Fp2FromBytes(fp2 *Fp2Element, input []byte) {
  251. if len(input) < 2*c.Params.Bytelen {
  252. panic("input byte slice too short")
  253. }
  254. for i := 0; i < c.Params.Bytelen; i++ {
  255. j := i / 8
  256. k := uint64(i % 8)
  257. fp2.A[j] |= uint64(input[i]) << (8 * k)
  258. fp2.B[j] |= uint64(input[i+c.Params.Bytelen]) << (8 * k)
  259. }
  260. c.Params.Op.ToMontgomery(fp2)
  261. }
  262. /* -------------------------------------------------------------------------
  263. Mechnisms used for isogeny calculations
  264. -------------------------------------------------------------------------*/
  265. // Constructs isogeny3 objects
  266. func Newisogeny3(op FieldOps) Isogeny {
  267. return &isogeny3{Field: op}
  268. }
  269. // Constructs isogeny4 objects
  270. func Newisogeny4(op FieldOps) Isogeny {
  271. return &isogeny4{isogeny3: isogeny3{Field: op}}
  272. }
  273. // Given a three-torsion point p = x(PB) on the curve E_(A:C), construct the
  274. // three-isogeny phi : E_(A:C) -> E_(A:C)/<P_3> = E_(A':C').
  275. //
  276. // Input: (XP_3: ZP_3), where P_3 has exact order 3 on E_A/C
  277. // Output: * Curve coordinates (A' + 2C', A' - 2C') corresponding to E_A'/C' = A_E/C/<P3>
  278. // * Isogeny phi with constants in F_p^2
  279. func (phi *isogeny3) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
  280. var t0, t1, t2, t3, t4 Fp2Element
  281. var coefEq CurveCoefficientsEquiv
  282. var K1, K2 = &phi.K1, &phi.K2
  283. op := phi.Field
  284. op.Sub(K1, &p.X, &p.Z) // K1 = XP3 - ZP3
  285. op.Square(&t0, K1) // t0 = K1^2
  286. op.Add(K2, &p.X, &p.Z) // K2 = XP3 + ZP3
  287. op.Square(&t1, K2) // t1 = K2^2
  288. op.Add(&t2, &t0, &t1) // t2 = t0 + t1
  289. op.Add(&t3, K1, K2) // t3 = K1 + K2
  290. op.Square(&t3, &t3) // t3 = t3^2
  291. op.Sub(&t3, &t3, &t2) // t3 = t3 - t2
  292. op.Add(&t2, &t1, &t3) // t2 = t1 + t3
  293. op.Add(&t3, &t3, &t0) // t3 = t3 + t0
  294. op.Add(&t4, &t3, &t0) // t4 = t3 + t0
  295. op.Add(&t4, &t4, &t4) // t4 = t4 + t4
  296. op.Add(&t4, &t1, &t4) // t4 = t1 + t4
  297. op.Mul(&coefEq.C, &t2, &t4) // A24m = t2 * t4
  298. op.Add(&t4, &t1, &t2) // t4 = t1 + t2
  299. op.Add(&t4, &t4, &t4) // t4 = t4 + t4
  300. op.Add(&t4, &t0, &t4) // t4 = t0 + t4
  301. op.Mul(&t4, &t3, &t4) // t4 = t3 * t4
  302. op.Sub(&t0, &t4, &coefEq.C) // t0 = t4 - A24m
  303. op.Add(&coefEq.A, &coefEq.C, &t0) // A24p = A24m + t0
  304. return coefEq
  305. }
  306. // Given a 3-isogeny phi and a point pB = x(PB), compute x(QB), the x-coordinate
  307. // of the image QB = phi(PB) of PB under phi : E_(A:C) -> E_(A':C').
  308. //
  309. // The output xQ = x(Q) is then a point on the curve E_(A':C'); the curve
  310. // parameters are returned by the GenerateCurve function used to construct phi.
  311. func (phi *isogeny3) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
  312. var t0, t1, t2 Fp2Element
  313. var q ProjectivePoint
  314. var K1, K2 = &phi.K1, &phi.K2
  315. var px, pz = &p.X, &p.Z
  316. op := phi.Field
  317. op.Add(&t0, px, pz) // t0 = XQ + ZQ
  318. op.Sub(&t1, px, pz) // t1 = XQ - ZQ
  319. op.Mul(&t0, K1, &t0) // t2 = K1 * t0
  320. op.Mul(&t1, K2, &t1) // t1 = K2 * t1
  321. op.Add(&t2, &t0, &t1) // t2 = t0 + t1
  322. op.Sub(&t0, &t1, &t0) // t0 = t1 - t0
  323. op.Square(&t2, &t2) // t2 = t2 ^ 2
  324. op.Square(&t0, &t0) // t0 = t0 ^ 2
  325. op.Mul(&q.X, px, &t2) // XQ'= XQ * t2
  326. op.Mul(&q.Z, pz, &t0) // ZQ'= ZQ * t0
  327. return q
  328. }
  329. // Given a four-torsion point p = x(PB) on the curve E_(A:C), construct the
  330. // four-isogeny phi : E_(A:C) -> E_(A:C)/<P_4> = E_(A':C').
  331. //
  332. // Input: (XP_4: ZP_4), where P_4 has exact order 4 on E_A/C
  333. // Output: * Curve coordinates (A' + 2C', 4C') corresponding to E_A'/C' = A_E/C/<P4>
  334. // * Isogeny phi with constants in F_p^2
  335. func (phi *isogeny4) GenerateCurve(p *ProjectivePoint) CurveCoefficientsEquiv {
  336. var coefEq CurveCoefficientsEquiv
  337. var xp4, zp4 = &p.X, &p.Z
  338. var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
  339. op := phi.Field
  340. op.Sub(K2, xp4, zp4)
  341. op.Add(K3, xp4, zp4)
  342. op.Square(K1, zp4)
  343. op.Add(K1, K1, K1)
  344. op.Square(&coefEq.C, K1)
  345. op.Add(K1, K1, K1)
  346. op.Square(&coefEq.A, xp4)
  347. op.Add(&coefEq.A, &coefEq.A, &coefEq.A)
  348. op.Square(&coefEq.A, &coefEq.A)
  349. return coefEq
  350. }
  351. // Given a 4-isogeny phi and a point xP = x(P), compute x(Q), the x-coordinate
  352. // of the image Q = phi(P) of P under phi : E_(A:C) -> E_(A':C').
  353. //
  354. // Input: Isogeny returned by GenerateCurve and point q=(Qx,Qz) from E0_A/C
  355. // Output: Corresponding point q from E1_A'/C', where E1 is 4-isogenous to E0
  356. func (phi *isogeny4) EvaluatePoint(p *ProjectivePoint) ProjectivePoint {
  357. var t0, t1 Fp2Element
  358. var q = *p
  359. var xq, zq = &q.X, &q.Z
  360. var K1, K2, K3 = &phi.K1, &phi.K2, &phi.K3
  361. op := phi.Field
  362. op.Add(&t0, xq, zq)
  363. op.Sub(&t1, xq, zq)
  364. op.Mul(xq, &t0, K2)
  365. op.Mul(zq, &t1, K3)
  366. op.Mul(&t0, &t0, &t1)
  367. op.Mul(&t0, &t0, K1)
  368. op.Add(&t1, xq, zq)
  369. op.Sub(zq, xq, zq)
  370. op.Square(&t1, &t1)
  371. op.Square(zq, zq)
  372. op.Add(xq, &t0, &t1)
  373. op.Sub(&t0, zq, &t0)
  374. op.Mul(xq, xq, &t1)
  375. op.Mul(zq, zq, &t0)
  376. return q
  377. }
  378. /* -------------------------------------------------------------------------
  379. Utils
  380. -------------------------------------------------------------------------*/
  381. func (point *ProjectivePoint) ToAffine(c *CurveOperations) *Fp2Element {
  382. var affine_x Fp2Element
  383. c.Params.Op.Inv(&affine_x, &point.Z)
  384. c.Params.Op.Mul(&affine_x, &affine_x, &point.X)
  385. return &affine_x
  386. }
  387. // Cleans data in fp
  388. func (fp *Fp2Element) Zeroize() {
  389. // Zeroizing in 2 seperated loops tells compiler to
  390. // use fast runtime.memclr()
  391. for i := range fp.A {
  392. fp.A[i] = 0
  393. }
  394. for i := range fp.B {
  395. fp.B[i] = 0
  396. }
  397. }