cnfy-uint 0.2.3

Zero-dependency 256-bit unsigned integer arithmetic for cryptographic applications
Documentation
//! Checked subtraction for [`U512`].
use super::U512;

impl U512 {
    /// Checked 512-bit subtraction, returning `None` on underflow.
    ///
    /// Computes `self - other` via [`overflowing_sub`](U512::overflowing_sub).
    /// Returns `Some(result)` if `self >= other`, or `None` if the
    /// subtraction would underflow.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u512::U512;
    ///
    /// let a = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 10]);
    /// let b = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 3]);
    /// assert_eq!(a.checked_sub(&b), Some(U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 7])));
    /// assert_eq!(U512::ZERO.checked_sub(&U512::ONE), None);
    /// ```
    #[inline]
    pub const fn checked_sub(&self, other: &U512) -> Option<U512> {
        let (result, underflow) = self.overflowing_sub(other);
        if underflow {
            None
        } else {
            Some(result)
        }
    }
}

#[cfg(test)]
mod ai_tests {
    use super::*;

    /// Small values subtract without underflow.
    #[test]
    fn small_sub() {
        let a = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 10]);
        let b = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 3]);
        assert_eq!(
            a.checked_sub(&b),
            Some(U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 7])),
        );
    }

    /// 0 - 1 underflows to None.
    #[test]
    fn zero_minus_one() {
        assert_eq!(U512::ZERO.checked_sub(&U512::ONE), None);
    }

    /// Self minus self is zero.
    #[test]
    fn self_cancellation() {
        let a = U512::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 1, 2, 3, 4]);
        assert_eq!(a.checked_sub(&a), Some(U512::ZERO));
    }

    /// Subtracting zero is identity.
    #[test]
    fn subtractive_identity() {
        let a = U512::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 1, 2, 3, 4]);
        assert_eq!(a.checked_sub(&U512::ZERO), Some(a));
    }

    /// Larger minus smaller succeeds with borrow.
    #[test]
    fn borrow_succeeds() {
        let a = U512::from_be_limbs([1, 0, 0, 0, 0, 0, 0, 0]);
        let b = U512::ONE;
        assert_eq!(
            a.checked_sub(&b),
            Some(U512::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX])),
        );
    }

    /// Smaller minus larger underflows.
    #[test]
    fn underflow() {
        let a = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 5]);
        let b = U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 10]);
        assert_eq!(a.checked_sub(&b), None);
    }
}