feat: add customizable hashes and serialization methods to the proof

This commit is contained in:
Anton Suprunchuk
2021-09-25 23:54:43 +03:00
parent 60e63d3bd2
commit bce4a64ae5
10 changed files with 396 additions and 87 deletions

View File

@@ -7,3 +7,7 @@ edition = "2018"
[dependencies]
sha2 = "0.9.8"
# standard crate data is left out
[dev-dependencies]
rayon = "1.5.1"

32
src/error.rs Normal file
View File

@@ -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)
}
}

View File

@@ -1,17 +1,26 @@
pub trait Hasher: Clone {
fn hash(data: &Vec<u8>) -> Vec<u8>;
use std::convert::TryFrom;
use std::mem;
pub trait Hasher {
type Hash: Copy + Into<Vec<u8>> + PartialEq + TryFrom<Vec<u8>>;
fn hash(data: &Vec<u8>) -> Self::Hash;
fn hash_size() -> usize {
mem::size_of::<Self::Hash>()
}
// This is a default solidity implementation
fn concat_and_hash(left: Option<&Vec<u8>>, right: Option<&Vec<u8>>) -> Vec<u8> {
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<u8> = 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<u8> = right_node.clone().into();
concatenated.append(&mut right_node_clone);
Self::hash(&concatenated)
},
None => concatenated
None => left.unwrap().clone()
}
}
}

View File

@@ -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;
mod error;

View File

