需要帮助实施Lucas Pseudoprimality测试

时间:2013-02-21 22:55:54

标签: primes

我正在尝试编写一个函数,使用Lucas伪伪测试来确定数字 n 是素数还是复合数;目前,我正在使用标准测试,但是一旦我开始工作,我将编写强大的测试。我正在阅读Baillie和Wagstaff的paper,并在implementation文件中关注Thomas Nicely的trn.c

据我所知,完整的测试涉及几个步骤:通过小素数进行试验划分,检查 n 不是正方形,对基数2执行强伪伪试验,然后最后进行Lucas伪试验。我可以处理所有其他部分,但我在Lucas pseudoprime测试中遇到了麻烦。这是我在Python中的实现:

def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a

def jacobi(a, m):
    a = a % m; t = 1
    while a != 0:
        while a % 2 == 0:
            a = a / 2
            if m % 8 == 3 or m % 8 == 5:
                t = -1 * t
        a, m = m, a # swap a and m
        if a % 4 == 3 and m % 4 == 3:
            t = -1 * t
        a = a % m
    if m == 1:
        return t
    return 0

def isLucasPrime(n):
    dAbs, sign, d = 5, 1, 5
    while 1:
        if 1 < gcd(d, n) > n:
            return False
        if jacobi(d, n) == -1:
            break
        dAbs, sign = dAbs + 2, sign * -1
        d = dAbs * sign
    p, q = 1, (1 - d) / 4
    print "p, q, d =", p, q, d
    u, v, u2, v2, q, q2 = 0, 2, 1, p, q, 2 * q
    bits = []
    t = (n + 1) / 2
    while t > 0:
        bits.append(t % 2)
        t = t // 2
    h = -1
    while -1 * len(bits) <= h:
        print "u, u2, v, v2, q, q2, bits, bits[h] = ",\
               u, u2, v, v2, q, q2, bits, bits[h]
        u2 = (u2 * v2) % n
        v2 = (v2 * v2 - q2) % n
        if bits[h] == 1:
            u = u2 * v + u * v2
            u = u if u % 2 == 0 else u + n
            u = (u / 2) % n
            v = (v2 * v) + (u2 * u * d)
            v = v if v % 2 == 0 else v + n
            v = (v / 2) % n
        if -1 * len(bits) < h:
            q = (q * q) % n
            q2 = q + q
        h = h - 1
    return u == 0

当我运行时,isLucasPrime会返回False这样的素数为83和89,这是不正确的。它还为复合111返回False,这是正确的。并且它返回复合323的False,我知道这是一个Lucas伪伪,isLucasPrime应返回True。实际上,isLucasPseudoprime会为我测试过的每个 n 返回False

我有几个问题:

1)我不是C / GMP的专家,但在我看来,Nicely从右到左(最不重要到最重要)的(n+1)/2位经历了其他作者通过的位这些位从左到右。我上面显示的代码从左到右贯穿各个位,但我也尝试从右到左遍历位,结果相同。哪个订单是正确的?

2)对我来说,Nicely只更新了1位的 u v 变量。它是否正确?我希望每次循环都更新所有四个Lucas链变量,因为链的索引在每一步都会增加。

3)我做错了什么?

1 个答案:

答案 0 :(得分:1)

  

1)我不是C / GMP的专家,但在我看来,Nicely从右到左(最不重要到最重要)的(n+1)/2位经历了其他作者通过的位这些位从左到右。我上面显示的代码从左到右贯穿各个位,但我也尝试从右到左遍历位,结果相同。哪个订单是正确的?

确实,Nicely从最不重要到最重要的一点。他在U(2^k)V(2^k)变量中计算Q^(2^k)N(以及mpzU2m;所有模mpzV2m},并且{存储在U((N+1) % 2^k)V((N+1) % 2^k)中的{1}} resp mpzU。遇到1位时,余数mpzV会发生变化,(N+1) % 2^kmpzU也会相应更新。

另一种方法是为mpzV的前缀U(p)计算U(p+1)V(p)V(p+1)和(可选)p,根据前缀N+1之后的下一位是0还是1,将这些组合起来计算U(2*p+1)U(2*p)U(2*p+2) [ditto for V]。

这两种方法都是正确的,就像你可以计算从左到右的功率p,以x^Nx^p为状态,或者从右到左计算{{1} }和x^(p+1)作为州[和,计算x^(2^k)x^(N % 2^k)基本上是计算U(n) U(n+1)]。

我 - 和其他人,显然 - 发现从左到右的顺序更简单。我还没有完成或阅读过分析,可能是从右到左平均而言计算成本更低,而Nicely选择从右到左的原因。

  

2)对我来说,Nicely只更新1位的ζ^nζ = (1 + sqrt(D))/2变量。它是否正确?我希望每次循环都更新所有四个Lucas链变量,因为链的索引在每一步都会增加。

是的,这是正确的,因为如果u位为0,则余数为v

  

3)我做错了什么?

首先是一个小错字:

(N+1) % 2^k == (N+1) % 2^(k-1)

应该是

2^k

当然。

更重要的是,您使用Nicely的遍历顺序(从右到左)的更新,但在另一个方向上遍历。这当然会产生错误的结果。

此外,更新if 1 < gcd(d, n) > n:

if 1 < gcd(d, n) < n:

您使用v的新值,但您应该使用旧值。

    if bits[h] == 1:
        u = u2 * v + u * v2
        u = u if u % 2 == 0 else u + n
        u = (u / 2) % n
        v = (v2 * v) + (u2 * u * d)
        v = v if v % 2 == 0 else v + n
        v = (v / 2) % n

有效(没有保证,但我认为这是正确的,并且做了一些测试,所有测试都通过了)。