1#![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::{Algebra, InjectiveMonomial, PrimeField, PrimeField64};
22use p3_symmetric::{CryptographicPermutation, Permutation};
23use rand::distr::{Distribution, StandardUniform};
24use rand::{Rng, RngExt};
25pub use round_numbers::poseidon2_round_numbers_128;
26
27const SUPPORTED_WIDTHS: [usize; 9] = [2, 3, 4, 8, 12, 16, 20, 24, 32];
28
29#[derive(Clone, Debug)]
31pub struct Poseidon2<F, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64> {
32 external_layer: ExternalPerm,
34
35 internal_layer: InternalPerm,
37
38 _phantom: PhantomData<F>,
39}
40
41impl<F, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
42 Poseidon2<F, ExternalPerm, InternalPerm, WIDTH, D>
43where
44 F: PrimeField,
45 ExternalPerm: ExternalLayerConstructor<F, WIDTH>,
46 InternalPerm: InternalLayerConstructor<F>,
47{
48 pub fn new(
51 external_constants: ExternalLayerConstants<F, WIDTH>,
52 internal_constants: Vec<F>,
53 ) -> Self {
54 const {
55 let mut i = 0;
56 let mut found = false;
57 while i < SUPPORTED_WIDTHS.len() {
58 if SUPPORTED_WIDTHS[i] == WIDTH {
59 found = true;
60 }
61 i += 1;
62 }
63 assert!(found, "WIDTH must be one of the supported widths");
64 assert!(D > 1);
65 }
66 let external_layer = ExternalPerm::new_from_constants(external_constants);
67 let internal_layer = InternalPerm::new_from_constants(internal_constants);
68
69 Self {
70 external_layer,
71 internal_layer,
72 _phantom: PhantomData,
73 }
74 }
75
76 pub fn new_from_rng<R: Rng>(rounds_f: usize, rounds_p: usize, rng: &mut R) -> Self
78 where
79 StandardUniform: Distribution<F> + Distribution<[F; WIDTH]>,
80 {
81 let external_constants = ExternalLayerConstants::new_from_rng(rounds_f, rng);
82 let internal_constants = rng.sample_iter(StandardUniform).take(rounds_p).collect();
83
84 Self::new(external_constants, internal_constants)
85 }
86}
87
88impl<F, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
89 Poseidon2<F, ExternalPerm, InternalPerm, WIDTH, D>
90where
91 F: PrimeField64,
92 ExternalPerm: ExternalLayerConstructor<F, WIDTH>,
93 InternalPerm: InternalLayerConstructor<F>,
94{
95 pub fn new_from_rng_128<R: Rng>(rng: &mut R) -> Self
101 where
102 StandardUniform: Distribution<F> + Distribution<[F; WIDTH]>,
103 {
104 let round_numbers = poseidon2_round_numbers_128::<F>(WIDTH, D);
105 let (rounds_f, rounds_p) = round_numbers.unwrap_or_else(|e| panic!("{e}"));
106 Self::new_from_rng(rounds_f, rounds_p, rng)
107 }
108}
109
110impl<F, A, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64> Permutation<[A; WIDTH]>
111 for Poseidon2<F, ExternalPerm, InternalPerm, WIDTH, D>
112where
113 F: PrimeField + InjectiveMonomial<D>,
114 A: Algebra<F> + Sync + InjectiveMonomial<D>,
115 ExternalPerm: ExternalLayer<A, WIDTH, D>,
116 InternalPerm: InternalLayer<A, WIDTH, D>,
117{
118 fn permute_mut(&self, state: &mut [A; WIDTH]) {
119 self.external_layer.permute_state_initial(state);
120 self.internal_layer.permute_state(state);
121 self.external_layer.permute_state_terminal(state);
122 }
123}
124
125impl<F, A, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64>
126 CryptographicPermutation<[A; WIDTH]> for Poseidon2<F, ExternalPerm, InternalPerm, WIDTH, D>
127where
128 F: PrimeField + InjectiveMonomial<D>,
129 A: Algebra<F> + Sync + InjectiveMonomial<D>,
130 ExternalPerm: ExternalLayer<A, WIDTH, D>,
131 InternalPerm: InternalLayer<A, WIDTH, D>,
132{
133}