const PRIME_BITLEN: usize = 256;
const M: usize = 128;
#[inline]
const fn n_sboxes(t: usize, rf: usize, rp: usize) -> usize {
t * rf + rp
}
pub(crate) fn round_numbers_base(arity: usize) -> (usize, usize) {
let t = arity + 1;
calc_round_numbers(t, true)
}
pub(crate) fn round_numbers_strengthened(arity: usize) -> (usize, usize) {
let (full_round, partial_rounds) = round_numbers_base(arity);
let strengthened_partial_rounds = f64::ceil(partial_rounds as f64 * 1.25) as usize;
(full_round, strengthened_partial_rounds)
}
pub(crate) fn calc_round_numbers(t: usize, security_margin: bool) -> (usize, usize) {
let mut rf = 0;
let mut rp = 0;
let mut n_sboxes_min = usize::MAX;
for mut rf_test in (2..=1000).step_by(2) {
for mut rp_test in 4..200 {
if round_numbers_are_secure(t, rf_test, rp_test) {
if security_margin {
rf_test += 2;
rp_test = (1.075 * rp_test as f32).ceil() as usize;
}
let n_sboxes = n_sboxes(t, rf_test, rp_test);
if n_sboxes < n_sboxes_min || (n_sboxes == n_sboxes_min && rf_test < rf) {
rf = rf_test;
rp = rp_test;
n_sboxes_min = n_sboxes;
}
}
}
}
(rf, rp)
}
fn round_numbers_are_secure(t: usize, rf: usize, rp: usize) -> bool {
let (rp, t, n, m) = (rp as f32, t as f32, PRIME_BITLEN as f32, M as f32);
let rf_stat = if m <= (n - 3.0) * (t + 1.0) {
6.0
} else {
10.0
};
let rf_interp = 0.43 * m + t.log2() - rp;
let rf_grob_1 = 0.21 * n - rp;
let rf_grob_2 = (0.14 * n - 1.0 - rp) / (t - 1.0);
let rf_max = [rf_stat, rf_interp, rf_grob_1, rf_grob_2]
.iter()
.map(|rf| rf.ceil() as usize)
.max()
.unwrap();
rf >= rf_max
}