Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

4 anos atrás
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /********************************************************************************************
  2. * Supersingular Isogeny Key Encapsulation Library
  3. *
  4. * Abstract: elliptic curve and isogeny functions
  5. *********************************************************************************************/
  6. #include "P751_internal.h"
  7. #include <stdio.h>
  8. void xDBL(const point_proj_t P, point_proj_t Q, const f2elm_t A24plus, const f2elm_t C24)
  9. { // Doubling of a Montgomery point in projective coordinates (X:Z).
  10. // Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constants A+2C and 4C.
  11. // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2).
  12. f2elm_t t0, t1;
  13. fp2sub(P->X, P->Z, t0); // t0 = X1-Z1
  14. fp2add(P->X, P->Z, t1); // t1 = X1+Z1
  15. fp2sqr_mont(t0, t0); // t0 = (X1-Z1)^2
  16. fp2sqr_mont(t1, t1); // t1 = (X1+Z1)^2
  17. fp2mul_mont(C24, t0, Q->Z); // Z2 = C24*(X1-Z1)^2
  18. fp2mul_mont(t1, Q->Z, Q->X); // X2 = C24*(X1-Z1)^2*(X1+Z1)^2
  19. fp2sub(t1, t0, t1); // t1 = (X1+Z1)^2-(X1-Z1)^2
  20. fp2mul_mont(A24plus, t1, t0); // t0 = A24plus*[(X1+Z1)^2-(X1-Z1)^2]
  21. fp2add(Q->Z, t0, Q->Z); // Z2 = A24plus*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2
  22. fp2mul_mont(Q->Z, t1, Q->Z); // Z2 = [A24plus*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2]*[(X1+Z1)^2-(X1-Z1)^2]
  23. }
  24. void xDBLe(const point_proj_t P, point_proj_t Q, const f2elm_t A24plus, const f2elm_t C24, const int e)
  25. { // Computes [2^e](X:Z) on Montgomery curve with projective constant via e repeated doublings.
  26. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A+2C and 4C.
  27. // Output: projective Montgomery x-coordinates Q <- (2^e)*P.
  28. int i;
  29. copy_words((digit_t *)P, (digit_t *)Q, 2 * 2 * NWORDS_FIELD);
  30. for (i = 0; i < e; i++)
  31. {
  32. xDBL(Q, Q, A24plus, C24);
  33. }
  34. }
  35. void get_4_isog(const point_proj_t P, f2elm_t A24plus, f2elm_t C24, f2elm_t *coeff)
  36. { // Computes the corresponding 4-isogeny of a projective Montgomery point (X4:Z4) of order 4.
  37. // Input: projective point of order four P = (X4:Z4).
  38. // Output: the 4-isogenous Montgomery curve with projective coefficients A+2C/4C and the 3 coefficients
  39. // that are used to evaluate the isogeny at a point in eval_4_isog().
  40. fp2sub(P->X, P->Z, coeff[1]); // coeff[1] = X4-Z4
  41. fp2add(P->X, P->Z, coeff[2]); // coeff[2] = X4+Z4
  42. fp2sqr_mont(P->Z, coeff[0]); // coeff[0] = Z4^2
  43. fp2add(coeff[0], coeff[0], coeff[0]); // coeff[0] = 2*Z4^2
  44. fp2sqr_mont(coeff[0], C24); // C24 = 4*Z4^4
  45. fp2add(coeff[0], coeff[0], coeff[0]); // coeff[0] = 4*Z4^2
  46. fp2sqr_mont(P->X, A24plus); // A24plus = X4^2
  47. fp2add(A24plus, A24plus, A24plus); // A24plus = 2*X4^2
  48. fp2sqr_mont(A24plus, A24plus); // A24plus = 4*X4^4
  49. }
  50. void eval_4_isog(point_proj_t P, f2elm_t *coeff)
  51. { // Evaluates the isogeny at the point (X:Z) in the domain of the isogeny, given a 4-isogeny phi defined
  52. // by the 3 coefficients in coeff (computed in the function get_4_isog()).
  53. // Inputs: the coefficients defining the isogeny, and the projective point P = (X:Z).
  54. // Output: the projective point P = phi(P) = (X:Z) in the codomain.
  55. f2elm_t t0, t1;
  56. fp2add(P->X, P->Z, t0); // t0 = X+Z
  57. fp2sub(P->X, P->Z, t1); // t1 = X-Z
  58. fp2mul_mont(t0, coeff[1], P->X); // X = (X+Z)*coeff[1]
  59. fp2mul_mont(t1, coeff[2], P->Z); // Z = (X-Z)*coeff[2]
  60. fp2mul_mont(t0, t1, t0); // t0 = (X+Z)*(X-Z)
  61. fp2mul_mont(t0, coeff[0], t0); // t0 = coeff[0]*(X+Z)*(X-Z)
  62. fp2add(P->X, P->Z, t1); // t1 = (X-Z)*coeff[2] + (X+Z)*coeff[1]
  63. fp2sub(P->X, P->Z, P->Z); // Z = (X-Z)*coeff[2] - (X+Z)*coeff[1]
  64. fp2sqr_mont(t1, t1); // t1 = [(X-Z)*coeff[2] + (X+Z)*coeff[1]]^2
  65. fp2sqr_mont(P->Z, P->Z); // Z = [(X-Z)*coeff[2] - (X+Z)*coeff[1]]^2
  66. fp2add(t1, t0, P->X); // X = coeff[0]*(X+Z)*(X-Z) + [(X-Z)*coeff[2] + (X+Z)*coeff[1]]^2
  67. fp2sub(P->Z, t0, t0); // t0 = [(X-Z)*coeff[2] - (X+Z)*coeff[1]]^2 - coeff[0]*(X+Z)*(X-Z)
  68. fp2mul_mont(P->X, t1, P->X); // Xfinal
  69. fp2mul_mont(P->Z, t0, P->Z); // Zfinal
  70. }
  71. void xTPL(const point_proj_t P, point_proj_t Q, const f2elm_t A24minus, const f2elm_t A24plus)
  72. { // Tripling of a Montgomery point in projective coordinates (X:Z).
  73. // Input: projective Montgomery x-coordinates P = (X:Z), where x=X/Z and Montgomery curve constants A24plus = A+2C and A24minus = A-2C.
  74. // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3).
  75. f2elm_t t0, t1, t2, t3, t4, t5, t6;
  76. fp2sub(P->X, P->Z, t0); // t0 = X-Z
  77. fp2sqr_mont(t0, t2); // t2 = (X-Z)^2
  78. fp2add(P->X, P->Z, t1); // t1 = X+Z
  79. fp2sqr_mont(t1, t3); // t3 = (X+Z)^2
  80. fp2add(t0, t1, t4); // t4 = 2*X
  81. fp2sub(t1, t0, t0); // t0 = 2*Z
  82. fp2sqr_mont(t4, t1); // t1 = 4*X^2
  83. fp2sub(t1, t3, t1); // t1 = 4*X^2 - (X+Z)^2
  84. fp2sub(t1, t2, t1); // t1 = 4*X^2 - (X+Z)^2 - (X-Z)^2
  85. fp2mul_mont(t3, A24plus, t5); // t5 = A24plus*(X+Z)^2
  86. fp2mul_mont(t3, t5, t3); // t3 = A24plus*(X+Z)^3
  87. fp2mul_mont(A24minus, t2, t6); // t6 = A24minus*(X-Z)^2
  88. fp2mul_mont(t2, t6, t2); // t2 = A24minus*(X-Z)^3
  89. fp2sub(t2, t3, t3); // t3 = A24minus*(X-Z)^3 - coeff*(X+Z)^3
  90. fp2sub(t5, t6, t2); // t2 = A24plus*(X+Z)^2 - A24minus*(X-Z)^2
  91. fp2mul_mont(t1, t2, t1); // t1 = [4*X^2 - (X+Z)^2 - (X-Z)^2]*[A24plus*(X+Z)^2 - A24minus*(X-Z)^2]
  92. fp2add(t3, t1, t2); // t2 = [4*X^2 - (X+Z)^2 - (X-Z)^2]*[A24plus*(X+Z)^2 - A24minus*(X-Z)^2] + A24minus*(X-Z)^3 - coeff*(X+Z)^3
  93. fp2sqr_mont(t2, t2); // t2 = t2^2
  94. fp2mul_mont(t4, t2, Q->X); // X3 = 2*X*t2
  95. fp2sub(t3, t1, t1); // t1 = A24minus*(X-Z)^3 - A24plus*(X+Z)^3 - [4*X^2 - (X+Z)^2 - (X-Z)^2]*[A24plus*(X+Z)^2 - A24minus*(X-Z)^2]
  96. fp2sqr_mont(t1, t1); // t1 = t1^2
  97. fp2mul_mont(t0, t1, Q->Z); // Z3 = 2*Z*t1
  98. }
  99. void xTPLe(const point_proj_t P, point_proj_t Q, const f2elm_t A24minus, const f2elm_t A24plus, const int e)
  100. { // Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings.
  101. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A24plus = A+2C and A24minus = A-2C.
  102. // Output: projective Montgomery x-coordinates Q <- (3^e)*P.
  103. int i;
  104. copy_words((digit_t *)P, (digit_t *)Q, 2 * 2 * NWORDS_FIELD);
  105. for (i = 0; i < e; i++)
  106. {
  107. xTPL(Q, Q, A24minus, A24plus);
  108. }
  109. }
  110. void get_3_isog(const point_proj_t P, f2elm_t A24minus, f2elm_t A24plus, f2elm_t *coeff)
  111. { // Computes the corresponding 3-isogeny of a projective Montgomery point (X3:Z3) of order 3.
  112. // Input: projective point of order three P = (X3:Z3).
  113. // Output: the 3-isogenous Montgomery curve with projective coefficient A/C.
  114. f2elm_t t0, t1, t2, t3, t4;
  115. fp2sub(P->X, P->Z, coeff[0]); // coeff0 = X-Z
  116. fp2sqr_mont(coeff[0], t0); // t0 = (X-Z)^2
  117. fp2add(P->X, P->Z, coeff[1]); // coeff1 = X+Z
  118. fp2sqr_mont(coeff[1], t1); // t1 = (X+Z)^2
  119. fp2add(t0, t1, t2); // t2 = (X+Z)^2 + (X-Z)^2
  120. fp2add(coeff[0], coeff[1], t3); // t3 = 2*X
  121. fp2sqr_mont(t3, t3); // t3 = 4*X^2
  122. fp2sub(t3, t2, t3); // t3 = 4*X^2 - (X+Z)^2 - (X-Z)^2
  123. fp2add(t1, t3, t2); // t2 = 4*X^2 - (X-Z)^2
  124. fp2add(t3, t0, t3); // t3 = 4*X^2 - (X+Z)^2
  125. fp2add(t0, t3, t4); // t4 = 4*X^2 - (X+Z)^2 + (X-Z)^2
  126. fp2add(t4, t4, t4); // t4 = 2(4*X^2 - (X+Z)^2 + (X-Z)^2)
  127. fp2add(t1, t4, t4); // t4 = 8*X^2 - (X+Z)^2 + 2*(X-Z)^2
  128. fp2mul_mont(t2, t4, A24minus); // A24minus = [4*X^2 - (X-Z)^2]*[8*X^2 - (X+Z)^2 + 2*(X-Z)^2]
  129. fp2add(t1, t2, t4); // t4 = 4*X^2 + (X+Z)^2 - (X-Z)^2
  130. fp2add(t4, t4, t4); // t4 = 2(4*X^2 + (X+Z)^2 - (X-Z)^2)
  131. fp2add(t0, t4, t4); // t4 = 8*X^2 + 2*(X+Z)^2 - (X-Z)^2
  132. fp2mul_mont(t3, t4, t4); // t4 = [4*X^2 - (X+Z)^2]*[8*X^2 + 2*(X+Z)^2 - (X-Z)^2]
  133. fp2sub(t4, A24minus, t0); // t0 = [4*X^2 - (X+Z)^2]*[8*X^2 + 2*(X+Z)^2 - (X-Z)^2] - [4*X^2 - (X-Z)^2]*[8*X^2 - (X+Z)^2 + 2*(X-Z)^2]
  134. fp2add(A24minus, t0, A24plus); // A24plus = 8*X^2 - (X+Z)^2 + 2*(X-Z)^2
  135. }
  136. void eval_3_isog(point_proj_t Q, const f2elm_t *coeff)
  137. { // Computes the 3-isogeny R=phi(X:Z), given projective point (X3:Z3) of order 3 on a Montgomery curve and
  138. // a point P with 2 coefficients in coeff (computed in the function get_3_isog()).
  139. // Inputs: projective points P = (X3:Z3) and Q = (X:Z).
  140. // Output: the projective point Q <- phi(Q) = (X3:Z3).
  141. f2elm_t t0, t1, t2;
  142. fp2add(Q->X, Q->Z, t0); // t0 = X+Z
  143. fp2sub(Q->X, Q->Z, t1); // t1 = X-Z
  144. fp2mul_mont(t0, coeff[0], t0); // t0 = coeff0*(X+Z)
  145. fp2mul_mont(t1, coeff[1], t1); // t1 = coeff1*(X-Z)
  146. fp2add(t0, t1, t2); // t2 = coeff0*(X-Z) + coeff1*(X+Z)
  147. fp2sub(t1, t0, t0); // t0 = coeff0*(X-Z) - coeff1*(X+Z)
  148. fp2sqr_mont(t2, t2); // t2 = [coeff0*(X-Z) + coeff1*(X+Z)]^2
  149. fp2sqr_mont(t0, t0); // t1 = [coeff0*(X-Z) - coeff1*(X+Z)]^2
  150. fp2mul_mont(Q->X, t2, Q->X); // X3final = X*[coeff0*(X-Z) + coeff1*(X+Z)]^2
  151. fp2mul_mont(Q->Z, t0, Q->Z); // Z3final = Z*[coeff0*(X-Z) - coeff1*(X+Z)]^2
  152. }
  153. void inv_3_way(f2elm_t z1, f2elm_t z2, f2elm_t z3)
  154. { // 3-way simultaneous inversion
  155. // Input: z1,z2,z3
  156. // Output: 1/z1,1/z2,1/z3 (override inputs).
  157. f2elm_t t0, t1, t2, t3;
  158. fp2mul_mont(z1, z2, t0); // t0 = z1*z2
  159. fp2mul_mont(z3, t0, t1); // t1 = z1*z2*z3
  160. fp2inv_mont(t1); // t1 = 1/(z1*z2*z3)
  161. fp2mul_mont(z3, t1, t2); // t2 = 1/(z1*z2)
  162. fp2mul_mont(t2, z2, t3); // t3 = 1/z1
  163. fp2mul_mont(t2, z1, z2); // z2 = 1/z2
  164. fp2mul_mont(t0, t1, z3); // z3 = 1/z3
  165. fp2copy(t3, z1); // z1 = 1/z1
  166. }
  167. void get_A(const f2elm_t xP, const f2elm_t xQ, const f2elm_t xR, f2elm_t A)
  168. { // Given the x-coordinates of P, Q, and R, returns the value A corresponding to the Montgomery curve E_A: y^2=x^3+A*x^2+x such that R=Q-P on E_A.
  169. // Input: the x-coordinates xP, xQ, and xR of the points P, Q and R.
  170. // Output: the coefficient A corresponding to the curve E_A: y^2=x^3+A*x^2+x.
  171. f2elm_t t0, t1, one = {0};
  172. fpcopy((digit_t *)&Montgomery_one, one[0]);
  173. fp2add(xP, xQ, t1); // t1 = xP+xQ
  174. fp2mul_mont(xP, xQ, t0); // t0 = xP*xQ
  175. fp2mul_mont(xR, t1, A); // A = xR*t1
  176. fp2add(t0, A, A); // A = A+t0
  177. fp2mul_mont(t0, xR, t0); // t0 = t0*xR
  178. fp2sub(A, one, A); // A = A-1
  179. fp2add(t0, t0, t0); // t0 = t0+t0
  180. fp2add(t1, xR, t1); // t1 = t1+xR
  181. fp2add(t0, t0, t0); // t0 = t0+t0
  182. fp2sqr_mont(A, A); // A = A^2
  183. fp2inv_mont(t0); // t0 = 1/t0
  184. fp2mul_mont(A, t0, A); // A = A*t0
  185. fp2sub(A, t1, A); // Afinal = A-t1
  186. }
  187. void j_inv(const f2elm_t A, const f2elm_t C, f2elm_t jinv)
  188. { // Computes the j-invariant of a Montgomery curve with projective constant.
  189. // Input: A,C in GF(p^2).
  190. // Output: j=256*(A^2-3*C^2)^3/(C^4*(A^2-4*C^2)), which is the j-invariant of the Montgomery curve B*y^2=x^3+(A/C)*x^2+x or (equivalently) j-invariant of B'*y^2=C*x^3+A*x^2+C*x.
  191. f2elm_t t0, t1;
  192. fp2sqr_mont(A, jinv); // jinv = A^2
  193. fp2sqr_mont(C, t1); // t1 = C^2
  194. fp2add(t1, t1, t0); // t0 = t1+t1
  195. fp2sub(jinv, t0, t0); // t0 = jinv-t0
  196. fp2sub(t0, t1, t0); // t0 = t0-t1
  197. fp2sub(t0, t1, jinv); // jinv = t0-t1
  198. fp2sqr_mont(t1, t1); // t1 = t1^2
  199. fp2mul_mont(jinv, t1, jinv); // jinv = jinv*t1
  200. fp2add(t0, t0, t0); // t0 = t0+t0
  201. fp2add(t0, t0, t0); // t0 = t0+t0
  202. fp2sqr_mont(t0, t1); // t1 = t0^2
  203. fp2mul_mont(t0, t1, t0); // t0 = t0*t1
  204. fp2add(t0, t0, t0); // t0 = t0+t0
  205. fp2add(t0, t0, t0); // t0 = t0+t0
  206. fp2inv_mont(jinv); // jinv = 1/jinv
  207. fp2mul_mont(jinv, t0, jinv); // jinv = t0*jinv
  208. }
  209. void xDBLADD(point_proj_t P, point_proj_t Q, const f2elm_t xPQ, const f2elm_t A24)
  210. { // Simultaneous doubling and differential addition.
  211. // Input: projective Montgomery points P=(XP:ZP) and Q=(XQ:ZQ) such that xP=XP/ZP and xQ=XQ/ZQ, affine difference xPQ=x(P-Q) and Montgomery curve constant A24=(A+2)/4.
  212. // Output: projective Montgomery points P <- 2*P = (X2P:Z2P) such that x(2P)=X2P/Z2P, and Q <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP.
  213. f2elm_t t0, t1, t2;
  214. fp2add(P->X, P->Z, t0); // t0 = XP+ZP
  215. fp2sub(P->X, P->Z, t1); // t1 = XP-ZP
  216. fp2sqr_mont(t0, P->X); // XP = (XP+ZP)^2
  217. fp2sub(Q->X, Q->Z, t2); // t2 = XQ-ZQ
  218. fp2correction(t2);
  219. fp2add(Q->X, Q->Z, Q->X); // XQ = XQ+ZQ
  220. fp2mul_mont(t2, t0, t0); // t0 = (XP+ZP)*(XQ-ZQ)
  221. fp2sqr_mont(t1, P->Z); // ZP = (XP-ZP)^2
  222. fp2mul_mont(Q->X, t1, t1); // t1 = (XP-ZP)*(XQ+ZQ)
  223. fp2sub(P->X, P->Z, t2); // t2 = (XP+ZP)^2-(XP-ZP)^2
  224. fp2mul_mont(P->X, P->Z, P->X); // XP = (XP+ZP)^2*(XP-ZP)^2
  225. fp2mul_mont(t2, A24, Q->X); // XQ = A24*[(XP+ZP)^2-(XP-ZP)^2]
  226. fp2sub(t0, t1, Q->Z); // ZQ = (XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)
  227. fp2add(Q->X, P->Z, P->Z); // ZP = A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2
  228. fp2add(t0, t1, Q->X); // XQ = (XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)
  229. fp2mul_mont(P->Z, t2, P->Z); // ZP = [A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2]*[(XP+ZP)^2-(XP-ZP)^2]
  230. fp2sqr_mont(Q->Z, Q->Z); // ZQ = [(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
  231. fp2sqr_mont(Q->X, Q->X); // XQ = [(XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)]^2
  232. fp2mul_mont(Q->Z, xPQ, Q->Z); // ZQ = xPQ*[(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
  233. }
  234. static void swap_points(point_proj_t P, point_proj_t Q, const digit_t option)
  235. { // Swap points.
  236. // If option = 0 then P <- P and Q <- Q, else if option = 0xFF...FF then P <- Q and Q <- P
  237. digit_t temp;
  238. unsigned int i;
  239. for (i = 0; i < NWORDS_FIELD; i++)
  240. {
  241. temp = option & (P->X[0][i] ^ Q->X[0][i]);
  242. P->X[0][i] = temp ^ P->X[0][i];
  243. Q->X[0][i] = temp ^ Q->X[0][i];
  244. temp = option & (P->Z[0][i] ^ Q->Z[0][i]);
  245. P->Z[0][i] = temp ^ P->Z[0][i];
  246. Q->Z[0][i] = temp ^ Q->Z[0][i];
  247. temp = option & (P->X[1][i] ^ Q->X[1][i]);
  248. P->X[1][i] = temp ^ P->X[1][i];
  249. Q->X[1][i] = temp ^ Q->X[1][i];
  250. temp = option & (P->Z[1][i] ^ Q->Z[1][i]);
  251. P->Z[1][i] = temp ^ P->Z[1][i];
  252. Q->Z[1][i] = temp ^ Q->Z[1][i];
  253. }
  254. }
  255. static void LADDER3PT(const f2elm_t xP, const f2elm_t xQ, const f2elm_t xPQ, const digit_t *m, const unsigned int AliceOrBob, point_proj_t R, const f2elm_t A)
  256. {
  257. point_proj_t R0 = {0}, R2 = {0};
  258. f2elm_t A24 = {0};
  259. digit_t mask;
  260. int i, nbits, bit, swap, prevbit = 0;
  261. if (AliceOrBob == ALICE)
  262. {
  263. nbits = OALICE_BITS;
  264. }
  265. else
  266. {
  267. nbits = OBOB_BITS;
  268. }
  269. // Initializing constant
  270. fpcopy((digit_t *)&Montgomery_one, A24[0]);
  271. fp2add(A24, A24, A24);
  272. fp2add(A, A24, A24);
  273. fp2div2(A24, A24);
  274. fp2div2(A24, A24); // A24 = (A+2)/4
  275. // Initializing points
  276. fp2copy(xQ, R0->X);
  277. fpcopy((digit_t *)&Montgomery_one, (digit_t *)R0->Z);
  278. fp2copy(xPQ, R2->X);
  279. fpcopy((digit_t *)&Montgomery_one, (digit_t *)R2->Z);
  280. fp2copy(xP, R->X);
  281. fpcopy((digit_t *)&Montgomery_one, (digit_t *)R->Z);
  282. fpzero((digit_t *)(R->Z)[1]);
  283. // Main loop
  284. for (i = 0; i < nbits; i++)
  285. {
  286. bit = (m[i >> LOG2RADIX] >> (i & (RADIX - 1))) & 1;
  287. swap = bit ^ prevbit;
  288. prevbit = bit;
  289. mask = 0 - (digit_t)swap;
  290. swap_points(R, R2, mask);
  291. xDBLADD(R0, R2, R->X, A24);
  292. fp2mul_mont(R2->X, R->Z, R2->X);
  293. }
  294. }