Skip to content

Commit

Permalink
Make mul_rem() primitive constant-time (#625)
Browse files Browse the repository at this point in the history
  • Loading branch information
fjarri authored Aug 2, 2024
1 parent 6370b08 commit c9b6124
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 12 deletions.
14 changes: 14 additions & 0 deletions src/non_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,20 @@ where
}

impl NonZero<Limb> {
/// Creates a new non-zero limb in a const context.
/// Panics if the value is zero.
///
/// In future versions of Rust it should be possible to replace this with
/// `NonZero::new(…).unwrap()`
// TODO: Remove when `Self::new` and `CtOption::unwrap` support `const fn`
pub const fn new_unwrap(n: Limb) -> Self {
if n.is_nonzero().is_true_vartime() {
Self(n)
} else {
panic!("Invalid value: zero")
}
}

/// Create a [`NonZero<Limb>`] from a [`NonZeroU8`] (const-friendly)
// TODO(tarcieri): replace with `const impl From<NonZeroU8>` when stable
pub const fn from_u8(n: NonZeroU8) -> Self {
Expand Down
6 changes: 0 additions & 6 deletions src/primitives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,3 @@ pub(crate) const fn mac(a: Word, b: Word, c: Word, carry: Word) -> (Word, Word)
let ret = a + (b * c) + carry;
(ret as Word, (ret >> Word::BITS) as Word)
}

/// Computes `(a * b) % d`.
#[inline(always)]
pub(crate) const fn mul_rem(a: Word, b: Word, d: Word) -> Word {
((a as WideWord * b as WideWord) % (d as WideWord)) as Word
}
10 changes: 7 additions & 3 deletions src/uint/boxed/mul_mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! [`BoxedUint`] modular multiplication operations.
use crate::{
div_limb::mul_rem,
modular::{BoxedMontyForm, BoxedMontyParams},
primitives::mul_rem,
BoxedUint, Limb, MulMod, Odd, WideWord, Word,
BoxedUint, Limb, MulMod, NonZero, Odd, WideWord, Word,
};

impl BoxedUint {
Expand Down Expand Up @@ -42,7 +42,11 @@ impl BoxedUint {
// We implicitly assume `LIMBS > 0`, because `Uint<0>` doesn't compile.
// Still the case `LIMBS == 1` needs special handling.
if self.nlimbs() == 1 {
let reduced = mul_rem(self.limbs[0].0, rhs.limbs[0].0, Word::MIN.wrapping_sub(c.0));
let reduced = mul_rem(
self.limbs[0],
rhs.limbs[0],
NonZero::<Limb>::new_unwrap(Limb(Word::MIN.wrapping_sub(c.0))),
);
return Self::from(reduced);
}

Expand Down
8 changes: 8 additions & 0 deletions src/uint/div_limb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@ pub(crate) const fn rem_limb_with_reciprocal_wide<const L: usize>(
Limb(r >> reciprocal.shift)
}

/// Computes `(a * b) % d`.
#[inline(always)]
pub(crate) const fn mul_rem(a: Limb, b: Limb, d: NonZero<Limb>) -> Limb {
let rec = Reciprocal::new(d);
let (hi, lo) = mulhilo(a.0, b.0);
rem_limb_with_reciprocal(&Uint::from_words([lo, hi]), &rec)
}

#[cfg(test)]
mod tests {
use super::{div2by1, Reciprocal};
Expand Down
10 changes: 7 additions & 3 deletions src/uint/mul_mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! [`Uint`] modular multiplication operations.
use crate::{
div_limb::mul_rem,
modular::{MontyForm, MontyParams},
primitives::mul_rem,
Concat, Limb, MulMod, NonZero, Split, Uint, WideWord, Word,
};

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

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

0 comments on commit c9b6124

Please sign in to comment.