Skip to content

Commit deeac92

Browse files
authored
Merge pull request #532 from qfall/set_modulus
Add `change_modulus` and `change_q`
2 parents df76b5c + 561b17f commit deeac92

8 files changed

Lines changed: 641 additions & 14 deletions

File tree

src/integer_mod_q/mat_polynomial_ring_zq/set.rs

Lines changed: 176 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//! Implementation to set elements of a [`MatPolynomialRingZq`] matrix.
1010
1111
use super::MatPolynomialRingZq;
12-
use crate::integer_mod_q::PolynomialRingZq;
12+
use crate::integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolynomialRingZq};
1313
use crate::macros::for_others::implement_for_owned;
1414
use crate::traits::{MatrixSetSubmatrix, MatrixSwaps};
1515
use crate::{error::MathError, integer::PolyOverZ, traits::MatrixSetEntry};
@@ -381,6 +381,60 @@ impl MatPolynomialRingZq {
381381
pub fn reverse_rows(&mut self) {
382382
self.matrix.reverse_rows()
383383
}
384+
385+
/// Changes the modulus of the given matrix to the new modulus.
386+
/// It takes the representation of each entry with coefficients in [0, q) as the new
387+
/// matrix entries and reduces them by the new [`ModulusPolynomialRingZq`].
388+
///
389+
/// Parameters:
390+
/// - `modulus`: the new modulus of the matrix
391+
///
392+
/// # Examples
393+
/// ```
394+
/// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
395+
/// use std::str::FromStr;
396+
/// let modulus0 = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
397+
/// let modulus1 = ModulusPolynomialRingZq::from_str("3 1 0 1 mod 19").unwrap();
398+
///
399+
/// let mut matrix = MatPolynomialRingZq::new(4, 3, modulus0);
400+
///
401+
/// matrix.change_modulus(modulus1);
402+
/// ```
403+
///
404+
/// # Panics ...
405+
/// - if `modulus` is smaller than `2`, or
406+
/// - if the modulus polynomial is of degree smaller than `1`.
407+
/// - if the leading coefficient is not `1.`
408+
pub fn change_modulus(&mut self, modulus: impl Into<ModulusPolynomialRingZq>) {
409+
self.modulus = modulus.into();
410+
self.reduce();
411+
}
412+
413+
/// Changes the modulus `q` of the given matrix to the new modulus `q`.
414+
/// It takes the representation of each entry with coefficients in `[0, q)` as the new
415+
/// matrix entries and reduces them by the new [`Modulus`].
416+
///
417+
/// Parameters:
418+
/// - `q`: the new modulus of the matrix
419+
///
420+
/// # Examples
421+
/// ```
422+
/// use qfall_math::integer_mod_q::{MatPolynomialRingZq, ModulusPolynomialRingZq};
423+
/// use std::str::FromStr;
424+
///
425+
/// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
426+
///
427+
/// let mut matrix = MatPolynomialRingZq::new(4, 3, modulus);
428+
///
429+
/// matrix.change_q(19);
430+
/// ```
431+
///
432+
/// # Panics ...
433+
/// - if `modulus` is smaller than `2`.
434+
pub fn change_q(&mut self, q: impl Into<Modulus>) {
435+
self.modulus.change_q(q);
436+
self.reduce();
437+
}
384438
}
385439

