📜  素数分解的Pollard Rho算法

📅  最后修改于: 2021-05-05 02:01:03             🧑  作者: Mango

给定一个正整数n ,并且它是复合的,找到它的除数。
例子:

Input: n = 12;
Output: 2 [OR 3 OR 4]

Input: n = 187;
Output: 11 [OR 17]

暴力破解方法:测试所有小于n的整数,直到找到除数。
即兴:测试所有小于√n的整数
足够多的数量仍然意味着大量工作。 Pollard的Rho是素数分解算法,对于具有较小素数的大量复合数尤其快速。 Rho算法最显着的成功是第八个费马数的因式分解:1238926361552897 * 9346163971535797776916355819960689658405123754163818858020321。
Rho算法是一个不错的选择,因为第一个素数要比另一个小得多。
Pollard的Rho算法中使用的概念:

  1. 如果两个数字x和y相等,则称n为模(x = y模n),如果
    1. 它们的绝对差是n,OR的整数倍
    2. 当除以n时,它们每个都留下相同的余数。
  2. 最大公因数是最大的数,该数被均分为每个原始数。
  3. 生日悖论:即使对于一小群人,两个人拥有相同生日的概率也异常高。
  4. 弗洛伊德(Floyd)的循环查找算法:如果乌龟和野兔从同一点开始并以一个周期运动,以致野兔速度是乌龟速度的两倍,则它们必须在某个点相遇。

算法

  1. 从随机的x和c开始。取y等于x且f(x)= x 2 + c。
  2. 虽然没有获得除数
    1. 将x更新为f(x)(模n)[乌龟移动]
    2. 将y更新为f(f(y))(模n)[野兔移动]
    3. 计算| xy |的GCD和n
    4. 如果GCD不统一
      1. 如果GCD为n,则从步骤2开始重复另一组x,y和c
      2. 其他GCD是我们的答案

插图:
让我们假设n = 187,并针对不同的随机值考虑不同的情况。

  1. 一个使算法找到结果的随机值示例:
    y = x = 2且c = 1,因此,我们的f(x)= x 2 + 1。

PollardRho1

  1. 随机值的示例,以使算法更快地找到结果
    y = x = 110且’c’=183。因此,我们的f(x)= x 2 + 183。

桌子

  1. 使得算法找不到结果的随机值示例:
    x = y = 147,c =67。因此,我们的f(x)= x 2 + 67。

PollardRho3

下面是上述算法的C / C++实现:

C++
/* C++ program to find a prime factor of composite using
   Pollard's Rho algorithm */
#include
using namespace std;
 
/* Function to calculate (base^exponent)%modulus */
long long int modular_pow(long long int base, int exponent,
                          long long int modulus)
{
    /* initialize result */
    long long int result = 1;
 
    while (exponent > 0)
    {
        /* if y is odd, multiply base with result */
        if (exponent & 1)
            result = (result * base) % modulus;
 
        /* exponent = exponent/2 */
        exponent = exponent >> 1;
 
        /* base = base * base */
        base = (base * base) % modulus;
    }
    return result;
}
 
/* method to return prime divisor for n */
long long int PollardRho(long long int n)
{
    /* initialize random seed */
    srand (time(NULL));
 
    /* no prime divisor for 1 */
    if (n==1) return n;
 
    /* even number means one of the divisors is 2 */
    if (n % 2 == 0) return 2;
 
    /* we will pick from the range [2, N) */
    long long int x = (rand()%(n-2))+2;
    long long int y = x;
 
    /* the constant in f(x).
     * Algorithm can be re-run with a different c
     * if it throws failure for a composite. */
    long long int c = (rand()%(n-1))+1;
 
    /* Initialize candidate divisor (or result) */
    long long int d = 1; 
 
    /* until the prime factor isn't obtained.
       If n is prime, return n */
    while (d==1)
    {
        /* Tortoise Move: x(i+1) = f(x(i)) */
        x = (modular_pow(x, 2, n) + c + n)%n;
 
        /* Hare Move: y(i+1) = f(f(y(i))) */
        y = (modular_pow(y, 2, n) + c + n)%n;
        y = (modular_pow(y, 2, n) + c + n)%n;
 
        /* check gcd of |x-y| and n */
        d = __gcd(abs(x-y), n);
 
        /* retry if the algorithm fails to find prime factor
         * with chosen x and c */
        if (d==n) return PollardRho(n);
    }
 
    return d;
}
 
/* driver function */
int main()
{
    long long int n = 10967535067;
    printf("One of the divisors for %lld is %lld.",
          n, PollardRho(n));
    return 0;
}


