p3_poseidon2/
lib.rs

1//! The Poseidon2 permutation.
2//!
3//! This implementation was based upon the following resources:
4//! - https://github.com/HorizenLabs/poseidon2/blob/main/plain_implementations/src/poseidon2/poseidon2.rs
5//! - https://eprint.iacr.org/2023/323.pdf
6
7#![no_std]
8
9extern crate alloc;
10
11mod external;
12mod generic;
13mod internal;
14mod round_numbers;
15use alloc::vec::Vec;
16use core::marker::PhantomData;
17
18pub use external::*;
19pub use generic::*;
20pub use internal::*;
21use p3_field::{Field, FieldAlgebra, PrimeField, PrimeField64};
22use p3_symmetric::{CryptographicPermutation, Permutation};
23use rand::distributions::{Distribution, Standard};
24use rand::Rng;
25pub use round_numbers::poseidon2_round_numbers_128;
26
27const SUPPORTED_WIDTHS: [usize; 8] = [2, 3, 4, 8, 12, 16, 20, 24];
28
29/// The Poseidon2 permutation.
30#[derive(Clone, Debug)]
31pub struct Poseidon2<F, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64> {
32    /// The permutations used in External Rounds.
33    external_layer: ExternalPerm,
34
35    /// The permutation used in Internal Rounds.
36    internal_layer: InternalPerm,
37
38    _phantom: PhantomData<F>,
39}
40
41impl<FA, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
42    Poseidon2<FA, ExternalPerm, InternalPerm, WIDTH, D>
43where
44    FA: FieldAlgebra,
45    FA::F: PrimeField,
46    ExternalPerm: ExternalLayerConstructor<FA, WIDTH>,
47    InternalPerm: InternalLayerConstructor<FA>,
48{
49    /// Create a new Poseidon2 configuration.
50    /// This internally converts the given constants to the relevant packed versions.
51    pub fn new(
52        external_constants: ExternalLayerConstants<FA::F, WIDTH>,
53        internal_constants: Vec<FA::F>,
54    ) -> Self {
55        assert!(SUPPORTED_WIDTHS.contains(&WIDTH));
56        let external_layer = ExternalPerm::new_from_constants(external_constants);
57        let internal_layer = InternalPerm::new_from_constants(internal_constants);
58
59        Self {
60            external_layer,
61            internal_layer,
62            _phantom: PhantomData,
63        }
64    }
65
66    /// Create a new Poseidon2 configuration with random parameters.
67    pub fn new_from_rng<R: Rng>(rounds_f: usize, rounds_p: usize, rng: &mut R) -> Self
68    where
69        Standard: Distribution<FA::F> + Distribution<[FA::F; WIDTH]>,
70    {
71        let external_constants = ExternalLayerConstants::new_from_rng(rounds_f, rng);
72        let internal_constants = rng.sample_iter(Standard).take(rounds_p).collect();
73
74        Self::new(external_constants, internal_constants)
75    }
76}
77
78impl<FA, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
79    Poseidon2<FA, ExternalPerm, InternalPerm, WIDTH, D>
80where
81    FA: FieldAlgebra,
82    FA::F: PrimeField64,
83    ExternalPerm: ExternalLayerConstructor<FA, WIDTH>,
84    InternalPerm: InternalLayerConstructor<FA>,
85{
86    /// Create a new Poseidon2 configuration with 128 bit security and random rounds constants.
87    pub fn new_from_rng_128<R: Rng>(rng: &mut R) -> Self
88    where
89        Standard: Distribution<FA::F> + Distribution<[FA::F; WIDTH]>,
90    {
91        let (rounds_f, rounds_p) = poseidon2_round_numbers_128::<FA::F>(WIDTH, D);
92        Self::new_from_rng(rounds_f, rounds_p, rng)
93    }
94}
95
96impl<FA, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64> Permutation<[FA; WIDTH]>
97    for Poseidon2<<FA::F as Field>::Packing, ExternalPerm, InternalPerm, WIDTH, D>
98where
99    FA: FieldAlgebra + Sync,
100    FA::F: PrimeField,
101    ExternalPerm: ExternalLayer<FA, WIDTH, D>,
102    InternalPerm: InternalLayer<FA, WIDTH, D>,
103{
104    fn permute_mut(&self, state: &mut [FA; WIDTH]) {
105        self.external_layer.permute_state_initial(state);
106        self.internal_layer.permute_state(state);
107        self.external_layer.permute_state_terminal(state);
108    }
109}
110
111impl<FA, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
112    CryptographicPermutation<[FA; WIDTH]>
113    for Poseidon2<<FA::F as Field>::Packing, ExternalPerm, InternalPerm, WIDTH, D>
114where
115    FA: FieldAlgebra + Sync,
116    FA::F: PrimeField,
117    ExternalPerm: ExternalLayer<FA, WIDTH, D>,
118    InternalPerm: InternalLayer<FA, WIDTH, D>,
119{
120}