Skip to main content

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 flint3_sys::{
23    fmpz, {fmpz_mod_add, fmpz_mod_add_fmpz, fmpz_mod_add_si, fmpz_mod_add_ui},
24};
25use std::ops::{Add, AddAssign};
26
27impl AddAssign<&Zq> for Zq {
28    /// Computes the addition of `self` and `other` reusing
29    /// the memory of `self`.
30    /// [`AddAssign`] 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 add to `self`
35    ///
36    /// Returns the sum 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 add_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_add(
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 AddAssign<i64> for Zq {
70    /// Documentation at [`Zq::add_assign`].
71    fn add_assign(&mut self, other: i64) {
72        unsafe {
73            fmpz_mod_add_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 AddAssign<u64> for Zq {
83    /// Documentation at [`Zq::add_assign`].
84    fn add_assign(&mut self, other: u64) {
85        unsafe {
86            fmpz_mod_add_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 AddAssign<&Z> for Zq {
96    /// Documentation at [`Zq::add_assign`].
97    fn add_assign(&mut self, other: &Z) {
98        unsafe {
99            fmpz_mod_add_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!(AddAssign, add_assign, Zq, Zq);
110arithmetic_assign_trait_borrowed_to_owned!(AddAssign, add_assign, Zq, Z);
111arithmetic_assign_between_types!(AddAssign, add_assign, Zq, i64, i32 i16 i8);
112arithmetic_assign_between_types!(AddAssign, add_assign, Zq, u64, u32 u16 u8);
113
114impl Add for &Zq {
115    type Output = Zq;
116    /// Implements the [`Add`] trait for two [`Zq`] values.
117    /// [`Add`] is implemented for any combination of [`Zq`] and borrowed [`Zq`].
118    ///
119    /// Parameters:
120    /// - `other`: specifies the value to add to `self`
121    ///
122    /// Returns the sum 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 add(self, other: Self) -> Self::Output {
140        self.add_safe(other).unwrap()
141    }
142}
143
144impl Zq {
145    /// Implements addition for two [`Zq`] values.
146    ///
147    ///
148    /// Parameters:
149    /// - `other`: specifies the value to add to `self`
150    ///
151    /// Returns the sum of both numbers as a [`Zq`] or an error if the modulus
152    /// does 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.add_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 add_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_add(
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!(Add, add, Zq, Zq, Zq);
188arithmetic_trait_mixed_borrowed_owned!(Add, add, Zq, Zq, Zq);
189arithmetic_between_types_zq!(Add, add, Zq, i64 i32 i16 i8 u64 u32 u16 u8);
190
191impl Add<&Z> for &Zq {
192    type Output = Zq;
193
194    /// Implements the [`Add`] trait for [`Zq`] and [`Z`] values.
195    /// [`Add`] is implemented for any combination of owned and borrowed values.
196    ///
197    /// Parameters:
198    ///  - `other`: specifies the value to add to `self`
199    ///
200    /// Returns the sum of both numbers as a [`Zq`].
201    ///
202    /// # Examples
203    /// ```
204    /// use qfall_math::integer_mod_q::Zq;
205    /// use qfall_math::integer::Z;
206    /// use std::str::FromStr;
207    ///
208    /// let a: Zq = Zq::from((42, 19));
209    /// let b: Z = Z::from(42);
210    ///
211    /// let c: Zq = &a + &b;
212    /// let d: Zq = a + b;
213    /// let e: Zq = &c + Z::from(42);
214    /// let f: Zq = c + &Z::from(42);
215    /// ```
216    fn add(self, other: &Z) -> Self::Output {
217        let mut out: fmpz = 0;
218        unsafe {
219            fmpz_mod_add_fmpz(
220                &mut out,
221                &self.value.value,
222                &other.value,
223                self.modulus.get_fmpz_mod_ctx_struct(),
224            );
225        }
226        Zq {
227            modulus: self.modulus.clone(),
228            value: Z { value: out },
229        }
230    }
231}
232
233arithmetic_trait_borrowed_to_owned!(Add, add, Zq, Z, Zq);
234arithmetic_trait_mixed_borrowed_owned!(Add, add, Zq, Z, Zq);
235
236#[cfg(test)]
237mod test_add_assign {
238    use crate::{integer::Z, integer_mod_q::Zq};
239
240    /// Ensure that `add_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((1, 7));
246
247        a += &b;
248        assert_eq!(Zq::from((5, 7)), a);
249        a += &c;
250        assert_eq!(Zq::from((6, 7)), a);
251        a += &c;
252        assert_eq!(Zq::from((0, 7)), a);
253        a += &c;
254        assert_eq!(Zq::from((1, 7)), a);
255        a += &c;
256        assert_eq!(Zq::from((2, 7)), a);
257        a += 2 * b;
258        assert_eq!(Zq::from((0, 7)), a);
259    }
260
261    /// Ensure that `add_assign` works for large numbers.
262    #[test]
263    fn correct_large() {
264        let mut a = Zq::from((i64::MAX, u64::MAX));
265        let b = Zq::from((i64::MIN + 2, u64::MAX));
266        let c = Zq::from((u64::MAX - 1, u64::MAX));
267
268        a += b;
269        assert_eq!(Zq::from((1, u64::MAX)), a);
270        a += c;
271        assert_eq!(Zq::from((0, u64::MAX)), a);
272    }
273
274    /// Ensure that `add_assign` is available for all types.
275    #[test]
276    fn availability() {
277        let mut a = Zq::from((3, 7));
278        let b = Zq::from((1, 7));
279        let c = Z::from(1);
280
281        a += &b;
282        a += b;
283        a += &c;
284        a += c;
285        a += 1_u8;
286        a += 1_u16;
287        a += 1_u32;
288        a += 1_u64;
289        a += 1_i8;
290        a += 1_i16;
291        a += 1_i32;
292        a += 1_i64;
293    }
294
295    /// Ensures that mismatching moduli result in a panic.
296    #[test]
297    #[should_panic]
298    fn mismatching_moduli() {
299        let mut a = Zq::from((3, 7));
300        let b = Zq::from((1, 8));
301
302        a += b;
303    }
304}
305
306#[cfg(test)]
307mod test_add {
308    use super::Zq;
309
310    /// Testing addition for two [`Zq`]
311    #[test]
312    fn add() {
313        let a: Zq = Zq::from((11, 17));
314        let b: Zq = Zq::from((12, 17));
315        let c: Zq = a + b;
316        assert_eq!(c, Zq::from((6, 17)));
317    }
318
319    /// Testing addition for two borrowed [`Zq`]
320    #[test]
321    fn add_borrow() {
322        let a: Zq = Zq::from((10, 11));
323        let b: Zq = Zq::from((1, 11));
324        let c: Zq = &a + &b;
325        assert_eq!(c, Zq::from((0, 11)));
326    }
327
328    /// Testing addition for borrowed [`Zq`] and [`Zq`]
329    #[test]
330    fn add_first_borrowed() {
331        let a: Zq = Zq::from((2, 11));
332        let b: Zq = Zq::from((5, 11));
333        let c: Zq = &a + b;
334        assert_eq!(c, Zq::from((7, 11)));
335    }
336
337    /// Testing addition for [`Zq`] and borrowed [`Zq`]
338    #[test]
339    fn add_second_borrowed() {
340        let a: Zq = Zq::from((12, 11));
341        let b: Zq = Zq::from((10, 11));
342        let c: Zq = a + &b;
343        assert_eq!(c, Zq::from((0, 11)));
344    }
345
346    /// Testing addition for large [`Zq`]
347    #[test]
348    fn add_large_numbers() {
349        let a: Zq = Zq::from((u32::MAX, u32::MAX - 58));
350        let b: Zq = Zq::from((i32::MAX, u32::MAX - 58));
351        let c: Zq = a + b;
352        assert_eq!(c, Zq::from(((u32::MAX - 1) / 2 + 58, u32::MAX - 58)));
353    }
354
355    /// Testing addition for [`Zq`] with different moduli does not work
356    #[test]
357    #[should_panic]
358    fn add_mismatching_modulus() {
359        let a: Zq = Zq::from((4, 11));
360        let b: Zq = Zq::from((1, 3));
361        let _c: Zq = a + b;
362    }
363
364    /// Testing whether add_safe throws an error for mismatching moduli
365    #[test]
366    fn add_safe_is_err() {
367        let a: Zq = Zq::from((4, 11));
368        let b: Zq = Zq::from((1, 3));
369        assert!(&a.add_safe(&b).is_err());
370    }
371}
372
373#[cfg(test)]
374mod test_add_between_zq_and_z {
375    use super::Z;
376    use crate::integer_mod_q::Zq;
377
378    /// Testing addition for [`Zq`] and [`Z`]
379    #[test]
380    fn add() {
381        let a: Zq = Zq::from((4, 11));
382        let b: Z = Z::from(9);
383        let c: Zq = a + b;
384        assert_eq!(c, Zq::from((2, 11)));
385    }
386
387    /// Testing addition for both borrowed [`Zq`] and [`Z`]
388    #[test]
389    fn add_borrow() {
390        let a: Zq = Zq::from((4, 11));
391        let b: Z = Z::from(9);
392        let c: Zq = &a + &b;
393        assert_eq!(c, Zq::from((2, 11)));
394    }
395
396    /// Testing addition for borrowed [`Zq`] and [`Z`]
397    #[test]
398    fn add_first_borrowed() {
399        let a: Zq = Zq::from((4, 11));
400        let b: Z = Z::from(9);
401        let c: Zq = &a + b;
402        assert_eq!(c, Zq::from((2, 11)));
403    }
404
405    /// Testing addition for [`Zq`] and borrowed [`Z`]
406    #[test]
407    fn add_second_borrowed() {
408        let a: Zq = Zq::from((4, 11));
409        let b: Z = Z::from(9);
410        let c: Zq = a + &b;
411        assert_eq!(c, Zq::from((2, 11)));
412    }
413
414    /// Testing addition for large numbers
415    #[test]
416    fn add_large_numbers() {
417        let a: Zq = Zq::from((i64::MAX, u64::MAX - 58));
418        let b: Zq = Zq::from((i64::MAX - 1, i64::MAX));
419        let c: Z = Z::from(u64::MAX);
420
421        let d: Zq = a + &c;
422        let e: Zq = b + c;
423
424        assert_eq!(d, Zq::from(((u64::MAX - 1) / 2 + 58, u64::MAX - 58)));
425        assert_eq!(e, Zq::from((0, i64::MAX)));
426    }
427}
428
429#[cfg(test)]
430mod test_add_between_types {
431    use crate::integer_mod_q::Zq;
432
433    /// Testing addition between different types
434    #[test]
435    #[allow(clippy::op_ref)]
436    fn add() {
437        let a: Zq = Zq::from((4, 11));
438        let b: u64 = 1;
439        let c: u32 = 1;
440        let d: u16 = 1;
441        let e: u8 = 1;
442        let f: i64 = 1;
443        let g: i32 = 1;
444        let h: i16 = 1;
445        let i: i8 = 1;
446
447        let _: Zq = &a + &b;
448        let _: Zq = &a + &c;
449        let _: Zq = &a + &d;
450        let _: Zq = &a + &e;
451        let _: Zq = &a + &f;
452        let _: Zq = &a + &g;
453        let _: Zq = &a + &h;
454        let _: Zq = &a + &i;
455
456        let _: Zq = &b + &a;
457        let _: Zq = &c + &a;
458        let _: Zq = &d + &a;
459        let _: Zq = &e + &a;
460        let _: Zq = &f + &a;
461        let _: Zq = &g + &a;
462        let _: Zq = &h + &a;
463        let _: Zq = &i + &a;
464
465        let _: Zq = &a + b;
466        let _: Zq = &a + c;
467        let _: Zq = &a + d;
468        let _: Zq = &a + e;
469        let _: Zq = &a + f;
470        let _: Zq = &a + g;
471        let _: Zq = &a + h;
472        let _: Zq = &a + i;
473
474        let _: Zq = &b + Zq::from((4, 11));
475        let _: Zq = &c + Zq::from((4, 11));
476        let _: Zq = &d + Zq::from((4, 11));
477        let _: Zq = &e + Zq::from((4, 11));
478        let _: Zq = &f + Zq::from((4, 11));
479        let _: Zq = &g + Zq::from((4, 11));
480        let _: Zq = &h + Zq::from((4, 11));
481        let _: Zq = &i + Zq::from((4, 11));
482
483        let _: Zq = Zq::from((4, 11)) + &b;
484        let _: Zq = Zq::from((4, 11)) + &c;
485        let _: Zq = Zq::from((4, 11)) + &d;
486        let _: Zq = Zq::from((4, 11)) + &e;
487        let _: Zq = Zq::from((4, 11)) + &f;
488        let _: Zq = Zq::from((4, 11)) + &g;
489        let _: Zq = Zq::from((4, 11)) + &h;
490        let _: Zq = Zq::from((4, 11)) + &i;
491
492        let _: Zq = b + &a;
493        let _: Zq = c + &a;
494        let _: Zq = d + &a;
495        let _: Zq = e + &a;
496        let _: Zq = f + &a;
497        let _: Zq = g + &a;
498        let _: Zq = h + &a;
499        let _: Zq = i + &a;
500
501        let _: Zq = Zq::from((4, 11)) + b;
502        let _: Zq = Zq::from((4, 11)) + c;
503        let _: Zq = Zq::from((4, 11)) + d;
504        let _: Zq = Zq::from((4, 11)) + e;
505        let _: Zq = Zq::from((4, 11)) + f;
506        let _: Zq = Zq::from((4, 11)) + g;
507        let _: Zq = Zq::from((4, 11)) + h;
508        let _: Zq = Zq::from((4, 11)) + i;
509
510        let _: Zq = b + Zq::from((4, 11));
511        let _: Zq = c + Zq::from((4, 11));
512        let _: Zq = d + Zq::from((4, 11));
513        let _: Zq = e + Zq::from((4, 11));
514        let _: Zq = f + Zq::from((4, 11));
515        let _: Zq = g + Zq::from((4, 11));
516        let _: Zq = h + Zq::from((4, 11));
517        let _: Zq = i + Zq::from((4, 11));
518    }
519}