crypto_bigint/limb/
sub.rs1use crate::{primitives::sbb, Checked, CheckedSub, Limb, Wrapping, WrappingSub, 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 (res, borrow) = sbb(self.0, rhs.0, borrow.0);
12 (Limb(res), Limb(borrow))
13 }
14
15 #[inline]
17 pub const fn saturating_sub(&self, rhs: Self) -> Self {
18 Limb(self.0.saturating_sub(rhs.0))
19 }
20
21 #[inline(always)]
24 pub const fn wrapping_sub(&self, rhs: Self) -> Self {
25 Limb(self.0.wrapping_sub(rhs.0))
26 }
27}
28
29impl CheckedSub for Limb {
30 #[inline]
31 fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
32 let (result, underflow) = self.sbb(*rhs, Limb::ZERO);
33 CtOption::new(result, underflow.is_zero())
34 }
35}
36
37impl Sub for Limb {
38 type Output = Self;
39
40 #[inline]
41 fn sub(self, rhs: Self) -> Self {
42 self.checked_sub(&rhs)
43 .expect("attempted to subtract with underflow")
44 }
45}
46
47impl Sub<&Self> for Limb {
48 type Output = Self;
49
50 #[inline]
51 fn sub(self, rhs: &Self) -> Self {
52 self - *rhs
53 }
54}
55
56impl SubAssign for Wrapping<Limb> {
57 #[inline]
58 fn sub_assign(&mut self, other: Self) {
59 *self = *self - other;
60 }
61}
62
63impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
64 #[inline]
65 fn sub_assign(&mut self, other: &Self) {
66 *self = *self - other;
67 }
68}
69
70impl SubAssign for Checked<Limb> {
71 #[inline]
72 fn sub_assign(&mut self, other: Self) {
73 *self = *self - other;
74 }
75}
76
77impl SubAssign<&Checked<Limb>> for Checked<Limb> {
78 #[inline]
79 fn sub_assign(&mut self, other: &Self) {
80 *self = *self - other;
81 }
82}
83
84impl WrappingSub for Limb {
85 #[inline]
86 fn wrapping_sub(&self, v: &Self) -> Self {
87 self.wrapping_sub(*v)
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use crate::{CheckedSub, Limb};
94
95 #[test]
96 fn sbb_no_borrow() {
97 let (res, borrow) = Limb::ONE.sbb(Limb::ONE, Limb::ZERO);
98 assert_eq!(res, Limb::ZERO);
99 assert_eq!(borrow, Limb::ZERO);
100 }
101
102 #[test]
103 fn sbb_with_borrow() {
104 let (res, borrow) = Limb::ZERO.sbb(Limb::ONE, Limb::ZERO);
105
106 assert_eq!(res, Limb::MAX);
107 assert_eq!(borrow, Limb::MAX);
108 }
109
110 #[test]
111 fn wrapping_sub_no_borrow() {
112 assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO);
113 }
114
115 #[test]
116 fn wrapping_sub_with_borrow() {
117 assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX);
118 }
119
120 #[test]
121 fn checked_sub_ok() {
122 let result = Limb::ONE.checked_sub(&Limb::ONE);
123 assert_eq!(result.unwrap(), Limb::ZERO);
124 }
125
126 #[test]
127 fn checked_sub_overflow() {
128 let result = Limb::ZERO.checked_sub(&Limb::ONE);
129 assert!(!bool::from(result.is_some()));
130 }
131}