扒一扒隨機數(Random Number)的誕生歷史

鬍子大哈發表於2017-03-20

作者:Alon Zakai

編譯:鬍子大哈

翻譯原文:huziketang.com/blog/posts/…

英文原文:A Brief History of Random Numbers

轉載請註明出處,保留原文連結以及作者資訊


扒一扒隨機數(Random Number)的誕生歷史

(羅馬 12mm 骰子,大英博物館行動式文物保護方案-CC BY-SA 2.0)

“在所有的產生隨機數的事物中,我認為沒有什麼能夠超越骰子了”,這是統計學家 Francis Galton 在 1890 年的《自然》雜誌中寫道。它們在容器中不斷地翻滾、互相撞擊,以各種形式和角度與容器壁發生碰撞,在容器中的位置和形態在外界看來都是那麼不可預知,容器哪怕只發生一次晃動,外界都不可能知道里面到底是什麼形態。

古已有之的隨機數

到底如何才能生成均勻的隨機數列呢?自然界中隨機性大量而近乎完美的存在,人類並不能準確地預知和量化這種隨機性。迄今為止發現最早的骰子(4 個面)是來自中東的一座公元前 24 世紀的墳墓裡。再近一些的歷史是在公元前 1100 年的中國,利用火燒龜殼產生的隨機龜裂現象,一些“先知”會根據龜裂情況來對未來做判斷。又過了幾個世紀,在中國誕生了易經占卜法,利用 49 蓍草法進行占卜,其操作的分裂過程很類似於拋硬幣。

機器生成隨機數的第一次觸碰

扒一扒隨機數(Random Number)的誕生歷史

(摘自:“ A Million Random Digits with 100,000 Normal Deviates”)

時間到了 20 世紀 40 年代中期,現代世界需要更多的隨機數,不再是骰子或者蓍草可以滿足的了。RAND 公司發明了一種機器,通過隨機脈衝發生器可以生成大量的隨機數。他們將這個機器執行所產生的數字聚合起來併發布成圖書“A Million Random Digits with 100,000 Normal Deviates”。這在現在看來是十分荒謬的,但是在當時卻是一個突破。這是人類第一次產生如此大量的、高質量的隨機數,並且對公眾是開放的。這本書 RAND 公司一直印刷到了 2001 年,現在在亞馬遜上也可以看得到

於此類似的機器:搖獎機,是由著名的 Bletchley Park WWII 破譯小組在 20 世紀 40 年代發明的,當時被用來生成英國保險債券彩票所使用的隨機數。為了平息公眾對搖獎機的公平性和準確性的質疑和擔心,官方斥資製作了當時的巨型紀錄片:“搖獎機的重要性(The Importance of Being E.R.N.I.E.)”。下面給出視訊,很值得一看。


(The Importance of Being E.R.N.I.E.)

1951 年隨機性終於被正式規範化並且整合到了計算機 Ferranti Mark 1 號中。Ferranti Mark 1 號內建了隨機數生成指令,利用電氣噪聲可以一次性生成 20 個隨機位元位。這一特性是由阿蘭·圖靈設計的。Christopher Strachey 利用這一特點,編寫了一套隨機情書生成器。下面這是情書例子,利用這個程式生成的 David Link 的 2009 複合計劃

JEWEL LOVE
MY LIKING HUNGERS FOR YOUR ADORABLE INFATUATION.
YOU ARE MY EROTIC ARDOUR.: MY FOND RAPTURE. MY THIRST
SIGHS FOR YOUR INFATUATION. MY HEART SEDUCTIVELY WISHES YOUR
BREATHLESS LONGING.

YOURS CURIOUSLY

M. U. C.

(由於上面文字過於漏骨,譯者嘗試引申出譯文如下)

我對你的可愛迷戀至極。

你勾起了我所有對情愛的幻想。

我為你而狂熱。

你的魅力使我對你充滿了渴望。

我的心隨你在而讓我無法呼吸。

你的追求者

M.U.C

