Skip to content

Commit 6368fca

Browse files
committed
Implement modular exponentiation
1 parent b146d44 commit 6368fca

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

2323
extern crate num_traits as traits;
2424

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

@@ -735,6 +735,30 @@ pub fn inverse<T: Integer + NumRef + Clone>(a: T, n: &T) -> Option<T>
735735
}
736736
}
737737

738+
/// Calculate base^exp (mod modulus).
739+
pub fn powm<T>(base: &T, exp: &T, modulus: &T) -> T
740+
where T: Integer + NumRef + Clone + Neg<Output = T> + Shr<i32, Output = T>,
741+
for<'a> &'a T: RefNum<T>
742+
{
743+
let zero = T::zero();
744+
let one = T::one();
745+
let two = &one + &one;
746+
let mut exp = exp.clone();
747+
let mut result = one.clone();
748+
let mut base = base % modulus;
749+
if exp < zero {
750+
exp = -exp;
751+
base = inverse(base, modulus).unwrap();
752+
}
753+
while exp > zero {
754+
if &exp % &two == one {
755+
result = (result * &base) % modulus;
756+
}
757+
exp = exp >> 1;
758+
base = (&base * &base) % modulus;
759+
}
760+
result
761+
}
738762

739763
/// An iterator over binomial coefficients.
740764
pub struct IterBinomial<T> {
@@ -901,6 +925,12 @@ fn test_inverse() {
901925
assert_eq!(inverse(5, &7).unwrap(), 3);
902926
}
903927

928+
#[test]
929+
fn test_powm() {
930+
// `i64::pow` would overflow.
931+
assert_eq!(powm(&11, &19, &7), 4);
932+
}
933+
904934
#[test]
905935
fn test_iter_binomial() {
906936
macro_rules! check_simple {

0 commit comments

Comments
 (0)