diff --git a/src/uint/ref_type/div.rs b/src/uint/ref_type/div.rs index c2d63450..3cc467e3 100644 --- a/src/uint/ref_type/div.rs +++ b/src/uint/ref_type/div.rs @@ -620,7 +620,7 @@ impl UintRef { // Check that the dividend evenly divides by 2^tz, and shift it to match the divisor let div2s_exact = self.ensure_trailing_zeros(tz).and(excess_z.not()); - self.shr_assign(tz); + self.unbounded_shr_assign(tz); let y = Odd::new_ref_unchecked(rhs); let y_inv = y.invert_mod_limb(); @@ -743,8 +743,12 @@ impl UintRef { const fn ensure_trailing_zeros(&self, zs: u32) -> Choice { let z_words = (zs >> Limb::LOG2_BITS) as usize; let z_bits = zs & (Limb::BITS - 1); - self.leading(z_words) - .is_zero() - .and(self.limbs[z_words].restrict_bits(z_bits).is_zero()) + if z_words >= self.nlimbs() { + self.is_zero() + } else { + self.leading(z_words) + .is_zero() + .and(self.limbs[z_words].restrict_bits(z_bits).is_zero()) + } } } diff --git a/tests/uint.rs b/tests/uint.rs index f82285ae..aee42e53 100644 --- a/tests/uint.rs +++ b/tests/uint.rs @@ -8,7 +8,7 @@ mod common; use common::to_biguint; use core::mem; use crypto_bigint::{ - Encoding, Limb, NonZero, Odd, U256, U512, U4096, U8192, Uint, Word, + Encoding, Limb, NonZero, Odd, U128, U256, U512, U4096, U8192, Uint, Word, modular::{FixedMontyForm, FixedMontyParams}, }; use num_bigint::BigUint; @@ -617,3 +617,12 @@ proptest! { prop_assert_eq!(expected, actual); } } + +#[test] +fn div_exact_wide_power_of_two_divisor_is_inexact() { + let lhs = U128::ONE; + let rhs = NonZero::new(U256::ONE << U128::BITS).unwrap(); + + assert!(bool::from(lhs.div_exact(&rhs).is_none())); + assert!(bool::from(lhs.div_exact_vartime(&rhs).is_none())); +}