@@ -1,18 +1,74 @@
use crate::{Hasher, utils};
use std::convert::TryInto;
use std::marker::PhantomData;
pub struct MerkleProof<T> {
proof_hashes: Vec<Vec<u8>>,
hasher: T
use crate::{Hasher, utils};
pub use crate::error::Error;
pub use crate::error::ErrorKind;
pub struct MerkleProof<T: Hasher> {
proof_hashes: Vec<T::Hash>,
_hasher: PhantomData<T>,
}
impl<T: Hasher> MerkleProof<T> {
pub fn new(proof_hashes: Vec<Vec<u8>>, 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>) -> [u8; 32] {
/// let mut hasher = Sha256::new();
///
/// hasher.update(data);
/// <[u8; 32]>::from(hasher.finalize_fixed())
/// }
/// }
/// ```
pub fn new(proof_hashes: Vec<T::Hash>) -> Self {
MerkleProof {
proof_hashes, hasher: hasher.clone()
proof_hashes,
_hasher: PhantomData
}
}
pub fn proof_hashes(&self) -> &Vec<Vec<u8>> {
/// Parses proof serialized as bytes
pub fn from_bytes(bytes: Vec<u8>) -> Result<Self, Error> {
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<T::Hash> = (0..hashes_count)
.map(|i| {
let x: Vec<u8> = 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<T::Hash> {
&self.proof_hashes
}
@@ -23,57 +79,72 @@ impl<T: Hasher> MerkleProof<T> {
.collect()
}
pub fn root(&self, leaf_indices: &Vec<usize>, leaf_hashes: &Vec<Vec<u8>>, total_leaves_count: usize) -> Vec<u8> {
let mut leaf_tuples: Vec<(usize, Vec<u8>)> = 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<usize>, leaf_hashes: &Vec<T::Hash>, 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<(usize, Vec<u8>)>> = Vec::new();
let mut proof_layers: Vec<Vec<(usize, T::Hash)>> = 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<usize> = nodes.iter().cloned().map(|(index, _)| index).collect();
proofs.append(&mut nodes);
proofs.sort_by(|(a, _), (b, _)| a.cmp(b));
let current_layer: Vec<Vec<u8>> = 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<usize>, Vec<T::Hash>) = 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<usize>, leaf_hashes: &Vec<Vec<u8>>, total_leaves_count: usize) -> String {
/// Calculates the root and serializes it into a hex string
pub fn hex_root(&self, leaf_indices: &Vec<usize>, leaf_hashes: &Vec<T::Hash>, 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<usize>, leaf_hashes: &Vec<T::Hash>, 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<u8> {
let vectors: Vec<Vec<u8>> = self.proof_hashes().iter().cloned().map(|hash| hash.into()).collect();
vectors.iter().cloned().flatten().collect()
}
}

View File

@@ -1,22 +1,22 @@
use crate::{utils, MerkleProof, Hasher};
use crate::utils::indices::parent_indices;
pub struct MerkleTree<T> {
layers: Vec<Vec<Vec<u8>>>,
hasher: T,
#[derive(Clone)]
pub struct MerkleTree<T: Hasher> {
layers: Vec<Vec<T::Hash>>,
}
impl<T: Hasher> MerkleTree<T> {
fn build_parent_layer(nodes: &Vec<Vec<u8>>) -> Vec<Vec<u8>> {
fn build_parent_layer(nodes: &Vec<T::Hash>) -> Vec<T::Hash> {
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<u8>>) -> Vec<Vec<Vec<u8>>> {
let tree_depth = utils::indices::tree_depth(leaf_hashes.len());
let mut tree = vec![leaf_hashes];
fn build_tree(leaves: &Vec<T::Hash>) -> Vec<Vec<T::Hash>> {
let tree_depth = utils::indices::tree_depth(leaves.len());
let mut tree: Vec<Vec<T::Hash>> = 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<T: Hasher> MerkleTree<T> {
tree
}
pub fn new(leaf_hashes: Vec<Vec<u8>>, hasher: T) -> Self {
let layers = Self::build_tree(leaf_hashes);
Self { layers, hasher }
pub fn new(leaves: &Vec<T::Hash>) -> Self {
let layers = Self::build_tree(leaves);
Self { layers }
}
pub fn root(&self) -> Option<&Vec<u8>> {
pub fn root(&self) -> Option<&T::Hash> {
self.layers.last()?.first()
}
@@ -40,19 +40,23 @@ impl<T: Hasher> MerkleTree<T> {
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<usize>) -> MerkleProof<T> {
// 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<u8>> = Vec::new();
let mut proof_hashes: Vec<T::Hash> = Vec::new();
for tree_layer in &self.layers {
let siblings = utils::indices::sibling_indices(&current_layer_indices);
@@ -60,7 +64,9 @@ impl<T: Hasher> MerkleTree<T> {
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<T: Hasher> MerkleTree<T> {
current_layer_indices = parent_indices(&current_layer_indices);
}
MerkleProof::new(proof_hashes, &self.hasher)
let proof: MerkleProof<T> = MerkleProof::<T>::new(proof_hashes);
proof
}
pub fn layers(&self) -> &Vec<Vec<Vec<u8>>> {
return &self.layers;
pub fn leaves(&self) -> Option<&Vec<T::Hash>> {
self.layers().first()
}
pub fn layers(&self) -> &Vec<Vec<T::Hash>> {
&self.layers
}
pub fn hex_layers(&self) -> Vec<Vec<String>> {

View File

@@ -2,8 +2,10 @@ fn byte_to_hex(byte: &u8) -> String {
format!("{:02x}", byte)
}
pub fn to_hex_string(bytes: &Vec<u8>) -> String {
let hex_vec: Vec<String> = bytes
pub fn to_hex_string<T: Clone + Into<Vec<u8>>>(bytes: &T) -> String {
// let keks: Vec<u8> = bytes.clone().into();
let hex_vec: Vec<String> = bytes.clone().into()
.iter()
.map(byte_to_hex)
.collect();
@@ -16,3 +18,25 @@ pub fn to_hex_string(bytes: &Vec<u8>) -> String {
pub fn difference(a: &Vec<usize>, b: &Vec<usize>) -> Vec<usize> {
a.iter().cloned().filter(|x| !b.contains(x)).collect()
}
fn combine<T: Clone>(active: Vec<T>, rest: Vec<T>, mut combinations: Vec<Vec<T>>) -> Vec<Vec<T>> {
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<T: Clone>(vec: Vec<T>) -> Vec<Vec<T>> {
combine(Vec::new(), vec, Vec::new())
}

View File

@@ -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<u8>) -> Vec<u8> {
fn hash(data: &Vec<u8>) -> [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<String>,
pub expected_root_hex: String,
pub leaf_hashes: Vec<Vec<u8>>,
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<Sha256Hasher>,
pub cases: Vec<MerkleProofTestCase>
}
#[derive(Clone)]
pub struct MerkleProofTestCase {
pub leaf_indices_to_prove: Vec<usize>,
pub leaf_hashes_to_prove: Vec<[u8; 32]>,
}
impl MerkleProofTestCase {
fn new(leaf_hashes_to_prove: Vec<[u8; 32]>, leaf_indices_to_prove: Vec<usize>) -> 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<ProofTestCases> {
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::<Sha256Hasher>::new(&leaves);
let indices = tree_elements
.iter()
.enumerate()
.map(|(index, _)| index)
.collect();
let possible_proof_index_combinations = utils::collections::combinations(indices);
let cases: Vec<MerkleProofTestCase> = 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()
}

View File

@@ -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::<Sha256Hasher>::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<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 test_data = common::setup();
let indices_to_prove = vec![3, 4];
let merkle_tree = MerkleTree::<Sha256Hasher>::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<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 = MerkleProof::<Sha256Hasher>::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<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,
];
let err = MerkleProof::<Sha256Hasher>::from_bytes(bytes).err().unwrap();
assert_eq!(err.message(), "Proof of size 84 bytes can not be divided into chunks of 32 bytes");
}
}

View File

@@ -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::<Sha256Hasher>::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::<Sha256Hasher>::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::<Sha256Hasher>::new(&test_data.leaf_hashes);
let proof = merkle_tree.proof(&indices_to_prove);
let proof_hashes = proof.hex_proof_hashes();