Skip to content

Commit bba7294

Browse files
committed
Implement modular exponentiation
1 parent 7a35f3d commit bba7294

File tree

1 file changed

+31
-1
lines changed

1 file changed

+31
-1
lines changed

src/lib.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ extern crate std;
2222
extern crate num_traits as traits;
2323

2424
use core::mem;
25-
use core::ops::Add;
25+
use core::ops::{Add, Neg, Shr};
2626
use core::cmp::Ordering;
2727

2828
use traits::{Num, NumRef, RefNum, Signed, Zero};
@@ -1064,6 +1064,30 @@ pub fn inverse<T: Integer + NumRef + Clone>(a: T, n: &T) -> Option<T>
10641064
}
10651065
}
10661066

1067+
/// Calculate base^exp (mod modulus).
1068+
pub fn powm<T>(base: &T, exp: &T, modulus: &T) -> T
1069+
where T: Integer + NumRef + Clone + Neg<Output = T> + Shr<i32, Output = T>,
1070+
for<'a> &'a T: RefNum<T>
1071+
{
1072+
let zero = T::zero();
1073+
let one = T::one();
1074+
let two = &one + &one;
1075+
let mut exp = exp.clone();
1076+
let mut result = one.clone();
1077+
let mut base = base % modulus;
1078+
if exp < zero {
1079+
exp = -exp;
1080+
base = inverse(base, modulus).unwrap();
1081+
}
1082+
while exp > zero {
1083+
if &exp % &two == one {
1084+
result = (result * &base) % modulus;
1085+
}
1086+
exp = exp >> 1;
1087+
base = (&base * &base) % modulus;
1088+
}
1089+
result
1090+
}
10671091

10681092
/// An iterator over binomial coefficients.
10691093
pub struct IterBinomial<T> {
@@ -1239,6 +1263,12 @@ fn test_inverse() {
12391263
assert_eq!(inverse(5, &7).unwrap(), 3);
12401264
}
12411265

1266+
#[test]
1267+
fn test_powm() {
1268+
// `i64::pow` would overflow.
1269+
assert_eq!(powm(&11, &19, &7), 4);
1270+
}
1271+
12421272
#[test]
12431273
fn test_iter_binomial() {
12441274
macro_rules! check_simple {

0 commit comments

Comments
 (0)