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