Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 176 additions & 1 deletion src/integer_mod_q/mat_polynomial_ring_zq/set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
//! Implementation to set elements of a [`MatPolynomialRingZq`] matrix.

use super::MatPolynomialRingZq;
use crate::integer_mod_q::PolynomialRingZq;
use crate::integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolynomialRingZq};
use crate::macros::for_others::implement_for_owned;
use crate::traits::{MatrixSetSubmatrix, MatrixSwaps};
use crate::{error::MathError, integer::PolyOverZ, traits::MatrixSetEntry};
Expand Down Expand Up @@ -381,6 +381,60 @@ impl MatPolynomialRingZq {
pub fn reverse_rows(&mut self) {
self.matrix.reverse_rows()
}

/// Changes the modulus of the given matrix to the new modulus.
/// It takes the representation of each entry with coefficients in [0, q) as the new
/// matrix entries and reduces them by the new [`ModulusPolynomialRingZq`].
///
/// Parameters:
/// - `modulus`: the new modulus of the matrix
///
/// # Examples
/// ```
/// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
/// use std::str::FromStr;
/// let modulus0 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
/// let modulus1 = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 19").unwrap();
///
/// let mut matrix = MatPolynomialRingZq::new(4, 3, modulus0);
///
/// matrix.change_modulus(modulus1);
/// ```
///
/// # Panics ...
/// - if `modulus` is smaller than `2`, or
/// - if the modulus polynomial is of degree smaller than `1`.
/// - if the leading coefficient is not `1.`
pub fn change_modulus(&mut self, modulus: impl Into<ModulusPolynomialRingZq>) {
self.modulus = modulus.into();
self.reduce();
}

/// Changes the modulus `q` of the given matrix to the new modulus `q`.
/// It takes the representation of each entry with coefficients in `[0, q)` as the new
/// matrix entries and reduces them by the new [`Modulus`].
///
/// Parameters:
/// - `q`: the new modulus of the matrix
///
/// # Examples
/// ```
/// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
/// use std::str::FromStr;
///
/// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
///
/// let mut matrix = MatPolynomialRingZq::new(4, 3, modulus);
///
/// matrix.change_q(19);
/// ```
///
/// # Panics ...
/// - if `modulus` is smaller than `2`.
pub fn change_q(&mut self, q: impl Into<Modulus>) {
self.modulus.change_q(q);
self.reduce();
}
}

#[cfg(test)]
Expand Down Expand Up @@ -1029,3 +1083,124 @@ mod test_set_submatrix {
assert!(mat1.set_submatrix(0, 0, &mat2.clone(), 0, 9, 0, 9).is_err());
}
}

#[cfg(test)]
mod test_change_modulus {
use super::MatPolynomialRingZq;
use crate::integer_mod_q::ModulusPolynomialRingZq;
use std::str::FromStr;

/// Ensures that the modulus is changed correctly.
#[test]
fn modulus_correct() {
let mut matrix = MatPolynomialRingZq::from_str(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 7",
)
.unwrap();
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 8").unwrap();

matrix.change_modulus(&modulus);

assert_eq!(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 8",
matrix.to_string()
);
}

/// Ensures that the modulus is changed correctly, if the modulus is big.
#[test]
fn big_modulus_correct() {
let mut matrix = MatPolynomialRingZq::from_str(&format!(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
i64::MAX
))
.unwrap();
let modulus =
ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();

matrix.change_modulus(&modulus);

assert_eq!(
format!(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
u64::MAX
),
matrix.to_string()
);
}

/// Ensures that the matrix is reduced correctly.
#[test]
fn reduced_correct() {
let mut matrix = MatPolynomialRingZq::from_str(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 4 1 0 0 1]] / 8 1 0 0 0 0 0 0 1 mod 7",
)
.unwrap();
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 2").unwrap();

matrix.change_modulus(&modulus);

assert_eq!(
"[[1 1, 0, 1 1],[0, 1 1, 0]] / 4 1 0 0 1 mod 2",
matrix.to_string()
);
}
}

#[cfg(test)]
mod test_change_q {
use super::MatPolynomialRingZq;
use std::str::FromStr;

/// Ensures that the modulus `q` is changed correctly.
#[test]
fn q_correct() {
let mut matrix = MatPolynomialRingZq::from_str(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 7",
)
.unwrap();

matrix.change_q(8);

assert_eq!(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 8",
matrix.to_string()
);
}

/// Ensures that the modulus `q` is changed correctly, if the modulus is big.
#[test]
fn big_q_correct() {
let mut matrix = MatPolynomialRingZq::from_str(&format!(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
i64::MAX
))
.unwrap();

matrix.change_q(u64::MAX);

assert_eq!(
format!(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
u64::MAX
),
matrix.to_string()
);
}

/// Ensures that the matrix is reduced correctly.
#[test]
fn reduced_correct() {
let mut matrix = MatPolynomialRingZq::from_str(
"[[1 1, 1 2, 1 3],[1 4, 1 5, 4 1 0 0 1]] / 4 1 0 0 1 mod 7",
)
.unwrap();

matrix.change_q(2);

assert_eq!(
"[[1 1, 0, 1 1],[0, 1 1, 0]] / 4 1 0 0 1 mod 2",
matrix.to_string()
);
}
}
4 changes: 3 additions & 1 deletion src/integer_mod_q/modulus_polynomial_ring_zq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,12 @@ mod norm;
mod ntt_basis;
mod ownership;
mod serialize;
mod set;
mod to_string;

