#![no_std]
extern crate alloc;
mod external;
mod generic;
mod internal;
mod round_numbers;
use alloc::vec::Vec;
use core::marker::PhantomData;
pub use external::*;
pub use generic::*;
pub use internal::*;
use p3_field::{AbstractField, Field, PrimeField, PrimeField64};
use p3_symmetric::{CryptographicPermutation, Permutation};
use rand::distributions::{Distribution, Standard};
use rand::Rng;
pub use round_numbers::poseidon2_round_numbers_128;
const SUPPORTED_WIDTHS: [usize; 8] = [2, 3, 4, 8, 12, 16, 20, 24];
#[derive(Clone, Debug)]
pub struct Poseidon2<F, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64> {
external_layer: ExternalPerm,
internal_layer: InternalPerm,
_phantom: PhantomData<F>,
}
impl<AF, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
Poseidon2<AF, ExternalPerm, InternalPerm, WIDTH, D>
where
AF: AbstractField,
AF::F: PrimeField,
ExternalPerm: ExternalLayerConstructor<AF, WIDTH>,
InternalPerm: InternalLayerConstructor<AF>,
{
pub fn new(
external_constants: ExternalLayerConstants<AF::F, WIDTH>,
internal_constants: Vec<AF::F>,
) -> Self {
assert!(SUPPORTED_WIDTHS.contains(&WIDTH));
let external_layer = ExternalPerm::new_from_constants(external_constants);
let internal_layer = InternalPerm::new_from_constants(internal_constants);
Self {
external_layer,
internal_layer,
_phantom: PhantomData,
}
}
pub fn new_from_rng<R: Rng>(rounds_f: usize, rounds_p: usize, rng: &mut R) -> Self
where
Standard: Distribution<AF::F> + Distribution<[AF::F; WIDTH]>,
{
let external_constants = ExternalLayerConstants::new_from_rng(rounds_f, rng);
let internal_constants = rng.sample_iter(Standard).take(rounds_p).collect();
Self::new(external_constants, internal_constants)
}
}
impl<AF, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
Poseidon2<AF, ExternalPerm, InternalPerm, WIDTH, D>
where
AF: AbstractField,
AF::F: PrimeField64,
ExternalPerm: ExternalLayerConstructor<AF, WIDTH>,
InternalPerm: InternalLayerConstructor<AF>,
{
pub fn new_from_rng_128<R: Rng>(rng: &mut R) -> Self
where
Standard: Distribution<AF::F> + Distribution<[AF::F; WIDTH]>,
{
let (rounds_f, rounds_p) = poseidon2_round_numbers_128::<AF::F>(WIDTH, D);
Self::new_from_rng(rounds_f, rounds_p, rng)
}
}
impl<AF, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64> Permutation<[AF; WIDTH]>
for Poseidon2<<AF::F as Field>::Packing, ExternalPerm, InternalPerm, WIDTH, D>
where
AF: AbstractField + Sync,
AF::F: PrimeField,
ExternalPerm: ExternalLayer<AF, WIDTH, D>,
InternalPerm: InternalLayer<AF, WIDTH, D>,
{
fn permute_mut(&self, state: &mut [AF; WIDTH]) {
self.external_layer.permute_state_initial(state);
self.internal_layer.permute_state(state);
self.external_layer.permute_state_terminal(state);
}
}
impl<AF, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
CryptographicPermutation<[AF; WIDTH]>
for Poseidon2<<AF::F as Field>::Packing, ExternalPerm, InternalPerm, WIDTH, D>
where
AF: AbstractField + Sync,
AF::F: PrimeField,
ExternalPerm: ExternalLayer<AF, WIDTH, D>,
InternalPerm: InternalLayer<AF, WIDTH, D>,
{
}