feat: implement TryFrom trait for MerkleProof (#5)

This commit is contained in:
Anton Suprunchuk
2021-10-11 12:31:02 +03:00
committed by GitHub
parent bd6cbfa63d
commit ce35f20104
4 changed files with 91 additions and 34 deletions

View File

@@ -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<Vec<u8>>` is required to be able to serialize proof.
/// `TryFrom<Vec<u8>>` is required to parse hashes from a serialized proof.
/// `PartialEq` is required to compare equality when verifying proof
/// `Into<Vec<u8>>` is required to be able to serialize proof
/// `TryFrom<Vec<u8>>` is required to parse hashes from a serialized proof
type Hash: Copy + PartialEq + Into<Vec<u8>> + TryFrom<Vec<u8>>;
/// This associated function takes arbitrary bytes and returns hash of it.

View File

@@ -31,40 +31,22 @@ impl<T: Hasher> MerkleProof<T> {
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<Self, Error> {
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::<T::Hash>::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::<u8>::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<String> {
/// 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<String> {
self.proof_hashes
.iter()
.map(utils::collections::to_hex_string)
@@ -117,7 +99,7 @@ impl<T: Hasher> MerkleProof<T> {
}
/// 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<T: Hasher> MerkleProof<T> {
vectors.iter().cloned().flatten().collect()
}
}
impl<T: Hasher> TryFrom<Vec<u8>> for MerkleProof<T> {
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<u8> = 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::<Sha256>::try_from(proof_bytes);
/// ```
fn try_from(bytes: Vec<u8>) -> Result<Self, Self::Error> {
MerkleProof::from_bytes(&bytes)
}
}
impl<T: Hasher> TryFrom<&[u8]> for MerkleProof<T> {
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<u8> = 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::<Sha256>::try_from(proof_bytes.as_slice());
/// ```
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
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::<T::Hash>::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::<u8>::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))
}
}

View File

@@ -21,7 +21,7 @@ pub mod root {
let merkle_tree = MerkleTree::<Sha256>::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::<Sha256>::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);
}

View File

@@ -46,7 +46,7 @@ pub mod proof {
let merkle_tree = MerkleTree::<Sha256>::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)
}