qfall_math/integer_mod_q/poly_over_zq/from.rs
1// Copyright © 2023 Marcel Luca Schmidt, Marvin Beckmann and Sven Moog
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 create a [`PolyOverZq`] value from other types.
10//!
11//! The explicit functions contain the documentation.
12
13use crate::{
14 error::{MathError, StringConversionError},
15 integer::{PolyOverZ, Z},
16 integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, Zq, modulus::Modulus},
17 macros::for_others::implement_for_owned,
18};
19use flint_sys::fmpz_mod_poly::{
20 fmpz_mod_poly_init, fmpz_mod_poly_set, fmpz_mod_poly_set_coeff_fmpz,
21 fmpz_mod_poly_set_fmpz_poly,
22};
23use std::{mem::MaybeUninit, str::FromStr};
24
25impl<Mod: Into<Modulus>> From<Mod> for PolyOverZq {
26 /// Creates a zero polynomial with a given [`Modulus`].
27 ///
28 /// Parameters:
29 /// - `modulus`: of the new [`PolyOverZq`]
30 ///
31 /// Returns a new constant [`PolyOverZq`] with the specified [`Modulus`].
32 ///
33 /// # Examples
34 /// ```
35 /// use qfall_math::integer_mod_q::PolyOverZq;
36 /// use std::str::FromStr;
37 ///
38 /// let poly = PolyOverZq::from(100);
39 ///
40 /// let poly_cmp = PolyOverZq::from_str("0 mod 100").unwrap();
41 /// assert_eq!(poly, poly_cmp);
42 /// ```
43 ///
44 /// # Panics ...
45 /// - if `modulus` is smaller than `2`.
46 fn from(modulus: Mod) -> Self {
47 let modulus = modulus.into();
48 let mut poly = MaybeUninit::uninit();
49 unsafe {
50 fmpz_mod_poly_init(poly.as_mut_ptr(), modulus.get_fmpz_mod_ctx_struct());
51 let poly = poly.assume_init();
52 PolyOverZq { poly, modulus }
53 }
54 }
55}
56
57impl From<&Zq> for PolyOverZq {
58 /// Creates a constant [`PolyOverZq`], i.e. the polynomial `x mod q`,
59 /// where `x` is the value of the given [`Zq`] value and `q` its modulus.
60 ///
61 /// Parameters:
62 /// - `value`: the constant value the polynomial will have.
63 ///
64 /// Returns a new constant [`PolyOverZq`] with the specified `value` and `modulus` of the [`Zq`] value.
65 ///
66 /// # Examples
67 /// ```
68 /// use qfall_math::{integer_mod_q::*, traits::*};
69 ///
70 /// let poly = PolyOverZq::from(&Zq::from((1, 10)));
71 ///
72 /// let poly_cmp = PolyOverZq::from((1, 10));
73 /// assert_eq!(poly, poly_cmp);
74 /// assert_eq!(poly.get_degree(), 0);
75 /// ```
76 fn from(value: &Zq) -> Self {
77 let mut res = PolyOverZq::from(&value.modulus);
78 unsafe {
79 fmpz_mod_poly_set_coeff_fmpz(
80 &mut res.poly,
81 0,
82 &value.value.value,
83 value.modulus.get_fmpz_mod_ctx_struct(),
84 );
85 };
86 res
87 }
88}
89
90implement_for_owned!(Zq, PolyOverZq, From);
91
92impl<Mod: Into<Modulus>> From<(&PolyOverZ, Mod)> for PolyOverZq {
93 /// Creates a [`PolyOverZq`] from a [`PolyOverZ`] and a value that implements [`Into<Modulus>`].
94 ///
95 /// Parameters:
96 /// - `poly`: the coefficients of the polynomial.
97 /// - `modulus`: the modulus by which each entry is reduced.
98 ///
99 /// Returns a new [`PolyOverZq`] with the coefficients from the
100 /// [`PolyOverZ`] instance under the specified [`Modulus`] value.
101 ///
102 /// # Examples
103 /// ```
104 /// use qfall_math::integer_mod_q::{PolyOverZq, Modulus};
105 /// use qfall_math::integer::PolyOverZ;
106 /// use std::str::FromStr;
107 ///
108 /// let poly = PolyOverZ::from_str("4 0 1 102 3").unwrap();
109 /// let modulus = Modulus::from(100);
110 ///
111 /// let mod_poly = PolyOverZq::from((&poly, &modulus));
112 ///
113 /// # let poly_cmp = PolyOverZq::from_str("4 0 1 2 3 mod 100").unwrap();
114 /// # assert_eq!(poly_cmp, mod_poly);
115 /// ```
116 ///
117 /// # Panics ...
118 /// - if `modulus` is smaller than `2`.
119 fn from((poly, modulus): (&PolyOverZ, Mod)) -> Self {
120 let mut res = PolyOverZq::from(modulus);
121 unsafe {
122 fmpz_mod_poly_set_fmpz_poly(
123 &mut res.poly,
124 &poly.poly,
125 res.modulus.get_fmpz_mod_ctx_struct(),
126 );
127 }
128 res
129 }
130}
131
132impl<Mod: Into<Modulus>> From<(PolyOverZ, Mod)> for PolyOverZq {
133 /// Creates a [`PolyOverZq`] from a [`PolyOverZ`] and a value that implements [`Into<Modulus>`].
134 ///
135 /// Parameters:
136 /// - `poly`: the coefficients of the polynomial.
137 /// - `modulus`: the modulus by which each entry is reduced.
138 ///
139 /// Returns a new [`PolyOverZq`] with the coefficients from the
140 /// [`PolyOverZ`] instance under the specified [`Modulus`] value.
141 ///
142 /// # Examples
143 /// ```
144 /// use qfall_math::integer_mod_q::PolyOverZq;
145 /// use qfall_math::integer::PolyOverZ;
146 /// use std::str::FromStr;
147 ///
148 /// let poly = PolyOverZ::from_str("4 0 1 102 3").unwrap();
149 ///
150 /// let mod_poly = PolyOverZq::from((poly, 100));
151 ///
152 /// # let poly_cmp = PolyOverZq::from_str("4 0 1 2 3 mod 100").unwrap();
153 /// # assert_eq!(poly_cmp, mod_poly);
154 /// ```
155 ///
156 /// # Panics ...
157 /// - if `modulus` is smaller than `2`.
158 fn from((poly, modulus): (PolyOverZ, Mod)) -> Self {
159 let mut res = PolyOverZq::from(modulus);
160 unsafe {
161 fmpz_mod_poly_set_fmpz_poly(
162 &mut res.poly,
163 &poly.poly,
164 res.modulus.get_fmpz_mod_ctx_struct(),
165 );
166 }
167 res
168 }
169}
170
171impl<Integer: Into<Z>, Mod: Into<Modulus>> From<(Integer, Mod)> for PolyOverZq {
172 /// Creates a [`PolyOverZq`] from any values that implement [`Into<Z>`] and [`Into<Modulus>`],
173 /// where the second value must be larger than `1`.
174 ///
175 /// Parameters:
176 /// - `z`: the single, constant coefficient of the polynomial.
177 /// - `modulus`: the modulus by which each entry is reduced.
178 ///
179 /// Returns a new constant [`PolyOverZq`] with the specified `z` and `modulus` value.
180 ///
181 /// # Examples
182 /// ```
183 /// use qfall_math::integer_mod_q::PolyOverZq;
184 /// use std::str::FromStr;
185 ///
186 /// let mod_poly = PolyOverZq::from((5, 42));
187 ///
188 /// # let poly_cmp = PolyOverZq::from_str("1 5 mod 42").unwrap();
189 /// # assert_eq!(poly_cmp, mod_poly);
190 /// ```
191 ///
192 /// # Panics ...
193 /// - if `modulus` is smaller than `2`.
194 fn from((z, modulus): (Integer, Mod)) -> Self {
195 let z: Z = z.into();
196 let mut res = PolyOverZq::from(modulus);
197 unsafe {
198 fmpz_mod_poly_set_coeff_fmpz(
199 &mut res.poly,
200 0,
201 &z.value,
202 res.modulus.get_fmpz_mod_ctx_struct(),
203 );
204 }
205 res
206 }
207}
208
209impl From<&ModulusPolynomialRingZq> for PolyOverZq {
210 /// Creates a [`PolyOverZq`] from a [`ModulusPolynomialRingZq`].
211 ///
212 /// Parameters:
213 /// - `modulus`: the context polynomial from which the coefficients are copied.
214 ///
215 /// # Examples
216 ///
217 /// Returns a new [`PolyOverZq`] representing the modulus object.
218 ///
219 /// ```
220 /// use qfall_math::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq};
221 /// use std::str::FromStr;
222 ///
223 /// let modulus = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
224 ///
225 /// let poly_zq = PolyOverZq::from(&modulus);
226 ///
227 /// let poly_cmp = PolyOverZq::from_str("4 1 0 0 1 mod 17").unwrap();
228 /// assert_eq!(poly_cmp, poly_zq);
229 /// ```
230 fn from(modulus: &ModulusPolynomialRingZq) -> Self {
231 let modulus_q = Modulus::from(&modulus.get_q());
232 let mut out = PolyOverZq::from(&modulus_q);
233 unsafe {
234 fmpz_mod_poly_set(
235 &mut out.poly,
236 &modulus.get_fq_ctx().modulus[0],
237 out.modulus.get_fmpz_mod_ctx_struct(),
238 )
239 };
240 out
241 }
242}
243
244implement_for_owned!(ModulusPolynomialRingZq, PolyOverZq, From);
245
246impl From<&PolyOverZq> for PolyOverZq {
247 /// Alias for [`PolyOverZq::clone`].
248 fn from(value: &PolyOverZq) -> Self {
249 value.clone()
250 }
251}
252
253impl FromStr for PolyOverZq {
254 type Err = MathError;
255
256 /// Creates a polynomial with arbitrarily many coefficients of type [`Zq`].
257 ///
258 /// **Warning**: If the input string starts with a correctly formatted [`PolyOverZ`] object,
259 /// the rest of the string until the `"mod"` is ignored. This means that the input string
260 /// `"4 0 1 2 3 mod 13"` is the same as `"4 0 1 2 3 4 5 6 7 mod 13"`.
261 ///
262 /// Parameters:
263 /// - `s`: the polynomial of form:
264 /// `"[#number of coefficients]⌴⌴[0th coefficient]⌴[1st coefficient]⌴...⌴mod⌴[modulus]"`.
265 ///
266 /// Note that the `[#number of coefficients]` and `[0th coefficient]`
267 /// are divided by two spaces and the string for the polynomial is trimmed,
268 /// i.e. all whitespaces before around the polynomial and the modulus are ignored.
269 ///
270 /// Returns a [`PolyOverZq`] or an error if the provided string was not
271 /// formatted correctly, the number of coefficients was smaller than the number provided
272 /// at the start of the provided string, or the modulus was smaller than `2`.
273 ///
274 /// # Examples
275 /// ```
276 /// use qfall_math::integer_mod_q::PolyOverZq;
277 /// use std::str::FromStr;
278 ///
279 /// let poly = PolyOverZq::from_str("4 0 1 -2 3 mod 42").unwrap();
280 /// ```
281 /// # Errors and Failures
282 /// - Returns a [`MathError`] of type
283 /// [`StringConversionError`](MathError::StringConversionError)
284 /// - if the provided first half of the string was not formatted correctly to
285 /// create a [`PolyOverZ`],
286 /// - if the provided second half of the
287 /// string was not formatted correctly to create a [`Modulus`],
288 /// - if the number of coefficients was smaller than the number provided
289 /// at the start of the provided string,
290 /// - if the provided value did not contain two whitespaces, or
291 /// - if the delimiter `mod` could not be found.
292 /// - Returns a [`MathError`] of type
293 /// [`InvalidModulus`](MathError::InvalidModulus)
294 /// if `modulus` is smaller than `2`.
295 fn from_str(s: &str) -> Result<Self, Self::Err> {
296 let (poly_s, modulus) = match s.split_once("mod") {
297 Some((poly_s, modulus)) => (poly_s, modulus.trim()),
298 None => {
299 return Err(StringConversionError::InvalidStringToPolyModulusInput(
300 s.to_owned(),
301 ))?;
302 }
303 };
304
305 let poly_over_z = PolyOverZ::from_str(poly_s)?;
306 let modulus = Modulus::from_str(modulus)?;
307
308 Ok(Self::from((&poly_over_z, &modulus)))
309 }
310}
311
312#[cfg(test)]
313mod test_availability {
314 use super::*;
315 use crate::{integer::Z, integer_mod_q::Zq};
316
317 /// Ensure that the from function can be called with several types.
318 #[test]
319 fn availability() {
320 let z = Z::from(3);
321 let modulus = Modulus::from(2);
322 let zq = Zq::from((1, 2));
323 let poly = PolyOverZ::from_str("2 1 1").unwrap();
324 let poly_mod = ModulusPolynomialRingZq::from_str("4 1 0 0 1 mod 17").unwrap();
325
326 let _ = PolyOverZq::from(3);
327 let _ = PolyOverZq::from(&z);
328 let _ = PolyOverZq::from(z.clone());
329 let _ = PolyOverZq::from(&modulus);
330 let _ = PolyOverZq::from(modulus.clone());
331
332 let _ = PolyOverZq::from(&zq);
333 let _ = PolyOverZq::from(zq.clone());
334
335 let _ = PolyOverZq::from((1, 2));
336 let _ = PolyOverZq::from((&z, 2));
337 let _ = PolyOverZq::from((z.clone(), 2));
338 let _ = PolyOverZq::from((&modulus, 2));
339 let _ = PolyOverZq::from((modulus.clone(), 2));
340 let _ = PolyOverZq::from((&poly, 2));
341 let _ = PolyOverZq::from((poly.clone(), 2));
342 let _ = PolyOverZq::from((1, &z));
343 let _ = PolyOverZq::from((1, z.clone()));
344 let _ = PolyOverZq::from((1, &modulus));
345 let _ = PolyOverZq::from((1, modulus));
346
347 let _ = PolyOverZq::from(&poly_mod);
348 let _ = PolyOverZq::from(poly_mod);
349 }
350}
351
352#[cfg(test)]
353mod test_from_zq {
354 use super::*;
355 use crate::{integer::Z, traits::GetCoefficient};
356
357 /// Ensure that the [`From`] trait works for small
358 /// borrowed and owned [`Zq`], and tuples of value and modulus instances
359 #[test]
360 fn small() {
361 let value: Zq = Zq::from((1, 2));
362
363 let poly = PolyOverZq::from(&value);
364 let poly_2 = PolyOverZq::from(value.clone());
365 let poly_3 = PolyOverZq::from((1, 2));
366 let poly_4 = PolyOverZq::from((&1, &2));
367
368 let value_set: Zq = poly.get_coeff(0).unwrap();
369 assert_eq!(value_set, value);
370 assert_eq!(poly.get_degree(), 0);
371 assert_eq!(poly, poly_2);
372 assert_eq!(poly, poly_3);
373 assert_eq!(poly, poly_4);
374 }
375
376 /// Ensure that the [`From`] trait works for large
377 /// borrowed and owned [`Zq`], and tuples of value and modulus instances.
378 #[test]
379 fn large() {
380 let value = Zq::from((u64::MAX - 1, u64::MAX));
381 let modulus = Modulus::from(u64::MAX);
382
383 let poly = PolyOverZq::from(&value);
384 let poly_2 = PolyOverZq::from(value.clone());
385 let poly_3 = PolyOverZq::from((u64::MAX - 1, &modulus));
386 let poly_4 = PolyOverZq::from((&(u64::MAX - 1), &modulus));
387 let poly_5 = PolyOverZq::from((Z::from(u64::MAX - 1), &u64::MAX));
388 let poly_6 = PolyOverZq::from((&Z::from(u64::MAX - 1), u64::MAX));
389
390 let value_set: Zq = poly.get_coeff(0).unwrap();
391 assert_eq!(value_set, value);
392 assert_eq!(poly.get_degree(), 0);
393 assert_eq!(poly, poly_2);
394 assert_eq!(poly, poly_3);
395 assert_eq!(poly, poly_4);
396 assert_eq!(poly, poly_5);
397 assert_eq!(poly, poly_6);
398 }
399
400 /// Ensure that the modulus is applied when creating a [`PolyOverZq`]
401 /// from a constant [`Zq`].
402 #[test]
403 fn modulus_reduction() {
404 let poly = PolyOverZq::from((42, 5));
405
406 let value_set: Zq = poly.get_coeff(0).unwrap();
407 assert_eq!(value_set, Zq::from((2, 5)));
408 }
409
410 /// Ensure that the polynomial can not be created with an invalid modulus.
411 #[test]
412 #[should_panic]
413 fn invalid_modulus() {
414 let _ = PolyOverZq::from((10, 1));
415 }
416}
417
418#[cfg(test)]
419mod test_from_poly_z_modulus {
420 use super::PolyOverZq;
421 use crate::{integer::PolyOverZ, integer_mod_q::Modulus};
422 use std::str::FromStr;
423
424 /// Test conversion of a [`PolyOverZ`] with small coefficients and small
425 /// [`Modulus`] into a [`PolyOverZq`].
426 #[test]
427 fn working_small() {
428 let poly = PolyOverZ::from_str("4 0 1 -2 3").unwrap();
429 let modulus = Modulus::from(100);
430
431 let mod_poly = PolyOverZq::from((&poly, &modulus));
432
433 let cmp_poly = PolyOverZq::from_str("4 0 1 -2 3 mod 100").unwrap();
434 assert_eq!(cmp_poly, mod_poly);
435 }
436
437 /// Test conversion of a [`PolyOverZ`] with large coefficients and large
438 /// [`Modulus`] into a [`PolyOverZq`].
439 #[test]
440 fn working_large() {
441 let poly = PolyOverZ::from_str(&format!("4 {} {} -2 3", u64::MAX - 1, u64::MAX)).unwrap();
442 let modulus = Modulus::from(u64::MAX);
443
444 let mod_poly = PolyOverZq::from((&poly, &modulus));
445
446 let cmp_poly = PolyOverZq::from_str(&format!("4 -1 0 -2 3 mod {}", u64::MAX)).unwrap();
447 assert_eq!(cmp_poly, mod_poly);
448 }
449
450 /// Test that the coefficients are reduced properly after the conversion.
451 #[test]
452 fn reduce() {
453 let poly = PolyOverZ::from_str("4 100 101 -102 103").unwrap();
454 let modulus = Modulus::from(100);
455
456 let mod_poly = PolyOverZq::from((&poly, &modulus));
457
458 let cmp_poly = PolyOverZq::from_str("4 0 1 -2 3 mod 100").unwrap();
459 assert_eq!(cmp_poly, mod_poly);
460 }
461}
462
463#[cfg(test)]
464mod test_from_z_modulus {
465 use super::PolyOverZq;
466 use crate::{integer::Z, integer_mod_q::Modulus};
467 use std::str::FromStr;
468
469 /// Test conversion of a [`Z`] with small coefficients and small
470 /// [`Modulus`] into a [`PolyOverZq`].
471 #[test]
472 fn working_small() {
473 let z = Z::from(42);
474 let modulus = Modulus::from(100);
475
476 let mod_poly = PolyOverZq::from((&z, &modulus));
477
478 let cmp_poly = PolyOverZq::from_str("1 42 mod 100").unwrap();
479 assert_eq!(cmp_poly, mod_poly);
480 }
481
482 /// Test conversion of a [`PolyOverZ`] with large coefficients and large
483 /// [`Modulus`] into a [`PolyOverZq`].
484 #[test]
485 fn working_large() {
486 let z = Z::from(u64::MAX - 1);
487 let modulus = Modulus::from(u64::MAX);
488
489 let mod_poly = PolyOverZq::from((&z, &modulus));
490
491 let cmp_poly =
492 PolyOverZq::from_str(&format!("1 {} mod {}", u64::MAX - 1, u64::MAX)).unwrap();
493 assert_eq!(cmp_poly, mod_poly);
494 }
495
496 /// Test that the coefficients are reduced properly after the conversion.
497 #[test]
498 fn reduce() {
499 let z = Z::from(101);
500 let modulus = Modulus::from(100);
501
502 let mod_poly = PolyOverZq::from((&z, &modulus));
503
504 let cmp_poly = PolyOverZq::from_str("1 1 mod 100").unwrap();
505 assert_eq!(cmp_poly, mod_poly);
506 }
507}
508
509#[cfg(test)]
510mod test_from_str {
511 use super::PolyOverZq;
512 use std::str::FromStr;
513
514 /// tests whether a falsely formatted string (modulus is 0) returns an
515 /// error
516 #[test]
517 fn modulus_zero_throws_error() {
518 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 0").is_err());
519 }
520
521 /// tests whether a falsely formatted string (several modulus) returns
522 /// an error
523 #[test]
524 fn several_mod() {
525 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 42 mod 13").is_err());
526 }
527
528 /// tests whether a falsely formatted string (wrong whitespaces) returns an
529 /// error
530 #[test]
531 fn whitespaces_in_modulus() {
532 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 4 2").is_err());
533 }
534
535 /// tests whether a falsely formatted string (wrong symbols) returns an error
536 #[test]
537 fn false_format_symbols_modulus() {
538 assert!(PolyOverZq::from_str("1 1 mod ba").is_err());
539 }
540
541 /// tests whether a falsely formatted string (wrong symbols) returns an error
542 #[test]
543 fn false_format_symbols_polynomial() {
544 assert!(PolyOverZq::from_str("1 ba mod 42").is_err());
545 }
546
547 /// tests whether a false string (negative modulus) returns an error
548 #[test]
549 fn false_sign() {
550 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod -42").is_err());
551 }
552
553 /// tests whether a falsely formatted string (missing double-space) returns
554 /// an error
555 #[test]
556 fn false_format() {
557 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 42").is_err());
558 }
559
560 /// tests whether a falsely formatted string (wrong number of total
561 /// coefficients) returns an error
562 #[test]
563 fn false_number_of_coefficient() {
564 assert!(PolyOverZq::from_str("5 0 1 -2 3 mod 42").is_err());
565 }
566
567 /// tests whether a falsely formatted string (missing double-space) returns
568 /// an error
569 #[test]
570 fn missing_whitespace() {
571 assert!(PolyOverZq::from_str("3 12 2 -3 mod 42").is_err());
572 assert!(PolyOverZq::from_str("2 17 42 mod 42").is_err());
573 assert!(PolyOverZq::from_str("2 17 42 mod 42").is_err());
574 assert!(PolyOverZq::from_str("2 17 42 mod 42").is_err());
575 assert!(PolyOverZq::from_str(" 2 17 42 mod 42").is_err());
576 assert!(PolyOverZq::from_str("2 17 42 mod 42 ").is_err());
577 }
578
579 /// tests whether a falsely formatted string (too many whitespaces) returns
580 /// an error
581 #[test]
582 fn too_many_whitespaces() {
583 assert!(PolyOverZq::from_str("4 0 1 -2 3 mod 42").is_err());
584 }
585
586 /// Ensure that the input works with strings that have to be trimmed
587 #[test]
588 fn trim_input() {
589 let poly = PolyOverZq::from_str(
590 " 4 1 2 3 -4 mod 17 ",
591 );
592 assert!(poly.is_ok());
593 assert_eq!(
594 PolyOverZq::from_str("4 1 2 3 -4 mod 17").unwrap(),
595 poly.unwrap()
596 );
597 }
598}
599
600#[cfg(test)]
601mod test_from_modulus_polynomial_ring_zq {
602 use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq};
603 use std::str::FromStr;
604
605 /// ensure that the conversion works with positive large entries
606 #[test]
607 fn large_positive() {
608 let modulus_ring =
609 ModulusPolynomialRingZq::from_str(&format!("4 -1 0 0 1 mod {}", u64::MAX - 58))
610 .unwrap();
611
612 let modulus = PolyOverZq::from(&modulus_ring);
613
614 let cmp_poly =
615 PolyOverZq::from_str(&format!("4 {} 0 0 1 mod {}", u64::MAX - 59, u64::MAX - 58))
616 .unwrap();
617 assert_eq!(cmp_poly, modulus);
618 }
619}