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