白話 Merkle Tree

今天為啥又聊 Merkle Tree 呢? 我們地球上大部分人應該連它的名字都沒有聽過,而且說實話它也是個比較傳統的概念了。Merkle Tree 是由計算機科學家 Ralph Merkle 在很多年前提出的,并以他本人的名字來命名。不過,Merkle Tree 確實涉及到了很多有意思的實際應用。最近幾年才有的一個例子是,比特幣錢包服務用 Merkle Tree 的機制來作”百分百準備金證明“ ( http://blog.bifubao.com/2014/03/16/proof-of-reserves/ )。不過今天,我們還是從數據的“完整性校驗”這個角度來聊 Merkle Tree。 Git 版本控制系統,ZFS 文件系統以及我們自己下載電影常用的點對點網絡 BT 下載,都是通過 Merkle Tree 來進行完整性校驗的。順便說一句,所謂的完整性校驗,就是檢查一下數據有沒有損壞。

先說哈希( Hash )

其實要實現完整性校驗,最簡單的方法就是對要校驗的整個的數據文件做個哈希運算,把得到的哈希值公布在網上,這樣我們把數據下載到手之后,再次運算一下哈希值,如果運算結果相等,就表示我們下載過程中文件沒有任何的損壞。因為哈希的最大特點是,如果你的輸入數據,稍微變了一點點,那么經過哈希運算,你得到的哈希值將會變得面目全非。這樣做的一個目的是可以防止有人根據哈希值反推出原始輸入數據的一些特征。

如果我們從一個穩定的服務器上進行下載,那么采用單個哈希來進行校驗的形式是可以接受的。

再說哈希列表( Hash List )

但是在點對點網絡中作數據傳輸的時候,我們會從同時從多個機器上下載數據,而且其中很多機器可以認為是不穩定或者是不可信的,這時需要有更加巧妙的做法。實際中,點對點網絡在傳輸數據的時候,其實都是把比較大的一個文件,切成小的數據塊。這樣的好處是,如果有一個小塊數據在傳輸過程中損壞了,那我只要重新下載這一個數據塊就行了,不用重新下載整個文件。當然這就要求每個數據塊都擁有自己的哈希值。BT 下載的時候,在下載真正的數據之前,我們會先下載一個哈希列表的。這時有一個問題就出現了,那么多的哈希,我們怎么保證它們本身都是正確地呢?

答案是我們需要一個根哈希。把每個小塊的哈希值拼到一起,然后對整個這個長長的字符串再做一次哈希運算,最終的結果就是哈希列表的根哈希。于是,如果我們能夠保證從一個絕對可信的網站,或者從我們的朋友手里拿到一個正確的根哈希,就可以用它來校驗哈希列表中的每一
個哈希都是正確的,進而可以保證下載的每一個數據塊的正確性了。

這種方式挺好,但是實際的應用中,其實還是有著它的不足之處的,這就是為什么 Merkle 教授要發明 Merkle Tree 了。

最后是 Merkle Tree

先看它的結構。在最底層,和哈希列表一樣,我們把數據分成小的數據塊,有相應地哈希和它對應。但是往上走,并不是直接去運算根哈希,而是把相鄰的兩個哈希合并成一個字符串,然后運算這個字符串的哈希,這樣每兩個哈希就結婚生子,得到了一個”子哈希“。如果最底層的哈希總數是單數,那到最后必然出現一個單身哈希,這種情況就直接對它進行哈希運算,所以也能得到它的子哈希。于是往上推,依然是一樣的方式,可以得到數目更少的新一級哈希,最終必然形成一棵倒掛的樹,到了樹根的這個位置,這一代就剩下一個根哈希了,我們把它叫做 Merkle root.

再說它的優點。相對于 Hash List,Merkle Tree 的明顯的一個好處是可以單獨拿出一個分支來(作為一個小樹)對部分數據進行校驗,這個很多使用場合就帶來了哈希列表所不能比擬的方便和高效。

好,這一期就說這么多,大家現在概念上有個認識,后面我們會有專門的文章講 Merkle Tree 實用的例子。

參考資料

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容