pub(super) fn modpow(x: &BigUint, exponent: &BigUint, modulus: &BigUint) -> BigUint {
assert!(
!modulus.is_zero(), "attempt to calculate with zero modulus!"
);
if modulus.is_odd() { // For an odd modulus, we can use Montgomery multiplication in base 2^32.
monty_modpow(x, exponent, modulus)
} else { // Otherwise do basically the same as `num::pow`, but with a modulus.
plain_modpow(x, &exponent.data, modulus)
}
}
fn plain_modpow(base: &BigUint, exp_data: &[BigDigit], modulus: &BigUint) -> BigUint {
assert!(
!modulus.is_zero(), "attempt to calculate with zero modulus!"
);
let i = match exp_data.iter().position(|&r| r != 0) {
None => return BigUint::one(),
Some(i) => i,
};
letmut base = base % modulus;
for _ in 0..i {
for _ in 0..big_digit::BITS {
base = &base * &base % modulus;
}
}
letmut r = exp_data[i]; letmut b = 0u8; while r.is_even() {
base = &base * &base % modulus;
r >>= 1;
b += 1;
}
{ letmut unit = |exp_is_odd| {
base = &base * &base % modulus; if exp_is_odd {
acc *= &base;
acc %= modulus;
}
};
iflet Some(&last) = exp_iter.next_back() { // consume exp_data[i]
for _ in b..big_digit::BITS {
unit(r.is_odd());
r >>= 1;
}
// consume all other digits before the last
for &r in exp_iter { letmut r = r;
for _ in 0..big_digit::BITS {
unit(r.is_odd());
r >>= 1;
}
}
r = last;
}
debug_assert_ne!(r, 0); while !r.is_zero() {
unit(r.is_odd());
r >>= 1;
}
}
acc
}
#[test]
fn test_plain_modpow() { let two = &BigUint::from(2u32); let modulus = BigUint::from(0x1100u32);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.