Skip to content

Commit e49c050

Browse files
committed
Make mul_rem() primitive constant-time
1 parent e948539 commit e49c050

5 files changed

Lines changed: 36 additions & 12 deletions

File tree

src/non_zero.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,20 @@ where
8484
}
8585

8686
impl NonZero<Limb> {
87+
/// Creates a new non-zero limb in a const context.
88+
/// Panics if the value is zero.
89+
///
90+
/// In future versions of Rust it should be possible to replace this with
91+
/// `NonZero::new(…).unwrap()`
92+
// TODO: Remove when `Self::new` and `CtOption::unwrap` support `const fn`
93+
pub const fn new_unwrap(n: Limb) -> Self {
94+
if n.is_nonzero().is_true_vartime() {
95+
Self(n)
96+
} else {
97+
panic!("Invalid value: zero")
98+
}
99+
}
100+
87101
/// Create a [`NonZero<Limb>`] from a [`NonZeroU8`] (const-friendly)
88102
// TODO(tarcieri): replace with `const impl From<NonZeroU8>` when stable
89103
pub const fn from_u8(n: NonZeroU8) -> Self {

src/primitives.rs

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,3 @@ pub(crate) const fn mac(a: Word, b: Word, c: Word, carry: Word) -> (Word, Word)
6565
let ret = a + (b * c) + carry;
6666
(ret as Word, (ret >> Word::BITS) as Word)
6767
}
68-
69-
/// Computes `(a * b) % d`.
70-
#[inline(always)]
71-
pub(crate) const fn mul_rem(a: Word, b: Word, d: Word) -> Word {
72-
((a as WideWord * b as WideWord) % (d as WideWord)) as Word
73-
}

src/uint/boxed/mul_mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! [`BoxedUint`] modular multiplication operations.
22
33
use crate::{
4+
div_limb::mul_rem,
45
modular::{BoxedMontyForm, BoxedMontyParams},
5-
primitives::mul_rem,
6-
BoxedUint, Limb, MulMod, Odd, WideWord, Word,
6+
BoxedUint, Limb, MulMod, NonZero, Odd, WideWord, Word,
77
};
88

99
impl BoxedUint {
@@ -42,7 +42,11 @@ impl BoxedUint {
4242
// We implicitly assume `LIMBS > 0`, because `Uint<0>` doesn't compile.
4343
// Still the case `LIMBS == 1` needs special handling.
4444
if self.nlimbs() == 1 {
45-
let reduced = mul_rem(self.limbs[0].0, rhs.limbs[0].0, Word::MIN.wrapping_sub(c.0));
45+
let reduced = mul_rem(
46+
self.limbs[0],
47+
rhs.limbs[0],
48+
NonZero::<Limb>::new_unwrap(Limb(Word::MIN.wrapping_sub(c.0))),
49+
);
4650
return Self::from(reduced);
4751
}
4852

src/uint/div_limb.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,14 @@ pub(crate) const fn rem_limb_with_reciprocal_wide<const L: usize>(
280280
Limb(r >> reciprocal.shift)
281281
}
282282

283+
/// Computes `(a * b) % d`.
284+
#[inline(always)]
285+
pub(crate) const fn mul_rem(a: Limb, b: Limb, d: NonZero<Limb>) -> Limb {
286+
let rec = Reciprocal::new(d);
287+
let (hi, lo) = mulhilo(a.0, b.0);
288+
rem_limb_with_reciprocal(&Uint::from_words([lo, hi]), &rec)
289+
}
290+
283291
#[cfg(test)]
284292
mod tests {
285293
use super::{div2by1, Reciprocal};

src/uint/mul_mod.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
//! [`Uint`] modular multiplication operations.
22
33
use crate::{
4+
div_limb::mul_rem,
45
modular::{MontyForm, MontyParams},
5-
primitives::mul_rem,
66
Concat, Limb, MulMod, NonZero, Split, Uint, WideWord, Word,
77
};
88

@@ -53,8 +53,12 @@ impl<const LIMBS: usize> Uint<LIMBS> {
5353
// We implicitly assume `LIMBS > 0`, because `Uint<0>` doesn't compile.
5454
// Still the case `LIMBS == 1` needs special handling.
5555
if LIMBS == 1 {
56-
let reduced = mul_rem(self.limbs[0].0, rhs.limbs[0].0, Word::MIN.wrapping_sub(c.0));
57-
return Self::from_word(reduced);
56+
let reduced = mul_rem(
57+
self.limbs[0],
58+
rhs.limbs[0],
59+
NonZero::<Limb>::new_unwrap(Limb(Word::MIN.wrapping_sub(c.0))),
60+
);
61+
return Self::from_word(reduced.0);
5862
}
5963

6064
let (lo, hi) = self.split_mul(rhs);

0 commit comments

Comments
 (0)