#![deny(missing_docs)]
#![doc(
html_logo_url = "https://raw.githubusercontent.com/LVivona/mrkle/refs/heads/main/.github/assets/logo.png"
)]
#![doc = include_str!("../DOC_README.md")]
#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
#[macro_use]
extern crate alloc;
#[cfg(all(feature = "std", feature = "alloc"))]
compile_error!("must choose either the `std` or `alloc` feature, but not both.");
#[cfg(all(not(feature = "std"), not(feature = "alloc")))]
compile_error!("must choose either the `std` or `alloc` feature");
#[path = "entry.rs"]
mod borrowed;
mod builder;
mod proof;
pub mod hasher;
pub mod tree;
pub mod error;
use crate::error::MrkleError;
pub(crate) use crate::error::{EntryError, NodeError, ProofError, TreeError};
pub(crate) use crate::tree::DefaultIx;
pub use crate::builder::MrkleDefaultBuilder;
pub use crate::hasher::{GenericArray, Hasher, MrkleHasher};
pub use crate::proof::{MrkleProof, ProofLevel, ProofPath};
pub use crate::tree::{IndexIter, IndexType, Iter, MutNode, Node, NodeIndex, Tree, TreeView};
pub use borrowed::*;
#[allow(unused_imports, reason = "future proofing for tree features.")]
pub(crate) mod prelude {
#[cfg(not(feature = "std"))]
mod no_stds {
pub use alloc::borrow::{Borrow, Cow, ToOwned};
pub use alloc::boxed::Box;
pub use alloc::collections::{BTreeMap, BTreeSet, VecDeque};
pub use alloc::str;
pub use alloc::string::{String, ToString};
pub use alloc::vec::Vec;
pub use hashbrown::{HashMap, HashSet};
}
#[cfg(feature = "std")]
mod stds {
pub use std::borrow::{Borrow, Cow, ToOwned};
pub use std::boxed::Box;
pub use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
pub use std::str;
pub use std::string::{String, ToString};
pub use std::vec::Vec;
}
pub use core::fmt::{Debug, Display};
pub use core::hash::Hash;
pub use core::marker::{Copy, PhantomData};
pub use core::slice::SliceIndex;
pub(crate) use crypto::digest::Digest;
#[cfg(not(feature = "std"))]
pub use no_stds::*;
#[cfg(feature = "std")]
pub use stds::*;
}
use prelude::*;
pub struct MrkleNode<T, D: Digest, Ix: IndexType = DefaultIx> {
payload: Payload<T>,
pub parent: Option<NodeIndex<Ix>>,
pub(crate) children: Vec<NodeIndex<Ix>>,
pub(crate) hash: GenericArray<D>,
}
impl<T, D: Digest, Ix: IndexType> Eq for MrkleNode<T, D, Ix> {}
impl<T, D: Digest, Ix: IndexType> MrkleNode<T, D, Ix>
where
T: AsRef<[u8]> + Clone,
{
#[inline]
pub fn leaf(payload: T) -> Self {
let hash = D::digest(&payload);
let payload = Payload::Leaf(payload);
Self {
payload,
hash,
parent: None,
children: Vec::with_capacity(0),
}
}
pub fn leaf_with_hash(payload: T, hash: GenericArray<D>) -> Self {
#[cold]
#[inline(never)]
fn assert_hash_digest<D: Digest>(value: &GenericArray<D>) {
panic!(
"Hash verification failed: provided hash {value:?} does not match \
the computed digest of the payload data. This indicates either \
corrupted data or an incorrect hash value."
);
}
if D::digest(&payload) != hash {
assert_hash_digest::<D>(&hash);
}
let payload = Payload::Leaf(payload);
Self {
payload,
hash,
parent: None,
children: Vec::with_capacity(0),
}
}
pub fn leaf_with_hasher(payload: T, hasher: &MrkleHasher<D>) -> Self {
let hash = hasher.hash(&payload);
let payload = Payload::Leaf(payload);
Self {
payload,
hash,
parent: None,
children: Vec::with_capacity(0),
}
}
}
impl<T, D: Digest, Ix: IndexType> MrkleNode<T, D, Ix> {
#[inline]
pub fn internal(
tree: &Tree<MrkleNode<T, D, Ix>, Ix>,
children: Vec<NodeIndex<Ix>>,
) -> Result<Self, MrkleError> {
let mut hasher = D::new();
children
.iter()
.try_for_each(|&idx| {
if let Some(node) = tree.get(idx.index()) {
if node.parent().is_some() {
return Err(TreeError::from(NodeError::ParentConflict {
parent: node.parent().unwrap().index(),
child: idx.index(),
}));
}
hasher.update(node.hash());
Ok(())
} else {
Err(TreeError::from(NodeError::NodeNotFound {
index: idx.index(),
}))
}
})
.map_err(MrkleError::from)?;
let hash = hasher.finalize();
Ok(Self {
payload: Payload::Internal,
parent: None,
children,
hash,
})
}
pub fn internal_with_hash(hash: GenericArray<D>, children: Vec<NodeIndex<Ix>>) -> Self {
Self {
payload: Payload::Internal,
parent: None,
children,
hash,
}
}
pub fn value(&self) -> Option<&T> {
if let Payload::Leaf(value) = &self.payload {
Some(value)
} else {
None
}
}
pub fn hash(&self) -> &GenericArray<D> {
&self.hash
}
pub fn to_hex(&self) -> HexDisplay<'_> {
entry::from_bytes(&self.hash[..]).to_hex()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Payload<T> {
Leaf(T),
Internal,
}
impl<T> Payload<T> {
#[inline]
pub fn is_leaf(&self) -> bool {
matches!(self, Self::Leaf(_))
}
}
impl<T> core::ops::Deref for Payload<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
match self {
Self::Leaf(value) => value,
_ => panic!("Can not deref a internal node."),
}
}
}
#[cfg(feature = "serde")]
impl<T> serde::Serialize for Payload<T>
where
T: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
match self {
Payload::Leaf(data) => serializer.serialize_some(data),
Payload::Internal => serializer.serialize_none(),
}
}
}
#[cfg(feature = "serde")]
impl<'de, T> serde::Deserialize<'de> for Payload<T>
where
T: serde::Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let opt: Option<T> = Option::deserialize(deserializer)?;
match opt {
Some(data) => Ok(Payload::Leaf(data)),
None => Ok(Payload::Internal),
}
}
}
impl<T, D: Digest, Ix: IndexType> PartialEq for MrkleNode<T, D, Ix> {
fn eq(&self, other: &Self) -> bool {
self.hash == other.hash
}
}
impl<T, D: Digest, Ix: IndexType> Clone for MrkleNode<T, D, Ix>
where
T: Clone,
{
fn clone(&self) -> Self {
Self {
payload: self.payload.clone(),
parent: self.parent,
children: self.children.clone(),
hash: self.hash.clone(),
}
}
}
impl<T, D: Digest, Ix: IndexType> Node<Ix> for MrkleNode<T, D, Ix> {
fn is_root(&self) -> bool {
self.parent.is_none() && !self.payload.is_leaf()
}
#[inline]
fn is_leaf(&self) -> bool {
self.payload.is_leaf() && self.children.is_empty()
}
#[inline]
fn parent(&self) -> Option<NodeIndex<Ix>> {
self.parent
}
#[inline]
fn children(&self) -> Vec<NodeIndex<Ix>> {
self.children.clone()
}
#[inline]
fn child_count(&self) -> usize {
self.children.len()
}
fn child_at(&self, index: usize) -> Option<NodeIndex<Ix>> {
if let Some(&child) = self.children.get(index) {
return Some(child);
}
None
}
#[inline]
fn contains(&self, node: &NodeIndex<Ix>) -> bool {
self.children.contains(node)
}
}
impl<T, D: Digest, Ix: IndexType> AsRef<entry> for MrkleNode<T, D, Ix> {
fn as_ref(&self) -> &entry {
entry::from_bytes_unchecked(&self.hash)
}
}
impl<T, D: Digest, Ix: IndexType> AsRef<[u8]> for MrkleNode<T, D, Ix> {
fn as_ref(&self) -> &[u8] {
&self.hash
}
}
impl<T, D: Digest> core::borrow::Borrow<entry> for MrkleNode<T, D> {
fn borrow(&self) -> &entry {
self.as_ref()
}
}
impl<T, D: Digest, Ix: IndexType> core::fmt::Debug for MrkleNode<T, D, Ix> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut debug_struct = f.debug_struct("MrkleNode");
debug_struct
.field("type", &if self.is_leaf() { "leaf" } else { "internal" })
.field("is_root", &self.is_root())
.field("child_count", &self.child_count());
if let Some(parent) = &self.parent {
debug_struct.field("parent", parent);
}
if !self.children.is_empty() {
debug_struct.field("children", &self.children);
}
let bytes = &self.hash;
if bytes.len() > 8 {
debug_struct.field(
"hash",
&format!(
"{:02x?}{:02x?}...{:02x?}{:02x?}",
bytes[0],
bytes[1],
bytes[bytes.len() - 2],
bytes[bytes.len() - 1]
),
);
} else {
debug_struct.field("hash", &format!("{:02x?}", bytes));
}
debug_struct.finish()
}
}
impl<T, D: Digest, Ix: IndexType> Display for MrkleNode<T, D, Ix> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let hash_bytes = self.hash.as_slice();
let hash_preview = if hash_bytes.len() >= 4 {
format!(
"{:02x}{:02x}...{:02x}{:02x}",
hash_bytes[0],
hash_bytes[1],
hash_bytes[hash_bytes.len() - 2],
hash_bytes[hash_bytes.len() - 1]
)
} else {
format!("{:02x?}", hash_bytes)
};
write!(f, "{}", hash_preview)
}
}
#[cfg(feature = "serde")]
impl<T, D: Digest, Ix: IndexType> serde::Serialize for MrkleNode<T, D, Ix>
where
T: serde::Serialize,
Ix: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use serde::ser::SerializeStruct;
let mut state = serializer.serialize_struct("MrkleNode", 4)?;
state.serialize_field("hash", &self.hash[..])?;
state.serialize_field("parent", &self.parent)?;
state.serialize_field("children", &self.children)?;
state.serialize_field("payload", &self.payload)?;
state.end()
}
}
#[cfg(feature = "serde")]
impl<'de, T, D: Digest, Ix: IndexType> serde::Deserialize<'de> for MrkleNode<T, D, Ix>
where
T: serde::Deserialize<'de>,
Ix: serde::Deserialize<'de>,
{
fn deserialize<_D>(deserializer: _D) -> Result<Self, _D::Error>
where
_D: serde::Deserializer<'de>,
{
#[derive(serde::Deserialize)]
#[serde(field_identifier, rename_all = "lowercase")]
enum Field {
Payload,
Parent,
Children,
Hash,
}
struct MrkleNodeVisitor<T, D: Digest, Ix: IndexType> {
marker: PhantomData<(T, D, Ix)>,
}
impl<'de, T, D: Digest, Ix: IndexType> serde::de::Visitor<'de> for MrkleNodeVisitor<T, D, Ix>
where
T: serde::Deserialize<'de>,
Ix: serde::Deserialize<'de>,
{
type Value = MrkleNode<T, D, Ix>;
fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
formatter.write_str("struct MrkleNode")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
let hash_layout: Vec<u8> = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(0, &self))?;
let parent: Option<NodeIndex<Ix>> = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(1, &self))?;
let children: Vec<NodeIndex<Ix>> = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(2, &self))?;
let payload: Payload<T> = seq
.next_element()?
.ok_or_else(|| serde::de::Error::invalid_length(3, &self))?;
let hash: GenericArray<D> =
crypto::digest::generic_array::GenericArray::clone_from_slice(&hash_layout);
Ok(MrkleNode {
payload,
parent,
children,
hash,
})
}
fn visit_map<V>(self, mut map: V) -> Result<MrkleNode<T, D, Ix>, V::Error>
where
V: serde::de::MapAccess<'de>,
{
let mut payload = None;
let mut parent = None;
let mut children = None;
let mut hash_bytes: Option<Vec<u8>> = None;
while let Some(key) = map.next_key()? {
match key {
Field::Payload => {
if payload.is_some() {
return Err(serde::de::Error::duplicate_field("payload"));
}
payload = Some(map.next_value()?);
}
Field::Parent => {
if parent.is_some() {
return Err(serde::de::Error::duplicate_field("parent"));
}
parent = Some(map.next_value()?);
}
Field::Children => {
if children.is_some() {
return Err(serde::de::Error::duplicate_field("children"));
}
children = Some(map.next_value()?);
}
Field::Hash => {
if hash_bytes.is_some() {
return Err(serde::de::Error::duplicate_field("hash"));
}
hash_bytes = Some(map.next_value()?);
}
}
}
let payload = payload.ok_or_else(|| serde::de::Error::missing_field("payload"))?;
let parent = parent.ok_or_else(|| serde::de::Error::missing_field("parent"))?;
let children =
children.ok_or_else(|| serde::de::Error::missing_field("children"))?;
let hash_bytes =
hash_bytes.ok_or_else(|| serde::de::Error::missing_field("hash"))?;
let hash: GenericArray<D> =
crypto::digest::generic_array::GenericArray::clone_from_slice(&hash_bytes);
Ok(MrkleNode {
payload,
parent,
children,
hash,
})
}
}
const FIELDS: &[&str] = &["hash", "parent", "children", "payload"];
deserializer.deserialize_struct(
"MrkleNode",
FIELDS,
MrkleNodeVisitor {
marker: PhantomData,
},
)
}
}
unsafe impl<T: Send, D: Digest, Ix: IndexType> Send for MrkleNode<T, D, Ix> {}
unsafe impl<T: Sync, D: Digest, Ix: IndexType> Sync for MrkleNode<T, D, Ix> {}
#[must_use]
pub struct MrkleTree<T, D: Digest, Ix: IndexType = DefaultIx> {
core: Tree<MrkleNode<T, D, Ix>, Ix>,
}
impl<T, D: Digest, Ix: IndexType> Default for MrkleTree<T, D, Ix> {
fn default() -> Self {
Self {
core: Tree::<_, Ix>::new(),
}
}
}
impl<T, D: Digest, Ix: IndexType> MrkleTree<T, D, Ix> {
pub(crate) fn new(tree: Tree<MrkleNode<T, D, Ix>, Ix>) -> Self {
Self { core: tree }
}
}
impl<T, D: Digest, Ix: IndexType> MrkleTree<T, D, Ix>
where
T: AsRef<[u8]> + Clone,
{
pub fn from_leaves(leaves: Vec<T>) -> Result<MrkleTree<T, D, Ix>, MrkleError> {
MrkleDefaultBuilder::build_from_data(leaves)
}
}
impl<T, D: Digest, Ix: IndexType> MrkleTree<T, D, Ix> {
pub fn root(&self) -> &MrkleNode<T, D, Ix> {
self.core.root()
}
pub fn root_hash(&self) -> &GenericArray<D> {
&self.core.root().hash
}
pub fn root_hex(&self) -> HexDisplay<'_> {
self.core.root().to_hex()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.core.is_empty()
}
#[inline]
pub fn len(&self) -> usize {
self.core.len()
}
#[inline]
pub fn capacity(&self) -> usize {
self.core.capacity()
}
#[inline]
pub fn get_children(&self, index: NodeIndex<Ix>) -> Vec<&MrkleNode<T, D, Ix>> {
self.get(index.index()).map_or(Vec::new(), |node| {
node.children()
.iter()
.map(|&idx| self.get(idx.index()).unwrap())
.collect()
})
}
#[inline]
pub fn get_children_indices(&self, index: NodeIndex<Ix>) -> Vec<NodeIndex<Ix>> {
self.get(index.index())
.map(|node| node.children())
.unwrap_or_default()
}
pub fn get<I>(&self, index: I) -> Option<&I::Output>
where
I: SliceIndex<[MrkleNode<T, D, Ix>]>,
{
self.core.get(index)
}
#[inline]
pub fn view(&self) -> TreeView<'_, MrkleNode<T, D, Ix>, Ix> {
self.core.view()
}
#[inline]
pub fn leaf_indices(&self) -> Vec<NodeIndex<Ix>> {
self.core.leaf_indices()
}
#[inline]
pub fn leaves(&self) -> Vec<&MrkleNode<T, D, Ix>> {
self.core.leaves()
}
pub fn find(&self, node: &MrkleNode<T, D, Ix>) -> Option<NodeIndex<Ix>> {
self.core.find(node)
}
#[inline]
pub fn subtree_view(
&self,
root: NodeIndex<Ix>,
) -> Option<TreeView<'_, MrkleNode<T, D, Ix>, Ix>> {
self.core.subtree_view(root)
}
pub fn iter(&self) -> Iter<'_, MrkleNode<T, D, Ix>, Ix> {
self.core.iter()
}
pub fn iter_idx(&self) -> IndexIter<'_, MrkleNode<T, D, Ix>, Ix> {
self.core.iter_idx()
}
pub fn generate_proof(&self, index: Vec<NodeIndex<Ix>>) -> MrkleProof<D>
where {
MrkleProof::generate_basic(self, &index).unwrap()
}
pub fn verify(proof: &MrkleProof<D>, data: Vec<T>) -> Result<bool, ProofError>
where
T: AsRef<[u8]>,
{
let leaves = data
.iter()
.map(|item| D::digest(item))
.collect::<Vec<GenericArray<D>>>();
proof.verify(leaves)
}
}
impl<T, D: Digest, Ix: IndexType> MrkleTree<T, D, Ix>
where
T: Eq + PartialEq,
{
pub fn subtree_from_node(
&self,
target: &MrkleNode<T, D, Ix>,
) -> Option<TreeView<'_, MrkleNode<T, D, Ix>, Ix>> {
self.core.subtree_from_node(target)
}
}
impl<'a, T, D: Digest, Ix: IndexType> IntoIterator for &'a MrkleTree<T, D, Ix> {
type IntoIter = Iter<'a, MrkleNode<T, D, Ix>, Ix>;
type Item = &'a MrkleNode<T, D, Ix>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<T, D: Digest, Ix: IndexType> From<Vec<T>> for MrkleTree<T, D, Ix>
where
T: AsRef<[u8]> + Clone,
{
fn from(value: Vec<T>) -> Self {
MrkleTree::from_leaves(value).unwrap()
}
}
impl<T, D: Digest, Ix: IndexType, const N: usize> From<&[T; N]> for MrkleTree<T, D, Ix>
where
T: AsRef<[u8]> + Clone,
{
fn from(value: &[T; N]) -> Self {
MrkleTree::from_leaves(value.to_vec()).unwrap()
}
}
impl<T, D: Digest, Ix: IndexType> From<VecDeque<T>> for MrkleTree<T, D, Ix>
where
T: AsRef<[u8]> + Clone,
{
fn from(value: VecDeque<T>) -> Self {
MrkleTree::from_leaves(value.into()).unwrap()
}
}
impl<T, D: Digest, Ix: IndexType> From<Box<[T]>> for MrkleTree<T, D, Ix>
where
T: AsRef<[u8]> + Clone,
{
fn from(value: Box<[T]>) -> Self {
MrkleTree::from_leaves(value.into_vec()).unwrap()
}
}
impl<T, D: Digest, Ix: IndexType> Display for MrkleTree<T, D, Ix> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.core)
}
}
impl<T, D: Digest, Ix: IndexType> Debug for MrkleTree<T, D, Ix> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", self.core)
}
}
impl<T, D: Digest, Ix: IndexType> PartialEq for MrkleTree<T, D, Ix> {
fn eq(&self, other: &Self) -> bool {
if self.root() != other.root() {
return false;
}
self.len() == other.len() && self.iter().eq(other.iter())
}
}
impl<T, D: Digest, Ix: IndexType> Eq for MrkleTree<T, D, Ix> {}
unsafe impl<T: Send, D: Digest, Ix: IndexType> Send for MrkleTree<T, D, Ix> {}
unsafe impl<T: Sync, D: Digest, Ix: IndexType> Sync for MrkleTree<T, D, Ix> {}
impl<T, D: Digest, Ix: IndexType> core::ops::Index<usize> for MrkleTree<T, D, Ix> {
type Output = MrkleNode<T, D, Ix>;
fn index(&self, index: usize) -> &Self::Output {
&self.core[index]
}
}
impl<T, D: Digest, Ix: IndexType> core::ops::Index<NodeIndex<Ix>> for MrkleTree<T, D, Ix> {
type Output = MrkleNode<T, D, Ix>;
fn index(&self, index: NodeIndex<Ix>) -> &Self::Output {
&self.core[index.index()]
}
}
#[cfg(feature = "serde")]
impl<T, D: Digest, Ix: IndexType> serde::Serialize for MrkleTree<T, D, Ix>
where
T: serde::Serialize,
Ix: serde::Serialize,
{
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
self.core.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T, D, Ix> serde::Deserialize<'de> for MrkleTree<T, D, Ix>
where
T: AsRef<[u8]> + serde::Deserialize<'de>,
D: Digest + Default,
Ix: IndexType + serde::Deserialize<'de>,
{
fn deserialize<De>(deserializer: De) -> Result<Self, De::Error>
where
De: serde::Deserializer<'de>,
{
let core = Tree::<MrkleNode<T, D, Ix>, Ix>::deserialize(deserializer)?;
for node in core.iter() {
let mut digest = D::new();
if node.is_leaf() {
let value = node.value().ok_or_else(|| {
serde::de::Error::custom("Leaf node missing value during deserialization")
})?;
digest.update(value.as_ref());
let computed = digest.finalize();
if computed.as_slice() != node.hash().as_slice() {
return Err(serde::de::Error::custom("Merkle tree leaf hash mismatch"));
}
} else {
if node.child_count() == 0 {
return Err(serde::de::Error::custom(
"Internal node should never have no children.",
));
}
for child in node.children() {
let child_node = core.get(child.index()).ok_or_else(|| {
serde::de::Error::custom("Missing child node during deserialization")
})?;
digest.update(child_node.hash());
}
let computed = digest.finalize();
if &computed != node.hash() {
return Err(serde::de::Error::custom(
"Merkle tree internal hash mismatch",
));
}
}
}
Ok(MrkleTree { core })
}
}
#[cfg(test)]
mod test {
use crate::{MrkleHasher, MrkleNode, MrkleTree, Node, prelude::*};
use sha1::Digest;
const DATA_PAYLOAD: [u8; 32] = [0u8; 32];
#[test]
fn test_merkle_tree_default_build() {
let tree: MrkleTree<[u8; 32], _> = MrkleTree::<[u8; 32], sha1::Sha1>::default();
assert!(tree.is_empty())
}
#[test]
fn test_default_mrkle_node() {
let node = MrkleNode::<_, sha1::Sha1, usize>::leaf(DATA_PAYLOAD);
let expected = sha1::Sha1::digest(DATA_PAYLOAD);
assert_eq!(node.hash, expected)
}
#[test]
fn test_build_with_mrkle() {
let hasher = MrkleHasher::<sha1::Sha1>::new();
let node = MrkleNode::<_, sha1::Sha1, usize>::leaf_with_hasher(DATA_PAYLOAD, &hasher);
assert_eq!(node.hash, sha1::Sha1::digest(DATA_PAYLOAD))
}
#[test]
fn test_building_binary_tree_base_case() {
let leaves: Vec<&str> = vec!["A"];
let tree = MrkleTree::<&str, sha1::Sha1>::from(leaves);
assert!(tree.len() == 2);
assert!(tree.leaves().len() == 1);
}
#[test]
fn test_building_binary_tree() {
let leaves: Vec<&str> = vec!["A", "B", "C", "D", "E"];
let tree = MrkleTree::<&str, sha1::Sha1>::from(leaves.clone());
assert_eq!(tree.len(), 11);
for node in &tree {
if node.is_leaf() {
if let Some(value) = node.value() {
assert!(leaves.contains(value));
} else {
panic!("Failed Test.")
}
}
}
}
#[test]
#[cfg(feature = "std")]
fn test_building_binary_tree_display() {
let leaves: Vec<&str> = vec!["A", "B", "C", "D", "E"];
let tree = MrkleTree::<&str, sha1::Sha1>::from(leaves.clone());
println!("{tree}");
}
#[test]
#[allow(clippy::clone_on_copy)]
fn test_building_binary_tree_proof() {
let leaves: Vec<&str> = vec!["A", "B", "C", "D", "E"];
let tree = MrkleTree::<&str, sha1::Sha1>::from(leaves.clone());
let proof = tree.generate_proof(vec![0.into()]);
let result = MrkleTree::<&str, sha1::Sha1>::verify(&proof, vec!["A"]);
assert!(result.is_ok());
assert!(result.unwrap());
}
#[cfg(feature = "serde")]
#[test]
fn test_mrkle_node_serde() {
let expected = MrkleNode::<[u8; 32], sha1::Sha1>::leaf(DATA_PAYLOAD);
let output = bincode::serde::encode_to_vec(&expected, bincode::config::standard()).unwrap();
let (node, _): (MrkleNode<[u8; 32], sha1::Sha1>, usize) =
bincode::serde::decode_from_slice(&output[..], bincode::config::standard()).unwrap();
assert_eq!(node, expected)
}
#[test]
#[allow(clippy::clone_on_copy)]
#[cfg(feature = "serde")]
fn test_building_binary_tree_serde() {
let nodes: Vec<&str> = Vec::from(["a", "b", "c", "d", "e", "f"]);
let expected = MrkleTree::<String, sha1::Sha1>::from(
nodes
.iter()
.map(|&node| String::from(node))
.collect::<Vec<String>>(),
);
let buffer = bincode::serde::encode_to_vec(&expected, bincode::config::standard()).unwrap();
let (tree, _): (MrkleTree<String, sha1::Sha1>, usize) =
bincode::serde::decode_from_slice(&buffer[..], bincode::config::standard()).unwrap();
assert_eq!(expected, tree);
}
}