但是圖靈的隨機數指令幾乎是當時的開發人員崩潰的,因為這種隨機在本身就已經很不穩定的開發環境下又引入了不確定性。人們希望在軟體中得到一致性的結果,但是用這種指令的軟體永遠不可能得到可重複的一致性結果,這也使得軟體測試幾乎變的不可行。

那麼如果隨機數生成器可以由一個確定性的函式來替代會怎樣呢?如果在給定一個確定的初始條件,每次可以生成同樣的隨機序列會怎樣呢?這就是偽隨機數生成器(PRNG)。

偽隨機數生成器(PRNG)

偽隨機數生成器是由馮諾依曼在 1946 年創造的。他的基本思想是從一個隨機數種子開始,對其平方,然後取中間值。接下來重複對得到的數取平方並取中間值的過程,就會得到一個具有統計意義屬性的隨機數序列了。這也就是廣為人知的平方取中法

然而,馮諾依曼的方法並沒有經得住時間的考驗,因為不論從什麼隨機種子開始,序列最終都會落入某個短迴圈序列,比如:8100,6100,4100,8100,6100,4100……。

序列中的數字是依賴於前一個數字的這種生成函式,上面的重複迴圈問題是不可避免的。但是如果說這個迴圈間隔非常非常大,對實際應用並不會產生影響,那會怎樣呢?

1949 年,數學家 D.H.Lehmer 利用線性同餘生成器(LCG)實現了這一思路。下面給出的是基於 Lehmer 的方法所實現的一種樸素 PRNG,叫做中央隨機數生成器,使用 JavaScript 在 1995 年寫的。

    // The Central Randomizer 1.3 (C) 1997 by Paul Houle (paul@honeylocust.com)
    // See:  http://www.honeylocust.com/javascript/randomizer.html
    rnd.today=new Date();
    rnd.seed=rnd.today.getTime();
    function rnd() {
      rnd.seed = (rnd.seed*9301+49297) % 233280;
      return rnd.seed/(233280.0);
    };

    function rand(number) {
      return Math.ceil(rnd()*number);
    };複製程式碼

注意程式碼中的魔法數字(如 9301 等),這些數字(通常是質數)是用來最大化重複區間的——上面所提到的自我重複的迴圈區間。這種 PRNG 使用當前時間作為種子值,重複區間可以達到 2 的 31 次方。

這種中央隨機生成器發明之初非常流行,因為那時的 JavaScript 1.0 還沒有內建 Math.random() 函式,當時的 Web 1.0 環境下,大家都想讓自己的 banner 廣告隨機旋轉。一個開發者 Paul Houle 說道:“它在很多情況下已經很好用了,但是不能使用它來做保密使用”。

對 PRNG 的更高要求

網際網路確實需要保密。SSL 誕生在 1995 年,它的加密方案需要高質量的 PRNG。它的發展也直接導致了一段時間的 PRNG 野蠻創新時期。如果你回頭看一下所有的隨機數生成器的專利,你可能會感受到就像現代版的第一次製造飛機的浪潮一樣。

20 世紀 90 年代中期的 CPU 是沒有內建隨機數生成指令的,這使得那時候好的隨機種子特別難得。本來這問題也不大,不過當飛利浦的 Hallam-Baker 發現 Netscape(當時市場上的巨頭)的 SSL web 伺服器使用了“當前時間 + 一組特殊 ID”組合作為種子的時候,這個問題變成了一個切身體會到的安全問題了。Hallam-Baker 展示了一個攻擊者很容易猜到種子值,並且對他們所拿到的伺服器流量進行解密的過程。猜種子值是一個非常常規的攻擊手段,儘管這種手法現在變得越來越困難。這裡給出 2009 年在 Hacker News 上的一段非常經典的攻擊演練

到了 1997 年,電腦科學家們厭倦了生成隨機數所受限的條件,來自 SGI 的一個團隊發明了 LavaRand,它是用一個網路攝像頭來對著熔岩燈拍照。從攝像頭中過來的圖片資料是一個真實的熵源——像圖靈那樣的真實隨機數生成器(TRNG)——可以以 165kb/s 的速率生成隨機數。一如當時矽谷的風格,熔岩燈平臺很快拿到了專利

