25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 

294 satır
9.9 KiB

  1. package p503toolbox
  2. // A point on the projective line P^1(F_{p^2}).
  3. //
  4. // This is used to work projectively with the curve coefficients.
  5. type ProjectiveCurveParameters struct {
  6. A ExtensionFieldElement
  7. C ExtensionFieldElement
  8. }
  9. // Stores curve projective parameters equivalent to A/C. Meaning of the
  10. // values depends on the context. When working with isogenies over
  11. // subgroup that are powers of:
  12. // * three then (A:C) ~ (A+2C:A-2C)
  13. // * four then (A:C) ~ (A+2C: 4C)
  14. // See Appendix A of SIKE for more details
  15. type CurveCoefficientsEquiv struct {
  16. A ExtensionFieldElement
  17. C ExtensionFieldElement
  18. }
  19. // A point on the projective line P^1(F_{p^2}).
  20. //
  21. // This represents a point on the Kummer line of a Montgomery curve. The
  22. // curve is specified by a ProjectiveCurveParameters struct.
  23. type ProjectivePoint struct {
  24. X ExtensionFieldElement
  25. Z ExtensionFieldElement
  26. }
  27. func (params *ProjectiveCurveParameters) FromAffine(a *ExtensionFieldElement) {
  28. params.A = *a
  29. params.C.One()
  30. }
  31. // Computes j-invariant for a curve y2=x3+A/Cx+x with A,C in F_(p^2). Result
  32. // is returned in jBytes buffer, encoded in little-endian format. Caller
  33. // provided jBytes buffer has to be big enough to j-invariant value. In case
  34. // of SIDH, buffer size must be at least size of shared secret.
  35. // Implementation corresponds to Algorithm 9 from SIKE.
  36. func (cparams *ProjectiveCurveParameters) Jinvariant(jBytes []byte) {
  37. var j, t0, t1 ExtensionFieldElement
  38. j.Square(&cparams.A) // j = A^2
  39. t1.Square(&cparams.C) // t1 = C^2
  40. t0.Add(&t1, &t1) // t0 = t1 + t1
  41. t0.Sub(&j, &t0) // t0 = j - t0
  42. t0.Sub(&t0, &t1) // t0 = t0 - t1
  43. j.Sub(&t0, &t1) // t0 = t0 - t1
  44. t1.Square(&t1) // t1 = t1^2
  45. j.Mul(&j, &t1) // t0 = t0 * t1
  46. t0.Add(&t0, &t0) // t0 = t0 + t0
  47. t0.Add(&t0, &t0) // t0 = t0 + t0
  48. t1.Square(&t0) // t1 = t0^2
  49. t0.Mul(&t0, &t1) // t0 = t0 * t1
  50. t0.Add(&t0, &t0) // t0 = t0 + t0
  51. t0.Add(&t0, &t0) // t0 = t0 + t0
  52. j.Inv(&j) // j = 1/j
  53. j.Mul(&t0, &j) // j = t0 * j
  54. j.ToBytes(jBytes)
  55. }
  56. // Given affine points x(P), x(Q) and x(Q-P) in a extension field F_{p^2}, function
  57. // recorvers projective coordinate A of a curve. This is Algorithm 10 from SIKE.
  58. func (curve *ProjectiveCurveParameters) RecoverCoordinateA(xp, xq, xr *ExtensionFieldElement) {
  59. var t0, t1 ExtensionFieldElement
  60. t1.Add(xp, xq) // t1 = Xp + Xq
  61. t0.Mul(xp, xq) // t0 = Xp * Xq
  62. curve.A.Mul(xr, &t1) // A = X(q-p) * t1
  63. curve.A.Add(&curve.A, &t0) // A = A + t0
  64. t0.Mul(&t0, xr) // t0 = t0 * X(q-p)
  65. curve.A.Sub(&curve.A, &oneExtensionField) // A = A - 1
  66. t0.Add(&t0, &t0) // t0 = t0 + t0
  67. t1.Add(&t1, xr) // t1 = t1 + X(q-p)
  68. t0.Add(&t0, &t0) // t0 = t0 + t0
  69. curve.A.Square(&curve.A) // A = A^2
  70. t0.Inv(&t0) // t0 = 1/t0
  71. curve.A.Mul(&curve.A, &t0) // A = A * t0
  72. curve.A.Sub(&curve.A, &t1) // A = A - t1
  73. }
  74. // Computes equivalence (A:C) ~ (A+2C : A-2C)
  75. func (curve *ProjectiveCurveParameters) CalcCurveParamsEquiv3() CurveCoefficientsEquiv {
  76. var coef CurveCoefficientsEquiv
  77. var c2 ExtensionFieldElement
  78. c2.Add(&curve.C, &curve.C)
  79. // A24p = A+2*C
  80. coef.A.Add(&curve.A, &c2)
  81. // A24m = A-2*C
  82. coef.C.Sub(&curve.A, &c2)
  83. return coef
  84. }
  85. // Computes equivalence (A:C) ~ (A+2C : 4C)
  86. func (cparams *ProjectiveCurveParameters) CalcCurveParamsEquiv4() CurveCoefficientsEquiv {
  87. var coefEq CurveCoefficientsEquiv
  88. coefEq.C.Add(&cparams.C, &cparams.C)
  89. // A24p = A+2C
  90. coefEq.A.Add(&cparams.A, &coefEq.C)
  91. // C24 = 4*C
  92. coefEq.C.Add(&coefEq.C, &coefEq.C)
  93. return coefEq
  94. }
  95. // Helper function for RightToLeftLadder(). Returns A+2C / 4.
  96. func (cparams *ProjectiveCurveParameters) calcAplus2Over4() (ret ExtensionFieldElement) {
  97. var tmp ExtensionFieldElement
  98. // 2C
  99. tmp.Add(&cparams.C, &cparams.C)
  100. // A+2C
  101. ret.Add(&cparams.A, &tmp)
  102. // 1/4C
  103. tmp.Add(&tmp, &tmp).Inv(&tmp)
  104. // A+2C/4C
  105. ret.Mul(&ret, &tmp)
  106. return
  107. }
  108. // Recovers (A:C) curve parameters from projectively equivalent (A+2C:A-2C).
  109. func (cparams *ProjectiveCurveParameters) RecoverCurveCoefficients3(coefEq *CurveCoefficientsEquiv) {
  110. cparams.A.Add(&coefEq.A, &coefEq.C)
  111. // cparams.A = 2*(A+2C+A-2C) = 4A
  112. cparams.A.Add(&cparams.A, &cparams.A)
  113. // cparams.C = (A+2C-A+2C) = 4C
  114. cparams.C.Sub(&coefEq.A, &coefEq.C)
  115. return
  116. }
  117. // Recovers (A:C) curve parameters from projectively equivalent (A+2C:4C).
  118. func (cparams *ProjectiveCurveParameters) RecoverCurveCoefficients4(coefEq *CurveCoefficientsEquiv) {
  119. var half = ExtensionFieldElement{
  120. A: Fp751Element{
  121. 0x00000000000124D6, 0x0000000000000000, 0x0000000000000000,
  122. 0x0000000000000000, 0x0000000000000000, 0xB8E0000000000000,
  123. 0x9C8A2434C0AA7287, 0xA206996CA9A378A3, 0x6876280D41A41B52,
  124. 0xE903B49F175CE04F, 0x0F8511860666D227, 0x00004EA07CFF6E7F},
  125. B: Fp751Element{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  126. }
  127. // cparams.C = (4C)*1/2=2C
  128. cparams.C.Mul(&coefEq.C, &half)
  129. // cparams.A = A+2C - 2C = A
  130. cparams.A.Sub(&coefEq.A, &cparams.C)
  131. // cparams.C = 2C * 1/2 = C
  132. cparams.C.Mul(&cparams.C, &half)
  133. return
  134. }
  135. func (point *ProjectivePoint) FromAffine(x *ExtensionFieldElement) {
  136. point.X = *x
  137. point.Z = oneExtensionField
  138. }
  139. func (point *ProjectivePoint) ToAffine() *ExtensionFieldElement {
  140. affine_x := new(ExtensionFieldElement)
  141. affine_x.Inv(&point.Z).Mul(affine_x, &point.X)
  142. return affine_x
  143. }
  144. func (lhs *ProjectivePoint) VartimeEq(rhs *ProjectivePoint) bool {
  145. var t0, t1 ExtensionFieldElement
  146. t0.Mul(&lhs.X, &rhs.Z)
  147. t1.Mul(&lhs.Z, &rhs.X)
  148. return t0.VartimeEq(&t1)
  149. }
  150. func ProjectivePointConditionalSwap(xP, xQ *ProjectivePoint, choice uint8) {
  151. ExtensionFieldConditionalSwap(&xP.X, &xQ.X, choice)
  152. ExtensionFieldConditionalSwap(&xP.Z, &xQ.Z, choice)
  153. }
  154. // Combined coordinate doubling and differential addition. Takes projective points
  155. // P,Q,Q-P and (A+2C)/4C curve E coefficient. Returns 2*P and P+Q calculated on E.
  156. // Function is used only by RightToLeftLadder. Corresponds to Algorithm 5 of SIKE
  157. func xDblAdd(P, Q, QmP *ProjectivePoint, a24 *ExtensionFieldElement) (dblP, PaQ ProjectivePoint) {
  158. var t0, t1, t2 ExtensionFieldElement
  159. xQmP, zQmP := &QmP.X, &QmP.Z
  160. xPaQ, zPaQ := &PaQ.X, &PaQ.Z
  161. x2P, z2P := &dblP.X, &dblP.Z
  162. xP, zP := &P.X, &P.Z
  163. xQ, zQ := &Q.X, &Q.Z
  164. t0.Add(xP, zP) // t0 = Xp+Zp
  165. t1.Sub(xP, zP) // t1 = Xp-Zp
  166. x2P.Square(&t0) // 2P.X = t0^2
  167. t2.Sub(xQ, zQ) // t2 = Xq-Zq
  168. xPaQ.Add(xQ, zQ) // Xp+q = Xq+Zq
  169. t0.Mul(&t0, &t2) // t0 = t0 * t2
  170. z2P.Mul(&t1, &t1) // 2P.Z = t1 * t1
  171. t1.Mul(&t1, xPaQ) // t1 = t1 * Xp+q
  172. t2.Sub(x2P, z2P) // t2 = 2P.X - 2P.Z
  173. x2P.Mul(x2P, z2P) // 2P.X = 2P.X * 2P.Z
  174. xPaQ.Mul(a24, &t2) // Xp+q = A24 * t2
  175. zPaQ.Sub(&t0, &t1) // Zp+q = t0 - t1
  176. z2P.Add(xPaQ, z2P) // 2P.Z = Xp+q + 2P.Z
  177. xPaQ.Add(&t0, &t1) // Xp+q = t0 + t1
  178. z2P.Mul(z2P, &t2) // 2P.Z = 2P.Z * t2
  179. zPaQ.Square(zPaQ) // Zp+q = Zp+q ^ 2
  180. xPaQ.Square(xPaQ) // Xp+q = Xp+q ^ 2
  181. zPaQ.Mul(xQmP, zPaQ) // Zp+q = Xq-p * Zp+q
  182. xPaQ.Mul(zQmP, xPaQ) // Xp+q = Zq-p * Xp+q
  183. return
  184. }
  185. // Given the curve parameters, xP = x(P), and k >= 0, compute x2P = x([2^k]P).
  186. //
  187. // Returns x2P to allow chaining. Safe to overlap xP, x2P.
  188. func (x2P *ProjectivePoint) Pow2k(params *CurveCoefficientsEquiv, xP *ProjectivePoint, k uint32) *ProjectivePoint {
  189. var t0, t1 ExtensionFieldElement
  190. *x2P = *xP
  191. x, z := &x2P.X, &x2P.Z
  192. for i := uint32(0); i < k; i++ {
  193. t0.Sub(x, z) // t0 = Xp - Zp
  194. t1.Add(x, z) // t1 = Xp + Zp
  195. t0.Square(&t0) // t0 = t0 ^ 2
  196. t1.Square(&t1) // t1 = t1 ^ 2
  197. z.Mul(&params.C, &t0) // Z2p = C24 * t0
  198. x.Mul(z, &t1) // X2p = Z2p * t1
  199. t1.Sub(&t1, &t0) // t1 = t1 - t0
  200. t0.Mul(&params.A, &t1) // t0 = A24+ * t1
  201. z.Add(z, &t0) // Z2p = Z2p + t0
  202. z.Mul(z, &t1) // Zp = Z2p * t1
  203. }
  204. return x2P
  205. }
  206. // Given the curve parameters, xP = x(P), and k >= 0, compute x3P = x([3^k]P).
  207. //
  208. // Returns x3P to allow chaining. Safe to overlap xP, xR.
  209. func (x3P *ProjectivePoint) Pow3k(params *CurveCoefficientsEquiv, xP *ProjectivePoint, k uint32) *ProjectivePoint {
  210. var t0, t1, t2, t3, t4, t5, t6 ExtensionFieldElement
  211. *x3P = *xP
  212. x, z := &x3P.X, &x3P.Z
  213. for i := uint32(0); i < k; i++ {
  214. t0.Sub(x, z) // t0 = Xp - Zp
  215. t2.Square(&t0) // t2 = t0^2
  216. t1.Add(x, z) // t1 = Xp + Zp
  217. t3.Square(&t1) // t3 = t1^2
  218. t4.Add(&t1, &t0) // t4 = t1 + t0
  219. t0.Sub(&t1, &t0) // t0 = t1 - t0
  220. t1.Square(&t4) // t1 = t4^2
  221. t1.Sub(&t1, &t3) // t1 = t1 - t3
  222. t1.Sub(&t1, &t2) // t1 = t1 - t2
  223. t5.Mul(&t3, &params.A) // t5 = t3 * A24+
  224. t3.Mul(&t3, &t5) // t3 = t5 * t3
  225. t6.Mul(&t2, &params.C) // t6 = t2 * A24-
  226. t2.Mul(&t2, &t6) // t2 = t2 * t6
  227. t3.Sub(&t2, &t3) // t3 = t2 - t3
  228. t2.Sub(&t5, &t6) // t2 = t5 - t6
  229. t1.Mul(&t2, &t1) // t1 = t2 * t1
  230. t2.Add(&t3, &t1) // t2 = t3 + t1
  231. t2.Square(&t2) // t2 = t2^2
  232. x.Mul(&t2, &t4) // X3p = t2 * t4
  233. t1.Sub(&t3, &t1) // t1 = t3 - t1
  234. t1.Square(&t1) // t1 = t1^2
  235. z.Mul(&t1, &t0) // Z3p = t1 * t0
  236. }
  237. return x3P
  238. }
  239. // RightToLeftLadder is a right-to-left point multiplication that given the
  240. // x-coordinate of P, Q and P-Q calculates the x-coordinate of R=Q+[scalar]P.
  241. // nbits must be smaller or equal to len(scalar).
  242. func RightToLeftLadder(c *ProjectiveCurveParameters, P, Q, PmQ *ProjectivePoint,
  243. nbits uint, scalar []uint8) ProjectivePoint {
  244. var R0, R2, R1 ProjectivePoint
  245. aPlus2Over4 := c.calcAplus2Over4()
  246. R1 = *P
  247. R2 = *PmQ
  248. R0 = *Q
  249. // Iterate over the bits of the scalar, bottom to top
  250. prevBit := uint8(0)
  251. for i := uint(0); i < nbits; i++ {
  252. bit := (scalar[i>>3] >> (i & 7) & 1)
  253. swap := prevBit ^ bit
  254. prevBit = bit
  255. ProjectivePointConditionalSwap(&R1, &R2, swap)
  256. R0, R2 = xDblAdd(&R0, &R2, &R1, &aPlus2Over4)
  257. }
  258. ProjectivePointConditionalSwap(&R1, &R2, prevBit)
  259. return R1
  260. }