use super::MatNTTPolynomialRingZq;
use crate::{
integer::Z,
integer_mod_q::{MatPolynomialRingZq, NTTPolynomialRingZq, PolynomialRingZq},
traits::{MatrixDimensions, MatrixGetEntry, MatrixSetEntry},
};
impl From<&MatPolynomialRingZq> for MatNTTPolynomialRingZq {
fn from(matrix: &MatPolynomialRingZq) -> Self {
let degree = matrix.get_mod().get_degree();
let nr_rows = matrix.get_num_rows();
let nr_columns = matrix.get_num_columns();
let mut res = Vec::with_capacity((degree * nr_rows * nr_columns) as usize);
for col in 0..nr_columns {
for row in 0..nr_rows {
let entry = unsafe { matrix.get_entry_unchecked(row, col) };
let mut ntt_poly = NTTPolynomialRingZq::from(&entry);
res.append(&mut ntt_poly.poly);
}
}
MatNTTPolynomialRingZq {
matrix: res,
nr_rows: nr_rows as usize,
nr_columns: nr_columns as usize,
modulus: matrix.modulus.clone(),
}
}
}
impl MatNTTPolynomialRingZq {
pub fn inv_ntt(mut self) -> MatPolynomialRingZq {
let height = self.nr_rows;
let width = self.nr_columns;
let mut res = MatPolynomialRingZq::new(height, width, &self.modulus);
for column in (0..width).rev() {
for row in (0..height).rev() {
let index = self.modulus.get_degree() as usize * row
+ self.modulus.get_degree() as usize * self.nr_rows * column;
let entry = PolynomialRingZq::from(NTTPolynomialRingZq {
poly: self.matrix.split_off(index).iter().map(Z::from).collect(),
modulus: self.modulus.clone(),
});
unsafe { res.set_entry_unchecked(row as i64, column as i64, entry) };
}
}
res
}
}
#[cfg(test)]
mod test_from {
use super::MatNTTPolynomialRingZq;
use crate::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
use std::str::FromStr;
#[test]
fn round_trip() {
let mut modulus = ModulusPolynomialRingZq::from_str("5 1 0 0 0 1 mod 257").unwrap();
modulus.set_ntt_unchecked(64);
let matrix = MatPolynomialRingZq::sample_uniform(3, 5, &modulus);
let ntt_matrix = MatNTTPolynomialRingZq::from(&matrix);
let cmp_matrix = MatPolynomialRingZq::from(ntt_matrix);
assert_eq!(matrix, cmp_matrix);
}
}