bigint: Add a modpow fallback for even modulus
This commit is contained in:
parent
35b7187e83
commit
ed10d617b5
|
@ -256,25 +256,39 @@ fn pow_bench(b: &mut Bencher) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// This modulus is the prime from the 2048-bit MODP DH group:
|
||||||
|
/// https://tools.ietf.org/html/rfc3526#section-3
|
||||||
|
const RFC3526_2048BIT_MODP_GROUP: &'static str = "\
|
||||||
|
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
||||||
|
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
||||||
|
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
||||||
|
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
||||||
|
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
||||||
|
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
||||||
|
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
||||||
|
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
||||||
|
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
||||||
|
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
||||||
|
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF";
|
||||||
|
|
||||||
#[bench]
|
#[bench]
|
||||||
fn modpow(b: &mut Bencher) {
|
fn modpow(b: &mut Bencher) {
|
||||||
let mut rng = get_rng();
|
let mut rng = get_rng();
|
||||||
let base = rng.gen_biguint(2048);
|
let base = rng.gen_biguint(2048);
|
||||||
let e = rng.gen_biguint(2048);
|
let e = rng.gen_biguint(2048);
|
||||||
// This modulus is the prime from the 2048-bit MODP DH group:
|
let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap();
|
||||||
// https://tools.ietf.org/html/rfc3526#section-3
|
|
||||||
let m = BigUint::from_str_radix("\
|
b.iter(|| base.modpow(&e, &m));
|
||||||
FFFFFFFF_FFFFFFFF_C90FDAA2_2168C234_C4C6628B_80DC1CD1\
|
}
|
||||||
29024E08_8A67CC74_020BBEA6_3B139B22_514A0879_8E3404DD\
|
|
||||||
EF9519B3_CD3A431B_302B0A6D_F25F1437_4FE1356D_6D51C245\
|
#[bench]
|
||||||
E485B576_625E7EC6_F44C42E9_A637ED6B_0BFF5CB6_F406B7ED\
|
fn modpow_even(b: &mut Bencher) {
|
||||||
EE386BFB_5A899FA5_AE9F2411_7C4B1FE6_49286651_ECE45B3D\
|
let mut rng = get_rng();
|
||||||
C2007CB8_A163BF05_98DA4836_1C55D39A_69163FA8_FD24CF5F\
|
let base = rng.gen_biguint(2048);
|
||||||
83655D23_DCA3AD96_1C62F356_208552BB_9ED52907_7096966D\
|
let e = rng.gen_biguint(2048);
|
||||||
670C354E_4ABC9804_F1746C08_CA18217C_32905E46_2E36CE3B\
|
// Make the modulus even, so monty (base-2^32) doesn't apply.
|
||||||
E39E772C_180E8603_9B2783A2_EC07A28F_B5C55DF0_6F4C52C9\
|
let m = BigUint::from_str_radix(RFC3526_2048BIT_MODP_GROUP, 16).unwrap() - 1u32;
|
||||||
DE2BCBF6_95581718_3995497C_EA956AE5_15D22618_98FA0510\
|
|
||||||
15728E5A_8AACAA68_FFFFFFFF_FFFFFFFF", 16).unwrap();
|
|
||||||
|
|
||||||
b.iter(|| base.modpow(&e, &m));
|
b.iter(|| base.modpow(&e, &m));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1625,7 +1625,34 @@ impl BigUint {
|
||||||
|
|
||||||
/// Returns `(self ^ exponent) % modulus`.
|
/// Returns `(self ^ exponent) % modulus`.
|
||||||
pub fn modpow(&self, exponent: &Self, modulus: &Self) -> Self {
|
pub fn modpow(&self, exponent: &Self, modulus: &Self) -> Self {
|
||||||
monty_modpow(self, exponent, modulus)
|
assert!(!modulus.is_zero(), "divide by zero!");
|
||||||
|
|
||||||
|
// For an odd modulus, we can use Montgomery multiplication in base 2^32.
|
||||||
|
if modulus.is_odd() {
|
||||||
|
return monty_modpow(self, exponent, modulus);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise do basically the same as `num::pow`, but with a modulus.
|
||||||
|
let one = BigUint::one();
|
||||||
|
if exponent.is_zero() { return one; }
|
||||||
|
|
||||||
|
let mut base = self % modulus;
|
||||||
|
let mut exp = exponent.clone();
|
||||||
|
while exp.is_even() {
|
||||||
|
base = &base * &base % modulus;
|
||||||
|
exp >>= 1;
|
||||||
|
}
|
||||||
|
if exp == one { return base }
|
||||||
|
|
||||||
|
let mut acc = base.clone();
|
||||||
|
while exp > one {
|
||||||
|
exp >>= 1;
|
||||||
|
base = &base * &base % modulus;
|
||||||
|
if exp.is_odd() {
|
||||||
|
acc = acc * &base % modulus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
acc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1098,6 +1098,11 @@ fn test_modpow() {
|
||||||
let big_r = BigUint::from(r);
|
let big_r = BigUint::from(r);
|
||||||
|
|
||||||
assert_eq!(big_b.modpow(&big_e, &big_m), big_r);
|
assert_eq!(big_b.modpow(&big_e, &big_m), big_r);
|
||||||
|
|
||||||
|
let even_m = &big_m << 1;
|
||||||
|
let even_modpow = big_b.modpow(&big_e, &even_m);
|
||||||
|
assert!(even_modpow < even_m);
|
||||||
|
assert_eq!(even_modpow % big_m, big_r);
|
||||||
}
|
}
|
||||||
|
|
||||||
check(1, 0, 11, 1);
|
check(1, 0, 11, 1);
|
||||||
|
@ -1160,6 +1165,11 @@ fn test_modpow_big() {
|
||||||
109c4735_6e7db425_7b5d74c7_0b709508", 16).unwrap();
|
109c4735_6e7db425_7b5d74c7_0b709508", 16).unwrap();
|
||||||
|
|
||||||
assert_eq!(b.modpow(&e, &m), r);
|
assert_eq!(b.modpow(&e, &m), r);
|
||||||
|
|
||||||
|
let even_m = &m << 1;
|
||||||
|
let even_modpow = b.modpow(&e, &even_m);
|
||||||
|
assert!(even_modpow < even_m);
|
||||||
|
assert_eq!(even_modpow % m, r);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_str_pairs() -> Vec<(BigUint, Vec<(u32, String)>)> {
|
fn to_str_pairs() -> Vec<(BigUint, Vec<(u32, String)>)> {
|
||||||
|
|
Loading…
Reference in New Issue