Skip to main content

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