Skip to content

Commit

Permalink
BoxedUint: even GCD support (#618)
Browse files Browse the repository at this point in the history
Uses an implementation similar to `Uint::gcd` as added in #617
  • Loading branch information
tarcieri authored Jul 16, 2024
1 parent 001f89f commit d7b3eab
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 15 deletions.
4 changes: 2 additions & 2 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,12 @@ pub trait FixedInteger: Bounded + ConditionallySelectable + Constants + Copy + I
const LIMBS: usize;
}

/// Compute greatest common divisor of two integers.
/// Compute the greatest common divisor of two integers.
pub trait Gcd<Rhs = Self>: Sized {
/// Output type.
type Output;

/// Compute greatest common divisor of `self` and `rhs`.
/// Compute the greatest common divisor of `self` and `rhs`.
///
/// Returns none unless `self` is odd (`rhs` may be even or odd)`.
fn gcd(&self, rhs: &Rhs) -> Self::Output;
Expand Down
51 changes: 45 additions & 6 deletions src/uint/boxed/gcd.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,27 @@
//! Support for computing greatest common divisor of two `BoxedUint`s.
use super::BoxedUint;
use crate::{modular::bernstein_yang, Gcd, Integer, Odd};
use subtle::CtOption;
use crate::{modular::bernstein_yang, ConstantTimeSelect, Gcd, Integer, Odd};
use subtle::{ConditionallySelectable, ConstantTimeLess};

impl Gcd for BoxedUint {
type Output = CtOption<Self>;
type Output = Self;

fn gcd(&self, rhs: &Self) -> CtOption<Self> {
let ret = bernstein_yang::boxed::gcd(self, rhs);
CtOption::new(ret, self.is_odd())
/// Compute the greatest common divisor (GCD) of this number and another.
fn gcd(&self, rhs: &Self) -> Self {
let k1 = self.trailing_zeros();
let k2 = rhs.trailing_zeros();

// Select the smaller of the two `k` values, making 2^k the common even divisor
let k = u32::conditional_select(&k1, &k2, u32::ct_lt(&k2, &k1));

// Decompose `self` and `rhs` into `s{1, 2} * 2^k` where either `s1` or `s2` is odd
let s1 = self.overflowing_shr(k).0;
let s2 = rhs.overflowing_shr(k).0;

let f = Self::ct_select(&s1, &s2, !s2.is_odd());
let g = Self::ct_select(&s1, &s2, s2.is_odd());
bernstein_yang::boxed::gcd(&f, &g).overflowing_shl(k).0
}
}

Expand Down Expand Up @@ -41,4 +53,31 @@ mod tests {
let gcd = f.gcd(&g);
assert_eq!(gcd, BoxedUint::from(1763u32));
}

#[test]
fn gcd_zero() {
let zero = BoxedUint::from(0u32);
let one = BoxedUint::from(1u32);

assert_eq!(zero.gcd(&zero), zero);
assert_eq!(zero.gcd(&one), one);
assert_eq!(one.gcd(&zero), one);
}

#[test]
fn gcd_one() {
let f = BoxedUint::from(1u32);
assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(1u32)));
assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(2u8)));
}

#[test]
fn gcd_two() {
let f = BoxedUint::from(2u32);
assert_eq!(f, f.gcd(&f));

let g = BoxedUint::from(4u32);
assert_eq!(f, f.gcd(&g));
assert_eq!(f, g.gcd(&f));
}
}
8 changes: 1 addition & 7 deletions tests/boxed_uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,7 @@ proptest! {
}

#[test]
fn gcd((mut f, g) in uint_pair()) {
if f.is_even().into() {
// Ensure `f` is always odd (required by Bernstein-Yang)
f = f.wrapping_add(&BoxedUint::one());
}

let f = f.to_odd().unwrap();
fn gcd((f, g) in uint_pair()) {
let f_bi = to_biguint(&f);
let g_bi = to_biguint(&g);

Expand Down

0 comments on commit d7b3eab

Please sign in to comment.