386440
#[cfg(test)]
@@ -1029,3 +1083,124 @@ mod test_set_submatrix {
10291083
assert!(mat1.set_submatrix(0, 0, &mat2.clone(), 0, 9, 0, 9).is_err());
10301084
}
10311085
}
1086+
1087+
#[cfg(test)]
1088+
mod test_change_modulus {
1089+
use super::MatPolynomialRingZq;
1090+
use crate::integer_mod_q::ModulusPolynomialRingZq;
1091+
use std::str::FromStr;
1092+
1093+
/// Ensures that the modulus is changed correctly.
1094+
#[test]
1095+
fn modulus_correct() {
1096+
let mut matrix = MatPolynomialRingZq::from_str(
1097+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 7",
1098+
)
1099+
.unwrap();
1100+
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 8").unwrap();
1101+
1102+
matrix.change_modulus(&modulus);
1103+
1104+
assert_eq!(
1105+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 8",
1106+
matrix.to_string()
1107+
);
1108+
}
1109+
1110+
/// Ensures that the modulus is changed correctly, if the modulus is big.
1111+
#[test]
1112+
fn big_modulus_correct() {
1113+
let mut matrix = MatPolynomialRingZq::from_str(&format!(
1114+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
1115+
i64::MAX
1116+
))
1117+
.unwrap();
1118+
let modulus =
1119+
ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {}", u64::MAX)).unwrap();
1120+
1121+
matrix.change_modulus(&modulus);
1122+
1123+
assert_eq!(
1124+
format!(
1125+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
1126+
u64::MAX
1127+
),
1128+
matrix.to_string()
1129+
);
1130+
}
1131+
1132+
/// Ensures that the matrix is reduced correctly.
1133+
#[test]
1134+
fn reduced_correct() {
1135+
let mut matrix = MatPolynomialRingZq::from_str(
1136+
"[[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",
1137+
)
1138+
.unwrap();
1139+
let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 2").unwrap();
1140+
1141+
matrix.change_modulus(&modulus);
1142+
1143+
assert_eq!(
1144+
"[[1 1, 0, 1 1],[0, 1 1, 0]] / 4 1 0 0 1 mod 2",
1145+
matrix.to_string()
1146+
);
1147+
}
1148+
}
1149+
1150+
#[cfg(test)]
1151+
mod test_change_q {
1152+
use super::MatPolynomialRingZq;
1153+
use std::str::FromStr;
1154+
1155+
/// Ensures that the modulus `q` is changed correctly.
1156+
#[test]
1157+
fn q_correct() {
1158+
let mut matrix = MatPolynomialRingZq::from_str(
1159+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 7",
1160+
)
1161+
.unwrap();
1162+
1163+
matrix.change_q(8);
1164+
1165+
assert_eq!(
1166+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod 8",
1167+
matrix.to_string()
1168+
);
1169+
}
1170+
1171+
/// Ensures that the modulus `q` is changed correctly, if the modulus is big.
1172+
#[test]
1173+
fn big_q_correct() {
1174+
let mut matrix = MatPolynomialRingZq::from_str(&format!(
1175+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
1176+
i64::MAX
1177+
))
1178+
.unwrap();
1179+
1180+
matrix.change_q(u64::MAX);
1181+
1182+
assert_eq!(
1183+
format!(
1184+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 1 6]] / 4 1 0 0 1 mod {}",
1185+
u64::MAX
1186+
),
1187+
matrix.to_string()
1188+
);
1189+
}
1190+
1191+
/// Ensures that the matrix is reduced correctly.
1192+
#[test]
1193+
fn reduced_correct() {
1194+
let mut matrix = MatPolynomialRingZq::from_str(
1195+
"[[1 1, 1 2, 1 3],[1 4, 1 5, 4 1 0 0 1]] / 4 1 0 0 1 mod 7",
1196+
)
1197+
.unwrap();
1198+
1199+
matrix.change_q(2);
1200+
1201+
assert_eq!(
1202+
"[[1 1, 0, 1 1],[0, 1 1, 0]] / 4 1 0 0 1 mod 2",
1203+
matrix.to_string()
1204+
);
1205+
}
1206+
}

src/integer_mod_q/modulus_polynomial_ring_zq.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,12 @@ mod norm;
2222
mod ntt_basis;
2323
mod ownership;
2424
mod serialize;
25+
mod set;
2526
mod to_string;
2627

2728
/// [`ModulusPolynomialRingZq`] represents the modulus object for
28-
/// [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq)
29+
/// [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq).
30+
/// The underlying polynomials need to be monic, i.e. the leading coefficient needs to be `1`.
2931
///
3032
/// Attributes
3133
/// - `modulus`: holds the specific content, i.e. the modulus `q` and f(X)

