1
- //! Support for computing greatest common divisor of two `Uint`s.
1
+ //! Support for computing the greatest common divisor of two `Uint`s.
2
2
3
- use crate :: { modular:: BernsteinYangInverter , ConstCtOption , Gcd , Odd , PrecomputeInverter , Uint } ;
3
+ use crate :: {
4
+ modular:: BernsteinYangInverter , ConstChoice , ConstCtOption , Gcd , Odd , PrecomputeInverter , Uint ,
5
+ } ;
4
6
use subtle:: CtOption ;
5
7
6
8
impl < const SAT_LIMBS : usize , const UNSAT_LIMBS : usize > Uint < SAT_LIMBS >
7
9
where
8
10
Odd < Self > : PrecomputeInverter < Inverter = BernsteinYangInverter < SAT_LIMBS , UNSAT_LIMBS > > ,
9
11
{
10
12
/// Compute the greatest common divisor (GCD) of this number and another.
11
- ///
12
- /// Returns none in the event that `self` is even (i.e. `self` MUST be odd). However, `rhs` may be even.
13
13
pub const fn gcd ( & self , rhs : & Self ) -> ConstCtOption < Self > {
14
- let ret = <Odd < Self > as PrecomputeInverter >:: Inverter :: gcd ( self , rhs) ;
15
- ConstCtOption :: new ( ret, self . is_odd ( ) )
14
+ let k1 = self . trailing_zeros ( ) ;
15
+ let k2 = rhs. trailing_zeros ( ) ;
16
+
17
+ // Select the smaller of the two `k` values, making 2^k the common even divisor
18
+ let k = ConstChoice :: from_u32_lt ( k2, k1) . select_u32 ( k1, k2) ;
19
+
20
+ // Decompose `self` and `rhs` into `s{1, 2} * 2^k` where either `s1` or `s2` is odd
21
+ let s1 = self . overflowing_shr ( k) . unwrap_or ( Self :: ZERO ) ;
22
+ let s2 = rhs. overflowing_shr ( k) . unwrap_or ( Self :: ZERO ) ;
23
+
24
+ let f = Self :: select ( & s1, & s2, s2. is_odd ( ) . not ( ) ) ;
25
+ let g = Self :: select ( & s1, & s2, s2. is_odd ( ) ) ;
26
+
27
+ let ret = <Odd < Self > as PrecomputeInverter >:: Inverter :: gcd ( & f, & g) ;
28
+ ConstCtOption :: new (
29
+ ret. overflowing_shl ( k) . unwrap_or ( Self :: ZERO ) ,
30
+ f. is_nonzero ( ) . and ( g. is_odd ( ) ) ,
31
+ )
16
32
}
17
33
}
18
34
@@ -61,8 +77,9 @@ mod tests {
61
77
62
78
#[ test]
63
79
fn gcd_zero ( ) {
64
- let f = U256 :: ZERO ;
65
- assert ! ( f. gcd( & U256 :: ONE ) . is_none( ) . is_true_vartime( ) ) ;
80
+ assert ! ( U256 :: ZERO . gcd( & U256 :: ZERO ) . is_none( ) . is_true_vartime( ) ) ;
81
+ assert ! ( U256 :: ZERO . gcd( & U256 :: ONE ) . is_none( ) . is_true_vartime( ) ) ;
82
+ assert ! ( U256 :: ONE . gcd( & U256 :: ZERO ) . is_none( ) . is_true_vartime( ) ) ;
66
83
}
67
84
68
85
#[ test]
@@ -71,4 +88,14 @@ mod tests {
71
88
assert_eq ! ( U256 :: ONE , f. gcd( & U256 :: ONE ) . unwrap( ) ) ;
72
89
assert_eq ! ( U256 :: ONE , f. gcd( & U256 :: from( 2u8 ) ) . unwrap( ) ) ;
73
90
}
91
+
92
+ #[ test]
93
+ fn gcd_two ( ) {
94
+ let f = U256 :: from_u8 ( 2 ) ;
95
+ assert_eq ! ( f, f. gcd( & f) . unwrap( ) ) ;
96
+
97
+ let g = U256 :: from_u8 ( 4 ) ;
98
+ assert_eq ! ( f, f. gcd( & g) . unwrap( ) ) ;
99
+ assert_eq ! ( f, g. gcd( & f) . unwrap( ) ) ;
100
+ }
74
101
}
0 commit comments