diff --git a/benches/lib.rs b/benches/lib.rs index cd70425..172a185 100644 --- a/benches/lib.rs +++ b/benches/lib.rs @@ -30,7 +30,7 @@ fn bench_small_str_tree(b: &mut Bencher) { #[bench] fn bench_small_str_proof_gen(b: &mut Bencher) { let values = vec!["one", "two", "three", "four"]; - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); b.iter(|| { for value in &values { @@ -43,7 +43,7 @@ fn bench_small_str_proof_gen(b: &mut Bencher) { #[bench] fn bench_small_str_proof_check(b: &mut Bencher) { let values = vec!["one", "two", "three", "four"]; - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let proofs = values.iter().map(|v| tree.gen_proof(v).unwrap()).collect::>(); b.iter(|| { @@ -63,7 +63,8 @@ fn bench_big_rnd_tree(b: &mut Bencher) { } b.iter(|| { - MerkleTree::from_vec(digest, values.clone()).unwrap() + let tree = MerkleTree::from_vec(digest, values.clone()); + test::black_box(tree) }); } @@ -76,7 +77,7 @@ fn bench_big_rnd_proof_gen(b: &mut Bencher) { rng.fill_bytes(&mut v); } - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); b.iter(|| { for value in &values { @@ -95,8 +96,10 @@ fn bench_big_rnd_proof_check(b: &mut Bencher) { rng.fill_bytes(&mut v); } - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); - let proofs = values.into_iter().map(|v| tree.gen_proof(v).unwrap()).collect::>(); + let tree = MerkleTree::from_vec(digest, values.clone()); + let proofs = values.into_iter() + .map(|v| tree.gen_proof(v).unwrap()) + .collect::>(); b.iter(|| { for proof in &proofs { @@ -114,7 +117,7 @@ fn bench_big_rnd_iter(b: &mut Bencher) { rng.fill_bytes(&mut v); } - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); b.iter(|| { for value in &tree { diff --git a/src/hashutils.rs b/src/hashutils.rs index 4823e6d..a643c32 100644 --- a/src/hashutils.rs +++ b/src/hashutils.rs @@ -1,27 +1,38 @@ -use ring::digest::{ Algorithm, Context, digest, Digest }; +use ring::digest::{ Algorithm, Context, Digest, digest }; /// The sole purpose of this trait is to extend the standard /// `ring::algo::Algorithm` type with a couple utility functions. pub trait HashUtils { - /// Compute the hash the given byte array - fn hash_bytes(&'static self, bytes: &AsRef<[u8]>) -> Digest; + /// Compute the hash of the empty string + fn hash_empty(&'static self) -> Digest; + + /// Compute the hash of the given leaf + fn hash_leaf(&'static self, bytes: &AsRef<[u8]>) -> Digest; /// Compute the hash of the concatenation of `left` and `right`. // XXX: This is overly generic temporarily to make refactoring easier. // TODO: Give `left` and `right` type &Digest. - fn combine_hashes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest; + fn hash_nodes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest; } impl HashUtils for Algorithm { - fn hash_bytes(&'static self, bytes: &AsRef<[u8]>) -> Digest { - digest(self, bytes.as_ref()) + fn hash_empty(&'static self) -> Digest { + digest(self, &[]) } - fn combine_hashes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest { + fn hash_leaf(&'static self, leaf: &AsRef<[u8]>) -> Digest { let mut ctx = Context::new(self); + ctx.update(&[0x00]); + ctx.update(leaf.as_ref()); + ctx.finish() + } + + fn hash_nodes(&'static self, left: &AsRef<[u8]>, right: &AsRef<[u8]>) -> Digest { + let mut ctx = Context::new(self); + ctx.update(&[0x01]); ctx.update(left.as_ref()); ctx.update(right.as_ref()); ctx.finish() diff --git a/src/merkletree.rs b/src/merkletree.rs index 9e165e9..a4a3982 100644 --- a/src/merkletree.rs +++ b/src/merkletree.rs @@ -28,11 +28,16 @@ impl MerkleTree { /// Constructs a Merkle Tree from a vector of data blocks. /// Returns `None` if `values` is empty. - pub fn from_vec(algorithm: &'static Algorithm, values: Vec) -> Option + pub fn from_vec(algorithm: &'static Algorithm, values: Vec) -> Self where T: AsRef<[u8]> { if values.is_empty() { - return None + return MerkleTree { + algorithm: algorithm, + root: Tree::empty(algorithm.hash_empty()), + height: 0, + count: 0 + }; } let count = values.len(); @@ -40,7 +45,7 @@ impl MerkleTree { let mut cur = Vec::with_capacity(count); for v in values { - let leaf = Tree::make_leaf(algorithm, v); + let leaf = Tree::new_leaf(algorithm, v); cur.push(leaf); } @@ -54,7 +59,7 @@ impl MerkleTree { let left = cur.remove(0); let right = cur.remove(0); - let combined_hash = algorithm.combine_hashes( + let combined_hash = algorithm.hash_nodes( left.hash(), right.hash() ); @@ -74,16 +79,16 @@ impl MerkleTree { cur = next; } - assert!(cur.len() == 1); + debug_assert!(cur.len() == 1); let root = cur.remove(0); - Some(MerkleTree { + MerkleTree { algorithm: algorithm, root: root, height: height, count: count - }) + } } /// Returns the root hash of Merkle tree @@ -107,9 +112,9 @@ impl MerkleTree { where T: AsRef<[u8]> { let root_hash = self.root_hash().clone(); - let node_hash = self.algorithm.hash_bytes(&value.as_ref()); + let leaf_hash = self.algorithm.hash_leaf(&value.as_ref()); - Lemma::new(&self.root, node_hash.as_ref()).map(|lemma| + Lemma::new(&self.root, leaf_hash.as_ref()).map(|lemma| Proof::new(self.algorithm, root_hash, lemma, value) ) } diff --git a/src/proof.rs b/src/proof.rs index 29b9f77..75c6319 100644 --- a/src/proof.rs +++ b/src/proof.rs @@ -56,13 +56,13 @@ impl Proof { false, Some(Positioned::Left(ref hash)) => { - let combined = self.algorithm.combine_hashes(hash, &sub.node_hash); + let combined = self.algorithm.hash_nodes(hash, &sub.node_hash); let hashes_match = combined.as_ref() == lemma.node_hash.as_slice(); hashes_match && self.validate_lemma(sub) } Some(Positioned::Right(ref hash)) => { - let combined = self.algorithm.combine_hashes(&sub.node_hash, hash); + let combined = self.algorithm.hash_nodes(&sub.node_hash, hash); let hashes_match = combined.as_ref() == lemma.node_hash.as_slice(); hashes_match && self.validate_lemma(sub) } @@ -91,6 +91,9 @@ impl Lemma { where T: AsRef<[u8]> { match *tree { + Tree::Empty {.. } => + None, + Tree::Leaf { ref hash, .. } => Lemma::new_leaf_proof(hash, needle), diff --git a/src/tests.rs b/src/tests.rs index 5de4b6e..fc07fa8 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -15,19 +15,19 @@ fn test_from_str_vec() { let values = vec!["one", "two", "three", "four"]; let hashes = vec![ - digest.hash_bytes(&values[0].as_bytes()), - digest.hash_bytes(&values[1].as_bytes()), - digest.hash_bytes(&values[2].as_bytes()), - digest.hash_bytes(&values[3].as_bytes()) + digest.hash_leaf(&values[0].as_bytes()), + digest.hash_leaf(&values[1].as_bytes()), + digest.hash_leaf(&values[2].as_bytes()), + digest.hash_leaf(&values[3].as_bytes()) ]; let count = values.len(); - let tree = MerkleTree::from_vec(digest, values).unwrap(); + let tree = MerkleTree::from_vec(digest, values); - let h01 = digest.combine_hashes(&hashes[0], &hashes[1]); - let h23 = digest.combine_hashes(&hashes[2], &hashes[3]); + let h01 = digest.hash_nodes(&hashes[0], &hashes[1]); + let h23 = digest.hash_nodes(&hashes[2], &hashes[3]); - let root_hash = digest.combine_hashes(&h01, &h23); + let root_hash = digest.hash_nodes(&h01, &h23); assert_eq!(tree.count(), count); assert_eq!(tree.height(), 2); @@ -36,18 +36,21 @@ fn test_from_str_vec() { #[test] -#[should_panic] fn test_from_vec_empty() { let values: Vec> = vec![]; - MerkleTree::from_vec(digest, values).unwrap(); + let tree = MerkleTree::from_vec(digest, values); + let empty_hash: Vec = digest.hash_empty().as_ref().into(); + let root_hash= tree.root_hash().clone(); + + assert_eq!(root_hash, empty_hash); } #[test] fn test_from_vec1() { let values = vec!["hello, world".to_string()]; - let tree = MerkleTree::from_vec(digest, values).unwrap(); + let tree = MerkleTree::from_vec(digest, values); - let root_hash = &digest.hash_bytes(&"hello, world".as_bytes()); + let root_hash = &digest.hash_leaf(&"hello, world".as_bytes()); assert_eq!(tree.count(), 1); assert_eq!(tree.height(), 0); @@ -58,17 +61,17 @@ fn test_from_vec1() { #[test] fn test_from_vec3() { let values = vec![vec![1], vec![2], vec![3]]; - let tree = MerkleTree::from_vec(digest, values).unwrap(); + let tree = MerkleTree::from_vec(digest, values); let hashes = vec![ - digest.hash_bytes(&vec![1]), - digest.hash_bytes(&vec![2]), - digest.hash_bytes(&vec![3]) + digest.hash_leaf(&vec![1]), + digest.hash_leaf(&vec![2]), + digest.hash_leaf(&vec![3]) ]; - let h01 = digest.combine_hashes(&hashes[0], &hashes[1]); + let h01 = digest.hash_nodes(&hashes[0], &hashes[1]); let h2 = &hashes[2]; - let root_hash = &digest.combine_hashes(&h01, h2); + let root_hash = &digest.hash_nodes(&h01, h2); assert_eq!(tree.count(), 3); assert_eq!(tree.height(), 2); @@ -78,20 +81,20 @@ fn test_from_vec3() { #[test] fn test_from_vec9() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); - let hashes = values.iter().map(|v| digest.hash_bytes(v)).collect::>(); + let hashes = values.iter().map(|v| digest.hash_leaf(v)).collect::>(); - let h01 = digest.combine_hashes(&hashes[0], &hashes[1]); - let h23 = digest.combine_hashes(&hashes[2], &hashes[3]); - let h45 = digest.combine_hashes(&hashes[4], &hashes[5]); - let h67 = digest.combine_hashes(&hashes[6], &hashes[7]); + let h01 = digest.hash_nodes(&hashes[0], &hashes[1]); + let h23 = digest.hash_nodes(&hashes[2], &hashes[3]); + let h45 = digest.hash_nodes(&hashes[4], &hashes[5]); + let h67 = digest.hash_nodes(&hashes[6], &hashes[7]); let h8 = &hashes[8]; - let h0123 = digest.combine_hashes(&h01, &h23); - let h4567 = digest.combine_hashes(&h45, &h67); - let h1to7 = digest.combine_hashes(&h0123, &h4567); + let h0123 = digest.hash_nodes(&h01, &h23); + let h4567 = digest.hash_nodes(&h45, &h67); + let h1to7 = digest.hash_nodes(&h0123, &h4567); - let root_hash = &digest.combine_hashes(&h1to7, h8); + let root_hash = &digest.hash_nodes(&h1to7, h8); assert_eq!(tree.count(), 9); assert_eq!(tree.height(), 4); @@ -101,7 +104,7 @@ fn test_from_vec9() { #[test] fn test_valid_proof() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let root_hash = tree.root_hash(); for value in values { @@ -115,7 +118,7 @@ fn test_valid_proof() { #[test] fn test_valid_proof_str() { let values = vec!["Hello", "my", "name", "is", "Rusty"]; - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let root_hash = tree.root_hash(); let value = "Rusty"; @@ -129,10 +132,10 @@ fn test_valid_proof_str() { #[test] fn test_wrong_proof() { let values1 = vec![vec![1], vec![2], vec![3], vec![4]]; - let tree1 = MerkleTree::from_vec(digest, values1.clone()).unwrap(); + let tree1 = MerkleTree::from_vec(digest, values1.clone()); let values2 = vec![vec![4], vec![5], vec![6], vec![7]]; - let tree2 = MerkleTree::from_vec(digest, values2.clone()).unwrap(); + let tree2 = MerkleTree::from_vec(digest, values2.clone()); let root_hash = tree2.root_hash(); @@ -147,7 +150,7 @@ fn test_wrong_proof() { #[test] fn test_mutate_proof_first_lemma() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let root_hash = tree.root_hash(); let mut i = 0; @@ -177,7 +180,7 @@ fn test_mutate_proof_first_lemma() { #[test] fn test_tree_iter() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let iter = tree.iter().map(|x| x.clone()).collect::>(); assert_eq!(values, iter); @@ -186,7 +189,7 @@ fn test_tree_iter() { #[test] fn test_tree_into_iter() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let iter = tree.into_iter().map(|x| x.clone()).collect::>(); assert_eq!(values, iter); @@ -195,7 +198,7 @@ fn test_tree_into_iter() { #[test] fn test_tree_into_iter_loop() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let mut collected = Vec::new(); @@ -209,7 +212,7 @@ fn test_tree_into_iter_loop() { #[test] fn test_tree_into_iter_loop_borrow() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); let mut collected = Vec::new(); diff --git a/src/tree.rs b/src/tree.rs index 1dbc3f5..19e65dc 100644 --- a/src/tree.rs +++ b/src/tree.rs @@ -12,6 +12,10 @@ pub use proof::{ /// Binary Tree where leaves hold a stand-alone value. #[derive(Clone, Debug, PartialEq)] pub enum Tree { + Empty { + hash: Vec + }, + Leaf { hash: Vec, value: T @@ -26,6 +30,13 @@ pub enum Tree { impl Tree { + /// Create an empty tree + pub fn empty(hash: Digest) -> Self { + Tree::Empty { + hash: hash.as_ref().into() + } + } + /// Create a new tree pub fn new(hash: Digest, value: T) -> Self { Tree::Leaf { @@ -35,18 +46,19 @@ impl Tree { } /// Create a new leaf - pub fn make_leaf(algo: &'static Algorithm, value: T) -> Tree + pub fn new_leaf(algo: &'static Algorithm, value: T) -> Tree where T: AsRef<[u8]> { - let hash = algo.hash_bytes(&value.as_ref()); + let hash = algo.hash_leaf(&value.as_ref()); Tree::new(hash, value) } /// Returns a hash from the tree. pub fn hash(&self) -> &Vec { match *self { - Tree::Leaf { ref hash, .. } | Tree::Node { ref hash, .. } => - hash + Tree::Empty { ref hash } => hash, + Tree::Leaf { ref hash, .. } => hash, + Tree::Node { ref hash, .. } => hash } } @@ -81,6 +93,11 @@ impl <'a, T> LeavesIterator<'a, T> { fn add_left(&mut self, mut tree: &'a Tree) { loop { match *tree { + Tree::Empty { .. } => { + self.current_value = None; + break; + }, + Tree::Node { ref left, ref right, .. } => { self.right_nodes.push(right); tree = left; @@ -135,6 +152,11 @@ impl LeavesIntoIterator { fn add_left(&mut self, mut tree: Tree) { loop { match tree { + Tree::Empty { .. } => { + self.current_value = None; + break; + }, + Tree::Node { left, right, .. } => { self.right_nodes.push(*right); tree = *left; diff --git a/tests/proto.rs b/tests/proto.rs index 2443ef7..db36eac 100644 --- a/tests/proto.rs +++ b/tests/proto.rs @@ -16,7 +16,7 @@ static digest: &'static Algorithm = &SHA512; fn test_protobuf_inverse() { let values = (1..10).map(|x| vec![x]).collect::>(); - let tree = MerkleTree::from_vec(digest, values.clone()).unwrap(); + let tree = MerkleTree::from_vec(digest, values.clone()); for value in values { let proof = tree.gen_proof(value).unwrap();