1. 引言
前序博客有:
Merkle proof又名Merkle path,为重新计算merkle root所需的最小节点数。
如上图,为了证明node2在root hash为65C7C87E2731AE97D0BE89EA3299A544FD28DE6A
的Merkle tree中,仅需提供Node 1,Node 34和Node 567,即可生成root Node 1234567。
Merkle tree proof相关代码实现有:
- https://github.com/iden3/iden3js(JavaScript)
- https://github.com/weijiekoh/semaphore-merkle-tree(TypeScript)
- https://github.com/appliedzkp/incrementalquintree(TypeScript)
- https://github.com/filecoin-project/merkletree(Rust)
- https://github.com/sitano/merkle_light(Rust)
- https://github.com/0xProject/OpenZKP/tree/master/crypto/merkle-tree (Rust)
- https://github.com/ing-bank/zkrp(Go)
- https://github.com/zcash/librustzcash/blob/master/zcash_primitives/src/merkle_tree.rs (Rust)
- https://github.com/wealdtech/go-merkletree/(Go)
- https://github.com/mit-dci/utreexo(Go),详细参看博客 Utreexo:比特币UTXO merkle tree proof以节约节点存储空间。
- https://github.com/aszepieniec/stark-anatomy/blob/master/code/merkle.py(Python)
2. stark-anatomy中merkle proof解析
针对的代码为:
详细的merkle proof测试用例见test_merkle()
:【运行指定测试文件并显示打印日志pytest test_merkle.py -s
。运行指定测试用例并显示打印日志pytest test_merkle.py::test_merkle -s
。】
1)构建具有64个leaf的merkle tree:
n = 64
leafs = [urandom(int(urandom(1)[0])) for i in range(n)]
root = Merkle.commit_(leafs)
H = blake2b
def commit_( leafs ):
assert(len(leafs) & (len(leafs)-1) == 0), "length must be power of two"
if len(leafs) == 1:
return leafs[0]
else:
# 对左右leaf未做hash运算,直接拼接再hash。递归调用。
return Merkle.H(Merkle.commit_(leafs[:len(leafs)//2]) + Merkle.commit_(leafs[len(leafs)//2:])).digest()
def commit( data_array ):
# 对最底层的data分别进行hash运算,生成的为leafs。
return Merkle.commit_([Merkle.H(bytes(da)).digest() for da in data_array])
2)Open第 i i i个leaf的path:
def open_( index, leafs ):
assert(len(leafs) & (len(leafs)-1) == 0), "length must be power of two"
assert(0 <= index and index < len(leafs)), "cannot open invalid index"
if len(leafs) == 2:
return [leafs[1 - index]]
elif index < (len(leafs)/2): # 递归调用。
return Merkle.open_(index, leafs[:len(leafs)//2]) + [Merkle.commit_(leafs[len(leafs)//2:])]
else:
return Merkle.open_(index - len(leafs)//2, leafs[len(leafs)//2:]) + [Merkle.commit_(leafs[:len(leafs)//2])]
def open( index, data_array ):
return Merkle.open_(index, [Merkle.H(bytes(da)).digest() for da in data_array])
3)Verify第 i i i个leaf的path:
def verify_( root, index, path, leaf ):
assert(0 <= index and index < (1 << len(path))), "cannot verify invalid index"
if len(path) == 1:
if index == 0: # 区分左右叶子
return root == Merkle.H(leaf + path[0]).digest()
else:
return root == Merkle.H(path[0] + leaf).digest()
else:
if index % 2 == 0:
return Merkle.verify_(root, index >> 1, path[1:], Merkle.H(leaf + path[0]).digest())
else:
return Merkle.verify_(root, index >> 1, path[1:], Merkle.H(path[0] + leaf).digest())
def verify( root, index, path, data_element ):
return Merkle.verify_(root, index, path, Merkle.H(bytes(data_element)).digest())
参考资料
[1] Merkle proofs Explained.
[2] Zero-knowledge proofs in identity systems
[3] ZKProof Zero-Knowledge Proofs for Set Membership
[4] Zero Knowledge Proofs and Merkle Trees – An overview before diving into it
[5] Data Validation
[6] Understanding Merkle pollards