Skip to main content

crypto_bigint/uint/boxed/
neg.rs

1//! [`BoxedUint`] negation operations.
2
3use crate::{BoxedUint, Choice, CtAssign, Limb, WideWord, Word, WrappingNeg};
4
5impl BoxedUint {
6    /// Perform wrapping negation.
7    #[must_use]
8    #[allow(clippy::cast_possible_truncation)]
9    pub fn wrapping_neg(&self) -> Self {
10        let mut ret = vec![Limb::ZERO; self.nlimbs()];
11        let mut carry = 1;
12
13        for i in 0..self.nlimbs() {
14            let r = WideWord::from(!self.limbs[i].0) + carry;
15            ret[i] = Limb(r as Word);
16            carry = r >> Limb::BITS;
17        }
18
19        ret.into()
20    }
21
22    /// Perform in-place wrapping subtraction, returning the truthy value as the second element of
23    /// the tuple if an underflow has occurred.
24    #[allow(clippy::cast_possible_truncation)]
25    pub(crate) fn conditional_wrapping_neg_assign(&mut self, choice: Choice) {
26        let mut carry = 1;
27
28        for i in 0..self.nlimbs() {
29            let r = WideWord::from(!self.limbs[i].0) + carry;
30            self.limbs[i].ct_assign(&Limb(r as Word), choice);
31            carry = r >> Limb::BITS;
32        }
33    }
34}
35
36impl WrappingNeg for BoxedUint {
37    fn wrapping_neg(&self) -> Self {
38        self.wrapping_neg()
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use crate::{BoxedUint, Choice, CtNeg};
45
46    #[test]
47    fn ct_neg() {
48        let a = BoxedUint::from(123u64);
49        assert_eq!(a.ct_neg(Choice::FALSE), a);
50        assert_eq!(a.ct_neg(Choice::TRUE), a.wrapping_neg());
51    }
52
53    #[test]
54    fn ct_neg_assign() {
55        let mut a = BoxedUint::from(123u64);
56        let control = a.clone();
57
58        a.ct_neg_assign(Choice::FALSE);
59        assert_eq!(a, control);
60
61        a.ct_neg_assign(Choice::TRUE);
62        assert_ne!(a, control);
63        assert_eq!(a, control.wrapping_neg());
64    }
65
66    #[cfg(feature = "subtle")]
67    #[test]
68    fn subtle_conditional_negate() {
69        use subtle::ConditionallyNegatable;
70        let mut a = BoxedUint::from(123u64);
71        let control = a.clone();
72
73        a.conditional_negate(Choice::FALSE.into());
74        assert_eq!(a, control);
75
76        a.conditional_negate(Choice::TRUE.into());
77        assert_ne!(a, control);
78        assert_eq!(a, control.wrapping_neg());
79    }
80
81    #[test]
82    fn wrapping_neg() {
83        assert_eq!(BoxedUint::zero().wrapping_neg(), BoxedUint::zero());
84        assert_eq!(BoxedUint::max(64).wrapping_neg(), BoxedUint::one());
85        // assert_eq!(
86        //     BoxedUint::from(13u64).wrapping_neg(),
87        //     BoxedUint::from(13u64).not().saturating_add(&BoxedUint::one())
88        // );
89        // assert_eq!(
90        //     BoxedUint::from(42u64).wrapping_neg(),
91        //     BoxedUint::from(42u64).saturating_sub(&BoxedUint::one()).not()
92        // );
93    }
94}