AutoDesk 的創始人 John Walker 在全世界範圍內推廣他的 HotBits,這是一種“隨機數即服務”的應用,背後原理是蓋革計數器來保證其量子隨機性。1998 年成立的 Random.org 為網際網路提供真正的隨機數。他們提供的服務包括真正的拋硬幣隨機、骰子隨機和卡牌洗牌隨機等。

上面所提到的大多數演算法後來都無人問津了,但是一個叫做梅森旋轉隨機數生成器(The Mersenne Twister)的軟體 PRNG 鶴立雞群,它是由松本真(Makoto Matsumoto)和西村 拓士(Takuji Nishimura)在 1997 年發明的。它完美地平衡了效能和隨機數的質量,並且經受住了時間的考驗。其基本思想是基於線性反饋移位暫存器(LFSR),產生一個迴圈週期非常長的確定性序列,迴圈週期能夠達到 2¹⁹⁹³⁷− 1。在當前的程式語言中,這種演算法依舊是預設的 PRNG。

在 1999 年,隨機數市場發生了一個巨大的變化,Intel 在其 i810 晶片組上整合了晶片級的隨機數生成器。這樣使得新的伺服器都自帶熱噪聲的本地源隨機數生成能力——真正的隨機數生成器(TRNG)。這很偉大,但是它始終沒有軟體 PRNG 快,所以加密軟體依舊不得不依賴於偽隨機數生成器(PRNG)。

這就把我們帶到了“密碼安全 PRNG”(CSPRNG)(這些討厭的縮寫!難怪很多人認為電腦科學很煩人)。CSPRNG 對於 SSL 特別重要。那麼 CSPRNG 的原理是什麼呢?這裡有一份 131 頁的論文來介紹 CSPRNG。祝你在裡面閱讀愉快。

不言而喻,CSPRNG 是一個強需求。梅森旋轉隨機數生成器並不是一種 CSPRNG,因為如果可以給定大量的先前序列樣本,後面的數字是可以預計的出來。

時間再拉近一些,2012 年,Intel 為 TRNG 增加了 RDRANDRDSEED 指令,具有 500MB/s 的生產效率。但是 RDRAND 的完整性一直被質疑,裡面是不是有某些缺陷?或者是為美國國家安全域性內建了什麼東西?沒人確切地知道這個問題的答案,我猜某些地方的某些人一定知道,可是他們也一定不會公開。

開源硬體隨機數生成器

扒一扒隨機數(Random Number)的誕生歷史

(由一種硬體隨機數生成器 PEDOUBLER 生成的隨機資料)

近些年開源硬體 TRNG 也逐漸顯露頭角。它們廣受歡迎得益於其設計的透明化:你可以自己構建線路,也可以用現有的元件搭建。完全的透明化使得對硬體隨機數生成沒有任何的擔心和疑慮。REDOUBLER無限噪聲 TRNG是兩個開源硬體隨機數生成器,連結中給出他們的 Github 原始碼地址。

結尾

今天,依舊有關於對隨機數生成方法選擇的爭論,在作業系統核心、程式語言和安全包(如 OpenSSL 或者 OpenSSH)方面均未停止。有許多不同的演算法聚焦於不同的特點上,如速度、佔用空間、安全性等方面,也有一些安全專家依舊在尋找攻破已有演算法的方法。但是對於我們日常的使用來講,在大多數的作業系統中你可以放心地使用 /dev/random,或者程式語言中你可以隨心地使用 rand() 函式,都能給你帶來很好的使用體驗,並且你這麼做,阿蘭·圖靈也會很開心。

歡迎大家關注我的前端大哈 - 知乎專欄,定期釋出高質量前端文章。


我最近正在寫一本《React.js 小書》,對 React.js 感興趣的童鞋,歡迎指點

相關文章