【Awesome EOS】从 Hash 到 Merkle Tree

哈希算法(Hash)

哈希算法也叫散列算法,一般来说满足这样的关系:Func(data)=key,输入任意长度的 data,经过哈希算法处理后输出一个定长的数据 key。同时这个过程是不可逆的,无法由 key 逆推出 data。

  • MD5
  • SHA:SHA-1,SHA-224, SHA-256,SHA-384,SHA-512

注意,哈希表(HashTable)是利用了哈希函数的一种数据结构

散列表(Hash table,也叫哈希表),是根据关键码值 (key/value) 而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。给定表 M,存在函数 Func(key),对任意给定的关键字值 key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表 M 为哈希表,函数 Func(key) 为哈希函数。
哈希表是一种通过哈希函数将特定的键映射到特定值的一种数据结构,他维护着 key 和 value 之间的一 一对应关系。


Hash List

在点对点网络中作数据传输的时候,会同时从多个机器上下载数据,而且很多机器可以认为是不稳定或者不可信的。为了校验数据的完整性,更好的办法是把大的文件分割成小的数据块(例如,把分割成 64KB 为单位的数据块)。这样的好处是,如果小块数据在传输过程中损坏了,那么只要重新下载这一快数据就行了,不用重新下载整个文件。

怎么确定小的数据块没有损坏哪?只需要为每个数据块做 Hash。BT下载的时候,在下载到真正数据之前,我们会先下载一个 Hash 列表。那么问题又来了,怎么确定这个Hash列表本事是正确的哪?答案是把每个小块数据的Hash值拼到一起,然后对这个长字符串在作一次Hash运算,这样就得到Hash列表的根Hash(Top Hash or Root Hash)。下载数据的时候,首先从可信的数据源得到正确的根Hash,就可以用它来校验Hash列表了,然后通过校验后的Hash列表校验数据块。


默克尔树(Merkle Tree)

  • 二叉树:平衡二叉树,非平衡二叉树

    在计算机科学中,二叉树是每个节点最多有两个子树的树结构,每个节点代表一条结构化数据。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。
    二叉树常被用于实现数据快速查询。二叉树如下图所示:

  • 默克尔树

默克尔树(Merkle tree)是一种哈希二叉树,1979年由 Ralph Merkle 发明。
Merkle Tree可以看做Hash List的泛化(Hash List可以看作一种特殊的Merkle Tree,即树高为2的多叉Merkle Tree)。

在最底层,和哈希列表一样,我们把数据分成小的数据块,有相应地哈希和它对应。但是往上走,并不是直接去运算根哈希,而是把相邻的两个哈希合并成一个字符串,然后运算这个字符串的哈希,这样每两个哈希就结婚生子,得到了一个”子哈希“。如果最底层的哈希总数是单数,那到最后必然出现一个单身哈希,这种情况就直接对它进行哈希运算,所以也能得到它的子哈希。于是往上推,依然是一样的方式,可以得到数目更少的新一级哈希,最终必然形成一棵倒挂的树,到了树根的这个位置,这一代就剩下一个根哈希了,我们把它叫做 Merkle Root[3]。

在 P2P 网络下载网络之前,先从可信的源获得文件的 Merkle Tree 树根。一旦获得了树根,就可以从其他从不可信的源获取 Merkle tree。通过可信的树根来检查接受到的Merkle Tree。如果 Merkle Tree 是损坏的或者虚假的,就从其他源获得另一 个Merkle Tree,直到获得一个与可信树根匹配的 Merkle Tree。

Merkle Tree 和Hash List 的主要区别是,可以直接下载并立即验证 Merkle Tree 的一个分支。因为可以将文件切分成小的数据块,这样如果有一块数据损坏,仅仅重新下载这个数据块就行了。如果文件非常大,那么 Merkle tree 和 Hash list 都很到,但是 Merkle tree 可以一次下载一个分支,然后立即验证这个分支,如果分支验证通过,就可以下载数据了。而Hash list只有下载整个hash list才能验证。


典型应用

  • 快速比较大量数据:当两个默克尔树根相同时,则意味着所代表的数据必然相同(哈希算法决定的)。
  • 快速定位修改:例如上例中,如果 D1 中数据被修改,会影响到Hash0-0,Hash0 和 Root。因此,沿着 Root --> 0 --> 0-0,可以快速定位到发生改变的 D1;
  • 零知识证明:例如如何证明某个数据(D0……D3)中包括给定内容 D0,很简单,构造一个默克尔树,公布 N0,N1,N4,Root,D0 拥有者可以很容易检测 D0 存在,但不知道其它内容。
  • 数据完整性校验:git 版本控制系统,ZFS/IPFS 分布式文件系统以及 BT 下载,都是通过 Merkle Tree 来进行完整性校验的。
  • 在分布式存储系统中的应用:

    为了保持数据一致,分布系统间数据需要同步,如果对机器上所有数据都进行比对的话,数据传输量就会很大,从而造成“网络拥挤”。为了解决这个问题,可以在每台机器上构造一棵 Merkle Tree,这样,在两台机器间进行数据比对时,从 Merkle Tree 的根节点开始进行比对,如果根节点一样,则表示两个副本目前是一致的,不再需要任何处理;如果不一样,则沿着hash值不同的节点路径查询,很快就能定位到数据不一致的叶节点,只用把不一致的数据同步即可,这样大大节省了比对时间以及数据的传输量。

相对于 Hash List,MT的明显的一个好处是可以单独拿出一个分支来(作为一个小树)对部分数据进行校验,这个很多使用场合就带来了哈希列表所不能比拟的方便和高效。正是源于这些优点,MT常用于分布式系统或分布式存储中。

more..

  • Merkle Tree 在数字加密货币中首先应用于比特币(BTC),以太坊(Etherum)采用了改进的 Merkle Patricia Tree (MPT) 。

默克尔证明(Merkle Proof)