Não pode escolher mais do que 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.
 
 
 

818 linhas
33 KiB

  1. #include <stdint.h>
  2. #include <string.h>
  3. #define NWORDS_FIELD 15
  4. #define MAX_INT_POINTS_ALICE 8
  5. #define MAX_INT_POINTS_BOB 10
  6. #define ALICE 0
  7. #define BOB 1
  8. #define OALICE_BITS 372
  9. #define OBOB_BITS 379
  10. #define MAX_Alice 186
  11. #define MAX_Bob 239
  12. #define NBITS_FIELD 751
  13. #define MAXBITS_FIELD 768
  14. #define FP2_ENCODED_BYTES 2 * ((NBITS_FIELD + 7) / 8)
  15. typedef uint64_t felm_t[NWORDS_FIELD];
  16. typedef felm_t f2elm_t[2];
  17. typedef struct
  18. {
  19. f2elm_t X;
  20. f2elm_t Z;
  21. } point_proj; // Point representation in projective XZ Montgomery coordinates.
  22. typedef point_proj point_proj_t[1];
  23. const uint64_t A_gen_ifma[5 * NWORDS_FIELD] = {
  24. 0x000ceab50ad8bc0d, 0x0005e457b1c2fc08, 0x000cd6e1d7d710f5, 0x000ae8738d92953d, 0x000a7ebee8a3418a, 0x0008345f03f46fba, 0x0007cfe2616c9a28, 0x000b4be50c8b9e16, 0x00039b6799643b2e, 0x000597a7ff9d56d5, 0x00021d410d97fe0a, 0x000a4a92a8f2ad52, 0x00054508e42abde4, 0x000ebf7d0178c137, 0x00000000004a0a75,
  25. 0x000d21582e4118ad, 0x0005df400ae6cc41, 0x000aec407c2ecb7c, 0x000de8e34b521432, 0x000761e2ab085167, 0x000bcaa6094b3c50, 0x000df9ddd71032cf, 0x00057d905265605f, 0x000f7dba2681f9d7, 0x0009e9732def416c, 0x0006f77956ce00ce, 0x000576fb3094772b, 0x000b2d166e2a949f, 0x0002f665c6588ea2, 0x0000000000337a25,
  26. 0x00026279148626cd, 0x0006b5baead56fe5, 0x000ab911fad60dc9, 0x000401e137d0bf07, 0x0004d3e925216196, 0x0005e4cd09a33740, 0x00069e4af733c538, 0x000d1169f6821367, 0x000c64ecfc721111, 0x000ba56507cd0dc7, 0x000995e4ae04dfad, 0x0007b992deeceab8, 0x0007bccd256aff1e, 0x000207f5fde1824c, 0x0000000000345cc7,
  27. 0x00041dffd19b3e7f, 0x000b48c18e0bb844, 0x000380584b4dea99, 0x0000692de648ad31, 0x000d72761b6dfaee, 0x0005c672c3058de6, 0x000cba26fdc22397, 0x000e15f9133d4bc3, 0x000d5ae123793466, 0x000bb494276e321d, 0x000c9c99fb74cd99, 0x0005da6e4fd03f75, 0x000b95feb24d0937, 0x000e6a307e03cd17, 0x000000000044ad2e,
  28. 0x0007f1ec71be8c36, 0x00053859b1ed78c1, 0x000529ff824d6df7, 0x000633a10839b2a8, 0x00003e9e25fdea79, 0x000a8054df1762fc, 0x000034c6467c4708, 0x000acb63530b60ec, 0x0000c6fc8c19bf71, 0x0005aca92467c3cb, 0x000d42050ba154a2, 0x000b4d5baa4ab074, 0x00044ba4962ac622, 0x0002bbf250aa70e6, 0x0000000000457f51};
  29. const uint64_t B_gen_ifma[5 * NWORDS_FIELD] = {
  30. 0x0001ef867ab0bcb9, 0x0009a45c76cfb6d7, 0x0001f034a5fdd76e, 0x000038b1ee69194b, 0x000e7b18a7761f3f, 0x000a486a52c84cf6, 0x0005aa75466fcf01, 0x00044164f797233f, 0x000331aeaec77db1, 0x0005185f83d9a22f, 0x000e2d4dc94f5b17, 0x0000f7b3858b15a4, 0x000635ac44515c99, 0x000a5b14eaf4ee2e, 0x000000000048e907,
  31. 0x0004e7c075cc3a24, 0x00004aa430a49203, 0x00094c8677baf00b, 0x000b3aae0c9a755c, 0x000c4b064e9ebb08, 0x000dd04e826c661d, 0x00061f01b223684e, 0x000d43bc8a6360b6, 0x00008c633a79ab30, 0x0008e0092fbd6f39, 0x0002b9ba797337f8, 0x000fcb3252ddaf84, 0x000467ded2ca9dce, 0x0006117350e479f4, 0x00000000001ae9d1,
  32. 0x000ed7b96c4ab279, 0x000178486ef1a8c9, 0x000c2f4299429da5, 0x000aef4926f20cd5, 0x0003b2e2858b4716, 0x000bcc3cac3eeb68, 0x0003a600460dda2f, 0x00050e6650a24c9f, 0x0004cb60c61775f8, 0x00082b196ebc78b3, 0x000cc7fec8cce966, 0x000d9b778d801d65, 0x0005324630f74af3, 0x0009018193e7592e, 0x00000000003aef05,
  33. 0x00033769d0f314ef, 0x000e2659d11c0d67, 0x000d133f084c3086, 0x0005e23d5da27bcb, 0x0008ec9a8d586402, 0x000c781b3b645bf3, 0x000c9fb03ee6426d, 0x000ddc7bb40b83e3, 0x000bb7b4ab585e3a, 0x0006c2672e53eeaf, 0x0000397a1e62b655, 0x0004ac383daab923, 0x0008eb1ecdd2f39e, 0x000f1516da469247, 0x00000000003693cf,
  34. 0x0007d8f72bd956dc, 0x000e9934884ae37e, 0x0003c3edd2d504b3, 0x00005d14e7fa1ecb, 0x0007610ceb75d635, 0x000b4cac446b1112, 0x000c1f70caf255b4, 0x00057d3e324d2f36, 0x0006181c3bb1a700, 0x000db2f2916ccc40, 0x00021ee51d1c92f1, 0x000c07c22031c32a, 0x000e4310e5103473, 0x00069c1148de9ef5, 0x00000000004d1227};
  35. const uint64_t One[NWORDS_FIELD] = {
  36. 0x00000000249ad67c, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0001f9800c542c00, 0x000b326488fe3b2a, 0x000e6176236db777, 0x000dd6e970232b83, 0x000d4d762277573f, 0x00054cd16c015f35, 0x0009fc72438c4fc7, 0x00000000001bf8f6};
  37. const uint64_t Two[NWORDS_FIELD] = {
  38. 0x000000004935acf8, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0003f30018a85800, 0x000664c911fc7654, 0x000cc2ec46db6eef, 0x000badd2e0465707, 0x000a9aec44eeae7f, 0x000a99a2d802be6b, 0x0003f8e487189f8e, 0x000000000037f1ed};
  39. // Fixed parameters for isogeny tree computation
  40. extern const unsigned int strat_Alice[MAX_Alice - 1];
  41. extern const unsigned int strat_Bob[MAX_Bob - 1];
  42. void norm2red(uint64_t *res, const uint64_t *a);
  43. void red2norm(uint64_t out[12], const uint64_t in[15])
  44. {
  45. out[0] = in[0] ^ in[1] << 52;
  46. out[1] = in[1] >> 12 ^ in[2] << 40;
  47. out[2] = in[2] >> 24 ^ in[3] << 28;
  48. out[3] = in[3] >> 36 ^ in[4] << 16;
  49. out[4] = in[4] >> 48 ^ in[5] << 4 ^ in[6] << 56;
  50. out[5] = in[6] >> 8 ^ in[7] << 44;
  51. out[6] = in[7] >> 20 ^ in[8] << 32;
  52. out[7] = in[8] >> 32 ^ in[9] << 20;
  53. out[8] = in[9] >> 44 ^ in[10] << 8 ^ in[11] << 60;
  54. out[9] = in[11] >> 4 ^ in[12] << 48;
  55. out[10] = in[12] >> 16 ^ in[13] << 36;
  56. out[11] = in[13] >> 28 ^ in[14] << 24;
  57. }
  58. static void init_basis(const uint64_t *gen, f2elm_t XP, f2elm_t XQ, f2elm_t XR)
  59. { // Initialization of basis points
  60. memcpy(XP[0], &gen[0 * NWORDS_FIELD], sizeof(felm_t));
  61. memcpy(XP[1], &gen[1 * NWORDS_FIELD], sizeof(felm_t));
  62. memcpy(XQ[0], &gen[2 * NWORDS_FIELD], sizeof(felm_t));
  63. memset(XQ[1], 0, sizeof(felm_t));
  64. memcpy(XR[0], &gen[3 * NWORDS_FIELD], sizeof(felm_t));
  65. memcpy(XR[1], &gen[4 * NWORDS_FIELD], sizeof(felm_t));
  66. }
  67. void fp2_mul_ifma(f2elm_t res, const f2elm_t a, const f2elm_t b);
  68. void fp2_mul_ifma_x2(f2elm_t res1, const f2elm_t a1, const f2elm_t b1, f2elm_t res2, const f2elm_t a2, const f2elm_t b2);
  69. void fp2_sqr_ifma(f2elm_t res, const f2elm_t a);
  70. void fp2_add(f2elm_t res, const f2elm_t a, const f2elm_t b);
  71. void fp2_sub(f2elm_t res, const f2elm_t a, const f2elm_t b);
  72. void fp2_swap(point_proj_t a, point_proj_t b, int swap);
  73. void fp_mul_ifma(felm_t res, felm_t a, felm_t b);
  74. void fp_add(felm_t res, const felm_t a, const felm_t b);
  75. void fp_sub(felm_t res, const felm_t a, const felm_t b);
  76. void to_mont_ifma(felm_t rp, const felm_t ap);
  77. void from_mont_ifma(felm_t rp, const felm_t ap);
  78. void red2norm(uint64_t out[12], const felm_t in);
  79. #define fp2mul_mont(a, b, r) fp2_mul_ifma(r, a, b)
  80. #define fp2sqr_mont(a, r) fp2_sqr_ifma(r, a)
  81. #define fp2add(a, b, r) fp2_add(r, a, b)
  82. #define fp2sub(a, b, r) fp2_sub(r, a, b)
  83. #define fp2correction
  84. #define fpsqr_mont(a, r) fp_mul_ifma(r, a, a)
  85. #define fpmul_mont(a, b, r) fp_mul_ifma(r, a, b)
  86. #define fpadd(a, b, r) fp_add(r, a, b)
  87. #define fpsub(a, b, r) fp_sub(r, a, b)
  88. void fpinv_chain_mont(felm_t a)
  89. { // Chain to compute a^(p-3)/4 using Montgomery arithmetic.
  90. unsigned int i, j;
  91. felm_t t[27], tt;
  92. // Precomputed table
  93. fpsqr_mont(a, tt);
  94. fpmul_mont(a, tt, t[0]);
  95. fpmul_mont(t[0], tt, t[1]);
  96. fpmul_mont(t[1], tt, t[2]);
  97. fpmul_mont(t[2], tt, t[3]);
  98. fpmul_mont(t[3], tt, t[3]);
  99. for (i = 3; i <= 8; i++)
  100. fpmul_mont(t[i], tt, t[i + 1]);
  101. fpmul_mont(t[9], tt, t[9]);
  102. for (i = 9; i <= 20; i++)
  103. fpmul_mont(t[i], tt, t[i + 1]);
  104. fpmul_mont(t[21], tt, t[21]);
  105. for (i = 21; i <= 24; i++)
  106. fpmul_mont(t[i], tt, t[i + 1]);
  107. fpmul_mont(t[25], tt, t[25]);
  108. fpmul_mont(t[25], tt, t[26]);
  109. memcpy(tt, a, sizeof(felm_t));
  110. for (i = 0; i < 6; i++)
  111. fpsqr_mont(tt, tt);
  112. fpmul_mont(t[20], tt, tt);
  113. for (i = 0; i < 6; i++)
  114. fpsqr_mont(tt, tt);
  115. fpmul_mont(t[24], tt, tt);
  116. for (i = 0; i < 6; i++)
  117. fpsqr_mont(tt, tt);
  118. fpmul_mont(t[11], tt, tt);
  119. for (i = 0; i < 6; i++)
  120. fpsqr_mont(tt, tt);
  121. fpmul_mont(t[8], tt, tt);
  122. for (i = 0; i < 8; i++)
  123. fpsqr_mont(tt, tt);
  124. fpmul_mont(t[2], tt, tt);
  125. for (i = 0; i < 6; i++)
  126. fpsqr_mont(tt, tt);
  127. fpmul_mont(t[23], tt, tt);
  128. for (i = 0; i < 6; i++)
  129. fpsqr_mont(tt, tt);
  130. fpmul_mont(t[2], tt, tt);
  131. for (i = 0; i < 9; i++)
  132. fpsqr_mont(tt, tt);
  133. fpmul_mont(t[2], tt, tt);
  134. for (i = 0; i < 10; i++)
  135. fpsqr_mont(tt, tt);
  136. fpmul_mont(t[15], tt, tt);
  137. for (i = 0; i < 8; i++)
  138. fpsqr_mont(tt, tt);
  139. fpmul_mont(t[13], tt, tt);
  140. for (i = 0; i < 8; i++)
  141. fpsqr_mont(tt, tt);
  142. fpmul_mont(t[26], tt, tt);
  143. for (i = 0; i < 8; i++)
  144. fpsqr_mont(tt, tt);
  145. fpmul_mont(t[20], tt, tt);
  146. for (i = 0; i < 6; i++)
  147. fpsqr_mont(tt, tt);
  148. fpmul_mont(t[11], tt, tt);
  149. for (i = 0; i < 6; i++)
  150. fpsqr_mont(tt, tt);
  151. fpmul_mont(t[10], tt, tt);
  152. for (i = 0; i < 6; i++)
  153. fpsqr_mont(tt, tt);
  154. fpmul_mont(t[14], tt, tt);
  155. for (i = 0; i < 6; i++)
  156. fpsqr_mont(tt, tt);
  157. fpmul_mont(t[4], tt, tt);
  158. for (i = 0; i < 10; i++)
  159. fpsqr_mont(tt, tt);
  160. fpmul_mont(t[18], tt, tt);
  161. for (i = 0; i < 6; i++)
  162. fpsqr_mont(tt, tt);
  163. fpmul_mont(t[1], tt, tt);
  164. for (i = 0; i < 7; i++)
  165. fpsqr_mont(tt, tt);
  166. fpmul_mont(t[22], tt, tt);
  167. for (i = 0; i < 10; i++)
  168. fpsqr_mont(tt, tt);
  169. fpmul_mont(t[6], tt, tt);
  170. for (i = 0; i < 7; i++)
  171. fpsqr_mont(tt, tt);
  172. fpmul_mont(t[24], tt, tt);
  173. for (i = 0; i < 6; i++)
  174. fpsqr_mont(tt, tt);
  175. fpmul_mont(t[9], tt, tt);
  176. for (i = 0; i < 8; i++)
  177. fpsqr_mont(tt, tt);
  178. fpmul_mont(t[18], tt, tt);
  179. for (i = 0; i < 6; i++)
  180. fpsqr_mont(tt, tt);
  181. fpmul_mont(t[17], tt, tt);
  182. for (i = 0; i < 8; i++)
  183. fpsqr_mont(tt, tt);
  184. fpmul_mont(a, tt, tt);
  185. for (i = 0; i < 10; i++)
  186. fpsqr_mont(tt, tt);
  187. fpmul_mont(t[16], tt, tt);
  188. for (i = 0; i < 6; i++)
  189. fpsqr_mont(tt, tt);
  190. fpmul_mont(t[7], tt, tt);
  191. for (i = 0; i < 6; i++)
  192. fpsqr_mont(tt, tt);
  193. fpmul_mont(t[0], tt, tt);
  194. for (i = 0; i < 7; i++)
  195. fpsqr_mont(tt, tt);
  196. fpmul_mont(t[12], tt, tt);
  197. for (i = 0; i < 7; i++)
  198. fpsqr_mont(tt, tt);
  199. fpmul_mont(t[19], tt, tt);
  200. for (i = 0; i < 6; i++)
  201. fpsqr_mont(tt, tt);
  202. fpmul_mont(t[22], tt, tt);
  203. for (i = 0; i < 6; i++)
  204. fpsqr_mont(tt, tt);
  205. fpmul_mont(t[25], tt, tt);
  206. for (i = 0; i < 7; i++)
  207. fpsqr_mont(tt, tt);
  208. fpmul_mont(t[2], tt, tt);
  209. for (i = 0; i < 6; i++)
  210. fpsqr_mont(tt, tt);
  211. fpmul_mont(t[10], tt, tt);
  212. for (i = 0; i < 7; i++)
  213. fpsqr_mont(tt, tt);
  214. fpmul_mont(t[22], tt, tt);
  215. for (i = 0; i < 8; i++)
  216. fpsqr_mont(tt, tt);
  217. fpmul_mont(t[18], tt, tt);
  218. for (i = 0; i < 6; i++)
  219. fpsqr_mont(tt, tt);
  220. fpmul_mont(t[4], tt, tt);
  221. for (i = 0; i < 6; i++)
  222. fpsqr_mont(tt, tt);
  223. fpmul_mont(t[14], tt, tt);
  224. for (i = 0; i < 7; i++)
  225. fpsqr_mont(tt, tt);
  226. fpmul_mont(t[13], tt, tt);
  227. for (i = 0; i < 6; i++)
  228. fpsqr_mont(tt, tt);
  229. fpmul_mont(t[5], tt, tt);
  230. for (i = 0; i < 6; i++)
  231. fpsqr_mont(tt, tt);
  232. fpmul_mont(t[23], tt, tt);
  233. for (i = 0; i < 6; i++)
  234. fpsqr_mont(tt, tt);
  235. fpmul_mont(t[21], tt, tt);
  236. for (i = 0; i < 6; i++)
  237. fpsqr_mont(tt, tt);
  238. fpmul_mont(t[2], tt, tt);
  239. for (i = 0; i < 7; i++)
  240. fpsqr_mont(tt, tt);
  241. fpmul_mont(t[23], tt, tt);
  242. for (i = 0; i < 8; i++)
  243. fpsqr_mont(tt, tt);
  244. fpmul_mont(t[12], tt, tt);
  245. for (i = 0; i < 6; i++)
  246. fpsqr_mont(tt, tt);
  247. fpmul_mont(t[9], tt, tt);
  248. for (i = 0; i < 6; i++)
  249. fpsqr_mont(tt, tt);
  250. fpmul_mont(t[3], tt, tt);
  251. for (i = 0; i < 7; i++)
  252. fpsqr_mont(tt, tt);
  253. fpmul_mont(t[13], tt, tt);
  254. for (i = 0; i < 7; i++)
  255. fpsqr_mont(tt, tt);
  256. fpmul_mont(t[17], tt, tt);
  257. for (i = 0; i < 8; i++)
  258. fpsqr_mont(tt, tt);
  259. fpmul_mont(t[26], tt, tt);
  260. for (i = 0; i < 8; i++)
  261. fpsqr_mont(tt, tt);
  262. fpmul_mont(t[5], tt, tt);
  263. for (i = 0; i < 8; i++)
  264. fpsqr_mont(tt, tt);
  265. fpmul_mont(t[8], tt, tt);
  266. for (i = 0; i < 6; i++)
  267. fpsqr_mont(tt, tt);
  268. fpmul_mont(t[2], tt, tt);
  269. for (i = 0; i < 6; i++)
  270. fpsqr_mont(tt, tt);
  271. fpmul_mont(t[11], tt, tt);
  272. for (i = 0; i < 7; i++)
  273. fpsqr_mont(tt, tt);
  274. fpmul_mont(t[20], tt, tt);
  275. for (j = 0; j < 61; j++)
  276. {
  277. for (i = 0; i < 6; i++)
  278. fpsqr_mont(tt, tt);
  279. fpmul_mont(t[26], tt, tt);
  280. }
  281. memcpy(a, tt, sizeof(felm_t));
  282. }
  283. void fpinv_mont(felm_t a)
  284. { // Field inversion using Montgomery arithmetic, a = a^(-1)*R mod p.
  285. felm_t tt;
  286. memcpy(tt, a, sizeof(felm_t));
  287. fpinv_chain_mont(tt);
  288. fpsqr_mont(tt, tt);
  289. fpsqr_mont(tt, tt);
  290. fpmul_mont(a, tt, a);
  291. }
  292. void fp2inv_mont(f2elm_t a)
  293. { // GF(p^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2).
  294. f2elm_t t1;
  295. felm_t zero = {0};
  296. fpsqr_mont(a[0], t1[0]); // t10 = a0^2
  297. fpsqr_mont(a[1], t1[1]); // t11 = a1^2
  298. fpadd(t1[0], t1[1], t1[0]); // t10 = a0^2+a1^2
  299. fpinv_mont(t1[0]); // t10 = (a0^2+a1^2)^-1
  300. fp_sub(a[1], zero, a[1]); // a = a0-i*a1
  301. fpmul_mont(a[0], t1[0], a[0]);
  302. fpmul_mont(a[1], t1[0], a[1]); // a = (a0-i*a1)*(a0^2+a1^2)^-1
  303. }
  304. void inv_3_way_ifma(f2elm_t z1, f2elm_t z2, f2elm_t z3)
  305. { // 3-way simultaneous inversion
  306. // Input: z1,z2,z3
  307. // Output: 1/z1,1/z2,1/z3 (override inputs).
  308. f2elm_t t0, t1, t2, t3;
  309. fp2mul_mont(z1, z2, t0); // t0 = z1*z2
  310. fp2mul_mont(z3, t0, t1); // t1 = z1*z2*z3
  311. fp2inv_mont(t1); // t1 = 1/(z1*z2*z3)
  312. fp2mul_mont(z3, t1, t2); // t2 = 1/(z1*z2)
  313. fp2_mul_ifma_x2(t3, t2, z2, z2, t2, z1);
  314. //fp2mul_mont(t2, z2, t3); // t3 = 1/z1
  315. //fp2mul_mont(t2, z1, z2); // z2 = 1/z2
  316. fp2mul_mont(t0, t1, z3); // z3 = 1/z3
  317. memcpy(z1, t3, sizeof(f2elm_t));
  318. }
  319. void xDBLADD_ifma(point_proj_t P, point_proj_t Q, const f2elm_t xPQ, const f2elm_t A24)
  320. { // Simultaneous doubling and differential addition.
  321. // 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.
  322. // 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.
  323. f2elm_t t0, t1, t2, t3;
  324. fp2add(P->X, P->Z, t0); // t0 = XP+ZP
  325. fp2sub(P->X, P->Z, t1); // t1 = XP-ZP
  326. fp2_mul_ifma_x2(P->X, t0, t0, P->Z, t1, t1);
  327. //fp2sqr_mont(t0, P->X); // XP = (XP+ZP)^2
  328. //fp2sqr_mont(t1, P->Z); // ZP = (XP-ZP)^2
  329. fp2add(Q->X, Q->Z, t2); // XQ = XQ+ZQ
  330. fp2sub(Q->X, Q->Z, t3); // t2 = XQ-ZQ
  331. fp2_mul_ifma_x2(t1, t1, t2, t0, t0, t3);
  332. //fp2mul_mont(t2, t1, t1); // t1 = (XP-ZP)*(XQ+ZQ)
  333. //fp2mul_mont(t3, t0, t0); // t0 = (XP+ZP)*(XQ-ZQ)
  334. fp2sub(P->X, P->Z, t2); // t2 = (XP+ZP)^2-(XP-ZP)^2
  335. fp2sub(t0, t1, Q->Z); // ZQ = (XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)
  336. fp2_mul_ifma_x2(P->X, P->X, P->Z, Q->X, A24, t2);
  337. //fp2mul_mont(P->X, P->Z, P->X); // XP = (XP+ZP)^2*(XP-ZP)^2
  338. //fp2mul_mont(t2, A24, Q->X); // XQ = A24*[(XP+ZP)^2-(XP-ZP)^2]
  339. fp2add(Q->X, P->Z, P->Z); // ZP = A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2
  340. fp2add(t0, t1, Q->X); // XQ = (XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)
  341. fp2_mul_ifma_x2(Q->Z, Q->Z, Q->Z, Q->X, Q->X, Q->X);
  342. //fp2sqr_mont(Q->Z, Q->Z); // ZQ = [(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
  343. //fp2sqr_mont(Q->X, Q->X); // XQ = [(XP+ZP)*(XQ-ZQ)+(XP-ZP)*(XQ+ZQ)]^2
  344. fp2_mul_ifma_x2(P->Z, P->Z, t2, Q->Z, Q->Z, xPQ);
  345. //fp2mul_mont(P->Z, t2, P->Z); // ZP = [A24*[(XP+ZP)^2-(XP-ZP)^2]+(XP-ZP)^2]*[(XP+ZP)^2-(XP-ZP)^2]
  346. //fp2mul_mont(Q->Z, xPQ, Q->Z); // ZQ = xPQ*[(XP+ZP)*(XQ-ZQ)-(XP-ZP)*(XQ+ZQ)]^2
  347. }
  348. static void LADDER3PT_ifma(const f2elm_t xP, const f2elm_t xQ, const f2elm_t xPQ, const uint64_t *m, const unsigned int AliceOrBob, point_proj_t R)
  349. {
  350. point_proj_t R0 = {0}, R2 = {0};
  351. const f2elm_t A24 = {
  352. {0x00000000124d6b3e, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000fcc0062a1600, 0x000d9932447f1d95, 0x000f30bb11b6dbbb, 0x000eeb74b81195c1, 0x000ea6bb113bab9f, 0x000aa668b600af9a, 0x0004fe3921c627e3, 0x00000000000dfc7b},
  353. {0}};
  354. uint64_t mask;
  355. int i, nbits, bit, swap, prevbit = 0;
  356. if (AliceOrBob == ALICE)
  357. {
  358. nbits = OALICE_BITS;
  359. }
  360. else
  361. {
  362. nbits = OBOB_BITS;
  363. }
  364. // Initializing points
  365. memcpy(R0->X, xQ, sizeof(f2elm_t));
  366. memcpy(R0->Z[0], One, sizeof(felm_t));
  367. memcpy(R2->X, xPQ, sizeof(f2elm_t));
  368. memcpy(R2->Z[0], One, sizeof(felm_t));
  369. memcpy(R->X, xP, sizeof(f2elm_t));
  370. memcpy(R->Z[0], One, sizeof(felm_t));
  371. memset(R->Z[1], 0, sizeof(felm_t));
  372. // Main loop
  373. for (i = 0; i < nbits; i++)
  374. {
  375. bit = (m[i >> 6] >> (i & (64 - 1))) & 1;
  376. swap = bit ^ prevbit;
  377. prevbit = bit;
  378. fp2_swap(R, R2, swap);
  379. xDBLADD_ifma(R0, R2, R->X, A24);
  380. fp2_mul_ifma(R2->X, R->Z, R2->X);
  381. }
  382. }
  383. static void xDBL_ifma(const point_proj_t P, point_proj_t Q, const f2elm_t A24plus, const f2elm_t C24)
  384. { // Doubling of a Montgomery point in projective coordinates (X:Z).
  385. // Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constants A+2C and 4C.
  386. // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2).
  387. f2elm_t t0, t1, t2;
  388. fp2sub(P->X, P->Z, t0); // t0 = X1-Z1
  389. fp2add(P->X, P->Z, t1); // t1 = X1+Z1
  390. fp2_mul_ifma_x2(t0, t0, t0, t1, t1, t1);
  391. //fp2sqr_mont(t0, t0); // t0 = (X1-Z1)^2
  392. //fp2sqr_mont(t1, t1); // t1 = (X1+Z1)^2
  393. fp2sub(t1, t0, t2); // t1 = (X1+Z1)^2-(X1-Z1)^2
  394. fp2_mul_ifma_x2(Q->Z, t0, C24, t0, t2, A24plus);
  395. //fp2mul_mont(C24, t0, Q->Z); // Z2 = C24*(X1-Z1)^2
  396. //fp2mul_mont(A24plus, t2, t0); // t0 = A24plus*[(X1+Z1)^2-(X1-Z1)^2]
  397. fp2add(Q->Z, t0, t0); // Z2 = A24plus*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2
  398. fp2_mul_ifma_x2(Q->X, Q->Z, t1, Q->Z, t2, t0);
  399. //fp2mul_mont(t1, Q->Z, Q->X); // X2 = C24*(X1-Z1)^2*(X1+Z1)^2
  400. //fp2mul_mont(t0, t2, Q->Z); // Z2 = [A24plus*[(X1+Z1)^2-(X1-Z1)^2] + C24*(X1-Z1)^2]*[(X1+Z1)^2-(X1-Z1)^2]
  401. }
  402. static void xDBLe_ifma(const point_proj_t P, point_proj_t Q, const f2elm_t A24plus, const f2elm_t C24, const int e)
  403. { // Computes [2^e](X:Z) on Montgomery curve with projective constant via e repeated doublings.
  404. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A+2C and 4C.
  405. // Output: projective Montgomery x-coordinates Q <- (2^e)*P.
  406. int i;
  407. memcpy(Q, P, sizeof(point_proj));
  408. for (i = 0; i < e; i++)
  409. {
  410. xDBL_ifma(Q, Q, A24plus, C24);
  411. }
  412. }
  413. static void xTPL_ifma(const point_proj_t P, point_proj_t Q, const f2elm_t A24minus, const f2elm_t A24plus)
  414. { // Tripling of a Montgomery point in projective coordinates (X:Z).
  415. // Input: projective Montgomery x-coordinates P = (X:Z), where x=X/Z and Montgomery curve constants A24plus = A+2C and A24minus = A-2C.
  416. // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3).
  417. f2elm_t t0, t1, t2, t3, t4, t5, t6, t7, t8;
  418. fp2sub(P->X, P->Z, t0); // t0 = X-Z
  419. fp2add(P->X, P->Z, t1); // t1 = X+Z
  420. fp2_mul_ifma_x2(t2, t0, t0, t3, t1, t1);
  421. //fp2sqr_mont(t0, t2); // t2 = (X-Z)^2
  422. //fp2sqr_mont(t1, t3); // t3 = (X+Z)^2
  423. fp2_mul_ifma_x2(t5, A24plus, t3, t6, A24minus, t2);
  424. //fp2mul_mont(t3, A24plus, t5); // t5 = A24plus*(X+Z)^2
  425. //fp2mul_mont(A24minus, t2, t6); // t6 = A24minus*(X-Z)^2
  426. fp2_mul_ifma_x2(t7, t3, t5, t8, t2, t6);
  427. //fp2mul_mont(t3, t5, t7); // t3 = A24plus*(X+Z)^3
  428. //fp2mul_mont(t2, t6, t8); // t2 = A24minus*(X-Z)^3
  429. fp2add(t0, t1, t4); // t4 = 2*X
  430. fp2sub(t1, t0, t0); // t0 = 2*Z
  431. fp2sqr_mont(t4, t1); // t1 = 4*X^2
  432. fp2sub(t1, t3, t1); // t1 = 4*X^2 - (X+Z)^2
  433. fp2sub(t1, t2, t1); // t1 = 4*X^2 - (X+Z)^2 - (X-Z)^2
  434. fp2sub(t8, t7, t7); // t3 = A24minus*(X-Z)^3 - coeff*(X+Z)^3
  435. fp2sub(t5, t6, t8); // t2 = A24plus*(X+Z)^2 - A24minus*(X-Z)^2
  436. fp2mul_mont(t1, t8, t1); // t1 = [4*X^2 - (X+Z)^2 - (X-Z)^2]*[A24plus*(X+Z)^2 - A24minus*(X-Z)^2]
  437. fp2add(t7, t1, t8); // 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
  438. fp2sub(t7, 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]
  439. fp2_mul_ifma_x2(t8, t8, t8, t1, t1, t1);
  440. //fp2sqr_mont(t8, t8); // t2 = t2^2
  441. //fp2sqr_mont(t1, t1); // t1 = t1^2
  442. fp2_mul_ifma_x2(Q->X, t4, t8, Q->Z, t1, t0);
  443. //fp2mul_mont(t4, t8, Q->X); // X3 = 2*X*t2
  444. //fp2mul_mont(t0, t1, Q->Z); // Z3 = 2*Z*t1
  445. }
  446. void xTPLe_ifma(const point_proj_t P, point_proj_t Q, const f2elm_t A24minus, const f2elm_t A24plus, const int e)
  447. { // Computes [3^e](X:Z) on Montgomery curve with projective constant via e repeated triplings.
  448. // Input: projective Montgomery x-coordinates P = (XP:ZP), such that xP=XP/ZP and Montgomery curve constants A24plus = A+2C and A24minus = A-2C.
  449. // Output: projective Montgomery x-coordinates Q <- (3^e)*P.
  450. int i;
  451. memcpy(Q, P, sizeof(point_proj));
  452. for (i = 0; i < e; i++)
  453. {
  454. xTPL_ifma(Q, Q, A24minus, A24plus);
  455. }
  456. }
  457. static void get_4_isog_ifma(const point_proj_t P, f2elm_t A24plus, f2elm_t C24, f2elm_t *coeff)
  458. { // Computes the corresponding 4-isogeny of a projective Montgomery point (X4:Z4) of order 4.
  459. // Input: projective point of order four P = (X4:Z4).
  460. // Output: the 4-isogenous Montgomery curve with projective coefficients A+2C/4C and the 3 coefficients
  461. // that are used to evaluate the isogeny at a point in eval_4_isog().
  462. fp2sub(P->X, P->Z, coeff[1]); // coeff[1] = X4-Z4
  463. fp2add(P->X, P->Z, coeff[2]); // coeff[2] = X4+Z4
  464. fp2_mul_ifma_x2(coeff[0], P->Z, P->Z, A24plus, P->X, P->X);
  465. //fp2sqr_mont(P->Z, coeff[0]); // coeff[0] = Z4^2
  466. //fp2sqr_mont(P->X, A24plus); // A24plus = X4^2
  467. fp2add(coeff[0], coeff[0], coeff[0]); // coeff[0] = 2*Z4^2
  468. fp2add(A24plus, A24plus, A24plus); // A24plus = 2*X4^2
  469. fp2_mul_ifma_x2(C24, coeff[0], coeff[0], A24plus, A24plus, A24plus);
  470. //fp2sqr_mont(coeff[0], C24); // C24 = 4*Z4^4
  471. //fp2sqr_mont(A24plus, A24plus); // A24plus = 4*X4^4
  472. fp2add(coeff[0], coeff[0], coeff[0]); // coeff[0] = 4*Z4^2
  473. }
  474. static void eval_4_isog_ifma(point_proj_t P, f2elm_t *coeff)
  475. { // Evaluates the isogeny at the point (X:Z) in the domain of the isogeny, given a 4-isogeny phi defined
  476. // by the 3 coefficients in coeff (computed in the function get_4_isog()).
  477. // Inputs: the coefficients defining the isogeny, and the projective point P = (X:Z).
  478. // Output: the projective point P = phi(P) = (X:Z) in the codomain.
  479. f2elm_t t0, t1, t2;
  480. fp2add(P->X, P->Z, t0); // t0 = X+Z
  481. fp2sub(P->X, P->Z, t1); // t1 = X-Z
  482. fp2_mul_ifma_x2(P->X, t0, coeff[1], t0, t0, t1);
  483. //fp2mul_mont(t0, coeff[1], P->X); // X = (X+Z)*coeff[1]
  484. //fp2mul_mont(t0, t1, t0); // t0 = (X+Z)*(X-Z)
  485. fp2_mul_ifma_x2(P->Z, coeff[2], t1, t0, coeff[0], t0);
  486. //fp2mul_mont(t1, coeff[2], P->Z); // Z = (X-Z)*coeff[2]
  487. //fp2mul_mont(t0, coeff[0], t0); // t0 = coeff[0]*(X+Z)*(X-Z)
  488. fp2add(P->X, P->Z, t1); // t1 = (X-Z)*coeff[2] + (X+Z)*coeff[1]
  489. fp2sub(P->X, P->Z, P->Z); // Z = (X-Z)*coeff[2] - (X+Z)*coeff[1]
  490. fp2_mul_ifma_x2(t1, t1, t1, P->Z, P->Z, P->Z);
  491. //fp2sqr_mont(t1, t1); // t1 = [(X-Z)*coeff[2] + (X+Z)*coeff[1]]^2
  492. //fp2sqr_mont(P->Z, P->Z); // Z = [(X-Z)*coeff[2] - (X+Z)*coeff[1]]^2
  493. fp2add(t1, t0, P->X); // X = coeff[0]*(X+Z)*(X-Z) + [(X-Z)*coeff[2] + (X+Z)*coeff[1]]^2
  494. fp2sub(P->Z, t0, t0); // t0 = [(X-Z)*coeff[2] - (X+Z)*coeff[1]]^2 - coeff[0]*(X+Z)*(X-Z)
  495. fp2_mul_ifma_x2(P->X, P->X, t1, P->Z, P->Z, t0);
  496. //fp2mul_mont(P->X, t1, P->X); // Xfinal
  497. //fp2mul_mont(P->Z, t0, P->Z); // Zfinal
  498. }
  499. static void get_3_isog_ifma(const point_proj_t P, f2elm_t A24minus, f2elm_t A24plus, f2elm_t *coeff)
  500. { // Computes the corresponding 3-isogeny of a projective Montgomery point (X3:Z3) of order 3.
  501. // Input: projective point of order three P = (X3:Z3).
  502. // Output: the 3-isogenous Montgomery curve with projective coefficient A/C.
  503. f2elm_t t0, t1, t2, t3, t4, t5;
  504. fp2sub(P->X, P->Z, coeff[0]); // coeff0 = X-Z
  505. fp2add(P->X, P->Z, coeff[1]); // coeff1 = X+Z
  506. fp2_mul_ifma_x2(t0, coeff[0], coeff[0], t1, coeff[1], coeff[1]);
  507. //fp2sqr_mont(coeff[0], t0); // t0 = (X-Z)^2
  508. //fp2sqr_mont(coeff[1], t1); // t1 = (X+Z)^2
  509. fp2add(t0, t1, t2); // t2 = (X+Z)^2 + (X-Z)^2
  510. fp2add(coeff[0], coeff[1], t3); // t3 = 2*X
  511. fp2sqr_mont(t3, t3); // t3 = 4*X^2
  512. fp2sub(t3, t2, t3); // t3 = 4*X^2 - (X+Z)^2 - (X-Z)^2
  513. fp2add(t1, t3, t2); // t2 = 4*X^2 - (X-Z)^2
  514. fp2add(t3, t0, t3); // t3 = 4*X^2 - (X+Z)^2
  515. fp2add(t0, t3, t4); // t4 = 4*X^2 - (X+Z)^2 + (X-Z)^2
  516. fp2add(t4, t4, t4); // t4 = 2(4*X^2 - (X+Z)^2 + (X-Z)^2)
  517. fp2add(t1, t4, t4); // t4 = 8*X^2 - (X+Z)^2 + 2*(X-Z)^2
  518. fp2add(t1, t2, t5); // t4 = 4*X^2 + (X+Z)^2 - (X-Z)^2
  519. fp2add(t5, t5, t5); // t4 = 2(4*X^2 + (X+Z)^2 - (X-Z)^2)
  520. fp2add(t0, t5, t5); // t4 = 8*X^2 + 2*(X+Z)^2 - (X-Z)^2
  521. fp2_mul_ifma_x2(A24minus, t2, t4, t5, t5, t3);
  522. // fp2mul_mont(t2, t4, A24minus); // A24minus = [4*X^2 - (X-Z)^2]*[8*X^2 - (X+Z)^2 + 2*(X-Z)^2]
  523. // fp2mul_mont(t3, t5, t5); // t4 = [4*X^2 - (X+Z)^2]*[8*X^2 + 2*(X+Z)^2 - (X-Z)^2]
  524. fp2sub(t5, 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]
  525. fp2add(A24minus, t0, A24plus); // A24plus = 8*X^2 - (X+Z)^2 + 2*(X-Z)^2
  526. }
  527. static void eval_3_isog_ifma(point_proj_t Q, const f2elm_t *coeff)
  528. { // Computes the 3-isogeny R=phi(X:Z), given projective point (X3:Z3) of order 3 on a Montgomery curve and
  529. // a point P with 2 coefficients in coeff (computed in the function get_3_isog()).
  530. // Inputs: projective points P = (X3:Z3) and Q = (X:Z).
  531. // Output: the projective point Q <- phi(Q) = (X3:Z3).
  532. f2elm_t t0, t1, t2;
  533. fp2add(Q->X, Q->Z, t0); // t0 = X+Z
  534. fp2sub(Q->X, Q->Z, t1); // t1 = X-Z
  535. fp2_mul_ifma_x2(t0, t0, coeff[0], t1, t1, coeff[1]);
  536. //fp2mul_mont(t0, coeff[0], t0); // t0 = coeff0*(X+Z)
  537. //fp2mul_mont(t1, coeff[1], t1); // t1 = coeff1*(X-Z)
  538. fp2add(t0, t1, t2); // t2 = coeff0*(X-Z) + coeff1*(X+Z)
  539. fp2sub(t1, t0, t0); // t0 = coeff0*(X-Z) - coeff1*(X+Z)
  540. fp2_mul_ifma_x2(t2, t2, t2, t0, t0, t0);
  541. //fp2sqr_mont(t2, t2); // t2 = [coeff0*(X-Z) + coeff1*(X+Z)]^2
  542. //fp2sqr_mont(t0, t0); // t1 = [coeff0*(X-Z) - coeff1*(X+Z)]^2
  543. fp2_mul_ifma_x2(Q->X, Q->X, t2, Q->Z, Q->Z, t0);
  544. //fp2mul_mont(Q->X, t2, Q->X); // X3final = X*[coeff0*(X-Z) + coeff1*(X+Z)]^2
  545. //fp2mul_mont(Q->Z, t0, Q->Z); // Z3final = Z*[coeff0*(X-Z) - coeff1*(X+Z)]^2
  546. }
  547. static void fp2_encode(const f2elm_t x, unsigned char *enc)
  548. { // Conversion of GF(p^2) element from Montgomery to standard representation, and encoding by removing leading 0 bytes
  549. unsigned int i;
  550. f2elm_t tt;
  551. uint64_t t[12 * 2];
  552. from_mont_ifma(tt[0], x[0]);
  553. from_mont_ifma(tt[1], x[1]);
  554. red2norm(t, tt[0]);
  555. red2norm(&t[12], tt[1]);
  556. for (i = 0; i < FP2_ENCODED_BYTES / 2; i++)
  557. {
  558. enc[i] = ((unsigned char *)t)[i];
  559. enc[i + FP2_ENCODED_BYTES / 2] = ((unsigned char *)t)[i + MAXBITS_FIELD / 8];
  560. }
  561. }
  562. static void fp2_decode(const unsigned char *enc, f2elm_t x)
  563. {
  564. unsigned int i;
  565. uint64_t t[12 * 2];
  566. memset(x, 0, sizeof(f2elm_t));
  567. for (i = 0; i < FP2_ENCODED_BYTES / 2; i++)
  568. {
  569. ((unsigned char *)t)[i] = enc[i];
  570. ((unsigned char *)t)[i + MAXBITS_FIELD / 8] = enc[i + FP2_ENCODED_BYTES / 2];
  571. }
  572. norm2red(x[0], t);
  573. norm2red(x[1], &t[12]);
  574. to_mont_ifma(x[0], x[0]);
  575. to_mont_ifma(x[1], x[1]);
  576. }
  577. int EphemeralKeyGeneration_A_ifma(const unsigned char *PrivateKeyA, unsigned char *PublicKeyA)
  578. { // Alice's ephemeral public key generation
  579. // Input: a private key PrivateKeyA in the range [0, 2^eA - 1].
  580. // Output: the public key PublicKeyA consisting of 3 elements in GF(p^2) which are encoded by removing leading 0 bytes.
  581. point_proj_t R, phiP = {0}, phiQ = {0}, phiR = {0}, pts[MAX_INT_POINTS_ALICE];
  582. f2elm_t XPA, XQA, XRA, coeff[3];
  583. unsigned int i, row, m, index = 0, pts_index[MAX_INT_POINTS_ALICE], npts = 0, ii = 0;
  584. f2elm_t C24 = {
  585. {0x000000004935acf8, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0003f30018a85800, 0x000664c911fc7654, 0x000cc2ec46db6eef, 0x000badd2e0465707, 0x000a9aec44eeae7f, 0x000a99a2d802be6b, 0x0003f8e487189f8e, 0x000000000037f1ed},
  586. {0}};
  587. f2elm_t A24plus = {
  588. {0x00000000249ad67c, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0001f9800c542c00, 0x000b326488fe3b2a, 0x000e6176236db777, 0x000dd6e970232b83, 0x000d4d762277573f, 0x00054cd16c015f35, 0x0009fc72438c4fc7, 0x00000000001bf8f6},
  589. {0}};
  590. // Initialize basis points
  591. init_basis(A_gen_ifma, XPA, XQA, XRA);
  592. init_basis(B_gen_ifma, phiP->X, phiQ->X, phiR->X);
  593. memcpy(phiP->Z, One, sizeof(felm_t));
  594. memcpy(phiQ->Z, One, sizeof(felm_t));
  595. memcpy(phiR->Z, One, sizeof(felm_t));
  596. // Retrieve kernel point
  597. LADDER3PT_ifma(XPA, XQA, XRA, (uint64_t *)PrivateKeyA, ALICE, R);
  598. // Traverse tree
  599. index = 0;
  600. for (row = 1; row < MAX_Alice; row++)
  601. {
  602. while (index < MAX_Alice - row)
  603. {
  604. memcpy(pts[npts]->X, R->X, sizeof(f2elm_t));
  605. memcpy(pts[npts]->Z, R->Z, sizeof(f2elm_t));
  606. pts_index[npts++] = index;
  607. m = strat_Alice[ii++];
  608. xDBLe_ifma(R, R, A24plus, C24, (int)(2 * m));
  609. index += m;
  610. }
  611. get_4_isog_ifma(R, A24plus, C24, coeff);
  612. for (i = 0; i < npts; i++)
  613. {
  614. eval_4_isog_ifma(pts[i], coeff);
  615. }
  616. eval_4_isog_ifma(phiP, coeff);
  617. eval_4_isog_ifma(phiQ, coeff);
  618. eval_4_isog_ifma(phiR, coeff);
  619. memcpy(R->X, pts[npts - 1]->X, sizeof(f2elm_t));
  620. memcpy(R->Z, pts[npts - 1]->Z, sizeof(f2elm_t));
  621. index = pts_index[npts - 1];
  622. npts -= 1;
  623. }
  624. get_4_isog_ifma(R, A24plus, C24, coeff);
  625. eval_4_isog_ifma(phiP, coeff);
  626. eval_4_isog_ifma(phiQ, coeff);
  627. eval_4_isog_ifma(phiR, coeff);
  628. inv_3_way_ifma(phiP->Z, phiQ->Z, phiR->Z);
  629. fp2_mul_ifma_x2(phiP->X, phiP->X, phiP->Z, phiQ->X, phiQ->X, phiQ->Z);
  630. //fp2mul_mont(phiP->X, phiP->Z, phiP->X);
  631. //fp2mul_mont(phiQ->X, phiQ->Z, phiQ->X);
  632. fp2mul_mont(phiR->X, phiR->Z, phiR->X);
  633. // Format public key
  634. fp2_encode(phiP->X, PublicKeyA);
  635. fp2_encode(phiQ->X, PublicKeyA + FP2_ENCODED_BYTES);
  636. fp2_encode(phiR->X, PublicKeyA + 2 * FP2_ENCODED_BYTES);
  637. return 0;
  638. }
  639. int EphemeralKeyGeneration_B_ifma(const unsigned char *PrivateKeyB, unsigned char *PublicKeyB)
  640. { // Bob's ephemeral public key generation
  641. // Input: a private key PrivateKeyB in the range [0, 2^Floor(Log(2,oB)) - 1].
  642. // Output: the public key PublicKeyB consisting of 3 elements in GF(p^2) which are encoded by removing leading 0 bytes.
  643. point_proj_t R, phiP = {0}, phiQ = {0}, phiR = {0}, pts[MAX_INT_POINTS_BOB];
  644. f2elm_t XPB, XQB, XRB, coeff[3], A = {0};
  645. unsigned int i, row, m, index = 0, pts_index[MAX_INT_POINTS_BOB], npts = 0, ii = 0;
  646. f2elm_t A24plus = {{0x000000004935acf8, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000, 0x0003f30018a85800, 0x000664c911fc7654, 0x000cc2ec46db6eef, 0x000badd2e0465707, 0x000a9aec44eeae7f, 0x000a99a2d802be6b, 0x0003f8e487189f8e, 0x000000000037f1ed},
  647. {0}};
  648. f2elm_t A24minus = {{0x000fffffb6ca5307, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x0000ac8771e692ff, 0x000167add1f02031, 0x000aaabd12d63250, 0x000ca0c5879094e0, 0x0000b5598636c600, 0x0004fe180463c6f7, 0x0000268d39c8897b, 0x000000000037f3e8},
  649. {0}};
  650. uint64_t temp[12];
  651. uint64_t ifma_temp[15];
  652. // Initialize basis points
  653. init_basis(B_gen_ifma, XPB, XQB, XRB);
  654. init_basis(A_gen_ifma, phiP->X, phiQ->X, phiR->X);
  655. memcpy(phiP->Z, One, sizeof(felm_t));
  656. memcpy(phiQ->Z, One, sizeof(felm_t));
  657. memcpy(phiR->Z, One, sizeof(felm_t));
  658. // Retrieve kernel point
  659. LADDER3PT_ifma(XPB, XQB, XRB, (uint64_t *)PrivateKeyB, BOB, R);
  660. // Traverse tree
  661. index = 0;
  662. for (row = 1; row < MAX_Bob; row++)
  663. {
  664. while (index < MAX_Bob - row)
  665. {
  666. memcpy(pts[npts]->X, R->X, sizeof(f2elm_t));
  667. memcpy(pts[npts]->Z, R->Z, sizeof(f2elm_t));
  668. pts_index[npts++] = index;
  669. m = strat_Bob[ii++];
  670. xTPLe_ifma(R, R, A24minus, A24plus, (int)m);
  671. index += m;
  672. }
  673. get_3_isog_ifma(R, A24minus, A24plus, coeff);
  674. for (i = 0; i < npts; i++)
  675. {
  676. eval_3_isog_ifma(pts[i], coeff);
  677. }
  678. eval_3_isog_ifma(phiP, coeff);
  679. eval_3_isog_ifma(phiQ, coeff);
  680. eval_3_isog_ifma(phiR, coeff);
  681. memcpy(R->X, pts[npts - 1]->X, sizeof(f2elm_t));
  682. memcpy(R->Z, pts[npts - 1]->Z, sizeof(f2elm_t));
  683. index = pts_index[npts - 1];
  684. npts -= 1;
  685. }
  686. get_3_isog_ifma(R, A24minus, A24plus, coeff);
  687. eval_3_isog_ifma(phiP, coeff);
  688. eval_3_isog_ifma(phiQ, coeff);
  689. eval_3_isog_ifma(phiR, coeff);
  690. inv_3_way_ifma(phiP->Z, phiQ->Z, phiR->Z);
  691. fp2mul_mont(phiP->X, phiP->Z, phiP->X);
  692. fp2mul_mont(phiQ->X, phiQ->Z, phiQ->X);
  693. fp2mul_mont(phiR->X, phiR->Z, phiR->X);
  694. // Format public key
  695. fp2_encode(phiP->X, PublicKeyB);
  696. fp2_encode(phiQ->X, PublicKeyB + FP2_ENCODED_BYTES);
  697. fp2_encode(phiR->X, PublicKeyB + 2 * FP2_ENCODED_BYTES);
  698. return 0;
  699. }