![[assets/643a3b52a1c9a2001c8982a7.png]] - [[Bitcoin]], [[Git]], [[IPFS]]で使われる - [[Balanced Tree]] - 別に二分木である必要はない - それはそう(kekeho) - 全てのノードはサブMerkle Treeのルート - $log_2(n)$で,与えられたデータがMerkle Treeに含まれるか検証できる($n$はLeafの数) - 最低限の各節のハッシュ値も知っている必要がある - 自己検証ができる - 同じ葉を持つTreeの根は、同じハッシュ値になる - データの重複排除に使える - [[Merkle TreeをTiling]]することでストレージを削減みたいな話もある - [[Sunlight]]で使われている - [https://research.swtch.com/tlog#tiling_a_log](https://research.swtch.com/tlog#tiling_a_log) 活用例 - [[Content Addressing]]に使われる - [[IPFS]] - 同期の最適化(同じ葉を持つTreeの根が同じハッシュ値になる性質を活かす) - [[Dynamo]]: レプリカ間の状態の効率的な比較 - [[ZFS]] - ブロックチェーン - [[Bitcoin]] 解説記事 - [https://medium.com/coinmonks/merkle-trees-concepts-and-use-cases-5da873702318](https://medium.com/coinmonks/merkle-trees-concepts-and-use-cases-5da873702318) 実装例 ```rust use ring::digest::{Digest, SHA256, Context}; use std::rc::Rc; struct Node { hash: Digest, left: Option<Rc<Node>>, right: Option<Rc<Node>>, } fn digest(data: &[u8]) -> Digest { let mut context = Context::new(&SHA256); context.update(data); let digest = context.finish(); return digest; } fn add(left: &Digest, right: &Digest) -> Digest { let or: Vec<u8> = left.as_ref().iter().zip(right.as_ref().iter()).map(|(&l, &r)| l | r).collect(); return digest(&or[..]); } impl Node { pub fn include(self: &Rc<Node>, data: &[u8], digests: &[&Digest]) -> bool { let mut prev_hash = digest(data); for digest in digests { prev_hash = add(&prev_hash, digest); } if self.hash.as_ref() == prev_hash.as_ref() { return true } return false; } pub fn merge(left: Rc<Node>, right: Rc<Node>) -> Rc<Node> { let parent: Rc<Node> = Rc::new(Node { hash: add(&left.hash, &right.hash), left: Some(left), right: Some(right), }); return parent; } fn build_nodetree(nodes: &[Rc<Node>]) -> Rc<Node> { if nodes.len() == 1 { return nodes[0].clone(); } let mut parent_list: Vec<Rc<Node>> = Vec::new(); for i in (0..nodes.len()).step_by(2) { if nodes.len() == i+1 { // 奇数この場合、最後の要素を複製する let parent = Node::merge(nodes[nodes.len()-1].clone(), nodes[nodes.len()-1].clone()); parent_list.push(parent); break; } let parent = Node::merge(nodes[i].clone(), nodes[i+1].clone()); parent_list.push(parent); } return Node::build_nodetree(&parent_list) } pub fn build_tree(data: &[&[u8]]) -> Rc<Node> { let mut leaf_list: Vec<Rc<Node>> = Vec::new(); for v in data { let d = digest(v); leaf_list.push( Rc::new(Node { hash: d, left: None, right: None, }) ); } return Node::build_nodetree(&leaf_list[..]) } } fn main() { let datalist = [ "hoge", "fuga", "piyo", ].map(|d| d.as_bytes()); // Build Merkle Tree let root = Node::build_tree(&datalist[..]); // Check piyo! let data = "piyo"; let given_digests = [ &root.right.clone().unwrap().left.clone().unwrap().hash, &root.left.clone().unwrap().hash ]; if root.include(data.as_bytes(), &given_digests) { println!("{} include!", data); } else { println!("error"); } // Check fuga! let data = "fuga"; let given_digests = [ &root.left.clone().unwrap().left.clone().unwrap().hash, &root.right.clone().unwrap().hash ]; if root.include(data.as_bytes(), &given_digests) { println!("{} include!", data); } else { println!("error"); } // Wrong digests let data = "fuga"; let given_digests = [ &root.left.clone().unwrap().left.clone().unwrap().hash, &root.left.clone().unwrap().hash ]; if root.include(data.as_bytes(), &given_digests) { println!("error"); } else { println!("wrong digests"); } // Check not include let data = "unko"; let given_digests = [ &root.left.clone().unwrap().right.clone().unwrap().hash, &root.right.clone().unwrap().hash ]; if root.include(data.as_bytes(), &given_digests) { println!("error") } else { println!("{} is not included", data); } } ```