extern crate framp as ramp;
use std::cmp::Ordering;
use ramp::Int;
#[derive(Debug,Copy,Clone,PartialEq,Eq)]
struct GcdResult<T> {
gcd: T,
c1: T, c2: T,
}
fn extended_gcd(a: Int, b: Int) -> GcdResult<Int> {
let (mut s, mut old_s) = (Int::zero(), Int::one());
let (mut t, mut old_t) = (Int::one(), Int::zero());
let (mut r, mut old_r) = (b, a);
let mut tmp = Int::zero();
while r != 0 {
let quotient = &old_r / &r;
tmp.clone_from(&r); r = &old_r - "ient * r; old_r.clone_from(&tmp);
tmp.clone_from(&s); s = &old_s - "ient * s; old_s.clone_from(&tmp);
tmp.clone_from(&t); t = &old_t - "ient * t; old_t.clone_from(&tmp);
}
let _quotients = (t, s);
GcdResult { gcd: old_r, c1: old_s, c2: old_t }
}
fn normalize(a: Int, n: &Int) -> Int {
let a = a % n;
match a.cmp(&Int::zero()) {
Ordering::Less => a + n,
_ => a,
}
}
fn inverse(a: Int, n: &Int) -> Option<Int> {
let GcdResult { gcd, c1: c, c2: _ } = extended_gcd(a, n.clone());
if gcd == 1 {
Some(normalize(c, n))
} else {
None
}
}
fn mpow(mut base: Int, mut exp: u32, modulus: &Int) -> Int {
let mut result = Int::one();
base = base % modulus;
while exp > 0 {
if exp % 2 == 1 {
result = (result * &base) % modulus;
}
exp = exp >> 1;
base = (base.dsquare()) % modulus;
}
result
}
fn main() {
let (a, b) = (Int::from(6), Int::from(3));
let GcdResult { gcd, c1, c2 } = extended_gcd(a.clone(), b.clone());
println!("gcd({}, {}) = {}*{} + {}*{} = {}", &a, &b, &c1, &a, &c2, &b, &gcd);
println!("7**-1 (mod 10) = {}", inverse(Int::from(7), &Int::from(10)).unwrap());
println!("7**1000 (mod 13) = {}", mpow(Int::from(7), 1000, &Int::from(13)));
}