Skip to main content

qfall_math/integer_mod_q/modulus_polynomial_ring_zq/
set.rs

1// Copyright 2026 Jan Niklas Siemer
2//
3// This file is part of qFALL-math.
4//
5// qFALL-math is free software: you can redistribute it and/or modify it under
6// the terms of the Mozilla Public License Version 2.0 as published by the
7// Mozilla Foundation. See <https://mozilla.org/en-US/MPL/2.0/>.
8
9//! Implementations to manipulate a [`ModulusPolynomialRingZq`].
10
11use crate::integer_mod_q::{
12    Modulus, ModulusPolynomialRingZq, PolyOverZq,
13    modulus_polynomial_ring_zq::from::non_zero_positions,
14};
15use std::rc::Rc;
16
17impl ModulusPolynomialRingZq {
18    /// Changes the modulus `q` of the given [`ModulusPolynomialRingZq`] to the new modulus `q`
19    /// and resets all NTT-related attributes.
20    /// It takes the representation of each coefficient in [0, q) as the new
21    /// coefficients and reduces them by the new [`Modulus`].
22    ///
23    /// Parameters:
24    /// - `modulus`: the new modulus `q`
25    ///
26    /// # Examples
27    /// ```
28    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
29    /// use std::str::FromStr;
30    ///
31    /// let mut poly = ModulusPolynomialRingZq::from_str("4  5 3 7 1 mod 13").unwrap();
32    ///
33    /// poly.change_q(5);
34    ///
35    /// assert_eq!(ModulusPolynomialRingZq::from_str("4  0 3 2 1 mod 5").unwrap(), poly);
36    /// ```
37    ///
38    /// # Panics ...
39    /// - if `modulus` is smaller than `2`.
40    pub fn change_q(&mut self, modulus: impl Into<Modulus>) {
41        self.ntt_basis = Rc::new(None);
42
43        let new_poly_zq =
44            PolyOverZq::from((self.get_representative_least_nonnegative_residue(), modulus));
45        self.non_zero = non_zero_positions(&new_poly_zq);
46
47        self.modulus = Rc::new(new_poly_zq);
48    }
49}
50
51#[cfg(test)]
52mod test_change_q {
53    use super::ModulusPolynomialRingZq;
54    use crate::integer_mod_q::Modulus;
55    use std::str::FromStr;
56
57    /// Ensures that the modulus is changed correctly.
58    #[test]
59    fn q_correct() {
60        let mut modulus = ModulusPolynomialRingZq::from_str("6  1 2 3 4 5 1 mod 7").unwrap();
61        let q = Modulus::from(8);
62
63        modulus.change_q(&q);
64
65        assert_eq!("6  1 2 3 4 5 1 mod 8", modulus.to_string());
66    }
67
68    /// Ensures that the modulus is changed correctly, if the modulus is big.
69    #[test]
70    fn big_q_correct() {
71        let mut modulus =
72            ModulusPolynomialRingZq::from_str(&format!("6  1 2 3 4 5 1 mod {}", i64::MAX)).unwrap();
73        let q = Modulus::from(u64::MAX);
74
75        modulus.change_q(&q);
76
77        assert_eq!(
78            format!("6  1 2 3 4 5 1 mod {}", u64::MAX),
79            modulus.to_string()
80        );
81    }
82
83    /// Ensures that the poly is reduced correctly.
84    #[test]
85    fn reduced_correct() {
86        let mut modulus = ModulusPolynomialRingZq::from_str("6  1 2 3 4 5 1 mod 7").unwrap();
87        let q = Modulus::from(2);
88
89        modulus.change_q(&q);
90
91        assert_eq!("6  1 0 1 0 1 1 mod 2", modulus.to_string());
92    }
93
94    /// Ensures that all NTT-related attributes are reset.
95    #[test]
96    fn reset_ntt_values() {
97        let mut modulus = ModulusPolynomialRingZq::from_str("6  1 2 3 4 5 1 mod 7").unwrap();
98        let q = Modulus::from(2);
99
100        modulus.change_q(&q);
101
102        assert_eq!(vec![0, 2, 4], modulus.non_zero);
103        assert!(modulus.ntt_basis.is_none());
104    }
105}