Skip to main content

qfall_math/integer_mod_q/z_q/arithmetic/
mul.rs

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