use crate::{
errors::MerkleError,
traits::{MerkleParameters, CRH},
};
use snarkvm_utilities::{FromBytes, ToBytes};
use std::{
io::{Read, Result as IoResult, Write},
sync::Arc,
};
pub type MerkleTreeDigest<P> = <<P as MerkleParameters>::H as CRH>::Output;
#[derive(Clone, Debug)]
pub struct MerklePath<P: MerkleParameters> {
pub parameters: Arc<P>,
pub path: Vec<MerkleTreeDigest<P>>,
pub leaf_index: u64,
}
impl<P: MerkleParameters> MerklePath<P> {
pub fn verify<L: ToBytes>(&self, root_hash: &MerkleTreeDigest<P>, leaf: &L) -> Result<bool, MerkleError> {
if !self.path.is_empty() {
let claimed_leaf_hash = self.parameters.hash_leaf::<L>(leaf)?;
let mut index = self.leaf_index;
let mut curr_path_node = claimed_leaf_hash;
for level in 0..self.path.len() {
let (left_bytes, right_bytes) =
Self::select_left_right_bytes(index, &curr_path_node, &self.path[level])?;
curr_path_node = self.parameters.hash_inner_node(&left_bytes, &right_bytes)?;
index >>= 1;
}
if &curr_path_node != root_hash {
return Ok(false);
}
Ok(true)
} else {
Ok(false)
}
}
fn select_left_right_bytes(
index: u64,
computed_hash: &<P::H as CRH>::Output,
sibling_hash: &<P::H as CRH>::Output,
) -> Result<(<P::H as CRH>::Output, <P::H as CRH>::Output), MerkleError> {
let is_left = index & 1 == 0;
let mut left_bytes = computed_hash;
let mut right_bytes = sibling_hash;
if !is_left {
core::mem::swap(&mut left_bytes, &mut right_bytes);
}
Ok((*left_bytes, *right_bytes))
}
pub fn position_list(&self) -> impl Iterator<Item = bool> + '_ {
(0..self.path.len()).map(move |i| ((self.leaf_index >> i) & 1) != 0)
}
}
impl<P: MerkleParameters> FromBytes for MerklePath<P> {
#[inline]
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
let parameters = {
let setup_message_length: u64 = FromBytes::read_le(&mut reader)?;
let mut setup_message_bytes = vec![0u8; setup_message_length as usize];
reader.read_exact(&mut setup_message_bytes)?;
let setup_message =
String::from_utf8(setup_message_bytes).expect("Failed to parse setup message for Merkle parameters");
Arc::new(P::setup(&setup_message))
};
let path_length: u64 = FromBytes::read_le(&mut reader)?;
let mut path = Vec::with_capacity(path_length as usize);
for _ in 0..path_length {
path.push(FromBytes::read_le(&mut reader)?);
}
let leaf_index: u64 = FromBytes::read_le(&mut reader)?;
Ok(Self {
parameters,
path,
leaf_index,
})
}
}
impl<P: MerkleParameters> ToBytes for MerklePath<P> {
#[inline]
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
let setup_message_bytes: &[u8] = self.parameters.setup_message().as_bytes();
let setup_message_length: u64 = setup_message_bytes.len() as u64;
setup_message_length.write_le(&mut writer)?;
setup_message_bytes.write_le(&mut writer)?;
(self.path.len() as u64).write_le(&mut writer)?;
self.path.write_le(&mut writer)?;
self.leaf_index.write_le(&mut writer)
}
}
impl<P: MerkleParameters> Default for MerklePath<P> {
fn default() -> Self {
let mut path = Vec::with_capacity(P::DEPTH);
for _i in 0..P::DEPTH {
path.push(MerkleTreeDigest::<P>::default());
}
Self {
parameters: Arc::new(P::setup("unsafe")),
path,
leaf_index: 0,
}
}
}