crypto_bigint/int/
neg.rs

1//! [`Int`] negation-related operations.
2
3use crate::{ConstChoice, ConstCtOption, Int, Uint};
4
5impl<const LIMBS: usize> Int<LIMBS> {
6    /// Map this [`Int`] to its two's-complement negation:
7    /// map `self` to `(self ^ 1111...1111) + 0000...0001`.
8    ///
9    /// Returns the negation, as well as whether the operation overflowed.
10    /// The operation overflows when attempting to negate [`Int::MIN`]; the positive counterpart
11    /// of this value cannot be represented.
12    pub const fn overflowing_neg(&self) -> (Self, ConstChoice) {
13        Self(self.0.bitxor(&Uint::MAX)).overflowing_add(&Int::ONE)
14    }
15
16    /// Wrapping negate this [`Int`].
17    ///
18    /// Warning: this operation maps [`Int::MIN`] to itself, since the positive counterpart of this
19    /// value cannot be represented.
20    pub const fn wrapping_neg(&self) -> Self {
21        self.overflowing_neg().0
22    }
23
24    /// Wrapping negate this [`Int`] if `negate` is truthy; otherwise do nothing.
25    ///
26    /// Warning: this operation maps [`Int::MIN`] to itself, since the positive counterpart of this
27    /// value cannot be represented.
28    pub const fn wrapping_neg_if(&self, negate: ConstChoice) -> Int<LIMBS> {
29        Self(self.0.wrapping_neg_if(negate))
30    }
31
32    /// Negate this [`Int`].
33    ///
34    /// Yields `None` when `self == Self::MIN`, since the positive counterpart of this value cannot
35    /// be represented.
36    pub const fn checked_neg(&self) -> ConstCtOption<Self> {
37        let (value, overflow) = self.overflowing_neg();
38        ConstCtOption::new(value, overflow.not())
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use crate::{ConstChoice, I128};
45
46    #[test]
47    fn overflowing_neg() {
48        let min_plus_one = I128 {
49            0: I128::MIN.0.wrapping_add(&I128::ONE.0),
50        };
51
52        let (res, overflow) = I128::MIN.overflowing_neg();
53        assert_eq!(res, I128::MIN);
54        assert_eq!(overflow, ConstChoice::TRUE);
55
56        let (res, overflow) = I128::MINUS_ONE.overflowing_neg();
57        assert_eq!(res, I128::ONE);
58        assert_eq!(overflow, ConstChoice::FALSE);
59
60        let (res, overflow) = I128::ZERO.overflowing_neg();
61        assert_eq!(res, I128::ZERO);
62        assert_eq!(overflow, ConstChoice::FALSE);
63
64        let (res, overflow) = I128::ONE.overflowing_neg();
65        assert_eq!(res, I128::MINUS_ONE);
66        assert_eq!(overflow, ConstChoice::FALSE);
67
68        let (res, overflow) = I128::MAX.overflowing_neg();
69        assert_eq!(res, min_plus_one);
70        assert_eq!(overflow, ConstChoice::FALSE);
71    }
72
73    #[test]
74    fn wrapping_neg_if() {
75        let min_plus_one = I128 {
76            0: I128::MIN.0.wrapping_add(&I128::ONE.0),
77        };
78
79        let do_negate = ConstChoice::TRUE;
80        assert_eq!(I128::MIN.wrapping_neg_if(do_negate), I128::MIN);
81        assert_eq!(I128::MINUS_ONE.wrapping_neg_if(do_negate), I128::ONE);
82        assert_eq!(I128::ZERO.wrapping_neg_if(do_negate), I128::ZERO);
83        assert_eq!(I128::ONE.wrapping_neg_if(do_negate), I128::MINUS_ONE);
84        assert_eq!(I128::MAX.wrapping_neg_if(do_negate), min_plus_one);
85
86        let do_not_negate = ConstChoice::FALSE;
87        assert_eq!(I128::MIN.wrapping_neg_if(do_not_negate), I128::MIN);
88        assert_eq!(
89            I128::MINUS_ONE.wrapping_neg_if(do_not_negate),
90            I128::MINUS_ONE
91        );
92        assert_eq!(I128::ZERO.wrapping_neg_if(do_not_negate), I128::ZERO);
93        assert_eq!(I128::ONE.wrapping_neg_if(do_not_negate), I128::ONE);
94        assert_eq!(I128::MAX.wrapping_neg_if(do_not_negate), I128::MAX);
95    }
96
97    #[test]
98    fn checked_neg() {
99        assert_eq!(I128::MIN.checked_neg().is_none(), ConstChoice::TRUE);
100        assert_eq!(I128::MINUS_ONE.checked_neg().unwrap(), I128::ONE);
101        assert_eq!(I128::ZERO.checked_neg().unwrap(), I128::ZERO);
102        assert_eq!(I128::ONE.checked_neg().unwrap(), I128::MINUS_ONE);
103        assert_eq!(
104            I128::MAX.checked_neg().unwrap(),
105            I128::from_be_hex("80000000000000000000000000000001")
106        );
107
108        let negative = I128::from_be_hex("91113333555577779999BBBBDDDDFFFF");
109        let positive = I128::from_be_hex("6EEECCCCAAAA88886666444422220001");
110        assert_eq!(negative.checked_neg().unwrap(), positive);
111        assert_eq!(positive.checked_neg().unwrap(), negative);
112        assert_eq!(
113            positive.checked_neg().unwrap().checked_neg().unwrap(),
114            positive
115        );
116    }
117}