|
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