//! Variable-time modular subtraction of two [`U256`] values.
use super::U256;

impl U256 {
    /// Computes `(self - other) mod modulus` using branching correction.
    ///
    /// When the subtraction underflows (`self < other`), a single addition
    /// of `modulus` corrects the result back into `[0, modulus)`. Correct
    /// for reduced inputs where both operands are less than `modulus`.
    ///
    /// This is the fastest path but execution time depends on operand values.
    /// Use `sub_mod_ct` when constant-time behavior is required.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    /// let P = U256::from_be_limbs([
    ///     0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
    ///     0xFFFFFFFFFFFFFFFF, 0xFFFFFFFEFFFFFC2F,
    /// ]);
    ///
    /// let a = U256::from_be_limbs([0, 0, 0, 30]);
    /// let b = U256::from_be_limbs([0, 0, 0, 20]);
    /// assert_eq!(a.sub_mod_vt(&b, &P), U256::from_be_limbs([0, 0, 0, 10]));
    /// ```
    #[inline]
    pub fn sub_mod_vt(&self, other: &U256, modulus: &U256) -> U256 {
        let (result, underflow) = self.overflowing_sub(other);
        match underflow {
            true => result.overflowing_add(modulus).0,
            false => result,
        }
    }
}

#[cfg(test)]
mod ai_tests {
    use super::*;
    const P: U256 = U256::from_be_limbs([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFEFFFFFC2F]);

    /// Subtracting zero from zero yields zero.
    #[test]
    fn zero_minus_zero() {
        assert_eq!(U256::ZERO.sub_mod_vt(&U256::ZERO, &P), U256::ZERO);
    }

    /// Subtracting zero is the identity operation.
    #[test]
    fn subtractive_identity() {
        let a = U256::from_be_limbs([0, 0, 0, 42]);
        assert_eq!(a.sub_mod_vt(&U256::ZERO, &P), a);
    }

    /// Subtracting a value from itself yields zero.
    #[test]
    fn self_cancellation() {
        let a = U256::from_be_limbs([
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFEFFFFFC2E,
        ]);
        assert_eq!(a.sub_mod_vt(&a, &P), U256::ZERO);
    }

    /// Zero minus a non-zero value wraps: 0 - a = P - a.
    #[test]
    fn zero_minus_value() {
        let p_minus_1 = U256::from_be_limbs([
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFEFFFFFC2E,
        ]);
        assert_eq!(U256::ZERO.sub_mod_vt(&U256::ONE, &P), p_minus_1);
    }

    /// 1 - 2 mod P = P - 1 (underflow path).
    #[test]
    fn one_minus_two() {
        let two = U256::from_be_limbs([0, 0, 0, 2]);
        let p_minus_1 = U256::from_be_limbs([
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFEFFFFFC2E,
        ]);
        assert_eq!(U256::ONE.sub_mod_vt(&two, &P), p_minus_1);
    }

    /// (P-1) - 1 = P - 2 (no underflow).
    #[test]
    fn p_minus_one_minus_one() {
        let p_minus_1 = U256::from_be_limbs([
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFEFFFFFC2E,
        ]);
        let p_minus_2 = U256::from_be_limbs([
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFFFFFFFFFF,
            0xFFFFFFFEFFFFFC2D,
        ]);
        assert_eq!(p_minus_1.sub_mod_vt(&U256::ONE, &P), p_minus_2);
    }

    /// Subtraction is not commutative: a - b != b - a (unless a == b).
    #[test]
    fn non_commutative() {
        let a = U256::from_be_limbs([0, 0, 0, 10]);
        let b = U256::from_be_limbs([0, 0, 0, 3]);
        assert_ne!(a.sub_mod_vt(&b, &P), b.sub_mod_vt(&a, &P));
    }

    /// Inverse of add_mod: (a + b) - b = a.
    #[test]
    fn add_then_sub() {
        let a = U256::from_be_limbs([0, 0x1234, 0, 0x5678]);
        let b = U256::from_be_limbs([0, 0xABCD, 0, 0xEF01]);
        assert_eq!(a.add_mod(&b, &P).sub_mod_vt(&b, &P), a);
    }
}
