選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。
 
 
 

742 行
28 KiB

  1. package p751toolbox
  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. func (params *ProjectiveCurveParameters) FromAffine(a *ExtensionFieldElement) {
  10. params.A = *a
  11. params.C = oneExtensionField
  12. }
  13. type CachedCurveParameters struct {
  14. Aplus2C ExtensionFieldElement
  15. C4 ExtensionFieldElement
  16. }
  17. type CachedTripleCurveParameters struct {
  18. Aminus2C ExtensionFieldElement
  19. C2 ExtensionFieldElement
  20. }
  21. // = 256
  22. var const256 = ExtensionFieldElement{
  23. A: Fp751Element{0x249ad67, 0x0, 0x0, 0x0, 0x0, 0x730000000000000, 0x738154969973da8b, 0x856657c146718c7f, 0x461860e4e363a697, 0xf9fd6510bba838cd, 0x4e1a3c3f06993c0c, 0x55abef5b75c7},
  24. B: Fp751Element{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0},
  25. }
  26. // Recover the curve parameters from three points on the curve.
  27. func RecoverCurveParameters(affine_xP, affine_xQ, affine_xQmP *ExtensionFieldElement) ProjectiveCurveParameters {
  28. var curveParams ProjectiveCurveParameters
  29. var t0, t1 ExtensionFieldElement
  30. t0.One() // = 1
  31. t1.Mul(affine_xP, affine_xQ) // = x_P * x_Q
  32. t0.Sub(&t0, &t1) // = 1 - x_P * x_Q
  33. t1.Mul(affine_xP, affine_xQmP) // = x_P * x_{Q-P}
  34. t0.Sub(&t0, &t1) // = 1 - x_P * x_Q - x_P * x_{Q-P}
  35. t1.Mul(affine_xQ, affine_xQmP) // = x_Q * x_{Q-P}
  36. t0.Sub(&t0, &t1) // = 1 - x_P * x_Q - x_P * x_{Q-P} - x_Q * x_{Q-P}
  37. curveParams.A.Square(&t0) // = (1 - x_P * x_Q - x_P * x_{Q-P} - x_Q * x_{Q-P})^2
  38. t1.Mul(&t1, affine_xP) // = x_P * x_Q * x_{Q-P}
  39. t1.Add(&t1, &t1) // = 2 * x_P * x_Q * x_{Q-P}
  40. curveParams.C.Add(&t1, &t1) // = 4 * x_P * x_Q * x_{Q-P}
  41. t0.Add(affine_xP, affine_xQ) // = x_P + x_Q
  42. t0.Add(&t0, affine_xQmP) // = x_P + x_Q + x_{Q-P}
  43. t1.Mul(&curveParams.C, &t0) // = 4 * x_P * x_Q * x_{Q-P} * (x_P + x_Q + x_{Q-P})
  44. curveParams.A.Sub(&curveParams.A, &t1) // = (1 - x_P * x_Q - x_P * x_{Q-P} - x_Q * x_{Q-P})^2 - 4 * x_P * x_Q * x_{Q-P} * (x_P + x_Q + x_{Q-P})
  45. return curveParams
  46. }
  47. // Compute the j-invariant (not the J-invariant) of the given curve.
  48. func (curveParams *ProjectiveCurveParameters) JInvariant() ExtensionFieldElement {
  49. var v0, v1, v2, v3 ExtensionFieldElement
  50. A := &curveParams.A
  51. C := &curveParams.C
  52. v0.Square(C) // C^2
  53. v1.Square(A) // A^2
  54. v2.Add(&v0, &v0) // 2C^2
  55. v3.Add(&v2, &v0) // 3C^2
  56. v2.Add(&v2, &v2) // 4C^2
  57. v2.Sub(&v1, &v2) // A^2 - 4C^2
  58. v1.Sub(&v1, &v3) // A^2 - 3C^2
  59. v3.Square(&v1) // (A^2 - 3C^2)^2
  60. v3.Mul(&v3, &v1) // (A^2 - 3C^2)^3
  61. v0.Square(&v0) // C^4
  62. v3.Mul(&v3, &const256) // 256(A^2 - 3C^2)^3
  63. v2.Mul(&v2, &v0) // C^4(A^2 - 4C^2)
  64. v2.Inv(&v2) // 1/C^4(A^2 - 4C^2)
  65. v0.Mul(&v3, &v2) // 256(A^2 - 3C^2)^3 / C^4(A^2 - 4C^2)
  66. return v0
  67. }
  68. // Compute cached parameters A + 2C, 4C.
  69. func (curve *ProjectiveCurveParameters) cachedParams() CachedCurveParameters {
  70. var cached CachedCurveParameters
  71. cached.Aplus2C.Add(&curve.C, &curve.C) // = 2*C
  72. cached.C4.Add(&cached.Aplus2C, &cached.Aplus2C) // = 4*C
  73. cached.Aplus2C.Add(&cached.Aplus2C, &curve.A) // = 2*C + A
  74. return cached
  75. }
  76. // Compute cached parameters A - 2C, 2C.
  77. func (curve *ProjectiveCurveParameters) cachedTripleParams() CachedTripleCurveParameters {
  78. var cached CachedTripleCurveParameters
  79. cached.C2.Add(&curve.C, &curve.C) // = 2*C
  80. cached.Aminus2C.Sub(&curve.A, &cached.C2) // = A- 2*C
  81. return cached
  82. }
  83. // A point on the projective line P^1(F_{p^2}).
  84. //
  85. // This represents a point on the (Kummer line) of a Montgomery curve. The
  86. // curve is specified by a ProjectiveCurveParameters struct.
  87. type ProjectivePoint struct {
  88. X ExtensionFieldElement
  89. Z ExtensionFieldElement
  90. }
  91. // A point on the projective line P^1(F_p).
  92. //
  93. // This represents a point on the (Kummer line) of the prime-field subgroup of
  94. // the base curve E_0(F_p), defined by E_0 : y^2 = x^3 + x.
  95. type ProjectivePrimeFieldPoint struct {
  96. X PrimeFieldElement
  97. Z PrimeFieldElement
  98. }
  99. func (point *ProjectivePoint) FromAffinePrimeField(x *PrimeFieldElement) {
  100. point.X.A = x.A
  101. point.X.B = zeroExtensionField.B
  102. point.Z = oneExtensionField
  103. }
  104. func (point *ProjectivePoint) FromAffine(x *ExtensionFieldElement) {
  105. point.X = *x
  106. point.Z = oneExtensionField
  107. }
  108. func (point *ProjectivePrimeFieldPoint) FromAffine(x *PrimeFieldElement) {
  109. point.X = *x
  110. point.Z = onePrimeField
  111. }
  112. func (point *ProjectivePoint) ToAffine() *ExtensionFieldElement {
  113. affine_x := new(ExtensionFieldElement)
  114. affine_x.Inv(&point.Z).Mul(affine_x, &point.X)
  115. return affine_x
  116. }
  117. func (point *ProjectivePrimeFieldPoint) ToAffine() *PrimeFieldElement {
  118. affine_x := new(PrimeFieldElement)
  119. affine_x.Inv(&point.Z).Mul(affine_x, &point.X)
  120. return affine_x
  121. }
  122. func (lhs *ProjectivePoint) VartimeEq(rhs *ProjectivePoint) bool {
  123. var t0, t1 ExtensionFieldElement
  124. t0.Mul(&lhs.X, &rhs.Z)
  125. t1.Mul(&lhs.Z, &rhs.X)
  126. return t0.VartimeEq(&t1)
  127. }
  128. func (lhs *ProjectivePrimeFieldPoint) VartimeEq(rhs *ProjectivePrimeFieldPoint) bool {
  129. var t0, t1 PrimeFieldElement
  130. t0.Mul(&lhs.X, &rhs.Z)
  131. t1.Mul(&lhs.Z, &rhs.X)
  132. return t0.VartimeEq(&t1)
  133. }
  134. func ProjectivePointConditionalSwap(xP, xQ *ProjectivePoint, choice uint8) {
  135. ExtensionFieldConditionalSwap(&xP.X, &xQ.X, choice)
  136. ExtensionFieldConditionalSwap(&xP.Z, &xQ.Z, choice)
  137. }
  138. func ProjectivePrimeFieldPointConditionalSwap(xP, xQ *ProjectivePrimeFieldPoint, choice uint8) {
  139. PrimeFieldConditionalSwap(&xP.X, &xQ.X, choice)
  140. PrimeFieldConditionalSwap(&xP.Z, &xQ.Z, choice)
  141. }
  142. // Given xP = x(P), xQ = x(Q), and xPmQ = x(P-Q), compute xR = x(P+Q).
  143. //
  144. // Returns xR to allow chaining. Safe to overlap xP, xQ, xR.
  145. func (xR *ProjectivePoint) Add(xP, xQ, xPmQ *ProjectivePoint) *ProjectivePoint {
  146. // Algorithm 1 of Costello-Smith.
  147. var v0, v1, v2, v3, v4 ExtensionFieldElement
  148. v0.Add(&xP.X, &xP.Z) // X_P + Z_P
  149. v1.Sub(&xQ.X, &xQ.Z).Mul(&v1, &v0) // (X_Q - Z_Q)(X_P + Z_P)
  150. v0.Sub(&xP.X, &xP.Z) // X_P - Z_P
  151. v2.Add(&xQ.X, &xQ.Z).Mul(&v2, &v0) // (X_Q + Z_Q)(X_P - Z_P)
  152. v3.Add(&v1, &v2).Square(&v3) // 4(X_Q X_P - Z_Q Z_P)^2
  153. v4.Sub(&v1, &v2).Square(&v4) // 4(X_Q Z_P - Z_Q X_P)^2
  154. v0.Mul(&xPmQ.Z, &v3) // 4X_{P-Q}(X_Q X_P - Z_Q Z_P)^2
  155. xR.Z.Mul(&xPmQ.X, &v4) // 4Z_{P-Q}(X_Q Z_P - Z_Q X_P)^2
  156. xR.X = v0
  157. return xR
  158. }
  159. // Given xP = x(P), xQ = x(Q), and xPmQ = x(P-Q), compute xR = x(P+Q).
  160. //
  161. // Returns xR to allow chaining. Safe to overlap xP, xQ, xR.
  162. func (xR *ProjectivePrimeFieldPoint) Add(xP, xQ, xPmQ *ProjectivePrimeFieldPoint) *ProjectivePrimeFieldPoint {
  163. // Algorithm 1 of Costello-Smith.
  164. var v0, v1, v2, v3, v4 PrimeFieldElement
  165. v0.Add(&xP.X, &xP.Z) // X_P + Z_P
  166. v1.Sub(&xQ.X, &xQ.Z).Mul(&v1, &v0) // (X_Q - Z_Q)(X_P + Z_P)
  167. v0.Sub(&xP.X, &xP.Z) // X_P - Z_P
  168. v2.Add(&xQ.X, &xQ.Z).Mul(&v2, &v0) // (X_Q + Z_Q)(X_P - Z_P)
  169. v3.Add(&v1, &v2).Square(&v3) // 4(X_Q X_P - Z_Q Z_P)^2
  170. v4.Sub(&v1, &v2).Square(&v4) // 4(X_Q Z_P - Z_Q X_P)^2
  171. v0.Mul(&xPmQ.Z, &v3) // 4X_{P-Q}(X_Q X_P - Z_Q Z_P)^2
  172. xR.Z.Mul(&xPmQ.X, &v4) // 4Z_{P-Q}(X_Q Z_P - Z_Q X_P)^2
  173. xR.X = v0
  174. return xR
  175. }
  176. // Given xP = x(P) and cached curve parameters Aplus2C = A + 2*C, C4 = 4*C, compute xQ = x([2]P).
  177. //
  178. // Returns xQ to allow chaining. Safe to overlap xP, xQ.
  179. func (xQ *ProjectivePoint) Double(xP *ProjectivePoint, curve *CachedCurveParameters) *ProjectivePoint {
  180. // Algorithm 2 of Costello-Smith, amended to work with projective curve coefficients.
  181. var v1, v2, v3, xz4 ExtensionFieldElement
  182. v1.Add(&xP.X, &xP.Z).Square(&v1) // (X+Z)^2
  183. v2.Sub(&xP.X, &xP.Z).Square(&v2) // (X-Z)^2
  184. xz4.Sub(&v1, &v2) // 4XZ = (X+Z)^2 - (X-Z)^2
  185. v2.Mul(&v2, &curve.C4) // 4C(X-Z)^2
  186. xQ.X.Mul(&v1, &v2) // 4C(X+Z)^2(X-Z)^2
  187. v3.Mul(&xz4, &curve.Aplus2C) // 4XZ(A + 2C)
  188. v3.Add(&v3, &v2) // 4XZ(A + 2C) + 4C(X-Z)^2
  189. xQ.Z.Mul(&v3, &xz4) // (4XZ(A + 2C) + 4C(X-Z)^2)4XZ
  190. // Now (xQ.x : xQ.z)
  191. // = (4C(X+Z)^2(X-Z)^2 : (4XZ(A + 2C) + 4C(X-Z)^2)4XZ )
  192. // = ((X+Z)^2(X-Z)^2 : (4XZ((A + 2C)/4C) + (X-Z)^2)4XZ )
  193. // = ((X+Z)^2(X-Z)^2 : (4XZ((a + 2)/4) + (X-Z)^2)4XZ )
  194. return xQ
  195. }
  196. // Given xP = x(P) and cached curve parameter aPlus2Over4 = (a+2)/4, compute xQ = x([2]P).
  197. //
  198. // Note that we don't use projective curve coefficients here because we only
  199. // ever use a fixed curve (in our case, the base curve E_0).
  200. //
  201. // Returns xQ to allow chaining. Safe to overlap xP, xQ.
  202. func (xQ *ProjectivePrimeFieldPoint) Double(xP *ProjectivePrimeFieldPoint, aPlus2Over4 *PrimeFieldElement) *ProjectivePrimeFieldPoint {
  203. // Algorithm 2 of Costello-Smith
  204. var v1, v2, v3, xz4 PrimeFieldElement
  205. v1.Add(&xP.X, &xP.Z).Square(&v1) // (X+Z)^2
  206. v2.Sub(&xP.X, &xP.Z).Square(&v2) // (X-Z)^2
  207. xz4.Sub(&v1, &v2) // 4XZ = (X+Z)^2 - (X-Z)^2
  208. xQ.X.Mul(&v1, &v2) // (X+Z)^2(X-Z)^2
  209. v3.Mul(&xz4, aPlus2Over4) // 4XZ((a+2)/4)
  210. v3.Add(&v3, &v2) // 4XZ((a+2)/4) + (X-Z)^2
  211. xQ.Z.Mul(&v3, &xz4) // (4XZ((a+2)/4) + (X-Z)^2)4XZ
  212. // Now (xQ.x : xQ.z)
  213. // = ((X+Z)^2(X-Z)^2 : (4XZ((a + 2)/4) + (X-Z)^2)4XZ )
  214. return xQ
  215. }
  216. // Given xP = x(P), xQ = x(Q), and xPmQ = x(P-Q), compute xPaddQ = x(P+Q) and x2P = x(2P).
  217. func xDblAdd(curve *CachedCurveParameters, xP, xQ, xPmQ *ProjectivePoint) (x2P, xPaddQ ProjectivePoint) {
  218. var A, AA, B, BB, C, D, E, DA, CB, t0, t1 ExtensionFieldElement
  219. x1, z1 := &xPmQ.X, &xPmQ.Z
  220. x2, z2 := &xP.X, &xP.Z
  221. x3, z3 := &xQ.X, &xQ.Z
  222. A.Add(x2, z2) // A = x2+z2
  223. B.Sub(x2, z2) // B = x2-z2
  224. C.Add(x3, z3) // C = x3+z3
  225. D.Sub(x3, z3) // D = x3-z3
  226. AA.Square(&A) // AA = A^2
  227. BB.Square(&B) // BB = B^2
  228. E.Sub(&AA, &BB) // E = AA-BB
  229. BB.Mul(&BB, &curve.C4) // BB = (4C)*BB
  230. DA.Mul(&D, &A) // DA = D*A
  231. CB.Mul(&C, &B) // CB = C*B
  232. t1.Add(&DA, &CB) // t1 = DA+CB
  233. t0.Sub(&DA, &CB) // t0 = DA-CB
  234. t1.Square(&t1) // t1 = t1^2
  235. t0.Square(&t0) // t0 = t0^2
  236. xPaddQ.X.Mul(z1, &t1) // z5 = z1*t1
  237. xPaddQ.Z.Mul(x1, &t0) // x5 = x1*t0
  238. x2P.X.Mul(&AA, &BB) // x4 = AA*(4C)*BB
  239. x2P.Z.Mul(&curve.Aplus2C, &E) // z4 = (A+2C)*E
  240. x2P.Z.Add(&x2P.Z, &BB) // z4 = (4C)*BB+(A+2C)*E
  241. x2P.Z.Mul(&x2P.Z, &E) // z4 = E*((4C)*BB+(A+2C)*E)
  242. return
  243. }
  244. // Given xP = x(P), xQ = x(Q), and xPmQ = x(P-Q), compute xPaddQ = x(P+Q) and x2P = x(2P).
  245. // Assumes that the Z-xoordinate of PmQ is equal to 1.
  246. func xDblAdd_primefield(aPlus2Over4 *PrimeFieldElement, xP, xQ, xPmQ *ProjectivePrimeFieldPoint) (x2P, xPaddQ ProjectivePrimeFieldPoint) {
  247. var A, AA, B, BB, C, D, E, DA, CB, t0, t1 PrimeFieldElement
  248. x1 := &xPmQ.X
  249. x2, z2 := &xP.X, &xP.Z
  250. x3, z3 := &xQ.X, &xQ.Z
  251. A.Add(x2, z2) // A = x2+z2
  252. B.Sub(x2, z2) // B = x2-z2
  253. C.Add(x3, z3) // C = x3+z3
  254. D.Sub(x3, z3) // D = x3-z3
  255. AA.Square(&A) // AA = A^2
  256. BB.Square(&B) // BB = B^2
  257. E.Sub(&AA, &BB) // E = AA-BB
  258. DA.Mul(&D, &A) // DA = D*A
  259. CB.Mul(&C, &B) // CB = C*B
  260. t1.Add(&DA, &CB) // t1 = DA+CB
  261. t0.Sub(&DA, &CB) // t0 = DA-CB
  262. t1.Square(&t1) // t1 = t1^2
  263. t0.Square(&t0) // t0 = t0^2
  264. xPaddQ.X = t1 // z5 = z1*t1
  265. xPaddQ.Z.Mul(x1, &t0) // x5 = x1*t0
  266. x2P.X.Mul(&AA, &BB) // x4 = AA*(4C)*BB
  267. x2P.Z.Mul(aPlus2Over4, &E) // z4 = (A+2C)*E
  268. x2P.Z.Add(&x2P.Z, &BB) // z4 = (4C)*BB+(A+2C)*E
  269. x2P.Z.Mul(&x2P.Z, &E) // z4 = E*((4C)*BB+(A+2C)*E)
  270. return
  271. }
  272. // Given the curve parameters, xP = x(P), and k >= 0, compute xQ = x([2^k]P).
  273. //
  274. // Returns xQ to allow chaining. Safe to overlap xP, xQ.
  275. func (xQ *ProjectivePoint) Pow2k(curve *ProjectiveCurveParameters, xP *ProjectivePoint, k uint32) *ProjectivePoint {
  276. cachedParams := curve.cachedParams()
  277. *xQ = *xP
  278. for i := uint32(0); i < k; i++ {
  279. xQ.Double(xQ, &cachedParams)
  280. }
  281. return xQ
  282. }
  283. // Uses the efficient Montgomery tripling formulas from FLOR-SIDH-x64
  284. // Given xP = x(P) and cached tripling curve parameters Aminus2C = A - 2*C, C2 = 2*C, compute xQ = x([3]P).
  285. // Returns xQ to allow chaining. Safe to overlap xP, xQ.
  286. // Reference: A faster SW implementation of SIDH (github.com/armfazh/flor-sidh-x64).
  287. func (xQ *ProjectivePoint) Triple(xP *ProjectivePoint, curve *CachedTripleCurveParameters) *ProjectivePoint {
  288. var t0, t1, t2, t3, t4, t5 ExtensionFieldElement
  289. x1, z1 := &xP.X, &xP.Z
  290. t0.Square(x1) // t0 = x1^2
  291. t1.Square(z1) // t1 = z1^2
  292. t2.Add(x1, z1) // t2 = x1+z1
  293. t2.Square(&t2) // t2 = t2^2
  294. t3.Add(&t0, &t1) // t3 = t0+t1
  295. t4.Sub(&t2, &t3) // t4 = t2-t3
  296. t5.Mul(&curve.Aminus2C, &t4) // t5 = (A-2C)*t4
  297. t2.Mul(&curve.C2, &t2) // t2 = (2C)*t2
  298. t5.Add(&t5, &t2) // t5 = t2+t5
  299. t5.Add(&t5, &t5) // t5 = t5+t5
  300. t5.Add(&t5, &t5) // t5 = t5+t5
  301. t0.Mul(&t0, &t5) // t0 = t0*t5
  302. t1.Mul(&t1, &t5) // t1 = t1*t5
  303. t4.Sub(&t3, &t4) // t4 = t3-t4
  304. t2.Mul(&t2, &t4) // t2 = t2*t4
  305. t0.Sub(&t2, &t0) // t0 = t2-t0
  306. t1.Sub(&t2, &t1) // t1 = t2-t1
  307. t0.Square(&t0) // t0 = t0^2
  308. t1.Square(&t1) // t1 = t1^2
  309. xQ.X.Mul(x1, &t1) // x3 = x1*t1
  310. xQ.Z.Mul(z1, &t0) // z3 = z1*t0
  311. return xQ
  312. }
  313. // Given the curve parameters, xP = x(P), and k >= 0, compute xQ = x([3^k]P).
  314. //
  315. // Returns xQ to allow chaining. Safe to overlap xP, xQ.
  316. func (xQ *ProjectivePoint) Pow3k(curve *ProjectiveCurveParameters, xP *ProjectivePoint, k uint32) *ProjectivePoint {
  317. cachedParams := curve.cachedTripleParams()
  318. *xQ = *xP
  319. for i := uint32(0); i < k; i++ {
  320. xQ.Triple(xQ, &cachedParams)
  321. }
  322. return xQ
  323. }
  324. // Given x(P) and a scalar m in little-endian bytes, compute x([m]P) using the
  325. // Montgomery ladder. This is described in Algorithm 8 of Costello-Smith.
  326. //
  327. // This function's execution time is dependent only on the byte-length of the
  328. // input scalar. All scalars of the same input length execute in uniform time.
  329. // The scalar can be padded with zero bytes to ensure a uniform length.
  330. //
  331. // Safe to overlap the source with the destination.
  332. func (xQ *ProjectivePoint) ScalarMult(curve *ProjectiveCurveParameters, xP *ProjectivePoint, scalar []uint8) *ProjectivePoint {
  333. cachedParams := curve.cachedParams()
  334. var x0, x1, tmp ProjectivePoint
  335. x0.X.One()
  336. x0.Z.Zero()
  337. x1 = *xP
  338. // Iterate over the bits of the scalar, top to bottom
  339. prevBit := uint8(0)
  340. for i := len(scalar) - 1; i >= 0; i-- {
  341. scalarByte := scalar[i]
  342. for j := 7; j >= 0; j-- {
  343. bit := (scalarByte >> uint(j)) & 0x1
  344. ProjectivePointConditionalSwap(&x0, &x1, (bit ^ prevBit))
  345. tmp.Double(&x0, &cachedParams)
  346. x1.Add(&x0, &x1, xP)
  347. x0 = tmp
  348. prevBit = bit
  349. }
  350. }
  351. // now prevBit is the lowest bit of the scalar
  352. ProjectivePointConditionalSwap(&x0, &x1, prevBit)
  353. *xQ = x0
  354. return xQ
  355. }
  356. // Given x(P) and a scalar m in little-endian bytes, compute x([m]P), x([m+1]P) using the
  357. // Montgomery ladder. This is described in Algorithm 8 of Costello-Smith.
  358. //
  359. // The extra value x([m+1]P) is returned to allow y-coordinate recovery;
  360. // otherwise, it can be ignored.
  361. //
  362. // This function's execution time is dependent only on the byte-length of the
  363. // input scalar. All scalars of the same input length execute in uniform time.
  364. // The scalar can be padded with zero bytes to ensure a uniform length.
  365. func ScalarMultPrimeField(aPlus2Over4 *PrimeFieldElement, xP *ProjectivePrimeFieldPoint, scalar []uint8) (ProjectivePrimeFieldPoint, ProjectivePrimeFieldPoint) {
  366. var x0, x1 ProjectivePrimeFieldPoint
  367. x0.X.One()
  368. x0.Z.Zero()
  369. x1 = *xP
  370. // Iterate over the bits of the scalar, top to bottom
  371. prevBit := uint8(0)
  372. for i := len(scalar) - 1; i >= 0; i-- {
  373. scalarByte := scalar[i]
  374. for j := 7; j >= 0; j-- {
  375. bit := (scalarByte >> uint(j)) & 0x1
  376. ProjectivePrimeFieldPointConditionalSwap(&x0, &x1, (bit ^ prevBit))
  377. x0, x1 = xDblAdd_primefield(aPlus2Over4, &x0, &x1, xP)
  378. prevBit = bit
  379. }
  380. }
  381. // now prevBit is the lowest bit of the scalar
  382. ProjectivePrimeFieldPointConditionalSwap(&x0, &x1, prevBit)
  383. return x0, x1
  384. }
  385. // Given P = (x_P, y_P) in affine coordinates, as well as projective points
  386. // x(Q), x(R) = x(P+Q), all in the prime-field subgroup of the starting curve
  387. // E_0(F_p), use the Okeya-Sakurai coordinate recovery strategy to recover Q =
  388. // (X_Q : Y_Q : Z_Q).
  389. //
  390. // This is Algorithm 5 of Costello-Smith, with the constants a = 0, b = 1 hardcoded.
  391. func OkeyaSakuraiCoordinateRecovery(affine_xP, affine_yP *PrimeFieldElement, xQ, xR *ProjectivePrimeFieldPoint) (X_Q, Y_Q, Z_Q PrimeFieldElement) {
  392. var v1, v2, v3, v4 PrimeFieldElement
  393. v1.Mul(affine_xP, &xQ.Z) // = x_P*Z_Q
  394. v2.Add(&xQ.X, &v1) // = X_Q + x_P*Z_Q
  395. v3.Sub(&xQ.X, &v1).Square(&v3) // = (X_Q - x_P*Z_Q)^2
  396. v3.Mul(&v3, &xR.X) // = X_R*(X_Q - x_P*Z_Q)^2
  397. // Skip setting v1 = 2a*Z_Q (step 6) since we hardcode a = 0
  398. // Skip adding v1 to v2 (step 7) since v1 is zero
  399. v4.Mul(affine_xP, &xQ.X) // = x_P*X_Q
  400. v4.Add(&v4, &xQ.Z) // = x_P*X_Q + Z_Q
  401. v2.Mul(&v2, &v4) // = (x_P*X_Q + Z_Q)*(X_Q + x_P*Z_Q)
  402. // Skip multiplication by v1 (step 11) since v1 is zero
  403. // Skip subtracting v1 from v2 (step 12) since v1 is zero
  404. v2.Mul(&v2, &xR.Z) // = (x_P*X_Q + Z_Q)*(X_Q + x_P*Z_Q)*Z_R
  405. Y_Q.Sub(&v2, &v3) // = (x_P*X_Q + Z_Q)*(X_Q + x_P*Z_Q)*Z_R - X_R*(X_Q - x_P*Z_Q)^2
  406. v1.Add(affine_yP, affine_yP) // = 2b*y_P
  407. v1.Mul(&v1, &xQ.Z).Mul(&v1, &xR.Z) // = 2b*y_P*Z_Q*Z_R
  408. X_Q.Mul(&v1, &xQ.X) // = 2b*y_P*Z_Q*Z_R*X_Q
  409. Z_Q.Mul(&v1, &xQ.Z) // = 2b*y_P*Z_Q^2*Z_R
  410. return
  411. }
  412. // Given x(P), x(Q), x(P-Q), as well as a scalar m in little-endian bytes,
  413. // compute x(P + [m]Q) using the "three-point ladder" of de Feo, Jao, and Plut.
  414. //
  415. // Safe to overlap the source with the destination.
  416. //
  417. // This function's execution time is dependent only on the byte-length of the
  418. // input scalar. All scalars of the same input length execute in uniform time.
  419. // The scalar can be padded with zero bytes to ensure a uniform length.
  420. //
  421. // The algorithm, as described in de Feo-Jao-Plut, is as follows:
  422. //
  423. // (x0, x1, x2) <--- (x(O), x(Q), x(P))
  424. //
  425. // for i = |m| down to 0, indexing the bits of m:
  426. // Invariant: (x0, x1, x2) == (x( [t]Q ), x( [t+1]Q ), x( P + [t]Q ))
  427. // where t = m//2^i is the high bits of m, starting at i
  428. // if m_i == 0:
  429. // (x0, x1, x2) <--- (xDBL(x0), xADD(x1, x0, x(Q)), xADD(x2, x0, x(P)))
  430. // Invariant: (x0, x1, x2) == (x( [2t]Q ), x( [2t+1]Q ), x( P + [2t]Q ))
  431. // == (x( [t']Q ), x( [t'+1]Q ), x( P + [t']Q ))
  432. // where t' = m//2^{i-1} is the high bits of m, starting at i-1
  433. // if m_i == 1:
  434. // (x0, x1, x2) <--- (xADD(x1, x0, x(Q)), xDBL(x1), xADD(x2, x1, x(P-Q)))
  435. // Invariant: (x0, x1, x2) == (x( [2t+1]Q ), x( [2t+2]Q ), x( P + [2t+1]Q ))
  436. // == (x( [t']Q ), x( [t'+1]Q ), x( P + [t']Q ))
  437. // where t' = m//2^{i-1} is the high bits of m, starting at i-1
  438. // return x2
  439. //
  440. // Notice that the roles of (x0,x1) and (x(P), x(P-Q)) swap depending on the
  441. // current bit of the scalar. Instead of swapping which operations we do, we
  442. // can swap variable names, producing the following uniform algorithm:
  443. //
  444. // (x0, x1, x2) <--- (x(O), x(Q), x(P))
  445. // (y0, y1) <--- (x(P), x(P-Q))
  446. //
  447. // for i = |m| down to 0, indexing the bits of m:
  448. // (x0, x1) <--- SWAP( m_{i+1} xor m_i, (x0,x1) )
  449. // (y0, y1) <--- SWAP( m_{i+1} xor m_i, (y0,y1) )
  450. // (x0, x1, x2) <--- ( xDBL(x0), xADD(x1,x0,x(Q)), xADD(x2, x0, y0) )
  451. //
  452. // return x2
  453. //
  454. func (xR *ProjectivePoint) ThreePointLadder(curve *ProjectiveCurveParameters, xP, xQ, xPmQ *ProjectivePoint, scalar []uint8) *ProjectivePoint {
  455. cachedParams := curve.cachedParams()
  456. var x0, x1, x2, y0, y1, tmp ProjectivePoint
  457. // (x0, x1, x2) <--- (x(O), x(Q), x(P))
  458. x0.X.One()
  459. x0.Z.Zero()
  460. x1 = *xQ
  461. x2 = *xP
  462. // (y0, y1) <--- (x(P), x(P-Q))
  463. y0 = *xP
  464. y1 = *xPmQ
  465. // Iterate over the bits of the scalar, top to bottom
  466. prevBit := uint8(0)
  467. for i := len(scalar) - 1; i >= 0; i-- {
  468. scalarByte := scalar[i]
  469. for j := 7; j >= 0; j-- {
  470. bit := (scalarByte >> uint(j)) & 0x1
  471. ProjectivePointConditionalSwap(&x0, &x1, (bit ^ prevBit))
  472. ProjectivePointConditionalSwap(&y0, &y1, (bit ^ prevBit))
  473. tmp, x2 = xDblAdd(&cachedParams, &x0, &x2, &y0)
  474. x1.Add(&x1, &x0, xQ) // = xADD(x1, x0, x(Q))
  475. x0 = tmp
  476. prevBit = bit
  477. }
  478. }
  479. *xR = x2
  480. return xR
  481. }
  482. /**
  483. Update: This is the right-to-left method for computing the x-coordinate of P+[k]Q.
  484. Desc: This function replaces the ThreePointLadder function and improves the running
  485. time by performing 1 Addition + 1 Doubling per bit of k.
  486. Reference: A faster SW implementation of SIDH (github.com/armfazh/flor-sidh-x64).
  487. */
  488. func (xR *ProjectivePoint) R2L(curve *ProjectiveCurveParameters, xP, xQ, xPmQ *ProjectivePoint, scalar []uint8) *ProjectivePoint {
  489. cachedParams := curve.cachedParams()
  490. var R0, R2, R1 ProjectivePoint
  491. R1 = *xP
  492. R2 = *xPmQ
  493. R0 = *xQ
  494. // Iterate over the bits of the scalar, bottom to top
  495. prevBit := uint8(0)
  496. for i := 0; i < len(scalar); i++ {
  497. scalarByte := scalar[i]
  498. for j := 0; j < 8; j++ {
  499. bit := (scalarByte >> uint(j)) & 0x1
  500. ProjectivePointConditionalSwap(&R1, &R2, (bit ^ prevBit))
  501. R0, R2 = xDblAdd(&cachedParams, &R0, &R2, &R1)
  502. prevBit = bit
  503. }
  504. }
  505. ProjectivePointConditionalSwap(&R1, &R2, prevBit)
  506. *xR = R1
  507. return xR
  508. }
  509. // Given the affine x-coordinate affine_xP of P, compute the x-coordinate
  510. // x(\tau(P)-P) of \tau(P)-P.
  511. func DistortAndDifference(affine_xP *PrimeFieldElement) ProjectivePoint {
  512. var xR ProjectivePoint
  513. var t0, t1 PrimeFieldElement
  514. t0.Square(affine_xP) // = x_P^2
  515. t1.One().Add(&t1, &t0) // = x_P^2 + 1
  516. xR.X.B = t1.A // = 0 + (x_P^2 + 1)*i
  517. t0.Add(affine_xP, affine_xP) // = 2*x_P
  518. xR.Z.A = t0.A // = 2*x_P + 0*i
  519. return xR
  520. }
  521. // Given an affine point P = (x_P, y_P) in the prime-field subgroup of the
  522. // starting curve E_0(F_p), together with a secret scalar m, compute x(P+[m]Q),
  523. // where Q = \tau(P) is the image of P under the distortion map described
  524. // below.
  525. //
  526. // The computation uses basically the same strategy as the
  527. // Costello-Longa-Naehrig implementation:
  528. //
  529. // 1. Use the standard Montgomery ladder to compute x([m]Q), x([m+1]Q)
  530. //
  531. // 2. Use Okeya-Sakurai coordinate recovery to recover [m]Q from Q, x([m]Q),
  532. // x([m+1]Q)
  533. //
  534. // 3. Use P and [m]Q to compute x(P + [m]Q)
  535. //
  536. // The distortion map \tau is defined as
  537. //
  538. // \tau : E_0(F_{p^2}) ---> E_0(F_{p^2})
  539. //
  540. // \tau : (x,y) |---> (-x, iy).
  541. //
  542. // The image of the distortion map is the _trace-zero_ subgroup of E_0(F_{p^2})
  543. // defined by Tr(P) = P + \pi_p(P) = id, where \pi_p((x,y)) = (x^p, y^p) is the
  544. // p-power Frobenius map. To see this, take P = (x,y) \in E_0(F_{p^2}). Then
  545. // Tr(P) = id if and only if \pi_p(P) = -P, so that
  546. //
  547. // -P = (x, -y) = (x^p, y^p) = \pi_p(P);
  548. //
  549. // we have x^p = x if and only if x \in F_p, while y^p = -y if and only if y =
  550. // i*y' for y' \in F_p.
  551. //
  552. // Thus (excepting the identity) every point in the trace-zero subgroup is of
  553. // the form \tau((x,y)) = (-x,i*y) for (x,y) \in E_0(F_p).
  554. //
  555. // Since the Montgomery ladder only uses the x-coordinate, and the x-coordinate
  556. // is always in the prime subfield, we can compute x([m]Q), x([m+1]Q) entirely
  557. // in the prime subfield.
  558. //
  559. // The affine form of the relation for Okeya-Sakurai coordinate recovery is
  560. // given on p. 13 of Costello-Smith:
  561. //
  562. // y_Q = ((x_P*x_Q + 1)*(x_P + x_Q + 2*a) - 2*a - x_R*(x_P - x_Q)^2)/(2*b*y_P),
  563. //
  564. // where R = Q + P and a,b are the Montgomery parameters. In our setting
  565. // (a,b)=(0,1) and our points are P=Q, Q=[m]Q, P+Q=[m+1]Q, so this becomes
  566. //
  567. // y_{mQ} = ((x_Q*x_{mQ} + 1)*(x_Q + x_{mQ}) - x_{m1Q}*(x_Q - x_{mQ})^2)/(2*y_Q)
  568. //
  569. // y_{mQ} = ((1 - x_P*x_{mQ})*(x_{mQ} - x_P) - x_{m1Q}*(x_P + x_{mQ})^2)/(2*y_P*i)
  570. //
  571. // y_{mQ} = i*((1 - x_P*x_{mQ})*(x_{mQ} - x_P) - x_{m1Q}*(x_P + x_{mQ})^2)/(-2*y_P)
  572. //
  573. // since (x_Q, y_Q) = (-x_P, y_P*i). In projective coordinates this is
  574. //
  575. // Y_{mQ}' = ((Z_{mQ} - x_P*X_{mQ})*(X_{mQ} - x_P*Z_{mQ})*Z_{m1Q}
  576. // - X_{m1Q}*(X_{mQ} + x_P*Z_{mQ})^2)
  577. //
  578. // with denominator
  579. //
  580. // Z_{mQ}' = (-2*y_P*Z_{mQ}*Z_{m1Q})*Z_{mQ}.
  581. //
  582. // Setting
  583. //
  584. // X_{mQ}' = (-2*y_P*Z_{mQ}*Z_{m1Q})*X_{mQ}
  585. //
  586. // gives [m]Q = (X_{mQ}' : i*Y_{mQ}' : Z_{mQ}') with X,Y,Z all in F_p. (Here
  587. // the ' just denotes that we've added extra terms to the denominators during
  588. // the computation of Y)
  589. //
  590. // To compute the x-coordinate x(P+[m]Q) from P and [m]Q, we use the affine
  591. // addition formulas of section 2.2 of Costello-Smith. We're only interested
  592. // in the x-coordinate, giving
  593. //
  594. // X_R = Z_{mQ}*(i*Y_{mQ} - y_P*Z_{mQ})^2 - (x_P*Z_{mQ} + X_{mQ})*(X_{mQ} - x_P*Z_{mQ})^2
  595. //
  596. // Z_R = Z_{mQ}*(X_{mQ} - x_P*Z_{mQ})^2.
  597. //
  598. // Notice that although X_R \in F_{p^2}, we can split the computation into
  599. // coordinates X_R = X_{R,a} + X_{R,b}*i as
  600. //
  601. // (i*Y_{mQ} - y_P*Z_{mQ})^2 = (y_P*Z_{mQ})^2 - Y_{mQ}^2 - 2*y_P*Z_{mQ}*Y_{mQ}*i,
  602. //
  603. // giving
  604. //
  605. // X_{R,a} = Z_{mQ}*((y_P*Z_{mQ})^2 - Y_{mQ}^2)
  606. // - (x_P*Z_{mQ} + X_{mQ})*(X_{mQ} - x_P*Z_{mQ})^2
  607. //
  608. // X_{R,b} = -2*y_P*Y_{mQ}*Z_{mQ}^2
  609. //
  610. // Z_R = Z_{mQ}*(X_{mQ} - x_P*Z_{mQ})^2.
  611. //
  612. // These formulas could probably be combined with the formulas for y-recover
  613. // and computed more efficiently, but efficiency isn't the biggest concern
  614. // here, since the bulk of the cost is already in the ladder.
  615. func SecretPoint(affine_xP, affine_yP *PrimeFieldElement, scalar []uint8) ProjectivePoint {
  616. var xQ ProjectivePrimeFieldPoint
  617. xQ.FromAffine(affine_xP)
  618. xQ.X.Neg(&xQ.X)
  619. // Compute x([m]Q) = (X_{mQ} : Z_{mQ}), x([m+1]Q) = (X_{m1Q} : Z_{m1Q})
  620. var xmQ, xm1Q = ScalarMultPrimeField(&E0_aPlus2Over4, &xQ, scalar)
  621. // Now perform coordinate recovery:
  622. // [m]Q = (X_{mQ} : Y_{mQ}*i : Z_{mQ})
  623. var XmQ, YmQ, ZmQ PrimeFieldElement
  624. var t0, t1 PrimeFieldElement
  625. // Y_{mQ} = (Z_{mQ} - x_P*X_{mQ})*(X_{mQ} - x_P*Z_{mQ})*Z_{m1Q}
  626. // - X_{m1Q}*(X_{mQ} + x_P*Z_{mQ})^2
  627. t0.Mul(affine_xP, &xmQ.X) // = x_P*X_{mQ}
  628. YmQ.Sub(&xmQ.Z, &t0) // = Z_{mQ} - x_P*X_{mQ}
  629. t1.Mul(affine_xP, &xmQ.Z) // = x_P*Z_{mQ}
  630. t0.Sub(&xmQ.X, &t1) // = X_{mQ} - x_P*Z_{mQ}
  631. YmQ.Mul(&YmQ, &t0) // = (Z_{mQ} - x_P*X_{mQ})*(X_{mQ} - x_P*Z_{mQ})
  632. YmQ.Mul(&YmQ, &xm1Q.Z) // = (Z_{mQ} - x_P*X_{mQ})*(X_{mQ} - x_P*Z_{mQ})*Z_{m1Q}
  633. t1.Add(&t1, &xmQ.X).Square(&t1) // = (X_{mQ} + x_P*Z_{mQ})^2
  634. t1.Mul(&t1, &xm1Q.X) // = X_{m1Q}*(X_{mQ} + x_P*Z_{mQ})^2
  635. YmQ.Sub(&YmQ, &t1) // = Y_{mQ}
  636. // Z_{mQ} = -2*(Z_{mQ}^2 * Z_{m1Q} * y_P)
  637. t0.Mul(&xmQ.Z, &xm1Q.Z).Mul(&t0, affine_yP) // = Z_{mQ} * Z_{m1Q} * y_P
  638. t0.Neg(&t0) // = -1*(Z_{mQ} * Z_{m1Q} * y_P)
  639. t0.Add(&t0, &t0) // = -2*(Z_{mQ} * Z_{m1Q} * y_P)
  640. ZmQ.Mul(&xmQ.Z, &t0) // = -2*(Z_{mQ}^2 * Z_{m1Q} * y_P)
  641. // We added terms to the denominator Z_{mQ}, so multiply them to X_{mQ}
  642. // X_{mQ} = -2*X_{mQ}*Z_{mQ}*Z_{m1Q}*y_P
  643. XmQ.Mul(&xmQ.X, &t0)
  644. // Now compute x(P + [m]Q) = (X_Ra + i*X_Rb : Z_R)
  645. var XRa, XRb, ZR PrimeFieldElement
  646. XRb.Square(&ZmQ).Mul(&XRb, &YmQ) // = Y_{mQ} * Z_{mQ}^2
  647. XRb.Mul(&XRb, affine_yP) // = Y_{mQ} * y_P * Z_{mQ}^2
  648. XRb.Add(&XRb, &XRb) // = 2 * Y_{mQ} * y_P * Z_{mQ}^2
  649. XRb.Neg(&XRb) // = -2 * Y_{mQ} * y_P * Z_{mQ}^2
  650. t0.Mul(affine_yP, &ZmQ).Square(&t0) // = (y_P * Z_{mQ})^2
  651. t1.Square(&YmQ) // = Y_{mQ}^2
  652. XRa.Sub(&t0, &t1) // = (y_P * Z_{mQ})^2 - Y_{mQ}^2
  653. XRa.Mul(&XRa, &ZmQ) // = Z_{mQ}*((y_P * Z_{mQ})^2 - Y_{mQ}^2)
  654. t0.Mul(affine_xP, &ZmQ) // = x_P * Z_{mQ}
  655. t1.Add(&XmQ, &t0) // = X_{mQ} + x_P*Z_{mQ}
  656. t0.Sub(&XmQ, &t0) // = X_{mQ} - x_P*Z_{mQ}
  657. t0.Square(&t0) // = (X_{mQ} - x_P*Z_{mQ})^2
  658. t1.Mul(&t1, &t0) // = (X_{mQ} + x_P*Z_{mQ})*(X_{mQ} - x_P*Z_{mQ})^2
  659. XRa.Sub(&XRa, &t1) // = Z_{mQ}*((y_P*Z_{mQ})^2 - Y_{mQ}^2) - (X_{mQ} + x_P*Z_{mQ})*(X_{mQ} - x_P*Z_{mQ})^2
  660. ZR.Mul(&ZmQ, &t0) // = Z_{mQ}*(X_{mQ} - x_P*Z_{mQ})^2
  661. var xR ProjectivePoint
  662. xR.X.A = XRa.A
  663. xR.X.B = XRb.A
  664. xR.Z.A = ZR.A
  665. return xR
  666. }