如何解决如何模块化素数分解 Python 脚本以将列表作为输入?
我有可用的 Python 代码(如下),可以破解 RSA 密钥并乘以质因数分解。如何将此代码放入一个模块中,该模块采用代表 n 的整数列表来创建范围 0...2^n 的 n 位素数?我想传入一个整数列表并返回一个包含 n 值和运行时间的表,如下所示:
n run time
15 0.2
16 1.1
17 1.4
18 10.6
19 30.2
20 46.6
代码:
import random
import math
import timeit
while True:
try:
n = input("Please enter a number n for creating an n-bit prime number for range 0...2^n: ")
n = int(n)
break
except ValueError:
print('\nPlease enter an integer value.')
def isPrime(m):
for i in range(2,m//2,1):
if m % i == 0:
return False
return True
def nBitPrime(n):
r = random.random()
m = int(r * (2**n))
if m >= 2 and isPrime(m) == True:
return m
return nBitPrime(n)
def getPQ(n):
pq = nBitPrime(n) * nBitPrime(n)
return pq
pq = getPQ(n)
def factor(pq):
p = math.floor(math.sqrt(getPQ(n)))
if p % 2 == 0:
p += 1
while p < pq:
if pq % p == 0:
return p,int(pq/p)
p += 2
def wrapper(func,*args):
def wrapped():
return func(*args)
return wrapped
wrapped = wrapper(factor,n)
speed = (timeit.timeit(wrapped,number=1))*1000
print(round(speed,4))
提前致谢。
解决方法
这里有几个问题。首先,您的因子函数会重新生成一个新的 pq 值,忽略您之前生成的值。这计算了两次获得 pq 的时间。此外,测量使用随机数生成器的进程的单次执行时间并不能让您对性能有一个很好的了解。您需要进行多次运行才能获得平均值。
我稍微清理了您的代码并更改了测量时间的方式以获得平均超过 100 次运行:
您的代码:
import random
import math
import timeit
def isPrime(m):
for i in range(2,m//2,1):
if m % i == 0:
return False
return True
def nBitPrime(n):
r = random.random()
m = int(r * (2**n))
if m >= 2 and isPrime(m) == True:
return m
return nBitPrime(n)
def getPQ(n):
pq = nBitPrime(n) * nBitPrime(n)
return pq
def factor(pq):
p = math.floor(math.sqrt(pq))
if p % 2 == 0:
p += 1
while p < pq:
if pq % p == 0:
return p,int(pq/p)
p += 2
while True:
try:
n = input("Please enter a number n for creating an n-bit prime number for range 0...2^n: ")
n = int(n)
time = timeit.timeit(lambda:factor(getPQ(n)),number=100)
print(f"{time*10:.4f}")
except ValueError:
print('\nPlease enter an integer value.')
除了简单的代码优化之外,使用质数生成器和质数列表将大大加快速度。
以下是相同函数的示例实现,以更高效和 Pythonic 的方式帮助您制作更好的自己的函数:
素数生成(根据需要)
primes = [2,3]
primeSkip = {9:3}
# fill primes list up to the square root of N
def morePrimes(N):
lastPrime = primes[-1]
while lastPrime*lastPrime<N:
lastPrime += 2
if lastPrime not in primeSkip:
primeSkip[lastPrime*lastPrime] = lastPrime
primes.append(lastPrime)
continue
prime = primeSkip.pop(lastPrime)
multiple = lastPrime + 2*prime
while multiple in primeSkip: multiple += 2*prime
primeSkip[multiple] = prime
主要测试
# prime test uses the known prime list as a search mechanism
# and only checks divisions for primes when a larger number is given
from bisect import bisect_left
def isPrime(N):
if N<=primes[-1]:
return primes[bisect_left(primes,N)] == N
morePrimes(N)
for p in primes:
if N%p == 0: return False
if p*p>N: return True
return True
随机 n 位素数
# non-recursive implementation (faster than recursive)
# also uses randrange() to get the appropriate values without multiplication
# and floating point arithmetics
def nBitPrime(n):
p = random.randrange(2,2**n)
while not isPrime(p):
p = random.randrange(2,2**n)
return p
因式分解
# factorisation uses primes going backward from the square root of pq
# given that p and q are supposed to be large primes,this should converge
# faster to the two factors.
def factor(pq):
morePrimes(pq)
i = bisect_left(primes,int(pq**0.5)+1)
i = min(i,len(primes)-1)
while i>0:
p = primes[i]
if pq%p == 0: return p,pq//p
i -= 1
测试运行
Your original code (cleaned up):
Please enter a number n for creating an n-bit prime number for range 0...2^n: 10
0.0531
Please enter a number n for creating an n-bit prime number for range 0...2^n: 15
1.2645
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
38.0535
...
# With the improved functions
Please enter a number n for creating an n-bit prime number for range 0...2^n: 10
0.0359
Please enter a number n for creating an n-bit prime number for range 0...2^n: 15
0.2044
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
3.76593
基于素数的函数有一些开销,抵消了较小位大小的好处,但它们在高端提供了显着的改进
其他注意事项
您为 p 和 q 生成的值不符合通常用于选择它们的标准。它们必须是彼此相距足够远的大素数。纯随机生成将产生易于因式分解的弱 pq 值(尽管在 32 位以下,基于素数的因式分解会很快找到它们)
这可能会好一点:
def getPQ(n):
p = random.randrange(2**(n-4),2**(n-2))
while not isPrime(p):
p = random.randrange(2**(n-4),2**(n-2))
q = random.randrange(p*2,2**n)
while not isPrime(q):
q = random.randrange(p*2,2**n)
return p*q
将分解时间与随机 pq 生成分开测量也是一个好主意。您的破解功能通常用于现有密钥,因此已预先生成 pq 以生成密钥。这将突出显示 factor() 函数的实现与基于素数的函数之间的巨大性能差异。
while True:
try:
n = input("Please enter a number n for creating an n-bit prime number for range 0...2^n: ")
n = int(n)
pq = getPQ(n)
print("pq",pq) # exclude this from time measurement
time = timeit.timeit(lambda:factor(pq),number=100)
print(f"{time*10:.4f}")
except ValueError:
print('\nPlease enter an integer value.')
仅测试 factor() 函数的性能:
# Your code:
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
pq 78161507029
4.5724
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
pq 414308573933
17.8163
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
pq 192833207923
14.7995
...
# Prime based:
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
pq 36909677657
1.9210
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
pq 62575471813
1.1313
Please enter a number n for creating an n-bit prime number for range 0...2^n: 20
pq 761609512621
1.5924
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。