我正在尝试使用Pollard的rho算法来计算离散对数,该算法基于Richard Crandall和Carl Pomerance在第5.2.2节(第232页)中的书Prime Numbers: A Computational Perspective中的描述。这是我的Python代码:
def dlog(g,t,p):
# l such that g**l == t (mod p), with p prime
# algorithm due to Crandall/Pomerance "Prime Numbers" sec 5.2.2
from fractions import gcd
def inverse(x, p): return pow(x, p-2, p)
def f(xab):
x, a, b = xab[0], xab[1], xab[2]
if x < p/3:
return [(t*x)%p, (a+1)%(p-1), b]
if 2*p/3 < x:
return [(g*x)%p, a, (b+1)%(p-1)]
return [(x*x)%p, (2*a)%(p-1), (2*b)%(p-1)]
i, j, k = 1, [1,0,0], f([1,0,0])
while j[0] <> k[0]:
print i, j, k
i, j, k = i+1, f(j), f(f(k))
print i, j, k
d = gcd(j[1] - k[1], p - 1)
if d == 1: return ((k[2]-j[2]) * inverse(j[1]-k[1],p-1)) % (p-1)
m, l = 0, ((k[2]-j[2]) * inverse(j[1]-k[1],(p-1)/d)) % ((p-1)/d)
while m <= d:
print m, l
if pow(g,l,p) == t: return l
m, l = m+1, (l+((p-1)/d))%(p-1)
return False
代码包含调试输出以显示正在发生的事情。您可以在 http://ideone.com/8lzzOf运行代码,在那里您还会看到两个测试用例。第一个测试用例,遵循 d &gt; 1路径,计算正确的值。第二个测试用例在 d == 1路径之后失败。
请帮我找错。
答案 0 :(得分:4)
有一件看起来很可疑的事情就是这个功能:
def inverse(x, p): return pow(x, p-2, p)
这是使用Euler's theorem计算x modulo p的模逆。如果p是素数,这很好,但是否则你需要将x提升到幂phi(p)-1。
在你的情况下,你用p-1的模数调用这个函数,这将是偶数,因此给出一个不正确的逆。
由于phi(p-1)难以计算,因此最好使用extended Euclidean algorithm for computing the inverse instead。
为案例g = 83,t = 566,p = 997运行代码会产生977,而您期望为147。
事实上,977确实是83的对数,我们可以看到,如果我们计算:
>>> pow(83,977,997)
566
但它不是你期待的那个(147)。
这是因为Pollard rho方法要求g是该组的生成器。不幸的是,83不是1,2组的发电机,997因为pow(83,166,997)== 1。 (换句话说,在生成组的166个元素后,您开始重复元素。)