给出正整数b, c, m
其中(b < m) is True
找到一个正整数e
,这样
(b**e % m == c) is True
其中**是取幂(例如在Ruby,Python或^中的某些其他语言中),%是模运算。什么是最有效的算法(具有最低的大O复杂度)来解决它?
示例:
给定b = 5; C = 8; m = 13,该算法必须找到e = 7,因为5 ** 7%13 = 8
答案 0 :(得分:28)
从%运算符我假设你正在使用整数。
您正在尝试解决the Discrete Logarithm问题。一个合理的算法是Baby step, giant step,虽然还有很多其他算法,但没有一个特别快。
找到离散对数问题的快速解决方案的难度是一些流行的加密算法的基本部分,所以如果你找到比维基百科上任何一个更好的解决方案,请告诉我!
答案 1 :(得分:15)
这根本不是一个简单的问题。它被称为计算discrete logarithm,它是modular exponentation的反向操作。
没有已知的有效算法。也就是说,如果N表示以m为单位的比特数,则所有已知算法都在O(2 ^(N ^ C))中运行,其中C> 0。
答案 2 :(得分:2)
Discrete logarithm是一个难题
计算离散对数被认为是困难的。没有 计算离散对数的有效通用方法 传统计算机是众所周知的。
我将在这里添加一个简单的强力算法,该算法会尝试从1
到m
的每个可能值,并在找到解决方案时输出解决方案。请注意,问题可能有多个解决方案,或者根本没有解决方案。此算法将返回尽可能小的值,如果不存在则返回-1
。
def bruteLog(b, c, m):
s = 1
for i in xrange(m):
s = (s * b) % m
if s == c:
return i + 1
return -1
print bruteLog(5, 8, 13)
在这里您可以看到3
实际上是解决方案:
print 5**3 % 13
有一个更好的算法,但因为它经常被要求在编程比赛中实现,我只会给你一个explanation的链接。
答案 3 :(得分:2)
由于在Python标签下提出了这个问题的重复,这里是一个Python步骤,巨大步骤的Python实现,正如@MarkBeyers所指出的那样,是一种合理的方法(只要模数不是太大)大):
def baby_steps_giant_steps(a,b,p,N = None):
if not N: N = 1 + int(math.sqrt(p))
#initialize baby_steps table
baby_steps = {}
baby_step = 1
for r in range(N+1):
baby_steps[baby_step] = r
baby_step = baby_step * a % p
#now take the giant steps
giant_stride = pow(a,(p-2)*N,p)
giant_step = b
for q in range(N+1):
if giant_step in baby_steps:
return q*N + baby_steps[giant_step]
else:
giant_step = giant_step * giant_stride % p
return "No Match"
在上面的实现中,即使N
加密大,也可以将明确的p
传递给fish以获得小指数。只要指数小于N**2
,它就会找到指数。省略N
时,将始终找到指数,但不一定在您的生命周期中,或者如果p
太大,则无法使用机器的内存。
例如,如果
p = 70606432933607
a = 100001
b = 54696545758787
然后'pow(a,b,p)'的评估结果为67385023448517
和
>>> baby_steps_giant_steps(a,67385023448517,p)
54696545758787
我的机器上花了大约5秒钟。对于指数和这些尺寸的模数,我估计(基于时间实验)蛮力可能需要几个月。
答案 4 :(得分:1)
感谢SymPy为您准备了implemented!
SymPy是用于符号数学的Python库。它旨在成为功能齐全的计算机代数系统(CAS),同时保持代码尽可能的简单,以便于理解和易于扩展。 SymPy完全用Python编写。
这是documentation on the discrete_log
函数。使用它导入它:
from sympy.ntheory.residue_ntheory import discrete_log
他们的示例计算\log_7(15) (mod 41)
:
>>> discrete_log(41, 15, 7)
3
由于采用(最新技术,请注意)算法来解决问题,因此您尝试的大多数输入都会获得O(\sqrt{n})
。当素数模数具有p - 1
可分解为许多小素数的属性时,速度会大大提高。
考虑大约100位的质数:(〜2 ^ {100})。由于\ sqrt {n}的复杂性,仍然是2 ^ {50}个迭代。话虽这么说,但不要重新发明轮子。这做得很好。我还可能要补充一点,当我使用大型输入(44 MiB与173 MiB)运行时,它的内存效率几乎是Mathematica的MultiplicativeOrder
函数的4倍。
答案 5 :(得分:0)
btw e == 3是你的例子的第一个解决方案,你可以在3个步骤中找到,比较解决非离散版本,并天真地寻找整数解,即
e = log(c + n * m)/ log(b)其中n是非负整数
在9个步骤中找到e == 3