Java
/* Java program to find a prime factor of composite using
   Pollard's Rho algorithm */
import java.util.*;
 
class GFG{
 
/* Function to calculate (base^exponent)%modulus */
static long  modular_pow(long  base, int exponent,
                          long  modulus)
{
    /* initialize result */
    long  result = 1;
 
    while (exponent > 0)
    {
        /* if y is odd, multiply base with result */
        if (exponent % 2 == 1)
            result = (result * base) % modulus;
 
        /* exponent = exponent/2 */
        exponent = exponent >> 1;
 
        /* base = base * base */
        base = (base * base) % modulus;
    }
    return result;
}
 
/* method to return prime divisor for n */
static long  PollardRho(long  n)
{
    /* initialize random seed */
    Random rand = new Random();
 
    /* no prime divisor for 1 */
    if (n == 1) return n;
 
    /* even number means one of the divisors is 2 */
    if (n % 2 == 0) return 2;
 
    /* we will pick from the range [2, N) */
    long  x = (long)(rand.nextLong() % (n - 2)) + 2;
    long  y = x;
 
    /* the constant in f(x).
     * Algorithm can be re-run with a different c
     * if it throws failure for a composite. */
    long  c = (long)(rand.nextLong()) % (n - 1) + 1;
 
    /* Initialize candidate divisor (or result) */
    long  d = 1L; 
 
    /* until the prime factor isn't obtained.
       If n is prime, return n */
    while (d == 1)
    {
        /* Tortoise Move: x(i+1) = f(x(i)) */
        x = (modular_pow(x, 2, n) + c + n) % n;
 
        /* Hare Move: y(i+1) = f(f(y(i))) */
        y = (modular_pow(y, 2, n) + c + n) % n;
        y = (modular_pow(y, 2, n) + c + n) % n;
 
        /* check gcd of |x-y| and n */
        d = __gcd(Math.abs(x - y), n);
 
        /* retry if the algorithm fails to find prime factor
         * with chosen x and c */
        if (d == n) return PollardRho(n);
    }
 
    return d;
}
   
// Recursive function to return gcd of a and b 
static long __gcd(long a, long b) 
{ 
 return b == 0? a:__gcd(b, a % b);    
}
 
/* driver function */
public static void main(String[] args)
{
    long n = 10967535067L;
    System.out.printf("One of the divisors for " + n + " is " +
          PollardRho(n));
}
}
 
// This code contributed by aashish1995


Python3
# Python 3 program to find a prime factor of composite using
# Pollard's Rho algorithm
import random
import math
 
# Function to calculate (base^exponent)%modulus
def modular_pow(base, exponent,modulus):
 
    # initialize result
    result = 1
 
    while (exponent > 0):
     
        # if y is odd, multiply base with result
        if (exponent & 1):
            result = (result * base) % modulus
 
        # exponent = exponent/2
        exponent = exponent >> 1
 
        # base = base * base
        base = (base * base) % modulus
     
    return result
 
# method to return prime divisor for n
def PollardRho( n):
 
    # no prime divisor for 1
    if (n == 1):
        return n
 
    # even number means one of the divisors is 2
    if (n % 2 == 0):
        return 2
 
    # we will pick from the range [2, N)
    x = (random.randint(0, 2) % (n - 2))
    y = x
 
    # the constant in f(x).
    # Algorithm can be re-run with a different c
    # if it throws failure for a composite.
    c = (random.randint(0, 1) % (n - 1))
 
    # Initialize candidate divisor (or result)
    d = 1
 
    # until the prime factor isn't obtained.
    # If n is prime, return n
    while (d == 1):
     
        # Tortoise Move: x(i+1) = f(x(i))
        x = (modular_pow(x, 2, n) + c + n)%n
 
        # Hare Move: y(i+1) = f(f(y(i)))
        y = (modular_pow(y, 2, n) + c + n)%n
        y = (modular_pow(y, 2, n) + c + n)%n
 
        # check gcd of |x-y| and n
        d = math.gcd(abs(x - y), n)
 
        # retry if the algorithm fails to find prime factor
        # with chosen x and c
        if (d == n):
            return PollardRho(n)
     
    return d
 
# Driver function
if __name__ == "__main__":
 
    n = 10967535067
    print("One of the divisors for", n , "is ",PollardRho(n))
     
# This code is contributed by chitranayal


C#
/* C# program to find a prime factor of composite using
   Pollard's Rho algorithm */
