【发布时间】:2011-07-19 18:42:55
【问题描述】:
我正在尝试在 Python 中计算以 P 为模的百位数字的立方根,但失败得很惨。
我找到了 Tonelli-Shanks 算法的代码,据说该算法很容易从平方根修改为立方根,但这让我无法理解。我搜索了网络和数学图书馆以及几本书,但无济于事。代码会很棒,用简单的英语解释的算法也会很棒。
这是用于求平方根的 Python(2.6?)代码:
def modular_sqrt(a, p):
""" Find a quadratic residue (mod p) of 'a'. p
must be an odd prime.
Solve the congruence of the form:
x^2 = a (mod p)
And returns x. Note that p - x is also a root.
0 is returned is no square root exists for
these a and p.
The Tonelli-Shanks algorithm is used (except
for some simple cases in which the solution
is known from an identity). This algorithm
runs in polynomial time (unless the
generalized Riemann hypothesis is false).
"""
# Simple cases
#
if legendre_symbol(a, p) != 1:
return 0
elif a == 0:
return 0
elif p == 2:
return n
elif p % 4 == 3:
return pow(a, (p + 1) / 4, p)
# Partition p-1 to s * 2^e for an odd s (i.e.
# reduce all the powers of 2 from p-1)
#
s = p - 1
e = 0
while s % 2 == 0:
s /= 2
e += 1
# Find some 'n' with a legendre symbol n|p = -1.
# Shouldn't take long.
#
n = 2
while legendre_symbol(n, p) != -1:
n += 1
# Here be dragons!
# Read the paper "Square roots from 1; 24, 51,
# 10 to Dan Shanks" by Ezra Brown for more
# information
#
# x is a guess of the square root that gets better
# with each iteration.
# b is the "fudge factor" - by how much we're off
# with the guess. The invariant x^2 = ab (mod p)
# is maintained throughout the loop.
# g is used for successive powers of n to update
# both a and b
# r is the exponent - decreases with each update
#
x = pow(a, (s + 1) / 2, p)
b = pow(a, s, p)
g = pow(n, s, p)
r = e
while True:
t = b
m = 0
for m in xrange(r):
if t == 1:
break
t = pow(t, 2, p)
if m == 0:
return x
gs = pow(g, 2 ** (r - m - 1), p)
g = (gs * gs) % p
x = (x * gs) % p
b = (b * g) % p
r = m
def legendre_symbol(a, p):
""" Compute the Legendre symbol a|p using
Euler's criterion. p is a prime, a is
relatively prime to p (if p divides
a, then a|p = 0)
Returns 1 if a has a square root modulo
p, -1 otherwise.
"""
ls = pow(a, (p - 1) / 2, p)
return -1 if ls == p - 1 else ls
【问题讨论】:
-
我很想看看完整的算法,但还没有机会。作为除平方根以外的根的简写,您始终可以使用
6 ** (1.0/3)。提高到 1/3 次方 -> 立方根。不过,您可能会失去一点精度:(5 ** (1.0/3)) ** 3 -> 4.9999999999999982 -
你看过这个:
scipy.special.cbrt(docs.scipy.org/doc/scipy/reference/generated/…)? -
你确定 p 是素数吗? pow(2,p-1,p) != 1 所以要么 pow 函数被破坏(可疑),要么 p 不是素数。 Pari 还认为 p 是复合的。
-
Ummmmmmmmmmmmmmmmmmmmmmmmmmmmmmm...它可能是3个素数的组合。那不好吗?我需要检查我的算法。
-
我是个白痴,你是个天才,而且你的代码完美运行(一旦我使用了正确的数字)!!!再次感谢您!
标签: python algorithm rsa modulo public-key-encryption