use crate::hash::Algorithm;
use crate::proof::Proof;
use anyhow::Result;
use std::marker::PhantomData;
use typenum::marker_traits::Unsigned;
#[cfg(test)]
use crate::compound_merkle::CompoundMerkleTree;
#[cfg(test)]
use crate::hash::Hashable;
#[cfg(test)]
use crate::store::VecStore;
#[cfg(test)]
use crate::test_common::{get_vec_tree_from_slice, Item, XOR128};
#[cfg(test)]
use typenum::{U3, U4, U8};
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct CompoundMerkleProof<T: Eq + Clone + AsRef<[u8]>, U: Unsigned, N: Unsigned> {
sub_tree_proof: Proof<T, U>,
lemma: Vec<T>, path: Vec<usize>, _n: PhantomData<N>,
}
impl<T: Eq + Clone + AsRef<[u8]>, U: Unsigned, N: Unsigned> CompoundMerkleProof<T, U, N> {
pub fn new(
sub_tree_proof: Proof<T, U>,
lemma: Vec<T>,
path: Vec<usize>,
) -> Result<CompoundMerkleProof<T, U, N>> {
ensure!(lemma.len() == N::to_usize(), "Invalid lemma length");
Ok(CompoundMerkleProof {
sub_tree_proof,
lemma,
path,
_n: PhantomData,
})
}
pub fn sub_tree_root(&self) -> T {
self.sub_tree_proof.root()
}
pub fn root(&self) -> T {
self.lemma.last().unwrap().clone()
}
pub fn validate<A: Algorithm<T>>(&self) -> bool {
if !self.sub_tree_proof.validate::<A>() {
return false;
}
let top_layer_nodes = N::to_usize();
if self.lemma.len() != top_layer_nodes {
return false;
}
let mut a = A::default();
a.reset();
let h = {
let mut nodes: Vec<T> = Vec::with_capacity(top_layer_nodes);
let mut cur_index = 0;
for j in 0..top_layer_nodes {
if j == self.path[0] {
nodes.push(self.sub_tree_root().clone());
} else {
nodes.push(self.lemma[cur_index].clone());
cur_index += 1;
}
}
if cur_index != top_layer_nodes - 1 {
return false;
}
a.multi_node(&nodes, 0)
};
h == self.root()
}
pub fn path(&self) -> &Vec<usize> {
&self.path
}
pub fn lemma(&self) -> &Vec<T> {
&self.lemma
}
}
#[cfg(test)]
fn modify_proof<U: Unsigned, N: Unsigned>(proof: &mut CompoundMerkleProof<Item, U, N>) {
use rand::prelude::*;
let i = random::<usize>() % proof.lemma.len();
let j = random::<usize>();
let mut a = XOR128::new();
j.hash(&mut a);
proof.lemma[i].hash(&mut a);
proof.lemma[i] = a.hash();
}
#[test]
fn test_compound_quad_broken_proofs() {
let leafs = 16384;
let mt1 = get_vec_tree_from_slice::<U4>(leafs);
let mt2 = get_vec_tree_from_slice::<U4>(leafs);
let mt3 = get_vec_tree_from_slice::<U4>(leafs);
let tree: CompoundMerkleTree<Item, XOR128, VecStore<_>, U4, U3> =
CompoundMerkleTree::from_trees(vec![mt1, mt2, mt3]).expect("Failed to build compound tree");
for i in 0..tree.leafs() {
let mut p = tree.gen_proof(i).unwrap();
assert!(p.validate::<XOR128>());
modify_proof(&mut p);
assert!(!p.validate::<XOR128>());
}
}
#[test]
fn test_compound_octree_broken_proofs() {
let leafs = 32768;
let mt1 = get_vec_tree_from_slice::<U8>(leafs);
let mt2 = get_vec_tree_from_slice::<U8>(leafs);
let mt3 = get_vec_tree_from_slice::<U8>(leafs);
let mt4 = get_vec_tree_from_slice::<U8>(leafs);
let tree: CompoundMerkleTree<Item, XOR128, VecStore<_>, U8, U4> =
CompoundMerkleTree::from_trees(vec![mt1, mt2, mt3, mt4])
.expect("Failed to build compound tree");
for i in 0..tree.leafs() {
let mut p = tree.gen_proof(i).unwrap();
assert!(p.validate::<XOR128>());
modify_proof(&mut p);
assert!(!p.validate::<XOR128>());
}
}