crypto_bigint/limb/
sub.rs

1//! Limb subtraction
2
3use crate::{primitives::sbb, Checked, CheckedSub, Limb, Wrapping, WrappingSub, Zero};
4use core::ops::{Sub, SubAssign};
5use subtle::CtOption;
6
7impl Limb {
8    /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow.
9    #[inline(always)]
10    pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) {
11        let (res, borrow) = sbb(self.0, rhs.0, borrow.0);
12        (Limb(res), Limb(borrow))
13    }
14
15    /// Perform saturating subtraction.
16    #[inline]
17    pub const fn saturating_sub(&self, rhs: Self) -> Self {
18        Limb(self.0.saturating_sub(rhs.0))
19    }
20
21    /// Perform wrapping subtraction, discarding underflow and wrapping around
22    /// the boundary of the type.
23    #[inline(always)]
24    pub const fn wrapping_sub(&self, rhs: Self) -> Self {
25        Limb(self.0.wrapping_sub(rhs.0))
26    }
27}
28
29impl CheckedSub for Limb {
30    #[inline]
31    fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
32        let (result, underflow) = self.sbb(*rhs, Limb::ZERO);
33        CtOption::new(result, underflow.is_zero())
34    }
35}
36
37impl Sub for Limb {
38    type Output = Self;
39
40    #[inline]
41    fn sub(self, rhs: Self) -> Self {
42        self.checked_sub(&rhs)
43            .expect("attempted to subtract with underflow")
44    }
45}
46
47impl Sub<&Self> for Limb {
48    type Output = Self;
49
50    #[inline]
51    fn sub(self, rhs: &Self) -> Self {
52        self - *rhs
53    }
54}
55
56impl SubAssign for Wrapping<Limb> {
57    #[inline]
58    fn sub_assign(&mut self, other: Self) {
59        *self = *self - other;
60    }
61}
62
63impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
64    #[inline]
65    fn sub_assign(&mut self, other: &Self) {
66        *self = *self - other;
67    }
68}
69
70impl SubAssign for Checked<Limb> {
71    #[inline]
72    fn sub_assign(&mut self, other: Self) {
73        *self = *self - other;
74    }
75}
76
77impl SubAssign<&Checked<Limb>> for Checked<Limb> {
78    #[inline]
79    fn sub_assign(&mut self, other: &Self) {
80        *self = *self - other;
81    }
82}
83
84impl WrappingSub for Limb {
85    #[inline]
86    fn wrapping_sub(&self, v: &Self) -> Self {
87        self.wrapping_sub(*v)
88    }
89}
90
91#[cfg(test)]
92mod tests {
93    use crate::{CheckedSub, Limb};
94
95    #[test]
96    fn sbb_no_borrow() {
97        let (res, borrow) = Limb::ONE.sbb(Limb::ONE, Limb::ZERO);
98        assert_eq!(res, Limb::ZERO);
99        assert_eq!(borrow, Limb::ZERO);
100    }
101
102    #[test]
103    fn sbb_with_borrow() {
104        let (res, borrow) = Limb::ZERO.sbb(Limb::ONE, Limb::ZERO);
105
106        assert_eq!(res, Limb::MAX);
107        assert_eq!(borrow, Limb::MAX);
108    }
109
110    #[test]
111    fn wrapping_sub_no_borrow() {
112        assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO);
113    }
114
115    #[test]
116    fn wrapping_sub_with_borrow() {
117        assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX);
118    }
119
120    #[test]
121    fn checked_sub_ok() {
122        let result = Limb::ONE.checked_sub(&Limb::ONE);
123        assert_eq!(result.unwrap(), Limb::ZERO);
124    }
125
126    #[test]
127    fn checked_sub_overflow() {
128        let result = Limb::ZERO.checked_sub(&Limb::ONE);
129        assert!(!bool::from(result.is_some()));
130    }
131}