Skip to main content

crypto_bigint/limb/
sub.rs

1//! Limb subtraction
2
3use crate::{
4    Checked, CheckedSub, CtOption, Limb, Sub, SubAssign, SubMod, Wrapping, WrappingSub,
5    primitives::borrowing_sub,
6};
7
8impl Limb {
9    /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow.
10    #[deprecated(since = "0.7.0", note = "please use `borrowing_sub` instead")]
11    #[must_use]
12    pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) {
13        self.borrowing_sub(rhs, borrow)
14    }
15
16    /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow.
17    #[inline(always)]
18    #[must_use]
19    pub const fn borrowing_sub(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) {
20        let (res, borrow) = borrowing_sub(self.0, rhs.0, borrow.0);
21        (Limb(res), Limb(borrow))
22    }
23
24    /// Perform saturating subtraction.
25    #[inline]
26    #[must_use]
27    pub const fn saturating_sub(&self, rhs: Self) -> Self {
28        Limb(self.0.saturating_sub(rhs.0))
29    }
30
31    /// Perform wrapping subtraction, discarding underflow and wrapping around
32    /// the boundary of the type.
33    #[inline(always)]
34    #[must_use]
35    pub const fn wrapping_sub(&self, rhs: Self) -> Self {
36        Limb(self.0.wrapping_sub(rhs.0))
37    }
38}
39
40impl CheckedSub for Limb {
41    #[inline]
42    fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
43        let (result, underflow) = self.borrowing_sub(*rhs, Limb::ZERO);
44        CtOption::new(result, underflow.is_zero())
45    }
46}
47
48impl Sub for Limb {
49    type Output = Self;
50
51    #[inline]
52    fn sub(self, rhs: Self) -> Self {
53        self.checked_sub(&rhs)
54            .expect("attempted to subtract with underflow")
55    }
56}
57
58impl Sub<&Self> for Limb {
59    type Output = Self;
60
61    #[inline]
62    fn sub(self, rhs: &Self) -> Self {
63        self - *rhs
64    }
65}
66
67impl SubAssign for Limb {
68    #[inline]
69    fn sub_assign(&mut self, rhs: Self) {
70        *self = *self - rhs;
71    }
72}
73
74impl SubAssign<&Self> for Limb {
75    #[inline]
76    fn sub_assign(&mut self, rhs: &Self) {
77        *self = *self - *rhs;
78    }
79}
80
81impl SubAssign for Wrapping<Limb> {
82    #[inline]
83    fn sub_assign(&mut self, other: Self) {
84        *self = *self - other;
85    }
86}
87
88impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
89    #[inline]
90    fn sub_assign(&mut self, other: &Self) {
91        *self = *self - other;
92    }
93}
94
95impl SubAssign for Checked<Limb> {
96    #[inline]
97    fn sub_assign(&mut self, other: Self) {
98        *self = *self - other;
99    }
100}
101
102impl SubAssign<&Checked<Limb>> for Checked<Limb> {
103    #[inline]
104    fn sub_assign(&mut self, other: &Self) {
105        *self = *self - other;
106    }
107}
108
109impl WrappingSub for Limb {
110    #[inline]
111    fn wrapping_sub(&self, v: &Self) -> Self {
112        self.wrapping_sub(*v)
113    }
114}
115
116impl SubMod for Limb {
117    type Output = Self;
118
119    fn sub_mod(&self, rhs: &Self, p: &crate::NonZero<Self>) -> Self::Output {
120        let (res, borrow) = self.borrowing_sub(*rhs, Limb::ZERO);
121        Self::select(res, res.wrapping_add(p.get()), borrow.is_nonzero())
122    }
123}
124
125#[cfg(test)]
126mod tests {
127    use crate::{CheckedSub, Limb};
128
129    #[test]
130    fn borrowing_sub_no_borrow() {
131        let (res, borrow) = Limb::ONE.borrowing_sub(Limb::ONE, Limb::ZERO);
132        assert_eq!(res, Limb::ZERO);
133        assert_eq!(borrow, Limb::ZERO);
134    }
135
136    #[test]
137    fn borrowing_sub_with_borrow() {
138        let (res, borrow) = Limb::ZERO.borrowing_sub(Limb::ONE, Limb::ZERO);
139
140        assert_eq!(res, Limb::MAX);
141        assert_eq!(borrow, Limb::MAX);
142    }
143
144    #[test]
145    fn wrapping_sub_no_borrow() {
146        assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO);
147    }
148
149    #[test]
150    fn wrapping_sub_with_borrow() {
151        assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX);
152    }
153
154    #[test]
155    fn checked_sub_ok() {
156        let result = Limb::ONE.checked_sub(&Limb::ONE);
157        assert_eq!(result.unwrap(), Limb::ZERO);
158    }
159
160    #[test]
161    fn checked_sub_overflow() {
162        let result = Limb::ZERO.checked_sub(&Limb::ONE);
163        assert!(!bool::from(result.is_some()));
164    }
165}