From 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 4 May 2024 14:41:41 +0200 Subject: Merging upstream version 1.70.0+dfsg2. Signed-off-by: Daniel Baumann --- vendor/crypto-bigint/src/uint/sub.rs | 192 +++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 vendor/crypto-bigint/src/uint/sub.rs (limited to 'vendor/crypto-bigint/src/uint/sub.rs') diff --git a/vendor/crypto-bigint/src/uint/sub.rs b/vendor/crypto-bigint/src/uint/sub.rs new file mode 100644 index 000000000..102f6b978 --- /dev/null +++ b/vendor/crypto-bigint/src/uint/sub.rs @@ -0,0 +1,192 @@ +//! [`UInt`] addition operations. + +use super::UInt; +use crate::{Checked, CheckedSub, Limb, Wrapping, Zero}; +use core::ops::{Sub, SubAssign}; +use subtle::CtOption; + +impl UInt { + /// Computes `a - (b + borrow)`, returning the result along with the new borrow. + #[inline(always)] + pub const fn sbb(&self, rhs: &Self, mut borrow: Limb) -> (Self, Limb) { + let mut limbs = [Limb::ZERO; LIMBS]; + let mut i = 0; + + while i < LIMBS { + let (w, b) = self.limbs[i].sbb(rhs.limbs[i], borrow); + limbs[i] = w; + borrow = b; + i += 1; + } + + (Self { limbs }, borrow) + } + + /// Perform saturating subtraction, returning `ZERO` on underflow. + pub const fn saturating_sub(&self, rhs: &Self) -> Self { + let (res, underflow) = self.sbb(rhs, Limb::ZERO); + + if underflow.0 == 0 { + res + } else { + Self::ZERO + } + } + + /// Perform wrapping subtraction, discarding underflow and wrapping around + /// the boundary of the type. + pub const fn wrapping_sub(&self, rhs: &Self) -> Self { + self.sbb(rhs, Limb::ZERO).0 + } +} + +impl CheckedSub<&UInt> for UInt { + type Output = Self; + + fn checked_sub(&self, rhs: &Self) -> CtOption { + let (result, underflow) = self.sbb(rhs, Limb::ZERO); + CtOption::new(result, underflow.is_zero()) + } +} + +impl Sub for Wrapping> { + type Output = Self; + + fn sub(self, rhs: Self) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl Sub<&Wrapping>> for Wrapping> { + type Output = Wrapping>; + + fn sub(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl Sub>> for &Wrapping> { + type Output = Wrapping>; + + fn sub(self, rhs: Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl Sub<&Wrapping>> for &Wrapping> { + type Output = Wrapping>; + + fn sub(self, rhs: &Wrapping>) -> Wrapping> { + Wrapping(self.0.wrapping_sub(&rhs.0)) + } +} + +impl SubAssign for Wrapping> { + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl SubAssign<&Wrapping>> for Wrapping> { + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +impl Sub for Checked> { + type Output = Self; + + fn sub(self, rhs: Self) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl Sub<&Checked>> for Checked> { + type Output = Checked>; + + fn sub(self, rhs: &Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl Sub>> for &Checked> { + type Output = Checked>; + + fn sub(self, rhs: Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl Sub<&Checked>> for &Checked> { + type Output = Checked>; + + fn sub(self, rhs: &Checked>) -> Checked> { + Checked( + self.0 + .and_then(|lhs| rhs.0.and_then(|rhs| lhs.checked_sub(&rhs))), + ) + } +} + +impl SubAssign for Checked> { + fn sub_assign(&mut self, other: Self) { + *self = *self - other; + } +} + +impl SubAssign<&Checked>> for Checked> { + fn sub_assign(&mut self, other: &Self) { + *self = *self - other; + } +} + +#[cfg(test)] +mod tests { + use crate::{CheckedSub, Limb, U128}; + + #[test] + fn sbb_no_borrow() { + let (res, borrow) = U128::ONE.sbb(&U128::ONE, Limb::ZERO); + assert_eq!(res, U128::ZERO); + assert_eq!(borrow, Limb::ZERO); + } + + #[test] + fn sbb_with_borrow() { + let (res, borrow) = U128::ZERO.sbb(&U128::ONE, Limb::ZERO); + + assert_eq!(res, U128::MAX); + assert_eq!(borrow, Limb::MAX); + } + + #[test] + fn wrapping_sub_no_borrow() { + assert_eq!(U128::ONE.wrapping_sub(&U128::ONE), U128::ZERO); + } + + #[test] + fn wrapping_sub_with_borrow() { + assert_eq!(U128::ZERO.wrapping_sub(&U128::ONE), U128::MAX); + } + + #[test] + fn checked_sub_ok() { + let result = U128::ONE.checked_sub(&U128::ONE); + assert_eq!(result.unwrap(), U128::ZERO); + } + + #[test] + fn checked_sub_overflow() { + let result = U128::ZERO.checked_sub(&U128::ONE); + assert!(!bool::from(result.is_some())); + } +} -- cgit v1.2.3