crypto_bigint/limb/
sub.rs1use crate::{
4 Checked, CheckedSub, CtOption, Limb, Sub, SubAssign, SubMod, Wrapping, WrappingSub,
5 primitives::borrowing_sub,
6};
7
8impl Limb {
9 #[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 #[inline(always)]
21 #[must_use]
22 pub const fn borrowing_sub(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) {
23 let (res, borrow) = borrowing_sub(self.0, rhs.0, borrow.0);
24 (Limb(res), Limb(borrow))
25 }
26
27 #[inline]
29 #[must_use]
30 pub const fn saturating_sub(&self, rhs: Self) -> Self {
31 Limb(self.0.saturating_sub(rhs.0))
32 }
33
34 #[inline(always)]
37 #[must_use]
38 pub const fn wrapping_sub(&self, rhs: Self) -> Self {
39 Limb(self.0.wrapping_sub(rhs.0))
40 }
41}
42
43impl CheckedSub for Limb {
44 #[inline]
45 fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
46 let (result, underflow) = self.borrowing_sub(*rhs, Limb::ZERO);
47 CtOption::new(result, underflow.is_zero())
48 }
49}
50
51impl Sub for Limb {
52 type Output = Self;
53
54 #[inline]
55 fn sub(self, rhs: Self) -> Self {
56 self.checked_sub(&rhs)
57 .expect("attempted to subtract with underflow")
58 }
59}
60
61impl Sub<&Self> for Limb {
62 type Output = Self;
63
64 #[inline]
65 fn sub(self, rhs: &Self) -> Self {
66 self - *rhs
67 }
68}
69
70impl SubAssign for Limb {
71 #[inline]
72 fn sub_assign(&mut self, rhs: Self) {
73 *self = *self - rhs;
74 }
75}
76
77impl SubAssign<&Self> for Limb {
78 #[inline]
79 fn sub_assign(&mut self, rhs: &Self) {
80 *self = *self - *rhs;
81 }
82}
83
84impl SubAssign for Wrapping<Limb> {
85 #[inline]
86 fn sub_assign(&mut self, other: Self) {
87 *self = *self - other;
88 }
89}
90
91impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
92 #[inline]
93 fn sub_assign(&mut self, other: &Self) {
94 *self = *self - other;
95 }
96}
97
98impl SubAssign for Checked<Limb> {
99 #[inline]
100 fn sub_assign(&mut self, other: Self) {
101 *self = *self - other;
102 }
103}
104
105impl SubAssign<&Checked<Limb>> for Checked<Limb> {
106 #[inline]
107 fn sub_assign(&mut self, other: &Self) {
108 *self = *self - other;
109 }
110}
111
112impl WrappingSub for Limb {
113 #[inline]
114 fn wrapping_sub(&self, v: &Self) -> Self {
115 self.wrapping_sub(*v)
116 }
117}
118
119impl SubMod for Limb {
120 type Output = Self;
121
122 fn sub_mod(&self, rhs: &Self, p: &crate::NonZero<Self>) -> Self::Output {
123 let (res, borrow) = self.borrowing_sub(*rhs, Limb::ZERO);
124 Self::select(res, res.wrapping_add(p.get()), borrow.is_nonzero())
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use crate::{CheckedSub, Limb};
131
132 #[test]
133 fn borrowing_sub_boundary_values() {
134 use crate::{Limb, Word};
135
136 let msb = 1 << (Word::BITS - 1);
137 let values = [0, 1, 2, msb - 1, msb, msb + 1, Word::MAX - 1, Word::MAX];
138 let borrows = [0, 1, msb, Word::MAX];
139
140 for lhs in values {
141 for rhs in values {
142 for borrow in borrows {
143 let (ret, borrow1) = lhs.overflowing_sub(borrow >> (Word::BITS - 1));
144 let (expected, borrow2) = ret.overflowing_sub(rhs);
145 let expected_borrow = Word::from(borrow1 | borrow2).wrapping_neg();
146
147 assert_eq!(
148 Limb(lhs).borrowing_sub(Limb(rhs), Limb(borrow)),
149 (Limb(expected), Limb(expected_borrow)),
150 "lhs={lhs:#x}, rhs={rhs:#x}, borrow={borrow:#x}"
151 );
152 }
153 }
154 }
155 }
156
157 #[test]
158 fn borrowing_sub_no_borrow() {
159 let (res, borrow) = Limb::ONE.borrowing_sub(Limb::ONE, Limb::ZERO);
160 assert_eq!(res, Limb::ZERO);
161 assert_eq!(borrow, Limb::ZERO);
162 }
163
164 #[test]
165 fn borrowing_sub_with_borrow() {
166 let (res, borrow) = Limb::ZERO.borrowing_sub(Limb::ONE, Limb::ZERO);
167
168 assert_eq!(res, Limb::MAX);
169 assert_eq!(borrow, Limb::MAX);
170 }
171
172 #[test]
173 fn wrapping_sub_no_borrow() {
174 assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO);
175 }
176
177 #[test]
178 fn wrapping_sub_with_borrow() {
179 assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX);
180 }
181
182 #[test]
183 fn checked_sub_ok() {
184 let result = Limb::ONE.checked_sub(&Limb::ONE);
185 assert_eq!(result.unwrap(), Limb::ZERO);
186 }
187
188 #[test]
189 fn checked_sub_overflow() {
190 let result = Limb::ZERO.checked_sub(&Limb::ONE);
191 assert!(!bool::from(result.is_some()));
192 }
193}