qfall_math/integer_mod_q/polynomial_ring_zq/arithmetic/
add.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 [`Add`] 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, arithmetic_trait_reverse,
19    },
20    traits::CompareBase,
21};
22use flint_sys::fq::fq_add;
23use std::ops::{Add, AddAssign};
24
25impl AddAssign<&PolynomialRingZq> for PolynomialRingZq {
26    /// Computes the addition of `self` and `other` reusing
27    /// the memory of `self`.
28    /// [`AddAssign`] can be used on [`PolynomialRingZq`] in combination with
29    /// [`PolynomialRingZq`], [`PolyOverZ`] and [`PolyOverZq`].
30    ///
31    /// Parameters:
32    /// - `other`: specifies the polynomial to add to `self`
33    ///
34    /// Returns the sum 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 add_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_add(
66                &mut self.poly.poly,
67                &self.poly.poly,
68                &other.poly.poly,
69                self.modulus.get_fq_ctx(),
70            );
71        };
72    }
73}
74impl AddAssign<&PolyOverZ> for PolynomialRingZq {
75    /// Documentation at [`PolynomialRingZq::add_assign`].
76    fn add_assign(&mut self, other: &PolyOverZ) {
77        self.poly += other;
78        self.reduce();
79    }
80}
81impl AddAssign<&PolyOverZq> for PolynomialRingZq {
82    /// Documentation at [`PolynomialRingZq::add_assign`].
83    ///
84    /// # Panics ...
85    /// - if the moduli are different.
86    fn add_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_add(
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    AddAssign,
106    add_assign,
107    PolynomialRingZq,
108    PolynomialRingZq
109);
110arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZ);
111arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, PolynomialRingZq, PolyOverZq);
112
113impl Add for &PolynomialRingZq {
114    type Output = PolynomialRingZq;
115    /// Implements the [`Add`] trait for two [`PolynomialRingZq`] values.
116    /// [`Add`] is implemented for any combination of [`PolynomialRingZq`] and borrowed [`PolynomialRingZq`].
117    ///
118    /// Parameters:
119    /// - `other`: specifies the polynomial to add to `self`
120    ///
121    /// Returns the sum 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 add(self, other: Self) -> Self::Output {
145        self.add_safe(other).unwrap()
146    }
147}
148
149impl Add<&PolyOverZ> for &PolynomialRingZq {
150    type Output = PolynomialRingZq;
151    /// Implements the [`Add`] trait for [`PolynomialRingZq`] and [`PolyOverZ`].
152    /// [`Add`] is implemented for any combination of owned and borrowed values.
153    ///
154    /// Parameters:
155    /// - `other`: specifies the polynomial to add to `self`
156    ///
157    /// Returns the addition 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 add(self, other: &PolyOverZ) -> Self::Output {
174        let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
175        unsafe {
176            fq_add(
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_reverse!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
188
189arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
190arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
191arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZ, PolynomialRingZq);
192arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZ, PolynomialRingZq, PolynomialRingZq);
193
194impl Add<&PolyOverZq> for &PolynomialRingZq {
195    type Output = PolynomialRingZq;
196    /// Implements the [`Add`] trait for [`PolynomialRingZq`] and [`PolyOverZq`].
197    /// [`Add`] is implemented for any combination of owned and borrowed values.
198    ///
199    /// Parameters:
200    /// - `other`: specifies the polynomial to add to `self`
201    ///
202    /// Returns the addition of both polynomials as a [`PolynomialRingZq`].
203    ///
204    /// # Examples
205    /// ```
206    /// use qfall_math::integer_mod_q::{PolyOverZq, PolynomialRingZq};
207    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
208    /// use qfall_math::integer::PolyOverZ;
209    /// use std::str::FromStr;
210    ///
211    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
212    /// let poly = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
213    /// let a = PolynomialRingZq::from((&poly, &modulus));
214    /// let b = PolyOverZq::from_str("4  2 0 3 1 mod 17").unwrap();
215    ///
216    /// let c: PolynomialRingZq = &a + &b;
217    /// ```
218    ///
219    /// # Panics ...
220    /// - if the moduli mismatch.
221    fn add(self, other: &PolyOverZq) -> Self::Output {
222        assert_eq!(
223            self.modulus.get_q(),
224            other.modulus,
225            "Tried to add polynomials with different moduli."
226        );
227
228        let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
229        unsafe {
230            fq_add(
231                &mut out.poly.poly,
232                &self.poly.poly,
233                &other.get_representative_least_nonnegative_residue().poly,
234                self.modulus.get_fq_ctx(),
235            );
236        }
237        out
238    }
239}
240
241arithmetic_trait_reverse!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
242
243arithmetic_trait_borrowed_to_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
244arithmetic_trait_borrowed_to_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
245arithmetic_trait_mixed_borrowed_owned!(Add, add, PolynomialRingZq, PolyOverZq, PolynomialRingZq);
246arithmetic_trait_mixed_borrowed_owned!(Add, add, PolyOverZq, PolynomialRingZq, PolynomialRingZq);
247
248impl PolynomialRingZq {
249    /// Implements addition for two [`PolynomialRingZq`] values.
250    ///
251    /// Parameters:
252    /// - `other`: specifies the polynomial to add to `self`
253    ///
254    /// Returns the sum of both polynomials as a [`PolynomialRingZq`] or an error if the moduli
255    /// mismatch.
256    ///
257    /// # Examples
258    /// ```
259    /// use qfall_math::integer_mod_q::PolynomialRingZq;
260    /// use qfall_math::integer_mod_q::ModulusPolynomialRingZq;
261    /// use qfall_math::integer::PolyOverZ;
262    /// use std::str::FromStr;
263    ///
264    /// let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
265    /// let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
266    /// let a = PolynomialRingZq::from((&poly_1, &modulus));
267    /// let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
268    /// let b = PolynomialRingZq::from((&poly_2, &modulus));
269    ///
270    /// let c: PolynomialRingZq = a.add_safe(&b).unwrap();
271    /// ```
272    /// # Errors and Failures
273    /// - Returns a [`MathError`] of type [`MathError::MismatchingModulus`] if the moduli of
274    ///   both [`PolynomialRingZq`] mismatch.
275    pub fn add_safe(&self, other: &Self) -> Result<PolynomialRingZq, MathError> {
276        if !self.compare_base(other) {
277            return Err(self.call_compare_base_error(other).unwrap());
278        }
279        let mut out = PolynomialRingZq::from((&PolyOverZ::default(), &self.modulus));
280        unsafe {
281            fq_add(
282                &mut out.poly.poly,
283                &self.poly.poly,
284                &other.poly.poly,
285                self.modulus.get_fq_ctx(),
286            );
287        }
288        Ok(out)
289    }
290}
291
292arithmetic_trait_borrowed_to_owned!(
293    Add,
294    add,
295    PolynomialRingZq,
296    PolynomialRingZq,
297    PolynomialRingZq
298);
299arithmetic_trait_mixed_borrowed_owned!(
300    Add,
301    add,
302    PolynomialRingZq,
303    PolynomialRingZq,
304    PolynomialRingZq
305);
306
307#[cfg(test)]
308mod test_add_assign {
309    use super::PolyOverZ;
310    use crate::integer_mod_q::{ModulusPolynomialRingZq, PolyOverZq, PolynomialRingZq};
311    use std::str::FromStr;
312
313    /// Ensure that `add_assign` works for small numbers.
314    #[test]
315    fn correct_small() {
316        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
317        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
318        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
319        let poly_2 = PolyOverZ::from_str("4  2 0 3 -1").unwrap();
320        let b = PolynomialRingZq::from((&poly_2, &modulus));
321        let cmp = PolynomialRingZq::from((&PolyOverZ::from_str("3  1 0 4").unwrap(), &modulus));
322
323        a += b;
324
325        assert_eq!(cmp, a);
326    }
327
328    /// Ensure that `add_assign` works for large numbers.
329    #[test]
330    fn correct_large() {
331        let modulus = ModulusPolynomialRingZq::from_str(&format!(
332            "4  {} 0 0 {} mod {}",
333            u64::MAX,
334            i64::MIN,
335            u64::MAX - 58
336        ))
337        .unwrap();
338        let poly_1 = PolyOverZ::from_str(&format!("4  {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
339        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
340        let poly_2 = PolyOverZ::from_str(&format!("4  {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
341        let b = PolynomialRingZq::from((&poly_2, &modulus));
342        let cmp = PolynomialRingZq::from((
343            &PolyOverZ::from_str(&format!("4  {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1)).unwrap(),
344            &modulus,
345        ));
346
347        a += b;
348
349        assert_eq!(cmp, a);
350    }
351
352    /// Ensure that `add_assign` is available for all types.
353    #[test]
354    fn availability() {
355        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
356        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
357        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
358        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
359        let b = PolynomialRingZq::from((&poly_2, &modulus));
360        let c = PolyOverZq::from((poly_2, 17));
361
362        a += &b;
363        a += b;
364        a += &poly_1;
365        a += poly_1;
366        a += &c;
367        a += c;
368    }
369
370    /// Ensures that mismatching moduli result in a panic.
371    #[test]
372    #[should_panic]
373    fn mismatching_moduli() {
374        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
375        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
376        let mut a = PolynomialRingZq::from((&poly_1, &modulus));
377        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 2 mod 17").unwrap();
378        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
379        let b = PolynomialRingZq::from((&poly_2, &modulus));
380
381        a += b;
382    }
383}
384
385#[cfg(test)]
386mod test_add {
387    use crate::integer::PolyOverZ;
388    use crate::integer_mod_q::ModulusPolynomialRingZq;
389    use crate::integer_mod_q::PolynomialRingZq;
390    use std::str::FromStr;
391
392    /// Testing addition for two [`PolynomialRingZq`]
393    #[test]
394    fn add() {
395        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
396        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
397        let a = PolynomialRingZq::from((&poly_1, &modulus));
398        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
399        let b = PolynomialRingZq::from((&poly_2, &modulus));
400        let c = a + b;
401        assert_eq!(
402            c,
403            PolynomialRingZq::from((&PolyOverZ::from_str("4  1 0 4 2").unwrap(), &modulus))
404        );
405    }
406
407    /// Testing addition for two borrowed [`PolynomialRingZq`]
408    #[test]
409    fn add_borrow() {
410        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
411        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
412        let a = PolynomialRingZq::from((&poly_1, &modulus));
413        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
414        let b = PolynomialRingZq::from((&poly_2, &modulus));
415        let c = &a + &b;
416        assert_eq!(
417            c,
418            PolynomialRingZq::from((&PolyOverZ::from_str("4  1 0 4 2").unwrap(), &modulus))
419        );
420    }
421
422    /// Testing addition for borrowed [`PolynomialRingZq`] and [`PolynomialRingZq`]
423    #[test]
424    fn add_first_borrowed() {
425        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
426        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
427        let a = PolynomialRingZq::from((&poly_1, &modulus));
428        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
429        let b = PolynomialRingZq::from((&poly_2, &modulus));
430        let c = &a + b;
431        assert_eq!(
432            c,
433            PolynomialRingZq::from((&PolyOverZ::from_str("4  1 0 4 2").unwrap(), &modulus))
434        );
435    }
436
437    /// Testing addition for [`PolynomialRingZq`] and borrowed [`PolynomialRingZq`]
438    #[test]
439    fn add_second_borrowed() {
440        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
441        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
442        let a = PolynomialRingZq::from((&poly_1, &modulus));
443        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
444        let b = PolynomialRingZq::from((&poly_2, &modulus));
445        let c = a + &b;
446        assert_eq!(
447            c,
448            PolynomialRingZq::from((&PolyOverZ::from_str("4  1 0 4 2").unwrap(), &modulus))
449        );
450    }
451
452    /// Testing addition for [`PolynomialRingZq`] reduces `0` coefficients
453    #[test]
454    fn add_reduce() {
455        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
456        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
457        let a = PolynomialRingZq::from((&poly_1, &modulus));
458        let poly_2 = PolyOverZ::from_str("4  2 0 3 -1").unwrap();
459        let b = PolynomialRingZq::from((&poly_2, &modulus));
460        let c = a + &b;
461        assert_eq!(
462            c,
463            PolynomialRingZq::from((&PolyOverZ::from_str("3  1 0 4").unwrap(), &modulus))
464        );
465    }
466
467    /// Testing addition for large [`PolynomialRingZq`]
468    #[test]
469    fn add_large_numbers() {
470        let modulus = ModulusPolynomialRingZq::from_str(&format!(
471            "4  {} 0 0 {} mod {}",
472            u64::MAX,
473            i64::MIN,
474            u64::MAX - 58
475        ))
476        .unwrap();
477
478        let poly_1 = PolyOverZ::from_str(&format!("4  {} 0 1 {}", u64::MAX, i64::MIN)).unwrap();
479        let a = PolynomialRingZq::from((&poly_1, &modulus));
480
481        let poly_2 = PolyOverZ::from_str(&format!("4  {} 0 -1 {}", i64::MAX, i64::MAX)).unwrap();
482        let b = PolynomialRingZq::from((&poly_2, &modulus));
483
484        let c = a + b;
485        assert_eq!(
486            c,
487            PolynomialRingZq::from((
488                &PolyOverZ::from_str(&format!("4  {} 0 0 {}", (u64::MAX - 1) / 2 + 58, -1))
489                    .unwrap(),
490                &modulus
491            ))
492        );
493    }
494
495    /// Testing addition for [`PolynomialRingZq`] with different moduli does not work
496    #[test]
497    #[should_panic]
498    fn add_mismatching_modulus() {
499        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
500        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
501        let a = PolynomialRingZq::from((&poly_1, &modulus));
502        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 2 mod 17").unwrap();
503        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
504        let b = PolynomialRingZq::from((&poly_2, &modulus));
505        let _ = a + b;
506    }
507
508    /// Testing whether add_safe throws an error for mismatching moduli
509    #[test]
510    fn add_safe_is_err() {
511        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 1 mod 17").unwrap();
512        let poly_1 = PolyOverZ::from_str("4  -1 0 1 1").unwrap();
513        let a = PolynomialRingZq::from((&poly_1, &modulus));
514        let modulus = ModulusPolynomialRingZq::from_str("4  1 0 0 2 mod 17").unwrap();
515        let poly_2 = PolyOverZ::from_str("4  2 0 3 1").unwrap();
516        let b = PolynomialRingZq::from((&poly_2, &modulus));
517
518        assert!(&a.add_safe(&b).is_err());
519    }
520}
521
522#[cfg(test)]
523mod test_add_poly_over_z {
524    use super::PolynomialRingZq;
525    use crate::integer::PolyOverZ;
526    use std::str::FromStr;
527
528    /// Checks if polynomial addition works fine for both borrowed
529    #[test]
530    fn borrowed_correctness() {
531        let poly_1 =
532            PolynomialRingZq::from_str(&format!("2  2 {} / 4  1 2 3 4 mod {}", i64::MAX, u64::MAX))
533                .unwrap();
534        let poly_2 = PolynomialRingZq::from_str(&format!(
535            "2  3 {} / 4  1 2 3 4 mod {}",
536            i64::MAX as u64 + 2,
537            u64::MAX
538        ))
539        .unwrap();
540        let poly = PolyOverZ::from_str("2  1 2").unwrap();
541
542        let poly_1 = &poly_1 + &poly;
543
544        assert_eq!(poly_2, poly_1);
545    }
546
547    /// Checks if addition works fine for different types
548    #[test]
549    fn availability() {
550        let poly = PolynomialRingZq::from_str("3  1 2 3 / 4  1 2 3 4 mod 17").unwrap();
551        let z = PolyOverZ::from(2);
552
553        _ = poly.clone() + z.clone();
554        _ = z.clone() + poly.clone();
555        _ = &poly + &z;
556        _ = &z + &poly;
557        _ = &poly + z.clone();
558        _ = z.clone() + &poly;
559        _ = &z + poly.clone();
560        _ = poly.clone() + &z;
561    }
562}
563
564#[cfg(test)]
565mod test_add_poly_over_zq {
566    use super::PolynomialRingZq;
567    use crate::integer_mod_q::PolyOverZq;
568    use std::str::FromStr;
569
570    /// Checks if polynomial addition works fine for both borrowed
571    #[test]
572    fn borrowed_correctness() {
573        let poly_1 =
574            PolynomialRingZq::from_str(&format!("2  2 {} / 4  1 2 3 4 mod {}", i64::MAX, u64::MAX))
575                .unwrap();
576        let poly_2 = PolynomialRingZq::from_str(&format!(
577            "2  3 {} / 4  1 2 3 4 mod {}",
578            i64::MAX as u64 + 2,
579            u64::MAX
580        ))
581        .unwrap();
582        let poly = PolyOverZq::from_str(&format!("2  1 2 mod {}", u64::MAX)).unwrap();
583
584        let poly_1 = &poly_1 + &poly;
585
586        assert_eq!(poly_2, poly_1);
587    }
588
589    /// Checks if addition works fine for different types
590    #[test]
591    fn availability() {
592        let poly = PolynomialRingZq::from_str("3  1 2 3 / 4  1 2 3 4 mod 17").unwrap();
593        let zq = PolyOverZq::from((2, 17));
594
595        _ = poly.clone() + zq.clone();
596        _ = zq.clone() + poly.clone();
597        _ = &poly + &zq;
598        _ = &zq + &poly;
599        _ = &poly + zq.clone();
600        _ = zq.clone() + &poly;
601        _ = &zq + poly.clone();
602        _ = poly.clone() + &zq;
603    }
604
605    /// Checks if addition panics if the moduli mismatch
606    #[test]
607    #[should_panic]
608    fn different_moduli_panic() {
609        let poly = PolynomialRingZq::from_str("3  1 2 3 / 4  1 2 3 4 mod 17").unwrap();
610        let zq = PolyOverZq::from((2, 16));
611
612        _ = &poly + &zq;
613    }
614}