use super::*;
use std::borrow::Cow;
impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> HashUncompressed
for BHPHasher<E, NUM_WINDOWS, WINDOW_SIZE>
{
type Input = bool;
type Output = Group<E>;
fn hash_uncompressed(&self, input: &[Self::Input]) -> Result<Self::Output> {
ensure!(
input.len() > Self::MIN_BITS,
"Inputs to this BHP must be greater than {} bits (window size: {WINDOW_SIZE}, num windows: {NUM_WINDOWS}), actual bits: {}",
Self::MIN_BITS,
input.len()
);
ensure!(
input.len() <= Self::MAX_BITS,
"Inputs to this BHP cannot exceed {} bits, found {}",
Self::MAX_BITS,
input.len()
);
let input = if input.len() % BHP_CHUNK_SIZE != 0 {
let padding = BHP_CHUNK_SIZE - (input.len() % BHP_CHUNK_SIZE);
let mut padded_input = vec![false; input.len() + padding];
padded_input[..input.len()].copy_from_slice(input);
ensure!((padded_input.len() % BHP_CHUNK_SIZE) == 0, "Input must be a multiple of {BHP_CHUNK_SIZE}");
Cow::Owned(padded_input)
} else {
Cow::Borrowed(input)
};
let sum = input
.chunks(WINDOW_SIZE as usize * BHP_CHUNK_SIZE)
.zip(self.combined_bases_lookup.iter())
.zip(self.bases_lookup.iter())
.flat_map(|((window_bits, combined_bases), bases)| {
let num_combined_bases = window_bits.len() / (BHP_CHUNK_SIZE * BHP_NUM_COMBINED_CHUNKS);
let num_combined_bits = num_combined_bases * BHP_CHUNK_SIZE * BHP_NUM_COMBINED_CHUNKS;
let combined = window_bits[..num_combined_bits]
.chunks_exact(BHP_CHUNK_SIZE * BHP_NUM_COMBINED_CHUNKS)
.zip(combined_bases)
.map(|(combined_chunks_bits, combined_base)| {
let index = combined_chunks_bits.chunks_exact(BHP_CHUNK_SIZE).fold(0, |idx, chunk_bits| {
(idx << BHP_CHUNK_SIZE)
| (chunk_bits[0] as usize)
| (chunk_bits[1] as usize) << 1
| (chunk_bits[2] as usize) << 2
});
combined_base[index]
});
let base_offset = num_combined_bases * BHP_NUM_COMBINED_CHUNKS;
let trailing = &window_bits[num_combined_bits..];
let remainder =
trailing.chunks_exact(BHP_CHUNK_SIZE).enumerate().map(move |(triplet_index, chunk_bits)| {
let idx =
(chunk_bits[0] as usize) | (chunk_bits[1] as usize) << 1 | (chunk_bits[2] as usize) << 2;
bases[base_offset + triplet_index][idx]
});
combined.chain(remainder)
})
.sum();
Ok(sum)
}
}