基礎的密碼學知識
在閱讀本文之前,建議大家可以先 Google 瞭解一下非對稱加密演算法和 Hash 演算法,這裡就不詳細介紹了。下面我們只描述一下非對稱加密傳輸資訊的一個大致流程:
- Sender(傳送者) 首先用相關的 hash 演算法對要傳送的 message(資訊) 進行 hash 生成 digest (數字摘要),然後用 private key(私鑰) 對 digest 加密生成 digital signature(數字簽名)。
- Recevier(接受者) 會收到 message 和 digital signature 以及 public key(在區塊鏈中 public key 是公開,類似於 https 則會引入一個第三方權威中心化機構 CA 來頒發確認 public key 避免中間人攻擊)。用 public key 對 digital signature 解密生成 digest,然後用 hash 演算法對 message 生成 digest,如果生成的 digest 一致的,則證明 message 是 public key 所有者傳送的並且 origin message 沒有被修改。
在位元中使用的 hash 演算法是 SHA(Secure Hash Algorithm),其摘要長度為 256 bits,即 32個 位元組,故稱 SHA256,對於一個區塊都會對其區塊頭(header)進行 double sha256。
在比特幣中使用的非對稱加密演算法是 ECDSA, 橢圓曲線數字簽名演算法的原理這裡就不介紹了。
區塊的組成
一個區塊是由區塊頭和區塊體組成。區塊體則是所有 transaction 的集合,區塊頭由五個部分組成,這篇我們重點來看一下 merkle root。剩下的幾個元素以後在單獨寫一篇 mining 相關的文章描述。
- 上一個區塊頭的 Hash,previous hash。由上個區塊的 block header 進行 double sha256 生成。32 bytes。
- 時間戳,timestamp。4 bytes。
- 挖礦難度值 target。4 bytes。
- 工作量證明隨機數,nonce。Miner 通過 nonce 達到某一個 target,達到這個 target 的 diffculty 隨著時間的推移會越來越大。
- merkle root,merkle root 可以簡單理解為 transaction set 的一個唯一 hash 標識。32 bytes。
- version。4 bytes。
一個 block header 的組成如下:
02000000 ........................... Block version: 2
b6ff0b1b1680a2862a30ca44d346d9e8
910d334beb48ca0c0000000000000000 ... Hash of previous block's header
9d10aa52ee949386ca9385695f04ede2
70dda20810decd12bc9b048aaab31471 ... Merkle root
24d95a54 ........................... Unix time: 1415239972
30c31b18 ........................... Target: 0x1bc330 * 256**(0x18-3)
fe9f0864 ........................... Nonce
複製程式碼
比特幣的 SPV(Simplified Payment Verification 簡單支付驗證) 機制,保證了每次只需要下載區塊頭(80 bytes),而不需要載入整個區塊。平均每個 transaction 至少是 250 bytes,而且平均每個區塊包含 2000 個transaction。因此,包含完整交易的區塊比區塊頭的 4k 倍還要大。
BitTorrent 下載中的 Hash List
單檔案
當我們去下載一個檔案的時候,下載連結後面提供了一個MD5(MD5也是一種Hash演算法),這樣我們可以在下載之後對檔案計算MD5,如果MD5與提供的MD5相等,說明檔案有沒有被損壞或者沒有被惡意劫持。
多檔案
在 p2p,比如我們下載一個 BT 種子的時候,如果這個檔案比較大比如下載一步電影,這個大電影檔案會被分成多個小的 data block (資料塊)。這些小的 data block 會從多個不同的機器下載,如何保證從其他機器下載的 data block 沒有被修改呢?
開始下載之前,我們會先下載一個 hash list(雜湊列表),如果有一個 data block 損壞了,只需要重新下載這個 data block 就行了。如下圖所示,把 hash list 中的各個 hash 值拼接成一個長的字串,在對這個長字串做一次 hash,得到 top hash(根雜湊)。把這個 top hash 和 origin top hash 來判斷有沒有資料塊缺失以及是否有資料庫被篡改。
事實上 hash list 可以看做是一課樹高為 merkle tree,top hash 就是 blockchain 中一個節點的 merkle root。
比特幣中的 Merkle Tree
如上圖所示,Lx 可以是做是 blockchain 中的一筆 transaction。
在比特幣中確認一個 transaction 是否合法有五個步驟:
- 從網路中獲取並儲存最長鏈的所有區塊頭資訊。
- 根據 block header 驗證這個 transaction 所在的區塊是否在上面的最長鏈中。block header 在 Merkle block 中獲取。
- 從 Merkle block 中的 Merkle 路徑獲得所需要驗證的 hash。
- 根據這些 hash 值計算出一個 Merkle Root。如果計算出 Merkle Root 值和區塊頭中的 Merkle Root 是否相等。
p.s: 一個 SPV 節點想知道它錢包中某個比特幣地址即將到達的支付。該節點會在節點間的通訊連結上建立起 bloom filter,限制只接受含有目標比特幣地址的交易。當對等體探測到某交易符合 bloom filter,它將以 Merkleblock 訊息的形式傳送該區塊。Merkleblock 訊息包含區塊頭和一條連線目標交易與 Merkle 根的 Merkle 路徑。
我們重點來看一下上面的步驟三。
如上圖所示我們相驗證交易 K 是否合法即是否包含在區塊中。Merkleblock 中返回的 Merkle 路徑會包含 H(L),H(IJ),H(MNOP),H(ABCDEFGH),根據這五個 hash 值就可以確定一個 Merkle Root,和使用 hash list 相比,不需要將所有小 hash 做一次 hash,也就是隻需要得到 Merkle 路徑下面的四個路徑加上這個 transaction 本身的 hash 就可以了不需要得到所有 transaction 的 action。在實際應用場景,當一個區塊中交易數非常多的時候,驗證速度非常快,是呈對數增長的。
Merkleblock
第一次看這部分的時候,當時有兩個比較困惑的問題,這裡列一下,如果能回答出了這兩個問題,對於 Bitcoin 的 merkle tree 的 spv 驗證的基本原理就差不多了。
- spv 知道 transaction 的 address,但是如何知道 transaction 在哪個 block 裡面?
- 知道了 transaction 對應的 block header,如何拿到的 Merkle Path,也就是 H(L),H(IJ),H(MNOP),H(ABCDEFGH)?
SPV 本身沒有 block 資訊,都是從全節點拿到的。其中的 getdata 請求中如果指定了 inventory type 為 MSG_MERKLEBLOCK,全節點就會在響應中回覆一個 MerkleBlock。
SPV 解析 MerkleBlock 的過程如下:
以太坊中的 Merkle Tree
以太坊使用的是 Merkle Patricia Tree,和比特幣有很大不同要複雜一些,這個準備下一篇文章在詳細介紹。總的來說比特幣中交易是無狀態,比如我們要查一個賬戶的餘額是無法直接實現的,我們平時看到的 balance 都是比特幣相關的 wallet client 自己實現生成計算的。在區塊鏈中交易是有狀態的,不僅僅是有一棵 Merkle Tree,有三棵 Merkle Tree:
- Transaction Tree。
- Receipt Tree。展示每一筆交易影響的資料條。
- State Tree。
See Also
TODO: Git 和 IPFS 中對於 Merkle Tree 的應用。
blog.ethereum.org/2015/11/15/…
easythereentropy.wordpress.com/2014/06/04/…
Last: 最近在 GitHub 上整理學習 BlockChain 相關的筆記,歡迎關注交流~