snarkvm_console_collections/kary_merkle_tree/path/
mod.rsuse super::*;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct KaryMerklePath<PH: PathHash, const DEPTH: u8, const ARITY: u8> {
leaf_index: u64,
siblings: Vec<Vec<PH::Hash>>,
}
impl<PH: PathHash, const DEPTH: u8, const ARITY: u8> KaryMerklePath<PH, DEPTH, ARITY> {
pub fn try_from((leaf_index, siblings): (u64, Vec<Vec<PH::Hash>>)) -> Result<Self> {
ensure!(DEPTH > 0, "Merkle tree depth must be greater than 0");
ensure!(DEPTH <= 64u8, "Merkle tree depth must be less than or equal to 64");
ensure!(ARITY > 1, "Merkle tree arity must be greater than 1");
ensure!((ARITY as u128).checked_pow(DEPTH as u32).is_some(), "Merkle tree size overflowed");
ensure!((leaf_index as u128) < (ARITY as u128).saturating_pow(DEPTH as u32), "Out of bounds Merkle leaf index");
ensure!(siblings.len() == DEPTH as usize, "Found an incorrect Merkle path length");
for sibling in &siblings {
ensure!(sibling.len() == (ARITY - 1) as usize, "Found an incorrect Merkle path arity");
}
Ok(Self { leaf_index, siblings })
}
}
impl<PH: PathHash, const DEPTH: u8, const ARITY: u8> KaryMerklePath<PH, DEPTH, ARITY> {
pub fn leaf_index(&self) -> u64 {
self.leaf_index
}
pub fn siblings(&self) -> &[Vec<PH::Hash>] {
&self.siblings
}
pub fn verify<LH: LeafHash<Hash = PH::Hash>>(
&self,
leaf_hasher: &LH,
path_hasher: &PH,
root: &PH::Hash,
leaf: &LH::Leaf,
) -> bool {
if (self.leaf_index as u128) >= (ARITY as u128).saturating_pow(DEPTH as u32) {
eprintln!("Found an out of bounds Merkle leaf index");
return false;
}
if self.siblings.len() != DEPTH as usize {
eprintln!("Found an incorrect Merkle path length");
return false;
}
let mut current_hash = match leaf_hasher.hash_leaf(leaf) {
Ok(candidate_leaf_hash) => candidate_leaf_hash,
Err(error) => {
eprintln!("Failed to hash the Merkle leaf during verification: {error}");
return false;
}
};
let Ok(indicator_indexes) = (0..DEPTH)
.map(|i| {
usize::try_from(self.leaf_index as u128 / (ARITY as u128).saturating_pow(i as u32) % (ARITY as u128))
})
.collect::<Result<Vec<_>, _>>()
else {
eprintln!("Found an incorrect Merkle leaf index");
return false;
};
for (indicator_index, sibling_hashes) in indicator_indexes.into_iter().zip_eq(&self.siblings) {
let mut sibling_hashes = sibling_hashes.clone();
sibling_hashes.insert(indicator_index, current_hash);
match path_hasher.hash_children(&sibling_hashes) {
Ok(hash) => current_hash = hash,
Err(error) => {
eprintln!("Failed to hash the Merkle path during verification: {error}");
return false;
}
}
}
current_hash == *root
}
}
impl<PH: PathHash, const DEPTH: u8, const ARITY: u8> FromBytes for KaryMerklePath<PH, DEPTH, ARITY> {
#[inline]
fn read_le<R: Read>(mut reader: R) -> IoResult<Self> {
let leaf_index = u64::read_le(&mut reader)?;
let siblings = (0..DEPTH)
.map(|_| (0..ARITY).map(|_| FromBytes::read_le(&mut reader)).collect::<IoResult<Vec<_>>>())
.collect::<IoResult<Vec<_>>>()?;
Self::try_from((leaf_index, siblings)).map_err(error)
}
}
impl<PH: PathHash, const DEPTH: u8, const ARITY: u8> ToBytes for KaryMerklePath<PH, DEPTH, ARITY> {
#[inline]
fn write_le<W: Write>(&self, mut writer: W) -> IoResult<()> {
self.leaf_index.write_le(&mut writer)?;
self.siblings
.iter()
.try_for_each(|siblings| siblings.iter().try_for_each(|sibling| sibling.write_le(&mut writer)))
}
}
impl<PH: PathHash, const DEPTH: u8, const ARITY: u8> Serialize for KaryMerklePath<PH, DEPTH, ARITY> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
ToBytesSerializer::serialize_with_size_encoding(self, serializer)
}
}
impl<'de, PH: PathHash, const DEPTH: u8, const ARITY: u8> Deserialize<'de> for KaryMerklePath<PH, DEPTH, ARITY> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
FromBytesDeserializer::<Self>::deserialize_with_size_encoding(deserializer, "K-ary Merkle path")
}
}