|
1 | 1 | use integer::Integer;
|
2 |
| -use traits::Zero; |
| 2 | +use traits::{One, Zero}; |
3 | 3 |
|
4 | 4 | use biguint::BigUint;
|
| 5 | +use big_digit::BITS; |
5 | 6 |
|
6 | 7 | struct MontyReducer<'a> {
|
7 | 8 | n: &'a BigUint,
|
@@ -49,79 +50,96 @@ impl<'a> MontyReducer<'a> {
|
49 | 50 | let n0inv = inv_mod_u32(n.data[0]);
|
50 | 51 | MontyReducer { n: n, n0inv: n0inv }
|
51 | 52 | }
|
52 |
| -} |
53 | 53 |
|
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 |
78 | 58 | }
|
79 | 59 |
|
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()); |
83 | 89 |
|
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 | + } |
89 | 96 | }
|
90 |
| -} |
91 | 97 |
|
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 | + } |
96 | 129 |
|
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 | + } |
101 | 132 | }
|
102 | 133 |
|
103 | 134 | pub fn monty_modpow(a: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint{
|
104 | 135 | let mr = MontyReducer::new(modulus);
|
105 | 136 |
|
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 |
| - |
111 | 137 | // 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); |
124 | 142 |
|
125 | 143 | // Map the result back to the residues domain
|
126 |
| - monty_redc(ans, &mr) |
| 144 | + mr.redc(answer) |
127 | 145 | }
|
0 commit comments