从零实现RSA一:找质数

质数

质数是大于1且只有1和它本身两个因数的整数。

以下列出一些质数(注意,1不被看做质数):
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  ......无穷无尽。

质数有无穷多个,这意味着没有“最大”质数。它们只会越来越大,就像普通数字一样。 RSA加密法的密钥使用非常大的质数。因此, 密钥太多而不能暴力破译。

但这些都是小数字。我们的RSA程序通常使用的质数都有上百个数位:
112 829 754 900 439 506 175 719 191 782 841 802 172 556 768 253 593 054 977 186 235 584 979 780 304 652 423 405 148 425 447 063 090 165 759 070 742 102 132 335 103 295 947 000 718 386 333 756 395 799 633 478 227 612 244 071 875 721 006 813 307 628 061 280 861 610 153 485 352 017 238 548 269 452 852 733 818 231 045 171 038 838 387 845 888 589 411 762 622 041 204 120 706 150 518 465 720 862 068 595 814 264 819

以上数字很大,我猜你甚至不会去看它里面有没有输入错误。

如何判断一个数是不是质数?

1)最直观的方法,根据定义,因为质数除了1和本身之外没有其他约数,所以判断n是否为质数,根据定义直接判断从2到n-1是否存在n的约数即可。

2)这种方法,明显存在效率极低的问题。对于每个数n,其实并不需要从2判断到n-1,我们知道,一个数若可以进行因数分解,那么分解时得到的两个数一定是一个小于等于sqrt(n),一个大于等于sqrt(n),据此,上述代码中并不需要遍历到n-1,遍历到sqrt(n)即可,因为若sqrt(n)左侧找不到约数,那么右侧也一定找不到约数。

3)其实质数还有一个特点,就是它总是等于 6x-1 或者 6x+1,其中 x 是大于等于1的自然数。如何论证这个结论呢,其实不难。首先 6x 肯定不是质数,因为它能被 6 整除;其次 6x+2 肯定也不是质数,因为它还能被2整除;依次类推,6x+3 肯定能被 3 整除;6x+4 肯定能被 2 整除。那么,就只有 6x+1 和 6x+5 (即等同于6x-1) 可能是质数了。所以循环的步长可以设为 6,然后每次只判断 6 两侧的数即可。
但是如果像 1 070 595 206 942 983这种数字呢?如果你用这三种方法来判断,可能需要数秒才能判断它是不是质数。如果某个数字有数百个数位(就像RSA程序的质数那样), 将要超过一万亿年才能判断这一个数字是不是质数。

Rabin-Miller

拉宾米勒质数测试 The Rabin-Miller Primality Test)的算法可以判断数百位的数字是不是质数。

费马小定理:N为任意正整数,P为素数且N不能被P整除(显然N和P互质),则(N^(P-1)) % P == 1。

所以如果N小于P,则N和P肯定互质。那么随机抽取N < P,如果(N^(P-1)) % P != 1,则P为合数如果等于1,则P有可能为质数;而且N取的组数越多,结果越精确

import random

def rabinMiller(num):
    s = num - 1
    t = 0
    while s%2 == 0:
        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 += 1
                    v = (v**2)%num
    return True

def isPrime(num):
    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 rabinMiller(num)

def generateLargePrime(keysize=1024):
    while True:
        num = random.randrange(2**(keysize-1),2**keysize)

        if isPrime(num):
            return num

if __name__ == '__main__':

    a=generateLargePrime()
    print(a)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

0xKent

有钱的捧个钱场,没钱的捧个人场

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值