|
3 | 3 | use crate::{ |
4 | 4 | modular::{MontyForm, MontyParams}, |
5 | 5 | primitives::mul_rem, |
6 | | - Limb, MulMod, Uint, WideWord, Word, |
| 6 | + Concat, Limb, MulMod, NonZero, Split, Uint, WideWord, Word, |
7 | 7 | }; |
8 | 8 |
|
9 | 9 | impl<const LIMBS: usize> Uint<LIMBS> { |
10 | 10 | /// Computes `self * rhs mod p` for odd `p`. |
11 | 11 | /// |
12 | | - /// Panics if `p` is even. |
13 | | - // TODO(tarcieri): support for even `p`? |
14 | | - pub fn mul_mod(&self, rhs: &Uint<LIMBS>, p: &Uint<LIMBS>) -> Uint<LIMBS> { |
| 12 | + /// Panics if `p` is even. (TODO: support even `p`) |
| 13 | + pub fn mul_mod<const WIDE_LIMBS: usize>( |
| 14 | + &self, |
| 15 | + rhs: &Uint<LIMBS>, |
| 16 | + p: &NonZero<Uint<LIMBS>>, |
| 17 | + ) -> Uint<LIMBS> |
| 18 | + where |
| 19 | + Uint<LIMBS>: Concat<Output = Uint<WIDE_LIMBS>>, |
| 20 | + Uint<WIDE_LIMBS>: Split<Output = Uint<LIMBS>>, |
| 21 | + { |
15 | 22 | // NOTE: the overhead of converting to Montgomery form to perform this operation and then |
16 | 23 | // immediately converting out of Montgomery form after just a single operation is likely to |
17 | 24 | // be higher than other possible implementations of this function, such as using a |
18 | 25 | // Barrett reduction instead. |
19 | 26 | // |
20 | 27 | // It's worth potentially exploring other approaches to improve efficiency. |
21 | | - match p.to_odd().into() { |
22 | | - Some(odd_p) => { |
23 | | - let params = MontyParams::new_vartime(odd_p); |
24 | | - (MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve() |
25 | | - } |
26 | | - None => todo!("even moduli are currently unsupported"), |
27 | | - } |
| 28 | + let params = MontyParams::new(p.to_odd().expect("p should be odd")); |
| 29 | + (MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve() |
| 30 | + } |
| 31 | + |
| 32 | + /// Computes `self * rhs mod p` for odd `p` in variable time with respect to `p`. |
| 33 | + /// |
| 34 | + /// Panics if `p` is even. (TODO: support even `p`) |
| 35 | + pub fn mul_mod_vartime(&self, rhs: &Uint<LIMBS>, p: &NonZero<Uint<LIMBS>>) -> Uint<LIMBS> { |
| 36 | + // NOTE: the overhead of converting to Montgomery form to perform this operation and then |
| 37 | + // immediately converting out of Montgomery form after just a single operation is likely to |
| 38 | + // be higher than other possible implementations of this function, such as using a |
| 39 | + // Barrett reduction instead. |
| 40 | + // |
| 41 | + // It's worth potentially exploring other approaches to improve efficiency. |
| 42 | + let params = MontyParams::new_vartime(p.to_odd().expect("p should be odd")); |
| 43 | + (MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve() |
28 | 44 | } |
29 | 45 |
|
30 | 46 | /// Computes `self * rhs mod p` for the special modulus |
@@ -64,7 +80,7 @@ impl<const LIMBS: usize> MulMod for Uint<LIMBS> { |
64 | 80 | type Output = Self; |
65 | 81 |
|
66 | 82 | fn mul_mod(&self, rhs: &Self, p: &Self) -> Self { |
67 | | - self.mul_mod(rhs, p) |
| 83 | + self.mul_mod_vartime(rhs, &NonZero::new(*p).expect("p should be non-zero")) |
68 | 84 | } |
69 | 85 | } |
70 | 86 |
|
|
0 commit comments