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