use p3_field::PrimeField32;
use p3_symmetric::Permutation;
use crate::memory::MemoryRecord;
use crate::poseidon2_wide::WIDTH;
use crate::runtime::DIGEST_SIZE;
use super::RATE;
#[derive(Debug, Clone)]
pub enum Poseidon2HashEvent<F> {
Absorb(Poseidon2AbsorbEvent<F>),
Finalize(Poseidon2FinalizeEvent<F>),
}
#[derive(Debug, Clone)]
pub struct Poseidon2CompressEvent<F> {
pub clk: F,
pub dst: F, pub left: F, pub right: F, pub input: [F; WIDTH],
pub result_array: [F; WIDTH],
pub input_records: [MemoryRecord<F>; WIDTH],
pub result_records: [MemoryRecord<F>; WIDTH],
}
#[derive(Debug, Clone)]
pub struct Poseidon2AbsorbEvent<F> {
pub clk: F,
pub hash_and_absorb_num: F, pub input_addr: F, pub input_len: F, pub hash_num: F,
pub absorb_num: F,
pub iterations: Vec<Poseidon2AbsorbIteration<F>>,
}
impl<F> Poseidon2AbsorbEvent<F> {
pub(crate) fn new(
clk: F,
hash_and_absorb_num: F,
input_addr: F,
input_len: F,
hash_num: F,
absorb_num: F,
) -> Self {
Self {
clk,
hash_and_absorb_num,
input_addr,
input_len,
hash_num,
absorb_num,
iterations: Vec::new(),
}
}
}
impl<F: PrimeField32> Poseidon2AbsorbEvent<F> {
pub(crate) fn populate_iterations(
&mut self,
start_addr: F,
input_len: F,
memory_records: &[MemoryRecord<F>],
permuter: &impl Permutation<[F; WIDTH]>,
hash_state: &mut [F; WIDTH],
hash_state_cursor: &mut usize,
) {
let mut input_records = Vec::new();
let mut previous_state = *hash_state;
let mut iter_num_consumed = 0;
let start_addr = start_addr.as_canonical_u32();
let end_addr = start_addr + input_len.as_canonical_u32();
for (addr_iter, memory_record) in (start_addr..end_addr).zip(memory_records.iter()) {
input_records.push(*memory_record);
hash_state[*hash_state_cursor] = memory_record.value[0];
*hash_state_cursor += 1;
iter_num_consumed += 1;
if *hash_state_cursor == RATE {
let perm_input = *hash_state;
*hash_state = permuter.permute(*hash_state);
self.iterations.push(Poseidon2AbsorbIteration {
state_cursor: *hash_state_cursor - iter_num_consumed,
start_addr: F::from_canonical_u32(addr_iter - iter_num_consumed as u32 + 1),
input_records,
perm_input,
perm_output: *hash_state,
previous_state,
state: *hash_state,
do_perm: true,
});
previous_state = *hash_state;
input_records = Vec::new();
*hash_state_cursor = 0;
iter_num_consumed = 0;
}
}
if *hash_state_cursor != 0 {
self.iterations.push(Poseidon2AbsorbIteration {
state_cursor: *hash_state_cursor - iter_num_consumed,
start_addr: F::from_canonical_u32(end_addr - iter_num_consumed as u32),
input_records,
perm_input: *hash_state,
perm_output: permuter.permute(*hash_state),
previous_state,
state: *hash_state,
do_perm: false,
});
}
}
}
#[derive(Debug, Clone)]
pub struct Poseidon2AbsorbIteration<F> {
pub state_cursor: usize,
pub start_addr: F,
pub input_records: Vec<MemoryRecord<F>>,
pub perm_input: [F; WIDTH],
pub perm_output: [F; WIDTH],
pub previous_state: [F; WIDTH],
pub state: [F; WIDTH],
pub do_perm: bool,
}
#[derive(Debug, Clone)]
pub struct Poseidon2FinalizeEvent<F> {
pub clk: F,
pub hash_num: F, pub output_ptr: F, pub output_records: [MemoryRecord<F>; DIGEST_SIZE],
pub state_cursor: usize,
pub perm_input: [F; WIDTH],
pub perm_output: [F; WIDTH],
pub previous_state: [F; WIDTH],
pub state: [F; WIDTH],
pub do_perm: bool,
}