summaryrefslogtreecommitdiffstats
path: root/vendor/crypto-bigint/src/limb/sub.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 12:47:55 +0000
commit2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4 (patch)
tree033cc839730fda84ff08db877037977be94e5e3a /vendor/crypto-bigint/src/limb/sub.rs
parentInitial commit. (diff)
downloadcargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.tar.xz
cargo-2aadc03ef15cb5ca5cc2af8a7c08e070742f0ac4.zip
Adding upstream version 0.70.1+ds1.upstream/0.70.1+ds1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/crypto-bigint/src/limb/sub.rs')
-rw-r--r--vendor/crypto-bigint/src/limb/sub.rs182
1 files changed, 182 insertions, 0 deletions
diff --git a/vendor/crypto-bigint/src/limb/sub.rs b/vendor/crypto-bigint/src/limb/sub.rs
new file mode 100644
index 0000000..0fc7a4a
--- /dev/null
+++ b/vendor/crypto-bigint/src/limb/sub.rs
@@ -0,0 +1,182 @@
+//! Limb subtraction
+
+use crate::{Checked, CheckedSub, Limb, WideWord, Word, Wrapping, Zero};
+use core::ops::{Sub, SubAssign};
+use subtle::CtOption;
+
+impl Limb {
+ /// Computes `self - (rhs + borrow)`, returning the result along with the new borrow.
+ #[inline(always)]
+ pub const fn sbb(self, rhs: Limb, borrow: Limb) -> (Limb, Limb) {
+ let a = self.0 as WideWord;
+ let b = rhs.0 as WideWord;
+ let borrow = (borrow.0 >> (Self::BITS - 1)) as WideWord;
+ let ret = a.wrapping_sub(b + borrow);
+ (Limb(ret as Word), Limb((ret >> Self::BITS) as Word))
+ }
+
+ /// Perform saturating subtraction.
+ #[inline]
+ pub const fn saturating_sub(&self, rhs: Self) -> Self {
+ Limb(self.0.saturating_sub(rhs.0))
+ }
+
+ /// Perform wrapping subtraction, discarding underflow and wrapping around
+ /// the boundary of the type.
+ #[inline(always)]
+ pub const fn wrapping_sub(&self, rhs: Self) -> Self {
+ Limb(self.0.wrapping_sub(rhs.0))
+ }
+}
+
+impl CheckedSub for Limb {
+ type Output = Self;
+
+ #[inline]
+ fn checked_sub(&self, rhs: Self) -> CtOption<Self> {
+ let (result, underflow) = self.sbb(rhs, Limb::ZERO);
+ CtOption::new(result, underflow.is_zero())
+ }
+}
+
+impl Sub for Wrapping<Limb> {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Wrapping<Limb> {
+ Wrapping(self.0.wrapping_sub(rhs.0))
+ }
+}
+
+impl Sub<&Wrapping<Limb>> for Wrapping<Limb> {
+ type Output = Wrapping<Limb>;
+
+ fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
+ Wrapping(self.0.wrapping_sub(rhs.0))
+ }
+}
+
+impl Sub<Wrapping<Limb>> for &Wrapping<Limb> {
+ type Output = Wrapping<Limb>;
+
+ fn sub(self, rhs: Wrapping<Limb>) -> Wrapping<Limb> {
+ Wrapping(self.0.wrapping_sub(rhs.0))
+ }
+}
+
+impl Sub<&Wrapping<Limb>> for &Wrapping<Limb> {
+ type Output = Wrapping<Limb>;
+
+ fn sub(self, rhs: &Wrapping<Limb>) -> Wrapping<Limb> {
+ Wrapping(self.0.wrapping_sub(rhs.0))
+ }
+}
+
+impl SubAssign for Wrapping<Limb> {
+ fn sub_assign(&mut self, other: Self) {
+ *self = *self - other;
+ }
+}
+
+impl SubAssign<&Wrapping<Limb>> for Wrapping<Limb> {
+ fn sub_assign(&mut self, other: &Self) {
+ *self = *self - other;
+ }
+}
+
+impl Sub for Checked<Limb> {
+ type Output = Self;
+
+ fn sub(self, rhs: Self) -> Checked<Limb> {
+ Checked(
+ self.0
+ .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
+ )
+ }
+}
+
+impl Sub<&Checked<Limb>> for Checked<Limb> {
+ type Output = Checked<Limb>;
+
+ fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
+ Checked(
+ self.0
+ .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
+ )
+ }
+}
+
+impl Sub<Checked<Limb>> for &Checked<Limb> {
+ type Output = Checked<Limb>;
+
+ fn sub(self, rhs: Checked<Limb>) -> Checked<Limb> {
+ Checked(
+ self.0
+ .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
+ )
+ }
+}
+
+impl Sub<&Checked<Limb>> for &Checked<Limb> {
+ type Output = Checked<Limb>;
+
+ fn sub(self, rhs: &Checked<Limb>) -> Checked<Limb> {
+ Checked(
+ self.0
+ .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(rhs))),
+ )
+ }
+}
+
+impl SubAssign for Checked<Limb> {
+ fn sub_assign(&mut self, other: Self) {
+ *self = *self - other;
+ }
+}
+
+impl SubAssign<&Checked<Limb>> for Checked<Limb> {
+ fn sub_assign(&mut self, other: &Self) {
+ *self = *self - other;
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::{CheckedSub, Limb};
+
+ #[test]
+ fn sbb_no_borrow() {
+ let (res, borrow) = Limb::ONE.sbb(Limb::ONE, Limb::ZERO);
+ assert_eq!(res, Limb::ZERO);
+ assert_eq!(borrow, Limb::ZERO);
+ }
+
+ #[test]
+ fn sbb_with_borrow() {
+ let (res, borrow) = Limb::ZERO.sbb(Limb::ONE, Limb::ZERO);
+
+ assert_eq!(res, Limb::MAX);
+ assert_eq!(borrow, Limb::MAX);
+ }
+
+ #[test]
+ fn wrapping_sub_no_borrow() {
+ assert_eq!(Limb::ONE.wrapping_sub(Limb::ONE), Limb::ZERO);
+ }
+
+ #[test]
+ fn wrapping_sub_with_borrow() {
+ assert_eq!(Limb::ZERO.wrapping_sub(Limb::ONE), Limb::MAX);
+ }
+
+ #[test]
+ fn checked_sub_ok() {
+ let result = Limb::ONE.checked_sub(Limb::ONE);
+ assert_eq!(result.unwrap(), Limb::ZERO);
+ }
+
+ #[test]
+ fn checked_sub_overflow() {
+ let result = Limb::ZERO.checked_sub(Limb::ONE);
+ assert!(!bool::from(result.is_some()));
+ }
+}