cnfy-uint 0.2.3

Zero-dependency 256-bit unsigned integer arithmetic for cryptographic applications
Documentation
//! Count of leading zero bytes in a [`U512`].
use super::U512;

impl U512 {
    /// Returns the number of leading zero bytes in the 512-bit value.
    ///
    /// Counts full zero bytes from the most significant position.
    /// Returns 64 for zero, 0 when the most significant byte is non-zero.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u512::U512;
    ///
    /// assert_eq!(U512::ZERO.leading_zero_bytes(), 64);
    /// assert_eq!(U512::ONE.leading_zero_bytes(), 63);
    /// ```
    #[inline]
    pub const fn leading_zero_bytes(&self) -> u32 {
        if self.0[7] != 0 {
            return self.0[7].leading_zeros() / 8;
        }
        if self.0[6] != 0 {
            return 8 + self.0[6].leading_zeros() / 8;
        }
        if self.0[5] != 0 {
            return 16 + self.0[5].leading_zeros() / 8;
        }
        if self.0[4] != 0 {
            return 24 + self.0[4].leading_zeros() / 8;
        }
        if self.0[3] != 0 {
            return 32 + self.0[3].leading_zeros() / 8;
        }
        if self.0[2] != 0 {
            return 40 + self.0[2].leading_zeros() / 8;
        }
        if self.0[1] != 0 {
            return 48 + self.0[1].leading_zeros() / 8;
        }
        if self.0[0] != 0 {
            return 56 + self.0[0].leading_zeros() / 8;
        }
        64
    }
}

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

    /// Zero has 64 leading zero bytes.
    #[test]
    fn zero() {
        assert_eq!(U512::ZERO.leading_zero_bytes(), 64);
    }

    /// One has 63 leading zero bytes (only the last byte is non-zero).
    #[test]
    fn one() {
        assert_eq!(U512::ONE.leading_zero_bytes(), 63);
    }

    /// Max value has no leading zero bytes.
    #[test]
    fn max() {
        assert_eq!(U512::MAX.leading_zero_bytes(), 0);
    }

    /// Value with non-zero second limb.
    #[test]
    fn second_limb() {
        assert_eq!(
            U512::from_be_limbs([0, 1, 0, 0, 0, 0, 0, 0]).leading_zero_bytes(),
            15,
        );
    }

    /// Value with non-zero fifth limb.
    #[test]
    fn fifth_limb() {
        assert_eq!(
            U512::from_be_limbs([0, 0, 0, 0, 0x100, 0, 0, 0]).leading_zero_bytes(),
            38,
        );
    }

    /// Value filling first byte exactly.
    #[test]
    fn first_byte_full() {
        assert_eq!(
            U512::from_be_limbs([0xFF00000000000000, 0, 0, 0, 0, 0, 0, 0]).leading_zero_bytes(),
            0,
        );
    }

    /// LSB limb with small value.
    #[test]
    fn lsb_limb_small() {
        assert_eq!(
            U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 0xFF]).leading_zero_bytes(),
            63,
        );
    }
}