mod constants;
use crate::field::Fr;
use ark_ff::AdditiveGroup;
const N_ROUNDS_F: usize = 8;
#[inline]
fn pow5(v: Fr) -> Fr {
let v2 = v * v;
v * v2 * v2
}
fn mix(state: &[Fr], m: &[Vec<Fr>]) -> Vec<Fr> {
(0..state.len())
.map(|x| {
let row = &m[x];
let mut acc = Fr::ZERO;
for (y, &s) in state.iter().enumerate() {
acc += row[y] * s;
}
acc
})
.collect()
}
pub fn poseidon(inputs: &[Fr]) -> Fr {
let arity = inputs.len();
assert!(arity >= 1, "poseidon: at least 1 input required");
assert!(
arity <= 16,
"poseidon: at most 16 inputs supported, got {arity}"
);
let p = constants::params(arity);
let t = p.t; let n_rounds_p = p.n_rounds_p;
let mut state: Vec<Fr> = Vec::with_capacity(t);
state.push(Fr::ZERO);
state.extend_from_slice(inputs);
for x in 0..(N_ROUNDS_F + n_rounds_p) {
let is_full = x < N_ROUNDS_F / 2 || x >= N_ROUNDS_F / 2 + n_rounds_p;
let base = x * t; for (y, sy) in state.iter_mut().enumerate() {
*sy += p.c[base + y];
if is_full || y == 0 {
*sy = pow5(*sy);
}
}
state = mix(&state, &p.m);
}
state[0]
}