pub mod hasher;
use hasher::BHPHasher;
mod commit;
mod commit_uncompressed;
mod hash;
mod hash_uncompressed;
use snarkvm_console_types::prelude::*;
use serde::{Deserialize, Serialize};
use std::sync::{Arc, OnceLock};
const BHP_CHUNK_SIZE: usize = 3;
pub type BHP256<E> = BHP<E, 3, 57>; pub type BHP512<E> = BHP<E, 6, 43>; pub type BHP768<E> = BHP<E, 15, 23>; pub type BHP1024<E> = BHP<E, 8, 54>;
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(bound = "E: Serialize + DeserializeOwned")]
pub struct BHP<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> {
domain: Vec<bool>,
hasher: BHPHasher<E, NUM_WINDOWS, WINDOW_SIZE>,
#[serde(skip)]
empty_hash: OnceLock<Field<E>>,
}
impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> PartialEq for BHP<E, NUM_WINDOWS, WINDOW_SIZE> {
fn eq(&self, other: &Self) -> bool {
let Self { domain, hasher, empty_hash: _ } = self;
*domain == other.domain && *hasher == other.hasher
}
}
impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> BHP<E, NUM_WINDOWS, WINDOW_SIZE> {
pub fn setup(domain: &str) -> Result<Self> {
let num_bits = domain.len().saturating_mul(8);
let max_bits = Field::<E>::size_in_data_bits() - 64; ensure!(num_bits <= max_bits, "Domain cannot exceed {max_bits} bits, found {num_bits} bits");
let hasher = BHPHasher::<E, NUM_WINDOWS, WINDOW_SIZE>::setup(domain)?;
let mut domain = domain.as_bytes().to_bits_le();
domain.resize(max_bits, false);
domain.reverse();
Ok(Self { domain, hasher, empty_hash: OnceLock::new() })
}
pub fn domain(&self) -> &[bool] {
&self.domain
}
pub fn merkle_empty_hash(&self) -> Result<Field<E>> {
if let Some(empty_hash) = self.empty_hash.get() {
return Ok(*empty_hash);
}
let mut input = Vec::with_capacity(1 + Field::<E>::size_in_bits() * 2);
input.push(true);
Field::<E>::zero().write_bits_le(&mut input);
Field::<E>::zero().write_bits_le(&mut input);
let empty_hash = Hash::hash(self, &input)?;
Ok(*self.empty_hash.get_or_init(|| empty_hash))
}
pub fn bases(&self) -> &Arc<Vec<Vec<Group<E>>>> {
self.hasher.bases()
}
pub fn random_base(&self) -> &Arc<Vec<Group<E>>> {
self.hasher.random_base()
}
pub fn num_windows(&self) -> u8 {
NUM_WINDOWS
}
pub fn window_size(&self) -> u8 {
WINDOW_SIZE
}
}