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

221 lines
5.5 KiB

  1. #include <string.h>
  2. #include <assert.h>
  3. #include "csidh.h"
  4. #include "rng.h"
  5. /* specific to p, should perhaps be somewhere else */
  6. const unsigned primes[num_primes] = {
  7. 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
  8. 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
  9. 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
  10. 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
  11. 317, 331, 337, 347, 349, 353, 359, 367, 373, 587,
  12. };
  13. const u512 four_sqrt_p = {{
  14. 0x85e2579c786882cf, 0x4e3433657e18da95, 0x850ae5507965a0b3, 0xa15bc4e676475964,
  15. }};
  16. const public_key base = {0}; /* A = 0 */
  17. void csidh_private(private_key *priv)
  18. {
  19. memset(&priv->e, 0, sizeof(priv->e));
  20. for (size_t i = 0; i < num_primes; ) {
  21. int8_t buf[64];
  22. randombytes(buf, sizeof(buf));
  23. for (size_t j = 0; j < sizeof(buf); ++j) {
  24. if (buf[j] <= max_exponent && buf[j] >= -max_exponent) {
  25. priv->e[i / 2] |= (buf[j] & 0xf) << i % 2 * 4;
  26. if (++i >= num_primes)
  27. break;
  28. }
  29. }
  30. }
  31. }
  32. /* compute [(p+1)/l] P for all l in our list of primes. */
  33. /* divide and conquer is much faster than doing it naively,
  34. * but uses more memory. */
  35. static void cofactor_multiples(proj *P, const proj *A, size_t lower, size_t upper)
  36. {
  37. assert(lower < upper);
  38. if (upper - lower == 1)
  39. return;
  40. size_t mid = lower + (upper - lower + 1) / 2;
  41. u512 cl = u512_1, cu = u512_1;
  42. for (size_t i = lower; i < mid; ++i)
  43. u512_mul3_64(&cu, &cu, primes[i]);
  44. for (size_t i = mid; i < upper; ++i)
  45. u512_mul3_64(&cl, &cl, primes[i]);
  46. xMUL(&P[mid], A, &P[lower], &cu);
  47. xMUL(&P[lower], A, &P[lower], &cl);
  48. cofactor_multiples(P, A, lower, mid);
  49. cofactor_multiples(P, A, mid, upper);
  50. }
  51. /* never accepts invalid keys. */
  52. bool validate(public_key const *in)
  53. {
  54. const proj A = {in->A, fp_1};
  55. do {
  56. proj P[num_primes];
  57. fp_random(&P->x);
  58. P->z = fp_1;
  59. /* maximal 2-power in p+1 */
  60. xDBL(P, &A, P);
  61. xDBL(P, &A, P);
  62. cofactor_multiples(P, &A, 0, num_primes);
  63. u512 order = u512_1;
  64. for (size_t i = num_primes - 1; i < num_primes; --i) {
  65. /* we only gain information if [(p+1)/l] P is non-zero */
  66. if (memcmp(&P[i].z, &fp_0, sizeof(fp))) {
  67. u512 tmp;
  68. u512_set(&tmp, primes[i]);
  69. xMUL(&P[i], &A, &P[i], &tmp);
  70. if (memcmp(&P[i].z, &fp_0, sizeof(fp)))
  71. /* P does not have order dividing p+1. */
  72. return false;
  73. u512_mul3_64(&order, &order, primes[i]);
  74. if (u512_sub3(&tmp, &four_sqrt_p, &order)) /* returns borrow */
  75. /* order > 4 sqrt(p), hence definitely supersingular */
  76. return true;
  77. }
  78. }
  79. /* P didn't have big enough order to prove supersingularity. */
  80. } while (1);
  81. }
  82. /* compute x^3 + Ax^2 + x */
  83. static void montgomery_rhs(fp *rhs, fp const *A, fp const *x)
  84. {
  85. fp tmp;
  86. *rhs = *x;
  87. fp_sq1(rhs);
  88. fp_mul3(&tmp, A, x);
  89. fp_add2(rhs, &tmp);
  90. fp_add2(rhs, &fp_1);
  91. fp_mul2(rhs, x);
  92. }
  93. /* totally not constant-time. */
  94. void action(public_key *out, public_key const *in, private_key const *priv)
  95. {
  96. u512 k[2];
  97. u512_set(&k[0], 4); /* maximal 2-power in p+1 */
  98. u512_set(&k[1], 4); /* maximal 2-power in p+1 */
  99. uint8_t e[2][num_primes];
  100. for (size_t i = 0; i < num_primes; ++i) {
  101. int8_t t = (int8_t) (priv->e[i / 2] << i % 2 * 4) >> 4;
  102. if (t > 0) {
  103. e[0][i] = t;
  104. e[1][i] = 0;
  105. u512_mul3_64(&k[1], &k[1], primes[i]);
  106. }
  107. else if (t < 0) {
  108. e[1][i] = -t;
  109. e[0][i] = 0;
  110. u512_mul3_64(&k[0], &k[0], primes[i]);
  111. }
  112. else {
  113. e[0][i] = 0;
  114. e[1][i] = 0;
  115. u512_mul3_64(&k[0], &k[0], primes[i]);
  116. u512_mul3_64(&k[1], &k[1], primes[i]);
  117. }
  118. }
  119. proj A = {in->A, fp_1};
  120. bool done[2] = {false, false};
  121. do {
  122. assert(!memcmp(&A.z, &fp_1, sizeof(fp)));
  123. proj P;
  124. fp_random(&P.x);
  125. P.z = fp_1;
  126. fp rhs;
  127. montgomery_rhs(&rhs, &A.x, &P.x);
  128. bool sign = !fp_issquare(&rhs);
  129. if (done[sign])
  130. continue;
  131. xMUL(&P, &A, &P, &k[sign]);
  132. done[sign] = true;
  133. for (size_t i = num_primes-1; i < num_primes; --i) { //changed loop direction
  134. if (e[sign][i]) {
  135. u512 cof = u512_1;
  136. for (size_t j = i - 1; j < num_primes; --j) //changed loop direction
  137. if (e[sign][j])
  138. u512_mul3_64(&cof, &cof, primes[j]);
  139. proj K;
  140. xMUL(&K, &A, &P, &cof);
  141. if (memcmp(&K.z, &fp_0, sizeof(fp))) {
  142. xISOG(&A, &P, &K, primes[i]);
  143. if (!--e[sign][i])
  144. u512_mul3_64(&k[sign], &k[sign], primes[i]);
  145. }
  146. }
  147. done[sign] &= !e[sign][i];
  148. }
  149. fp_inv(&A.z);
  150. fp_mul2(&A.x, &A.z);
  151. A.z = fp_1;
  152. } while (!(done[0] && done[1]));
  153. out->A = A.x;
  154. }
  155. /* includes public-key validation. */
  156. bool csidh(public_key *out, public_key const *in, private_key const *priv)
  157. {
  158. if (!validate(in)) {
  159. fp_random(&out->A);
  160. return false;
  161. }
  162. action(out, in, priv);
  163. return true;
  164. }