25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

474 lines
14 KiB

  1. /********************************************************************************************
  2. * Supersingular Isogeny Key Encapsulation Library
  3. *
  4. * Abstract: core functions over GF(p) and GF(p^2)
  5. *********************************************************************************************/
  6. #include "P751_internal.h"
  7. __inline void fpcopy(const felm_t a, felm_t c)
  8. { // Copy a field element, c = a.
  9. unsigned int i;
  10. for (i = 0; i < NWORDS_FIELD; i++)
  11. c[i] = a[i];
  12. }
  13. __inline void fpzero(felm_t a)
  14. { // Zero a field element, a = 0.
  15. unsigned int i;
  16. for (i = 0; i < NWORDS_FIELD; i++)
  17. a[i] = 0;
  18. }
  19. void to_mont(const felm_t a, felm_t mc)
  20. { // Conversion to Montgomery representation,
  21. // mc = a*R^2*R^(-1) mod p = a*R mod p, where a in [0, p-1].
  22. // The Montgomery constant R^2 mod p is the global value "Montgomery_R2".
  23. fpmul_mont(a, (digit_t *)&Montgomery_R2, mc);
  24. }
  25. void from_mont(const felm_t ma, felm_t c)
  26. { // Conversion from Montgomery representation to standard representation,
  27. // c = ma*R^(-1) mod p = a mod p, where ma in [0, p-1].
  28. digit_t one[NWORDS_FIELD] = {0};
  29. one[0] = 1;
  30. fpmul_mont(ma, one, c);
  31. fpcorrection(c);
  32. }
  33. void copy_words(const digit_t *a, digit_t *c, const unsigned int nwords)
  34. { // Copy wordsize digits, c = a, where lng(a) = nwords.
  35. unsigned int i;
  36. for (i = 0; i < nwords; i++)
  37. {
  38. c[i] = a[i];
  39. }
  40. }
  41. void fpmul_mont(const felm_t ma, const felm_t mb, felm_t mc)
  42. { // Multiprecision multiplication, c = a*b mod p.
  43. dfelm_t temp = {0};
  44. mp_mul(ma, mb, temp, NWORDS_FIELD);
  45. rdc_mont(temp, mc);
  46. }
  47. void fpsqr_mont(const felm_t ma, felm_t mc)
  48. { // Multiprecision squaring, c = a^2 mod p.
  49. dfelm_t temp = {0};
  50. mp_mul(ma, ma, temp, NWORDS_FIELD);
  51. rdc_mont(temp, mc);
  52. }
  53. void fpinv_mont(felm_t a)
  54. { // Field inversion using Montgomery arithmetic, a = a^(-1)*R mod p.
  55. felm_t tt;
  56. fpcopy(a, tt);
  57. fpinv_chain_mont(tt);
  58. fpsqr_mont(tt, tt);
  59. fpsqr_mont(tt, tt);
  60. fpmul_mont(a, tt, a);
  61. }
  62. void fp2copy(const f2elm_t a, f2elm_t c)
  63. { // Copy a GF(p^2) element, c = a.
  64. fpcopy(a[0], c[0]);
  65. fpcopy(a[1], c[1]);
  66. }
  67. void fp2zero(f2elm_t a)
  68. { // Zero a GF(p^2) element, a = 0.
  69. fpzero(a[0]);
  70. fpzero(a[1]);
  71. }
  72. void fp2neg(f2elm_t a)
  73. { // GF(p^2) negation, a = -a in GF(p^2).
  74. fpneg(a[0]);
  75. fpneg(a[1]);
  76. }
  77. __inline void fp2add(const f2elm_t a, const f2elm_t b, f2elm_t c)
  78. { // GF(p^2) addition, c = a+b in GF(p^2).
  79. fpadd(a[0], b[0], c[0]);
  80. fpadd(a[1], b[1], c[1]);
  81. }
  82. __inline void fp2sub(const f2elm_t a, const f2elm_t b, f2elm_t c)
  83. { // GF(p^2) subtraction, c = a-b in GF(p^2).
  84. fpsub(a[0], b[0], c[0]);
  85. fpsub(a[1], b[1], c[1]);
  86. }
  87. void fp2div2(const f2elm_t a, f2elm_t c)
  88. { // GF(p^2) division by two, c = a/2 in GF(p^2).
  89. fpdiv2(a[0], c[0]);
  90. fpdiv2(a[1], c[1]);
  91. }
  92. void fp2correction(f2elm_t a)
  93. { // Modular correction, a = a in GF(p^2).
  94. fpcorrection(a[0]);
  95. fpcorrection(a[1]);
  96. }
  97. __inline static void mp_addfast(const digit_t *a, const digit_t *b, digit_t *c)
  98. { // Multiprecision addition, c = a+b.
  99. mp_add_asm(a, b, c);
  100. }
  101. __inline static void mp_addfastx2(const digit_t *a, const digit_t *b, digit_t *c)
  102. { // Double-length multiprecision addition, c = a+b.
  103. mp_addx2_asm(a, b, c);
  104. }
  105. void fp2sqr_mont(const f2elm_t a, f2elm_t c)
  106. { // GF(p^2) squaring using Montgomery arithmetic, c = a^2 in GF(p^2).
  107. // Inputs: a = a0+a1*i, where a0, a1 are in [0, 2*p-1]
  108. // Output: c = c0+c1*i, where c0, c1 are in [0, 2*p-1]
  109. felm_t t1, t2, t3;
  110. mp_addfast(a[0], a[1], t1); // t1 = a0+a1
  111. fpsub(a[0], a[1], t2); // t2 = a0-a1
  112. mp_addfast(a[0], a[0], t3); // t3 = 2a0
  113. fpmul_mont(t1, t2, c[0]); // c0 = (a0+a1)(a0-a1)
  114. fpmul_mont(t3, a[1], c[1]); // c1 = 2a0*a1
  115. }
  116. __inline unsigned int mp_sub(const digit_t *a, const digit_t *b, digit_t *c, const unsigned int nwords)
  117. { // Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = nwords. Returns the borrow bit.
  118. unsigned int i, borrow = 0;
  119. for (i = 0; i < nwords; i++)
  120. {
  121. SUBC(borrow, a[i], b[i], borrow, c[i]);
  122. }
  123. return borrow;
  124. }
  125. __inline static digit_t mp_subfast(const digit_t *a, const digit_t *b, digit_t *c)
  126. { // Multiprecision subtraction, c = a-b, where lng(a) = lng(b) = 2*NWORDS_FIELD.
  127. // If c < 0 then returns mask = 0xFF..F, else mask = 0x00..0
  128. return mp_subx2_asm(a, b, c);
  129. }
  130. void fp2mul_mont(const f2elm_t a, const f2elm_t b, f2elm_t c)
  131. { // GF(p^2) multiplication using Montgomery arithmetic, c = a*b in GF(p^2).
  132. // Inputs: a = a0+a1*i and b = b0+b1*i, where a0, a1, b0, b1 are in [0, 2*p-1]
  133. // Output: c = c0+c1*i, where c0, c1 are in [0, 2*p-1]
  134. felm_t t1, t2;
  135. dfelm_t tt1, tt2, tt3;
  136. digit_t mask;
  137. unsigned int i, borrow = 0;
  138. mp_mul(a[0], b[0], tt1, NWORDS_FIELD); // tt1 = a0*b0
  139. mp_mul(a[1], b[1], tt2, NWORDS_FIELD); // tt2 = a1*b1
  140. mp_addfast(a[0], a[1], t1); // t1 = a0+a1
  141. mp_addfast(b[0], b[1], t2); // t2 = b0+b1
  142. mask = mp_subfast(tt1, tt2, tt3); // tt3 = a0*b0 - a1*b1. If tt3 < 0 then mask = 0xFF..F, else if tt3 >= 0 then mask = 0x00..0
  143. for (i = 0; i < NWORDS_FIELD; i++)
  144. {
  145. ADDC(borrow, tt3[NWORDS_FIELD + i], ((digit_t *)PRIME)[i] & mask, borrow, tt3[NWORDS_FIELD + i]);
  146. }
  147. rdc_mont(tt3, c[0]); // c[0] = a0*b0 - a1*b1
  148. mp_addfastx2(tt1, tt2, tt1); // tt1 = a0*b0 + a1*b1
  149. mp_mul(t1, t2, tt2, NWORDS_FIELD); // tt2 = (a0+a1)*(b0+b1)
  150. mp_subfast(tt2, tt1, tt2); // tt2 = (a0+a1)*(b0+b1) - a0*b0 - a1*b1
  151. rdc_mont(tt2, c[1]); // c[1] = (a0+a1)*(b0+b1) - a0*b0 - a1*b1
  152. //a1*b0+a0*b1
  153. }
  154. void fpinv_chain_mont(felm_t a)
  155. { // Chain to compute a^(p-3)/4 using Montgomery arithmetic.
  156. unsigned int i, j;
  157. felm_t t[27], tt;
  158. // Precomputed table
  159. fpsqr_mont(a, tt);
  160. fpmul_mont(a, tt, t[0]);
  161. fpmul_mont(t[0], tt, t[1]);
  162. fpmul_mont(t[1], tt, t[2]);
  163. fpmul_mont(t[2], tt, t[3]);
  164. fpmul_mont(t[3], tt, t[3]);
  165. for (i = 3; i <= 8; i++)
  166. fpmul_mont(t[i], tt, t[i + 1]);
  167. fpmul_mont(t[9], tt, t[9]);
  168. for (i = 9; i <= 20; i++)
  169. fpmul_mont(t[i], tt, t[i + 1]);
  170. fpmul_mont(t[21], tt, t[21]);
  171. for (i = 21; i <= 24; i++)
  172. fpmul_mont(t[i], tt, t[i + 1]);
  173. fpmul_mont(t[25], tt, t[25]);
  174. fpmul_mont(t[25], tt, t[26]);
  175. fpcopy(a, tt);
  176. for (i = 0; i < 6; i++)
  177. fpsqr_mont(tt, tt);
  178. fpmul_mont(t[20], tt, tt);
  179. for (i = 0; i < 6; i++)
  180. fpsqr_mont(tt, tt);
  181. fpmul_mont(t[24], tt, tt);
  182. for (i = 0; i < 6; i++)
  183. fpsqr_mont(tt, tt);
  184. fpmul_mont(t[11], tt, tt);
  185. for (i = 0; i < 6; i++)
  186. fpsqr_mont(tt, tt);
  187. fpmul_mont(t[8], tt, tt);
  188. for (i = 0; i < 8; i++)
  189. fpsqr_mont(tt, tt);
  190. fpmul_mont(t[2], tt, tt);
  191. for (i = 0; i < 6; i++)
  192. fpsqr_mont(tt, tt);
  193. fpmul_mont(t[23], tt, tt);
  194. for (i = 0; i < 6; i++)
  195. fpsqr_mont(tt, tt);
  196. fpmul_mont(t[2], tt, tt);
  197. for (i = 0; i < 9; i++)
  198. fpsqr_mont(tt, tt);
  199. fpmul_mont(t[2], tt, tt);
  200. for (i = 0; i < 10; i++)
  201. fpsqr_mont(tt, tt);
  202. fpmul_mont(t[15], tt, tt);
  203. for (i = 0; i < 8; i++)
  204. fpsqr_mont(tt, tt);
  205. fpmul_mont(t[13], tt, tt);
  206. for (i = 0; i < 8; i++)
  207. fpsqr_mont(tt, tt);
  208. fpmul_mont(t[26], tt, tt);
  209. for (i = 0; i < 8; i++)
  210. fpsqr_mont(tt, tt);
  211. fpmul_mont(t[20], tt, tt);
  212. for (i = 0; i < 6; i++)
  213. fpsqr_mont(tt, tt);
  214. fpmul_mont(t[11], tt, tt);
  215. for (i = 0; i < 6; i++)
  216. fpsqr_mont(tt, tt);
  217. fpmul_mont(t[10], tt, tt);
  218. for (i = 0; i < 6; i++)
  219. fpsqr_mont(tt, tt);
  220. fpmul_mont(t[14], tt, tt);
  221. for (i = 0; i < 6; i++)
  222. fpsqr_mont(tt, tt);
  223. fpmul_mont(t[4], tt, tt);
  224. for (i = 0; i < 10; i++)
  225. fpsqr_mont(tt, tt);
  226. fpmul_mont(t[18], tt, tt);
  227. for (i = 0; i < 6; i++)
  228. fpsqr_mont(tt, tt);
  229. fpmul_mont(t[1], tt, tt);
  230. for (i = 0; i < 7; i++)
  231. fpsqr_mont(tt, tt);
  232. fpmul_mont(t[22], tt, tt);
  233. for (i = 0; i < 10; i++)
  234. fpsqr_mont(tt, tt);
  235. fpmul_mont(t[6], tt, tt);
  236. for (i = 0; i < 7; i++)
  237. fpsqr_mont(tt, tt);
  238. fpmul_mont(t[24], tt, tt);
  239. for (i = 0; i < 6; i++)
  240. fpsqr_mont(tt, tt);
  241. fpmul_mont(t[9], tt, tt);
  242. for (i = 0; i < 8; i++)
  243. fpsqr_mont(tt, tt);
  244. fpmul_mont(t[18], tt, tt);
  245. for (i = 0; i < 6; i++)
  246. fpsqr_mont(tt, tt);
  247. fpmul_mont(t[17], tt, tt);
  248. for (i = 0; i < 8; i++)
  249. fpsqr_mont(tt, tt);
  250. fpmul_mont(a, tt, tt);
  251. for (i = 0; i < 10; i++)
  252. fpsqr_mont(tt, tt);
  253. fpmul_mont(t[16], tt, tt);
  254. for (i = 0; i < 6; i++)
  255. fpsqr_mont(tt, tt);
  256. fpmul_mont(t[7], tt, tt);
  257. for (i = 0; i < 6; i++)
  258. fpsqr_mont(tt, tt);
  259. fpmul_mont(t[0], tt, tt);
  260. for (i = 0; i < 7; i++)
  261. fpsqr_mont(tt, tt);
  262. fpmul_mont(t[12], tt, tt);
  263. for (i = 0; i < 7; i++)
  264. fpsqr_mont(tt, tt);
  265. fpmul_mont(t[19], tt, tt);
  266. for (i = 0; i < 6; i++)
  267. fpsqr_mont(tt, tt);
  268. fpmul_mont(t[22], tt, tt);
  269. for (i = 0; i < 6; i++)
  270. fpsqr_mont(tt, tt);
  271. fpmul_mont(t[25], tt, tt);
  272. for (i = 0; i < 7; i++)
  273. fpsqr_mont(tt, tt);
  274. fpmul_mont(t[2], tt, tt);
  275. for (i = 0; i < 6; i++)
  276. fpsqr_mont(tt, tt);
  277. fpmul_mont(t[10], tt, tt);
  278. for (i = 0; i < 7; i++)
  279. fpsqr_mont(tt, tt);
  280. fpmul_mont(t[22], tt, tt);
  281. for (i = 0; i < 8; i++)
  282. fpsqr_mont(tt, tt);
  283. fpmul_mont(t[18], tt, tt);
  284. for (i = 0; i < 6; i++)
  285. fpsqr_mont(tt, tt);
  286. fpmul_mont(t[4], tt, tt);
  287. for (i = 0; i < 6; i++)
  288. fpsqr_mont(tt, tt);
  289. fpmul_mont(t[14], tt, tt);
  290. for (i = 0; i < 7; i++)
  291. fpsqr_mont(tt, tt);
  292. fpmul_mont(t[13], tt, tt);
  293. for (i = 0; i < 6; i++)
  294. fpsqr_mont(tt, tt);
  295. fpmul_mont(t[5], tt, tt);
  296. for (i = 0; i < 6; i++)
  297. fpsqr_mont(tt, tt);
  298. fpmul_mont(t[23], tt, tt);
  299. for (i = 0; i < 6; i++)
  300. fpsqr_mont(tt, tt);
  301. fpmul_mont(t[21], tt, tt);
  302. for (i = 0; i < 6; i++)
  303. fpsqr_mont(tt, tt);
  304. fpmul_mont(t[2], tt, tt);
  305. for (i = 0; i < 7; i++)
  306. fpsqr_mont(tt, tt);
  307. fpmul_mont(t[23], tt, tt);
  308. for (i = 0; i < 8; i++)
  309. fpsqr_mont(tt, tt);
  310. fpmul_mont(t[12], tt, tt);
  311. for (i = 0; i < 6; i++)
  312. fpsqr_mont(tt, tt);
  313. fpmul_mont(t[9], tt, tt);
  314. for (i = 0; i < 6; i++)
  315. fpsqr_mont(tt, tt);
  316. fpmul_mont(t[3], tt, tt);
  317. for (i = 0; i < 7; i++)
  318. fpsqr_mont(tt, tt);
  319. fpmul_mont(t[13], tt, tt);
  320. for (i = 0; i < 7; i++)
  321. fpsqr_mont(tt, tt);
  322. fpmul_mont(t[17], tt, tt);
  323. for (i = 0; i < 8; i++)
  324. fpsqr_mont(tt, tt);
  325. fpmul_mont(t[26], tt, tt);
  326. for (i = 0; i < 8; i++)
  327. fpsqr_mont(tt, tt);
  328. fpmul_mont(t[5], tt, tt);
  329. for (i = 0; i < 8; i++)
  330. fpsqr_mont(tt, tt);
  331. fpmul_mont(t[8], tt, tt);
  332. for (i = 0; i < 6; i++)
  333. fpsqr_mont(tt, tt);
  334. fpmul_mont(t[2], tt, tt);
  335. for (i = 0; i < 6; i++)
  336. fpsqr_mont(tt, tt);
  337. fpmul_mont(t[11], tt, tt);
  338. for (i = 0; i < 7; i++)
  339. fpsqr_mont(tt, tt);
  340. fpmul_mont(t[20], tt, tt);
  341. for (j = 0; j < 61; j++)
  342. {
  343. for (i = 0; i < 6; i++)
  344. fpsqr_mont(tt, tt);
  345. fpmul_mont(t[26], tt, tt);
  346. }
  347. fpcopy(tt, a);
  348. }
  349. void fp2inv_mont(f2elm_t a)
  350. { // GF(p^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2).
  351. f2elm_t t1;
  352. fpsqr_mont(a[0], t1[0]); // t10 = a0^2
  353. fpsqr_mont(a[1], t1[1]); // t11 = a1^2
  354. fpadd(t1[0], t1[1], t1[0]); // t10 = a0^2+a1^2
  355. fpinv_mont(t1[0]); // t10 = (a0^2+a1^2)^-1
  356. fpneg(a[1]); // a = a0-i*a1
  357. fpmul_mont(a[0], t1[0], a[0]);
  358. fpmul_mont(a[1], t1[0], a[1]); // a = (a0-i*a1)*(a0^2+a1^2)^-1
  359. }
  360. void to_fp2mont(const f2elm_t a, f2elm_t mc)
  361. { // Conversion of a GF(p^2) element to Montgomery representation,
  362. // mc_i = a_i*R^2*R^(-1) = a_i*R in GF(p^2).
  363. to_mont(a[0], mc[0]);
  364. to_mont(a[1], mc[1]);
  365. }
  366. void from_fp2mont(const f2elm_t ma, f2elm_t c)
  367. { // Conversion of a GF(p^2) element from Montgomery representation to standard representation,
  368. // c_i = ma_i*R^(-1) = a_i in GF(p^2).
  369. from_mont(ma[0], c[0]);
  370. from_mont(ma[1], c[1]);
  371. }
  372. __inline unsigned int mp_add(const digit_t *a, const digit_t *b, digit_t *c, const unsigned int nwords)
  373. { // Multiprecision addition, c = a+b, where lng(a) = lng(b) = nwords. Returns the carry bit.
  374. unsigned int i, carry = 0;
  375. for (i = 0; i < nwords; i++)
  376. {
  377. ADDC(carry, a[i], b[i], carry, c[i]);
  378. }
  379. return carry;
  380. }
  381. void mp_shiftleft(digit_t *x, unsigned int shift, const unsigned int nwords)
  382. {
  383. unsigned int i, j = 0;
  384. while (shift > RADIX)
  385. {
  386. j += 1;
  387. shift -= RADIX;
  388. }
  389. for (i = 0; i < nwords - j; i++)
  390. x[nwords - 1 - i] = x[nwords - 1 - i - j];
  391. for (i = nwords - j; i < nwords; i++)
  392. x[nwords - 1 - i] = 0;
  393. if (shift != 0)
  394. {
  395. for (j = nwords - 1; j > 0; j--)
  396. SHIFTL(x[j], x[j - 1], shift, x[j], RADIX);
  397. x[0] <<= shift;
  398. }
  399. }
  400. void mp_shiftr1(digit_t *x, const unsigned int nwords)
  401. { // Multiprecision right shift by one.
  402. unsigned int i;
  403. for (i = 0; i < nwords - 1; i++)
  404. {
  405. SHIFTR(x[i + 1], x[i], 1, x[i], RADIX);
  406. }
  407. x[nwords - 1] >>= 1;
  408. }
  409. void mp_shiftl1(digit_t *x, const unsigned int nwords)
  410. { // Multiprecision left shift by one.
  411. int i;
  412. for (i = nwords - 1; i > 0; i--)
  413. {
  414. SHIFTL(x[i], x[i - 1], 1, x[i], RADIX);
  415. }
  416. x[0] <<= 1;
  417. }