Skip to content

Commit d7b3eab

Browse files
authored
BoxedUint: even GCD support (#618)
Uses an implementation similar to `Uint::gcd` as added in #617
1 parent 001f89f commit d7b3eab

File tree

3 files changed

+48
-15
lines changed

3 files changed

+48
-15
lines changed

src/traits.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,12 @@ pub trait FixedInteger: Bounded + ConditionallySelectable + Constants + Copy + I
197197
const LIMBS: usize;
198198
}
199199

200-
/// Compute greatest common divisor of two integers.
200+
/// Compute the greatest common divisor of two integers.
201201
pub trait Gcd<Rhs = Self>: Sized {
202202
/// Output type.
203203
type Output;
204204

205-
/// Compute greatest common divisor of `self` and `rhs`.
205+
/// Compute the greatest common divisor of `self` and `rhs`.
206206
///
207207
/// Returns none unless `self` is odd (`rhs` may be even or odd)`.
208208
fn gcd(&self, rhs: &Rhs) -> Self::Output;

src/uint/boxed/gcd.rs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,27 @@
11
//! Support for computing greatest common divisor of two `BoxedUint`s.
22
33
use super::BoxedUint;
4-
use crate::{modular::bernstein_yang, Gcd, Integer, Odd};
5-
use subtle::CtOption;
4+
use crate::{modular::bernstein_yang, ConstantTimeSelect, Gcd, Integer, Odd};
5+
use subtle::{ConditionallySelectable, ConstantTimeLess};
66

77
impl Gcd for BoxedUint {
8-
type Output = CtOption<Self>;
8+
type Output = Self;
99

10-
fn gcd(&self, rhs: &Self) -> CtOption<Self> {
11-
let ret = bernstein_yang::boxed::gcd(self, rhs);
12-
CtOption::new(ret, self.is_odd())
10+
/// Compute the greatest common divisor (GCD) of this number and another.
11+
fn gcd(&self, rhs: &Self) -> Self {
12+
let k1 = self.trailing_zeros();
13+
let k2 = rhs.trailing_zeros();
14+
15+
// Select the smaller of the two `k` values, making 2^k the common even divisor
16+
let k = u32::conditional_select(&k1, &k2, u32::ct_lt(&k2, &k1));
17+
18+
// Decompose `self` and `rhs` into `s{1, 2} * 2^k` where either `s1` or `s2` is odd
19+
let s1 = self.overflowing_shr(k).0;
20+
let s2 = rhs.overflowing_shr(k).0;
21+
22+
let f = Self::ct_select(&s1, &s2, !s2.is_odd());
23+
let g = Self::ct_select(&s1, &s2, s2.is_odd());
24+
bernstein_yang::boxed::gcd(&f, &g).overflowing_shl(k).0
1325
}
1426
}
1527

@@ -41,4 +53,31 @@ mod tests {
4153
let gcd = f.gcd(&g);
4254
assert_eq!(gcd, BoxedUint::from(1763u32));
4355
}
56+
57+
#[test]
58+
fn gcd_zero() {
59+
let zero = BoxedUint::from(0u32);
60+
let one = BoxedUint::from(1u32);
61+
62+
assert_eq!(zero.gcd(&zero), zero);
63+
assert_eq!(zero.gcd(&one), one);
64+
assert_eq!(one.gcd(&zero), one);
65+
}
66+
67+
#[test]
68+
fn gcd_one() {
69+
let f = BoxedUint::from(1u32);
70+
assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(1u32)));
71+
assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(2u8)));
72+
}
73+
74+
#[test]
75+
fn gcd_two() {
76+
let f = BoxedUint::from(2u32);
77+
assert_eq!(f, f.gcd(&f));
78+
79+
let g = BoxedUint::from(4u32);
80+
assert_eq!(f, f.gcd(&g));
81+
assert_eq!(f, g.gcd(&f));
82+
}
4483
}

tests/boxed_uint.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -143,13 +143,7 @@ proptest! {
143143
}
144144

145145
#[test]
146-
fn gcd((mut f, g) in uint_pair()) {
147-
if f.is_even().into() {
148-
// Ensure `f` is always odd (required by Bernstein-Yang)
149-
f = f.wrapping_add(&BoxedUint::one());
150-
}
151-
152-
let f = f.to_odd().unwrap();
146+
fn gcd((f, g) in uint_pair()) {
153147
let f_bi = to_biguint(&f);
154148
let g_bi = to_biguint(&g);
155149

0 commit comments

Comments
 (0)