diff --git a/Cargo.lock b/Cargo.lock index 29acab7e..023b1f4d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -77,12 +77,6 @@ version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" -[[package]] -name = "byteorder" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" - [[package]] name = "bytes" version = "1.5.0" @@ -231,8 +225,9 @@ dependencies = [ "der", "generic-array", "hex-literal", - "num-bigint-dig", + "num-bigint", "num-integer", + "num-modular", "num-traits", "proptest", "rand_chacha", @@ -356,9 +351,6 @@ name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] [[package]] name = "libc" @@ -400,20 +392,14 @@ dependencies = [ ] [[package]] -name = "num-bigint-dig" -version = "0.8.4" +name = "num-bigint" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" dependencies = [ - "byteorder", - "lazy_static", - "libm", + "autocfg", "num-integer", - "num-iter", "num-traits", - "rand", - "serde", - "smallvec", ] [[package]] @@ -427,12 +413,12 @@ dependencies = [ ] [[package]] -name = "num-iter" -version = "0.1.43" +name = "num-modular" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "64a5fe11d4135c3bcdf3a95b18b194afa9608a5f6ff034f5d857bc9a27fb0119" dependencies = [ - "autocfg", + "num-bigint", "num-integer", "num-traits", ] @@ -737,18 +723,6 @@ dependencies = [ "serde", ] -[[package]] -name = "smallvec" -version = "1.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - [[package]] name = "subtle" version = "2.5.0" diff --git a/Cargo.toml b/Cargo.toml index 79e980d1..a8ba1221 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,8 +32,9 @@ zeroize = { version = "1", optional = true, default-features = false } bincode = "1" criterion = { version = "0.5", features = ["html_reports"] } hex-literal = "0.4" -num-bigint = { package = "num-bigint-dig", version = "0.8" } +num-bigint = "0.4" num-integer = "0.1" +num-modular = { version = "0.5", features = ["num-bigint"] } proptest = "1" rand_core = { version = "0.6", features = ["std"] } rand_chacha = "0.3" diff --git a/src/traits.rs b/src/traits.rs index 80c88384..2888ee67 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -8,7 +8,7 @@ pub use num_traits::{ pub(crate) use sealed::PrecomputeInverterWithAdjuster; -use crate::{Limb, NonZero, Odd}; +use crate::{Limb, NonZero, Odd, Reciprocal}; use core::fmt::Debug; use core::ops::{ Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div, DivAssign, @@ -110,11 +110,13 @@ pub trait Integer: + for<'a> Div<&'a NonZero, Output = Self> + DivAssign> + for<'a> DivAssign<&'a NonZero> + + DivRemLimb + Eq + From + From + From + From + + From + Mul + for<'a> Mul<&'a Self, Output = Self> + MulMod @@ -123,6 +125,7 @@ pub trait Integer: + Ord + Rem, Output = Self> + for<'a> Rem<&'a NonZero, Output = Self> + + RemLimb + Send + Sized + Shl @@ -452,6 +455,29 @@ pub trait SquareAssign { fn square_assign(&mut self); } +/// Support for optimized division by a single limb. +pub trait DivRemLimb: Sized { + /// Computes `self / rhs` using a pre-made reciprocal, + /// returns the quotient (q) and remainder (r). + fn div_rem_limb(&self, rhs: NonZero) -> (Self, Limb) { + self.div_rem_limb_with_reciprocal(&Reciprocal::new(rhs)) + } + + /// Computes `self / rhs`, returns the quotient (q) and remainder (r). + fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb); +} + +/// Support for optimized division by a single limb. +pub trait RemLimb: Sized { + /// Computes `self % rhs` using a pre-made reciprocal. + fn rem_limb(&self, rhs: NonZero) -> Limb { + self.rem_limb_with_reciprocal(&Reciprocal::new(rhs)) + } + + /// Computes `self % rhs`. + fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb; +} + /// Constant-time exponentiation. pub trait Pow { /// Raises to the `exponent` power. @@ -561,7 +587,7 @@ pub trait Monty: type Integer: Integer; /// The precomputed data needed for this representation. - type Params: Clone; + type Params: 'static + Clone + Debug + Eq + Sized + Send + Sync; /// Create the precomputed data for Montgomery representation of integers modulo `modulus`. fn new_params(modulus: Odd) -> Self::Params; diff --git a/src/uint/boxed/div.rs b/src/uint/boxed/div.rs index d230fc1d..97f002ae 100644 --- a/src/uint/boxed/div.rs +++ b/src/uint/boxed/div.rs @@ -1,23 +1,36 @@ //! [`BoxedUint`] division operations. use crate::{ - uint::boxed, BoxedUint, CheckedDiv, ConstantTimeSelect, Limb, NonZero, Reciprocal, Wrapping, + uint::boxed, BoxedUint, CheckedDiv, ConstantTimeSelect, DivRemLimb, Limb, NonZero, Reciprocal, + RemLimb, Wrapping, }; use core::ops::{Div, DivAssign, Rem, RemAssign}; use subtle::{Choice, ConstantTimeEq, ConstantTimeLess, CtOption}; impl BoxedUint { - /// Computes `self` / `rhs` using a pre-made reciprocal, + /// Computes `self / rhs` using a pre-made reciprocal, /// returns the quotient (q) and remainder (r). pub fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) { boxed::div_limb::div_rem_limb_with_reciprocal(self, reciprocal) } - /// Computes `self` / `rhs`, returns the quotient (q) and remainder (r). + /// Computes `self / rhs`, returns the quotient (q) and remainder (r). pub fn div_rem_limb(&self, rhs: NonZero) -> (Self, Limb) { boxed::div_limb::div_rem_limb_with_reciprocal(self, &Reciprocal::new(rhs)) } + /// Computes `self % rhs` using a pre-made reciprocal. + #[inline(always)] + pub fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb { + boxed::div_limb::rem_limb_with_reciprocal(self, reciprocal) + } + + /// Computes `self % rhs`. + #[inline(always)] + pub fn rem_limb(&self, rhs: NonZero) -> Limb { + boxed::div_limb::rem_limb_with_reciprocal(self, &Reciprocal::new(rhs)) + } + /// Computes self / rhs, returns the quotient, remainder. pub fn div_rem(&self, rhs: &NonZero) -> (Self, Self) { // Since `rhs` is nonzero, this should always hold. @@ -295,6 +308,18 @@ impl RemAssign> for BoxedUint { } } +impl DivRemLimb for BoxedUint { + fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) { + Self::div_rem_limb_with_reciprocal(self, reciprocal) + } +} + +impl RemLimb for BoxedUint { + fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb { + Self::rem_limb_with_reciprocal(self, reciprocal) + } +} + #[cfg(test)] mod tests { use super::{BoxedUint, NonZero}; diff --git a/src/uint/boxed/div_limb.rs b/src/uint/boxed/div_limb.rs index 4e4c7eeb..662a273f 100644 --- a/src/uint/boxed/div_limb.rs +++ b/src/uint/boxed/div_limb.rs @@ -23,3 +23,18 @@ pub(crate) fn div_rem_limb_with_reciprocal( } (BoxedUint { limbs: q.into() }, Limb(r >> reciprocal.shift())) } + +/// Divides `u` by the divisor encoded in the `reciprocal`, and returns the remainder. +#[inline(always)] +pub(crate) fn rem_limb_with_reciprocal(u: &BoxedUint, reciprocal: &Reciprocal) -> Limb { + let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift()); + let mut r = u_hi.0; + + let mut j = u.limbs.len(); + while j > 0 { + j -= 1; + let (_, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal); + r = rj; + } + Limb(r >> reciprocal.shift()) +} diff --git a/src/uint/div.rs b/src/uint/div.rs index d650235d..4ee6c63b 100644 --- a/src/uint/div.rs +++ b/src/uint/div.rs @@ -1,24 +1,36 @@ //! [`Uint`] division operations. -use super::div_limb::{div_rem_limb_with_reciprocal, Reciprocal}; -use crate::{CheckedDiv, ConstChoice, Limb, NonZero, Uint, Word, Wrapping}; +use super::div_limb::{div_rem_limb_with_reciprocal, rem_limb_with_reciprocal, Reciprocal}; +use crate::{CheckedDiv, ConstChoice, DivRemLimb, Limb, NonZero, RemLimb, Uint, Word, Wrapping}; use core::ops::{Div, DivAssign, Rem, RemAssign}; use subtle::CtOption; impl Uint { - /// Computes `self` / `rhs` using a pre-made reciprocal, + /// Computes `self / rhs` using a pre-made reciprocal, /// returns the quotient (q) and remainder (r). #[inline(always)] pub const fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) { div_rem_limb_with_reciprocal(self, reciprocal) } - /// Computes `self` / `rhs`, returns the quotient (q) and remainder (r). + /// Computes `self / rhs`, returns the quotient (q) and remainder (r). #[inline(always)] pub const fn div_rem_limb(&self, rhs: NonZero) -> (Self, Limb) { div_rem_limb_with_reciprocal(self, &Reciprocal::new(rhs)) } + /// Computes `self % rhs` using a pre-made reciprocal. + #[inline(always)] + pub const fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb { + rem_limb_with_reciprocal(self, reciprocal) + } + + /// Computes `self % rhs`. + #[inline(always)] + pub const fn rem_limb(&self, rhs: NonZero) -> Limb { + rem_limb_with_reciprocal(self, &Reciprocal::new(rhs)) + } + /// Computes `self` / `rhs`, returns the quotient (q) and the remainder (r) /// /// This function is constant-time with respect to both `self` and `rhs`. @@ -84,7 +96,7 @@ impl Uint { /// Computes `self` % `rhs`, returns the remainder. pub const fn rem(&self, rhs: &NonZero) -> Self { - self.div_rem_vartime(rhs).1 + self.div_rem(rhs).1 } /// Computes `self` % `rhs`, returns the remainder in variable-time with respect to `rhs`. @@ -211,7 +223,7 @@ impl Uint { /// Perform checked reduction, returning a [`CtOption`] which `is_some` /// only if the rhs != 0 pub fn checked_rem(&self, rhs: &Self) -> CtOption { - NonZero::new(*rhs).map(|rhs| self.rem_vartime(&rhs)) + NonZero::new(*rhs).map(|rhs| self.rem(&rhs)) } } @@ -584,6 +596,18 @@ impl RemAssign<&NonZero>> for Wrapping DivRemLimb for Uint { + fn div_rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> (Self, Limb) { + Self::div_rem_limb_with_reciprocal(self, reciprocal) + } +} + +impl RemLimb for Uint { + fn rem_limb_with_reciprocal(&self, reciprocal: &Reciprocal) -> Limb { + Self::rem_limb_with_reciprocal(self, reciprocal) + } +} + #[cfg(test)] mod tests { use crate::{Limb, NonZero, Uint, Word, U256}; diff --git a/src/uint/div_limb.rs b/src/uint/div_limb.rs index 415b5ebe..f622d899 100644 --- a/src/uint/div_limb.rs +++ b/src/uint/div_limb.rs @@ -236,6 +236,24 @@ pub(crate) const fn div_rem_limb_with_reciprocal( (Uint::::new(q), Limb(r >> reciprocal.shift)) } +/// Divides `u` by the divisor encoded in the `reciprocal`, and returns the remainder. +#[inline(always)] +pub(crate) const fn rem_limb_with_reciprocal( + u: &Uint, + reciprocal: &Reciprocal, +) -> Limb { + let (u_shifted, u_hi) = u.shl_limb(reciprocal.shift); + let mut r = u_hi.0; + + let mut j = L; + while j > 0 { + j -= 1; + let (_, rj) = div2by1(r, u_shifted.as_limbs()[j].0, reciprocal); + r = rj; + } + Limb(r >> reciprocal.shift) +} + #[cfg(test)] mod tests { use super::{div2by1, Reciprocal}; diff --git a/tests/boxed_monty_form.rs b/tests/boxed_monty_form.rs index e7ff4240..5a01667c 100644 --- a/tests/boxed_monty_form.rs +++ b/tests/boxed_monty_form.rs @@ -6,7 +6,8 @@ use crypto_bigint::{ modular::{BoxedMontyForm, BoxedMontyParams}, BoxedUint, Integer, Inverter, Limb, NonZero, Odd, PrecomputeInverter, }; -use num_bigint::{BigUint, ModInverse}; +use num_bigint::BigUint; +use num_modular::ModularUnaryOps; use proptest::prelude::*; use std::cmp::Ordering; @@ -84,7 +85,7 @@ proptest! { let x_bi = retrieve_biguint(&x); let n_bi = to_biguint(n.modulus()); - let expected = x_bi.mod_inverse(&n_bi); + let expected = x_bi.invm(&n_bi); match (expected, actual) { (Some(exp), Some(act)) => prop_assert_eq!(exp, to_biguint(&act).into()), @@ -101,7 +102,7 @@ proptest! { let x_bi = retrieve_biguint(&x); let n_bi = to_biguint(n.modulus()); - let expected = x_bi.mod_inverse(&n_bi); + let expected = x_bi.invm(&n_bi); match (expected, actual) { (Some(exp), Some(act)) => { diff --git a/tests/boxed_uint_proptests.rs b/tests/boxed_uint_proptests.rs index d6c19948..1e1956fc 100644 --- a/tests/boxed_uint_proptests.rs +++ b/tests/boxed_uint_proptests.rs @@ -4,8 +4,9 @@ use core::cmp::Ordering; use crypto_bigint::{BoxedUint, CheckedAdd, Gcd, Integer, Limb, NonZero}; -use num_bigint::{BigUint, ModInverse}; +use num_bigint::BigUint; use num_integer::Integer as _; +use num_modular::ModularUnaryOps; use num_traits::identities::One; use proptest::prelude::*; @@ -168,7 +169,7 @@ proptest! { let a_bi = to_biguint(&a); let b_bi = to_biguint(&b); - let expected = a_bi.mod_inverse(b_bi); + let expected = a_bi.invm(&b_bi); let actual = Option::from(a.inv_odd_mod(&b)); match (expected, actual) { diff --git a/tests/const_monty_form.rs b/tests/const_monty_form.rs index 8af636b4..fc1276da 100644 --- a/tests/const_monty_form.rs +++ b/tests/const_monty_form.rs @@ -1,7 +1,8 @@ //! Equivalence tests between `crypto_bigint::ConstMontyForm` and `num-bigint`. use crypto_bigint::{impl_modulus, modular::ConstMontyParams, Encoding, Invert, Inverter, U256}; -use num_bigint::{BigUint, ModInverse}; +use num_bigint::BigUint; +use num_modular::ModularUnaryOps; use proptest::prelude::*; impl_modulus!( @@ -38,7 +39,7 @@ proptest! { let x_bi = retrieve_biguint(&x); let n_bi = to_biguint(&Modulus::MODULUS); - let expected = x_bi.mod_inverse(&n_bi); + let expected = x_bi.invm(&n_bi); match (expected, actual) { (Some(exp), Some(act)) => { @@ -59,7 +60,7 @@ proptest! { let x_bi = retrieve_biguint(&x); let n_bi = to_biguint(&Modulus::MODULUS); - let expected = x_bi.mod_inverse(&n_bi); + let expected = x_bi.invm(&n_bi); match (expected, actual) { (Some(exp), Some(act)) => { diff --git a/tests/monty_form.rs b/tests/monty_form.rs index a4b7c51b..dce91363 100644 --- a/tests/monty_form.rs +++ b/tests/monty_form.rs @@ -1,7 +1,8 @@ //! Equivalence tests between `crypto_bigint::MontyForm` and `num-bigint`. use crypto_bigint::{Encoding, Integer, Invert, Inverter, NonZero, Odd, PrecomputeInverter, U256}; -use num_bigint::{BigUint, ModInverse}; +use num_bigint::BigUint; +use num_modular::ModularUnaryOps; use proptest::prelude::*; type MontyForm = crypto_bigint::modular::MontyForm<{ U256::LIMBS }>; @@ -45,7 +46,7 @@ proptest! { let x_bi = retrieve_biguint(&x); let n_bi = to_biguint(n.modulus()); - let expected = x_bi.mod_inverse(&n_bi); + let expected = x_bi.invm(&n_bi); match (expected, actual) { (Some(exp), Some(act)) => { @@ -66,7 +67,7 @@ proptest! { let x_bi = retrieve_biguint(&x); let n_bi = to_biguint(n.modulus()); - let expected = x_bi.mod_inverse(&n_bi); + let expected = x_bi.invm(&n_bi); match (expected, actual) { (Some(exp), Some(act)) => {