use super::*;
use snarkvm_console_algorithms::{BHP512, BHP1024, Poseidon};
use snarkvm_console_types::prelude::Console;
type CurrentEnvironment = Console;
const ITERATIONS: u128 = 10;
fn check_merkle_tree<E: Environment, LH: LeafHash<Hash = PH::Hash>, PH: PathHash<Hash = Field<E>>, const DEPTH: u8>(
leaf_hasher: &LH,
path_hasher: &PH,
leaves: &[LH::Leaf],
additional_leaves: &[LH::Leaf],
) -> Result<()> {
let merkle_tree = MerkleTree::<E, LH, PH, DEPTH>::new(leaf_hasher, path_hasher, leaves)?;
assert_eq!(leaves.len(), merkle_tree.number_of_leaves);
let mut new_merkle_tree = merkle_tree.prepare_append(additional_leaves)?;
assert_eq!(leaves.len() + additional_leaves.len(), new_merkle_tree.number_of_leaves);
if !additional_leaves.is_empty() {
new_merkle_tree.remove_last_n(additional_leaves.len())?;
}
assert_eq!(new_merkle_tree.number_of_leaves, merkle_tree.number_of_leaves);
assert_eq!(new_merkle_tree.root(), merkle_tree.root());
assert_eq!(new_merkle_tree.tree(), merkle_tree.tree());
if !leaves.is_empty() {
for (leaf_index, leaf) in leaves.iter().enumerate() {
let proof = merkle_tree.prove(leaf_index, leaf)?;
let new_proof = new_merkle_tree.prove(leaf_index, leaf)?;
assert_eq!(proof, new_proof);
}
}
Ok(())
}
#[test]
fn test_merkle_tree_bhp_remove() -> Result<()> {
fn run_test<const DEPTH: u8>(rng: &mut TestRng) -> Result<()> {
type LH = BHP1024<CurrentEnvironment>;
type PH = BHP512<CurrentEnvironment>;
let leaf_hasher = LH::setup("AleoMerkleTreeTest0")?;
let path_hasher = PH::setup("AleoMerkleTreeTest1")?;
for i in 0..ITERATIONS {
for j in 0..ITERATIONS {
let num_leaves = core::cmp::min(2u128.pow(DEPTH as u32), i);
let num_additional_leaves = core::cmp::min(2u128.pow(DEPTH as u32) - num_leaves, j);
check_merkle_tree::<CurrentEnvironment, LH, PH, DEPTH>(
&leaf_hasher,
&path_hasher,
&(0..num_leaves)
.map(|_| Field::<CurrentEnvironment>::rand(rng).to_bits_le())
.collect::<Vec<Vec<bool>>>(),
&(0..num_additional_leaves)
.map(|_| Field::<CurrentEnvironment>::rand(rng).to_bits_le())
.collect::<Vec<Vec<bool>>>(),
)?;
}
}
for i in 1..ITERATIONS {
if i >= DEPTH as u128 {
continue;
}
let limit_depth = core::cmp::min(DEPTH, 16).saturating_sub(u8::try_from(i)?);
let num_leaves = core::cmp::min(2u128.pow(DEPTH as u32), 2u128.pow(limit_depth as u32));
let next_power_of_two = (0..i).fold(num_leaves, |acc, _| acc.next_power_of_two());
let num_additional_leaves = core::cmp::min(2u128.pow(DEPTH as u32) - num_leaves, next_power_of_two);
check_merkle_tree::<CurrentEnvironment, LH, PH, DEPTH>(
&leaf_hasher,
&path_hasher,
&(0..num_leaves)
.map(|_| Field::<CurrentEnvironment>::rand(rng).to_bits_le())
.collect::<Vec<Vec<bool>>>(),
&(0..num_additional_leaves)
.map(|_| Field::<CurrentEnvironment>::rand(rng).to_bits_le())
.collect::<Vec<Vec<bool>>>(),
)?;
}
Ok(())
}
let mut rng = TestRng::default();
assert!(run_test::<0>(&mut rng).is_err());
assert!(run_test::<1>(&mut rng).is_ok());
assert!(run_test::<2>(&mut rng).is_ok());
assert!(run_test::<3>(&mut rng).is_ok());
assert!(run_test::<4>(&mut rng).is_ok());
assert!(run_test::<5>(&mut rng).is_ok());
assert!(run_test::<6>(&mut rng).is_ok());
assert!(run_test::<7>(&mut rng).is_ok());
assert!(run_test::<8>(&mut rng).is_ok());
assert!(run_test::<9>(&mut rng).is_ok());
assert!(run_test::<10>(&mut rng).is_ok());
assert!(run_test::<15>(&mut rng).is_ok());
assert!(run_test::<16>(&mut rng).is_ok());
assert!(run_test::<17>(&mut rng).is_ok());
assert!(run_test::<31>(&mut rng).is_ok());
assert!(run_test::<32>(&mut rng).is_ok());
assert!(run_test::<64>(&mut rng).is_ok());
Ok(())
}
#[test]
fn test_merkle_tree_poseidon_remove() -> Result<()> {
fn run_test<const DEPTH: u8>(rng: &mut TestRng) -> Result<()> {
type LH = Poseidon<CurrentEnvironment, 4>;
type PH = Poseidon<CurrentEnvironment, 2>;
let leaf_hasher = LH::setup("AleoMerkleTreeTest0")?;
let path_hasher = PH::setup("AleoMerkleTreeTest1")?;
for i in 0..ITERATIONS {
for j in 0..ITERATIONS {
let num_leaves = core::cmp::min(2u128.pow(DEPTH as u32), i);
let num_additional_leaves = core::cmp::min(2u128.pow(DEPTH as u32) - num_leaves, j);
check_merkle_tree::<CurrentEnvironment, LH, PH, DEPTH>(
&leaf_hasher,
&path_hasher,
&(0..num_leaves).map(|_| vec![Uniform::rand(rng)]).collect::<Vec<_>>(),
&(0..num_additional_leaves).map(|_| vec![Uniform::rand(rng)]).collect::<Vec<_>>(),
)?;
}
}
for i in 1..ITERATIONS {
if i >= DEPTH as u128 {
continue;
}
let limit_depth = core::cmp::min(DEPTH, 16).saturating_sub(u8::try_from(i)?);
let num_leaves = core::cmp::min(2u128.pow(DEPTH as u32), 2u128.pow(limit_depth as u32));
let next_power_of_two = (0..i).fold(num_leaves, |acc, _| acc.next_power_of_two());
let num_additional_leaves = core::cmp::min(2u128.pow(DEPTH as u32) - num_leaves, next_power_of_two);
check_merkle_tree::<CurrentEnvironment, LH, PH, DEPTH>(
&leaf_hasher,
&path_hasher,
&(0..num_leaves).map(|_| vec![Uniform::rand(rng)]).collect::<Vec<_>>(),
&(0..num_additional_leaves).map(|_| vec![Uniform::rand(rng)]).collect::<Vec<_>>(),
)?;
}
Ok(())
}
let mut rng = TestRng::default();
assert!(run_test::<0>(&mut rng).is_err());
assert!(run_test::<1>(&mut rng).is_ok());
assert!(run_test::<2>(&mut rng).is_ok());
assert!(run_test::<3>(&mut rng).is_ok());
assert!(run_test::<4>(&mut rng).is_ok());
assert!(run_test::<5>(&mut rng).is_ok());
assert!(run_test::<6>(&mut rng).is_ok());
assert!(run_test::<7>(&mut rng).is_ok());
assert!(run_test::<8>(&mut rng).is_ok());
assert!(run_test::<9>(&mut rng).is_ok());
assert!(run_test::<10>(&mut rng).is_ok());
assert!(run_test::<15>(&mut rng).is_ok());
assert!(run_test::<16>(&mut rng).is_ok());
assert!(run_test::<17>(&mut rng).is_ok());
assert!(run_test::<31>(&mut rng).is_ok());
assert!(run_test::<32>(&mut rng).is_ok());
assert!(run_test::<64>(&mut rng).is_ok());
Ok(())
}