cnfy-uint 0.2.3

Zero-dependency 256-bit unsigned integer arithmetic for cryptographic applications
Documentation
//! Wrapping 320-bit subtraction via the `Sub` trait.
use super::U320;
use core::ops::Sub;

/// Wrapping subtraction of two 320-bit integers, producing a 320-bit result.
///
/// Computes `self - rhs` using u128-packed borrow chaining across five
/// limbs. The lowest two limb pairs are packed into `u128` for native
/// `sub`/`sbb` sequences; the fifth (most significant) limb is handled
/// as a single `u64` subtraction with the final borrow.
///
/// The result wraps on underflow (modular 2^320 arithmetic). No underflow
/// flag is returned.
///
/// # Examples
///
/// ```
/// use cnfy_uint::u320::U320;
///
/// let a = U320::from_be_limbs([0, 0, 0, 0, 10]);
/// let b = U320::from_be_limbs([0, 0, 0, 0, 3]);
/// assert_eq!(a - b, U320::from_be_limbs([0, 0, 0, 0, 7]));
/// ```
impl Sub for U320 {
    type Output = U320;

    #[inline]
    fn sub(self, rhs: U320) -> U320 {
        // Pack limb pairs into u128 for efficient borrow chaining
        let a_lo = ((self.0[1] as u128) << 64) | (self.0[0] as u128);
        let a_hi = ((self.0[3] as u128) << 64) | (self.0[2] as u128);
        let b_lo = ((rhs.0[1] as u128) << 64) | (rhs.0[0] as u128);
        let b_hi = ((rhs.0[3] as u128) << 64) | (rhs.0[2] as u128);

        let (diff_lo, borrow1) = a_lo.overflowing_sub(b_lo);
        let (diff_hi, u1) = a_hi.overflowing_sub(b_hi);
        let (diff_hi, u2) = diff_hi.overflowing_sub(borrow1 as u128);

        let top = self.0[4]
            .wrapping_sub(rhs.0[4])
            .wrapping_sub((u1 | u2) as u64);

        U320([
            diff_lo as u64,
            (diff_lo >> 64) as u64,
            diff_hi as u64,
            (diff_hi >> 64) as u64,
            top,
        ])
    }
}

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

    /// Subtracting a smaller value produces the correct difference.
    #[test]
    fn small_no_underflow() {
        let a = U320::from_be_limbs([0, 0, 0, 0, 10]);
        let b = U320::from_be_limbs([0, 0, 0, 0, 3]);
        assert_eq!(a - b, U320::from_be_limbs([0, 0, 0, 0, 7]));
    }

    /// Subtracting self yields zero.
    #[test]
    fn self_cancellation() {
        let a = U320::from_be_limbs([0x1234, 0x5678, 0x9ABC, 0xDEF0, 0x1111]);
        assert_eq!(a - a, U320::from_be_limbs([0; 5]));
    }

    /// Borrow propagates across all five limbs.
    #[test]
    fn borrow_propagation() {
        let a = U320::from_be_limbs([1, 0, 0, 0, 0]);
        let b = U320::from_be_limbs([0, 0, 0, 0, 1]);
        assert_eq!(
            a - b,
            U320::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX]),
        );
    }

    /// Zero minus one wraps to all-MAX (modular 2^320).
    #[test]
    fn underflow_wraps() {
        let a = U320::from_be_limbs([0; 5]);
        let b = U320::from_be_limbs([0, 0, 0, 0, 1]);
        assert_eq!(
            a - b,
            U320::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX]),
        );
    }

    /// Subtraction across the u128-pair boundary (limbs 2-3).
    #[test]
    fn cross_pair_borrow() {
        let a = U320::from_be_limbs([0, 1, 0, 0, 0]);
        let b = U320::from_be_limbs([0, 0, 0, 0, 1]);
        assert_eq!(
            a - b,
            U320::from_be_limbs([0, 0, u64::MAX, u64::MAX, u64::MAX]),
        );
    }

    /// Large values in all limbs.
    #[test]
    fn full_width_subtraction() {
        let a = U320::from_be_limbs([u64::MAX, u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
        let b = U320::from_be_limbs([0, u64::MAX, u64::MAX, u64::MAX, u64::MAX]);
        assert_eq!(a - b, U320::from_be_limbs([u64::MAX, 0, 0, 0, 0]));
    }
}