use crate::ModularOps;
use num_integer::Integer;
use std::borrow::Borrow;
use std::rc::Rc;
pub trait Montgomery: ModularOps + Sized {
type Inv;
fn inv(m: &Self) -> Self::Inv;
fn transform(target: Self, m: &Self, minv: &Self::Inv) -> Self;
fn reduce(monty: Self, m: &Self, minv: &Self::Inv) -> Self;
fn mul(lhs: Self, rhs: Self, m: &Self, minv: &Self::Inv) -> Self;
fn pow(base: Self, exp: Self, m: &Self, minv: &Self::Inv) -> Self;
}
pub struct MontgomeryInt<T: Integer + Montgomery> {
a: T,
m: Option<Rc<T>>,
minv: Option<T::Inv>,
}
impl<T: Integer + Montgomery> MontgomeryInt<T> {
pub fn modulus(&self) -> Option<&T> {
self.m.as_ref().map(Borrow::borrow)
}
pub fn reduce(self) -> T {
match self.m {
Some(rc) => {
let inv = match self.minv {
Some(v) => v,
None => <T as Montgomery>::inv(rc.borrow()),
};
Montgomery::reduce(self.a, rc.borrow(), &inv)
}
None => self.a,
}
}
}