diff --git a/Cargo.lock b/Cargo.lock index 7b3f99f14..31171356a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -210,7 +210,7 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" -version = "0.6.0-rc.1" +version = "0.6.0-rc.2" dependencies = [ "bincode", "criterion", diff --git a/src/uint/mul_mod.rs b/src/uint/mul_mod.rs index b1a130f70..103ef8d87 100644 --- a/src/uint/mul_mod.rs +++ b/src/uint/mul_mod.rs @@ -3,28 +3,44 @@ use crate::{ modular::{MontyForm, MontyParams}, primitives::mul_rem, - Limb, MulMod, Uint, WideWord, Word, + Concat, Limb, MulMod, NonZero, Split, Uint, WideWord, Word, }; impl Uint { /// 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, p: &Uint) -> Uint { + /// Panics if `p` is even. (TODO: support even `p`) + pub fn mul_mod( + &self, + rhs: &Uint, + p: &NonZero>, + ) -> Uint + where + Uint: Concat>, + Uint: Split>, + { // 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.to_odd().expect("p should be odd")); + (MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve() + } + + /// Computes `self * rhs mod p` for odd `p` in variable time with respect to `p`. + /// + /// Panics if `p` is even. (TODO: support even `p`) + pub fn mul_mod_vartime(&self, rhs: &Uint, p: &NonZero>) -> Uint { + // 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.to_odd().expect("p should be odd")); + (MontyForm::new(self, params) * MontyForm::new(rhs, params)).retrieve() } /// Computes `self * rhs mod p` for the special modulus @@ -64,7 +80,7 @@ impl MulMod for Uint { type Output = Self; fn mul_mod(&self, rhs: &Self, p: &Self) -> Self { - self.mul_mod(rhs, p) + self.mul_mod_vartime(rhs, &NonZero::new(*p).expect("p should be non-zero")) } } diff --git a/tests/uint.rs b/tests/uint.rs index db8045e2c..341e7fdef 100644 --- a/tests/uint.rs +++ b/tests/uint.rs @@ -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.as_nz_ref()); assert!(expected < P); assert!(actual < P);