crypto_bigint/uint/
sub.rs

1//! [`Uint`] addition operations.
2
3use super::Uint;
4use crate::{Checked, CheckedSub, CtChoice, Limb, Wrapping, Zero};
5use core::ops::{Sub, SubAssign};
6use subtle::CtOption;
7
8impl<const LIMBS: usize> Uint<LIMBS> {
9    /// Computes `a - (b + borrow)`, returning the result along with the new borrow.
10    #[inline(always)]
11    pub const fn sbb(&self, rhs: &Self, mut borrow: Limb) -> (Self, Limb) {
12        let mut limbs = [Limb::ZERO; LIMBS];
13        let mut i = 0;
14
15        while i < LIMBS {
16            let (w, b) = self.limbs[i].sbb(rhs.limbs[i], borrow);
17            limbs[i] = w;
18            borrow = b;
19            i += 1;
20        }
21
22        (Self { limbs }, borrow)
23    }
24
25    /// Perform saturating subtraction, returning `ZERO` on underflow.
26    pub const fn saturating_sub(&self, rhs: &Self) -> Self {
27        let (res, underflow) = self.sbb(rhs, Limb::ZERO);
28        Self::ct_select(&res, &Self::ZERO, CtChoice::from_mask(underflow.0))
29    }
30
31    /// Perform wrapping subtraction, discarding underflow and wrapping around
32    /// the boundary of the type.
33    pub const fn wrapping_sub(&self, rhs: &Self) -> Self {
34        self.sbb(rhs, Limb::ZERO).0
35    }
36
37    /// Perform wrapping subtraction, returning the truthy value as the second element of the tuple
38    /// if an underflow has occurred.
39    pub(crate) const fn conditional_wrapping_sub(
40        &self,
41        rhs: &Self,
42        choice: CtChoice,
43    ) -> (Self, CtChoice) {
44        let actual_rhs = Uint::ct_select(&Uint::ZERO, rhs, choice);
45        let (res, borrow) = self.sbb(&actual_rhs, Limb::ZERO);
46        (res, CtChoice::from_mask(borrow.0))
47    }
48}
49
50impl<const LIMBS: usize> CheckedSub<&Uint<LIMBS>> for Uint<LIMBS> {
51    type Output = Self;
52
53    fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
54        let (result, underflow) = self.sbb(rhs, Limb::ZERO);
55        CtOption::new(result, underflow.is_zero())
56    }
57}
58
59impl<const LIMBS: usize> Sub for Wrapping<Uint<LIMBS>> {
60    type Output = Self;
61
62    fn sub(self, rhs: Self) -> Wrapping<Uint<LIMBS>> {
63        Wrapping(self.0.wrapping_sub(&rhs.0))
64    }
65}
66
67impl<const LIMBS: usize> Sub<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
68    type Output = Wrapping<Uint<LIMBS>>;
69
70    fn sub(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
71        Wrapping(self.0.wrapping_sub(&rhs.0))
72    }
73}
74
75impl<const LIMBS: usize> Sub<Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
76    type Output = Wrapping<Uint<LIMBS>>;
77
78    fn sub(self, rhs: Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
79        Wrapping(self.0.wrapping_sub(&rhs.0))
80    }
81}
82
83impl<const LIMBS: usize> Sub<&Wrapping<Uint<LIMBS>>> for &Wrapping<Uint<LIMBS>> {
84    type Output = Wrapping<Uint<LIMBS>>;
85
86    fn sub(self, rhs: &Wrapping<Uint<LIMBS>>) -> Wrapping<Uint<LIMBS>> {
87        Wrapping(self.0.wrapping_sub(&rhs.0))
88    }
89}
90
91impl<const LIMBS: usize> SubAssign for Wrapping<Uint<LIMBS>> {
92    fn sub_assign(&mut self, other: Self) {
93        *self = *self - other;
94    }
95}
96
97impl<const LIMBS: usize> SubAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
98    fn sub_assign(&mut self, other: &Self) {
99        *self = *self - other;
100    }
101}
102
103impl<const LIMBS: usize> Sub for Checked<Uint<LIMBS>> {
104    type Output = Self;
105
106    fn sub(self, rhs: Self) -> Checked<Uint<LIMBS>> {
107        Checked(
108            self.0
109                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
110        )
111    }
112}
113
114impl<const LIMBS: usize> Sub<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
115    type Output = Checked<Uint<LIMBS>>;
116
117    fn sub(self, rhs: &Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
118        Checked(
119            self.0
120                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
121        )
122    }
123}
124
125impl<const LIMBS: usize> Sub<Checked<Uint<LIMBS>>> for &Checked<Uint<LIMBS>> {
126    type Output = Checked<Uint<LIMBS>>;
127
128    fn sub(self, rhs: Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
129        Checked(
130            self.0
131                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
132        )
133    }
134}
135
136impl<const LIMBS: usize> Sub<&Checked<Uint<LIMBS>>> for &Checked<Uint<LIMBS>> {
137    type Output = Checked<Uint<LIMBS>>;
138
139    fn sub(self, rhs: &Checked<Uint<LIMBS>>) -> Checked<Uint<LIMBS>> {
140        Checked(
141            self.0
142                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))),
143        )
144    }
145}
146
147impl<const LIMBS: usize> SubAssign for Checked<Uint<LIMBS>> {
148    fn sub_assign(&mut self, other: Self) {
149        *self = *self - other;
150    }
151}
152
153impl<const LIMBS: usize> SubAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
154    fn sub_assign(&mut self, other: &Self) {
155        *self = *self - other;
156    }
157}
158
159#[cfg(test)]
160mod tests {
161    use crate::{CheckedSub, Limb, U128};
162
163    #[test]
164    fn sbb_no_borrow() {
165        let (res, borrow) = U128::ONE.sbb(&U128::ONE, Limb::ZERO);
166        assert_eq!(res, U128::ZERO);
167        assert_eq!(borrow, Limb::ZERO);
168    }
169
170    #[test]
171    fn sbb_with_borrow() {
172        let (res, borrow) = U128::ZERO.sbb(&U128::ONE, Limb::ZERO);
173
174        assert_eq!(res, U128::MAX);
175        assert_eq!(borrow, Limb::MAX);
176    }
177
178    #[test]
179    fn saturating_sub_no_borrow() {
180        assert_eq!(
181            U128::from(5u64).saturating_sub(&U128::ONE),
182            U128::from(4u64)
183        );
184    }
185
186    #[test]
187    fn saturating_sub_with_borrow() {
188        assert_eq!(
189            U128::from(4u64).saturating_sub(&U128::from(5u64)),
190            U128::ZERO
191        );
192    }
193
194    #[test]
195    fn wrapping_sub_no_borrow() {
196        assert_eq!(U128::ONE.wrapping_sub(&U128::ONE), U128::ZERO);
197    }
198
199    #[test]
200    fn wrapping_sub_with_borrow() {
201        assert_eq!(U128::ZERO.wrapping_sub(&U128::ONE), U128::MAX);
202    }
203
204    #[test]
205    fn checked_sub_ok() {
206        let result = U128::ONE.checked_sub(&U128::ONE);
207        assert_eq!(result.unwrap(), U128::ZERO);
208    }
209
210    #[test]
211    fn checked_sub_overflow() {
212        let result = U128::ZERO.checked_sub(&U128::ONE);
213        assert!(!bool::from(result.is_some()));
214    }
215}