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