p3_poseidon2/
lib.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
//! The Poseidon2 permutation.
//!
//! This implementation was based upon the following resources:
//! - https://github.com/HorizenLabs/poseidon2/blob/main/plain_implementations/src/poseidon2/poseidon2.rs
//! - https://eprint.iacr.org/2023/323.pdf

#![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];

/// The Poseidon2 permutation.
#[derive(Clone, Debug)]
pub struct Poseidon2<F, ExternalPerm, InternalPerm, const WIDTH: usize, const D: u64> {
    /// The permutations used in External Rounds.
    external_layer: ExternalPerm,

    /// The permutation used in Internal Rounds.
    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>,
{
    /// Create a new Poseidon2 configuration.
    /// This internally converts the given constants to the relevant packed versions.
    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,
        }
    }

    /// Create a new Poseidon2 configuration with random parameters.
    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>,
{
    /// Create a new Poseidon2 configuration with 128 bit security and random rounds constants.
    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>,
{
}