1use alloc::{vec, vec::Vec};
6
7use core::marker::PhantomData;
8
9use crate::DomainParameter;
10use mina_curves::pasta::Fp;
11use mina_poseidon::{
12 constants::{PlonkSpongeConstantsKimchi, PlonkSpongeConstantsLegacy, SpongeConstants},
13 pasta::{self, FULL_ROUNDS},
14 poseidon::{ArithmeticSponge, ArithmeticSpongeParams, Sponge, SpongeState},
15};
16
17use super::{domain_prefix_to_field, Hashable, Hasher};
18
19pub struct Poseidon<SC: SpongeConstants, H: Hashable, const FULL_ROUNDS: usize> {
26 sponge: ArithmeticSponge<Fp, SC, FULL_ROUNDS>,
27 sponge_state: SpongeState,
28 pub state: Vec<Fp>,
30 phantom: PhantomData<H>,
31}
32
33impl<SC: SpongeConstants, H: Hashable, const FULL_ROUNDS: usize> Poseidon<SC, H, FULL_ROUNDS> {
34 fn new(
35 domain_param: H::D,
36 sponge_params: &'static ArithmeticSpongeParams<Fp, FULL_ROUNDS>,
37 ) -> Self {
38 let mut poseidon = Self {
39 sponge: ArithmeticSponge::<Fp, SC, FULL_ROUNDS>::new(sponge_params),
40 sponge_state: SpongeState::Absorbed(0),
41 state: vec![],
42 phantom: PhantomData,
43 };
44
45 poseidon.init(domain_param);
46
47 poseidon
48 }
49}
50
51pub type PoseidonHasherLegacy<H> = Poseidon<PlonkSpongeConstantsLegacy, H, 100>;
53
54pub(crate) fn new_legacy<H: Hashable>(domain_param: H::D) -> PoseidonHasherLegacy<H> {
56 Poseidon::<PlonkSpongeConstantsLegacy, H, 100>::new(
57 domain_param,
58 pasta::fp_legacy::static_params(),
59 )
60}
61
62pub type PoseidonHasherKimchi<H> = Poseidon<PlonkSpongeConstantsKimchi, H, FULL_ROUNDS>;
64
65pub(crate) fn new_kimchi<H: Hashable>(domain_param: H::D) -> PoseidonHasherKimchi<H> {
67 Poseidon::<PlonkSpongeConstantsKimchi, H, FULL_ROUNDS>::new(
68 domain_param,
69 pasta::fp_kimchi::static_params(),
70 )
71}
72
73impl<SC: SpongeConstants, H: Hashable, const FULL_ROUNDS: usize> Hasher<H>
74 for Poseidon<SC, H, FULL_ROUNDS>
75where
76 H::D: DomainParameter,
77{
78 fn reset(&mut self) -> &mut dyn Hasher<H> {
79 self.sponge.sponge_state = self.sponge_state.clone();
81 self.sponge.state.clone_from(&self.state);
82
83 self
84 }
85
86 fn init(&mut self, domain_param: H::D) -> &mut dyn Hasher<H> {
87 self.sponge.reset();
92
93 if let Some(domain_string) = H::domain_string(domain_param) {
94 self.sponge
95 .absorb(&[domain_prefix_to_field::<Fp>(domain_string)]);
96 self.sponge.squeeze();
97 }
98
99 self.sponge_state = self.sponge.sponge_state.clone();
101 self.state.clone_from(&self.sponge.state);
102
103 self
104 }
105
106 fn update(&mut self, input: &H) -> &mut dyn Hasher<H> {
107 self.sponge.absorb(&input.to_roinput().to_fields());
108
109 self
110 }
111
112 fn digest(&mut self) -> Fp {
113 let output = self.sponge.squeeze();
114 self.sponge.reset();
115 output
116 }
117}