cnfy-uint 0.2.3

Zero-dependency 256-bit unsigned integer arithmetic for cryptographic applications
Documentation
//! Bit-level leading zero count for [`U256`].

use super::U256;

impl U256 {
    /// Returns the number of leading zero bits in the 256-bit value.
    ///
    /// Scans from the most significant limb (`w3`, index 3) downward. Returns 256
    /// for zero, 0 for any value with the MSB set, and `256 - bit_len()`
    /// in general. Useful for difficulty target comparison in Bitcoin
    /// mining.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u256::U256;
    ///
    /// assert_eq!(U256::ZERO.leading_zeros(), 256);
    /// assert_eq!(U256::ONE.leading_zeros(), 255);
    /// assert_eq!(U256::MAX.leading_zeros(), 0);
    /// ```
    #[inline]
    pub const fn leading_zeros(&self) -> u32 {
        if self.0[3] != 0 {
            self.0[3].leading_zeros()
        } else if self.0[2] != 0 {
            64 + self.0[2].leading_zeros()
        } else if self.0[1] != 0 {
            128 + self.0[1].leading_zeros()
        } else if self.0[0] != 0 {
            192 + self.0[0].leading_zeros()
        } else {
            256
        }
    }
}

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

    /// Zero has 256 leading zeros.
    #[test]
    fn zero() {
        assert_eq!(U256::ZERO.leading_zeros(), 256);
    }

    /// One has 255 leading zeros.
    #[test]
    fn one() {
        assert_eq!(U256::ONE.leading_zeros(), 255);
    }

    /// MAX has 0 leading zeros.
    #[test]
    fn max() {
        assert_eq!(U256::MAX.leading_zeros(), 0);
    }

    /// Consistent with bit_len: leading_zeros + bit_len = 256 (nonzero).
    #[test]
    fn consistent_with_bit_len() {
        let cases = [
            U256::ONE,
            U256::from_be_limbs([0, 0, 0, 0xFF]),
            U256::from_be_limbs([0, 0, 1, 0]),
            U256::from_be_limbs([0, 1, 0, 0]),
            U256::from_be_limbs([1, 0, 0, 0]),
            U256::MAX,
        ];
        for v in &cases {
            assert_eq!(v.leading_zeros() + v.bit_len(), 256);
        }
    }

    /// Powers of two have leading_zeros = 255 - exponent.
    #[test]
    fn powers_of_two() {
        // 2^0 = 1 → 255 leading zeros
        assert_eq!(U256::from_be_limbs([0, 0, 0, 1]).leading_zeros(), 255);
        // 2^64 → 191 leading zeros
        assert_eq!(U256::from_be_limbs([0, 0, 1, 0]).leading_zeros(), 191);
        // 2^128 → 127 leading zeros
        assert_eq!(U256::from_be_limbs([0, 1, 0, 0]).leading_zeros(), 127);
        // 2^192 → 63 leading zeros
        assert_eq!(U256::from_be_limbs([1, 0, 0, 0]).leading_zeros(), 63);
    }

    /// Limb boundary values.
    #[test]
    fn limb_boundaries() {
        // Full w3 → 192 leading zeros
        assert_eq!(U256::from_be_limbs([0, 0, 0, u64::MAX]).leading_zeros(), 192);
        // Full w2 → 128 leading zeros
        assert_eq!(U256::from_be_limbs([0, 0, u64::MAX, 0]).leading_zeros(), 128);
        // Full w1 → 64 leading zeros
        assert_eq!(U256::from_be_limbs([0, u64::MAX, 0, 0]).leading_zeros(), 64);
        // Full w0 → 0 leading zeros
        assert_eq!(U256::from_be_limbs([u64::MAX, 0, 0, 0]).leading_zeros(), 0);
    }

    /// Value 0x80 in the LSB limb.
    #[test]
    fn byte_boundary() {
        assert_eq!(U256::from_be_limbs([0, 0, 0, 0x80]).leading_zeros(), 248);
    }
}