Skip to main content

crypto_bigint/uint/ref_type/
sub.rs

1use super::UintRef;
2use crate::Limb;
3use ctutils::Choice;
4
5impl UintRef {
6    /// Perform an in-place borrowing sub of a limb, returning the borrowed limb value.
7    #[inline]
8    pub const fn borrowing_sub_assign_limb(&mut self, mut rhs: Limb, mut borrow: Limb) -> Limb {
9        let mut i = 0;
10        while i < self.limbs.len() {
11            (self.limbs[i], borrow) = self.limbs[i].borrowing_sub(rhs, borrow);
12            rhs = Limb::ZERO;
13            i += 1;
14        }
15        borrow
16    }
17
18    /// Perform an in-place borrowing subtraction of another [`UintRef`], returning the carried limb
19    /// value.
20    ///
21    /// # Panics
22    /// If `self` is shorter than `rhs`.
23    #[inline]
24    #[track_caller]
25    pub const fn borrowing_sub_assign(&mut self, rhs: &Self, borrow: Limb) -> Limb {
26        self.borrowing_sub_assign_slice(&rhs.limbs, borrow)
27    }
28
29    /// Perform an in-place borrowing subtraction of another limb slice, returning the borrowed limb
30    /// value.
31    ///
32    /// # Panics
33    /// If `self` is shorter than `rhs`.
34    #[inline]
35    #[track_caller]
36    pub const fn borrowing_sub_assign_slice(&mut self, rhs: &[Limb], mut borrow: Limb) -> Limb {
37        assert!(
38            self.limbs.len() >= rhs.len(),
39            "length mismatch in borrowing_sub_assign_slice"
40        );
41        let mut i = 0;
42        while i < rhs.len() {
43            (self.limbs[i], borrow) = self.limbs[i].borrowing_sub(rhs[i], borrow);
44            i += 1;
45        }
46        while i < self.limbs.len() {
47            (self.limbs[i], borrow) = self.limbs[i].borrowing_sub(Limb::ZERO, borrow);
48            i += 1;
49        }
50        borrow
51    }
52
53    /// Perform in-place wrapping subtraction, returning the truthy value as the second element of
54    /// the tuple if an underflow has occurred.
55    ///
56    /// # Panics
57    /// If `self` is shorter than `rhs`.
58    #[track_caller]
59    pub(crate) const fn conditional_borrowing_sub_assign(
60        &mut self,
61        rhs: &Self,
62        choice: Choice,
63    ) -> Choice {
64        assert!(
65            self.limbs.len() >= rhs.limbs.len(),
66            "length mismatch in conditional_borrowing_sub_assign"
67        );
68        let mask = Limb::select(Limb::ZERO, Limb::MAX, choice);
69        let mut borrow = Limb::ZERO;
70
71        let mut i = 0;
72        while i < rhs.limbs.len() {
73            let masked_rhs = rhs.limbs[i].bitand(mask);
74            (self.limbs[i], borrow) = self.limbs[i].borrowing_sub(masked_rhs, borrow);
75            i += 1;
76        }
77        while i < self.limbs.len() {
78            (self.limbs[i], borrow) = self.limbs[i].borrowing_sub(Limb::ZERO, borrow);
79            i += 1;
80        }
81
82        borrow.lsb_to_choice()
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use crate::{Choice, Limb, UintRef, Unsigned};
89
90    #[test]
91    fn borrowing_sub_assign_mixed() {
92        let mut a = [Limb::MAX];
93        let borrow =
94            UintRef::new_mut(&mut a).borrowing_sub_assign(Limb::MAX.as_uint_ref(), Limb::MAX);
95        assert_eq!((a, borrow), ([Limb::MAX], Limb::MAX));
96
97        let mut a = [Limb::MAX];
98        let borrow = UintRef::new_mut(&mut a)
99            .conditional_borrowing_sub_assign(Limb::MAX.as_uint_ref(), Choice::FALSE);
100        assert_eq!((a, borrow.to_bool()), ([Limb::MAX], false));
101
102        let mut a = [Limb::MAX - Limb::ONE];
103        let borrow = UintRef::new_mut(&mut a)
104            .conditional_borrowing_sub_assign(Limb::MAX.as_uint_ref(), Choice::TRUE);
105        assert_eq!((a, borrow.to_bool()), ([Limb::MAX], true));
106
107        let mut a = [Limb::MAX - Limb::ONE, Limb::ONE];
108        let borrow =
109            UintRef::new_mut(&mut a).borrowing_sub_assign(Limb::MAX.as_uint_ref(), Limb::ZERO);
110        assert_eq!((a, borrow), ([Limb::MAX, Limb::ZERO], Limb::ZERO));
111
112        let mut a = [Limb::MAX - Limb::ONE, Limb::ZERO];
113        let borrow =
114            UintRef::new_mut(&mut a).borrowing_sub_assign(Limb::MAX.as_uint_ref(), Limb::ZERO);
115        assert_eq!((a, borrow), ([Limb::MAX, Limb::MAX], Limb::MAX));
116
117        let mut a = [Limb::MAX - Limb::ONE, Limb::ONE];
118        let borrow = UintRef::new_mut(&mut a)
119            .conditional_borrowing_sub_assign(Limb::MAX.as_uint_ref(), Choice::TRUE);
120        assert_eq!((a, borrow.to_bool()), ([Limb::MAX, Limb::ZERO], false));
121
122        let mut a = [Limb::MAX - Limb::ONE, Limb::ZERO];
123        let borrow = UintRef::new_mut(&mut a)
124            .conditional_borrowing_sub_assign(Limb::MAX.as_uint_ref(), Choice::TRUE);
125        assert_eq!((a, borrow.to_bool()), ([Limb::MAX, Limb::MAX], true));
126    }
127}