diff --git a/src/hasher.rs b/src/hasher.rs index 525eaf9..979c18a 100644 --- a/src/hasher.rs +++ b/src/hasher.rs @@ -35,9 +35,9 @@ pub trait Hasher: Clone { /// # Trait bounds /// `Copy` is required as the hash needs to be copied to be concatenated/propagated /// when constructing nodes. - /// `PartialEq` is required to compare equality when verifying proof. - /// `Into>` is required to be able to serialize proof. - /// `TryFrom>` is required to parse hashes from a serialized proof. + /// `PartialEq` is required to compare equality when verifying proof + /// `Into>` is required to be able to serialize proof + /// `TryFrom>` is required to parse hashes from a serialized proof type Hash: Copy + PartialEq + Into> + TryFrom>; /// This associated function takes arbitrary bytes and returns hash of it. diff --git a/src/merkle_proof.rs b/src/merkle_proof.rs index 92ea2d6..b31fc95 100644 --- a/src/merkle_proof.rs +++ b/src/merkle_proof.rs @@ -31,40 +31,22 @@ impl MerkleProof { MerkleProof { proof_hashes } } - /// Parses proof serialized as bytes + /// Creates a proof from a slice of bytes. For more details and examples, please see + /// [`try_from`](MerkleProof::try_from) pub fn from_bytes(bytes: &[u8]) -> Result { - let hash_size = T::hash_size(); - - if bytes.len() % hash_size != 0 { - return Err(Error::wrong_proof_size(bytes.len(), hash_size)); - } - - let hashes_count = bytes.len() / hash_size; - let mut proof_hashes_slices = Vec::::with_capacity(hashes_count); - - for i in 0..hashes_count { - let slice_start = i * hash_size; - let slice_end = (i + 1) * hash_size; - let slice = bytes - .get(slice_start..slice_end) - .ok_or_else(Error::vec_to_hash_conversion_error)?; - let vec = - Vec::::try_from(slice).map_err(|_| Error::vec_to_hash_conversion_error())?; - match T::Hash::try_from(vec) { - Ok(val) => proof_hashes_slices.push(val), - Err(_) => return Err(Error::vec_to_hash_conversion_error()), - } - } - - Ok(Self::new(proof_hashes_slices)) + Self::try_from(bytes) } - /// Returns all hashes from the proof + /// Returns all hashes from the proof, sorted from the left to right, + /// bottom to top. pub fn proof_hashes(&self) -> &[T::Hash] { &self.proof_hashes } - pub fn hex_proof_hashes(&self) -> Vec { + /// Returns all hashes from the proof, sorted from the left to right, + /// bottom to top, as a vector of lower hex strings. + /// For a slice of `&[T::Hash]`, see [`proof_hashes`](MerkleProof::proof_hashes) + pub fn proof_hashes_hex(&self) -> Vec { self.proof_hashes .iter() .map(utils::collections::to_hex_string) @@ -117,7 +99,7 @@ impl MerkleProof { } /// Calculates the root and serializes it into a hex string - pub fn hex_root( + pub fn root_hex( &self, leaf_indices: &[usize], leaf_hashes: &[T::Hash], @@ -152,3 +134,78 @@ impl MerkleProof { vectors.iter().cloned().flatten().collect() } } + +impl TryFrom> for MerkleProof { + type Error = Error; + + /// Parses proof serialized to a collection of bytes. Consumes passed vector. + /// + /// # Example + /// ``` + /// use std::convert::TryFrom; + /// use rs_merkle::{MerkleProof, algorithms::Sha256}; + /// + /// let proof_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_result = MerkleProof::::try_from(proof_bytes); + /// ``` + fn try_from(bytes: Vec) -> Result { + MerkleProof::from_bytes(&bytes) + } +} + +impl TryFrom<&[u8]> for MerkleProof { + type Error = Error; + + /// Parses proof serialized to a collection of bytes + /// + /// # Example + /// ``` + /// use std::convert::TryFrom; + /// use rs_merkle::{MerkleProof, algorithms::Sha256}; + /// + /// let proof_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_result = MerkleProof::::try_from(proof_bytes.as_slice()); + /// ``` + fn try_from(bytes: &[u8]) -> Result { + let hash_size = T::hash_size(); + + if bytes.len() % hash_size != 0 { + return Err(Error::wrong_proof_size(bytes.len(), hash_size)); + } + + let hashes_count = bytes.len() / hash_size; + let mut proof_hashes_slices = Vec::::with_capacity(hashes_count); + + for i in 0..hashes_count { + let slice_start = i * hash_size; + let slice_end = (i + 1) * hash_size; + let slice = bytes + .get(slice_start..slice_end) + .ok_or_else(Error::vec_to_hash_conversion_error)?; + let vec = + Vec::::try_from(slice).map_err(|_| Error::vec_to_hash_conversion_error())?; + match T::Hash::try_from(vec) { + Ok(val) => proof_hashes_slices.push(val), + Err(_) => return Err(Error::vec_to_hash_conversion_error()), + } + } + + Ok(Self::new(proof_hashes_slices)) + } +} diff --git a/tests/merkle_proof_test.rs b/tests/merkle_proof_test.rs index c446481..93294bb 100644 --- a/tests/merkle_proof_test.rs +++ b/tests/merkle_proof_test.rs @@ -21,7 +21,7 @@ pub mod root { let merkle_tree = MerkleTree::::from_leaves(&test_data.leaf_hashes); let proof = merkle_tree.proof(&indices_to_prove); let extracted_root = proof - .hex_root( + .root_hex( &indices_to_prove, &leaves_to_prove, test_data.leaf_values.len(), @@ -131,7 +131,7 @@ pub mod from_bytes { ]; let proof = MerkleProof::::from_bytes(&bytes).unwrap(); - let hex_hashes = proof.hex_proof_hashes(); + let hex_hashes = proof.proof_hashes_hex(); assert_eq!(hex_hashes, expected_proof_hashes); } diff --git a/tests/merkle_tree_test.rs b/tests/merkle_tree_test.rs index 6fa5468..f5bfb9e 100644 --- a/tests/merkle_tree_test.rs +++ b/tests/merkle_tree_test.rs @@ -46,7 +46,7 @@ pub mod proof { let merkle_tree = MerkleTree::::from_leaves(&test_data.leaf_hashes); let proof = merkle_tree.proof(&indices_to_prove); - let proof_hashes = proof.hex_proof_hashes(); + let proof_hashes = proof.proof_hashes_hex(); assert_eq!(proof_hashes, expected_proof_hashes) }