diff --git a/src/non_zero.rs b/src/non_zero.rs index fe91b1ee7..7ffd06bb2 100644 --- a/src/non_zero.rs +++ b/src/non_zero.rs @@ -84,6 +84,20 @@ where } impl NonZero { + /// 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`] from a [`NonZeroU8`] (const-friendly) // TODO(tarcieri): replace with `const impl From` when stable pub const fn from_u8(n: NonZeroU8) -> Self { diff --git a/src/primitives.rs b/src/primitives.rs index 5d79a5f6c..3a0ae58e3 100644 --- a/src/primitives.rs +++ b/src/primitives.rs @@ -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 -} diff --git a/src/uint/boxed/mul_mod.rs b/src/uint/boxed/mul_mod.rs index 8c6b7ee15..340bf76ff 100644 --- a/src/uint/boxed/mul_mod.rs +++ b/src/uint/boxed/mul_mod.rs @@ -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 { @@ -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::::new_unwrap(Limb(Word::MIN.wrapping_sub(c.0))), + ); return Self::from(reduced); } diff --git a/src/uint/div_limb.rs b/src/uint/div_limb.rs index 28f876517..4f50032cc 100644 --- a/src/uint/div_limb.rs +++ b/src/uint/div_limb.rs @@ -280,6 +280,14 @@ pub(crate) const fn rem_limb_with_reciprocal_wide( Limb(r >> reciprocal.shift) } +/// Computes `(a * b) % d`. +#[inline(always)] +pub(crate) const fn mul_rem(a: Limb, b: Limb, d: NonZero) -> 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}; diff --git a/src/uint/mul_mod.rs b/src/uint/mul_mod.rs index 103ef8d87..97dc1ee33 100644 --- a/src/uint/mul_mod.rs +++ b/src/uint/mul_mod.rs @@ -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, }; @@ -53,8 +53,12 @@ impl Uint { // 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::::new_unwrap(Limb(Word::MIN.wrapping_sub(c.0))), + ); + return Self::from_word(reduced.0); } let (lo, hi) = self.split_mul(rhs);