Skip to main content

qfall_math/integer_mod_q/polynomial_ring_zq/arithmetic/
sub.rs

1// Copyright © 2023 Phil Milewski, 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//! Implementation of the [`Sub`] trait for [`PolynomialRingZq`] values.
10
11use super::super::PolynomialRingZq;
12use crate::{
13    error::MathError,
14    integer::PolyOverZ,
15    integer_mod_q::PolyOverZq,
16    macros::arithmetics::{
17        arithmetic_assign_trait_borrowed_to_owned, arithmetic_trait_borrowed_to_owned,
18        arithmetic_trait_mixed_borrowed_owned,
19    },
20    traits::CompareBase,
21};
22use std::ops::{Sub, SubAssign};
23
24impl SubAssign<&PolynomialRingZq> for PolynomialRingZq {
25    /// Computes the subtraction of `self` and `other` reusing
26    /// the memory of `self`.
27    /// [`SubAssign`] can be used on [`PolynomialRingZq`] in combination with
28    /// [`PolynomialRingZq`], [`PolyOverZ`] and [`PolyOverZq`].
29    ///
30    /// Parameters:
31    /// - `other`: specifies the polynomial to subtract from `self`
32    ///
33    /// Returns the difference of both polynomials modulo `Z_q[X]` as a [`PolynomialRingZq`].
34    ///
35    /// # Examples
36    /// ```
37    /// use qfall_math::integer_mod_q::{PolynomialRingZq, ModulusPolynomialRingZq, PolyOverZq};
38    /// use qfall_math::integer::PolyOverZ;
39    /// use std::str::FromStr;
40    ///
41    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
42    /// let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
43    /// let mut a = PolynomialRingZq::from((&poly_1, &modulus));
44    /// let c = PolyOverZ::from_str("4  2 0 3 1").unwrap();
45    /// let b = PolynomialRingZq::from((&c, &modulus));
46    /// let d = PolyOverZq::from((&c, 17));
47    ///
48    /// a -= &b;
49    /// a -= b;
50    /// a -= &c;
51    /// a -= c;
52    /// a -= &d;
53    /// a -= d;
54    /// ```
55    ///
56    /// # Panics ...
57    /// - if the moduli of both [`PolynomialRingZq`] mismatch.
58    fn sub_assign(&mut self, other: &Self) {
59        if !self.compare_base(other) {
60            panic!("{}", self.call_compare_base_error(other).unwrap());
61        }
62
63        self.poly -= &other.poly;
64        self.reduce();
65    }
66}
67impl SubAssign<&PolyOverZ> for PolynomialRingZq {
68    /// Documentation at [`PolynomialRingZq::sub_assign`].
69    fn sub_assign(&mut self, other: &PolyOverZ) {
70        self.poly -= other;
71        self.reduce();
72    }
73}
74impl SubAssign<&PolyOverZq> for PolynomialRingZq {
75    /// Documentation at [`PolynomialRingZq::sub_assign`].
76    ///
77    /// # Panics ...
78    /// - if the moduli are different.
79    fn sub_assign(&mut self, other: &PolyOverZq) {
80        if !self.compare_base(other) {
81            panic!("{}", self.call_compare_base_error(other).unwrap())
82        }
83        self.poly -= other.get_representative_least_nonnegative_residue();
84        self.reduce();
85    }
86}
87
88arithmetic_assign_trait_borrowed_to_owned!(
89    SubAssign,
90    sub_assign,
91    PolynomialRingZq,
92    PolynomialRingZq
93);
94arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolynomialRingZq, PolyOverZ);
95arithmetic_assign_trait_borrowed_to_owned!(SubAssign, sub_assign, PolynomialRingZq, PolyOverZq);
96
97impl Sub for &PolynomialRingZq {
98    type Output = PolynomialRingZq;
99    /// Implements the [`Sub`] trait for two [`PolynomialRingZq`] values.
100    /// [`Sub`] is implemented for any combination of [`PolynomialRingZq`] and borrowed [`PolynomialRingZq`].
101    ///
102    /// Parameters:
103    /// - `other`: specifies the polynomial to subtract from `self`
104    ///
105    /// Returns the result of the subtraction of both polynomials as a [`PolynomialRingZq`].
106    ///
107    /// # Examples
108    /// ```
109    /// use qfall_math::integer_mod_q::PolynomialRingZq;
110    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
111    /// use qfall_math::integer::PolyOverZ;
112    /// use std::str::FromStr;
113    ///
114    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
115    /// let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
116    /// let a = PolynomialRingZq::from((&poly_1, &modulus));
117    /// let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
118    /// let b = PolynomialRingZq::from((&poly_2, &modulus));
119    ///
120    /// let c: PolynomialRingZq = &a - &b;
121    /// let d: PolynomialRingZq = a - b;
122    /// let e: PolynomialRingZq = &c - d;
123    /// let f: PolynomialRingZq = c - &e;
124    /// ```
125    ///
126    /// # Panics ...
127    /// - if the moduli of both [`PolynomialRingZq`] mismatch.
128    fn sub(self, other: Self) -> Self::Output {
129        self.sub_safe(other).unwrap()
130    }
131}
132
133impl Sub<&PolyOverZ> for &PolynomialRingZq {
134    type Output = PolynomialRingZq;
135    /// Implements the [`Sub`] trait for [`PolynomialRingZq`] and [`PolyOverZ`].
136    /// [`Sub`] is implemented for any combination of owned and borrowed values.
137    ///
138    /// Parameters:
139    /// - `other`: specifies the polynomial to subtract from `self`
140    ///
141    /// Returns the subtraction of both polynomials as a [`PolynomialRingZq`].
142    ///
143    /// # Examples
144    /// ```
145    /// use qfall_math::integer_mod_q::PolynomialRingZq;
146    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
147    /// use qfall_math::integer::PolyOverZ;
148    /// use std::str::FromStr;
149    ///
150    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
151    /// let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
152    /// let a = PolynomialRingZq::from((&poly, &modulus));
153    /// let b = PolyOverZ::from_str("4  2 0 3 1").unwrap();
154    ///
155    /// let c: PolynomialRingZq = &a - &b;
156    /// ```
157    fn sub(self, other: &PolyOverZ) -> Self::Output {
158        let mut out = self.clone();
159        out -= other;
160        out
161    }
162}
163
164arithmetic_trait_borrowed_to_owned!(Sub, sub, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
165arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
166
167impl Sub<&PolyOverZq> for &PolynomialRingZq {
168    type Output = PolynomialRingZq;
169    /// Implements the [`Sub`] trait for [`PolynomialRingZq`] and [`PolyOverZq`].
170    /// [`Sub`] is implemented for any combination of owned and borrowed values.
171    ///
172    /// Parameters:
173    /// - `other`: specifies the polynomial to subtract from `self`
174    ///
175    /// Returns the subtraction of both polynomials as a [`PolynomialRingZq`].
176    ///
177    /// # Examples
178    /// ```
179    /// use qfall_math::integer_mod_q::{PolyOverZq, PolynomialRingZq};
180    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
181    /// use qfall_math::integer::PolyOverZ;
182    /// use std::str::FromStr;
183    ///
184    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
185    /// let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
186    /// let a = PolynomialRingZq::from((&poly, &modulus));
187    /// let b = PolyOverZq::from_str("4  2 0 3 1 mod 17").unwrap();
188    ///
189    /// let c: PolynomialRingZq = &a - &b;
190    /// ```
191    ///
192    /// # Panics ...
193    /// - if the moduli mismatch.
194    fn sub(self, other: &PolyOverZq) -> Self::Output {
195        if !self.compare_base(other) {
196            panic!("{}", self.call_compare_base_error(other).unwrap())
197        }
198
199        let mut out = self.clone();
200        out -= &other.get_representative_least_nonnegative_residue();
201        out
202    }
203}
204
205arithmetic_trait_borrowed_to_owned!(Sub, sub, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
206arithmetic_trait_mixed_borrowed_owned!(Sub, sub, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
207
208impl PolynomialRingZq {
209    /// Implements subtraction for two [`PolynomialRingZq`] values.
210    ///
211    /// Parameters:
212    /// - `other`: specifies the polynomial to subtract from `self`
213    ///
214    /// Returns the result of subtraction of both polynomials as a
215    /// [`PolynomialRingZq`] or an error if the moduli mismatch.
216    ///
217    /// # Examples
218    /// ```
219    /// use qfall_math::integer_mod_q::PolynomialRingZq;
220    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
221    /// use qfall_math::integer::PolyOverZ;
222    /// use std::str::FromStr;
223    ///
224    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
225    /// let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
226    /// let a = PolynomialRingZq::from((&poly_1, &modulus));
227    /// let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
228    /// let b = PolynomialRingZq::from((&poly_2, &modulus));
229    ///
230    /// let c: PolynomialRingZq = a.sub_safe(&b).unwrap();
231    /// ```
232    /// # Errors and Failures
233    /// - Returns a [`MathError`] of type [`MathError::MismatchingModulus`] if the moduli of
234    ///   both [`PolynomialRingZq`] mismatch.
235    pub fn sub_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
236        if !self.compare_base(other) {
237            return Err(self.call_compare_base_error(other).unwrap());
238        }
239        let mut out = self.clone();
240        out.poly -= &other.get_representative_least_nonnegative_residue();
241        out.reduce();
242        Ok(out)
243    }
244}
245
246arithmetic_trait_borrowed_to_owned!(
247    Sub,
248    sub,
249    PolynomialRingZq,
250    PolynomialRingZq,
251    PolynomialRingZq
252);
253arithmetic_trait_mixed_borrowed_owned!(
254    Sub,
255    sub,
256    PolynomialRingZq,
257    PolynomialRingZq,
258    PolynomialRingZq
259);
260
261#[cfg(test)]
262mod test_sub_assign {
263    use super::PolyOverZ;
264    use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
265    use std::str::FromStr;
266
267    /// Ensure that `sub_assign` works for small numbers.
268    #[test]
269    fn correct_small() {
270        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
271        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
272        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
273        let poly_2 = PolyOverZ::from_str("4  -2 0 -3 1").unwrap();
274        let b = PolynomialRingZq::from((&poly_2, &modulus));
275        let cmp = PolynomialRingZq::from((&PolyOverZ::from_str("3  1 0 4").unwrap(), &modulus));
276
277        a -= b;
278
279        assert_eq!(cmp, a);
280    }
281
282    /// Ensure that `sub_assign` works for large numbers.
283    #[test]
284    fn correct_large() {
285        let modulus = ModulusPolynomialRingZq::from_str(&format!(
286            "4  {} 0 0 1 mod {}",
287            u64::MAX,
288            u64::MAX - 58
289        ))
290        .unwrap();
291        let poly_1 = PolyOverZ::from_str(&format!("4  {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
292        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
293        let poly_2 = PolyOverZ::from_str(&format!("4  -{} 0 1 -{}", i64::MAX, i64::MAX)).unwrap();
294        let b = PolynomialRingZq::from((&poly_2, &modulus));
295        let cmp = PolynomialRingZq::from((
296            &PolyOverZ::from_str("1  9223372036854775923").unwrap(),
297            &modulus,
298        ));
299
300        a -= b;
301
302        assert_eq!(cmp, a);
303    }
304
305    /// Ensure that `sub_assign` is available for all types.
306    #[test]
307    fn availability() {
308        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
309        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
310        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
311        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
312        let b = PolynomialRingZq::from((&poly_2, &modulus));
313        let c = PolyOverZq::from((poly_2, 17));
314
315        a -= &b;
316        a -= b;
317        a -= &poly_1;
318        a -= poly_1;
319        a -= &c;
320        a -= c;
321    }
322
323    /// Ensures that mismatching moduli result in a panic.
324    #[test]
325    #[should_panic]
326    fn mismatching_moduli() {
327        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
328        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
329        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
330        let modulus = ModulusPolynomialRingZq::from_str("4  2 0 0 1 mod 17").unwrap();
331        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
332        let b = PolynomialRingZq::from((&poly_2, &modulus));
333
334        a -= b;
335    }
336}
337
338#[cfg(test)]
339mod test_sub {
340    use crate::integer::PolyOverZ;
341    use crate::integer_mod_q::ModulusPolynomialRingZq;
342    use crate::integer_mod_q::PolynomialRingZq;
343    use std::str::FromStr;
344
345    /// Testing subtraction for two [`PolynomialRingZq`]
346    #[test]
347    fn sub() {
348        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
349        let poly_1 = PolyOverZ::from_str("4  -1 0 1 2").unwrap();
350        let a = PolynomialRingZq::from((&poly_1, &modulus));
351        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
352        let b = PolynomialRingZq::from((&poly_2, &modulus));
353        let c = a - b;
354        assert_eq!(
355            c,
356            PolynomialRingZq::from((&PolyOverZ::from_str("4  -3 0 -2 1").unwrap(), &modulus))
357        );
358    }
359
360    /// Testing subtraction for two borrowed [`PolynomialRingZq`]
361    #[test]
362    fn sub_borrow() {
363        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
364        let poly_1 = PolyOverZ::from_str("4  -1 0 1 2").unwrap();
365        let a = PolynomialRingZq::from((&poly_1, &modulus));
366        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
367        let b = PolynomialRingZq::from((&poly_2, &modulus));
368        let c = &a - &b;
369        assert_eq!(
370            c,
371            PolynomialRingZq::from((&PolyOverZ::from_str("4  -3 0 -2 1").unwrap(), &modulus))
372        );
373    }
374
375    /// Testing subtraction for borrowed [`PolynomialRingZq`] and [`PolynomialRingZq`]
376    #[test]
377    fn sub_first_borrowed() {
378        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
379        let poly_1 = PolyOverZ::from_str("4  -1 0 1 2").unwrap();
380        let a = PolynomialRingZq::from((&poly_1, &modulus));
381        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
382        let b = PolynomialRingZq::from((&poly_2, &modulus));
383        let c = &a - b;
384        assert_eq!(
385            c,
386            PolynomialRingZq::from((&PolyOverZ::from_str("4  -3 0 -2 1").unwrap(), &modulus))
387        );
388    }
389
390    /// Testing subtraction for [`PolynomialRingZq`] and borrowed [`PolynomialRingZq`]
391    #[test]
392    fn sub_second_borrowed() {
393        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
394        let poly_1 = PolyOverZ::from_str("4  -1 0 1 2").unwrap();
395        let a = PolynomialRingZq::from((&poly_1, &modulus));
396        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
397        let b = PolynomialRingZq::from((&poly_2, &modulus));
398        let c = a - &b;
399        assert_eq!(
400            c,
401            PolynomialRingZq::from((&PolyOverZ::from_str("4  -3 0 -2 1").unwrap(), &modulus))
402        );
403    }
404
405    /// Testing subtraction for [`PolynomialRingZq`] reduces `0` coefficients
406    #[test]
407    fn sub_reduce() {
408        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
409        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
410        let a = PolynomialRingZq::from((&poly_1, &modulus));
411        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
412        let b = PolynomialRingZq::from((&poly_2, &modulus));
413        let c = a - &b;
414        assert_eq!(
415            c,
416            PolynomialRingZq::from((&PolyOverZ::from_str("3  -3 0 -2").unwrap(), &modulus))
417        );
418    }
419
420    /// Testing subtraction for large [`PolynomialRingZq`]
421    #[test]
422    fn sub_large_numbers() {
423        let modulus = ModulusPolynomialRingZq::from_str(&format!(
424            "4  {} 0 0 1 mod {}",
425            u64::MAX,
426            u64::MAX - 58
427        ))
428        .unwrap();
429
430        let poly_1 = PolyOverZ::from_str(&format!("4  {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
431        let a = PolynomialRingZq::from((&poly_1, &modulus));
432
433        let poly_2 = PolyOverZ::from_str(&format!("4  {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
434        let b = PolynomialRingZq::from((&poly_2, &modulus));
435
436        let c = a - b;
437
438        assert_eq!(
439            c,
440            PolynomialRingZq::from((
441                &PolyOverZ::from_str(&format!(
442                    "4  {} 0 2 {}",
443                    (u64::MAX - 1) / 2 + 1,
444                    -18446744073709551615_i128
445                ))
446                .unwrap(),
447                &modulus
448            ))
449        );
450    }
451
452    /// Testing subtraction for [`PolynomialRingZq`] with different moduli does not work
453    #[test]
454    #[should_panic]
455    fn sub_mismatching_modulus() {
456        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
457        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
458        let a = PolynomialRingZq::from((&poly_1, &modulus));
459        let modulus = ModulusPolynomialRingZq::from_str("4  2 0 0 1 mod 17").unwrap();
460        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
461        let b = PolynomialRingZq::from((&poly_2, &modulus));
462        let _ = a - b;
463    }
464
465    /// Testing whether sub_safe throws an error for mismatching moduli
466    #[test]
467    fn sub_safe_is_err() {
468        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
469        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
470        let a = PolynomialRingZq::from((&poly_1, &modulus));
471        let modulus = ModulusPolynomialRingZq::from_str("4  2 0 0 1 mod 17").unwrap();
472        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
473        let b = PolynomialRingZq::from((&poly_2, &modulus));
474
475        assert!(&a.sub_safe(&b).is_err());
476    }
477}
478
479#[cfg(test)]
480mod test_sub_poly_over_z {
481    use super::PolynomialRingZq;
482    use crate::integer::PolyOverZ;
483    use std::str::FromStr;
484
485    /// Checks if polynomial subtraction works fine for both borrowed
486    #[test]
487    fn borrowed_correctness() {
488        let poly_1 =
489            PolynomialRingZq::from_str(&format!("2  2 {} / 4  1 2 3 1 mod {}", i64::MAX, u64::MAX))
490                .unwrap();
491        let poly_2 = PolynomialRingZq::from_str(&format!(
492            "2  1 {} / 4  1 2 3 1 mod {}",
493            i64::MAX as u64 - 2,
494            u64::MAX
495        ))
496        .unwrap();
497        let poly = PolyOverZ::from_str("2  1 2").unwrap();
498
499        let poly_1 = &poly_1 - &poly;
500
501        assert_eq!(poly_2, poly_1);
502    }
503
504    /// Checks if subtraction works fine for different types
505    #[test]
506    fn availability() {
507        let poly = PolynomialRingZq::from_str("3  1 2 3 / 4  1 2 3 1 mod 17").unwrap();
508        let z = PolyOverZ::from(2);
509
510        _ = poly.clone() - z.clone();
511        _ = &poly - &z;
512        _ = &poly - z.clone();
513        _ = poly.clone() - &z;
514    }
515}
516
517#[cfg(test)]
518mod test_sub_poly_over_zq {
519    use super::PolynomialRingZq;
520    use crate::integer_mod_q::PolyOverZq;
521    use std::str::FromStr;
522
523    /// Checks if polynomial subtraction works fine for both borrowed
524    #[test]
525    fn borrowed_correctness() {
526        let poly_1 =
527            PolynomialRingZq::from_str(&format!("2  2 {} / 4  1 2 3 1 mod {}", i64::MAX, u64::MAX))
528                .unwrap();
529        let poly_2 = PolynomialRingZq::from_str(&format!(
530            "2  1 {} / 4  1 2 3 1 mod {}",
531            i64::MAX as u64 - 1,
532            u64::MAX
533        ))
534        .unwrap();
535        let poly = PolyOverZq::from_str(&format!("2  1 1 mod {}", u64::MAX)).unwrap();
536
537        let poly_1 = &poly_1 - &poly;
538
539        assert_eq!(poly_2, poly_1);
540    }
541
542    /// Checks if subtraction works fine for different types
543    #[test]
544    fn availability() {
545        let poly = PolynomialRingZq::from_str("3  1 2 3 / 4  1 2 3 1 mod 17").unwrap();
546        let zq = PolyOverZq::from((2, 17));
547
548        _ = poly.clone() - zq.clone();
549        _ = &poly - &zq;
550        _ = &poly - zq.clone();
551        _ = poly.clone() - &zq;
552    }
553
554    /// Checks if subtraction panics if the moduli mismatch
555    #[test]
556    #[should_panic]
557    fn different_moduli_panic() {
558        let poly = PolynomialRingZq::from_str("3  1 2 3 / 4  1 2 3 1 mod 17").unwrap();
559        let zq = PolyOverZq::from((2, 16));
560
561        _ = &poly - &zq;
562    }
563}