mod helpers;
use helpers::{LeafHash, PathHash};
mod verify;
#[cfg(all(test, console))]
use snarkvm_circuit_types::environment::assert_scope;
use snarkvm_circuit_types::{environment::prelude::*, Boolean, Field, U64};
pub struct MerklePath<E: Environment, const DEPTH: u8> {
leaf_index: U64<E>,
siblings: Vec<Field<E>>,
}
#[cfg(console)]
impl<E: Environment, const DEPTH: u8> Inject for MerklePath<E, DEPTH> {
type Primitive = console::merkle_tree::MerklePath<E::Network, DEPTH>;
fn new(mode: Mode, merkle_path: Self::Primitive) -> Self {
let leaf_index = U64::new(mode, merkle_path.leaf_index());
let siblings: Vec<_> = merkle_path.siblings().iter().map(|node| Field::new(mode, *node)).collect();
match siblings.len() == DEPTH as usize {
true => Self { leaf_index, siblings },
false => E::halt("Merkle path is not the correct depth"),
}
}
}
#[cfg(console)]
impl<E: Environment, const DEPTH: u8> Eject for MerklePath<E, DEPTH> {
type Primitive = console::merkle_tree::MerklePath<E::Network, DEPTH>;
fn eject_mode(&self) -> Mode {
(&self.leaf_index, &self.siblings).eject_mode()
}
fn eject_value(&self) -> Self::Primitive {
match Self::Primitive::try_from((&self.leaf_index, &self.siblings).eject_value()) {
Ok(merkle_path) => merkle_path,
Err(error) => E::halt(format!("Failed to eject the Merkle path: {error}")),
}
}
}
#[cfg(all(test, console))]
mod tests {
use super::*;
use snarkvm_circuit_network::AleoV0 as Circuit;
use snarkvm_utilities::{TestRng, Uniform};
use anyhow::Result;
const ITERATIONS: u128 = 100;
fn check_new<const DEPTH: u8>(
mode: Mode,
num_constants: u64,
num_public: u64,
num_private: u64,
num_constraints: u64,
) -> Result<()> {
let mut rng = TestRng::default();
let mut create_leaves = |num_leaves| {
(0..num_leaves)
.map(|_| console::Field::<<Circuit as Environment>::Network>::rand(&mut rng).to_bits_le())
.collect::<Vec<_>>()
};
for i in 0..ITERATIONS {
let num_leaves = core::cmp::min(2u128.pow(DEPTH as u32), i);
let leaves = create_leaves(num_leaves);
let merkle_tree = <<Circuit as Environment>::Network as snarkvm_console_network::Network>::merkle_tree_bhp::<
DEPTH,
>(&leaves)?;
for (index, leaf) in leaves.iter().enumerate() {
let merkle_path = merkle_tree.prove(index, leaf)?;
Circuit::scope(format!("New {mode}"), || {
let candidate = MerklePath::<Circuit, DEPTH>::new(mode, merkle_path.clone());
assert_eq!(merkle_path, candidate.eject_value());
assert_scope!(num_constants, num_public, num_private, num_constraints);
});
Circuit::reset();
}
}
Ok(())
}
#[test]
fn test_new_constant() -> Result<()> {
check_new::<32>(Mode::Constant, 96, 0, 0, 0)
}
#[test]
fn test_new_public() -> Result<()> {
check_new::<32>(Mode::Public, 0, 96, 0, 64)
}
#[test]
fn test_new_private() -> Result<()> {
check_new::<32>(Mode::Private, 0, 0, 96, 64)
}
}