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