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
#![cfg_attr(not(feature = "std"), no_std)]
#![allow(non_snake_case)]

mod arc_matrix;
mod matrix;
mod matrix_ops;
mod mds_matrix;
#[cfg(test)]
mod tests;

pub use arc_matrix::*;
use ark_ff::{BigInteger, PrimeField};
pub use matrix::*;
pub use matrix_ops::*;
pub use mds_matrix::*;

/// Input parameters that are used to generate Poseidon parameters.
#[derive(Clone, Debug)]
pub struct InputParameters<T: BigInteger> {
    /// Whether or not to allow inverse alpha.
    pub allow_inverse: bool,

    /// Security level in bits.
    pub M: usize,

    /// Width of desired hash function, e.g. $t=3$ corresponds to 2-to-1 hash.
    pub t: usize,

    /// Modulus of the prime field.
    pub p: T, // let modulus = <F as PrimeField>::Params::MODULUS;

    // The below are derived values, stored for convenience.
    /// log_2(p)
    pub log_2_p: f64,
}

/// The exponent in `Sbox(x) = x^\alpha`.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Alpha {
    /// A positive exponent $x^{alpha}$.
    Exponent(u32),
    /// 1/x
    Inverse,
}

impl Alpha {
    /// Return the memory representation of alpha as a byte array in little-endian byte order.
    pub fn to_bytes_le(&self) -> [u8; 4] {
        match self {
            Alpha::Exponent(exp) => exp.to_le_bytes(),
            Alpha::Inverse => (-1i32).to_le_bytes(),
        }
    }
}

/// `RoundNumbers` required for security based on known attacks.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct RoundNumbers {
    /// Number of partial rounds.
    pub r_P: usize,
    /// Number of full rounds.
    pub r_F: usize,
}

impl RoundNumbers {
    /// Number of full rounds.    
    pub fn full(&self) -> usize {
        self.r_F
    }

    /// Number of full rounds as mutable reference.
    pub fn full_mut(&mut self) -> &mut usize {
        &mut self.r_F
    }

    /// Number of partial rounds.    
    pub fn partial(&self) -> usize {
        self.r_P
    }

    /// Number of full rounds as mutable reference.
    pub fn partial_mut(&mut self) -> &mut usize {
        &mut self.r_P
    }

    /// Number of total rounds.
    pub fn total(&self) -> usize {
        self.r_P + self.r_F
    }
}

// TODO: arc and mds could be collections
/// A set of Poseidon parameters for a given set of input parameters.
#[derive(Clone, Debug)]
pub struct PoseidonParameters<F: PrimeField> {
    // Input parameters.
    /// Security level.
    pub M: usize,
    /// Width of desired hash function, e.g. $t=3$ corresponds to a 2-to-1 hash.
    pub t: usize,

    // Generated parameters.
    /// Exponent of the Sbox, i.e. S-box(x) = x^{\alpha} used in the `SubWords` step
    pub alpha: Alpha,

    /// Round numbers
    pub rounds: RoundNumbers,

    /// `t x t` MDS matrix used in the `MixLayer` step
    pub mds: MdsMatrix<F>,

    /// `num_total_rounds x t` matrix of constants used in the `AddRoundConstant` step
    pub arc: ArcMatrix<F>,

    /// Optimized round constants.
    pub optimized_arc: OptimizedArcMatrix<F>,

    /// Optimized MDS matrices.
    pub optimized_mds: OptimizedMdsMatrices<F>,
}