Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 25 additions & 13 deletions src/uint/mul_mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,40 @@
use crate::{
modular::{MontyForm, MontyParams},
primitives::mul_rem,
Limb, MulMod, Uint, WideWord, Word,
Concat, Limb, MulMod, Odd, Split, Uint, WideWord, Word,
};

impl<const LIMBS: usize> Uint<LIMBS> {
/// Computes `self * rhs mod p` for odd `p`.
///
/// Panics if `p` is even.
// TODO(tarcieri): support for even `p`?
pub fn mul_mod(&self, rhs: &Uint<LIMBS>, p: &Uint<LIMBS>) -> Uint<LIMBS> {
pub fn mul_mod<const WIDE_LIMBS: usize>(
&self,
rhs: &Uint<LIMBS>,
p: &Odd<Uint<LIMBS>>,
) -> Uint<LIMBS>
where
Uint<LIMBS>: Concat<Output = Uint<WIDE_LIMBS>>,
Uint<WIDE_LIMBS>: Split<Output = Uint<LIMBS>>,
{
// NOTE: the overhead of converting to Montgomery form to perform this operation and then
// immediately converting out of Montgomery form after just a single operation is likely to
// be higher than other possible implementations of this function, such as using a
// Barrett reduction instead.
//
// It's worth potentially exploring other approaches to improve efficiency.
match p.to_odd().into() {
Some(odd_p) => {
let params = MontyParams::new_vartime(odd_p);
(MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve()
}
None => todo!("even moduli are currently unsupported"),
}
let params = MontyParams::new(*p);
(MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve()
}

/// Computes `self * rhs mod p` for odd `p` in variable time with respect to `p`,
pub fn mul_mod_vartime(&self, rhs: &Uint<LIMBS>, p: &Odd<Uint<LIMBS>>) -> Uint<LIMBS> {
// NOTE: the overhead of converting to Montgomery form to perform this operation and then
// immediately converting out of Montgomery form after just a single operation is likely to
// be higher than other possible implementations of this function, such as using a
// Barrett reduction instead.
//
// It's worth potentially exploring other approaches to improve efficiency.
let params = MontyParams::new_vartime(*p);
(MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve()
}

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

fn mul_mod(&self, rhs: &Self, p: &Self) -> Self {
self.mul_mod(rhs, p)
self.mul_mod_vartime(rhs, &p.to_odd().expect("only odd moduli supported"))
}
}

Expand Down
2 changes: 1 addition & 1 deletion tests/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ proptest! {
let p_bi = to_biguint(&P);

let expected = to_uint((a_bi * b_bi) % p_bi);
let actual = a.mul_mod(&b, &P);
let actual = a.mul_mod_vartime(&b, &P);

assert!(expected < P);
assert!(actual < P);
Expand Down