crypto_bigint/limb/
sub.rs1use crate::{Checked, CheckedSub, Limb, WideWord, Word, Wrapping, Zero};
4use core::ops::{Sub, SubAssign};
5use subtle::CtOption;
6
7impl Limb {
8 #[inline(always)]
10 pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) {
11 let a = self.0 as WideWord;
12 let b = rhs.0 as WideWord;
13 let borrow = (borrow.0 >> (Self::BITS - 1)) as WideWord;
14 let ret = a.wrapping_sub(b + borrow);
15 (Limb(ret as Word), Limb((ret >> Self::BITS) as Word))
16 }
17
18 #[inline]
20 pub const fn saturating_sub(&self, rhs: Self) -> Self {
21 Limb(self.0.saturating_sub(rhs.0))
22 }
23
24 #[inline(always)]
27 pub const fn wrapping_sub(&self, rhs: Self) -> Self {
28 Limb(self.0.wrapping_sub(rhs.0))
29 }
30}
31
32impl CheckedSub for Limb {
33 type Output = Self;
34
35 #[inline]
36 fn checked_sub(&self, rhs: Self) -> CtOption<Self> {
37 let (result, underflow) = self.sbb(rhs, Limb::ZERO);
38 CtOption::new(result, underflow.is_zero())
39 }
40}
41
42impl Sub for Wrapping<Limb> {
43 type Output = Self;
44
45 fn sub(self, rhs: Self) -> Wrapping<Limb> {
46 Wrapping(self.0.wrapping_sub(rhs.0))
47 }
48}
49
50impl Sub<&Wrapping<Limb>> for Wrapping<Limb> {
51 type Output = Wrapping<Limb>;
52
53 fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
54 Wrapping(self.0.wrapping_sub(rhs.0))
55 }
56}
57
58impl Sub<Wrapping<Limb>> for &Wrapping<Limb> {
59 type Output = Wrapping<Limb>;
60
61 fn sub(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> {
62 Wrapping(self.0.wrapping_sub(rhs.0))
63 }
64}
65
66impl Sub<&Wrapping<Limb>> for &Wrapping<Limb> {
67 type Output = Wrapping<Limb>;
68
69 fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
70 Wrapping(self.0.wrapping_sub(rhs.0))
71 }
72}
73
74impl SubAssign for Wrapping<Limb> {
75 fn sub_assign(&mut self, other: Self) {
76 *self = *self - other;
77 }
78}
79
80impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
81 fn sub_assign(&mut self, other: &Self) {
82 *self = *self - other;
83 }
84}
85
86impl Sub for Checked<Limb> {
87 type Output = Self;
88
89 fn sub(self, rhs: Self) -> Checked<Limb> {
90 Checked(
91 self.0
92 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
93 )
94 }
95}
96
97impl Sub<&Checked<Limb>> for Checked<Limb> {
98 type Output = Checked<Limb>;
99
100 fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
101 Checked(
102 self.0
103 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
104 )
105 }
106}
107
108impl Sub<Checked<Limb>> for &Checked<Limb> {
109 type Output = Checked<Limb>;
110
111 fn sub(self, rhs: Checked<Limb>) -> Checked<Limb> {
112 Checked(
113 self.0
114 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
115 )
116 }
117}
118
119impl Sub<&Checked<Limb>> for &Checked<Limb> {
120 type Output = Checked<Limb>;
121
122 fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
123 Checked(
124 self.0
125 .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
126 )
127 }
128}
129
130impl SubAssign for Checked<Limb> {
131 fn sub_assign(&mut self, other: Self) {
132 *self = *self - other;
133 }
134}
135
136impl SubAssign<&Checked<Limb>> for Checked<Limb> {
137 fn sub_assign(&mut self, other: &Self) {
138 *self = *self - other;
139 }
140}
141
142#[cfg(test)]
143mod 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}