我使用以下代码在 Python 中查找primitive roots模n
:
代码:
def gcd(a,b):
while b != 0:
a, b = b, a % b
return a
def primRoots(modulo):
roots = []
required_set = set(num for num in range (1, modulo) if gcd(num, modulo) == 1)
for g in range(1, modulo):
actual_set = set(pow(g, powers) % modulo for powers in range (1, modulo))
if required_set == actual_set:
roots.append(g)
return roots
if __name__ == "__main__":
p = 17
primitive_roots = primRoots(p)
print(primitive_roots)
输出:
[3, 5, 6, 7, 10, 11, 12, 14]
从以下网址提取的代码片段: Diffie-Hellman (Github)
{<1}}方法可以在内存使用和性能 /效率方面进行简化或优化吗?
答案 0 :(得分:5)
根据 Pete 的评论和 Kasramvd 的回答,我可以建议:
from math import gcd as bltin_gcd
def primRoots(modulo):
required_set = {num for num in range(1, modulo) if bltin_gcd(num, modulo) }
return [g for g in range(1, modulo) if required_set == {pow(g, powers, modulo)
for powers in range(1, modulo)}]
print(primRoots(17))
<强>输出:强>
[3, 5, 6, 7, 10, 11, 12, 14]
<强>的变化:强>
有关内置 gcd 的其他信息,请访问: Co-primes checking
答案 1 :(得分:4)
您可以在此处进行一次快速更改(效率不佳)是使用列表和设置理解:
def primRoots(modulo):
coprime_set = {num for num in range(1, modulo) if gcd(num, modulo) == 1}
return [g for g in range(1, modulo) if coprime_set == {pow(g, powers, modulo)
for powers in range(1, modulo)}]
现在,您可以在此处进行一项功能强大且有趣的算法更改,即使用gcd
function优化memoization。或者甚至更好,您可以在Python-3.5 +或以前版本的gcd
模块中使用内置的math
函数形式fractions
模块:
from functools import wraps
def cache_gcd(f):
cache = {}
@wraps(f)
def wrapped(a, b):
key = (a, b)
try:
result = cache[key]
except KeyError:
result = cache[key] = f(a, b)
return result
return wrapped
@cache_gcd
def gcd(a,b):
while b != 0:
a, b = b, a % b
return a
# or just do the following (recommended)
# from math import gcd
然后:
def primRoots(modulo):
coprime_set = {num for num in range(1, modulo) if gcd(num, modulo) == 1}
return [g for g in range(1, modulo) if coprime_set == {pow(g, powers, modulo)
for powers in range(1, modulo)}]
正如评论中所提到的,作为更多pythoinc优化器方式,您可以使用fractions.gcd
(或者用于Python-3.5 + math.gcd
)。
答案 2 :(得分:1)
在p为素数的特殊情况下,以下是更快的一点:
string Value = ((grdAppSetting.Rows[e.RowIndex].Cells[2].Controls[0]) as TextBox).Text;
答案 3 :(得分:1)
通过使用更高效的算法,您可以极大地改善isNotPrime功能。你可以通过对偶数进行特殊测试来加倍速度,然后只测试奇数直到平方根,但与米勒拉宾测试等算法相比,这仍然是非常低效的。 Rosetta Code网站中的此版本将始终为少于25位左右的任何数字提供正确答案。对于大质数,这将在使用试验分工所用的一小部分时间内运行。
此外,在处理整数时,应避免使用浮点指数运算符**,就像在这种情况下一样(即使我刚刚链接的Rosetta代码也做同样的事情!)。在特定情况下,事情可能会正常工作,但是当Python必须从浮点转换为整数时,或者当一个整数太大而无法准确表示浮点时,它可能是一个微妙的错误来源。您可以使用有效的整数平方根算法。这是一个简单的:
def int_sqrt(n):
if n == 0:
return 0
x = n
y = (x + n//x)//2
while (y<x):
x=y
y = (x + n//x)//2
return x
答案 4 :(得分:0)
那些代码都是低效的,在很多方面,首先你不需要迭代 n 的所有互质提醒,你只需要检查欧拉函数与 n 的除数的幂。在 n 是素数的情况下,欧拉函数是 n-1。如果 n i 素数,则需要对 n-1 进行因式分解并仅检查那些除法器,而不是所有除法器。这背后有一个简单的数学原理。
第二。你需要更好的函数来为一个数字供电,想象功率太大了,我认为在 python 中你有函数 pow(g, powers, modulo) 它在每个步骤进行除法并只得到余数( _ % modulo )。>
如果您要实现 Diff & Helman 算法,最好使用安全素数。它们是这样的素数,p 是素数,2p+1 也是素数,所以 2p+1 被称为安全素数。如果你得到 n = 2*p+1,那么 n-1 的除法器(n 是素数,欧拉函数从 n 是 n-1)是 1、2、p 和 2p,你只需要检查数字是否g 在 2 次幂和 g 在 p 次幂中,如果其中一个给出 1,那么那个 g 不是原始根,你可以扔掉那个 g 并选择另一个 g,下一个 g+1,如果 g^2 和 g^ p 的模 n 不等于 1,那么 g 是一个原始根,该检查保证除 2p 之外的所有幂将给出与模 n 不同的数字。
示例代码使用 Sophie Germain 素数 p 和相应的安全素数 2p+1,并计算该安全素数 2p+1 的本原根。
您可以轻松地为任何质数或任何其他数字重新编写代码,方法是添加一个函数来计算欧拉函数并找到该值的所有除数。但这只是一个演示,而不是完整的代码。并且可能有更好的方法。
class SGPrime :
'''
This object expects a Sophie Germain prime p, it does not check that it accept that as input.
Euler function from any prime is n-1, and the order (see method get_order) of any co-prime
remainder of n could be only a divider of Euler function value.
'''
def __init__(self, pSophieGermain ):
self.n = 2*pSophieGermain+1
#TODO! check if pSophieGermain is prime
#TODO! check if n is also prime.
#They both have to be primes, elsewhere the code does not work!
# Euler's function is n-1, #TODO for any n, calculate Euler's function from n
self.elrfunc = self.n-1
# All divisors of Euler's function value, #TODO for any n, get all divisors of the Euler's function value.
self.elrfunc_divisors = [1, 2, pSophieGermain, self.elrfunc]
def get_order(self, r):
'''
Calculate the order of a number, the minimal power at which r would be congruent with 1 by modulo p.
'''
r = r % self.n
for d in self.elrfunc_divisors:
if ( pow( r, d, self.n) == 1 ):
return d
return 0 # no such order, not possible if n is prime, - see small Fermat's theorem
def is_primitive_root(self, r):
'''
Check if r is a primitive root by modulo p. Such always exists if p is prime.
'''
return ( self.get_order(r) == self.elrfunc )
def find_all_primitive_roots(self, max_num_of_roots = None):
'''
Find all primitive roots, only for demo if n is large the list is large for DH or any other such algorithm
better to stop at first primitive roots.
'''
primitive_roots = []
for g in range(1, self.n):
if ( self.is_primitive_root(g) ):
primitive_roots.append(g)
if (( max_num_of_roots != None ) and (len(primitive_roots) >= max_num_of_roots)):
break
return primitive_roots
#demo, Sophie Germain's prime
p = 20963
sggen = SGPrime(p)
print (f"Safe prime : {sggen.n}, and primitive roots of {sggen.n} are : " )
print(sggen.find_all_primitive_roots())
问候