Skip to content

Commit 7b4e975

Browse files
committed
refactor monty_modpow
1 parent 1836b8d commit 7b4e975

File tree

2 files changed

+84
-66
lines changed

2 files changed

+84
-66
lines changed

src/biguint.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,26 +1653,26 @@ impl BigUint {
16531653
/// Panics if the modulus is zero.
16541654
pub fn modpow(&self, exponent: &Self, modulus: &Self) -> Self {
16551655
assert!(!modulus.is_zero(), "divide by zero!");
1656+
if modulus.is_one() { return BigUint::zero(); }
1657+
if exponent.is_zero() { return BigUint::one(); }
1658+
if self.is_zero() || self.is_one() { return self.clone(); }
16561659

16571660
// For an odd modulus, we can use Montgomery multiplication in base 2^32.
16581661
if modulus.is_odd() {
16591662
return monty_modpow(self, exponent, modulus);
16601663
}
16611664

16621665
// Otherwise do basically the same as `num::pow`, but with a modulus.
1663-
let one = BigUint::one();
1664-
if exponent.is_zero() { return one; }
1665-
16661666
let mut base = self % modulus;
16671667
let mut exp = exponent.clone();
16681668
while exp.is_even() {
16691669
base = &base * &base % modulus;
16701670
exp >>= 1;
16711671
}
1672-
if exp == one { return base }
1672+
if exp.is_one() { return base }
16731673

16741674
let mut acc = base.clone();
1675-
while exp > one {
1675+
while !exp.is_one() {
16761676
exp >>= 1;
16771677
base = &base * &base % modulus;
16781678
if exp.is_odd() {

src/monty.rs

Lines changed: 79 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
use integer::Integer;
2-
use traits::Zero;
2+
use traits::{One, Zero};
33

44
use biguint::BigUint;
5+
use big_digit::BITS;
56

67
struct MontyReducer<'a> {
78
n: &'a BigUint,
@@ -49,79 +50,96 @@ impl<'a> MontyReducer<'a> {
4950
let n0inv = inv_mod_u32(n.data[0]);
5051
MontyReducer { n: n, n0inv: n0inv }
5152
}
52-
}
5353

54-
// Montgomery Reduction
55-
//
56-
// Reference:
57-
// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 2.6
58-
fn monty_redc(a: BigUint, mr: &MontyReducer) -> BigUint {
59-
let mut c = a.data;
60-
let n = &mr.n.data;
61-
let n_size = n.len();
62-
63-
// Allocate sufficient work space
64-
c.resize(2 * n_size + 2, 0);
65-
66-
// β is the size of a word, in this case 32 bits. So "a mod β" is
67-
// equivalent to masking a to 32 bits.
68-
// mu <- -N^(-1) mod β
69-
let mu = 0u32.wrapping_sub(mr.n0inv);
70-
71-
// 1: for i = 0 to (n-1)
72-
for i in 0..n_size {
73-
// 2: q_i <- mu*c_i mod β
74-
let q_i = c[i].wrapping_mul(mu);
75-
76-
// 3: C <- C + q_i * N * β^i
77-
super::algorithms::mac_digit(&mut c[i..], n, q_i);
54+
/// Map a number to the Montgomery domain
55+
fn map(&self, x: &BigUint) -> BigUint {
56+
let shift = self.n.data.len() * BITS;
57+
(x << shift) % self.n
7858
}
7959

80-
// 4: R <- C * β^(-n)
81-
// This is an n-word bitshift, equivalent to skipping n words.
82-
let ret = BigUint::new(c[n_size..].to_vec());
60+
/// Montgomery Reduction
61+
///
62+
/// Reference:
63+
/// Brent & Zimmermann, Modern Computer Arithmetic, v0.5.9, Algorithm 2.6
64+
fn redc(&self, a: BigUint) -> BigUint {
65+
let mut c = a.data;
66+
let n = &self.n.data;
67+
let n_size = n.len();
68+
69+
// Allocate sufficient work space
70+
c.resize(2 * n_size + 2, 0);
71+
72+
// β is the size of a word, in this case 32 bits. So "a mod β" is
73+
// equivalent to masking a to 32 bits.
74+
// mu <- -N^(-1) mod β
75+
let mu = 0u32.wrapping_sub(self.n0inv);
76+
77+
// 1: for i = 0 to (n-1)
78+
for i in 0..n_size {
79+
// 2: q_i <- mu*c_i mod β
80+
let q_i = c[i].wrapping_mul(mu);
81+
82+
// 3: C <- C + q_i * N * β^i
83+
super::algorithms::mac_digit(&mut c[i..], n, q_i);
84+
}
85+
86+
// 4: R <- C * β^(-n)
87+
// This is an n-word bitshift, equivalent to skipping n words.
88+
let ret = BigUint::new(c[n_size..].to_vec());
8389

84-
// 5: if R >= β^n then return R-N else return R.
85-
if &ret < mr.n {
86-
ret
87-
} else {
88-
ret - mr.n
90+
// 5: if R >= β^n then return R-N else return R.
91+
if &ret < self.n {
92+
ret
93+
} else {
94+
ret - self.n
95+
}
8996
}
90-
}
9197

92-
// Montgomery Multiplication
93-
fn monty_mult(a: BigUint, b: &BigUint, mr: &MontyReducer) -> BigUint {
94-
monty_redc(a * b, mr)
95-
}
98+
/// Montgomery Multiplication
99+
fn mul(&self, a: BigUint, b: &BigUint) -> BigUint {
100+
self.redc(a * b)
101+
}
102+
103+
/// Montgomery Squaring
104+
fn square(&self, a: BigUint) -> BigUint {
105+
// TODO: Replace with an optimised squaring function
106+
self.redc(&a * &a)
107+
}
108+
109+
/// Montgomery Exponentiation
110+
fn pow(&self, mut base: BigUint, exp: &BigUint) -> BigUint {
111+
debug_assert!(!exp.is_zero());
112+
113+
// Binary exponentiation
114+
let mut exp = exp.clone();
115+
while exp.is_even() {
116+
base = self.square(base);
117+
exp >>= 1;
118+
}
119+
if exp.is_one() { return base; }
120+
121+
let mut acc = base.clone();
122+
while !exp.is_one() {
123+
exp >>= 1;
124+
base = self.square(base);
125+
if exp.is_odd() {
126+
acc = self.mul(acc, &base);
127+
}
128+
}
96129

97-
// Montgomery Squaring
98-
fn monty_sqr(a: BigUint, mr: &MontyReducer) -> BigUint {
99-
// TODO: Replace with an optimised squaring function
100-
monty_redc(&a * &a, mr)
130+
acc
131+
}
101132
}
102133

103134
pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint{
104135
let mr = MontyReducer::new(modulus);
105136

106-
// Calculate the Montgomery parameter
107-
let mut v = vec![0; modulus.data.len()];
108-
v.push(1);
109-
let r = BigUint::new(v);
110-
111137
// Map the base to the Montgomery domain
112-
let mut apri = a * &r % modulus;
113-
114-
// Binary exponentiation
115-
let mut ans = &r % modulus;
116-
let mut e = exp.clone();
117-
while !e.is_zero() {
118-
if e.is_odd() {
119-
ans = monty_mult(ans, &apri, &mr);
120-
}
121-
apri = monty_sqr(apri, &mr);
122-
e = e >> 1;
123-
}
138+
let base = mr.map(a);
139+
140+
// Do the computation
141+
let answer = mr.pow(base, exp);
124142

125143
// Map the result back to the residues domain
126-
monty_redc(ans, &mr)
144+
mr.redc(answer)
127145
}

0 commit comments

Comments
 (0)