using System;
class GFG
{
 
/* Function to calculate (base^exponent)%modulus */
static long  modular_pow(long  _base, int exponent,
                          long  modulus)
{
   
    /* initialize result */
    long  result = 1;
 
    while (exponent > 0)
    {
       
        /* if y is odd, multiply base with result */
        if (exponent % 2 == 1)
            result = (result * _base) % modulus;
 
        /* exponent = exponent/2 */
        exponent = exponent >> 1;
 
        /* base = base * base */
       _base = (_base * _base) % modulus;
    }
    return result;
}
 
/* method to return prime divisor for n */
static long  PollardRho(long  n)
{
   
    /* initialize random seed */
    Random rand = new Random();
 
    /* no prime divisor for 1 */
    if (n == 1) return n;
 
    /* even number means one of the divisors is 2 */
    if (n % 2 == 0) return 2;
 
    /* we will pick from the range [2, N) */
    long  x = (long)(rand.Next(0, -(int)n + 1));
    long  y = x;
 
    /* the constant in f(x).
     * Algorithm can be re-run with a different c
     * if it throws failure for a composite. */
    long  c = (long)(rand.Next(1, -(int)n));
 
    /* Initialize candidate divisor (or result) */
    long  d = 1L; 
 
    /* until the prime factor isn't obtained.
       If n is prime, return n */
    while (d == 1)
    {
       
        /* Tortoise Move: x(i+1) = f(x(i)) */
        x = (modular_pow(x, 2, n) + c + n) % n;
 
        /* Hare Move: y(i+1) = f(f(y(i))) */
        y = (modular_pow(y, 2, n) + c + n) % n;
        y = (modular_pow(y, 2, n) + c + n) % n;
 
        /* check gcd of |x-y| and n */
        d = __gcd(Math.Abs(x - y), n);
 
        /* retry if the algorithm fails to find prime factor
         * with chosen x and c */
        if (d == n) return PollardRho(n);
    }
 
    return d;
}
   
// Recursive function to return gcd of a and b 
static long __gcd(long a, long b) 
{ 
  return b == 0 ? a:__gcd(b, a % b);    
}
 
/* Driver code */
public static void Main(String[] args)
{
    long n = 10967535067L;
    Console.Write("One of the divisors for " + n + " is " +
          PollardRho(n));
}
}
 
// This code is contributed by aashish1995


Javascript


输出:

One of the divisors for 10967535067 is 104729

这是如何运作的?
n为复合数(非素数) 。由于n是复合的,因此它具有非平凡的因子f f <=√n 。
现在假设我们必须从[0,n-1]范围中选择两个数字x和y。我们唯一获得x = y模n的时间是x和y相同时。但是,由于f <√n,即使x和y不相同(生日悖论),也有很好的机会以x = y为模f。
我们首先从集合{0,1,…,n-1}中随机选择x进行替换,以形成序列s 1 ,s 2 ,s 3 i = s i mod f ,我们的序列现在每个&sacute;属于{0,1,…,f-1}。因为这两个集合都是有限的,所以最终两个集合中都会有一个重复的整数。我们希望在&sacute;中早日实现重复。 i ,因为f 我=&sacute; j代表i≠j,则s i = s j模d。因此| s i – s j |将是f的倍数。如上所述,n也是f的倍数。这意味着| s i – s j |的GCD。并且n将是f的正整数倍,也是我们的候选除数d!这里的要点是,我们只是知道n必须有一个约数,而且我们甚至都不在乎它的值。一旦我们命中了s i和s j (我们的最终x和y),则以s i开头的序列中的每个元素将与以s j开头的序列中的对应元素的模f为模,因此是一个循环。如果绘制序列s i的图,我们将观察到希腊字母Rho(ρ)的形状。
Rho算法的核心是获取随机值并评估GCD。为了减少昂贵的GCD计算,我们可以使用弗洛伊德(Floyd)的周期检测来实现Pollard的Rho(这可以通过乌龟比喻来理解,其中乌龟一次一次穿过每个元素,而兔子在同一点开始但移动速度是乌龟的两倍。我们将具有相同的多项式f(x),从随机x 0开始,y 0 = x 0 ,然后计算x i + 1 = f(x i )和y i + 1 = f(f(y i ) )。由于我们对d的了解不多,因此多项式的典型选择是f(x)= x 2 + c(取模n)(是的,“ c”也可以随机选择)。
笔记:

  1. 算法将对质数无限期运行。
  2. 该算法可能找不到因素并返回复合n的故障。在这种情况下,我们使用x,y和c的不同集合,然后重试。
  3. 上面的算法仅找到一个除数。为了找到一个素数,我们可以递归分解除数d,运行d和n / d的算法。周期长度通常约为√d。