#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use digest::{
ExtendableOutput,
Update,
XofReader,
};
use lib_q_sha3::Shake256;
use lib_q_stark_field::extension::Complex;
use lib_q_stark_field::{
Field,
PrimeCharacteristicRing,
};
use lib_q_stark_mersenne31::Mersenne31;
type F = Complex<Mersenne31>;
const P: u32 = (1 << 31) - 1;
#[cfg(feature = "alloc")]
fn cauchy_mds(n: usize) -> Vec<Vec<F>> {
let xs: Vec<F> = (0..n)
.map(|i| F::from(Mersenne31::new((i + 1) as u32)))
.collect();
let ys: Vec<F> = (0..n)
.map(|j| F::from(Mersenne31::new((n + j + 1) as u32)))
.collect();
(0..n)
.map(|i| (0..n).map(|j| (xs[i] + ys[j]).inverse()).collect())
.collect()
}
#[cfg(feature = "alloc")]
pub fn mds_matrix_5x5() -> Vec<Vec<F>> {
cauchy_mds(5)
}
#[cfg(feature = "alloc")]
pub fn mds_matrix_7x7() -> Vec<Vec<F>> {
cauchy_mds(7)
}
#[cfg(feature = "alloc")]
pub fn round_constants_128() -> Vec<F> {
generate_round_constants("Poseidon128_Mersenne31_v1_w5", 320)
}
#[cfg(feature = "alloc")]
pub fn round_constants_256() -> Vec<F> {
generate_round_constants("Poseidon256_Mersenne31_v1_w7", 476)
}
#[cfg(feature = "alloc")]
fn generate_round_constants(seed: &str, count: usize) -> Vec<F> {
let mut hasher = Shake256::default();
hasher.update(seed.as_bytes());
let mut reader = hasher.finalize_xof();
let mut bytes = alloc::vec![0u8; count * 8];
reader.read(&mut bytes);
let mut constants = Vec::with_capacity(count);
for i in 0..count {
let real_bytes = [
bytes[i * 8],
bytes[i * 8 + 1],
bytes[i * 8 + 2],
bytes[i * 8 + 3],
];
let imag_bytes = [
bytes[i * 8 + 4],
bytes[i * 8 + 5],
bytes[i * 8 + 6],
bytes[i * 8 + 7],
];
let real_u32 = u32::from_le_bytes(real_bytes) % P;
let imag_u32 = u32::from_le_bytes(imag_bytes) % P;
let real = Mersenne31::new(real_u32);
let imag = Mersenne31::new(imag_u32);
constants.push(Complex::new_complex(real, imag));
}
debug_assert!(
constants.iter().all(|c| *c != F::ZERO),
"round constant must not be zero"
);
constants
}
#[inline]
pub fn sbox(x: F) -> F {
use lib_q_stark_field::PrimeCharacteristicRing;
let x2 = x.square();
let x4 = x2.square();
x4 * x
}