qfall_math/integer_mod_q/polynomial_ring_zq/
properties.rs

1// Copyright © 2024 Marcel Luca Schmidt
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 check certain properties of [`PolynomialRingZq`].
10//! This includes checks such as reducibility.
11
12use super::PolynomialRingZq;
13use crate::integer_mod_q::{NTTPolynomialRingZq, PolyOverZq};
14
15impl PolynomialRingZq {
16    /// Checks if a [`PolynomialRingZq`] is irreducible.
17    ///
18    /// Returns `true` if the polynomial is irreducible and `false` otherwise.
19    ///
20    /// # Examples
21    /// ```
22    /// use qfall_math::integer_mod_q::PolynomialRingZq;
23    /// use std::str::FromStr;
24    ///
25    /// let poly_irr = PolynomialRingZq::from_str("2  1 1 / 3  1 2 3 mod 17").unwrap();
26    /// // returns true, since X + 1 is irreducible
27    /// assert!(poly_irr.is_irreducible());
28    /// ```
29    pub fn is_irreducible(&self) -> bool {
30        let poly_over_zq = PolyOverZq::from((&self.poly, self.modulus.get_q()));
31
32        // Since after reduction with the polynomial modulus, the check of
33        // irreducibility is the same as without the polynomial modulus
34        poly_over_zq.is_irreducible()
35    }
36
37    /// Checks if a [`PolynomialRingZq`] is the constant polynomial with coefficient `1`.
38    ///
39    /// Returns `true` if there is only one coefficient, which is `1`.
40    ///
41    /// # Examples
42    /// ```
43    /// use qfall_math::integer_mod_q::PolynomialRingZq;
44    /// use std::str::FromStr;
45    ///
46    /// let value = PolynomialRingZq::from_str("1  1 / 3  1 0 1 mod 4").unwrap();
47    /// assert!(value.is_one());
48    /// ```
49    pub fn is_one(&self) -> bool {
50        self.poly.is_one()
51    }
52
53    /// Checks if every entry of a [`PolynomialRingZq`] is `0`.
54    ///
55    /// Returns `true` if [`PolynomialRingZq`] has no coefficients.
56    ///
57    /// # Examples
58    /// ```
59    /// use qfall_math::integer_mod_q::PolynomialRingZq;
60    /// use std::str::FromStr;
61    ///
62    /// let value = PolynomialRingZq::from_str("0 / 2  1 1 mod 7").unwrap();
63    /// assert!(value.is_zero());
64    /// ```
65    pub fn is_zero(&self) -> bool {
66        self.poly.is_zero()
67    }
68
69    /// Computes the NTT representation of `self`.
70    ///
71    /// # Examples
72    /// ```
73    /// use qfall_math::integer_mod_q::{NTTPolynomialRingZq, PolynomialRingZq, ModulusPolynomialRingZq, PolyOverZq};
74    /// use crate::qfall_math::traits::SetCoefficient;
75    /// use std::str::FromStr;
76    ///
77    /// let n = 4;
78    /// let modulus = 7681;
79    ///
80    /// let mut mod_poly = PolyOverZq::from(modulus);
81    /// mod_poly.set_coeff(0, 1).unwrap();
82    /// mod_poly.set_coeff(n, 1).unwrap();
83    ///
84    /// let mut polynomial_modulus = ModulusPolynomialRingZq::from(&mod_poly);
85    /// polynomial_modulus.set_ntt_unchecked(1925);
86    ///
87    /// let poly_ring = PolynomialRingZq::sample_uniform(&polynomial_modulus);
88    ///
89    /// let ntt_poly_ring = poly_ring.ntt();
90    /// ```
91    ///
92    /// # Panics ...
93    /// - if the [`NTTBasisPolynomialRingZq`](crate::integer_mod_q::NTTBasisPolynomialRingZq),
94    ///   which is part of the [`ModulusPolynomialRingZq`](crate::integer_mod_q::ModulusPolynomialRingZq) in `self`
95    ///   is not set.
96    pub fn ntt(&self) -> NTTPolynomialRingZq {
97        NTTPolynomialRingZq::from(self)
98    }
99}
100
101#[cfg(test)]
102mod test_is_irreducible {
103    use crate::integer_mod_q::PolynomialRingZq;
104    use std::str::FromStr;
105
106    /// Ensure that a irreducible [`PolynomialRingZq`] returns `true`.
107    #[test]
108    fn poly_is_irreducible() {
109        // 9X^2 + 12X + 10 is irreducible over 17
110        let poly_irr = PolynomialRingZq::from_str("3  10 12 9 / 4  1 10 12 9 mod 17").unwrap();
111        assert!(poly_irr.is_irreducible());
112    }
113
114    /// Ensure that a reducible [`PolynomialRingZq`] returns `false`.
115    #[test]
116    fn poly_is_reducible() {
117        let poly_irr = PolynomialRingZq::from_str("3  1 2 1 / 4  1 10 12 9 mod 17").unwrap();
118        assert!(!poly_irr.is_irreducible());
119    }
120}
121
122#[cfg(test)]
123mod test_is_one {
124    use super::PolynomialRingZq;
125    use std::str::FromStr;
126
127    /// Ensure that is_one returns `true` for the one polynomial.
128    #[test]
129    fn one_detection() {
130        let one = PolynomialRingZq::from_str("1  1 / 4  1 10 12 9 mod 7").unwrap();
131        let one_2 = PolynomialRingZq::from_str("2  1 14 / 4  1 10 12 9 mod 7").unwrap();
132        let one_3 = PolynomialRingZq::from_str("3  11 4 10 / 3  5 2 5 mod 11").unwrap();
133
134        assert!(one.is_one());
135        assert!(one_2.is_one());
136        assert!(one_3.is_one());
137    }
138
139    /// Ensure that is_one returns `false` for other polynomials.
140    #[test]
141    fn one_rejection() {
142        let small = PolynomialRingZq::from_str("4  1 0 0 1 / 4  1 10 12 9 mod 7").unwrap();
143        let large = PolynomialRingZq::from_str(&format!(
144            "1  {} / 4  1 10 12 9 mod {}",
145            (u128::MAX - 1) / 2 + 2,
146            u128::MAX
147        )) // 2^127 + 1 the last memory entry is `1`
148        .unwrap();
149
150        assert!(!small.is_one());
151        assert!(!large.is_one());
152    }
153}
154
155#[cfg(test)]
156mod test_is_zero {
157    use super::PolynomialRingZq;
158    use std::str::FromStr;
159
160    /// Ensure that is_zero returns `true` for the zero polynomial.
161    #[test]
162    fn zero_detection() {
163        let zero = PolynomialRingZq::from_str("0 / 2  1 1 mod 7").unwrap();
164        let zero_2 = PolynomialRingZq::from_str("2  7 14 / 2  1 1  mod 7").unwrap();
165        let zero_3 = PolynomialRingZq::from_str("3  3 3 6 / 3  1 1 2 mod 11").unwrap();
166
167        assert!(zero.is_zero());
168        assert!(zero_2.is_zero());
169        assert!(zero_3.is_zero());
170    }
171
172    /// Ensure that is_zero returns `false` for non-zero polynomials.
173    #[test]
174    fn zero_rejection() {
175        let small = PolynomialRingZq::from_str("4  0 0 0 1 / 2  1 1 mod 7").unwrap();
176        let large = PolynomialRingZq::from_str(&format!(
177            "1  {} / 2  1 1 mod {}",
178            (u128::MAX - 1) / 2 + 1,
179            u128::MAX
180        )) // last 126 bits are 0
181        .unwrap();
182
183        assert!(!small.is_zero());
184        assert!(!large.is_zero());
185    }
186}