pub const WIDTH: usize = 16;
pub const RATE: usize = 8;
pub const BYTE_BLOCK_SIZE: usize = RATE * 3;
use crate::syscall_poseidon2;
#[repr(C)]
#[repr(align(8))]
pub struct Poseidon2State([u32; WIDTH]);
impl Default for Poseidon2State {
fn default() -> Self {
Self([0; WIDTH])
}
}
impl Poseidon2State {
#[inline]
pub fn permute(&mut self) {
unsafe {
syscall_poseidon2(self);
}
}
#[inline]
pub fn as_mut_ptr(&mut self) -> *mut u32 {
self.0.as_mut_ptr()
}
pub fn absorb_field_block_unchecked(&mut self, block: &[u32; RATE]) {
self.0[0..RATE].copy_from_slice(block);
self.permute();
}
pub fn absorb_byte_block(&mut self, block: &[u8; BYTE_BLOCK_SIZE]) {
let mut field_block = [0u32; RATE];
for (i, element) in field_block.iter_mut().enumerate() {
let start_idx = 3 * i;
*element += block[start_idx] as u32;
*element += (block[start_idx + 1] as u32) << 8;
*element += (block[start_idx + 2] as u32) << 16;
}
self.absorb_field_block_unchecked(&field_block);
}
pub fn output(self) -> [u32; RATE] {
let mut output = [0; RATE];
output.copy_from_slice(&self.0[0..RATE]);
output
}
}
pub struct Poseidon2ByteHash;
impl Poseidon2ByteHash {
pub fn hash(input: &[u8]) -> [u32; RATE] {
let mut state = Poseidon2State::default();
let len_bytes = input.len().to_le_bytes();
let mut len_block = [0u8; BYTE_BLOCK_SIZE];
len_block[..len_bytes.len()].copy_from_slice(&len_bytes);
state.absorb_byte_block(&len_block);
let chunks = input.chunks_exact(BYTE_BLOCK_SIZE);
let remainder = chunks.remainder();
for chunk in chunks {
state.absorb_byte_block(chunk.try_into().unwrap());
}
if !remainder.is_empty() {
let mut last_block = [0u8; BYTE_BLOCK_SIZE];
last_block[..remainder.len()].copy_from_slice(remainder);
state.absorb_byte_block(&last_block);
}
state.output()
}
}