Skip to content

Commit ff7f3a5

Browse files
authored
Split Uint::mul_mod and Uint::mul_mod_vartime (#623)
The previous `mul_mod` was variable-time with respect to the modulus. This adds a proper constant-time version. It also changes the `p` argument to be `NonZero<Self>`.
1 parent 1a38df0 commit ff7f3a5

File tree

3 files changed

+30
-14
lines changed

3 files changed

+30
-14
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/uint/mul_mod.rs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,28 +3,44 @@
33
use crate::{
44
modular::{MontyForm, MontyParams},
55
primitives::mul_rem,
6-
Limb, MulMod, Uint, WideWord, Word,
6+
Concat, Limb, MulMod, NonZero, Split, Uint, WideWord, Word,
77
};
88

99
impl<const LIMBS: usize> Uint<LIMBS> {
1010
/// Computes `self * rhs mod p` for odd `p`.
1111
///
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+
{
1522
// NOTE: the overhead of converting to Montgomery form to perform this operation and then
1623
// immediately converting out of Montgomery form after just a single operation is likely to
1724
// be higher than other possible implementations of this function, such as using a
1825
// Barrett reduction instead.
1926
//
2027
// 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()
2844
}
2945

3046
/// Computes `self * rhs mod p` for the special modulus
@@ -64,7 +80,7 @@ impl<const LIMBS: usize> MulMod for Uint<LIMBS> {
6480
type Output = Self;
6581

6682
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"))
6884
}
6985
}
7086

tests/uint.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ proptest! {
188188
let p_bi = to_biguint(&P);
189189

190190
let expected = to_uint((a_bi * b_bi) % p_bi);
191-
let actual = a.mul_mod(&b, &P);
191+
let actual = a.mul_mod_vartime(&b, P.as_nz_ref());
192192

193193
assert!(expected < P);
194194
assert!(actual < P);

0 commit comments

Comments
 (0)