pollardrho.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. /**
  2. * \file pollardrho.c
  3. *
  4. * \brief Pollard's ρ factorization method.
  5. *
  6. * This file contains two implementations of the pollard's ρ algorithm, used in
  7. * order to attempt a factorization of N.
  8. */
  9. #include <openssl/rsa.h>
  10. #include <qa/questions/qarith.h>
  11. #include <qa/questions/questions.h>
  12. #define ATTEMPTS 20
  13. static inline void f(BIGNUM *y, BIGNUM *n, BN_CTX *ctx)
  14. {
  15. /* y ← f(y) = y² + 1 (mod N) */
  16. BN_mod_sqr(y, y, n, ctx);
  17. BN_uiadd1(y);
  18. }
  19. /*
  20. * \brief Pollard-Brent variant of the ρ factorization.
  21. *
  22. * This algorithm shall be around 24% fasted discovering the cyclic part.
  23. * Moreover, gcd is computed on the accoumulated value q, which makes it even
  24. * just awesome.
  25. */
  26. static RSA*
  27. pollardbrent_question_ask_rsa(const RSA *rsa)
  28. {
  29. RSA *ret = NULL;
  30. BIGNUM
  31. *x = BN_new(),
  32. *y = BN_new(),
  33. *ys = BN_new(),
  34. *r = BN_new(),
  35. *q = BN_new(),
  36. *g = BN_new(),
  37. *i = BN_new(),
  38. *j = BN_new(),
  39. *m = BN_new(),
  40. *k = BN_new(),
  41. *diff = BN_new();
  42. BN_CTX *ctx = BN_CTX_new();
  43. int lim;
  44. BN_one(r);
  45. BN_one(q);
  46. BN_one(g);
  47. BN_dec2bn(&m, "100");
  48. BN_pseudo_rand_range(y, rsa->n);
  49. for (lim = ATTEMPTS; BN_is_one(g) && lim; lim--) {
  50. BN_copy(x, y);
  51. for (BN_copy(i, r);
  52. !BN_is_zero(i);
  53. BN_sub(i, i, BN_value_one()))
  54. f(y, rsa->n, ctx);
  55. for (BN_zero(k);
  56. BN_cmp(k, r) < 1 && BN_is_one(g);
  57. BN_add(k, k, m)) {
  58. BN_copy(ys, y);
  59. BN_sub(diff, r, k);
  60. for (BN_copy(j, BN_min(m, diff));
  61. !BN_is_zero(j);
  62. BN_sub(j, j, BN_value_one())) {
  63. f(y, rsa->n, ctx);
  64. /* q ← q * |x-y| */
  65. BN_sub(diff, x, y);
  66. BN_abs(diff);
  67. BN_mod_mul(q, q, diff, rsa->n, ctx);
  68. }
  69. BN_gcd(g, q, rsa->n, ctx);
  70. }
  71. BN_lshift1(r,r);
  72. }
  73. if (!BN_cmp(g, rsa->n)) do {
  74. f(ys, rsa->n, ctx);
  75. BN_sub(diff, x, ys);
  76. BN_abs(diff);
  77. BN_gcd(g, diff, rsa->n, ctx);
  78. } while (BN_is_one(g));
  79. if (!BN_is_one(g) && BN_cmp(g, rsa->n))
  80. ret = qa_RSA_recover(rsa, g, ctx);
  81. BN_free(diff);
  82. BN_free(x);
  83. BN_free(k);
  84. BN_free(m);
  85. BN_free(y);
  86. BN_free(ys);
  87. BN_free(r);
  88. BN_free(q);
  89. BN_free(g);
  90. BN_free(i);
  91. return ret;
  92. }
  93. /**
  94. * \brief Pollard's ρ factorization.
  95. *
  96. * This is the naïve implementation of pollard's ρ factorization employing
  97. * Floyd's cycle finding algorithm.
  98. *
  99. */
  100. static RSA*
  101. pollardrho_question_ask_rsa(const RSA *rsa)
  102. {
  103. RSA *ret = NULL;
  104. BIGNUM
  105. *x = NULL,
  106. *y = NULL;
  107. BIGNUM *n;
  108. BIGNUM *tmp;
  109. BIGNUM *gcd;
  110. BN_CTX *ctx;
  111. ctx = BN_CTX_new();
  112. gcd = BN_new();
  113. x = BN_new();
  114. y = BN_new();
  115. tmp = BN_new();
  116. n = rsa->n;
  117. /* initialization */
  118. BN_one(gcd);
  119. BN_pseudo_rand(x, 512, 0, 0);
  120. BN_copy(y, x);
  121. while (BN_is_one(gcd)) {
  122. /* x ← x² + 1 (mod N) */
  123. BN_mod_sqr(x, x, n, ctx);
  124. BN_uiadd1(x);
  125. /* y ← y⁴ + 2y² + 2 (mod N) */
  126. BN_mod_sqr(tmp, y, n, ctx);
  127. BN_mod_sqr(y, tmp, n, ctx);
  128. BN_lshift1(tmp, tmp);
  129. BN_mod_add(y, y, tmp, n, ctx);
  130. BN_mod_add(y, y, BN_value_two(), n, ctx);
  131. /* gcd(|x-y|, N) */
  132. BN_mod_sub(tmp, x, y, n, ctx);
  133. BN_gcd(gcd, tmp, n, ctx);
  134. }
  135. if (BN_ucmp(gcd, n) != 0)
  136. ret = qa_RSA_recover(rsa, gcd, ctx);
  137. BN_free(tmp);
  138. BN_free(x);
  139. BN_free(y);
  140. BN_free(gcd);
  141. return ret;
  142. }
  143. qa_question_t PollardRhoQuestion = {
  144. .name = "pollardrho",
  145. .pretty_name = "Pollard's ρ factorization",
  146. .ask_rsa = pollardrho_question_ask_rsa
  147. };
  148. qa_question_t PollardBrentRhoQuestion = {
  149. .name = "pollard-brent",
  150. .pretty_name = "Pollard-Brent's ρ factorization",
  151. .ask_rsa = pollardbrent_question_ask_rsa
  152. };