crypto_bigint/uint/
sub.rs1use super::Uint;
4use crate::{Checked, CheckedSub, CtOption, Limb, Sub, SubAssign, Wrapping, WrappingSub, word};
5
6impl<const LIMBS: usize> Uint<LIMBS> {
7 #[deprecated(since = "0.7.0", note = "please use `borrowing_sub` instead")]
9 #[must_use]
10 pub const fn sbb(&self, rhs: &Self, borrow: Limb) -> (Self, Limb) {
11 self.borrowing_sub(rhs, borrow)
12 }
13
14 #[inline(always)]
16 #[must_use]
17 pub const fn borrowing_sub(&self, rhs: &Self, mut borrow: Limb) -> (Self, Limb) {
18 let mut limbs = [Limb::ZERO; LIMBS];
19 let mut i = 0;
20
21 while i < LIMBS {
22 let (w, b) = self.limbs[i].borrowing_sub(rhs.limbs[i], borrow);
23 limbs[i] = w;
24 borrow = b;
25 i += 1;
26 }
27
28 (Self { limbs }, borrow)
29 }
30
31 #[must_use]
33 pub const fn saturating_sub(&self, rhs: &Self) -> Self {
34 let (res, underflow) = self.borrowing_sub(rhs, Limb::ZERO);
35 Self::select(&res, &Self::ZERO, word::choice_from_mask(underflow.0))
36 }
37
38 #[inline]
41 #[must_use]
42 pub const fn wrapping_sub(&self, rhs: &Self) -> Self {
43 self.borrowing_sub(rhs, Limb::ZERO).0
44 }
45}
46
47impl<const LIMBS: usize> CheckedSub for Uint<LIMBS> {
48 fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
49 let (result, underflow) = self.borrowing_sub(rhs, Limb::ZERO);
50 CtOption::new(result, underflow.is_zero())
51 }
52}
53
54impl<const LIMBS: usize> Sub for Uint<LIMBS> {
55 type Output = Self;
56
57 fn sub(self, rhs: Self) -> Self {
58 self.sub(&rhs)
59 }
60}
61
62impl<const LIMBS: usize> Sub<&Uint<LIMBS>> for Uint<LIMBS> {
63 type Output = Self;
64
65 fn sub(self, rhs: &Self) -> Self {
66 self.checked_sub(rhs)
67 .expect("attempted to subtract with underflow")
68 }
69}
70
71impl<const LIMBS: usize> SubAssign<Uint<LIMBS>> for Uint<LIMBS> {
72 fn sub_assign(&mut self, rhs: Uint<LIMBS>) {
73 *self = self.sub(&rhs);
74 }
75}
76
77impl<const LIMBS: usize> SubAssign<&Uint<LIMBS>> for Uint<LIMBS> {
78 fn sub_assign(&mut self, rhs: &Uint<LIMBS>) {
79 *self = self.sub(rhs);
80 }
81}
82
83impl<const LIMBS: usize> SubAssign for Wrapping<Uint<LIMBS>> {
84 fn sub_assign(&mut self, other: Self) {
85 *self = *self - other;
86 }
87}
88
89impl<const LIMBS: usize> SubAssign<&Wrapping<Uint<LIMBS>>> for Wrapping<Uint<LIMBS>> {
90 fn sub_assign(&mut self, other: &Self) {
91 *self = *self - other;
92 }
93}
94
95impl<const LIMBS: usize> SubAssign for Checked<Uint<LIMBS>> {
96 fn sub_assign(&mut self, other: Self) {
97 *self = *self - other;
98 }
99}
100
101impl<const LIMBS: usize> SubAssign<&Checked<Uint<LIMBS>>> for Checked<Uint<LIMBS>> {
102 fn sub_assign(&mut self, other: &Self) {
103 *self = *self - other;
104 }
105}
106
107impl<const LIMBS: usize> WrappingSub for Uint<LIMBS> {
108 fn wrapping_sub(&self, v: &Self) -> Self {
109 self.wrapping_sub(v)
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use crate::{CheckedSub, Limb, U128};
116
117 #[test]
118 fn borrowing_sub_no_borrow() {
119 let (res, borrow) = U128::ONE.borrowing_sub(&U128::ONE, Limb::ZERO);
120 assert_eq!(res, U128::ZERO);
121 assert_eq!(borrow, Limb::ZERO);
122 }
123
124 #[test]
125 fn borrowing_sub_with_borrow() {
126 let (res, borrow) = U128::ZERO.borrowing_sub(&U128::ONE, Limb::ZERO);
127
128 assert_eq!(res, U128::MAX);
129 assert_eq!(borrow, Limb::MAX);
130 }
131
132 #[test]
133 fn borrowing_sub_matches_u128() {
134 use crate::Word;
135
136 let values = [
138 0,
139 1,
140 2,
141 (1 << 32) - 1,
142 1 << 32,
143 (1 << 64) - 1,
144 1 << 64,
145 (1 << 127) - 1,
146 1 << 127,
147 u128::MAX - 1,
148 u128::MAX,
149 ];
150
151 for lhs in values {
152 for rhs in values {
153 for borrow in [0, 1, 1 << (Word::BITS - 1), Word::MAX] {
154 let (expected, b1) = lhs.overflowing_sub(rhs);
155 let (expected, b2) =
156 expected.overflowing_sub(u128::from(borrow >> (Word::BITS - 1)));
157 let expected_borrow = Limb(Word::from(b1 | b2).wrapping_neg());
158
159 assert_eq!(
160 U128::from(lhs).borrowing_sub(&U128::from(rhs), Limb(borrow)),
161 (U128::from(expected), expected_borrow),
162 "lhs={lhs:#x}, rhs={rhs:#x}, borrow={borrow:#x}"
163 );
164 }
165 }
166 }
167 }
168
169 #[test]
170 fn saturating_sub_no_borrow() {
171 assert_eq!(
172 U128::from(5u64).saturating_sub(&U128::ONE),
173 U128::from(4u64)
174 );
175 }
176
177 #[test]
178 fn saturating_sub_with_borrow() {
179 assert_eq!(
180 U128::from(4u64).saturating_sub(&U128::from(5u64)),
181 U128::ZERO
182 );
183 }
184
185 #[test]
186 fn wrapping_sub_no_borrow() {
187 assert_eq!(U128::ONE.wrapping_sub(&U128::ONE), U128::ZERO);
188 }
189
190 #[test]
191 fn wrapping_sub_with_borrow() {
192 assert_eq!(U128::ZERO.wrapping_sub(&U128::ONE), U128::MAX);
193 }
194
195 #[test]
196 fn checked_sub_ok() {
197 let result = U128::ONE.checked_sub(&U128::ONE);
198 assert_eq!(result.unwrap(), U128::ZERO);
199 }
200
201 #[test]
202 fn checked_sub_overflow() {
203 let result = U128::ZERO.checked_sub(&U128::ONE);
204 assert!(!bool::from(result.is_some()));
205 }
206}