use crate::modular::mod_pow;
#[derive(Debug, Clone, Copy)]
pub struct Params {
pub n: usize,
pub q: u64,
pub sigma_x1000: u64,
pub t: u64,
}
impl Params {
pub fn research_2048() -> Self {
Self {
n: 2048,
q: 132120577,
sigma_x1000: 3200, t: 65537, }
}
pub fn test_small() -> Self {
Self {
n: 256,
q: 12289,
sigma_x1000: 1000, t: 17, }
}
pub fn test_tiny() -> Self {
Self {
n: 64,
q: 769,
sigma_x1000: 1000, t: 5,
}
}
pub fn ntt_root(&self) -> u64 {
let two_n = (2 * self.n) as u64;
assert!(
(self.q - 1) % two_n == 0,
"q - 1 = {} is not divisible by 2N = {two_n}",
self.q - 1
);
let exp = (self.q - 1) / two_n;
for g in 2..self.q {
let w = mod_pow(g, exp, self.q);
if w != 1 && mod_pow(w, self.n as u64, self.q) != 1 {
let wn = mod_pow(w, self.n as u64, self.q);
if wn == self.q - 1 {
return w;
}
}
}
panic!("no primitive 2N-th root of unity found");
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_tiny_root() {
let p = Params::test_tiny();
let w = p.ntt_root();
let wn = mod_pow(w, p.n as u64, p.q);
assert_eq!(wn, p.q - 1, "w^N should equal -1 mod q");
let w2n = mod_pow(w, (2 * p.n) as u64, p.q);
assert_eq!(w2n, 1, "w^(2N) should equal 1 mod q");
}
#[test]
fn test_small_root() {
let p = Params::test_small();
let w = p.ntt_root();
let wn = mod_pow(w, p.n as u64, p.q);
assert_eq!(wn, p.q - 1);
}
}