【问题标题】:Python Pollard P-1 factorizationPython Pollard P-1 分解
【发布时间】:2013-05-01 17:18:10
【问题描述】:

我正在尝试在 Python 中实现 Pollard 的 P-1 分解。请注意,Rho 方法有一些答案,但这个 p-1 是不同的,关于 p-1,我可以在这里为您提供的最好的答案是 wiki 和 Wolfram:

http://en.wikipedia.org/wiki/Pollard's_p_%E2%88%92_1_algorithm

http://mathworld.wolfram.com/Pollardp-1FactorizationMethod.html

这是从 n 中分解出一些东西,但始终找不到 p。 np 和 sp 分别来自 numpy 和 scipy。所以 sp.uint64 的内置函数是一个 unsigned long 64 int (因为预期整数的大小),而 np.prod(p) 是列表 p 的累积乘积 pi:

def pm1_attack(n,b):
  p = [2,3,5,7,11,13,17]; i=19; a=2
  while i<b:
    if is_prime(i,10): p.append(i)
    i+=2;
  k = sp.uint64(np.prod(p)); q = power2(a,k,n)
  g = euc_al_i((q-1),n)
  print "product pi: ",k
  print "q: ",q
  print "g: ",g
  #return a

print "pollard_pm1_attack(n,b): ",pollard_pm1_attack(n,2000)

输出没有找到p:

