Coverage Report

Created: 2025-12-31 06:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/crypto-bigint-0.5.5/src/limb/sub.rs
Line
Count
Source
1
//! Limb subtraction
2
3
use crate::{Checked, CheckedSub, Limb, WideWord, Word, Wrapping, Zero};
4
use core::ops::{Sub, SubAssign};
5
use subtle::CtOption;
6
7
impl Limb {
8
    /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow.
9
    #[inline(always)]
10
232k
    pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) {
11
232k
        let a = self.0 as WideWord;
12
232k
        let b = rhs.0 as WideWord;
13
232k
        let borrow = (borrow.0 >> (Self::BITS - 1)) as WideWord;
14
232k
        let ret = a.wrapping_sub(b + borrow);
15
232k
        (Limb(ret as Word), Limb((ret >> Self::BITS) as Word))
16
232k
    }
17
18
    /// Perform saturating subtraction.
19
    #[inline]
20
0
    pub const fn saturating_sub(&self, rhs: Self) -> Self {
21
0
        Limb(self.0.saturating_sub(rhs.0))
22
0
    }
23
24
    /// Perform wrapping subtraction, discarding underflow and wrapping around
25
    /// the boundary of the type.
26
    #[inline(always)]
27
0
    pub const fn wrapping_sub(&self, rhs: Self) -> Self {
28
0
        Limb(self.0.wrapping_sub(rhs.0))
29
0
    }
30
}
31
32
impl CheckedSub for Limb {
33
    type Output = Self;
34
35
    #[inline]
36
0
    fn checked_sub(&self, rhs: Self) -> CtOption<Self> {
37
0
        let (result, underflow) = self.sbb(rhs, Limb::ZERO);
38
0
        CtOption::new(result, underflow.is_zero())
39
0
    }
40
}
41
42
impl Sub for Wrapping<Limb> {
43
    type Output = Self;
44
45
0
    fn sub(self, rhs: Self) -> Wrapping<Limb> {
46
0
        Wrapping(self.0.wrapping_sub(rhs.0))
47
0
    }
48
}
49
50
impl Sub<&Wrapping<Limb>> for Wrapping<Limb> {
51
    type Output = Wrapping<Limb>;
52
53
0
    fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
54
0
        Wrapping(self.0.wrapping_sub(rhs.0))
55
0
    }
56
}
57
58
impl Sub<Wrapping<Limb>> for &Wrapping<Limb> {
59
    type Output = Wrapping<Limb>;
60
61
0
    fn sub(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> {
62
0
        Wrapping(self.0.wrapping_sub(rhs.0))
63
0
    }
64
}
65
66
impl Sub<&Wrapping<Limb>> for &Wrapping<Limb> {
67
    type Output = Wrapping<Limb>;
68
69
0
    fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
70
0
        Wrapping(self.0.wrapping_sub(rhs.0))
71
0
    }
72
}
73
74
impl SubAssign for Wrapping<Limb> {
75
0
    fn sub_assign(&mut self, other: Self) {
76
0
        *self = *self - other;
77
0
    }
78
}
79
80
impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
81
0
    fn sub_assign(&mut self, other: &Self) {
82
0
        *self = *self - other;
83
0
    }
84
}
85
86
impl Sub for Checked<Limb> {
87
    type Output = Self;
88
89
0
    fn sub(self, rhs: Self) -> Checked<Limb> {
90
        Checked(
91
0
            self.0
92
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
93
        )
94
0
    }
95
}
96
97
impl Sub<&Checked<Limb>> for Checked<Limb> {
98
    type Output = Checked<Limb>;
99
100
0
    fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
101
        Checked(
102
0
            self.0
103
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
104
        )
105
0
    }
106
}
107
108
impl Sub<Checked<Limb>> for &Checked<Limb> {
109
    type Output = Checked<Limb>;
110
111
0
    fn sub(self, rhs: Checked<Limb>) -> Checked<Limb> {
112
        Checked(
113
0
            self.0
114
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
115
        )
116
0
    }
117
}
118
119
impl Sub<&Checked<Limb>> for &Checked<Limb> {
120
    type Output = Checked<Limb>;
121
122
0
    fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
123
        Checked(
124
0
            self.0
125
0
                .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
126
        )
127
0
    }
128
}
129
130
impl SubAssign for Checked<Limb> {
131
0
    fn sub_assign(&mut self, other: Self) {
132
0
        *self = *self - other;
133
0
    }
134
}
135
136
impl SubAssign<&Checked<Limb>> for Checked<Limb> {
137
0
    fn sub_assign(&mut self, other: &Self) {
138
0
        *self = *self - other;
139
0
    }
140
}
141
142
#[cfg(test)]
143
mod tests {
144
    use crate::{CheckedSub, Limb};
145
146
    #[test]
147
    fn sbb_no_borrow() {
148
        let (res, borrow) = Limb::ONE.sbb(Limb::ONE, Limb::ZERO);
149
        assert_eq!(res, Limb::ZERO);
150
        assert_eq!(borrow, Limb::ZERO);
151
    }
152
153
    #[test]
154
    fn sbb_with_borrow() {
155
        let (res, borrow) = Limb::ZERO.sbb(Limb::ONE, Limb::ZERO);
156
157
        assert_eq!(res, Limb::MAX);
158
        assert_eq!(borrow, Limb::MAX);
159
    }
160
161
    #[test]
162
    fn wrapping_sub_no_borrow() {
163
        assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO);
164
    }
165
166
    #[test]
167
    fn wrapping_sub_with_borrow() {
168
        assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX);
169
    }
170
171
    #[test]
172
    fn checked_sub_ok() {
173
        let result = Limb::ONE.checked_sub(Limb::ONE);
174
        assert_eq!(result.unwrap(), Limb::ZERO);
175
    }
176
177
    #[test]
178
    fn checked_sub_overflow() {
179
        let result = Limb::ZERO.checked_sub(Limb::ONE);
180
        assert!(!bool::from(result.is_some()));
181
    }
182
}