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}