use super::params::N;
pub struct SmallPoly {
pub coeffs: [i16; N],
}
impl SmallPoly {
pub const fn zero() -> Self {
Self { coeffs: [0i16; N] }
}
pub fn from_i32(src: &[i32; N]) -> Self {
let mut s = Self::zero();
for i in 0..N {
s.coeffs[i] = src[i] as i16;
}
s
}
}
pub fn small_ntt(p: &mut SmallPoly) {
crate::ml_kem::ntt::ntt(&mut p.coeffs);
}
pub fn small_invntt(p: &mut SmallPoly) {
crate::ml_kem::ntt::ntt_inv(&mut p.coeffs);
}
pub fn small_basemul(out: &mut SmallPoly, a: &SmallPoly, b: &SmallPoly) {
crate::ml_kem::ntt::multiply_ntts(&a.coeffs, &b.coeffs, &mut out.coeffs);
}
pub fn small_basemul_acc(out: &mut SmallPoly, a: &SmallPoly, b: &SmallPoly) {
let mut tmp = [0i16; N];
crate::ml_kem::ntt::multiply_ntts(&a.coeffs, &b.coeffs, &mut tmp);
for i in 0..N {
out.coeffs[i] = crate::ml_kem::ntt::barrett_reduce(out.coeffs[i].wrapping_add(tmp[i]));
}
}
pub fn small_basemul_invntt_widen(a: &SmallPoly, b: &SmallPoly) -> [i32; N] {
let mut tmp = SmallPoly::zero();
small_basemul(&mut tmp, a, b);
small_invntt(&mut tmp);
let mut out = [0i32; N];
for i in 0..N {
out[i] = tmp.coeffs[i] as i32;
}
out
}
#[cfg(test)]
mod tests {
use super::super::ntt as dsa_ntt;
use super::super::params::Q;
use super::*;
#[test]
fn small_mul_matches_full_ntt() {
let mut c_i32 = [0i32; N];
for i in (N - 39)..N {
c_i32[i] = if i % 3 == 0 { -1 } else { 1 };
}
let mut s_i32 = [0i32; N];
for i in 0..N {
s_i32[i] = ((i as i32 * 7 + 3) % 5) - 2; }
let mut c_ntt = c_i32;
for c in c_ntt.iter_mut() {
*c = dsa_ntt::mod_q(*c);
}
dsa_ntt::ntt(&mut c_ntt);
let mut s_ntt = s_i32;
for c in s_ntt.iter_mut() {
*c = dsa_ntt::mod_q(*c);
}
dsa_ntt::ntt(&mut s_ntt);
let mut prod_full = dsa_ntt::pointwise_mul(&c_ntt, &s_ntt);
dsa_ntt::ntt_inv(&mut prod_full);
for c in prod_full.iter_mut() {
*c = dsa_ntt::mod_q(*c);
}
let c_small = SmallPoly::from_i32(&c_i32);
let s_small = SmallPoly::from_i32(&s_i32);
let mut c_small_ntt = c_small;
small_ntt(&mut c_small_ntt);
let mut s_small_ntt = s_small;
small_ntt(&mut s_small_ntt);
let prod_small = small_basemul_invntt_widen(&c_small_ntt, &s_small_ntt);
for i in 0..N {
let expected = dsa_ntt::mod_q(prod_full[i]);
let got_raw = prod_small[i];
let got = dsa_ntt::mod_q(got_raw);
assert_eq!(
got, expected,
"mismatch at i={}: small={} (raw={}), full={}",
i, got, got_raw, expected
);
}
}
}