use snarkvm_console_algorithms::{Keccak, Poseidon, BHP};
use snarkvm_console_types::prelude::*;
use crate::kary_merkle_tree::BooleanHash;
#[cfg(not(feature = "serial"))]
use rayon::prelude::*;
pub trait LeafHash: Clone + Send + Sync {
type Hash: Copy + Clone + Debug + Default + PartialEq + Eq + FromBytes + ToBytes + Send + Sync;
type Leaf: Clone + Send + Sync;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Result<Self::Hash>;
fn hash_leaves(&self, leaves: &[Self::Leaf]) -> Result<Vec<Self::Hash>> {
match leaves.len() {
0 => Ok(vec![]),
1..=100 => leaves.iter().map(|leaf| self.hash_leaf(leaf)).collect(),
_ => cfg_iter!(leaves).map(|leaf| self.hash_leaf(leaf)).collect(),
}
}
}
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<bool>;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Result<Self::Hash> {
let mut input = Vec::with_capacity(1 + leaf.len());
input.push(false);
input.extend(leaf);
Hash::hash(self, &input)
}
}
impl<E: Environment, const RATE: usize> LeafHash for Poseidon<E, RATE> {
type Hash = Field<E>;
type Leaf = Vec<Self::Hash>;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Result<Self::Hash> {
let mut input = Vec::with_capacity(1 + leaf.len());
input.push(Self::Hash::zero());
input.extend(leaf);
Hash::hash(self, &input)
}
}
impl<const TYPE: u8, const VARIANT: usize> LeafHash for Keccak<TYPE, VARIANT> {
type Hash = BooleanHash<VARIANT>;
type Leaf = Vec<bool>;
fn hash_leaf(&self, leaf: &Self::Leaf) -> Result<Self::Hash> {
let mut input = Vec::with_capacity(1 + leaf.len());
input.push(false);
input.extend(leaf);
let output = Hash::hash(self, &input)?;
let mut result = BooleanHash::new();
result.0.copy_from_slice(&output[..VARIANT]);
Ok(result)
}
}