crypto_bigint/uint/boxed/
gcd.rs1use super::BoxedUint;
4use crate::{modular::safegcd, ConstantTimeSelect, Gcd, Integer, Odd};
5use subtle::{ConditionallySelectable, ConstantTimeLess};
6
7impl Gcd for BoxedUint {
8 type Output = Self;
9
10 fn gcd(&self, rhs: &Self) -> Self {
12 let k1 = self.trailing_zeros();
13 let k2 = rhs.trailing_zeros();
14
15 let k = u32::conditional_select(&k1, &k2, u32::ct_lt(&k2, &k1));
17
18 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 safegcd::boxed::gcd(&f, &g).overflowing_shl(k).0
25 }
26
27 fn gcd_vartime(&self, rhs: &Self) -> Self::Output {
28 match Odd::<Self>::new(self.clone()).into_option() {
29 Some(odd) => odd.gcd_vartime(rhs),
30 None => self.gcd(rhs), }
32 }
33}
34
35impl Gcd<BoxedUint> for Odd<BoxedUint> {
36 type Output = BoxedUint;
37
38 fn gcd(&self, rhs: &BoxedUint) -> BoxedUint {
39 safegcd::boxed::gcd(self, rhs)
40 }
41
42 fn gcd_vartime(&self, rhs: &BoxedUint) -> Self::Output {
43 safegcd::boxed::gcd_vartime(self, rhs)
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use crate::{BoxedUint, Gcd};
50
51 #[test]
52 fn gcd_relatively_prime() {
53 let f = BoxedUint::from(59u32 * 67).to_odd().unwrap();
55 let g = BoxedUint::from(61u32 * 71);
56 let gcd = f.gcd(&g);
57 assert_eq!(gcd, BoxedUint::one());
58 }
59
60 #[test]
61 fn gcd_nonprime() {
62 let f = BoxedUint::from(4391633u32).to_odd().unwrap();
63 let g = BoxedUint::from(2022161u32);
64 let gcd = f.gcd(&g);
65 assert_eq!(gcd, BoxedUint::from(1763u32));
66 }
67
68 #[test]
69 fn gcd_zero() {
70 let zero = BoxedUint::from(0u32);
71 let one = BoxedUint::from(1u32);
72
73 assert_eq!(zero.gcd(&zero), zero);
74 assert_eq!(zero.gcd(&one), one);
75 assert_eq!(one.gcd(&zero), one);
76 }
77
78 #[test]
79 fn gcd_one() {
80 let f = BoxedUint::from(1u32);
81 assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(1u32)));
82 assert_eq!(BoxedUint::from(1u32), f.gcd(&BoxedUint::from(2u8)));
83 }
84
85 #[test]
86 fn gcd_two() {
87 let f = BoxedUint::from(2u32);
88 assert_eq!(f, f.gcd(&f));
89
90 let g = BoxedUint::from(4u32);
91 assert_eq!(f, f.gcd(&g));
92 assert_eq!(f, g.gcd(&f));
93 }
94
95 #[test]
96 fn gcd_different_sizes() {
97 let f = BoxedUint::from(4391633u32).widen(128).to_odd().unwrap();
99 let g = BoxedUint::from(2022161u32);
100 let gcd = f.gcd(&g);
101 assert_eq!(gcd, BoxedUint::from(1763u32));
102 }
103
104 #[test]
105 fn gcd_vartime_different_sizes() {
106 let f = BoxedUint::from(4391633u32).widen(128).to_odd().unwrap();
108 let g = BoxedUint::from(2022161u32);
109 let gcd = f.gcd_vartime(&g);
110 assert_eq!(gcd, BoxedUint::from(1763u32));
111 }
112}