轉載自http://www.matrix67.com/blog/archives/5100程序員
數論,數學中的皇冠,最純粹的數學。早在古希臘時代,人們就開始癡迷地研究數字,沉浸於這個幾乎沒有任何實用價值的思惟遊戲中。直到計算機誕生以後,幾千年來的數論研究成果忽然有了實際的應用,這個過程能夠說是最爲激動人心的數學話題之一。最近我在《程序員》雜誌上連載了《跨越千年的 RSA 算法》,但受篇幅限制,只有一萬字左右的內容。其實,從數論到 RSA 算法,裏面的數學之美哪裏是一萬字能扯完的?在寫做的過程當中,我查了不少資料,找到了不少漂亮的例子,也積累了不少我的的思考,但最終都由於篇幅緣由沒有加進《程序員》的文章中。今天,我想從新梳理一下線索,把全部值得分享的內容一次性地呈如今這篇長文中,但願你們會有所收穫。須要注意的是,本文有意爲了照顧可讀性而犧牲了嚴謹性。不少具體內容都僅做了直觀解釋,一些「顯然如此」的細節其實是須要證實的。若是你但願看到有關定理及其證實的嚴格表述,能夠參見任意一本初等數論的書。把本文做爲初等數論的學習讀物是很是危險的。最後,但願你們可以積極指出文章中的缺陷,我會不斷地作出修改。算法
======= 更新記錄 =======數組
2012 年 12 月 15 日:發佈全文。
2012 年 12 月 18 日:修改了幾處表達。安全
======== 目錄 ========網絡
(一)可公度線段
(二)中國剩餘定理
(三)擴展的展轉相除
(四)Fermat 小定理
(五)公鑰加密的可能性
(六)RSA 算法學習
(一)可公度線段測試
Euclid ,中文譯做「歐幾里得」,古希臘數學家。他用公理化系統的方法概括整理了當時的幾何理論,並寫成了偉大的數學著做《幾何本來》,於是被後人稱做「幾何學之父」。有趣的是,《幾何本來》一書裏並不全講的幾何。全書共有十三卷,第七捲到第十卷所討論的其實是數論問題——只不過是以幾何的方式來描述的。在《幾何本來》中,數的大小用線段的長度來表示,越長的線段就表示越大的數。不少數字與數字之間的簡單關係,在《幾何本來》中都有對應的幾何語言。例如,若數字 a 是數字 b 的整倍數,在《幾何本來》中就表達爲,長度爲 a 的線段能夠用長度爲 b 的線段來度量。比方說,黑板的長度是 2.7 米,一支鉛筆的長度是 18 釐米,你會發現黑板的長度正好等於 15 個鉛筆的長度。咱們就說,鉛筆的長度能夠用來度量黑板的長度。若是一張課桌的長度是 117 釐米,那麼 6 個鉛筆的長度不夠課桌長, 7 個鉛筆的長度又超過了課桌長,於是咱們就沒法用鉛筆來度量課桌的長度了。哦,固然,實際上課桌長至關於 6.5 個鉛筆長,可是鉛筆上又沒有刻度,咱們用鉛筆來度量課桌時,怎麼知道最終結果是 6.5 個鉛筆長呢?於是,只有 a 剛好是 b 的整數倍時,咱們才說 b 能夠度量 a 。優化
給定兩條長度不一樣的線段 a 和 b ,若是可以找到第三條線段 c ,它既能夠度量 a ,又能夠度量 b ,咱們就說 a 和 b 是可公度的( commensurable ,也叫作可通約的), c 就是 a 和 b 的一個公度單位。舉個例子: 1 英寸和 1 釐米是可公度的嗎?歷史上,英寸和釐米的換算關係不斷在變,但如今,英寸已經有了一個明確的定義: 1 英寸精確地等於 2.54 釐米。所以,咱們能夠把 0.2 毫米看成單位長度,它就能夠同時用於度量 1 英寸和 1 釐米: 1 英寸將正好等於 127 個單位長度, 1 釐米將正好等於 50 個單位長度。實際上, 0.1 毫米、 0.04 毫米 、 (0.2 / 3) 毫米也均可以用做 1 英寸和 1 釐米的公度單位,不過 0.2 毫米是最大的公度單位。加密
等等,咱們怎麼知道 0.2 毫米是最大的公度單位?更通常地,任意給定兩條線段後,咱們怎麼求出這兩條線段的最大公度單位呢?在《幾何本來》第七卷的命題 2 當中, Euclid 給出了一種求最大公度單位的通用算法,這就是後來所說的 Euclid 算法。這種方法其實很是直觀。假如咱們要求線段 a 和線段 b 的最大公度單位,不妨假設 a 比 b 更長。若是 b 正好能度量 a ,那麼考慮到 b 固然也能度量它自身,於是 b 就是 a 和 b 的一個公度單位;若是 b 不能度量 a ,這說明 a 的長度等於 b 的某個整倍數,再加上一個零頭。咱們不妨把這個零頭的長度記做 c 。若是有某條線段可以同時度量 b 和 c ,那麼它顯然也就能度量 a 。也就是說,爲了找到 a 和 b 的公度單位,咱們只須要去尋找 b 和 c 的公度單位便可。怎樣找呢?咱們故技重施,看看 c 是否能正好度量 b 。若是 c 正好能度量 b ,c 就是 b 和 c 的公度單位,從而也就是 a 和 b 的公度單位;若是 c 不能度量 b ,那看一看 b 被 c 度量以後剩餘的零頭,把它記做 d ,而後繼續用 d 度量 c ,並不斷這樣繼續下去,直到某一步沒有零頭了爲止。url
咱們仍是來看一個實際的例子吧。讓咱們試着找出 690 和 2202 的公度單位。顯然, 1 是它們的一個公度單位, 2 也是它們的一個公度單位。咱們但願用 Euclid 的算法求出它們的最大公度單位。首先,用 690 去度量 2202 ,結果發現 3 個 690 等於 2070 ,度量 2202 時會有一個大小爲 132 的零頭。接下來,咱們用 132 去度量 690 ,這將會產生一個 690 – 132 × 5 = 30 的零頭。用 30 去度量 132 ,仍然會有一個大小爲 132 – 30 × 4 = 12 零頭。再用 12 去度量 30 ,零頭爲 30 – 12 × 2 = 6 。最後,咱們用 6 去度量 12 ,你會發現這回終於沒有零頭了。所以, 6 就是 6 和 12 的一個公度單位,從而是 12 和 30 的公度單位,從而是 30 和 132 的公度單位,從而是 132 和 690 的公度單位,從而是 690 和 2202 的公度單位。
咱們不妨把 Euclid 算法對 a 和 b 進行這番折騰後獲得的結果記做 x 。從上面的描述中咱們看出, x 確實是 a 和 b 的公度單位。不過,它爲何必定是最大的公度單位呢?爲了說明這一點,下面咱們來證實,事實上, a 和 b 的任意一個公度單位必定可以度量 x ,從而不會超過 x 。若是某條長爲 y 的線段能同時度量 a 和 b ,那麼注意到,它能度量 b 就意味着它能度量 b 的任意整倍數,要想讓它也能度量 a 的話,只須並且必須讓它可以度量 c 。因而, y 也就可以同時度量 b 和 c ,根據一樣的道理,這又能夠推出 y 必定能度量 d ……所以,最後你會發現, y 必定能度量 x 。
用如今的話來說,求兩條線段的最大公度單位,實際上就是求兩個數的最大公約數——最大的能同時整除這兩個數的數。用如今的話來描述 Euclid 算法也會簡明得多:假設剛開始的兩個數是 a 和 b ,其中 a > b ,那麼把 a 除以 b 的餘數記做 c ,把 b 除以 c 的餘數記做 d ,c 除以 d 餘 e , d 除以 e 餘 f ,等等等等,不斷拿上一步的除數去除以上一步的餘數。直到某一次除法餘數爲 0 了,那麼此時的除數就是最終結果。所以, Euclid 算法又有一個形象的名字,叫作「展轉相除法」。
展轉相除法的效率很是高,剛纔你們已經看到了,計算 690 和 2202 的最大公約數時,咱們依次獲得的餘數是 132, 30, 12, 6 ,作第 5 次除法時就除盡了。實際上,咱們能夠大體估計出展轉相除法的效率。第一次作除法時,咱們是用 a 來除以 b ,把餘數記做 c 。若是 b 的值不超過 a 的一半,那麼 c 更不會超過 a 的一半(由於餘數小於除數);若是 b 的值超過了 a 的一半,那麼顯然 c 直接就等於 a – b ,一樣小於 a 的一半。所以,無論怎樣, c 都會小於 a 的一半。下一步輪到 b 除以 c ,根據一樣的道理,所得的餘數 d 會小於 b 的一半。接下來, e 將小於 c 的一半, f 將小於 d 的一半,等等等等。按照這種速度遞減下去的話,即便最開始的數是上百位的大數,不到 1000 次除法就會變成一位數(若是算法沒有提早結束的話),交給計算機來執行的話保證秒殺。用專業的說法就是,展轉相除法的運算次數是對數級別的。
很長一段時間裏,古希臘人都認爲,任意兩條線段都是能夠公度的,咱們只須要作一遍展轉相除便能把這個公度單位給找出來。事實真的如此嗎?展轉相除法有可能失效嗎?咱們至少能想到一種可能:會不會有兩條長度關係很是特殊的線段,讓展轉相除永遠達不到終止的條件,從而根本不能算出一個「最終結果」?注意,線段的長度不必定(也幾乎不可能)剛好是整數或者有限小數,它們每每是一些根本不能用有限的方式精確表示出來的數。考慮到這一點,兩條線段不可公度徹底是有可能的。
爲了讓兩條線段展轉相除永遠除不盡,咱們有一種絕妙的構造思路:讓線段 a 和 b 的比值剛好等於線段 b 和 c 的比值。這樣,展轉相除一次後,兩數的關係又回到了起點。從此每一次展轉相除,餘數總會佔據除數的某個相同的比例,因而永遠不會出現除盡的狀況。不妨假設一種最爲簡單的狀況,即 a 最多隻能包含一個 b 的長度,此時 c 等於 a – b 。解方程 a / b = b / (a – b) 能夠獲得 a : b = 1 : (√5 – 1) / 2 ,約等於一個你們很是熟悉的比值 1: 0.618 。因而咱們立刻得出:成黃金比例的兩條線段是不可公度的。
更典型的例子則是,正方形的邊長和對角線是不可公度的。讓咱們畫個圖來講明這一點。如圖,咱們試着用展轉相除求出邊長 AB 和對角線 AC 的最大公度單位。按照規則,第一步咱們應該用 AB 去度量 AC ,假設所得的零頭是 EC 。下一步,咱們應該用 EC 去度量 AB ,或者說用 EC 去度量 BC (反正正方形各邊都相等)。讓咱們以 EC 爲邊做一個小正方形 CEFG ,容易看出 F 點將正好落在 BC 上,同時三角形 AEF 和三角形 ABF 將會因爲 HL 全等。所以, EC = EF = BF 。注意到 BC 上已經有一段 BF 和 EC 是相等的了,於是咱們用 EC 去度量 BC 所剩的零頭,也就至關於用 EC 去度量 FC 所剩的零頭。結果又回到了最初的局面——尋找正方形的邊長和對角線的公度單位。於是,展轉相除永遠不會結束。線段 AB 的長度和線段 AC 的長度不能公度,它們處於兩個不一樣的世界中。
若是正方形 ABCD 的邊長 1 ,正方形的面積也就是 1 。從上圖中能夠看到,若以對角線 AC 爲邊作一個大正方形,它的面積就該是 2 。於是, AC 就應該是一個與自身相乘以後剛好等於 2 的數,咱們一般把這個數記做 √2 。《幾何本來》的第十卷專門研究不可公度量,其中就有一段 1 和 √2 不可公度的證實,但所用的方法不是咱們上面講的這種,而更接近於課本上的證實:設 √2 = p / q ,其中 p / q 已經是最簡分數,但推着推着就發現,這將意味着 p 和 q 都是偶數,與最簡分數的假設矛盾。
用今天的話來說, 1 和 √2 不可公度,實際上至關因而說 √2 是無理數。所以,古希臘人發現了無理數,這確實當屬不爭的事實。奇怪的是,無理數的發現經常會幾乎毫無根據地歸功於一個史料記載嚴重不足的古希臘數學家 Hippasus 。根據各類不靠譜的描述, Hippasus 的發現觸犯了 Pythagoras (古希臘哲學家)的教條,最後被溺死在了海里。
可公度線段和不可公度線段的概念與有理數和無理數的概念很是接近,咱們甚至能夠說明這兩個概念是等價的——它們之間有一種很巧妙的等價關係。注意到,即便 a 和 b 自己都是無理數, a 和 b 仍是有可能被公度的,例如 a = √2 而且 b = 2 · √2 的時候。不過,有一件事咱們能夠確定: a 和 b 的比值必定是一個有理數。事實上,能夠證實,線段 a 和 b 是可公度的,當且僅當 a / b 是一個有理數。線段 a 和 b 是可公度的,說明存在一個 c 以及兩個整數 m 和 n ,使得 a = m · c ,而且 b = n · c 。因而 a / b = (m · c) / (n · c) = m / n ,這是一個有理數。反過來,若是 a / b 是一個有理數,說明存在整數 m 和 n 使得 a / b = m / n ,等式變形後可得 a / m = b / n ,令這個商爲 c ,那麼 c 就能夠做爲 a 和 b 的公度單位。
有時候,「是否能夠公度」的說法甚至比「是否有理」更好一些,由於這是一個相對的概念,不是一個絕對的概念。當咱們遇到生活當中的某個物理量時,咱們毫不能指着它就說「這是一個有理的量」或者「這是一個無理的量」,咱們只能說,以某某某(好比 1 釐米、 1 英寸、 0.2 毫米或者一支鉛筆的長度等等)做爲單位來衡量時,這是一個有理的量或者無理的量。考慮到所選用的單位長度自己也是由另外一個物理量定義出來的(好比 1 米被定義爲光在真空中 1 秒走過的路程的 1 / 299792458 ),於是在討論一個物理量是不是有理數時,咱們討論的實際上是兩個物理量是否能夠被公度。
(二)中國剩餘定理
若是兩個正整數的最大公約數爲 1 ,咱們就說這兩個數是互質的。這是一個很是重要的概念。若是 a 和 b 互質,這就意味着分數 a / b 已經不能再約分了,意味着 a × b 的棋盤的對角線不會通過中間的任何交叉點,意味着循環長度分別爲 a 和 b 的兩個週期性事件一同上演,則新的循環長度最短爲 a · b 。
最後一點可能須要一些解釋。讓咱們來舉些例子。假若有 1 路和 2 路兩種公交車,其中 1 路車每 6 分鐘一班,2 路車每 8 分鐘一班。若是你剛剛錯過兩路公交車同時出發的壯景,那麼下一次再遇到這樣的事情是多少分鐘以後呢?固然, 6 × 8 = 48 分鐘,這是一個正確的答案,此時 1 路公交車正好是第 8 班, 2 路公交車正好是第 6 班。不過,實際上,在第 24 分鐘就已經出現了兩車再次同發的狀況了,此時 1 路車正好是第 4 班, 2 路車正好是第 3 班。可是,若是把例子中的 6 分鐘和 8 分鐘分別改爲 4 分鐘和 7 分鐘,那麼要想等到兩車再次同發,等到第 4 × 7 = 28 分鐘是必須的。相似的,假如某一首歌的長度正好是 6 分鐘,另外一首歌的長度正好是 8 分鐘,讓兩首歌各自循環播放, 6 × 8 = 48 分鐘以後你聽到的「合聲」將會重複,但實際上第 24 分鐘就已經開始重複了。但若兩首歌的長度分別是 4 分鐘和 7 分鐘,則必須到第 4 × 7 = 28 分鐘以後纔有重複,循環現象不會提早發生。
究其緣由,其實就是,對於任意兩個數,兩個數的乘積必定是它們的一個公倍數,但若這兩個數互質,則它們的乘積必定是它們的最小公倍數。事實上,咱們還能證實一個更強的結論: a 和 b 的最大公約數和最小公倍數的乘積,必定等於 a 和 b 的乘積。在第四節中,咱們會給出一個證實。
不少更復雜的數學現象也都跟互質有關。《孫子算經》卷下第二十六問:「今有物,不知其數。3、三數之,剩二;5、五數之,剩三;7、七數之,剩二。問物幾何?答曰:二十三。」翻譯過來,就是有一堆東西,三個三個數餘 2 ,五個五個數餘 3 ,七個七個數餘 2 ,問這堆東西有多少個?《孫子算經》給出的答案是 23 個。固然,這個問題還有不少其餘的解。因爲 105 = 3 × 5 × 7 ,於是 105 這個數被 3 除、被 5 除、被 7 除都能除盡。因此,在 23 的基礎上額外加上一個 105 ,獲得的 128 也是知足要求的解。固然,咱們還能夠在 23 的基礎上加上 2 個 105 ,加上 3 個 105 ,等等,所得的數都知足要求。除了形如 23 + 105n 的數之外,還有別的解嗎?沒有了。事實上,無論物體總數除以 3 的餘數、除以 5 的餘數以及除以 7 的餘數分別是多少,在 0 到 104 當中總存在惟一解;在這個解的基礎上再加上 105 的整倍數後,能夠獲得其餘全部的正整數解。後人將其表述爲「中國剩餘定理」:給出 m 個兩兩互質的整數,它們的乘積爲 P ;假設有一個未知數 M ,若是咱們已知 M 分別除以這 m 個數所得的餘數,那麼在 0 到 P – 1 的範圍內,咱們能夠惟一地肯定這個 M 。這能夠看做是 M 的一個特解。其餘全部知足要求的 M ,則正好是那些除以 P 以後餘數等於這個特解的數。注意,除數互質的條件是必需的,不然結論就不成立了。好比說,在 0 到 7 的範圍內,除以 4 餘 1 而且除以 2 也餘 1 的數有 2 個,除以 4 餘 1 而且除以 2 餘 0 的數則一個也沒有。
從某種角度來講,中國剩餘定理幾乎是顯然的。讓咱們以兩個除數的狀況爲例,來講明中國剩餘定理背後的直覺吧。假設兩個除數分別是 4 和 7 。下表顯示的就是各天然數除以 4 和除以 7 的餘數狀況,其中 x mod y 表示 x 除以 y 的餘數,這個記號後面還會用到。
i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 |
i mod 4 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 |
i mod 7 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 | 3 | 4 | 5 |
i | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
i mod 4 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 | 0 | 1 | 2 | 3 |
i mod 7 | 6 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 0 | 1 | 2 | 3 | 4 |
i mod 4 的值顯然是以 4 爲週期在循環, i mod 7 的值顯然是以 7 爲週期在循環。因爲 4 和 7 是互質的,它們的最小公倍數是 4 × 7 = 28 ,於是 (i mod 4, i mod 7) 的循環週期是 28 ,不會更短。所以,當 i 從 0 增長到 27 時, (i mod 4, i mod 7) 的值始終沒有出現重複。可是, (i mod 4, i mod 7) 也就只有 4 × 7 = 28 種不一樣的取值,於是它們正好既無重複又無遺漏地分給了 0 到 27 之間的數。這說明,每一個特定的餘數組合都在前 28 項中出現過,而且都只出現過一次。在此以後,餘數組合將產生長度爲 28 的循環,因而每一個特定的餘數組合都將會以 28 爲週期重複出現。這正是中國剩餘定理的內容。
中國剩餘定理有不少漂亮的應用,這裏我想說一個我最喜歡的。設想這樣一個場景:總部打算把一份祕密文件發送給 5 名特工,但直接把文件原封不動地發給每一個人,很難保障安全性。萬一有特工背叛或者被捕,把祕密泄露給了敵人怎麼辦?因而就有了電影和小說中常常出現的情節:把絕密文件拆成 5 份, 5 名特工各自只持有文件的 1/5 。不過,原來的問題並無完全解決,咱們只能祈禱壞人竊取到的並非最關鍵的文件片斷。所以,更好的作法是對原文件進行加密,每名特工只持有密碼的 1/5 ,這 5 名特工須要同時在場才能獲取文件全文。但這也有一個隱患:若是真的有特工被抓了,當壞人們發現只拿到其中一份密碼沒有任何用處的同時,特工們也會由於少一份密碼沒法解開全文而煩惱。此時,你或許會想,是否有什麼辦法可以讓特工們仍然能夠恢復原文,即便一部分特工被抓住了?換句話說,有沒有什麼密文發佈方式,使得只要 5 我的中半數以上的人在場就能夠解開絕密文件?這樣的話,壞人必需要能操縱半數以上的特工纔可能對祕密文件形成實質性的影響。這種祕密共享方式被稱爲 (3, 5) 門限方案,意即 5 我的中至少 3 人在場才能解開密文。
利用中國剩餘定理,咱們能夠獲得一種巧妙的方案。回想中國剩餘定理的內容:給定 m 個兩兩互質的整數,它們的乘積爲 P ;假設有一個未知數 M ,若是咱們已知 M 分別除以這 m 個數所得的餘數,那麼在 0 到 P – 1 的範圍內,咱們能夠惟一地肯定這個 M 。咱們能夠想辦法構造這樣一種狀況, n 個數之中任意 m 個的乘積都比 M 大,可是任意 m – 1 個數的乘積就比 M 小。這樣,任意 m 個除數就能惟一地肯定 M ,但 m – 1 個數就不足以求出 M 來。 Mignotte 門限方案就用到了這樣一個思路。咱們選取 n 個兩兩互質的數,使得最小的 m 個數的乘積比最大的 m – 1 個數的乘積還大。例如,在 (3, 5) 門限方案中,咱們能夠取 53 、 59 、 64 、 67 、 71 這 5 個數,前面 3 個數乘起來得 200128 ,然後面兩個數相乘才得 4757 。咱們把文件的密碼設爲一個 4757 和 200128 之間的整數,好比 123456 。分別算出 123456 除以上面那 5 個數的餘數,獲得 19 、 28 、 0 、 42 、 58 。而後,把 (53, 19) 、 (59, 28) 、 (64, 0) 、 (67, 42) 、 (71, 58) 分別告訴 5 名特工,也就是說特工 1 只知道密碼除以 53 餘 19 ,特工 2 只知道密碼除以 59 餘 28 ,等等。這樣,根據中國剩餘定理,任意 3 名特工碰頭後就能夠惟一地肯定出 123456 ,但根據 2 名特工手中的信息只能獲得成百上千個不定解。例如,假設咱們知道了 x 除以 59 餘 28 ,也知道了 x 除以 67 餘 42 ,那麼咱們只能肯定在 0 和 59 × 67 – 1 之間有一個解 913 ,在 913 的基礎上加上 59 × 67 的整倍數,能夠獲得其餘知足要求的 x ,而真正的 M 則能夠是其中的任意一個數。
不過,爲了讓 Mignotte 門限方案真正可行,咱們還須要一種根據餘數信息反推出 M 的方法。換句話說,咱們須要有一種通用的方法,可以回答《孫子算經》中提出的那個問題。咱們會在下一節中講到。
(三)擴展的展轉相除
中國剩餘定理是一個很基本的定理。不少數學現象均可以用中國剩餘定理來解釋。背九九乘法口訣表時,你或許會發現,寫下 3 × 1, 3 × 2, …, 3 × 9 ,它們的個位數正好遍歷了 1 到 9 全部的狀況。 7 的倍數、 9 的倍數也是如此,但 2 、 4 、 5 、 6 、 8 就不行。 3 、 7 、 9 這三個數究竟有什麼特別的地方呢?祕密就在於, 3 、 7 、 9 都是和 10 互質的。好比說 3 ,因爲 3 和 10 是互質的,那麼根據中國剩餘定理,在 0 到 29 之間必定有這樣一個數,它除以 3 餘 0 ,而且除以 10 餘 1 。它將會是 3 的某個整倍數,而且個位爲 1 。一樣地,在 0 到 29 之間也必定有一個 3 的整倍數,它的個位是 2 ;在 0 到 29 之間也必定有一個 3 的整倍數,它的個位是 3 ……而在 0 到 29 之間,除掉 0 之外, 3 的整倍數正好有 9 個,因而它們的末位就正好既無重複又無遺漏地取遍了 1 到 9 全部的數字。
這代表,若是 a 和 n 互質,那麼 a · x mod n = 1 、 a · x mod n = 2 等全部方程都是有解的。 18 世紀的法國數學家 Étienne Bézout 曾經證實了一個基本上與此等價的定理,這裏咱們姑且把它叫作「 Bézout 定理」。事實上,咱們不但知道上述方程是有解的,還能求出全部知足要求的解來。
咱們不妨花點時間,把方程 a · x mod n = b 和中國剩餘定理的關係再理一下。尋找方程 a · x mod n = b 的解,至關於尋找一個 a 的倍數使得它除以 n 餘 b ,或者說是尋找一個數 M 同時知足 M mod a = 0 且 M mod n = b 。若是 a 和 n 是互質的,那麼根據中國剩餘定理,這樣的 M 必定存在,而且找到一個這樣的 M 以後,在它的基礎上加減 a · n 的整倍數,能夠獲得全部知足要求的 M 。所以,爲了解出方程 a · x mod n = b 的全部解,咱們也只須要解出方程的某個特解就好了。假如咱們找到了方程 a · x mod n = b 中 x 的一個解,在這個解的基礎上加上或減去 n 的倍數(至關於在整個被除數 a · x 的基礎上加上或者減去 a · n 的倍數,這裏的 a · x 就是前面所說的 M ),就能獲得全部的解了。
更妙的是,咱們其實只須要考慮形如 a · x mod n = 1 的方程。由於,若是能解出這樣的方程, a · x mod n = 2 、 a · x mod n = 3 也都自動地獲解了。假如 a · x mod n = 1 有一個解 x = 100 ,因爲 100 個 a 除以 n 餘 1 ,天然 200 個 a 除以 n 就餘 2 , 300 個 a 除以 n 就餘 3 ,等等,等式右邊餘數不爲 1 的方程也都解開了。
讓咱們嘗試求解 115x mod 367 = 1 。注意,因爲 115 和 367 是互質的,所以方程確實有解。咱們解方程的基本思路是,不斷尋找 115 的某個倍數以及 367 的某個倍數,使得它們之間的差愈來愈小,直到最終變爲 1 。因爲 367 除以 115 得 3 ,餘 22 ,於是 3 個 115 只比 367 少 22 。因而, 15 個 115 就要比 5 個 367 少 110 ,從而 16 個 115 就會比 5 個 367 多 5 。好了,真正巧妙的就在這裏了: 16 個 115 比 5 個 367 多 5 ,但 3 個 115 比 1 個 367 少 22 ,二者結合起來,咱們便能找到 115 的某個倍數和 367 的某個倍數,它們只相差 2 : 16 個 115 比 5 個 367 多 5 ,說明 64 個 115 比 20 個 367 多 20 ,又考慮到 3 個 115 比 1 個 367 少 22 ,因而 67 個 115 只比 21 個 367 少 2 。如今,結合「少 2 」和「多 5 」兩個式子,咱們就能把差距縮小到 1 了: 67 個 115 比 21 個 367 少 2 ,說明 134 個 115 比 42 個 367 少 4 ,而 16 個 115 比 5 個 367 多 5 ,因而 150 個 115 比 47 個 367 多 1 。這樣,咱們就解出了一個知足 115x mod 367 = 1 的 x ,即 x = 150 。你們會發現,在求解過程,咱們至關於對 115 和 367 作了一遍展轉相除:咱們不斷給出 115 的某個倍數和 367 的某個倍數,經過展轉對比最近的兩個結果,讓它們的差距從「少 22 」縮小到「多 5 」,再到「少 2 」、「多 1 」,其中 22, 5, 2, 1 這幾個數正是用展轉相除法求 115 和 367 的最大公約數時將會經歷的數。於是,算法的步驟數仍然是對數級別的,即便面對上百位上千位的大數,計算機也毫無壓力。這種求解方程 a · x mod n = b 的算法就叫作「擴展的展轉相除法」。
注意,整個算法有時也會以「少 1 」的形式了結。例如,用此方法求解 128x mod 367 = 1 時,最後會得出 43 個 128 比 15 個 367 少 1 。這下怎麼辦呢?很簡單, 43 個 128 比 15 個 367 少 1 ,可是 367 個 128 顯然等於 128 個 367 ,對比兩個式子可知, 324 個 128 就會比 113 個 367 多 1 了,因而獲得 x = 324 。
最後還有一個問題:咱們最終總能到達「多 1 」或者「少 1 」,這正是由於一開始的兩個數是互質的。若是方程 a · x mod n = b 當中 a 和 n 不互質,它們的最大公約數是 d > 1 ,那麼在 a 和 n 之間作展轉相除時,算到 d 就直接終止了。天然,擴展的展轉相除也將在到達「多 1 」或者「少 1 」以前提早結束。那怎麼辦呢?咱們有一種巧妙的處理方法:以 d 爲單位從新去度量 a 和 n (或者說讓 a 和 n 都除以 d ),問題就變成咱們熟悉的狀況了。讓咱們來舉個例子吧。假如咱們要解方程 24 · x mod 42 = 30 ,爲了方便後面的解釋,咱們來給這個方程編造一個背景:說一盒雞蛋 24 個,那麼買多少盒雞蛋,才能讓全部的雞蛋 42 個 42 個地數最後正好能餘 30 個?咱們發現 24 和 42 不是互質的,擴展的展轉相除彷佛就沒有用了。不過不要緊。咱們找出 24 和 42 的最大公約數,發現它們的最大公約數是 6 。如今,讓 24 和 42 都來除以 6 ,分別獲得 4 和 7 。因爲 6 已是 24 和 42 的公約數中最大的了,所以把 24 和 42 當中的 6 除掉後,剩下的 4 和 7 就再也不有大於 1 的公約數,從而就是互質的了。好了,如今咱們把題目改編一下,把每 6 個雞蛋視爲一個新的單位量,好比說「 1 把」。記住, 1 把雞蛋就是 6 個雞蛋。因而,原問題就變成了,每一個盒子能裝 4 把雞蛋,那麼買多少盒雞蛋,才能讓全部的雞蛋 7 把 7 把地數,最後正好會餘 5 把?因而,方程就變成了 4 · x mod 7 = 5 。因爲此時 4 和 7 是互質的了,於是套用擴展的展轉相除法,此方程必定有解。能夠解出特解 x = 3 ,在它的基礎上加減 7 的整倍數,能夠獲得其餘全部知足要求的 x 。這就是改編以後的問題的解。可是,雖然說咱們對原題作了「改編」,題目內容自己卻徹底沒變,連數值都沒變,只不過換了一種說法。改編後的題目裏須要買 3 盒雞蛋,改編前的題目裏固然也是要買 3 盒雞蛋。 x = 3 ,以及全部形如 3 + 7n 的數,也都是原方程的解。
你們或許已經看到了,咱們成功地找到了 24 · x mod 42 = 30 的解,依賴於一個巧合: 24 和 42 的最大公約數 6 ,正好也是 30 的約數。所以,改用「把」做單位從新敘述問題,正好最後的「餘 30 個」變成了「餘 5 把」,依舊是一個整數。若是原方程是 24 · x mod 42 = 31 的話,咱們就沒有那麼走運了,問題將變成「買多少盒才能讓最後數完餘 5 又 1/6 把」。這怎麼可能呢?咱們是整把整把地買,整把整把地數,固然餘數也是整把整把的。所以,方程 24 · x mod 42 = 31 顯然無解。
綜上所述,若是關於 x 的方程 a · x mod n = b 當中的 a 和 n 不互質,那麼求出 a 和 n 的最大公約數 d 。若是 b 剛好是 d 的整倍數,那麼把方程中的 a 、 n 、 b 全都除以 d ,新的 a 和 n 就互質了,新的 b 也剛好爲整數,用擴展的展轉相除求解新方程,獲得的解也就是原方程的解。但若 b 不是 d 的整倍數,則方程無解。
擴展的展轉相除法有不少應用,其中一個有趣的應用就是你們小時候確定見過的「倒水問題」。假如你有一個 3 升的容器和一個 5 升的容器(以及充足的水源),如何精確地取出 4 升的水來?爲了敘述簡便,咱們不妨把 3 升的容器和 5 升的容器分別記做容器 A 和容器 B 。一種解法以下:
1. 將 A 裝滿,此時 A 中的水爲 3 升, B 中的水爲 0 升;
2. 將 A 裏的水所有倒入 B ,此時 A 中的水爲 0 升, B 中的水爲 3 升;
3. 將 A 裝滿,此時 A 中的水爲 3 升, B 中的水爲 3 升;
4. 將 A 裏的水倒入 B 直到把 B 裝滿,此時 A 中的水爲 1 升, B 中的水爲 5 升;
5. 將 B 裏的水所有倒掉,此時 A 中的水爲 1 升, B 中的水爲 0 升;
6. 將 A 裏剩餘的水所有倒入 B ,此時 A 中的水爲 0 升, B 中的水爲 1 升;
7. 將 A 裝滿,此時 A 中的水爲 3 升, B 中的水爲 1 升;
8. 將 A 裏的水所有倒入 B ,此時 A 中的水爲 0 升, B 中的水爲 4 升;
這樣,咱們就獲得 4 升的水了。顯然,這類問題能夠編出無窮多個來,好比可否用 7 升的水杯和 13 升的水杯量出 5 升的水,可否又用 9 升的水杯和 15 升的水杯量出 10 升的水,等等。這樣的問題有什麼萬能解法嗎?有!注意到,前面用 3 升的水杯和 5 升的水杯量出 4 升的水,看似複雜的步驟能夠簡單地歸納爲:不斷將整杯整杯的 A 往 B 裏倒,期間只要 B 被裝滿就把 B 倒空。因爲 3 × 3 mod 5 = 4 ,於是把 3 杯的 A 所有倒進 B 裏,而且每裝滿一個 B 就把水倒掉, B 裏面正好會剩下 4 升的水。相似地,用容積分別爲 a 和 b 的水杯量出體積爲 c 的水,實際上至關於解方程 a · x mod b = c 。若是 c 是 a 和 b 的最大公約數,或者能被它們的最大公約數整除,用擴展的展轉相除便能求出 x ,獲得對應的量水方案。特別地,若是兩個水杯的容積互質,問題將保證有解。若是 c 不能被 a 和 b 的最大公約數整除,方程就沒有解了,怎麼辦?不用着急,由於很顯然,此時問題正好也沒有解。比方說 9 和 15 都是 3 的倍數,那咱們就把每 3 升的水視做一個單位,因而你會發現,在 9 升和 15 升之間加加減減,倒來倒去,獲得的量永遠只能在 3 的倍數當中轉,毫不可能弄出 10 升的水來。這樣一來,咱們就給出了問題有解無解的判斷方法,以及在有解時生成一種合法解的方法,從而完美地解決了倒水問題。
最後,讓咱們把上一節留下的一點懸念給補完:怎樣求解《孫子算經》中的「今有物,不知其數」一題。已知有一堆東西,三個三個數餘 2 ,五個五個數餘 3 ,七個七個數餘 2 ,問這堆東西有多少個?根據中國剩餘定理,因爲除數 3 、 5 、 7 兩兩互質,於是在 0 到 104 之間,該問題有惟一的答案。咱們求解的基本思路就是,依次找出知足每一個條件,可是又不會破壞掉其餘條件的數。咱們首先要尋找一個數,它既是 5 的倍數,又是 7 的倍數,同時除以 3 正好餘 2 。這至關因而在問, 35 的多少倍除以 3 將會餘 2 。因而,咱們利用擴展的展轉相除法求解方程 35x mod 3 = 2 。這個方程是必定有解的,由於 5 和 3 、 7 和 3 都是互質的,從而 5 × 7 和 3 也是互質的(到了下一節,這一點會變得很顯然)。解這個方程可得 x = 1 。因而, 35 就是咱們要找到的數。第二步,是尋找這麼一個數,它既是 3 的倍數,又是 7 的倍數,同時除以 5 餘 3 。這至關於求解方程 21x mod 5 = 3 ,根據和剛纔相同的道理,這個方程必定有解。能夠解得 x = 3 ,所以咱們要找的數就是 63 。最後,咱們須要尋找一個數,它能同時被 3 和 5 整除,但被 7 除餘 2 。這至關於求解方程 15x mod 7 = 2 ,解得 x = 2 。咱們想要找的數就是 30 。如今,若是咱們把 35 、 63 和 30 這三個數加在一塊兒會怎麼樣?它將會同時知足題目當中的三個條件!它知足「三個三個數餘 2 」,由於 35 除以 3 是餘 2 的,然後面兩個數都是 3 的整倍數,因此加在一塊兒後除以 3 仍然餘 2 。相似地,它知足「五個五個數餘 3 」,由於 63 除以 5 餘 3 ,另外兩個數都是 5 的倍數。相似地,它也知足「七個七個數餘 2 」,於是它就是原問題的一個解。你能夠驗證一下, 35 + 63 + 30 = 128 ,它確實知足題目的全部要求!爲了得出一個 0 到 104 之間的解,咱們在 128 的基礎上減去一個 105 ,因而正好獲得《孫子算經》當中給出的答案, 23 。
已知 M 除以 m 個兩兩互質的數以後所得的餘數,利用相似的方法總能反解出 M 來。至此,咱們也就完成了 Mignotte 祕密共享方案的最後一環。
(四)Fermat 小定理
不少天然數均可以被分解成一些更小的數的乘積,例如 12 能夠被分紅 4 乘以 3 ,其中 4 還能夠繼續地被分紅 2 乘以 2 ,於是咱們能夠把 12 寫做 2 × 2 × 3 。此時, 2 和 3 都不能再繼續分解了,它們是最基本、最純淨的數。咱們就把這樣的數叫作「質數」或者「素數」。一樣地, 2 、 3 、 5 、 7 、 11 、 13 等等都是不可分解的,它們也都是質數。它們是天然數的構件,是天然數世界的基本元素。 12 是由兩個 2 和一個 3 組成的,正如水分子是由兩個氫原子和一個氧原子組成的同樣。只不過,和化學世界不一樣的是,天然數世界裏的基本元素是無限的——質數有無窮多個。
關於爲何質數有無窮多個,古希臘的 Euclid 有一個很是漂亮的證實。假設質數只有有限個,其中最大的那個質數爲 p 。如今,把全部的質數所有乘起來,再加上 1 ,獲得一個新的數 N 。也就是說, N 等於 2 · 3 · 5 · 7 · … · p + 1 。注意到, N 除以每個質數都會餘 1 ,好比 N 除以 2 就會商 3 · 5 · 7 · … · p 餘 1 , N 除以 3 就會商 2 · 5 · 7 · … · p 餘 1 ,等等。這意味着, N 不能被任何一個質數整除,換句話說 N 是不能被分解的,它自己就是質數。然而這也不對,由於 p 已是最大的質數了,因而產生了矛盾。這說明,咱們剛開始的假設是錯的,質數應該有無窮多個。須要額外說明的一點是,這個證實容易讓人產生一個誤解,即把頭 n 個質數乘起來再加 1 ,總能產生一個新的質數。這是不對的,由於既然咱們沒法把所有質數都乘起來,那麼所得的數就有多是由那些咱們沒有乘進去的質數構成的,好比 2 · 3 · 5 · 7 · 11 · 13 + 1 = 30031 ,它能夠被分解成 59 × 509 。
從古希臘時代開始,人們就近乎瘋狂地想要認識天然數的本質規律。組成天然數的基本元素天然地就成爲了一個絕佳的突破口,因而對質數的研究成爲了探索天然數世界的一個永久的話題。這就是咱們今天所說的「數論」。
用質數理論來研究數,真的會很是方便。 a 是 b 的倍數(或者說 a 能被 b 整除, b 是 a 的約數),意思就是 a 擁有 b 所含的每一種質數,並且個數不會更少。咱們舉個例子吧,好比說 b = 12 ,它能夠被分解成 2 × 2 × 3 , a = 180 ,能夠被分解成 2 × 2 × 3 × 3 × 5 。 b 裏面有兩個 2 ,這不稀罕, a 裏面也有兩個 2 ; b 裏面有一個 3 ,這也沒什麼, a 裏面有兩個 3 呢。何況, a 裏面還包含有 b 沒有的質數, 5 。對於每一種質數, b 裏面所含的個數都比不過 a ,這其實就代表了 b 就是 a 的約數。
如今,假設 a = 36 = 2 × 2 × 3 × 3 , b = 120 = 2 × 2 × 2 × 3 × 5 。那麼, a 和 b 的最大公約數是多少?咱們能夠依次考察,最大公約數裏面能夠包含哪些質數,每一個質數都能有多少個。這個最大公約數最多能夠包含多少個質數 2 ?顯然最多隻能包含兩個,不然它就不能整除 a 了;這個最大公約數最多能夠包含多少個質數 3 ?顯然最多隻能包含一個,不然它就不能整除 b 了;這個最大公約數最多能夠包含多少個質數 5 ?顯然一個都不能有,不然它就不能整除 a 了。所以, a 和 b 的最大公約數就是 2 × 2 × 3 = 12 。
在構造 a 和 b 的最小公倍數時,咱們但願每種質數在數量足夠的前提下越少越好。爲了讓這個數既是 a 的倍數,又是 b 的倍數,三個 2 是必需的;爲了讓這個數既是 a 的倍數,又是 b 的倍數,兩個 3 是必需的;爲了讓這個數既是 a 的倍數,又是 b 的倍數,那一個 5 也是必不可少的。所以, a 和 b 的最小公倍數就是 2 × 2 × 2 × 3 × 3 × 5 = 360 。
你會發現, 12 × 360 = 36 × 120 ,最大公約數乘以最小公倍數正好等於原來兩數的乘積。這其實並不奇怪。在最大公約數裏面,每種質數各有多少個,取決於 a 和 b 當中誰所含的這種質數更少一些。在最小公倍數裏面,每種質數各有多少個,取決於 a 和 b 當中誰所含的這種質數更多一些。所以,對於每一種質數而言,最大公約數和最小公倍數裏面一共包含了多少個這種質數, a 和 b 裏面也就一共包含了多少個這種質數。最大公約數和最小公倍數乘在一塊兒,也就至關因而把 a 和 b 各自所包含的質數都乘了個遍,天然也就等於 a 與 b 的乘積了。這當即帶來了咱們熟悉的推論:若是兩數互質,這兩數的乘積就是它們的最小公倍數。
第三節裏,咱們曾說到,「由於 5 和 3 、 7 和 3 都是互質的,從而 5 × 7 和 3 也是互質的」。利用質數的觀點,這很容易解釋。兩個數互質,至關因而說這兩個數不包含任何相同的質數。若是 a 與 c 互質, b 與 c 互質,顯然 a · b 也與 c 互質。另一個值得注意的結論是,若是 a 和 b 是兩個不一樣的質數,則這兩個數顯然就直接互質了。事實上,只要知道了 a 是質數,而且 a 不能整除 b ,那麼無論 b 是否是質數,咱們也都能肯定 a 和 b 是互質的。咱們後面會用到這些結論。
在不少場合中,質數都扮演着重要的角色。 1640 年,法國業餘數學家 Pierre de Fermat (一般譯做「費馬」)發現,若是 n 是一個質數的話,那麼對於任意一個數 a , a 的 n 次方減去 a 以後都將是 n 的倍數。例如, 7 是一個質數,因而 27 – 2 、 37 – 3 , 47 – 4 ,甚至 1007 – 100 ,通通都能被 7 整除。但 15 不是質數(它能夠被分解爲 3 × 5 ),因而 a15 – a 除以 15 以後就可能會出現五花八門的餘數了。這個規律在數論研究中是如此基本如此重要,以致於它有一個專門的名字—— Fermat 小定理。做爲一個業餘數學家, Fermat 發現了不少數論中精彩的結論, Fermat 「小」定理只是其中之一。雖然與本文無關,但有一點不得不提:以 Fermat 的名字命名的東西里,最著名的要數 Fermat 大定理了(其實譯做「 Fermat 最終定理」更貼切)。若是你沒據說過,上網查查,或者看看相關的書籍。千萬不要錯過與此相關的一系列激動人心的故事。
言歸正傳。 Fermat 小定理有一個很是精彩的證實。咱們不妨以「 37 – 3 能被 7 整除」爲例進行說明,稍後你會發現,對於其餘的狀況,道理是同樣的。首先,讓我來解釋一下「循環移位」的意思。想象一個由若干字符所組成的字符串,在一塊大小恰好合適的 LED 屏幕上滾動顯示。比方說, HELLOWORLD 就是一個 10 位的字符串,而咱們的 LED 屏幕很少很多正好容納 10 個字符。剛開始,屏幕上顯示 HELLOWORLD 。下一刻,屏幕上的字母 H 將會移出屏幕,但又會從屏幕右邊移進來,因而屏幕變成了 ELLOWORLDH 。下一刻,屏幕變成了 LLOWORLDHE ,再下一刻又變成了 LOWORLDHEL 。移動到第 10 次,屏幕又會回到 HELLOWORLD 。在此過程當中,屏幕上曾經顯示過的 ELLOWORLDH, LLOWORLDHE, LOWORLDHEL, … ,都是由初始的字符串 HELLOWORLD 經過「循環移位」得來的。如今,考慮全部僅由 A 、 B 、 C 三個字符組成的長度爲 7 的字符串,它們一共有 37 個。若是某個字符串循環移位後能夠獲得另外一個字符串,咱們就認爲這兩個字符串屬於同一組字符串。好比說, ABBCCCC 和 CCCABBC 就屬於同一組字符串,而且該組內還有其餘 5 個字符串。因而,在全部 37 個字符串當中,除了 AAAAAAA 、 BBBBBBB 、 CCCCCCC 這三個特殊的字符串之外,其餘全部的字符串正好都是每 7 個一組。這說明, 37 – 3 能被 7 整除。
在這個證實過程當中,「 7 是質數」這個條件用到哪裏去了?仔細想一想你會發現,正由於 7 是質數,因此每一組裏纔剛好有 7 個字符串。若是字符串的長度不是 7 而是 15 的話,有些組裏將會只含 3 個或者 5 個字符串。比方說, ABCABCABCABCABC 所在的組裏就只有 3 個字符串,循環移動 3 個字符後,字符串將會和原來重合。
Fermat 小定理有一個等價的表述:若是 n 是一個質數的話,那麼對於任意一個數 a ,隨着 i 的增長, a 的 i 次方除以 n 的餘數將會呈現出長度爲 n – 1 的週期性(下表所示的是 a = 3 、 n = 7 的狀況)。這是由於,根據前面的結論, an 與 a 的差可以被 n 整除,這說明 an 和 a 分別都除以 n 以後將會擁有相同的餘數。這代表,依次計算 a 的 1 次方、 2 次方、 3 次方除以 n 的餘數,算到 a 的 n 次方時,餘數將會變得和最開始相同。另外一方面, ai 除以 n 的餘數,徹底由 ai-1 除以 n 的餘數決定。比方說,假如咱們已經知道 33 除以 7 等於 3 餘 6 ,這代表 33 裏包含 3 個 7 以及 1 個 6 ;所以, 34 裏就包含 9 個 7 以及 3 個 6 ,或者說 9 個 7 以及 1 個 18 。爲了獲得 34 除以 7 的餘數,只須要看看 18 除以 7 餘多少就好了。可見,要想算出 ai-1 · a 除以 n 的餘數,咱們不須要完整地知道 ai-1 的值,只須要知道 ai-1 除以 n 的餘數就能夠了。反正最後都要對乘積取餘,相乘以前事先對乘數取餘不會對結果形成影響(記住這一點,後面咱們還會屢次用到)。既然第 n 個餘數和第 1 個餘數相同,而餘數序列的每一項都由上一項決定,那麼第 n + 1 個、第 n + 2 個餘數也都會跟着和第 2 個、第 3 個餘數相同,餘數序列今後處開始重複,造成長爲 n – 1 的週期。
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
3i | 3 | 9 | 27 | 81 | 243 | 729 | 2187 | 6561 | 19683 | 59049 | 177147 | 531441 | 1594323 | 4782969 | 14348907 |
3i mod 7 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 | 6 |
須要注意的是, n – 1 並不見得是最小的週期。下表所示的是 2i 除以 7 的餘數狀況,餘數序列確實存在長度爲 6 的週期現象,但實際上它有一個更小的週期, 3 。
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
2i | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8192 | 16384 | 32768 |
2i mod 7 | 2 | 4 | 1 | 2 | 4 | 1 | 2 | 4 | 1 | 2 | 4 | 1 | 2 | 4 | 1 |
那麼,若是除數 n 不是質數,而是兩個質數的乘積(好比 35 ),週期的長度又會怎樣呢?讓咱們試着看看, 3i 除以 35 的餘數有什麼規律吧。注意到 5 和 7 是兩個不一樣的質數,於是它們是互質的。根據中國剩餘定理,一個數除以 35 的餘數就能夠惟一地由它除以 5 的餘數和除以 7 的餘數肯定出來。於是,爲了研究 3i 除以 35 的餘數,咱們只須要觀察 (3i mod 5, 3i mod 7) 便可。由 Fermat 小定理可知,數列 3i mod 5 有一個長爲 4 的週期,數列 3i mod 7 有一個長爲 6 的週期。 4 和 6 的最小公倍數是 12 ,所以 (3i mod 5, 3i mod 7) 存在一個長爲 12 的週期。到了 i = 13 時, (3i mod 5, 3i mod 7) 將會和最開始重複,因而 3i 除以 35 的餘數將今後處開始發生循環。
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
3i mod 5 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 |
3i mod 7 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 | 6 | 4 |
3i mod 35 | 3 | 9 | 27 | 11 | 33 | 29 | 17 | 16 | 13 | 4 | 12 | 1 | 3 | 9 | 27 | 11 | 33 | 29 | 17 | 16 | 13 | 4 |
i | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
3i mod 5 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 | 3 | 4 | 2 | 1 |
3i mod 7 | 5 | 1 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 | 6 | 4 | 5 | 1 | 3 | 2 |
3i mod 35 | 12 | 1 | 3 | 9 | 27 | 11 | 33 | 29 | 17 | 16 | 13 | 4 | 12 | 1 | 3 | 9 | 27 | 11 | 33 | 29 | 17 | 16 |
相似地,假如某個整數 n 等於兩個質數 p 、 q 的乘積,那麼對於任意一個整數 a ,寫出 ai依次除以 n 所得的餘數序列, p – 1 和 q – 1 的最小公倍數將成爲該序列的一個週期。事實上, p – 1 和 q – 1 的任意一個公倍數,好比表達起來最方便的 (p – 1) × (q – 1) ,也將成爲該序列的一個週期。這個規律能夠用來解釋不少數學現象。例如,你們可能早就注意過,任何一個數的乘方,其個位數都會呈現長度爲 4 的週期(這包括了週期爲 1 和週期爲 2 的狀況)。其實這就是由於, 10 等於 2 和 5 這兩個質數的乘積,而 (2 – 1) × (5 – 1) = 4,所以任意一個數的乘方除以 10 的餘數序列都將會產生長爲 4 的週期。
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
3i | 3 | 9 | 27 | 81 | 243 | 729 | 2187 | 6561 | 19683 | 59049 |
3i的個位 | 3 | 9 | 7 | 1 | 3 | 9 | 7 | 1 | 3 | 9 |
4i | 4 | 16 | 64 | 256 | 1024 | 4096 | 16384 | 65536 | 262144 | 1048576 |
4i的個位 | 4 | 6 | 4 | 6 | 4 | 6 | 4 | 6 | 4 | 6 |
5i | 5 | 25 | 125 | 625 | 3125 | 15625 | 78125 | 390625 | 1953125 | 9765625 |
5i的個位 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 5 | 5 |
1736 年,瑞士大數學家 Leonhard Euler (一般譯做「歐拉」)對此作過進一步研究,討論了當 n 是更復雜的數時推導餘數序列循環週期的方法,獲得了一個很是漂亮的結果:在 1 到 n 的範圍內有多少個數和 n 互質(包括 1 在內), a 的 i 次方除以 n 的餘數序列就會有一個多長的週期。這個經典的結論就叫作「 Euler 定理」。做爲歷史上最高產的數學家之一, Euler 的一輩子當中發現的定理實在是太多了。爲了把上述定理和其餘的「 Euler 定理」區別開來,有時也稱它爲「 Fermat – Euler 定理」。這是一個很是深入的定理,它有一些很是具備啓發性的證實方法。考慮到在後文的講解中這個定理不是必需的,所以這裏就不詳說了。
這些東西有什麼用呢?沒有什麼用。幾千年來,數論一直沒有任何實際應用,數學家們研究數論的動力徹底來源於數字自己的魅力。不過,到了 1970 年左右,狀況有了戲劇性的變化。
有的朋友可能要說了,你怎麼賴皮呢,「沒有任何實際應用」,那剛纔的 Mignotte 祕密共享方案算什麼?其實, Mignotte 祕密共享方案已是很後來的事了。祕密共享原本遠沒那麼複雜,爲了使得只要 5 我的中半數以上的人在場就能夠解開絕密文件,總部能夠把絕密文件鎖進一個特殊的機械裝置裏,裝置上有三個如出一轍的鎖孔,並配有 5 把徹底相同且不可複製的鑰匙。只有把其中任意 3 把鑰匙同時插進鑰匙孔並一塊兒轉動,才能打開整個裝置。把 5 把鑰匙分發給 5 名特工,目的就直接達到了。於是,一般狀況下咱們並不須要動用 Mignotte 祕密共享方案。那麼,利用中國剩餘定理費盡周折弄出的 Mignotte 祕密共享方案,意義究竟何在呢?這種新的祕密共享方案直到 1983 年才被提出,想必是爲了解決某個之前未曾有過的需求。 20 世紀中後期究竟出現了什麼?答案即是——計算機網絡。鎖孔方案只適用於物理世界,不能用於網絡世界。爲了在網絡世界中共享祕密,咱們須要一種純信息層面的、只涉及數據交換的新方法, Mignotte 祕密共享方案才應運而生。
數論知識開始煥發新生,一切都是由於這該死的計算機網絡。
(五)公鑰加密的可能性
計算機網絡的出現無疑下降了交流的成本,但卻給信息安全帶來了難題。在計算機網絡中,一切都是數據,一切都是數字,一切都是透明的。假如你的朋友要給你發送一份絕密文件,你如何阻止第三者在大家的通訊線路的中間節點上竊走信息?其中一種方法就是,讓他對發送的數據進行加密,密碼只有大家兩人知道。可是,這個密碼又是怎麼商定出來的呢?直接叫對方編好密碼發給你的話,密碼自己會有泄漏的風險;若是讓對方給密碼加個密再發過來呢,給密碼加密的方式仍然不知道該怎麼肯定。若是是朋友之間的通訊,把兩人已知的小祕密用做密鑰(例如約定密鑰爲 A 的生日加上 B 的手機號)或許能讓人放心許多;但對於不少更常見的情形,比方說用戶在郵件服務提供商首次申請郵箱時,會話雙方徹底沒有任何能夠利用的公共祕密。此時,咱們須要一個絕對邪的辦法……若是說我不告訴任何人解密的算法呢?這樣的話,我就能夠公開加密的方法,任何人都可以按照這種方法對信息進行加密,可是隻有我本身才知道怎樣給由此獲得的密文解密。而後,讓對方用這種方法給文件加密傳過來,問題不就解決了嗎?這聽上去彷佛不太可能,由於直覺上,知道加密的方法也就知道了解密的方法,只須要把過程反過來作就好了。加密算法和解密算法有多是不對稱的嗎?
有可能。小時候我常常在朋友之間表演這麼一個數學小魔術:讓對方任意想一個三位數,把這個三位數乘以 91 的乘積的末三位告訴我,我便能猜出對方原來想的數是多少。若是對方內心想的數是 123 ,那麼對方就計算出 123 × 91 等於 11193 ,並把結果的末三位 193 告訴我。看起來,這麼作彷佛損失了很多信息,讓我無法反推出原來的數。不過,我仍然有辦法:只須要把對方告訴個人結果再乘以 11 ,乘積的末三位就是對方剛開始想的數了。你能夠驗證一下, 193 × 11 = 2123 ,末三位正是對方所想的祕密數字!其實道理很簡單, 91 乘以 11 等於 1001 ,而任何一個三位數乘以 1001 後,末三位顯然都不變(例如 123 乘以 1001 就等於 123123 )。先讓對方在他所想的數上乘以 91 ,假設乘積爲 X ;我再在 X 的基礎上乘以 11 ,其結果至關於我倆合做把原數乘以了 1001 ,天然末三位又變了回去。然而, X 乘以 11 後的末三位是什麼,只與 X 的末三位有關。所以,對方只須要告訴我 X 的末三位就好了,這並不會丟掉信息。站在數論的角度來看,上面這句話有一個更好的解釋:反正最後都要取除以 1000 的餘數,在中途取一次餘數不會有影響(還記得嗎,「反正最後都要對乘積取餘,相乘以前事先對乘數取餘不會對結果形成影響」)。知道原理後,咱們能夠構造一個定義域和值域更大的加密解密系統。比方說,任意一個數乘以 500000001 後,末 8 位都不變,而 500000001 = 42269 × 11829 ,因而你來乘以 42269 ,我來乘以 11829 ,又一個加密解密不對稱的系統就構造好了。這是一件很酷的事情,任何人均可以按照個人方法加密一個數,可是隻有我才知道怎麼把所得的密文變回去。在現代密碼學中,數論漸漸地開始有了本身的地位。
不過,加密和解密的過程不對稱,並不妨礙咱們根據加密方法推出解密方法來,雖然這可能得費些功夫。比方說,剛纔的加密算法就能被破解:猜出對方內心想的數至關於求解形如 91x mod 1000 = 193 的方程,這能夠利用擴展的展轉相除法很快求解出來,根本不須要其餘的雕蟲小技(注意到 91 和 1000 是互質的,根據 Bézout 定理,方程確實保證有解)。爲了獲得一個能夠公開加密鑰匙的算法,咱們還須要從理論上說服本身,在只知道加密鑰匙的狀況下構造出解密鑰匙是很是很是困難的。
1970 年左右,科學家們開始認真地思考「公鑰加密系統」的可能性。 1977 年,來自 MIT 的 Ron Rivest 、 Adi Shamir 和 Leonard Adleman 三我的合寫了一篇論文,給出了一種至今仍然安全的公鑰加密算法。隨後,該算法以三人名字的首字母命名,即 RSA 算法。
RSA 算法爲何會更加安全呢?由於 RSA 算法用到了一種很是犀利的不對稱性——大數分解難題。
爲了判斷一個數是否是質數,最笨的方法就是試除法——看它能不能被 2 整除,若是不能的話再看它能不能被 3 整除,這樣不斷試除上去。直到除遍了全部比它小的數,都還不能把它分解開來,它就是質數了。可是,試除法的速度太慢了,咱們須要一些高效的方法。 Fermat 素性測試就是一種比較經常使用的高效方法,它基於以下原理: Fermat 小定理對一切質數都成立。回想 Fermat 小定理的內容:若是 n 是一個質數的話,那麼對於任意一個數 a , a 的 n 次方減去 a 以後都將是 n 的倍數。爲了判斷 209 是否是質數,咱們隨便選取一個 a ,好比 38 。結果發現,38209 – 38 除以 209 餘 114 (稍後咱們會看到,即便把 209 換成上百位的大數,利用計算機也能很快算出這個餘數來),不能被 209 整除。因而, 209 確定不是質數。咱們再舉一個例子。爲了判斷 221 是否是質數,咱們隨機選擇 a ,好比說仍是 38 吧。你會發現 38221– 38 除以 221 正好除盡。那麼, 221 是否就必定是質數了呢?麻煩就麻煩在這裏:這並不能告訴咱們 221 是質數,由於 Fermat 小定理畢竟只說了對一切質數都成立,但沒說對其餘的數成不成立。萬一 221 根本就不是質數,但 a = 38 時碰巧也符合 Fermat 小定理呢?爲了保險起見,咱們不妨再選一個不一樣的 a 值。比方說,令 a = 26 ,能夠算出 26221 – 26 除以 221 餘 169 ,於是 221 果真並非質數。這個例子告訴了咱們,若是運氣很差的話,所選的 a 值會讓不是質數的數也能騙過檢測,雖然這個機率其實並不大。所以,咱們一般的作法即是,多選幾個不一樣的 a ,只要有一次沒經過測試,被檢測的數必定不是質數,若是都經過測試了,則被檢測的數極可能是質數。沒錯, Fermat 素性測試的效率很是高,但它是基於必定機率的,有誤報的可能。若是發現某個數 n 不知足 Fermat 小定理,它必定不是質數;但若是發現某個數 n 總能經過 Fermat 小定理的檢驗,只能說明它有很大的概率是質數。
Fermat 素性測試真正麻煩的地方就是,竟然有這麼一種極其特殊的數,它不是質數,但對於任意的 a 值,它都能經過測試。這樣的數叫作 Carmichael 數,最小的一個是 561 ,接下來的幾個則是 1105, 1729, 2465, 2821, 6601, 8911… 雖然很少,但很致命。所以,在實際應用時,咱們一般會選用 Miller-Rabin 素性測試算法。這個算法以 Gary Miller 的研究成果爲基礎,由 Michael Rabin 提出,時間大約是 1975 年。它能夠看做是對 Fermat 素性測試的改良。若是選用了 k 個不一樣的 a 值,那麼 Miller-Rabin 素性測試算法出現誤判的機率不會超過 1 / 4k ,足以應付不少現實須要了。
有沒有什麼高效率的、肯定性的質數斷定算法呢?有,不過這已是很後來的事情了。 2002 年, Manindra Agrawal 、 Neeraj Kayal 和 Nitin Saxena 發表了一篇重要的論文 PRIMES is in P ,給出了第一個高效判斷質數的肯定性算法,並以三人名字的首字母命名,叫作 AKS 素性測試。不過,已有的質數判斷算法已經作得很好了,所以對於 AKS 來講,更重要的是它的理論意義。
有了判斷質數的算法,要想生成一個很大的質數也並不困難了。一種常見的作法是,先選定一串連續的大數,而後去掉其中全部能被 2 整除的數,再去掉全部能被 3 整除的數,再去掉全部能被 5 整除的數……直到把某個範圍內(好比說 65000 之內)的全部質數的倍數全都去掉。剩下的數就很少了,利用判斷質數的算法對它們一一進行測試,不久便能找出一個質數來。
怪就怪在,咱們能夠高效地判斷一個數是否是質數,咱們能夠高效地生成一個很大的質數,但咱們卻始終找不到高效的大數分解方法。任意選兩個比較大的質數,好比 19394489 和 27687937 。咱們可以很容易計算出 19394489 乘以 27687937 的結果,它等於 536993389579193 ;可是,除了試除法之外,目前尚未什麼本質上更有效的方法(也很難找到更有效的方法)可以把 536993389579193 迅速分解成 19394489 乘以 27687937 。這種不對稱性很快便成了現代密碼學的重要基礎。讓咱們經過一個有趣的例子來看看,大數分解的困難性是如何派上用場的吧。
假如你和朋友用短信吵架,最後決定拋擲硬幣來分勝負,正面表示你獲勝,反面表示對方獲勝。問題來了——兩我的如何經過短信公平地拋擲一枚硬幣?你可讓對方真的拋擲一枚硬幣,而後將結果告訴你,不過前提是,你必須充分信任對方纔行。在雙方互不信任的狀況下,還有辦法模擬一枚虛擬硬幣嗎?在咱們生活中,有一個常見的解決方法:考你一道題,好比「明天是否會下雨」、「地球的半徑是多少」或者「《新華字典》第 307 頁的第一個字是什麼」,猜對了就算你贏,猜錯了就算你輸。不過,上面提到的幾個問題顯然都不是徹底公平的。咱們須要一類能快速生成的、很難出現重複的、解答不具技巧性的、猜對猜錯概率均等的、具備一個確鑿的答案而且知道答案後很容易驗證答案正確性的問題。大數分解爲咱們構造難題提供了一個模板。比方說,讓對方選擇兩個 90 位的大質數,或者三個 60 位的大質數,而後把乘積告訴你。不管是哪一種狀況,你都會獲得一個大約有 180 位的數。你須要猜想這個數到底是兩個質數乘在一塊兒得來的,仍是三個質數乘在一塊兒得來的。猜對了就算正面,你贏;猜錯了就算反面,對方贏。宣佈你的猜想後,讓對方公開他原先想的那兩個數或者三個數,由你來檢查它們是否確實都是質數,乘起來是否等於以前給你的數。
大數分解難題成爲了 RSA 算法的理論基礎。
(六)RSA 算法
全部工做都準備就緒,下面咱們能夠開始描述 RSA 算法了。
首先,找兩個質數,好比說 13 和 17 。實際使用時,咱們會選取大得多的質數。把它們乘在一塊兒,得 221 。再計算出 (13 – 1) × (17 – 1) = 192。根據前面的結論,任選一個數 a ,它的 i 次方除以 221 的餘數將會呈現長度爲 192 的週期(雖然可能存在更短的週期)。換句話說,對於任意的一個 a,a, a193, a385, a577, … 除以 221 都擁有相同的餘數。注意到, 385 能夠寫成 11 × 35 ……嘿嘿,這下咱們就又能變數學小魔術了。叫一我的隨便想一個不超過 221 的數,好比 123 。算出 123 的 11 次方除以 221 的餘數,把結果告訴你。若是他的計算是正確的,你將會獲得 115 這個數。看上去,咱們彷佛很難把 115 還原回去,但實際上,你只須要計算 115 的 35 次方,它除以 221 的餘數就會變回 123 。這是由於,對方把他所想的數 123 連乘了 11 次,獲得了一個數 X ;你再把這個 X 乘以自身 35 次,這至關於大家合做把 123 連乘了 385 次,根據週期性現象,它除以 221 的餘數仍然是 123 。然而,計算 35 個 X 連乘時,反正咱們要取乘積除以 221 的餘數,所以咱們沒必要完整地獲知 X 的值,只須要知道 X 除以 221 的餘數就夠了。於是,讓對方只告訴你 X 取餘後的結果,不會形成信息的丟失。
不過這一次,只知道加密方法後,構造解密方法就難了。容易看出, 35 之因此能做爲解密的鑰匙,是由於 11 乘以 35 的結果在數列 193, 385, 577, … 當中,它除以 192 的餘數正好是 1 。所以,攻擊者能夠求解 11x mod 192 = 1 ,找出知足要求的密鑰 x 。但關鍵是,他怎麼知道 192 這個數?要想獲得 192 這個數,咱們須要把 221 分解成 13 和 17 的乘積。當最初所選的質數很是很是大時,這一點是很難辦到的。
根據這個原理,咱們能夠選擇兩個充分大的質數 p 和 q ,並算出 n = p · q 。接下來,算出 m = (p – 1)(q – 1) 。最後,找出兩個數 e 和 d ,使得 e 乘以 d 的結果除以 m 餘 1 。怎麼找到這樣的一對 e 和 d 呢?很簡單。首先,隨便找一個和 m 互質的數(這是能夠作到的,比方說,能夠不斷生成小於 m 的質數,直到找到一個不能整除 m 的爲止),把它用做咱們的 e 。而後,求解關於 d 的方程 e · d mod m = 1(就像剛纔攻擊者想要作的那樣,只不過咱們有 m 的值而他沒有)。 Bézout 定理將保證這樣的 d 必定存在。
好了,如今, e 和 n 就能夠做爲加密鑰匙公之於衆, d 和 n 則是隻有本身知道的解密鑰匙。於是,加密鑰匙有時也被稱做公鑰,解密鑰匙有時也被稱做私鑰。任何知道公鑰的人均可以利用公式 c = ae mod n 把原始數據 a 加密成一個新的數 c ;私鑰的持有者則能夠計算 cdmod n ,恢復出原始數據 a 來。不過這裏還有個大問題: e 和 d 都是上百位的大數,怎麼才能算出一個數的 e 次方或者一個數的 d 次方呢?顯然不能老老實實地算那麼屢次乘法,否則效率實在過低了。好在,「反覆平方」能夠幫咱們快速計算出一個數的乘方。比方說,計算 a35 至關於計算 a34 · a ,也即 (a17)2 · a ,也即 (a16 · a)2 · a,也即 ((a8)2 · a)2 · a……最終簡化爲 ((((a2)2)2)2 · a)2 · a ,於是 7 次乘法操做就夠了。在簡化的過程當中, a 的指數以成半的速度遞減,於是在最後的式子當中,所需的乘法次數也是對數級別的,計算機徹底可以承受。不過,減小了運算的次數,並無減少數的大小。 a 已是一個數十位上百位的大數了,再拿 a 和它本身多乘幾回,很快就會變成一個計算機內存沒法容納的超級大數。怎麼辦呢?別忘了,「反正最後都要對乘積取餘,相乘以前事先對乘數取餘不會對結果形成影響」,所以咱們能夠在運算過程當中邊算邊取餘,每作一次乘法都只取乘積除以 n 的餘數。這樣一來,咱們的每次乘法都是兩個 n 之內的數相乘了。利用這些小竅門,計算機才能在足夠短的時間裏完成 RSA 加密解密的過程。
RSA 算法實施起來速度較慢,所以在運算速度上的任何一點優化都是有益的。利用中國剩餘定理,咱們還能進一步加快運算速度。咱們想要求的是 a35 除以 n 的餘數,而 n 是兩個質數 p 和 q 的乘積。因爲 p 和 q 都是質數,它們顯然也就互質了。於是,若是咱們知道 a35 分別除以 p 和 q 的餘數,也就可以反推出它除以 n 的餘數了。所以,在反覆平方的過程當中,咱們只須要保留所得的結果除以 p 的餘數和除以 q 的餘數便可,運算時的數字規模進一步下降到了 p 和 q 所在的數量級上。到最後,咱們再借助「今有物,不知其數」的求解思路,把這兩條餘數信息恢復成一個 n 之內的數。更神的是,別忘了, ai 除以 p 的餘數是以 p – 1 爲週期的,所以爲了計算 a35 mod p ,咱們只須要計算 a35 mod (p-1) mod p 就能夠了。相似地,因爲餘數的週期性現象,計算 a35 mod q 就至關於計算 a35 mod (q-1) mod q 。這樣一來,連指數的數量級也減少到了和 p 、 q 相同的水平, RSA 運算的速度會有明顯的提高。
須要注意的是, RSA 算法的安全性並不徹底等價於大數分解的困難性(至少目前咱們尚未證實這一點)。已知 n 和 e 以後,不分解 n 確實很難求出 d 來。但咱們並不能排除,有某種很是巧妙的方法能夠繞過大數分解,不去求 p 和 q 的值,甚至不去求 m 的值,而直接求出一個知足要求的 d 來。不過,即便考慮到這一點,目前人們也沒有破解密鑰 d 的好辦法。 RSA 算法經受住了實踐的考驗,並逐漸成爲了行業標準。若是 A 、 B 兩我的想要創建會話,那麼咱們可讓 A 先向 B 索要公鑰,而後想一個兩人從此通話用的密碼,用 B 的公鑰加密後傳給 B ,這將只能由 B 解開。所以,即便竊聽者徹底掌握了雙方約定密碼時傳遞的信息,也沒法推出這個密碼是多少來。
上述方案讓雙方在不安全的通訊線路上神奇地約定好了密碼,一切看上去彷佛都很完美了。然而,在這個漂亮的解決方案背後,有一個讓人意想不到的、很有些喜劇色彩的漏洞——中間人攻擊。在 A 、 B 兩人創建會話的過程當中,攻擊者很容易在線路中間操縱信息,讓 A 、 B 兩人誤覺得他們是在直接對話。讓咱們來看看這具體是如何操做的吧。創建會話時, A 首先呼叫 B 並索要 B 的公鑰,此時攻擊者注意到了這個消息。當 B 將公鑰回傳給 A 時,攻擊者截獲 B 的公鑰,而後把他本身的公鑰傳給 A 。接下來, A 隨便想一個密碼,好比說 314159 ,而後用他所收到的公鑰進行加密,並將加密後的結果傳給 B 。 A 覺得本身加密時用的是 B 的公鑰,但他其實用的是攻擊者的公鑰。攻擊者截獲 A 傳出來的信息,用本身的私鑰解出 314159 ,再把 314159 用 B 的公鑰加密後傳給 B 。 B 收到信息後不會發現什麼異樣,由於這段信息確實能用 B 的私鑰解開,並且確實能解出正確的信息 314159 。從此, A 、 B 將會用 314159 做爲密碼進行通話,而徹底不知道有攻擊者已經掌握了密碼。
怎麼封住這個漏洞呢?咱們得想辦法創建一個獲取對方公鑰的可信渠道。一個簡單而有效的辦法就是,創建一個全部人都信任的權威機構,由該權威機構來儲存並分發你們的公鑰。這就是咱們一般所說的數字證書認證機構,英文是 Certificate Authority ,一般簡稱 CA 。任何人均可以申請把本身的公鑰放到 CA 上去,不過 CA 必須親自檢查申請者是否符合資格。若是 A 想要和 B 創建會話,那麼 A 就直接從 CA 處獲取 B 的公鑰,這樣就不用擔憂獲得的是假的公鑰了。
新的問題又出來了:那麼,怎麼防止攻擊者冒充 CA 呢? CA 不但須要向 A 保證「這個公鑰確實是 B 的」,還要向 A 證實「我確實就是 CA 」。
把加密鑰匙和解密鑰匙稱做「公鑰」和「私鑰」是有緣由的——有時候,私鑰也能夠用來加密,公鑰也能夠用來解密。容易看出,既然 a 的 e 次方的 d 次方除以 n 的餘數就回到了 a ,那麼固然, a 的 d 次方的 e 次方除以 n 的餘數也會變回 a 。因而,咱們可讓私鑰的持有者計算 a 的 d 次方除以 n 的餘數,對原文 a 進行加密;而後公鑰的持有者取加密結果的 e 次方除以 n 的餘數,這也能恢復出原文 a 。可是,用我本身的私鑰加密,而後你們均可以解密,這有什麼用處呢?不妨來看看這樣「加密」後的效果吧:第一,貌似是最荒謬的,你們均可以用個人公鑰解出它所對應的原始文件;第二,很關鍵的,你們只能查看它背後的原文件,不能越過它去修改它背後的原文件;第三,這樣的東西是別人作不出來的,只有我能作出來。
這些性質正好完美地描述出「數字簽名」的實質,剛纔的 CA 難題迎刃而解。 CA 首先生成一個本身的公鑰私鑰對,而後把公鑰公之於衆。以後, CA 對每條發出去的消息都用本身的私鑰加個密做爲簽名,以證實此消息的來源是真實的。收到 CA 的消息後,用 CA 的公鑰進行解密,若是能恢復出 CA 的原文,則說明對方必定是正宗的 CA 。由於,這樣的消息只有私鑰的持有者才能作出來,它上面的簽名是別人沒法僞造的。至此爲止,創建安全的通訊線路終於算是有了一個比較完美的方案。
實際應用中,創建完善的安全機制更加複雜。而且,這還不足以解決不少其餘形式的網絡安全問題。隨便哪一個簡單的社交活動,都包含着很是豐富的協議內涵,在互聯網上實現起來並不容易。比方說,如何創建一個網絡投票機制?這裏面的含義太多了:咱們須要保證每張選票確實都來自符合資格的投票人,咱們須要保證每一個投票人只投了一票,咱們須要保證投票人的選票內容不會被泄露,咱們須要保證投票人的選票內容不會被篡改,咱們還須要讓唱票環節足夠透明,讓每一個投票人都確信本身的票被算了進去。做爲密碼學與協議領域的基本模塊, RSA 算法隨時準備上陣。古希臘數學家對數字執着的研究,直到今天也仍然綻開着光彩。