use crate::{
crh::{PedersenCRH, PedersenCompressedCRH, PedersenSize},
define_merkle_tree_parameters,
merkle_tree::MerkleTree,
traits::{crh::CRH, merkle_tree::LoadableMerkleParameters},
};
use snarkvm_utilities::{to_bytes, ToBytes};
fn generate_merkle_tree<P: LoadableMerkleParameters, L: ToBytes + Clone + Eq>(
leaves: &[L],
parameters: &P,
) -> MerkleTree<P> {
let tree = MerkleTree::<P>::new(parameters.clone(), leaves.iter()).unwrap();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i, &leaf).unwrap();
assert_eq!(P::DEPTH, proof.path.len());
assert!(proof.verify(&tree.root(), &leaf).unwrap());
}
tree
}
fn bad_merkle_tree_verify<P: LoadableMerkleParameters, L: ToBytes + Clone + Eq>(leaves: &[L], parameters: &P) {
let tree = MerkleTree::<P>::new(parameters.clone(), leaves.iter()).unwrap();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i, &leaf).unwrap();
assert!(proof.verify(&<P::H as CRH>::Output::default(), &leaf).unwrap());
}
}
fn run_empty_merkle_tree_test<P: LoadableMerkleParameters>() {
let parameters = &P::default();
generate_merkle_tree::<P, Vec<u8>>(&[], parameters);
}
fn run_good_root_test<P: LoadableMerkleParameters>() {
let parameters = &P::default();
let mut leaves = vec![];
for i in 0..4u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
generate_merkle_tree::<P, _>(&leaves, parameters);
let mut leaves = vec![];
for i in 0..15u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
generate_merkle_tree::<P, _>(&leaves, parameters);
}
fn run_bad_root_test<P: LoadableMerkleParameters>() {
let parameters = &P::default();
let mut leaves = vec![];
for i in 0..4u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
generate_merkle_tree::<P, _>(&leaves, parameters);
let mut leaves = vec![];
for i in 0..15u8 {
leaves.push([i, i, i, i, i, i, i, i]);
}
bad_merkle_tree_verify::<P, _>(&leaves, parameters);
}
fn run_merkle_tree_matches_hashing_test<P: LoadableMerkleParameters>() {
let parameters = &P::default();
let mut leaves = Vec::new();
for i in 0..4u8 {
let input = [i; 64];
leaves.push(input.to_vec());
}
let merkle_tree = generate_merkle_tree(&leaves, parameters);
let merkle_tree_root = merkle_tree.root();
let pedersen = &P::crh(parameters);
let leaf1 = pedersen.hash(&leaves[0]).unwrap();
let leaf2 = pedersen.hash(&leaves[1]).unwrap();
let leaf3 = pedersen.hash(&leaves[2]).unwrap();
let leaf4 = pedersen.hash(&leaves[3]).unwrap();
let left = pedersen.hash(&to_bytes![leaf1, leaf2].unwrap()).unwrap();
let right = pedersen.hash(&to_bytes![leaf3, leaf4].unwrap()).unwrap();
let expected_root = pedersen.hash(&to_bytes![left, right].unwrap()).unwrap();
println!(
"merkle_root == expected_root\n\t{} == {}",
merkle_tree.root(),
expected_root
);
assert_eq!(merkle_tree_root, expected_root);
}
fn run_padded_merkle_tree_matches_hashing_test<P: LoadableMerkleParameters>() {
let parameters = &P::default();
let mut leaves = Vec::new();
for i in 0..4u8 {
let input = [i; 64];
leaves.push(input.to_vec());
}
let merkle_tree = generate_merkle_tree(&leaves, parameters);
let merkle_tree_root = merkle_tree.root();
let pedersen = &P::crh(parameters);
let leaf1 = pedersen.hash(&leaves[0]).unwrap();
let leaf2 = pedersen.hash(&leaves[1]).unwrap();
let leaf3 = pedersen.hash(&leaves[2]).unwrap();
let leaf4 = pedersen.hash(&leaves[3]).unwrap();
let left = pedersen.hash(&to_bytes![leaf1, leaf2].unwrap()).unwrap();
let right = pedersen.hash(&to_bytes![leaf3, leaf4].unwrap()).unwrap();
let penultimate_left = pedersen.hash(&to_bytes![left, right].unwrap()).unwrap();
let penultimate_right = parameters.hash_empty().unwrap();
let expected_root = pedersen
.hash(&to_bytes![penultimate_left, penultimate_right].unwrap())
.unwrap();
println!(
"merkle_root == expected_root\n\t{} == {}",
merkle_tree.root(),
expected_root
);
assert_eq!(merkle_tree_root, expected_root);
}
mod pedersen_crh_on_affine {
use super::*;
use snarkvm_curves::edwards_bls12::EdwardsAffine as Edwards;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Size;
impl PedersenSize for Size {
const NUM_WINDOWS: usize = 512;
const WINDOW_SIZE: usize = 4;
}
#[test]
fn empty_merkle_tree_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 32);
run_empty_merkle_tree_test::<MTParameters>();
}
#[test]
fn good_root_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 32);
run_good_root_test::<MTParameters>();
}
#[should_panic]
#[test]
fn bad_root_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 32);
run_bad_root_test::<MTParameters>();
}
#[test]
fn depth2_merkle_tree_matches_hashing_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 2);
run_merkle_tree_matches_hashing_test::<MTParameters>();
}
#[test]
fn depth3_padded_merkle_tree_matches_hashing_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 3);
run_padded_merkle_tree_matches_hashing_test::<MTParameters>();
}
}
mod pedersen_crh_on_projective {
use super::*;
use snarkvm_curves::edwards_bls12::EdwardsProjective as Edwards;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Size;
impl PedersenSize for Size {
const NUM_WINDOWS: usize = 512;
const WINDOW_SIZE: usize = 4;
}
#[test]
fn empty_merkle_tree_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 32);
run_empty_merkle_tree_test::<MTParameters>();
}
#[test]
fn good_root_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 32);
run_good_root_test::<MTParameters>();
}
#[should_panic]
#[test]
fn bad_root_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 32);
run_bad_root_test::<MTParameters>();
}
#[ignore]
#[test]
fn depth2_merkle_tree_matches_hashing_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 2);
run_merkle_tree_matches_hashing_test::<MTParameters>();
}
#[ignore]
#[test]
fn depth3_padded_merkle_tree_matches_hashing_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCRH<Edwards, Size>, 3);
run_padded_merkle_tree_matches_hashing_test::<MTParameters>();
}
}
mod pedersen_compressed_crh_on_projective {
use super::*;
use snarkvm_curves::edwards_bls12::EdwardsProjective as Edwards;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Size;
impl PedersenSize for Size {
const NUM_WINDOWS: usize = 512;
const WINDOW_SIZE: usize = 4;
}
#[test]
fn empty_merkle_tree_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCompressedCRH<Edwards, Size>, 32);
run_empty_merkle_tree_test::<MTParameters>();
}
#[test]
fn good_root_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCompressedCRH<Edwards, Size>, 32);
run_good_root_test::<MTParameters>();
}
#[should_panic]
#[test]
fn bad_root_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCompressedCRH<Edwards, Size>, 32);
run_bad_root_test::<MTParameters>();
}
#[test]
fn depth2_merkle_tree_matches_hashing_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCompressedCRH<Edwards, Size>, 2);
run_merkle_tree_matches_hashing_test::<MTParameters>();
}
#[test]
fn depth3_padded_merkle_tree_matches_hashing_test() {
define_merkle_tree_parameters!(MTParameters, PedersenCompressedCRH<Edwards, Size>, 3);
run_padded_merkle_tree_matches_hashing_test::<MTParameters>();
}
}