1use integer::Integer;
2use traits::Zero;
3
4use biguint::BigUint;
5
6struct MontyReducer<'a> {
7 n: &'a BigUint,
8 n0inv: u32,
9}
10
11fn inv_mod_u32(num: u32) -> u32 {
16 assert!(num % 2 != 0);
18
19 let mut a: i64 = i64::from(num);
20 let mut b: i64 = i64::from(u32::max_value()) + 1;
21
22 let mut u = 1;
29 let mut w = 0;
30 while b != 0 {
32 let q = a / b;
34 let r = a % b;
35 a = b;
37 b = r;
38 let m = u - w * q;
40 u = w;
41 w = m;
42 }
43
44 assert!(a == 1);
45 u as u32
47}
48
49impl<'a> MontyReducer<'a> {
50 fn new(n: &'a BigUint) -> Self {
51 let n0inv = inv_mod_u32(n.data[0]);
52 MontyReducer { n: n, n0inv: n0inv }
53 }
54}
55
56fn monty_redc(a: BigUint, mr: &MontyReducer) -> BigUint {
61 let mut c = a.data;
62 let n = &mr.n.data;
63 let n_size = n.len();
64
65 c.resize(2 * n_size + 2, 0);
67
68 let mu = 0u32.wrapping_sub(mr.n0inv);
72
73 for i in 0..n_size {
75 let q_i = c[i].wrapping_mul(mu);
77
78 super::algorithms::mac_digit(&mut c[i..], n, q_i);
80 }
81
82 let ret = BigUint::new(c[n_size..].to_vec());
85
86 if ret < *mr.n {
88 ret
89 } else {
90 ret - mr.n
91 }
92}
93
94fn monty_mult(a: BigUint, b: &BigUint, mr: &MontyReducer) -> BigUint {
96 monty_redc(a * b, mr)
97}
98
99fn monty_sqr(a: BigUint, mr: &MontyReducer) -> BigUint {
101 monty_redc(&a * &a, mr)
103}
104
105pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint {
106 let mr = MontyReducer::new(modulus);
107
108 let mut v = vec![0; modulus.data.len()];
110 v.push(1);
111 let r = BigUint::new(v);
112
113 let mut apri = a * &r % modulus;
115
116 let mut ans = &r % modulus;
118 let mut e = exp.clone();
119 while !e.is_zero() {
120 if e.is_odd() {
121 ans = monty_mult(ans, &apri, &mr);
122 }
123 apri = monty_sqr(apri, &mr);
124 e >>= 1;
125 }
126
127 monty_redc(ans, &mr)
129}