覺得是高性能神仙算法,一看源代碼才發現...

在昨天的文章中,咱們講到了 RSA 算法。RSA 算法的根本原理中,有兩個核心質數 p和 q,他們相乘獲得一個數 n。因爲反向從 n 分解出 p 和 q 很是困難,因此只要 p 和 q 足夠大,RSA 算法在如今的計算機水平下就沒法被破解。python

如今,你先暫停一下,打開百度或者 Google,搜索一下 RSA 算法的教程。隨便看10篇。git

你會發現,這些教程無一例外都是說:尋找兩個足夠大的質數 p 和 q。但他們都不會告訴你,怎麼尋找。github

在如今的數學體系中,質數是找出來的,而不是生成出來的。尚未一個完美的通項公式能夠生成質數。咱們能夠作到快速檢查一個數是否是質數,可是咱們如今還作不到直接生成一個質數。算法

那麼問題來了,RSA 算法中生成密鑰時,須要的這兩個質數,究竟是怎麼來的?app

當咱們使用 RSA 算法生成2048 bit的密鑰時,咱們須要找到的兩個質數 p 和 q,他們各是1024bit。1024bit的數字有多大?它最小的值爲2^{1024},最大爲2^{1025} - 1。若是你從最小的這個數字開始數,數到最大的這個數,每秒你能數1億個數字,你須要數570044753571256946895391042233962688235025678254156066950247593726955466151385601004275993538836681954338260654082297557264046704764131857219835840434659197037569423594829671728507799344387665269701556798848952843855120124119935570376436804099528276139492994306780499238797710357939232321萬年才能數完。dom

這麼大範圍的數字裏面,讓你去找兩個質數。你說,這 TM 怎麼找?函數

因此,Python的這個 rsa 庫,裏面是使用了什麼神仙算法,可以快速找到這兩個質數的?因而我去閱讀了它的源代碼。結果嚇得我一身冷汗。spa

生成密鑰使用的是rsa.newkeys()函數,因而我首先在 rsa/key.py文件中找到了這個函數:3d

先看758-762行,這裏它經過poolsize參數來決定使用CPU的幾個核,若是個人 CPU 是4核心,那麼能夠同時開4個進程來尋找質數。但這段代碼咱們能夠先跳過,由於在昨天的文章裏面,咱們沒有指定 poolsize參數,因此它使用默認值1.因而代碼運行到第767行,經過gen_keys函數來生成p 和 q。code

咱們再來看gen_keys函數:

能夠看到,在第714行,經過函數find_p_q生成了 p 和 q,而且這裏若是咱們的密鑰是2048bit的話,p 和q 均是1024bit。

咱們再來看 find_p_q函數:

這個函數很長,可是大部分是在驗證生成的 p 和 q 是否符合要求(不能相等,而且要相差足夠大),若是不符合要求就重試。因此真正核心的代碼只有第613行和第615行。這裏調用的genprime_func函數是經過參數傳進來的。而這個genprime_func是咱們在newkeys函數第764行得到的rsa.prime.getprime函數。

如今咱們進入/rsa/prime.py文件,閱讀getprime函數的源代碼:

這段代碼居然很是簡單。在第162行先判斷要生成的質數的bit 數不小於3.而後高潮來了:

while True:
        integer = rsa.randnum.read_random_odd_int(nbits)

        # Test for primeness
        if is_prime(integer):
            return integer
複製代碼

開一個死循環,調用read_random_odd_int不停獲取nbit的奇數,而後,使用is_prime判斷它是否是質數,若是是,返回這個數。若是不是質數,繼續隨機生成一個 nbit 的奇數,再判斷它是否是質數。

這 TM 在逗我?在死循環裏面隨機生成奇數,而後判斷是否是質數,不是就重試直到隨機到一個質數爲止?

2^{1024}2^{1025}-1這麼大的範圍裏面隨機選奇數?這要選多少年才碰得上兩個質數啊?

爲了解決這個疑惑,咱們來看一下素數定理

對於正實數x,定義π(x)爲素數計數函數,亦即不大於x的素數個數。數學家找到了一些函數來估計π(x)的增加:\pi(x)\approx \frac{x}{ln(x)}

x足夠大時,可使用這個公司估算出不大於x的質數的個數。

那麼咱們來看看,在2^{1024}2^{1025}-1的範圍中,質數的密度是多少:

質數的密度居然高達0.14%!那麼隨機選一個數字,不是質數的機率是99.86%。咱們來計算一下,若是隨機選10000個數字,即便在不考慮奇偶性的狀況下:

也就是說,在隨機10000個數字裏面,不出現質數的機率是一千萬分之一。出現質數的機率超過99.9999%

而用 Python 循環10000次,並不須要多長時間。因此,rsa 庫裏面的這個算法,居然沒什麼問題!!

最後,你們有興趣能夠看看prime.py中的is_prime函數,用於快速判斷一個數是否是質數。還有randnum.py中的read_random_odd_int用於隨機生成一個計數,代碼都很簡單,相信你能學到很多東西。

相關文章
相關標籤/搜索