snarkvm_circuit_collections/kary_merkle_tree/helpers/
leaf_hash.rsuse super::*;
use snarkvm_circuit_algorithms::{BHP, Hash, Keccak, Poseidon};
pub trait LeafHash {
type Hash: Default + Inject + Eject + Ternary;
type Leaf;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Self::Hash;
}
impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> LeafHash for BHP<E, NUM_WINDOWS, WINDOW_SIZE> {
type Hash = Field<E>;
type Leaf = Vec<Boolean<E>>;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Self::Hash {
let mut input = Vec::with_capacity(1 + leaf.len());
input.push(Boolean::constant(false));
input.extend_from_slice(leaf);
Hash::hash(self, &input)
}
}
impl<E: Environment, const RATE: usize> LeafHash for Poseidon<E, RATE> {
type Hash = Field<E>;
type Leaf = Vec<Field<E>>;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Self::Hash {
let mut input = Vec::with_capacity(1 + leaf.len());
input.push(Self::Hash::zero());
input.extend_from_slice(leaf);
Hash::hash(self, &input)
}
}
impl<E: Environment, const TYPE: u8, const VARIANT: usize> LeafHash for Keccak<E, TYPE, VARIANT> {
type Hash = BooleanHash<E, VARIANT>;
type Leaf = Vec<Boolean<E>>;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Self::Hash {
let mut input = Vec::with_capacity(1 + leaf.len());
input.push(Boolean::constant(false));
input.extend_from_slice(leaf);
let output = Hash::hash(self, &input);
let mut result = BooleanHash::default();
result.0.clone_from_slice(&output[..VARIANT]);
result
}
}
#[cfg(all(test, feature = "console"))]
mod tests {
use super::*;
use snarkvm_circuit_algorithms::{BHP1024, Keccak256, Poseidon4, Sha3_256};
use snarkvm_circuit_types::environment::Circuit;
use snarkvm_utilities::{TestRng, Uniform};
use anyhow::Result;
const ITERATIONS: u64 = 10;
const DOMAIN: &str = "MerkleTreeCircuit0";
macro_rules! check_hash_leaf {
($native:ident, $circuit:ident, $mode:ident, $num_inputs:expr, ($num_constants:expr, $num_public:expr, $num_private:expr, $num_constraints:expr)) => {{
let mut rng = TestRng::default();
for i in 0..ITERATIONS {
let input = (0..$num_inputs).map(|_| Uniform::rand(&mut rng)).collect::<Vec<_>>();
let expected = console::kary_merkle_tree::LeafHash::hash_leaf(&$native, &input)?;
let circuit_input: Vec<_> = Inject::new(Mode::$mode, input);
Circuit::scope(format!("LeafHash {i}"), || {
let candidate = $circuit.hash_leaf(&circuit_input);
assert_scope!($num_constants, $num_public, $num_private, $num_constraints);
assert_eq!(expected, candidate.eject_value());
});
Circuit::reset();
}
Ok::<_, anyhow::Error>(())
}};
($hash:ident, $mode:ident, $num_inputs:expr, ($num_constants:expr, $num_public:expr, $num_private:expr, $num_constraints:expr)) => {{
let native = snarkvm_console_algorithms::$hash::<<Circuit as Environment>::Network>::setup(DOMAIN)?;
let circuit = $hash::<Circuit>::constant(native.clone());
check_hash_leaf!(
native,
circuit,
$mode,
$num_inputs,
($num_constants, $num_public, $num_private, $num_constraints)
)
}};
}
#[test]
fn test_hash_leaf_bhp1024_constant() -> Result<()> {
check_hash_leaf!(BHP1024, Constant, 1024, (1791, 0, 0, 0))
}
#[test]
fn test_hash_leaf_bhp1024_public() -> Result<()> {
check_hash_leaf!(BHP1024, Public, 1024, (413, 0, 1744, 1744))
}
#[test]
fn test_hash_leaf_bhp1024_private() -> Result<()> {
check_hash_leaf!(BHP1024, Private, 1024, (413, 0, 1744, 1744))
}
#[test]
fn test_hash_leaf_poseidon4_constant() -> Result<()> {
check_hash_leaf!(Poseidon4, Constant, 4, (1, 0, 0, 0))
}
#[test]
fn test_hash_leaf_poseidon4_public() -> Result<()> {
check_hash_leaf!(Poseidon4, Public, 4, (1, 0, 700, 700))
}
#[test]
fn test_hash_leaf_poseidon4_private() -> Result<()> {
check_hash_leaf!(Poseidon4, Private, 4, (1, 0, 700, 700))
}
#[test]
fn test_hash_leaf_keccak256_constant() -> Result<()> {
let native = snarkvm_console_algorithms::Keccak256 {};
let circuit = Keccak256::<Circuit>::new();
check_hash_leaf!(native, circuit, Constant, 1024, (256, 0, 0, 0))
}
#[test]
fn test_hash_leaf_keccak256_public() -> Result<()> {
let native = snarkvm_console_algorithms::Keccak256 {};
let circuit = Keccak256::<Circuit>::new();
check_hash_leaf!(native, circuit, Public, 1024, (256, 0, 152448, 152448))
}
#[test]
fn test_hash_leaf_keccak256_private() -> Result<()> {
let native = snarkvm_console_algorithms::Keccak256 {};
let circuit = Keccak256::<Circuit>::new();
check_hash_leaf!(native, circuit, Private, 1024, (256, 0, 152448, 152448))
}
#[test]
fn test_hash_leaf_sha3_256_constant() -> Result<()> {
let native = snarkvm_console_algorithms::Sha3_256 {};
let circuit = Sha3_256::<Circuit>::new();
check_hash_leaf!(native, circuit, Constant, 1024, (256, 0, 0, 0))
}
#[test]
fn test_hash_leaf_sha3_256_public() -> Result<()> {
let native = snarkvm_console_algorithms::Sha3_256 {};
let circuit = Sha3_256::<Circuit>::new();
check_hash_leaf!(native, circuit, Public, 1024, (256, 0, 152448, 152448))
}
#[test]
fn test_hash_leaf_sha3_256_private() -> Result<()> {
let native = snarkvm_console_algorithms::Sha3_256 {};
let circuit = Sha3_256::<Circuit>::new();
check_hash_leaf!(native, circuit, Private, 1024, (256, 0, 152448, 152448))
}
}