用来快速判断一个数是不是素数.
1、费马小定理:如果n是素数,则$$a ^ {n - 1}$$ % n 等于 1。
2、快速模取幂
米勒-拉宾算法就是结合上面两种,通过不断判断fmod(a, n - 1, n)的值是否为1来判断。这是一个概率算法,如果为1,不一定为素数,不为1,则必定是合数。循环判断多次就会让概率变得极为的小。
大素数随机生成原理是,随机生成一个大素数,检测其是否为素数,如果是则输出,否则继续生成。
给出了一个数n是素数的充要条件 (n-1)! ≡ -1 (mod n)
计算量太大,不现实
假如p是质数,a是整数,且a、p互质,那么a的(p-1)次方除以p的余数恒等于1,即:$$a^{p-1}$$≡1(mod p).
但是反过来却不一定成立,就是说,如果a、p互质,且$$a^{p-1}$$≡1(mod p),不能推出p是质数,比如Carmichael数。
如果p是一个素数,0<x<p,则方程$$x^2$$≡1(mod p)的解为x=1或x=p-1。
若x>p, 则结果为x mod p = 1 或 -1 (即p-1)
(因为x*x mod p = 1, 根据模运算可乘性性质, x mod p = 1 或 -1)
$$(a \times b)\%n=(a\%n \times b\%n)\%n$$
快速幂算法(蒙哥马利算法)
http://139.196.53.116/ml/index.php/archives/173/
$$a^{n-1}=a^{2^q \times m}=a^{2^{q-1}\times 2 \times m}={(a^{2^{q-1} \times m})}^2$$
对于要判断的数n:
1.先判断是不是2,是的话就返回true。
2.判断是不是小于2的,或合数,是的话就返回false。
3.令$$n-1=u*2^t$$求出u,t 其中u是奇数。
4.随机取一个a,且1<a<n
/*根据费马小定理,如果$$a^{n-1}$$≡1(mod p)
那么n就极有可能是素数,如果等式不成立,那肯定不是素数了
因为$$n-1=u\times 2^t$$所以$$a^{n-1}=a^{u\times 2^t}=(a^u)^{2^t}$$。*/
5.所以我们令$$x=a^u\ mod\ n $$
6.然后是t次循环,每次循环都让$$y=(x^2)\ mod\ n,x=y$$这样t次循环之后$$x=a^{u\times 2^t}=a^{n-1}$$了
7.因为循环的时候$$y=(x\times x)\ mod\ n$$ 且x肯定是小于n的,正好可以用二次探测定理:
如果$$(x^2)$$%n==1 也就是y等于1的时候,假如n是素数,那么x==1||x==n-1
如果x!=1&&x!=n-1 那么n肯定不是素数了,返回false。
(这里只要第一次$$a^u$$判断是否为1就行,后面平方后只需判断是否为n-1,因为第一次不为1,后面只要不是p-1就不能模1)
8.运行到这里的时候$$x=a^{n-1}$$根据费马小定理,x!=1的话,肯定不是素数了,返回false
9.因为Miller-Rabin得到的结果的正确率为 75%,所以要多次循环步骤4~8来提高正确率
10.循环多次之后还没返回,那么n肯定是素数了,返回true
满足p|q的两个大素数,通过p不好找q。不如反过来先随机产生q。q乘以一个偶数再加一,因为数越大,素数越多。用这种方法找到满足p|q的速度还是很快的。我用的512位的随机数,这样的到的p极大概率是1024位的。如果不是1024位,舍弃再产生一个新的就好了。
先生成随机数x
将x变为偶数 if x % 2 == 1: x = x+1
在用q乘以x+1 判段是否为素数,是否符合位数要求
import random
def generateLargePrime(keysize=512):
'''生成一个大素数,默认生成512位大素数。'''
while True:
num = random.randrange(2 ** (keysize - 1), 2 ** keysize)
if isPrime(num):
return num
def generateLargePrime1(q,keysize=512):
while True:
x=random.randrange(2 ** (keysize - 1), 2 ** keysize)
if x % 2 == 1:
x = x+1
num1 = (q-1) * x+1
if isPrime(num1) :
return num1
p = generateLargePrime()
q = generateLargePrime1(p)
print(p)
print(q)
def millerRabin(num):
s = num - 1
t = 0
while s % 2 == 0:
s = s // 2
t += 1
for trials in range(5):
a = random.randrange(2, num - 1)
v = pow(a, s, num)
if v != 1:
i = 0
while v != (num - 1):
if i == t - 1:
return False
else:
i = i + 1
v = (v ** 2) % num
return True
需要先对1000以内素数查表排除,加速算法
def isPrime(num):
'''对 Miller-Rabin 素性检测算法的封装,判断一个数是否为素数。'''
if (num < 2):
return False
lowPrimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
151, 157, 163, 167, 173, 179, 181, 191, 193, 197,
199, 211, 223, 227, 229, 233, 239, 241, 251, 257,
263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
503, 509, 521, 523, 541, 547, 557, 563, 569, 571,
577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
641, 643, 647, 653, 659, 661, 673, 677, 683, 691,
701, 709, 719, 727, 733, 739, 743, 751, 757, 761,
769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883, 887, 907,
911, 919, 929, 937, 941, 947, 953, 967, 971, 977,
983, 991, 997]
if num in lowPrimes:
return True
for prime in lowPrimes:
if num % prime == 0:
return False
return millerRabin(num)
基于费马小定理 ap-1 mod p≡1这个公式,随机选取若干个小于p的正整数a,若所有的a都满足p-1 mod p≡1,则基本认为p是质数。
Fermat素性测试只能大概率排除伪质数,而不能排除所有的伪质数,就是因为有卡迈克尔数的存在。从定义中也能看出这点。
Fermat素性测试实际上就是对费马小定理的应用。
统计表明,在前10亿个自然数中共有50847534个满足费马小定理的数,其中满足2(n-1) mod n = 1的合数n有5597个,这些合数都是以2为底的伪质数。有些伪质数可能通过了以2为底的测试,却不能通过以3为底的测试(3(n-1) mod n = 1)。能同时通过2和3测试的合数叫做以2和3为底的伪质数,前10亿中只有1272个。
所以,Fermat素性测试需要做相互独立的若干轮随机测试来降低出错的可能性。这个逻辑类似布隆过滤器。
而取遍1到n-1的所有整数进行素性测试,仍然没有被查出来的伪质数就被称为卡迈克尔数,前10亿中有600多个。
Fermat素性测试之所以不那么靠谱就是因为有卡迈克尔数的存在,这可以说是费马小定理的盲点吧。
基于fermat定理的强素性检测另一种实现。
算法如下:
输入:数N
输出:是或否
(1).N-1=2^k * m, m是奇数, k>=1;
(2).在N的既约剩余系中随机选取一个数a, 1<a<N-1, 计算(a^m) mod N = b0;
if b0 = 1, output "是"
(3).i 1:k, 计算b(i+1) = (bi)^2 mod N
if bk != 1, output "否"
(4).j = min{i | b(i+1) = 1}
bj != 1, b(j+1) = 1
(5). g = gcd(bj != 1, N)
if g = N or g = 1, output "是"
else output "否"