use crate::helpers::full_reduce32;
use crate::types::{Zq, R};
use crate::{D, Q};
pub(crate) fn power2round<const K: usize>(r: &[R; K]) -> ([R; K], [R; K]) {
debug_assert!(
r.iter().flat_map(|row| row.0).all(|element| (0..Q).contains(&element)),
"power2round input"
);
let r_1: [R; K] = core::array::from_fn(|k| {
R(core::array::from_fn(|n| (r[k].0[n] + (1 << (D - 1)) - 1) >> D))
});
let r_0: [R; K] =
core::array::from_fn(|k| R(core::array::from_fn(|n| r[k].0[n] - (r_1[k].0[n] << D))));
debug_assert!(
{
let mut result = true;
for k in 0..K {
for n in 0..256 {
result &= r[k].0[n] == ((r_1[k].0[n] << D) + r_0[k].0[n]);
}
}
result
},
"Alg 35: fails"
);
(r_1, r_0)
}
pub(crate) fn decompose(gamma2: i32, r: Zq) -> (Zq, Zq) {
let rp = full_reduce32(r);
let mut xr1;
if gamma2 & (1 << 17) == 0 {
xr1 = (rp + 127) >> 7;
xr1 = (xr1 * 11275 + (1 << 23)) >> 24;
xr1 ^= ((43 - xr1) >> 31) & xr1;
} else {
xr1 = (rp + 127) >> 7;
xr1 = (xr1 * 1025 + (1 << 21)) >> 22;
xr1 &= 15;
}
let xr0 = rp - xr1 * 2 * gamma2;
let xr0 = xr0 - ((((Q - 1) / 2 - xr0) >> 31) & Q);
debug_assert_eq!(r.rem_euclid(Q), (xr1 * 2 * gamma2 + xr0).rem_euclid(Q), "Alg 36: fails");
(xr1, xr0)
}
pub(crate) fn high_bits(gamma2: i32, r: Zq) -> Zq {
let (r1, _r0) = decompose(gamma2, r);
r1
}
pub(crate) fn low_bits(gamma2: i32, r: Zq) -> Zq {
let (_r1, r0) = decompose(gamma2, r);
r0
}
pub(crate) fn make_hint(gamma2: i32, z: Zq, r: Zq) -> bool {
let r1 = high_bits(gamma2, r);
let v1 = high_bits(gamma2, r + z);
r1 != v1
}
pub(crate) fn use_hint(gamma2: i32, h: Zq, r: Zq) -> Zq {
let (r1, r0) = decompose(gamma2, r);
if h == 0 {
return r1;
}
if gamma2 & (1 << 17) == 0 {
if r0 > 0 {
if r1 == 43 {
return 0;
}
return r1 + 1;
} if r1 == 0 {
return 43;
}
r1 - 1
} else {
if r0 > 0 {
return (r1 + 1) & 15;
} (r1 - 1) & 15
}
}