Skip to main content

qfall_math/integer_mod_q/z_q/arithmetic/
neg.rs

1// Copyright 2026 Jan Niklas Siemer
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 [`Neg`] trait for [`Zq`] values.
10
11use super::super::Zq;
12use crate::integer::Z;
13use flint3_sys::fmpz_mod_neg;
14use std::ops::Neg;
15
16impl Neg for Zq {
17    type Output = Zq;
18
19    /// Implements the [`Neg`] trait for [`Zq`] values.
20    /// [`Neg`] is implemented for both borrowed and owned [`Zq`].
21    ///
22    /// When called on owned [`Zq`] it will reuse the memory of `self`.
23    ///
24    /// Returns the additive inverse of `self` as a [`Zq`].
25    ///
26    /// # Examples
27    /// ```
28    /// use qfall_math::integer_mod_q::Zq;
29    ///
30    /// let a: Zq = Zq::from((42, 17));
31    ///
32    /// let b: Zq = -&a;
33    /// let c: Zq = -a;
34    /// ```
35    fn neg(mut self) -> Self::Output {
36        unsafe {
37            fmpz_mod_neg(
38                &mut self.value.value,
39                &self.value.value,
40                self.modulus.get_fmpz_mod_ctx_struct(),
41            )
42        };
43        self
44    }
45}
46
47impl Neg for &Zq {
48    type Output = Zq;
49
50    /// Documentation at [`Zq::neg`].
51    fn neg(self) -> Self::Output {
52        let mut out = Z::ZERO;
53        unsafe {
54            fmpz_mod_neg(
55                &mut out.value,
56                &self.value.value,
57                self.modulus.get_fmpz_mod_ctx_struct(),
58            )
59        };
60        Zq {
61            value: out,
62            modulus: self.modulus.clone(),
63        }
64    }
65}
66
67#[cfg(test)]
68mod test_neg {
69    use super::Zq;
70    use crate::integer::Z;
71
72    /// Ensure that `neg` works for small values.
73    #[test]
74    fn correct_small() {
75        let a = Zq::from((1, 17));
76        let b = Zq::from((-1, 17));
77        let c = Zq::from((0, 17));
78
79        assert_eq!(a, -(-&a));
80        assert_eq!(a, -&b);
81        assert_eq!(b, -&a);
82        assert_eq!(a, -b.clone());
83        assert_eq!(b, -a);
84        assert_eq!(c, -&c);
85        assert_eq!(c.clone(), -c);
86    }
87
88    /// Ensure that `neg` works for large values and moduli.
89    #[test]
90    fn correct_large() {
91        let a = Zq::from((i64::MAX, u64::MAX));
92        let b = Zq::from((u64::MAX - i64::MAX as u64, u64::MAX));
93
94        assert_eq!(a, -(-&a));
95        assert_eq!(b, -&a);
96        assert_eq!(b, -a);
97    }
98
99    /// Ensure that the result is reduced to the least non-negative residue
100    /// and that the modulus is kept.
101    #[test]
102    fn reduced() {
103        let a = Zq::from((3, 17));
104        let c = Zq::from((0, 17));
105
106        let neg_a = -&a;
107        let neg_c = -c;
108
109        assert_eq!(
110            Z::from(14),
111            neg_a.get_representative_least_nonnegative_residue()
112        );
113        assert_eq!(
114            Z::from(14),
115            (-a).get_representative_least_nonnegative_residue()
116        );
117        assert_eq!(
118            Z::ZERO,
119            neg_c.get_representative_least_nonnegative_residue()
120        );
121        assert_eq!(Z::from(17), neg_a.get_mod());
122    }
123}