/// [`ModulusPolynomialRingZq`] represents the modulus object for
/// [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq)
/// [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq).
/// The underlying polynomials need to be monic, i.e. the leading coefficient needs to be `1`.
///
/// Attributes
/// - `modulus`: holds the specific content, i.e. the modulus `q` and f(X)
Expand Down
58 changes: 49 additions & 9 deletions src/integer_mod_q/modulus_polynomial_ring_zq/from.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ impl<Mod: Into<Modulus>> From<(&PolyOverZ, Mod)> for ModulusPolynomialRingZq {
///
/// # Panics ...
/// - if `modulus` is smaller than `2`, or
/// - if the degree of the polynomial is smaller than `1`.
/// - if the modulus polynomial is of degree smaller than `1`.
/// - if the leading coefficient is not `1.`
fn from((poly, modulus): (&PolyOverZ, Mod)) -> Self {
let poly_zq = PolyOverZq::from((poly, modulus));

Expand Down Expand Up @@ -85,6 +86,7 @@ impl<Mod: Into<Modulus>> From<(PolyOverZ, Mod)> for ModulusPolynomialRingZq {
/// # Panics ...
/// - if `modulus` is smaller than `2`, or
/// - if the modulus polynomial is of degree smaller than `1`.
/// - if the leading coefficient is not `1.`
fn from((poly, modulus): (PolyOverZ, Mod)) -> Self {
let poly_zq = PolyOverZq::from((poly, modulus));

Expand All @@ -96,7 +98,8 @@ impl<Mod: Into<Modulus>> From<(PolyOverZ, Mod)> for ModulusPolynomialRingZq {

impl From<&PolyOverZq> for ModulusPolynomialRingZq {
/// Creates a Modulus object of type [`ModulusPolynomialRingZq`]
/// for [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq)
/// for [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq).
/// It requires that the leading coefficient is `1`.
///
/// Parameters:
/// - `poly`: the polynomial which is used as the modulus.
Expand All @@ -117,15 +120,12 @@ impl From<&PolyOverZq> for ModulusPolynomialRingZq {
/// # Panics ...
/// - if `modulus` is smaller than `2`, or
/// - if the modulus polynomial is of degree smaller than `1`.
/// - if the leading coefficient is not `1.`
fn from(poly: &PolyOverZq) -> Self {
check_poly_mod(poly).unwrap();
let mut non_zero = Vec::new();
for i in 0..poly.get_degree() {
let coeff: Z = poly.get_coeff(i).unwrap();
if coeff != 0 {
non_zero.push(i.try_into().unwrap());
}
}

let non_zero = non_zero_positions(poly);

Self {
modulus: Rc::new(poly.clone()),
ntt_basis: Rc::new(None),
Expand Down Expand Up @@ -192,6 +192,7 @@ impl FromStr for ModulusPolynomialRingZq {
/// [`InvalidModulus`](MathError::InvalidModulus)
/// - if `modulus` is smaller than `2`, or
/// - if the modulus polynomial is of degree smaller than `1`.
/// - if the leading coefficient is not `1`.
fn from_str(s: &str) -> Result<Self, Self::Err> {
let poly_zq = PolyOverZq::from_str(s)?;

Expand All @@ -201,6 +202,33 @@ impl FromStr for ModulusPolynomialRingZq {
}
}

/// Fills a vector with the position of all non-zero coefficients in a [`PolyOverZq`].
///
/// Parameters:
/// - `poly`: defines the polynomial whose positions of non-zero coefficients are output
///
/// Returns a [`Vec<usize>`] containing the positions of all non-zero coefficients.
///
/// # Examples
/// ```compile_fail
/// use qfall_math::integer_mod_q::PolyOverZq;
/// use std::str::FromStr;
///
/// let poly_zq = PolyOverZq::from_str("4 1 0 0 1 mod 17").unwrap();
///
/// let non_zero = non_zero_positions(&poly_zq);
/// ```
pub(crate) fn non_zero_positions(poly: &PolyOverZq) -> Vec<usize> {
let mut non_zero = Vec::new();
for i in 0..=poly.get_degree() {
let coeff: Z = poly.get_coeff(i).unwrap();
if coeff != 0 {
non_zero.push(i.try_into().unwrap());
}
}
non_zero
}

/// Checks weather a given [`PolyOverZq`] can be used as a [`ModulusPolynomialRingZq`].
/// It requires that the leading coefficient is `1`.
///
Expand All @@ -223,6 +251,9 @@ impl FromStr for ModulusPolynomialRingZq {
/// - Returns a [`MathError`] of type
/// [`InvalidModulus`](MathError::InvalidModulus)
/// if the modulus polynomial is of degree less than `1`.
/// - Returns a [`MathError`] of type
/// [`InvalidModulus`](MathError::InvalidModulus)
/// if the leading coefficient is not `1`.
pub(crate) fn check_poly_mod(poly_zq: &PolyOverZq) -> Result<(), MathError> {
let leading_coefficient: Z = poly_zq.get_coeff(poly_zq.get_degree())?;
if poly_zq.get_degree() < 1 {
Expand Down Expand Up @@ -343,6 +374,15 @@ mod test_try_from_poly_zq {

let _ = ModulusPolynomialRingZq::from(poly);
}

/// Ensure that the function panics if the leading coefficient is not `1`
#[test]
#[should_panic]
fn panic_leading_coefficient() {
let poly = PolyOverZq::from_str("2 1 2 mod 10").unwrap();

let _ = ModulusPolynomialRingZq::from(poly);
}
}

/// most tests with specific values are covered in [`PolyOverZq`](crate::integer_mod_q::PolyOverZq)
Expand Down
Loading
Loading