|
| 1 | +//! Bit manipulation functions. |
| 2 | +
|
| 3 | +use crate::{BoxedUint, Limb, Zero}; |
| 4 | +use subtle::{ConditionallySelectable, ConstantTimeEq}; |
| 5 | + |
| 6 | +impl BoxedUint { |
| 7 | + /// Calculate the number of bits needed to represent this number, i.e. the index of the highest |
| 8 | + /// set bit. |
| 9 | + /// |
| 10 | + /// Use [`BoxedUint::bits_precision`] to get the total capacity of this integer. |
| 11 | + pub fn bits(&self) -> usize { |
| 12 | + // Use `u32` because `subtle` can't select on `usize` and it matches what `core` uses for |
| 13 | + // the return value of `leading_zeros` |
| 14 | + let mut leading_zeros = 0u32; |
| 15 | + let mut n = 0u32; |
| 16 | + |
| 17 | + for limb in self.limbs.iter().rev() { |
| 18 | + n.conditional_assign(&(n + 1), !limb.is_zero() | !n.ct_eq(&0)); |
| 19 | + |
| 20 | + // Set `leading_zeros` for the first nonzero limb we encounter |
| 21 | + leading_zeros.conditional_assign(&(limb.leading_zeros() as u32), n.ct_eq(&1)); |
| 22 | + } |
| 23 | + |
| 24 | + Limb::BITS * (n as usize) - (leading_zeros as usize) |
| 25 | + } |
| 26 | + |
| 27 | + /// Get the precision of this [`BoxedUint`] in bits. |
| 28 | + pub fn bits_precision(&self) -> usize { |
| 29 | + self.limbs.len() * Limb::BITS |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +#[cfg(test)] |
| 34 | +mod tests { |
| 35 | + use super::BoxedUint; |
| 36 | + use hex_literal::hex; |
| 37 | + |
| 38 | + #[test] |
| 39 | + fn bits() { |
| 40 | + assert_eq!(0, BoxedUint::zero().bits()); |
| 41 | + assert_eq!(128, BoxedUint::max(128).bits()); |
| 42 | + |
| 43 | + let n1 = BoxedUint::from_be_slice(&hex!("000000000029ffffffffffffffffffff"), 128).unwrap(); |
| 44 | + assert_eq!(86, n1.bits()); |
| 45 | + |
| 46 | + let n2 = BoxedUint::from_be_slice(&hex!("00000000004000000000000000000000"), 128).unwrap(); |
| 47 | + assert_eq!(87, n2.bits()); |
| 48 | + } |
| 49 | +} |
0 commit comments