#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use lib_q_stark_field::extension::Complex;
use lib_q_stark_mersenne31::Mersenne31;
use crate::params::{
Poseidon128,
Poseidon256,
PoseidonField,
PoseidonParams,
};
use crate::permutation::PoseidonPermutation;
#[derive(Debug, Clone)]
struct SpongeState {
permutation: PoseidonPermutation,
state: Vec<PoseidonField>,
rate: usize,
capacity: usize,
absorbed: usize,
}
impl SpongeState {
fn new(params: PoseidonParams) -> Self {
use lib_q_stark_field::PrimeCharacteristicRing;
let state_width = params.state_width;
Self {
permutation: PoseidonPermutation::new(params.clone()),
state: alloc::vec![Complex::<Mersenne31>::ZERO; state_width],
rate: params.rate,
capacity: params.capacity,
absorbed: 0,
}
}
fn absorb(&mut self, elements: &[PoseidonField]) {
for &element in elements {
self.state[self.absorbed] += element;
self.absorbed += 1;
if self.absorbed >= self.rate {
self.state = self.permutation.permute(self.state.clone());
self.absorbed = 0;
}
}
}
fn apply_padding_and_permute(mut self) -> Self {
use lib_q_stark_field::PrimeCharacteristicRing;
self.state[self.absorbed] += Complex::<Mersenne31>::ONE;
if self.absorbed + 1 < self.rate {
self.state[self.rate - 1] += Complex::<Mersenne31>::ONE;
}
self.state = self.permutation.permute(self.state.clone());
self.absorbed = 0;
self
}
fn squeeze(&mut self, num_elements: usize) -> Vec<PoseidonField> {
let mut output = Vec::with_capacity(num_elements);
let mut squeezed = 0;
while squeezed < num_elements {
if self.absorbed >= self.rate {
self.state = self.permutation.permute(self.state.clone());
self.absorbed = 0;
}
output.push(self.state[self.absorbed]);
self.absorbed += 1;
squeezed += 1;
}
output
}
}
#[derive(Debug, Clone)]
pub struct PoseidonSponge(SpongeState);
impl PoseidonSponge {
pub fn new(params: PoseidonParams) -> Self {
Self(SpongeState::new(params))
}
pub fn absorb(&mut self, elements: &[PoseidonField]) {
self.0.absorb(elements);
}
pub fn finish_absorbing(self) -> PoseidonSpongeSqueeze {
PoseidonSpongeSqueeze(self.0.apply_padding_and_permute())
}
pub fn finalize(self) -> Vec<PoseidonField> {
self.finish_absorbing().into_state()
}
pub fn capacity(&self) -> usize {
self.0.capacity
}
pub fn rate(&self) -> usize {
self.0.rate
}
}
#[derive(Debug, Clone)]
pub struct PoseidonSpongeSqueeze(SpongeState);
impl PoseidonSpongeSqueeze {
pub fn squeeze(&mut self, num_elements: usize) -> Vec<PoseidonField> {
self.0.squeeze(num_elements)
}
pub fn into_state(self) -> Vec<PoseidonField> {
self.0.state
}
pub fn capacity(&self) -> usize {
self.0.capacity
}
pub fn rate(&self) -> usize {
self.0.rate
}
}
pub trait Poseidon {
fn hash(&self, input: &[PoseidonField]) -> Vec<PoseidonField>;
fn hash_single(&self, input: &[PoseidonField]) -> PoseidonField {
self.hash(input)[0]
}
}
impl Poseidon for Poseidon128 {
fn hash(&self, input: &[PoseidonField]) -> Vec<PoseidonField> {
let params = Self::params();
let mut sponge = PoseidonSponge::new(params);
sponge.absorb(input);
let mut sponge = sponge.finish_absorbing();
sponge.squeeze(1)
}
}
impl Poseidon for Poseidon256 {
fn hash(&self, input: &[PoseidonField]) -> Vec<PoseidonField> {
let params = Self::params();
let mut sponge = PoseidonSponge::new(params);
sponge.absorb(input);
let mut sponge = sponge.finish_absorbing();
sponge.squeeze(1)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_sponge_absorb_squeeze() {
let params = Poseidon128::params();
let mut sponge = PoseidonSponge::new(params);
let input = alloc::vec![
Complex::<Mersenne31>::from(Mersenne31::new(1)),
Complex::<Mersenne31>::from(Mersenne31::new(2)),
];
sponge.absorb(&input);
let mut sponge = sponge.finish_absorbing();
let output = sponge.squeeze(1);
assert_eq!(output.len(), 1);
}
#[test]
fn test_poseidon_hash_deterministic() {
use super::Poseidon;
let hasher = Poseidon128;
let input = alloc::vec![
Complex::<Mersenne31>::from(Mersenne31::new(1)),
Complex::<Mersenne31>::from(Mersenne31::new(2)),
];
let hash1 = hasher.hash(&input);
let hash2 = hasher.hash(&input);
assert_eq!(hash1, hash2);
}
}