diff --git a/Cargo.toml b/Cargo.toml index 1b561cd..2a27a4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,7 @@ edition = "2018" [dependencies] sha2 = "0.9.8" + +# standard crate data is left out +[dev-dependencies] +rayon = "1.5.1" diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..43360c1 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,32 @@ +use std::fmt::{Debug, Formatter, Display}; + +#[derive(Copy, Clone, Debug)] +pub enum ErrorKind { + SerializedProofSizeIsIncorrect +} + +#[derive(Clone, Debug)] +pub struct Error { + kind: ErrorKind, + message: String +} + +impl Error { + pub fn new(kind: ErrorKind, message: String) -> Self { + Self { kind, message } + } + + pub fn kind(&self) -> ErrorKind { + self.kind + } + + pub fn message(&self) -> &str { &self.message } +} + +impl std::error::Error for Error {} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.message) + } +} \ No newline at end of file diff --git a/src/hasher.rs b/src/hasher.rs index 949504d..ec05558 100644 --- a/src/hasher.rs +++ b/src/hasher.rs @@ -1,17 +1,26 @@ -pub trait Hasher: Clone { - fn hash(data: &Vec) -> Vec; +use std::convert::TryFrom; +use std::mem; + +pub trait Hasher { + type Hash: Copy + Into> + PartialEq + TryFrom>; + + fn hash(data: &Vec) -> Self::Hash; + + fn hash_size() -> usize { + mem::size_of::() + } // This is a default solidity implementation - fn concat_and_hash(left: Option<&Vec>, right: Option<&Vec>) -> Vec { - let mut concatenated = left.expect("Left node should always be present, otherwise it's impossible to calculate hash").to_vec(); + fn concat_and_hash(left: Option<&Self::Hash>, right: Option<&Self::Hash>) -> Self::Hash { + let mut concatenated: Vec = left.expect("Left node should always be present, otherwise it's impossible to calculate hash").clone().into(); match right { Some(right_node) => { - let mut right_node_clone = right_node.to_vec(); + let mut right_node_clone: Vec = right_node.clone().into(); concatenated.append(&mut right_node_clone); Self::hash(&concatenated) }, - None => concatenated + None => left.unwrap().clone() } } } \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 7655e6a..50fe5ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,11 @@ +pub use hasher::Hasher; +pub use merkle_proof::MerkleProof; +pub use merkle_tree::MerkleTree; + mod merkle_tree; mod merkle_proof; mod hasher; pub mod utils; -pub use merkle_tree::MerkleTree; -pub use merkle_proof::MerkleProof; -pub use hasher::Hasher; \ No newline at end of file +mod error; + diff --git a/src/merkle_proof.rs b/src/merkle_proof.rs index 9b0003d..8eae484 100644 --- a/src/merkle_proof.rs +++ b/src/merkle_proof.rs @@ -1,18 +1,74 @@ -use crate::{Hasher, utils}; +use std::convert::TryInto; +use std::marker::PhantomData; -pub struct MerkleProof { - proof_hashes: Vec>, - hasher: T +use crate::{Hasher, utils}; +pub use crate::error::Error; +pub use crate::error::ErrorKind; + +pub struct MerkleProof { + proof_hashes: Vec, + _hasher: PhantomData, } impl MerkleProof { - pub fn new(proof_hashes: Vec>, hasher: &T) -> Self { + /// MerkleProof requires specifying hashing algorithm and hash size in order to work. + /// It uses Hasher trait from the crate to do that. An sha256 implementation of Hasher + /// could look like this: + /// ``` + /// use rs_merkle::Hasher; + /// use sha2::{Sha256, Digest, digest::FixedOutput}; + /// + /// #[derive(Clone)] + /// pub struct Sha256Hasher {} + /// + /// impl Hasher for Sha256Hasher { + /// // The size of sha256 is 32 bytes + /// type Hash = [u8; 32]; + /// + /// fn hash(data: &Vec) -> [u8; 32] { + /// let mut hasher = Sha256::new(); + /// + /// hasher.update(data); + /// <[u8; 32]>::from(hasher.finalize_fixed()) + /// } + /// } + /// ``` + pub fn new(proof_hashes: Vec) -> Self { MerkleProof { - proof_hashes, hasher: hasher.clone() + proof_hashes, + _hasher: PhantomData } } - pub fn proof_hashes(&self) -> &Vec> { + /// Parses proof serialized as bytes + pub fn from_bytes(bytes: Vec) -> Result { + let hash_size = T::hash_size(); + + if bytes.len() % hash_size != 0 { + return Err(Error::new( + ErrorKind::SerializedProofSizeIsIncorrect, + format!("Proof of size {} bytes can not be divided into chunks of {} bytes", bytes.len(), hash_size))); + } + + let hashes_count = bytes.len() / hash_size; + let proof_hashes_slices: Vec = (0..hashes_count) + .map(|i| { + let x: Vec = bytes.get(i * hash_size..(i + 1) * hash_size).unwrap().try_into().unwrap(); + match x.try_into() { + Ok(val) => val, + // Because of the check above the initial bytes are always slices perfectly + // into appropriately sized hashes. + // Unwrap is not used here due to more complex trait bounds on T::Hash + // that would be require to satisfy .unwrap usage + Err(_) => panic!("Unexpected error during proof parsing") + } + }) + .collect(); + + Ok(Self::new(proof_hashes_slices)) + } + + pub fn proof_hashes(&self) -> &Vec { &self.proof_hashes } @@ -23,57 +79,72 @@ impl MerkleProof { .collect() } - pub fn root(&self, leaf_indices: &Vec, leaf_hashes: &Vec>, total_leaves_count: usize) -> Vec { - let mut leaf_tuples: Vec<(usize, Vec)> = leaf_indices.iter().cloned().zip(leaf_hashes.iter().cloned()).collect(); + /// Calculates merkle root bases on provided leaves and proof hashes + pub fn root(&self, leaf_indices: &Vec, leaf_hashes: &Vec, total_leaves_count: usize) -> T::Hash { + // Zipping indices and hashes into a vector of (original_index_in_tree, leaf_hash) + let mut leaf_tuples: Vec<(usize, T::Hash)> = leaf_indices.iter().cloned().zip(leaf_hashes.iter().cloned()).collect(); + // Sorting leaves by indexes in case they weren't sorted already leaf_tuples.sort_by(|(a, _), (b, _)| a.cmp(b)); + // Getting back _sorted_ indices let proof_indices = utils::indices::proof_indices(leaf_indices, total_leaves_count); - let mut proof_tuples_by_layers: Vec)>> = Vec::new(); + let mut proof_layers: Vec> = Vec::new(); let mut next_slice_start = 0; for indices in proof_indices { let slice_start = next_slice_start; next_slice_start += indices.len(); - let hashes = self.proof_hashes.get(slice_start..next_slice_start).unwrap().to_vec(); - proof_tuples_by_layers.push(indices.iter().cloned().zip(hashes.iter().cloned()).collect()); + let hashes = self.proof_hashes.get(slice_start..next_slice_start).unwrap(); + proof_layers.push(indices.iter().cloned().zip(hashes.iter().cloned()).collect()); } - let mut tree = vec![leaf_tuples]; + let mut partial_tree = vec![leaf_tuples]; - for layerIndex in 0..proof_tuples_by_layers.len() { - let mut proofs = proof_tuples_by_layers.get(layerIndex).unwrap().clone(); - //println!("Proofs: {:?}", proofs.iter().cloned().map()); - let mut nodes = tree.get(layerIndex).unwrap().clone(); - let known_indices: Vec = nodes.iter().cloned().map(|(index, _)| index).collect(); - proofs.append(&mut nodes); - proofs.sort_by(|(a, _), (b, _)| a.cmp(b)); - let current_layer: Vec> = proofs.iter().cloned().map(|(_, hash)| hash).collect(); + for layer_index in 0..proof_layers.len() { + let mut current_layer = partial_tree.get(layer_index).unwrap().clone(); + let mut current_proofs = proof_layers.get(layer_index).unwrap().clone(); + current_layer.append(&mut current_proofs); + current_layer.sort_by(|(a, _), (b, _)| a.cmp(b)); - let parent_indices = utils::indices::parent_indices(&known_indices); + let (indices, hashes): (Vec, Vec) = current_layer.drain(..).unzip(); + let parent_layer_indices = utils::indices::parent_indices(&indices); - let parent_layer = parent_indices + let parent_layer = parent_layer_indices .iter() .cloned() .enumerate() .map(|(i, parent_node_index)| ( parent_node_index, T::concat_and_hash( - current_layer.get(i * 2), - current_layer.get(i * 2 + 1) + hashes.get(i * 2), + hashes.get(i * 2 + 1) )) ) .collect(); - tree.push(parent_layer); + partial_tree.push(parent_layer); } - return tree.last().unwrap().first().unwrap().1.clone(); + return partial_tree.last().unwrap().first().unwrap().1.clone(); } - pub fn hex_root(&self, leaf_indices: &Vec, leaf_hashes: &Vec>, total_leaves_count: usize) -> String { + /// Calculates the root and serializes it into a hex string + pub fn hex_root(&self, leaf_indices: &Vec, leaf_hashes: &Vec, total_leaves_count: usize) -> String { let root = self.root(leaf_indices, leaf_hashes, total_leaves_count); utils::collections::to_hex_string(&root) } + + /// Verifies + pub fn verify(&self, root: T::Hash, leaf_indices: &Vec, leaf_hashes: &Vec, total_leaves_count: usize) -> bool { + let extracted_root = self.root(leaf_indices, leaf_hashes, total_leaves_count); + root == extracted_root + } + + /// Serializes proof hashes to a flat vector of bytes + pub fn to_bytes(&self) -> Vec { + let vectors: Vec> = self.proof_hashes().iter().cloned().map(|hash| hash.into()).collect(); + vectors.iter().cloned().flatten().collect() + } } \ No newline at end of file diff --git a/src/merkle_tree.rs b/src/merkle_tree.rs index 060afda..869eb0a 100644 --- a/src/merkle_tree.rs +++ b/src/merkle_tree.rs @@ -1,22 +1,22 @@ use crate::{utils, MerkleProof, Hasher}; use crate::utils::indices::parent_indices; -pub struct MerkleTree { - layers: Vec>>, - hasher: T, +#[derive(Clone)] +pub struct MerkleTree { + layers: Vec>, } impl MerkleTree { - fn build_parent_layer(nodes: &Vec>) -> Vec> { + fn build_parent_layer(nodes: &Vec) -> Vec { let parent_layer_nodes_count = utils::indices::div_ceil(nodes.len(),2); (0..parent_layer_nodes_count) .map(|i| T::concat_and_hash(nodes.get(i * 2), nodes.get(i * 2 + 1))) .collect() } - fn build_tree(leaf_hashes: Vec>) -> Vec>> { - let tree_depth = utils::indices::tree_depth(leaf_hashes.len()); - let mut tree = vec![leaf_hashes]; + fn build_tree(leaves: &Vec) -> Vec> { + let tree_depth = utils::indices::tree_depth(leaves.len()); + let mut tree: Vec> = vec![leaves.clone()]; for _ in 0..tree_depth { // Using unwrap is fine here, since tree always has at least one element @@ -26,12 +26,12 @@ impl MerkleTree { tree } - pub fn new(leaf_hashes: Vec>, hasher: T) -> Self { - let layers = Self::build_tree(leaf_hashes); - Self { layers, hasher } + pub fn new(leaves: &Vec) -> Self { + let layers = Self::build_tree(leaves); + Self { layers } } - pub fn root(&self) -> Option<&Vec> { + pub fn root(&self) -> Option<&T::Hash> { self.layers.last()?.first() } @@ -40,19 +40,23 @@ impl MerkleTree { Some(utils::collections::to_hex_string(root)) } + /// Returns tree depth. Tree depth is how many layers there is between + /// leaves and root pub fn depth(&self) -> usize { - return self.layers.len() - 1; + self.layers.len() - 1 } + /// Proof consists of all siblings hashes that aren't in the set we're trying to prove + /// + /// # Implementation + /// + /// 1. Get all sibling indices. Those are the indices we need to get to the root + /// 2. Filter all nodes that doesn't require an additional hash + /// 3. Get all hashes for indices from step 2 + /// 4. Remove empty spaces (the leftmost nodes that do not have anything to the right) pub fn proof(&self, leaf_indices: &Vec) -> MerkleProof { - // Proof consists of all siblings hashes that aren't in the set we're trying to prove - // 1. Get all sibling indices. Those are the indices we need to get to the root - // 2. Filter all nodes that doesn't require an additional hash - // 3. Get all hashes for indices from step 2 - // 4. Remove empty spaces (the leftmost nodes that do not have anything to the right)7 - let mut current_layer_indices = leaf_indices.to_vec(); - let mut proof_hashes: Vec> = Vec::new(); + let mut proof_hashes: Vec = Vec::new(); for tree_layer in &self.layers { let siblings = utils::indices::sibling_indices(¤t_layer_indices); @@ -60,7 +64,9 @@ impl MerkleTree { for index in proof_indices { match tree_layer.get(index) { - Some(hash) => proof_hashes.push(hash.to_vec()), + Some(hash) => { + proof_hashes.push(hash.clone()); + }, None => continue, } } @@ -68,11 +74,16 @@ impl MerkleTree { current_layer_indices = parent_indices(¤t_layer_indices); } - MerkleProof::new(proof_hashes, &self.hasher) + let proof: MerkleProof = MerkleProof::::new(proof_hashes); + proof } - pub fn layers(&self) -> &Vec>> { - return &self.layers; + pub fn leaves(&self) -> Option<&Vec> { + self.layers().first() + } + + pub fn layers(&self) -> &Vec> { + &self.layers } pub fn hex_layers(&self) -> Vec> { diff --git a/src/utils/collections.rs b/src/utils/collections.rs index f0e2893..2bf7682 100644 --- a/src/utils/collections.rs +++ b/src/utils/collections.rs @@ -2,8 +2,10 @@ fn byte_to_hex(byte: &u8) -> String { format!("{:02x}", byte) } -pub fn to_hex_string(bytes: &Vec) -> String { - let hex_vec: Vec = bytes +pub fn to_hex_string>>(bytes: &T) -> String { + // let keks: Vec = bytes.clone().into(); + + let hex_vec: Vec = bytes.clone().into() .iter() .map(byte_to_hex) .collect(); @@ -16,3 +18,25 @@ pub fn to_hex_string(bytes: &Vec) -> String { pub fn difference(a: &Vec, b: &Vec) -> Vec { a.iter().cloned().filter(|x| !b.contains(x)).collect() } + +fn combine(active: Vec, rest: Vec, mut combinations: Vec>) -> Vec> { + return if rest.is_empty() { + if active.is_empty() { + combinations + } else { + combinations.push(active); + combinations + } + } else { + let mut next = active.clone(); + next.push(rest.get(0).unwrap().clone()); + + combinations = combine(next, rest.clone().drain(1..).collect(), combinations); + combinations = combine(active, rest.clone().drain(1..).collect(), combinations); + combinations + } +} + +pub fn combinations(vec: Vec) -> Vec> { + combine(Vec::new(), vec, Vec::new()) +} diff --git a/tests/common.rs b/tests/common.rs index e5a79e7..bec23ff 100644 --- a/tests/common.rs +++ b/tests/common.rs @@ -1,42 +1,101 @@ -use rs_merkle::Hasher; -use sha2::{Sha256, Digest}; +use rayon::prelude::*; +use rs_merkle::{Hasher, MerkleTree, utils}; +use sha2::{Sha256, Digest, digest::FixedOutput}; #[derive(Clone)] -pub struct TestHasher {} +pub struct Sha256Hasher {} -impl TestHasher { - pub fn new() -> Self { TestHasher {} } -} +impl Hasher for Sha256Hasher { + type Hash = [u8; 32]; -impl Hasher for TestHasher { - fn hash(data: &Vec) -> Vec { + fn hash(data: &Vec) -> [u8; 32] { let mut hasher = Sha256::new(); hasher.update(data); - hasher.finalize().to_owned().to_vec() + <[u8; 32]>::from(hasher.finalize_fixed()) } } pub struct TestData { - pub test_hasher: TestHasher, pub leaf_values: Vec, pub expected_root_hex: String, - pub leaf_hashes: Vec>, + pub leaf_hashes: Vec<[u8; 32]>, } pub fn setup() -> TestData { - let test_hasher = TestHasher::new(); let leaf_values = ["a", "b", "c", "d", "e", "f"]; let expected_root_hex = "1f7379539707bcaea00564168d1d4d626b09b73f8a2a365234c62d763f854da2"; let leaf_hashes = leaf_values .iter() - .map(|x| TestHasher::hash(x.as_bytes().to_vec().as_ref())) + .map(|x| Sha256Hasher::hash(x.as_bytes().to_vec().as_ref())) .collect(); TestData { - test_hasher, leaf_values: leaf_values.iter().cloned().map(String::from).collect(), leaf_hashes, expected_root_hex: String::from(expected_root_hex) } } + +#[derive(Clone)] +pub struct ProofTestCases { + pub merkle_tree: MerkleTree, + pub cases: Vec +} + +#[derive(Clone)] +pub struct MerkleProofTestCase { + pub leaf_indices_to_prove: Vec, + pub leaf_hashes_to_prove: Vec<[u8; 32]>, +} + +impl MerkleProofTestCase { + fn new(leaf_hashes_to_prove: Vec<[u8; 32]>, leaf_indices_to_prove: Vec) -> Self { + Self { + // title: format!("from a tree of {} elements for {} elements at positions {:?}", leaf_hashes.len(), leaf_indices_to_prove.len(), leaf_indices_to_prove), + leaf_hashes_to_prove, + leaf_indices_to_prove, + } + } +} + +pub fn setup_proof_test_cases() -> Vec { + let max_case = ["a", "b", "c", "d", "e", "f", "g", "h", "k", "l", "m", "o", "p", "r", "s"]; + + max_case + .par_iter() + .enumerate() + .map(|(index, _)| { + let tree_elements = max_case.get(0..index + 1).unwrap(); + + let leaves: Vec<[u8; 32]> = tree_elements + .iter() + .map(|x| Sha256Hasher::hash(x.as_bytes().to_vec().as_ref())) + .collect(); + + let merkle_tree = MerkleTree::::new(&leaves); + + let indices = tree_elements + .iter() + .enumerate() + .map(|(index, _)| index) + .collect(); + + let possible_proof_index_combinations = utils::collections::combinations(indices); + + let cases: Vec = possible_proof_index_combinations + .par_iter() + .cloned() + .map(|index_combination| { + MerkleProofTestCase::new( + index_combination.iter().map(|index| leaves.get(*index).unwrap().clone()).collect(), + index_combination, + ) + } + ) + .collect(); + let case = ProofTestCases { merkle_tree, cases }; + case + }) + .collect() +} \ No newline at end of file diff --git a/tests/merkle_proof_test.rs b/tests/merkle_proof_test.rs index 70bf2e9..59d9b21 100644 --- a/tests/merkle_proof_test.rs +++ b/tests/merkle_proof_test.rs @@ -1,8 +1,10 @@ mod common; pub mod root { - use crate::common; - use rs_merkle::{MerkleTree, utils}; + use crate::{common, common::Sha256Hasher}; + use rs_merkle::{MerkleTree}; + use std::time::Instant; + use rayon::prelude::*; #[test] pub fn should_return_a_correct_root() { @@ -12,10 +14,104 @@ pub mod root { let indices_to_prove = vec![3, 4]; let leaves_to_prove = indices_to_prove.iter().cloned().map(|i| leaf_hashes.get(i).unwrap().clone()).collect(); - let merkle_tree = MerkleTree::new(test_data.leaf_hashes.to_vec(), test_data.test_hasher.clone()); + let merkle_tree = MerkleTree::::new(&test_data.leaf_hashes); let proof = merkle_tree.proof(&indices_to_prove); let extracted_root = proof.hex_root(&indices_to_prove, &leaves_to_prove, test_data.leaf_values.len()); - assert_eq!(extracted_root, *expected_root) + assert_eq!(extracted_root, *expected_root); + + let test_preparation_started = Instant::now(); + let test_cases = common::setup_proof_test_cases(); + println!("Preparing test cases took {:.2}s", test_preparation_started.elapsed().as_secs_f32()); + let test_cases_count = test_cases.iter().fold(0, |acc, case| acc + case.cases.len()); + + let test_run_started = Instant::now(); + test_cases.par_iter().for_each(|test_case| { + let merkle_tree = &test_case.merkle_tree; + + test_case.cases.par_iter().for_each(|case| { + let proof = merkle_tree.proof(&case.leaf_indices_to_prove); + let root = merkle_tree.hex_root().unwrap(); + let extracted_root = proof.hex_root(&case.leaf_indices_to_prove, &case.leaf_hashes_to_prove, merkle_tree.leaves().unwrap().len()); + + assert_eq!(extracted_root, root) + }); + }); + println!("{} test cases executed in {:.2}s", test_cases_count, test_run_started.elapsed().as_secs_f32()); + } +} + +pub mod to_bytes { + use crate::{common, common::Sha256Hasher}; + use rs_merkle::MerkleTree; + + #[test] + pub fn should_correctly_serialize_to_bytes() { + let expected_bytes: Vec = vec![ + 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, + 53, 104, 133, 165, 51, 147, 162, 2, 157, 36, 19, 148, + 153, 114, 101, 161, 162, 90, 239, 198, 37, 47, 16, 200, + 54, 16, 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, + 162, 249, 91, 228, 209, 215, 188, 250, 137, 215, 36, 138, + 130, 217, 241, 17, 229, 160, 31, 238, 20, 224, 237, 92, + 72, 113, 79, 34, 24, 15, 37, 173, 131, 101, 181, 63, + 151, 121, 247, 157, 196, 163, 215, 233, 57, 99, 249, 74 + ]; + + let test_data = common::setup(); + let indices_to_prove = vec![3, 4]; + let merkle_tree = MerkleTree::::new(&test_data.leaf_hashes); + let proof = merkle_tree.proof(&indices_to_prove); + + let bytes = proof.to_bytes(); + + assert_eq!(bytes, expected_bytes); + } +} + +pub mod from_bytes { + use rs_merkle::MerkleProof; + use crate::common::Sha256Hasher; + + #[test] + pub fn should_return_result_with_proof() { + let expected_proof_hashes = [ + "2e7d2c03a9507ae265ecf5b5356885a53393a2029d241394997265a1a25aefc6", + "252f10c83610ebca1a059c0bae8255eba2f95be4d1d7bcfa89d7248a82d9f111", + "e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a", + ]; + + let bytes: Vec = vec![ + 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, + 53, 104, 133, 165, 51, 147, 162, 2, 157, 36, 19, 148, + 153, 114, 101, 161, 162, 90, 239, 198, 37, 47, 16, 200, + 54, 16, 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, + 162, 249, 91, 228, 209, 215, 188, 250, 137, 215, 36, 138, + 130, 217, 241, 17, 229, 160, 31, 238, 20, 224, 237, 92, + 72, 113, 79, 34, 24, 15, 37, 173, 131, 101, 181, 63, + 151, 121, 247, 157, 196, 163, 215, 233, 57, 99, 249, 74 + ]; + + let proof = MerkleProof::::from_bytes(bytes).unwrap(); + let hex_hashes = proof.hex_proof_hashes(); + + assert_eq!(hex_hashes, expected_proof_hashes); + } + + #[test] + pub fn should_return_error_when_proof_can_not_be_parsed() { + let bytes: Vec = vec![ + 46, 125, 44, 3, 169, 80, 122, 226, 101, 236, 245, 181, + 53, 104, 133, 165, 51, 147, 162, 2, 157, 36, 19, 148, + 153, 114, 101, 161, 162, 90, 239, 198, 37, 47, 16, 200, + 54, 16, 235, 202, 26, 5, 156, 11, 174, 130, 85, 235, + 162, 249, 91, 228, 209, 215, 188, 250, 137, 215, 36, 138, + 130, 217, 241, 17, 229, 160, 31, 238, 20, 224, 237, 92, + 72, 113, 79, 34, 24, 15, 37, 173, 131, 101, 181, 63, + ]; + + let err = MerkleProof::::from_bytes(bytes).err().unwrap(); + + assert_eq!(err.message(), "Proof of size 84 bytes can not be divided into chunks of 32 bytes"); } } \ No newline at end of file diff --git a/tests/merkle_tree_test.rs b/tests/merkle_tree_test.rs index c485d57..13e13d4 100644 --- a/tests/merkle_tree_test.rs +++ b/tests/merkle_tree_test.rs @@ -1,14 +1,14 @@ mod common; pub mod root { - use crate::common; - use rs_merkle::{MerkleTree, utils}; + use crate::{common, common::Sha256Hasher}; + use rs_merkle::{MerkleTree}; #[test] pub fn should_return_a_correct_root() { let test_data = common::setup(); - let merkle_tree = MerkleTree::new(test_data.leaf_hashes.to_vec(), test_data.test_hasher.clone()); + let merkle_tree = MerkleTree::::new(&test_data.leaf_hashes); let hex_root = merkle_tree.hex_root().unwrap(); assert_eq!(hex_root, test_data.expected_root_hex); @@ -16,14 +16,14 @@ pub mod root { } pub mod tree_depth { - use crate::common; + use crate::{common, common::Sha256Hasher}; use rs_merkle::MerkleTree; #[test] pub fn should_return_a_correct_tree_depth() { let test_data = common::setup(); - let merkle_tree = MerkleTree::new(test_data.leaf_hashes.to_vec(), test_data.test_hasher.clone()); + let merkle_tree = MerkleTree::::new(&test_data.leaf_hashes); let depth = merkle_tree.depth(); assert_eq!(depth, 3) @@ -31,7 +31,7 @@ pub mod tree_depth { } pub mod proof { - use crate::common; + use crate::{common, common::Sha256Hasher}; use rs_merkle::MerkleTree; #[test] @@ -44,7 +44,7 @@ pub mod proof { "e5a01fee14e0ed5c48714f22180f25ad8365b53f9779f79dc4a3d7e93963f94a", ]; - let merkle_tree = MerkleTree::new(test_data.leaf_hashes.to_vec(), test_data.test_hasher.clone()); + let merkle_tree = MerkleTree::::new(&test_data.leaf_hashes); let proof = merkle_tree.proof(&indices_to_prove); let proof_hashes = proof.hex_proof_hashes();