cnfy-uint 0.2.3

Zero-dependency 256-bit unsigned integer arithmetic for cryptographic applications
Documentation
//! Bit-level trailing zero count for [`U512`].
use super::U512;

impl U512 {
    /// Returns the number of trailing zero bits in the 512-bit value.
    ///
    /// Scans from the least significant limb (`w7`) upward. Returns 512
    /// for zero, 0 for any odd value, and the position of the lowest set
    /// bit in general.
    ///
    /// # Examples
    ///
    /// ```
    /// use cnfy_uint::u512::U512;
    ///
    /// assert_eq!(U512::ZERO.trailing_zeros(), 512);
    /// assert_eq!(U512::ONE.trailing_zeros(), 0);
    /// assert_eq!(U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 8]).trailing_zeros(), 3);
    /// ```
    #[inline]
    pub const fn trailing_zeros(&self) -> u32 {
        if self.0[0] != 0 {
            self.0[0].trailing_zeros()
        } else if self.0[1] != 0 {
            64 + self.0[1].trailing_zeros()
        } else if self.0[2] != 0 {
            128 + self.0[2].trailing_zeros()
        } else if self.0[3] != 0 {
            192 + self.0[3].trailing_zeros()
        } else if self.0[4] != 0 {
            256 + self.0[4].trailing_zeros()
        } else if self.0[5] != 0 {
            320 + self.0[5].trailing_zeros()
        } else if self.0[6] != 0 {
            384 + self.0[6].trailing_zeros()
        } else if self.0[7] != 0 {
            448 + self.0[7].trailing_zeros()
        } else {
            512
        }
    }
}

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

    /// Zero has 512 trailing zeros.
    #[test]
    fn zero() {
        assert_eq!(U512::ZERO.trailing_zeros(), 512);
    }

    /// One has 0 trailing zeros.
    #[test]
    fn one() {
        assert_eq!(U512::ONE.trailing_zeros(), 0);
    }

    /// MAX has 0 trailing zeros (all bits set).
    #[test]
    fn max() {
        assert_eq!(U512::MAX.trailing_zeros(), 0);
    }

    /// Powers of two have trailing_zeros = exponent.
    #[test]
    fn powers_of_two() {
        assert_eq!(U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 2]).trailing_zeros(), 1);
        assert_eq!(U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 8]).trailing_zeros(), 3);
        assert_eq!(U512::from_be_limbs([0, 0, 0, 0, 0, 0, 1, 0]).trailing_zeros(), 64);
        assert_eq!(U512::from_be_limbs([0, 0, 0, 0, 0, 1, 0, 0]).trailing_zeros(), 128);
        assert_eq!(U512::from_be_limbs([0, 0, 0, 0, 1, 0, 0, 0]).trailing_zeros(), 192);
        assert_eq!(U512::from_be_limbs([0, 0, 0, 1, 0, 0, 0, 0]).trailing_zeros(), 256);
        assert_eq!(U512::from_be_limbs([0, 0, 1, 0, 0, 0, 0, 0]).trailing_zeros(), 320);
        assert_eq!(U512::from_be_limbs([0, 1, 0, 0, 0, 0, 0, 0]).trailing_zeros(), 384);
        assert_eq!(U512::from_be_limbs([1, 0, 0, 0, 0, 0, 0, 0]).trailing_zeros(), 448);
    }

    /// MSB-only value has 511 trailing zeros.
    #[test]
    fn msb_only() {
        assert_eq!(
            U512::from_be_limbs([0x8000000000000000, 0, 0, 0, 0, 0, 0, 0]).trailing_zeros(),
            511,
        );
    }

    /// Odd values always have 0 trailing zeros.
    #[test]
    fn odd_values() {
        assert_eq!(U512::from_be_limbs([0, 0, 0, 0, 0, 0, 0, 3]).trailing_zeros(), 0);
        assert_eq!(U512::from_be_limbs([0xFF, 0, 0, 0, 0, 0, 0, 1]).trailing_zeros(), 0);
    }
}