#[cfg(feature = "constraints")]
mod constraints;
mod test_utils;
mod bytes_mt_tests {
use crate::{crh::*, merkle_tree::*};
use ark_ed_on_bls12_381::EdwardsProjective as JubJub;
use ark_ff::BigInteger256;
use ark_std::{iter::zip, test_rng, UniformRand};
#[derive(Clone)]
pub(super) struct Window4x256;
impl pedersen::Window for Window4x256 {
const WINDOW_SIZE: usize = 4;
const NUM_WINDOWS: usize = 256;
}
type LeafH = pedersen::CRH<JubJub, Window4x256>;
type CompressH = pedersen::TwoToOneCRH<JubJub, Window4x256>;
struct JubJubMerkleTreeParams;
impl Config for JubJubMerkleTreeParams {
type Leaf = [u8];
type LeafDigest = <LeafH as CRHScheme>::Output;
type LeafInnerDigestConverter = ByteDigestConverter<Self::LeafDigest>;
type InnerDigest = <CompressH as TwoToOneCRHScheme>::Output;
type LeafHash = LeafH;
type TwoToOneHash = CompressH;
}
type JubJubMerkleTree = MerkleTree<JubJubMerkleTreeParams>;
fn merkle_tree_test<L: CanonicalSerialize>(leaves: &[L], update_query: &[(usize, L)]) -> () {
let mut rng = ark_std::test_rng();
let mut leaves: Vec<_> = leaves
.iter()
.map(|leaf| crate::to_uncompressed_bytes!(leaf).unwrap())
.collect();
let leaf_crh_params = <LeafH as CRHScheme>::setup(&mut rng).unwrap();
let two_to_one_params = <CompressH as TwoToOneCRHScheme>::setup(&mut rng).unwrap();
let mut tree =
JubJubMerkleTree::new(&leaf_crh_params, &two_to_one_params, &leaves).unwrap();
let mut root = tree.root();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i).unwrap();
assert!(proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaf.as_slice())
.unwrap());
}
let mut multi_proof = tree
.generate_multi_proof((0..leaves.len()).collect::<Vec<_>>())
.unwrap();
assert!(multi_proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaves.clone())
.unwrap());
for (i, v) in update_query {
let v = crate::to_uncompressed_bytes!(v).unwrap();
tree.update(*i, &v).unwrap();
leaves[*i] = v.clone();
}
root = tree.root();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i).unwrap();
assert!(proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaf.as_slice())
.unwrap());
}
multi_proof = tree
.generate_multi_proof((0..leaves.len()).collect::<Vec<_>>())
.unwrap();
assert!(multi_proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaves.clone())
.unwrap());
}
#[test]
fn good_root_test() {
let mut rng = test_rng();
let mut leaves = Vec::new();
for _ in 0..2u8 {
leaves.push(BigInteger256::rand(&mut rng));
}
merkle_tree_test(
&leaves,
&vec![
(0, BigInteger256::rand(&mut rng)),
(1, BigInteger256::rand(&mut rng)),
],
);
let mut leaves = Vec::new();
for _ in 0..4u8 {
leaves.push(BigInteger256::rand(&mut rng));
}
merkle_tree_test(&leaves, &vec![(3, BigInteger256::rand(&mut rng))]);
let mut leaves = Vec::new();
for _ in 0..128u8 {
leaves.push(BigInteger256::rand(&mut rng));
}
merkle_tree_test(
&leaves,
&vec![
(2, BigInteger256::rand(&mut rng)),
(3, BigInteger256::rand(&mut rng)),
(5, BigInteger256::rand(&mut rng)),
(111, BigInteger256::rand(&mut rng)),
(127, BigInteger256::rand(&mut rng)),
],
);
}
#[test]
fn multi_proof_dissection_test() {
let mut rng = test_rng();
let mut leaves = Vec::new();
for _ in 0..8u8 {
leaves.push(BigInteger256::rand(&mut rng));
}
assert_eq!(leaves.len(), 8);
let serialized_leaves: Vec<_> = leaves
.iter()
.map(|leaf| crate::to_uncompressed_bytes!(leaf).unwrap())
.collect();
let leaf_crh_params = <LeafH as CRHScheme>::setup(&mut rng).unwrap();
let two_to_one_params = <CompressH as TwoToOneCRHScheme>::setup(&mut rng).unwrap();
let tree = JubJubMerkleTree::new(&leaf_crh_params, &two_to_one_params, &serialized_leaves)
.unwrap();
let mut proofs = Vec::with_capacity(leaves.len());
for (i, _) in leaves.iter().enumerate() {
proofs.push(tree.generate_proof(i).unwrap());
}
let multi_proof = tree
.generate_multi_proof((0..leaves.len()).collect::<Vec<_>>())
.unwrap();
let theoretical_prefix_lengths = vec![0, 2, 1, 2, 0, 2, 1, 2];
for (comp_len, exp_len) in zip(
&multi_proof.auth_paths_prefix_lenghts,
&theoretical_prefix_lengths,
) {
assert_eq!(comp_len, exp_len);
}
for (prefix_len, suffix) in zip(
&multi_proof.auth_paths_prefix_lenghts,
&multi_proof.auth_paths_suffixes,
) {
assert_eq!(prefix_len + suffix.len(), proofs[0].auth_path.len());
}
}
}
mod field_mt_tests {
use crate::{
crh::poseidon,
merkle_tree::{
tests::test_utils::poseidon_parameters, Config, IdentityDigestConverter, MerkleTree,
},
};
use ark_std::{test_rng, One, UniformRand};
type F = ark_ed_on_bls12_381::Fr;
type H = poseidon::CRH<F>;
type TwoToOneH = poseidon::TwoToOneCRH<F>;
struct FieldMTConfig;
impl Config for FieldMTConfig {
type Leaf = [F];
type LeafDigest = F;
type LeafInnerDigestConverter = IdentityDigestConverter<F>;
type InnerDigest = F;
type LeafHash = H;
type TwoToOneHash = TwoToOneH;
}
type FieldMT = MerkleTree<FieldMTConfig>;
fn merkle_tree_test(leaves: &[Vec<F>], update_query: &[(usize, Vec<F>)]) -> () {
let mut leaves = leaves.to_vec();
let leaf_crh_params = poseidon_parameters();
let two_to_one_params = leaf_crh_params.clone();
let mut tree = FieldMT::new(&leaf_crh_params, &two_to_one_params, &leaves).unwrap();
let mut root = tree.root();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i).unwrap();
assert!(proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaf.as_slice())
.unwrap());
}
let mut multi_proof = tree
.generate_multi_proof((0..leaves.len()).collect::<Vec<_>>())
.unwrap();
assert!(multi_proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaves.clone())
.unwrap());
{
let wrong_root = root + F::one();
let proof = tree.generate_proof(0).unwrap();
assert!(!proof
.verify(
&leaf_crh_params,
&two_to_one_params,
&wrong_root,
leaves[0].as_slice()
)
.unwrap());
let multi_proof = tree
.generate_multi_proof((0..leaves.len()).collect::<Vec<_>>())
.unwrap();
assert!(!multi_proof
.verify(
&leaf_crh_params,
&two_to_one_params,
&wrong_root,
leaves.clone()
)
.unwrap());
}
for (i, v) in update_query {
tree.update(*i, v).unwrap();
leaves[*i] = v.to_vec();
}
root = tree.root();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i).unwrap();
assert!(proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaf.as_slice())
.unwrap());
}
multi_proof = tree
.generate_multi_proof((0..leaves.len()).collect::<Vec<_>>())
.unwrap();
assert!(multi_proof
.verify(&leaf_crh_params, &two_to_one_params, &root, leaves.clone())
.unwrap());
}
#[test]
fn good_root_test() {
let mut rng = test_rng();
let mut rand_leaves = || (0..3).map(|_| F::rand(&mut rng)).collect();
let mut leaves: Vec<Vec<_>> = Vec::new();
for _ in 0..128u8 {
leaves.push(rand_leaves())
}
merkle_tree_test(
&leaves,
&vec![
(2, rand_leaves()),
(3, rand_leaves()),
(5, rand_leaves()),
(111, rand_leaves()),
(127, rand_leaves()),
],
)
}
}
mod poseidon_config_tests {
use crate::merkle_tree::{
configs::PoseidonMerkleConfig, tests::test_utils::poseidon_parameters, MerkleTree,
};
use ark_std::{test_rng, UniformRand};
type F = ark_ed_on_bls12_381::Fr;
type MT = MerkleTree<PoseidonMerkleConfig<F>>;
#[test]
fn poseidon_merkle_config_prove_verify() {
let mut rng = test_rng();
let leaves: Vec<Vec<F>> = (0..8)
.map(|_| (0..3).map(|_| F::rand(&mut rng)).collect())
.collect();
let params = poseidon_parameters();
let tree = MT::new(¶ms, ¶ms, &leaves).unwrap();
let root = tree.root();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i).unwrap();
assert!(proof
.verify(¶ms, ¶ms, &root, leaf.as_slice())
.unwrap());
}
}
}
#[cfg(feature = "blake3")]
mod blake3_config_tests {
use crate::merkle_tree::{configs::Blake3MerkleConfig, MerkleTree};
use ark_std::{test_rng, UniformRand};
type F = ark_ed_on_bls12_381::Fr;
type MT = MerkleTree<Blake3MerkleConfig<F>>;
#[test]
fn blake3_merkle_config_prove_verify() {
let mut rng = test_rng();
let leaves: Vec<Vec<F>> = (0..8)
.map(|_| (0..3).map(|_| F::rand(&mut rng)).collect())
.collect();
let tree = MT::new(&(), &(), &leaves).unwrap();
let root = tree.root();
for (i, leaf) in leaves.iter().enumerate() {
let proof = tree.generate_proof(i).unwrap();
assert!(proof.verify(&(), &(), &root, leaf.as_slice()).unwrap());
}
}
}