Pollard Rho在不太大的输入上崩溃

时间:2019-04-21 04:03:02

标签: c++ algorithm math gmp

我实现了wikipedia上给出的Pollard Rho算法

x ← 2; y ← 2; d ← 1
while d = 1:
    x ← g(x)
    y ← g(g(y))
    d ← gcd(|x - y|, n)
if d = n: 
    return failure
else:
    return d

大输入给出错误:

  

GNU MP:无法分配内存(大小= 4294950944)

这是我的实现方式

mpz_class factor(mpz_class num)
{
    mpz_class x(2), y(2), d(1);
    while(d == 1)
    {
        x = polynomial(x);
        y = polynomial(polynomial(y));
        mpz_class diff = x - y;
        if(diff < 0)
        {
            diff *= -1;
        }
        mpz_gcd(d.get_mpz_t(), diff.get_mpz_t(), num.get_mpz_t());
    }
    if(d == num)
    {
        return -1;//failure
    }
    else
    {
        return d;//found factor
    }
}

mpz_class polynomial (mpz_class x)
{
    return ((x * x) + 1);
}

它可以在121之类的输入上工作,但在5540987上崩溃。我做错了吗?有没有一种方法可以改善这一点,以便可以考虑这些数字?我见过some implementations似乎使用多项式((x*x)%N+c)%N(请注意,额外的mod n)。这样行得通,因为可以使用任何多项式吗?

1 个答案:

答案 0 :(得分:1)

具有两个模运算,这是多余的,但是除非其中的算法很快终止,否则让其中一个精确地解决数字爆炸的问题。

>
  

这项工作是因为可以使用任何多项式吗?

这有点微妙,将模运算扔进混合中并不是“任何多项式”的情况。关键在于算法寻找的是某个序列x[i]x[j]i != j的两个值,使得abs(x[i] - x[j])p的倍数(其中N = pqpq都不是1),或换句话说,abs(x[i] - x[j]) mod p = 0x[i] ≡ x[j] mod p。在这一点上,以p取模时,在序列中找到了一个周期,重要的是,如果x[i] != x[j]则它们的差是p的非零倍,从而有机会提取出一个至少如果N的差也不是N的倍数(在这种情况下,GCD的结果将是N本身,并且没有因素出现)。 / p>

因此,纯粹从数学上看,模量N步骤在理论上是不必要的,循环模量p的发生没有这种“帮助”。但这是可能N = pq,因此如果我们减少序列模数N,则其模数p的性质不会受到干扰,该算法仍然有效。除此之外,归约模N实际上非常重要,因为它阻止了所涉及的数字变得不切实际地变大,否则,这不仅会减慢算法的速度,而且最终会在实际(有限大小)的硬件上失败。 >

这有很多理论上的依据,实现起来非常简单,

mpz_class polynomial (mpz_class x, mpz_class num)
{
    return ((x * x) + 1) % num;
}