/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 | | } |