Browse Source

Implementing Brent's variant for the ρ method.

Michele Orrù 11 years ago
parent
commit
497656b0ae
2 changed files with 106 additions and 1 deletions
  1. 1 0
      src/questions/allquestions.c
  2. 105 1
      src/questions/pollardrho.c

+ 1 - 0
src/questions/allquestions.c

@@ -47,4 +47,5 @@ void select_all_questions(void)
   REGISTER_QUESTION(PollardRhoQuestion);
   REGISTER_QUESTION(WilliamsQuestion);
   REGISTER_QUESTION(DixonQuestion);
+  REGISTER_QUESTION(PollardBrentRhoQuestion);
 }

+ 105 - 1
src/questions/pollardrho.c

@@ -13,6 +13,103 @@
 #include <qa/questions/questions.h>
 
 
+static inline void f(BIGNUM *y, BIGNUM *n, BN_CTX *ctx)
+{
+  /* y ← f(y) = y² + 1 (mod N) */
+  BN_mod_sqr(y, y, n, ctx);
+  BN_uiadd1(y);
+}
+
+/*
+ * \brief Pollard-Brent variant of the ρ factorization.
+ *
+ * This algorithm shall be around 24% fasted discovering the cyclic part.
+ * Moreover, gcd is computed on the accoumulated value q, which makes it even
+ * just awesome.
+ */
+static RSA*
+pollardbrent_question_ask_rsa(const RSA *rsa)
+{
+  RSA *ret = NULL;
+  BIGNUM
+    *x = BN_new(),
+    *y = BN_new(),
+    *ys = BN_new(),
+    *r = BN_new(),
+    *q = BN_new(),
+    *g = BN_new(),
+    *i = BN_new(),
+    *j = BN_new(),
+    *m = BN_new(),
+    *k = BN_new(),
+    *diff = BN_new();
+  BN_CTX *ctx = BN_CTX_new();
+
+
+  BN_one(r);
+  BN_one(q);
+  BN_one(g);
+  BN_dec2bn(&m, "100");
+  BN_pseudo_rand_range(y, rsa->n);
+
+  while (BN_is_one(g)) {
+    BN_copy(x, y);
+    for (BN_copy(i, r);
+         !BN_is_zero(i);
+         BN_sub(i, i, BN_value_one()))
+      f(y, rsa->n, ctx);
+
+    for (BN_zero(k);
+         BN_cmp(k, r) < 1 && BN_is_one(g);
+         BN_add(k, k, m)) {
+      BN_copy(ys, y);
+      BN_sub(diff, r, k);
+      for (BN_copy(j, BN_min(m, diff));
+           !BN_is_zero(j);
+           BN_sub(j, j, BN_value_one())) {
+        f(y, rsa->n, ctx);
+        /* q ← q * |x-y| */
+        BN_sub(diff, x, y);
+        BN_abs(diff);
+        BN_mod_mul(q, q, diff, rsa->n, ctx);
+      }
+      BN_gcd(g, q, rsa->n, ctx);
+    }
+    BN_lshift1(r,r);
+  }
+
+  if (!BN_cmp(g, rsa->n)) do {
+      f(ys, rsa->n, ctx);
+      BN_sub(diff, x, ys);
+      BN_abs(diff);
+      BN_gcd(g, diff, rsa->n, ctx);
+    } while (BN_is_one(g));
+
+  if (BN_cmp(g, rsa->n))
+    ret = qa_RSA_recover(rsa, g, ctx);
+
+
+  BN_free(diff);
+  BN_free(x);
+  BN_free(k);
+  BN_free(m);
+  BN_free(y);
+  BN_free(ys);
+  BN_free(r);
+  BN_free(q);
+  BN_free(g);
+  BN_free(i);
+
+  return ret;
+}
+
+/**
+ * \brief Pollard's ρ factorization.
+ *
+ * This is the naïve implementation of pollard's ρ factorization employing
+ * Floyd's cycle finding algorithm.
+ *
+ */
 static RSA*
 pollardrho_question_ask_rsa(const RSA *rsa)
 {
@@ -41,7 +138,7 @@ pollardrho_question_ask_rsa(const RSA *rsa)
   BN_one(two); BN_uiadd1(two);
 
 
-  while (!BN_cmp(gcd, BN_value_one())) {
+  while (BN_is_one(gcd)) {
     /* x ← x² + 1 (mod N) */
     BN_mod_sqr(x, x, n, ctx);
     BN_uiadd1(x);
@@ -72,3 +169,10 @@ qa_question_t PollardRhoQuestion = {
   .pretty_name = "Pollard's rho factorization",
   .ask_rsa = pollardrho_question_ask_rsa
 };
+
+
+qa_question_t PollardBrentRhoQuestion = {
+  .name = "pollard-brent",
+  .pretty_name = "Pollard-Brent's rho factorization",
+  .ask_rsa = pollardbrent_question_ask_rsa
+};