use std::collections::BTreeMap;
use std::sync::LazyLock;
use serde::Deserialize;
use crate::field::{Fr, fr_from_dec};
const CONSTANTS_JSON: &str = include_str!("../../testdata/poseidon_constants.json");
#[derive(Deserialize)]
struct RawArity {
t: usize,
#[serde(rename = "nRoundsP")]
n_rounds_p: usize,
#[serde(rename = "C")]
c: Vec<String>,
#[serde(rename = "M")]
m: Vec<Vec<String>>,
}
#[derive(Deserialize)]
struct RawFile {
arities: BTreeMap<String, RawArity>,
}
pub struct Params {
pub t: usize,
pub n_rounds_p: usize,
pub c: Vec<Fr>,
pub m: Vec<Vec<Fr>>,
}
static PARAMS: LazyLock<BTreeMap<usize, Params>> = LazyLock::new(|| {
let raw: RawFile =
serde_json::from_str(CONSTANTS_JSON).expect("poseidon_constants.json must parse");
raw.arities
.into_iter()
.map(|(arity_str, a)| {
let arity: usize = arity_str.parse().expect("arity key must be an integer");
assert_eq!(a.t, arity + 1, "arity {arity}: t must be arity + 1");
assert_eq!(
a.c.len(),
(super::N_ROUNDS_F + a.n_rounds_p) * a.t,
"arity {arity}: unexpected C length",
);
assert_eq!(a.m.len(), a.t, "arity {arity}: M must be t x t");
let c = a.c.iter().map(|s| fr_from_dec(s)).collect();
let m =
a.m.iter()
.map(|row| {
assert_eq!(row.len(), a.t, "arity {arity}: M row must have t entries");
row.iter().map(|s| fr_from_dec(s)).collect()
})
.collect();
(
arity,
Params {
t: a.t,
n_rounds_p: a.n_rounds_p,
c,
m,
},
)
})
.collect()
});
pub fn params(arity: usize) -> &'static Params {
PARAMS
.get(&arity)
.unwrap_or_else(|| panic!("no Poseidon parameters for arity {arity}"))
}