use std::marker::PhantomData;
use crate::DomainParameter;
use mina_curves::pasta::Fp;
use mina_poseidon::{
constants::{PlonkSpongeConstantsKimchi, PlonkSpongeConstantsLegacy, SpongeConstants},
pasta,
poseidon::{ArithmeticSponge, ArithmeticSpongeParams, Sponge, SpongeState},
};
use super::{domain_prefix_to_field, Hashable, Hasher};
pub struct Poseidon<SC: SpongeConstants, H: Hashable> {
sponge: ArithmeticSponge<Fp, SC>,
sponge_state: SpongeState,
state: Vec<Fp>,
phantom: PhantomData<H>,
}
impl<SC: SpongeConstants, H: Hashable> Poseidon<SC, H> {
fn new(domain_param: H::D, sponge_params: &'static ArithmeticSpongeParams<Fp>) -> Self {
let mut poseidon = Poseidon::<SC, H> {
sponge: ArithmeticSponge::<Fp, SC>::new(sponge_params),
sponge_state: SpongeState::Absorbed(0),
state: vec![],
phantom: PhantomData,
};
poseidon.init(domain_param);
poseidon
}
}
pub type PoseidonHasherLegacy<H> = Poseidon<PlonkSpongeConstantsLegacy, H>;
pub(crate) fn new_legacy<H: Hashable>(domain_param: H::D) -> PoseidonHasherLegacy<H> {
Poseidon::<PlonkSpongeConstantsLegacy, H>::new(domain_param, pasta::fp_legacy::static_params())
}
pub type PoseidonHasherKimchi<H> = Poseidon<PlonkSpongeConstantsKimchi, H>;
pub(crate) fn new_kimchi<H: Hashable>(domain_param: H::D) -> PoseidonHasherKimchi<H> {
Poseidon::<PlonkSpongeConstantsKimchi, H>::new(domain_param, pasta::fp_kimchi::static_params())
}
impl<SC: SpongeConstants, H: Hashable> Hasher<H> for Poseidon<SC, H>
where
H::D: DomainParameter,
{
fn reset(&mut self) -> &mut dyn Hasher<H> {
self.sponge.sponge_state = self.sponge_state.clone();
self.sponge.state = self.state.clone();
self
}
fn init(&mut self, domain_param: H::D) -> &mut dyn Hasher<H> {
self.sponge.reset();
if let Some(domain_string) = H::domain_string(domain_param) {
self.sponge
.absorb(&[domain_prefix_to_field::<Fp>(domain_string)]);
self.sponge.squeeze();
}
self.sponge_state = self.sponge.sponge_state.clone();
self.state = self.sponge.state.clone();
self
}
fn update(&mut self, input: &H) -> &mut dyn Hasher<H> {
self.sponge.absorb(&input.to_roinput().to_fields());
self
}
fn digest(&mut self) -> Fp {
let output = self.sponge.squeeze();
self.sponge.reset();
output
}
}