mirror of
https://github.com/tlsnotary/rs-merkle.git
synced 2026-01-08 22:38:07 -05:00
feat: implement TryFrom trait for MerkleProof (#5)
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user