qfall_math/integer_mod_q/modulus_polynomial_ring_zq/get.rs
1// Copyright © 2023 Marcel Luca Schmidt, Marvin Beckmann, 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 get information about a [`ModulusPolynomialRingZq].
10
11use crate::{
12 integer::{PolyOverZ, Z},
13 integer_mod_q::{Modulus, ModulusPolynomialRingZq, PolyOverZq, Zq},
14 traits::GetCoefficient,
15};
16use flint_sys::fmpz_mod_poly::fmpz_mod_poly_get_coeff_fmpz;
17
18impl GetCoefficient<Zq> for ModulusPolynomialRingZq {
19 /// Returns the coefficient of a polynomial [`ModulusPolynomialRingZq`] as a [`Zq`].
20 ///
21 /// If an index is provided which exceeds the highest set coefficient, `0` is returned.
22 ///
23 /// Parameters:
24 /// - `index`: the index of the coefficient to get (has to be positive)
25 ///
26 /// Returns the coefficient as a [`Zq`].
27 ///
28 /// # Examples
29 /// ```
30 /// use qfall_math::traits::*;
31 /// use qfall_math::integer_mod_q::{Zq, ModulusPolynomialRingZq};
32 /// use std::str::FromStr;
33 ///
34 /// let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
35 ///
36 /// let coeff_0: Zq = poly.get_coeff(0).unwrap();
37 /// let coeff_1: Zq = unsafe{ poly.get_coeff_unchecked(1) };
38 /// let coeff_4: Zq = poly.get_coeff(4).unwrap();
39 ///
40 /// assert_eq!(Zq::from((0, 17)), coeff_0);
41 /// assert_eq!(Zq::from((1, 17)), coeff_1);
42 /// assert_eq!(Zq::from((0, 17)), coeff_4);
43 /// ```
44 ///
45 /// # Safety
46 /// To use this function safely, make sure that the selected index
47 /// is greater or equal than `0`.
48 unsafe fn get_coeff_unchecked(&self, index: i64) -> Zq {
49 let out_z: Z = unsafe { self.get_coeff_unchecked(index) };
50
51 let modulus = self.modulus.modulus.clone();
52
53 Zq::from((out_z, modulus))
54 }
55}
56
57impl GetCoefficient<Z> for ModulusPolynomialRingZq {
58 /// Returns the coefficient of a polynomial [`ModulusPolynomialRingZq`] as a [`Z`].
59 ///
60 /// If an index is provided which exceeds the highest set coefficient, `0` is returned.
61 ///
62 /// Parameters:
63 /// - `index`: the index of the coefficient to get (has to be positive)
64 ///
65 /// Returns the coefficient as a [`Z`], or a [`MathError`](crate::error::MathError) if the provided index
66 /// is negative and therefore invalid, or it does not fit into an [`i64`].
67 ///
68 /// # Examples
69 /// ```
70 /// use qfall_math::traits::*;
71 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
72 /// use qfall_math::integer::Z;
73 /// use std::str::FromStr;
74 ///
75 /// let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
76 ///
77 /// let coeff_0: Z = poly.get_coeff(0).unwrap();
78 /// let coeff_1: Z = unsafe{ poly.get_coeff_unchecked(1) };
79 /// let coeff_4: Z = poly.get_coeff(4).unwrap();
80 ///
81 /// assert_eq!(Z::ZERO, coeff_0);
82 /// assert_eq!(Z::ONE, coeff_1);
83 /// assert_eq!(Z::ZERO, coeff_4);
84 /// ```
85 ///
86 /// # Safety
87 /// To use this function safely, make sure that the selected index
88 /// is greater or equal than `0`.
89 unsafe fn get_coeff_unchecked(&self, index: i64) -> Z {
90 let mut out = Z::default();
91
92 let modulus = self.get_q_as_modulus();
93
94 unsafe {
95 fmpz_mod_poly_get_coeff_fmpz(
96 &mut out.value,
97 &self.modulus.poly,
98 index,
99 modulus.get_fmpz_mod_ctx_struct(),
100 )
101 }
102
103 out
104 }
105}
106
107impl ModulusPolynomialRingZq {
108 pub fn get_q_as_modulus(&self) -> Modulus {
109 self.modulus.modulus.clone()
110 }
111
112 /// Returns the context integer as a [`Z`].
113 ///
114 /// # Examples
115 /// ```
116 /// use qfall_math::integer::Z;
117 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
118 /// use std::str::FromStr;
119 ///
120 /// let modulus_ring = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
121 ///
122 /// let modulus = modulus_ring.get_q();
123 ///
124 /// let cmp_modulus = Z::from(17);
125 /// assert_eq!(cmp_modulus, modulus);
126 /// ```
127 pub fn get_q(&self) -> Z {
128 Z::from(&self.modulus.modulus)
129 }
130
131 /// Returns the degree of a polynomial [`ModulusPolynomialRingZq`] as a [`i64`].
132 /// The zero polynomial has degree `-1`.
133 ///
134 /// # Examples
135 /// ```
136 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
137 /// use std::str::FromStr;
138 ///
139 /// let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 7").unwrap();
140 ///
141 /// let degree = poly.get_degree(); // This would only return 3
142 /// ```
143 pub fn get_degree(&self) -> i64 {
144 self.modulus.get_degree()
145 }
146
147 /// Returns a representative polynomial of the [`ModulusPolynomialRingZq`] element.
148 ///
149 /// The representation of the coefficients is in the range `[0, modulus)`.
150 ///
151 /// # Examples
152 /// ```
153 /// use qfall_math::integer::PolyOverZ;
154 /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
155 /// use std::str::FromStr;
156 ///
157 /// let modulus = ModulusPolynomialRingZq::from_str("4 -3 0 31 1 mod 17").unwrap();
158 ///
159 /// let poly_z = modulus.get_representative_least_nonnegative_residue();
160 ///
161 /// let cmp_poly = PolyOverZ::from_str("4 14 0 14 1").unwrap();
162 /// assert_eq!(cmp_poly, poly_z);
163 /// ```
164 pub fn get_representative_least_nonnegative_residue(&self) -> PolyOverZ {
165 let poly_zq = PolyOverZq::from(self);
166 poly_zq.get_representative_least_nonnegative_residue()
167 }
168}
169
170#[cfg(test)]
171mod test_get_coeff_z {
172 use crate::{
173 integer::Z,
174 integer_mod_q::{ModulusPolynomialRingZq, Zq},
175 traits::GetCoefficient,
176 };
177 use std::str::FromStr;
178
179 /// Ensure that `0` is returned if the provided index is not yet set.
180 #[test]
181 fn index_out_of_range() {
182 let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
183
184 let zero_coeff_1: Z = poly.get_coeff(4).unwrap();
185 let zero_coeff_2 = poly.get_coeff(4).unwrap();
186
187 assert_eq!(0, zero_coeff_1);
188 assert_eq!(Zq::from((0, 17)), zero_coeff_2);
189 }
190
191 /// Tests if coefficients are returned correctly.
192 #[test]
193 fn positive_coeff() {
194 let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
195
196 let coeff_1: Z = poly.get_coeff(2).unwrap();
197 let coeff_2 = poly.get_coeff(2).unwrap();
198
199 assert_eq!(2, coeff_1);
200 assert_eq!(Zq::from((2, 17)), coeff_2);
201 }
202
203 /// Tests if large coefficients are returned correctly.
204 #[test]
205 fn large_coeff() {
206 let poly =
207 ModulusPolynomialRingZq::from_str(&format!("2 {} 1 mod {}", u64::MAX - 1, u64::MAX))
208 .unwrap();
209
210 let coefficient_1: Z = poly.get_coeff(0).unwrap();
211 let coefficient_2: Zq = poly.get_coeff(0).unwrap();
212
213 assert_eq!(u64::MAX - 1, coefficient_1);
214 assert_eq!(Zq::from((u64::MAX - 1, u64::MAX)), coefficient_2);
215 }
216
217 /// Tests if negative index yields an error in get_coeff with [`Z`].
218 #[test]
219 #[should_panic]
220 fn negative_index_error_z() {
221 let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
222
223 let _: Z = poly.get_coeff(-1).unwrap();
224 }
225
226 /// Tests if negative index yields an error in get_coeff with [`Zq`].
227 #[test]
228 #[should_panic]
229 fn negative_index_error_zq() {
230 let poly = ModulusPolynomialRingZq::from_str("4 0 1 2 1 mod 17").unwrap();
231
232 let _: Zq = poly.get_coeff(-1).unwrap();
233 }
234}
235
236#[cfg(test)]
237mod test_get_degree {
238 use crate::integer_mod_q::ModulusPolynomialRingZq;
239 use std::str::FromStr;
240
241 /// Ensures that degree is working for constant polynomials.
242 #[test]
243 fn degree_constant() {
244 let degrees = [1, 3, 7, 15, 32, 120];
245 for degree in degrees {
246 let modulus_ring = ModulusPolynomialRingZq::from_str(&format!(
247 "{} {}1 mod 17",
248 degree + 1,
249 "0 ".repeat(degree)
250 ))
251 .unwrap();
252
253 assert_eq!(degree as i64, modulus_ring.get_degree());
254 }
255 }
256
257 /// Ensure that degree is working for polynomials with leading 0 coefficients.
258 #[test]
259 fn degree_leading_zeros() {
260 let poly = ModulusPolynomialRingZq::from_str("4 2 1 0 0 mod 199").unwrap();
261
262 let deg = poly.get_degree();
263
264 assert_eq!(1, deg);
265 }
266
267 /// Ensure that degree is working for polynomials with many coefficients
268 /// flint does not reduce the exponent due to computational cost.
269 #[test]
270 fn degree_many_coefficients() {
271 let poly_1 = ModulusPolynomialRingZq::from_str("7 1 2 3 4 8 1 1 mod 2").unwrap();
272 let poly_2 = ModulusPolynomialRingZq::from_str(&format!(
273 "7 1 2 3 4 8 {} 1 mod {}",
274 u64::MAX,
275 u128::MAX
276 ))
277 .unwrap();
278
279 let deg_1 = poly_1.get_degree();
280 let deg_2 = poly_2.get_degree();
281
282 assert_eq!(6, deg_1);
283 assert_eq!(6, deg_2);
284 }
285}
286
287#[cfg(test)]
288mod test_get_q {
289 use crate::{integer::Z, integer_mod_q::ModulusPolynomialRingZq};
290 use std::str::FromStr;
291
292 /// Ensure that the same modulus is correctly returned for a large modulus.
293 #[test]
294 fn correct_large() {
295 let large_prime = u64::MAX - 58;
296 let modulus_ring =
297 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {large_prime}")).unwrap();
298
299 let modulus = modulus_ring.get_q();
300
301 let cmp_modulus = Z::from(large_prime);
302 assert_eq!(cmp_modulus, modulus);
303 }
304}
305
306#[cfg(test)]
307mod test_get_representative_least_nonnegative_residue {
308 use crate::{
309 integer::PolyOverZ,
310 integer_mod_q::{ModulusPolynomialRingZq, PolynomialRingZq},
311 };
312 use std::str::FromStr;
313
314 /// Ensure that the getter works for large entries.
315 #[test]
316 fn large_positive() {
317 let large_prime = u64::MAX - 58;
318 let modulus =
319 ModulusPolynomialRingZq::from_str(&format!("4 1 0 0 1 mod {large_prime}")).unwrap();
320 let poly = PolyOverZ::from_str("4 -1 0 1 1").unwrap();
321 let poly_ring = PolynomialRingZq::from((&poly, &modulus));
322
323 let poly_z = poly_ring.get_representative_least_nonnegative_residue();
324
325 let cmp_poly = PolyOverZ::from_str(&format!("3 {} 0 1", u64::MAX - 60)).unwrap();
326 assert_eq!(cmp_poly, poly_z);
327 }
328}