Python 2.7 (r27:82525, Jul  4 2010, 09:01:59) [MSC v.1500 32 bit (Intel)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>> 
p = 1300199 
q = 2063507 

euler_totient = 2682966374188 

common n = 2682969737893 


public key e = 1588051820871 

secret key d = 2410616084843 

cleartext message = test 

encoded message = 1489995542681 

decoded message = test 

check_rsa = Successful encryption and decrytion. Message is authenticated. 

pollard_pm1_attack(n,b):  product pi:  18446744073460481730
q:  2391570546599
g:  1
None
>>> 

我正在学习 Python,所以可能是一些简单的错误。 power2() 函数使用平方求幂,基本上是一个超大整数的超强 pow()。 euc_al_i() 只是 gcd。你可以使用任何你喜欢的 gcd(),但是因为我正在学习我想自己做这些。

我正试图找出这里出了什么可怕的错误,以至于它甚至无法从相对较小的 n(小至 20 位长度)中找到 p。

【问题讨论】:

    标签: python primes prime-factoring factorization


    【解决方案1】:

    我不知道np.prodsp.uint64是做什么的,但是我可以告诉你p-1算法,由约翰·波拉德于 1974 年发明。

    Pollard 的算法基于费马小定理 a ^ p == a (mod p),其中当 a != 0 可以表述为 a ^ (p - 1) == 1 (mod p ) 通过将 a 除以表达式。因此,如果 p - 1 整除 m,则 p 整除 gcd(2^m - 1, n)。 Pollard 的 p - 1 算法将 m 计算为小于界限 b 的整数的最小公倍数,因此如果 b 的所有因子em>p - 1 小于 b,则 gcd(2 ^ lcm(1..b) - 1, n) 是 n 的一个因数。最小公倍数的计算方法是将小于 b 的素数乘以小于 b 的素数:

    function pminus1(n, b)
        c := 2
        for p in primes(b)
            pp := p
            while pp < b
                c := powerMod(c, p, n)
                pp := pp * p
        g := gcd(c-1, n)
        if 1 < g < n return g
        error "factorization failed"
    

    可选的第二阶段搜索 b1b2 之间的“大素数”,它与第一阶段的最小公倍数结合以找到一个因子。第二阶段只需要对每个素数进行模乘,而不是模幂运算,因此速度非常快,并且第二阶段的 gcd 可以批量计算。缓存虽小,但对函数的效率很重要。

    function pminus1(n, b1, b2)
        c := 2
        for p in primes(b1)
            pp := p
            while pp < b
                c := powerMod(c, p, n)
                pp := pp * p
        g := gcd(c-1, n)
        if 1 < g < n return g
        k := 0
        for q in primes(b1, b2)
            d := q - p
            if d is not in cache
                x := powerMod(c, d, n)
                store d, x in cache
            c := (c * x(d)) % n
            p := q
            k := k + 1
            if k % 100 == 0
                g := gcd(c-1, n)
                if 1 < g < n return g
        g := gcd(c-1, n)
        if 1 < g < n return g
        error "factorization failed"
    

    有可能Pollard的p-1方法可能找不到n的因子;它取决于 n - 1 的因式分解和您选择的边界。检查的方法是自己因子n - 1,然后用大于n的最大因子的b调用Pollard的方法 - 1. 例如,如果您想分解 n = 87463 = 149 * 587,请注意 n - 1 = 87462 = 2 * 3 * 3 * 43 * 113,所以调用 b = 120 的单阶段算法或 b1 = 50 和 b2 = 120 的两阶段算法,看看你是否找到一个因素。

    我在my blog 讨论了 Pollard 的 p - 1 分解算法以及其他几种分解算法。我还提供了 powerMod 和 gcd 函数的实现,以防您在实现这些函数时遇到问题。我用 Python 在http://ideone.com/wdyjxK 写了一个简单的单阶段算法实现。

    【讨论】:

    • 如果您使用 np.prod 计算素数的乘积小于当前界限,那么问题在于它没有考虑素数的多重性。例如,对于 87463,n-1 的因式分解包括 3^2,但您在计算最小公倍数时只包括了一个因数 3。
    • 太棒了!这解决了我对算法本身的一些疑问。伪代码和示例代码真的很重要。我编辑解释了您不确定的内置 np 和 sp 函数。我不确定我哪里出错了……在 n=2867396366521 上尝试了你的错误并得到了这个错误 --- sieve = [True] * n OverflowError: cannot fit 'long' into an index-sized integer ---但基本算法在这里很重要,你的解释解决了我错过的问题,所以这只是处理非常大的 int 的问题,这只是一个技术问题。
    • @stackuser:要分解 n = 2867396366521,您需要 b1=50 和 b2=b1*10^6,这意味着 p-1 不是分解 n 的首选算法。试试 Pollard 的 rho 算法。一般来说,您可能想先尝试除法到 1000,以获得唾手可得的果实,然后使用一百万步 Pollard 的 rho 算法作为因式分解函数的主力,然后是 Pollard 的 p-1 算法,它可能会找到一个当 n-1 在小范围内平滑时的幸运因素。之后是椭圆曲线或二次筛。关键是在每个步骤中使用适当的分解方法。
    • 我有一个问题:该算法的维基百科页面说,如果我们在获取 GCD 后以 N 结束,那么我们应该减少界限(因为这意味着所有因素都是幂次平滑的,所以我们需要回到一个不是的地方)。但是如果我们使用模幂来计算乘积,我们不会失去这样做的能力吗?还是c == 0 在这种情况下?
    • @Thomas:模幂运算与失去任何能力无关。而且你不应该设置c = 0,因为那样一切都将永远为零。如果您找到的因子是复合因子,请使用更改的谓词 k % 100 == 0 重新运行算法,以便更频繁地计算 gcd,例如 k % 10 == 0。这应该很少见,因为通常在第二阶段发现的因素相距甚远。
    【解决方案2】:

    这是一个用python实现的两阶段版本。

    from math import gcd, log
    
    def pminus1(n, B1, B2):
        log_B1 = log(B1)
        M = 1
        primes = prime_sieve()
        for p in primes:
            if p > B1:
                break
            M *= p**int(log_B1/log(p))
        M = pow(2, M, n)
        g = gcd(M-1, n)
        if 1 < g < n:
            return True
        if g == n:
            return False
    
        # Start part 2.
        cache = {0:M}
        S = (M*M) % n
        for d in range(2, int(log(B2)**2), 2):
            cache[d] = cache[d-2] * S) % n
    
        HQ = M
        for k, q in enumerate(primes):
            if q > B2:
                break
            d = q - p
            HQ = (HQ * cache[d]) % n
            M = (M * (HQ-1)) % n
            p = q
            if k % 200 == 0:
                if 1 < gcd(M, n) < n:
                    return True
        return 1 < gcd(M, n) < n
    

    【讨论】:

    • 我认为这个评论的问题是错误的,但是,是的,我认为我的编辑可能是 python 3+,但老实说,还有人在 2.7 中写东西吗?
    • 这是一个错误的问题,因为这是我可以联系到你的地方。 :)
    • @OscarSmith 我试图了解两个阶段 P-1。你能解释一下你的代码是如何工作的吗?例如,缓存或对数与它有什么关系?我问了一个问题here
    • 这里的缓存存储了 S mod n 的幂,因为需要很多,而且价格昂贵。日志在那里,因为那是需要多少权力。
    • @OscarSmith 我认为这行有错字cache[d] = cache[d-2] * S) % n
    猜你喜欢
    • 1970-01-01
    • 2011-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多