src/integer_mod_q/modulus_polynomial_ring_zq/from.rs

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ impl<Mod: Into<Modulus>> From<(&PolyOverZ, Mod)> for ModulusPolynomialRingZq {
4747
///
4848
/// # Panics ...
4949
/// - if `modulus` is smaller than `2`, or
50-
/// - if the degree of the polynomial is smaller than `1`.
50+
/// - if the modulus polynomial is of degree smaller than `1`.
51+
/// - if the leading coefficient is not `1.`
5152
fn from((poly, modulus): (&PolyOverZ, Mod)) -> Self {
5253
let poly_zq = PolyOverZq::from((poly, modulus));
5354

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

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

9799
impl From<&PolyOverZq> for ModulusPolynomialRingZq {
98100
/// Creates a Modulus object of type [`ModulusPolynomialRingZq`]
99-
/// for [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq)
101+
/// for [`PolynomialRingZq`](crate::integer_mod_q::PolynomialRingZq).
102+
/// It requires that the leading coefficient is `1`.
100103
///
101104
/// Parameters:
102105
/// - `poly`: the polynomial which is used as the modulus.
@@ -117,15 +120,12 @@ impl From<&PolyOverZq> for ModulusPolynomialRingZq {
117120
/// # Panics ...
118121
/// - if `modulus` is smaller than `2`, or
119122
/// - if the modulus polynomial is of degree smaller than `1`.
123+
/// - if the leading coefficient is not `1.`
120124
fn from(poly: &PolyOverZq) -> Self {
121125
check_poly_mod(poly).unwrap();
122-
let mut non_zero = Vec::new();
123-
for i in 0..poly.get_degree() {
124-
let coeff: Z = poly.get_coeff(i).unwrap();
125-
if coeff != 0 {
126-
non_zero.push(i.try_into().unwrap());
127-
}
128-
}
126+
127+
let non_zero = non_zero_positions(poly);
128+
129129
Self {
130130
modulus: Rc::new(poly.clone()),
131131
ntt_basis: Rc::new(None),
@@ -192,6 +192,7 @@ impl FromStr for ModulusPolynomialRingZq {
192192
/// [`InvalidModulus`](MathError::InvalidModulus)
193193
/// - if `modulus` is smaller than `2`, or
194194
/// - if the modulus polynomial is of degree smaller than `1`.
195+
/// - if the leading coefficient is not `1`.
195196
fn from_str(s: &str) -> Result<Self, Self::Err> {
196197
let poly_zq = PolyOverZq::from_str(s)?;
197198

@@ -201,6 +202,33 @@ impl FromStr for ModulusPolynomialRingZq {
201202
}
202203
}
203204

205+
/// Fills a vector with the position of all non-zero coefficients in a [`PolyOverZq`] except the leading coefficient.
206+
///
207+
/// Parameters:
208+
/// - `poly`: defines the polynomial whose positions of non-zero coefficients are output
209+
///
210+
/// Returns a [`Vec<usize>`] containing the positions of all non-zero coefficients except the leading coefficient.
211+
///
212+
/// # Examples
213+
/// ```compile_fail
214+
/// use qfall_math::integer_mod_q::PolyOverZq;
215+
/// use std::str::FromStr;
216+
///
217+
/// let poly_zq = PolyOverZq::from_str("4 1 0 0 1 mod 17").unwrap();
218+
///
219+
/// let non_zero = non_zero_positions(&poly_zq);
220+
/// ```
221+
pub(crate) fn non_zero_positions(poly: &PolyOverZq) -> Vec<usize> {
222+
let mut non_zero = Vec::new();
223+
for i in 0..poly.get_degree() {
224+
let coeff: Z = poly.get_coeff(i).unwrap();
225+
if coeff != 0 {
226+
non_zero.push(i.try_into().unwrap());
227+
}
228+
}
229+
non_zero
230+
}
231+
204232
/// Checks weather a given [`PolyOverZq`] can be used as a [`ModulusPolynomialRingZq`].
205233
/// It requires that the leading coefficient is `1`.
206234
///
@@ -223,6 +251,9 @@ impl FromStr for ModulusPolynomialRingZq {
223251
/// - Returns a [`MathError`] of type
224252
/// [`InvalidModulus`](MathError::InvalidModulus)
225253
/// if the modulus polynomial is of degree less than `1`.
254+
/// - Returns a [`MathError`] of type
255+
/// [`InvalidModulus`](MathError::InvalidModulus)
256+
/// if the leading coefficient is not `1`.
226257
pub(crate) fn check_poly_mod(poly_zq: &PolyOverZq) -> Result<(), MathError> {
227258
let leading_coefficient: Z = poly_zq.get_coeff(poly_zq.get_degree())?;
228259
if poly_zq.get_degree() < 1 {
@@ -343,6 +374,15 @@ mod test_try_from_poly_zq {
343374

344375
let _ = ModulusPolynomialRingZq::from(poly);
345376
}
377+
378+
/// Ensure that the function panics if the leading coefficient is not `1`
379+
#[test]
380+
#[should_panic]
381+
fn panic_leading_coefficient() {
382+
let poly = PolyOverZq::from_str("2 1 2 mod 10").unwrap();
383+
384+
let _ = ModulusPolynomialRingZq::from(poly);
385+
}
346386
}
347387

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

0 commit comments

Comments
 (0)