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
use alloc::vec::Vec;
use lambdaworks_math::field::{element::FieldElement as FE, traits::IsPrimeField};
/// Parameters for Poseidon
/// MDS constants and rounds constants are stored as references to slices
/// representing matrices of `N_MDS_MATRIX_ROWS * N_MDS_MATRIX_COLS` and
/// `N_ROUND_CONSTANTS_ROWS * N_ROUND_CONSTANTS_COLS` respectively.
/// We use this representation rather than an array because we can't use the
/// associated constants for dimension, requiring many generic parameters
/// otherwise.
pub trait PermutationParameters {
type F: IsPrimeField + 'static;
const RATE: usize;
const CAPACITY: usize;
const ALPHA: u32;
const N_FULL_ROUNDS: usize;
const N_PARTIAL_ROUNDS: usize;
const STATE_SIZE: usize = Self::RATE + Self::CAPACITY;
const MDS_MATRIX: &'static [FE<Self::F>];
const N_MDS_MATRIX_ROWS: usize;
const N_MDS_MATRIX_COLS: usize;
const ROUND_CONSTANTS: &'static [FE<Self::F>];
const N_ROUND_CONSTANTS_ROWS: usize;
const N_ROUND_CONSTANTS_COLS: usize;
/// This is the mix function that operates with the MDS matrix
/// Round Constants are sometimes picked to simplify this function,
/// so it can be redefined by each set of permutation parameters if a simplification can be made to make it faster. Notice in that case, MDS constants may not be used.
fn mix(state: &mut [FE<Self::F>]) {
let mut new_state: Vec<FE<Self::F>> = Vec::with_capacity(Self::STATE_SIZE);
for i in 0..Self::STATE_SIZE {
let mut new_e = FE::zero();
for (j, current_state) in state.iter().enumerate() {
let mut mij = Self::MDS_MATRIX[i * Self::N_MDS_MATRIX_COLS + j].clone();
mij *= current_state;
new_e += mij;
}
new_state.push(new_e);
}
state.clone_from_slice(&new_state[0..Self::STATE_SIZE]);
}
}