diff --git a/src/modular/safegcd/boxed.rs b/src/modular/safegcd/boxed.rs index d8ace2e0..09f4695a 100644 --- a/src/modular/safegcd/boxed.rs +++ b/src/modular/safegcd/boxed.rs @@ -133,11 +133,10 @@ pub fn gcd(f: &BoxedUint, g: &BoxedUint) -> BoxedUint { gcd_nz::(f_nz, g).get() } else { // gcd of (0, g) is g - g.clone() + g.resize(u32_max(f.bits_precision(), g.bits_precision())) } } else { let (f_nz, f_is_nonzero) = f.to_nz_or_one(); - // gcd of (0, g) is g let mut r = gcd_nz::(&f_nz, g).get(); r.ct_assign(g, !f_is_nonzero); r @@ -163,7 +162,10 @@ pub fn gcd_nz(f: &NonZero, g: &BoxedUint) -> Non // 4) 2^k•gcd(f, g) = 2^k•gcd(a, 2^j•b) let i = f.as_ref().trailing_zeros(); - let k = u32_min(i, g.trailing_zeros()); + let j = g + .is_nonzero() + .select_u32(f.bits_precision(), g.trailing_zeros()); + let k = u32_min(i, j); let f_odd = Odd::new_unchecked(f.as_ref().shr(i)); let mut r = gcd_odd::(&f_odd, g).get(); diff --git a/src/uint/boxed/ct.rs b/src/uint/boxed/ct.rs index a7d1e78c..6b30b75f 100644 --- a/src/uint/boxed/ct.rs +++ b/src/uint/boxed/ct.rs @@ -7,8 +7,8 @@ use ctutils::{CtAssignSlice, CtEqSlice}; impl CtAssign for BoxedUint { #[inline] fn ct_assign(&mut self, other: &Self, choice: Choice) { - assert_eq!(self.bits_precision(), other.bits_precision()); - self.limbs.ct_assign(&other.limbs, choice); + self.as_mut_uint_ref() + .ct_assign(other.as_uint_ref(), choice); } } impl CtAssignSlice for BoxedUint {} diff --git a/src/uint/boxed/gcd.rs b/src/uint/boxed/gcd.rs index 43f6f9b5..b802520c 100644 --- a/src/uint/boxed/gcd.rs +++ b/src/uint/boxed/gcd.rs @@ -42,7 +42,7 @@ impl Gcd for Odd { #[cfg(test)] mod tests { - use crate::{BoxedUint, Gcd, Resize}; + use crate::{BoxedUint, Gcd, Limb, Resize}; #[test] fn gcd_relatively_prime() { @@ -71,6 +71,105 @@ mod tests { assert_eq!(one.gcd(&zero), one); } + #[test] + fn gcd_zero_lhs_wider_than_rhs() { + let zero = BoxedUint::zero_with_precision(2 * Limb::BITS); + let one = BoxedUint::one(); + + let gcd = zero.gcd(&one); + assert_eq!(gcd, one); + assert_eq!(gcd.bits_precision(), zero.bits_precision()); + } + + #[test] + fn gcd_zero_rhs_wider_than_lhs() { + let one = BoxedUint::one(); + let zero = BoxedUint::zero_with_precision(2 * Limb::BITS); + + let gcd = one.gcd(&zero); + assert_eq!(gcd, one); + } + + #[test] + fn gcd_zero_rhs_narrower_than_power_of_two_lhs() { + let x = BoxedUint::one_with_precision(3 * Limb::BITS).wrapping_shl_vartime(Limb::BITS + 1); + let zero = BoxedUint::zero_with_precision(Limb::BITS); + + let gcd = x.gcd(&zero); + assert_eq!(gcd, x); + } + + #[test] + fn gcd_vartime_zero_rhs_narrower_than_power_of_two_lhs() { + let x = BoxedUint::one_with_precision(3 * Limb::BITS).wrapping_shl_vartime(Limb::BITS + 1); + let zero = BoxedUint::zero_with_precision(Limb::BITS); + + let gcd = x.gcd_vartime(&zero); + assert_eq!(gcd, x); + } + + #[test] + fn gcd_nonzero_lhs_wider_than_rhs_precision() { + let wide = BoxedUint::from(6u8).resize(2 * Limb::BITS); + let narrow = BoxedUint::from(4u8); + + let gcd = wide.gcd(&narrow); + assert_eq!(gcd, BoxedUint::from(2u8)); + assert_eq!(gcd.bits_precision(), wide.bits_precision()); + } + + #[test] + fn gcd_nonzero_rhs_wider_than_lhs_precision() { + let narrow = BoxedUint::from(4u8); + let wide = BoxedUint::from(6u8).resize(2 * Limb::BITS); + + let gcd = narrow.gcd(&wide); + assert_eq!(gcd, BoxedUint::from(2u8)); + assert_eq!(gcd.bits_precision(), wide.bits_precision()); + } + + #[test] + fn gcd_vartime_zero_lhs_wider_than_rhs() { + let zero = BoxedUint::zero_with_precision(2 * Limb::BITS); + let one = BoxedUint::one(); + + let gcd = zero.gcd_vartime(&one); + assert_eq!(gcd, one); + assert_eq!(gcd.bits_precision(), zero.bits_precision()); + } + + #[test] + fn gcd_vartime_zero_rhs_wider_than_lhs() { + let one = BoxedUint::one(); + let zero = BoxedUint::zero_with_precision(2 * Limb::BITS); + + let gcd = one.gcd_vartime(&zero); + assert_eq!(gcd, one); + assert_eq!(gcd.bits_precision(), zero.bits_precision()); + } + + #[test] + fn gcd_zero_zero_mixed_precision() { + let narrow = BoxedUint::zero_with_precision(Limb::BITS); + let wide = BoxedUint::zero_with_precision(2 * Limb::BITS); + + let gcd = narrow.gcd(&wide); + assert_eq!(gcd, narrow); + assert_eq!(gcd.bits_precision(), wide.bits_precision()); + assert_eq!(gcd, wide.gcd(&narrow)); + } + + #[test] + fn gcd_vartime_zero_zero_mixed_precision() { + let narrow = BoxedUint::zero_with_precision(Limb::BITS); + let wide = BoxedUint::zero_with_precision(2 * Limb::BITS); + + let gcd = narrow.gcd_vartime(&wide); + assert_eq!(gcd, narrow); + assert_eq!(gcd.bits_precision(), wide.bits_precision()); + assert_eq!(gcd, wide.gcd_vartime(&narrow)); + } + #[test] fn gcd_one() { let f = BoxedUint::from(1u32); diff --git a/src/uint/ref_type/ct.rs b/src/uint/ref_type/ct.rs index caf3a6ca..cfd353f4 100644 --- a/src/uint/ref_type/ct.rs +++ b/src/uint/ref_type/ct.rs @@ -6,8 +6,10 @@ use crate::{Choice, CtAssign, CtEq, CtLt}; impl CtAssign for UintRef { #[inline] fn ct_assign(&mut self, other: &Self, choice: Choice) { - debug_assert_eq!(self.bits_precision(), other.bits_precision()); - self.limbs.ct_assign(&other.limbs, choice); + assert!(self.bits_precision() >= other.bits_precision()); + let (lo, hi) = self.split_at_mut(other.nlimbs()); + lo.limbs.ct_assign(&other.limbs, choice); + hi.conditional_set_zero(choice); } }