Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
7 changes: 5 additions & 2 deletions benches/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ fn bench_division(c: &mut Criterion) {
b.iter_batched(
|| {
let x = U256::random(&mut OsRng);
let y = Limb::random(&mut OsRng);
let r = Reciprocal::new(y);
let mut y = Limb::random(&mut OsRng);
if y == Limb::ZERO {
y = Limb::ONE;
}
let r = Reciprocal::new(NonZero::new(y).unwrap());
(x, r)
},
|(x, r)| black_box(x.div_rem_limb_with_reciprocal(&r)),
Expand Down
22 changes: 16 additions & 6 deletions src/modular/dyn_residue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use super::{
residue::{Residue, ResidueParams},
Retrieve,
};
use crate::{Limb, Uint, Word};
use crate::{Limb, NonZero, Uint, Word, Zero};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

/// Parameters to efficiently go to/from the Montgomery form for an odd modulus provided at runtime.
Expand All @@ -35,12 +35,22 @@ pub struct DynResidueParams<const LIMBS: usize> {
impl<const LIMBS: usize> DynResidueParams<LIMBS> {
/// Instantiates a new set of `ResidueParams` representing the given `modulus` if it is odd.
///
/// Returns a `CtOption` that is `None` if the provided modulus is not odd.
/// Returns `None` if the provided modulus is not odd.
pub fn new(modulus: &Uint<LIMBS>) -> CtOption<Self> {
let r = Uint::MAX.const_rem(modulus).0.wrapping_add(&Uint::ONE);
let r2 = Uint::const_rem_wide(r.square_wide(), modulus).0;
// Use a surrogate value of `1` in case a modulus of `0` is passed.
// This will be rejected by the `modulus_is_odd` check below,
// which will fail and return `None`.
let nz_modulus = NonZero::new(Uint::conditional_select(
modulus,
&Uint::ONE,
modulus.is_zero(),
))
.expect("modulus ensured non-zero");

let r = Uint::MAX.rem(&nz_modulus).wrapping_add(&Uint::ONE);
let r2 = Uint::rem_wide(r.square_wide(), &nz_modulus);

// If the inverse does not exist, it means the modulus is odd.
// If the inverse exists, it means the modulus is odd.
let (inv_mod_limb, modulus_is_odd) = modulus.inv_mod2k_vartime(Word::BITS);
let mod_neg_inv = Limb(Word::MIN.wrapping_sub(inv_mod_limb.limbs[0].0));

Expand Down Expand Up @@ -68,7 +78,7 @@ impl<const LIMBS: usize> DynResidueParams<LIMBS> {
P: ResidueParams<LIMBS>,
{
Self {
modulus: P::MODULUS,
modulus: P::MODULUS.0,
r: P::R,
r2: P::R2,
r3: P::R3,
Expand Down
36 changes: 7 additions & 29 deletions src/modular/residue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ mod pow;
mod sub;

use super::{div_by_2::div_by_2, reduction::montgomery_reduction, Retrieve};
use crate::{Limb, Uint, ZeroConstant};
use crate::{Limb, NonZero, Uint, ZeroConstant};
use core::{fmt::Debug, marker::PhantomData};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};

#[cfg(feature = "rand_core")]
use crate::{rand_core::CryptoRngCore, NonZero, Random, RandomMod};
use crate::{rand_core::CryptoRngCore, Random, RandomMod};

#[cfg(feature = "serde")]
use {
Expand All @@ -38,7 +38,7 @@ pub trait ResidueParams<const LIMBS: usize>:
const LIMBS: usize;

/// The constant modulus
const MODULUS: Uint<LIMBS>;
const MODULUS: NonZero<Uint<LIMBS>>;
/// Parameter used in Montgomery reduction
const R: Uint<LIMBS>;
/// R^2, used to move into Montgomery form
Expand Down Expand Up @@ -86,7 +86,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
const fn generate_residue(integer: &Uint<LIMBS>) -> Self {
let product = integer.mul_wide(&MOD::R2);
let montgomery_form =
montgomery_reduction::<LIMBS>(&product, &MOD::MODULUS, MOD::MOD_NEG_INV);
montgomery_reduction::<LIMBS>(&product, &MOD::MODULUS.0, MOD::MOD_NEG_INV);

Self {
montgomery_form,
Expand All @@ -95,37 +95,15 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
}

/// Instantiates a new [`Residue`] that represents this `integer` mod `MOD`.
///
/// If the modulus represented by `MOD` is not odd, this function will panic; use
/// [`new_checked`][`Residue::new_checked`] if you want to be able to detect an invalid modulus.
pub const fn new(integer: &Uint<LIMBS>) -> Self {
// A valid modulus must be odd
if MOD::MODULUS.ct_is_odd().to_u8() == 0 {
panic!("modulus must be odd");
}

Self::generate_residue(integer)
}

/// Instantiates a new `Residue` that represents this `integer` mod `MOD` if the modulus is odd.
///
/// Returns a [`CtOption`] that is `None` if the provided modulus is not odd; this is a safer
/// version of [`new`][`Residue::new`], which can panic.
// TODO: remove this method when we can use `generic_const_exprs.` to ensure the modulus is
// always valid.
pub fn new_checked(integer: &Uint<LIMBS>) -> CtOption<Self> {
// A valid modulus must be odd.
CtOption::new(
Self::generate_residue(integer),
MOD::MODULUS.ct_is_odd().into(),
)
}

/// Retrieves the integer currently encoded in this [`Residue`], guaranteed to be reduced.
pub const fn retrieve(&self) -> Uint<LIMBS> {
montgomery_reduction::<LIMBS>(
&(self.montgomery_form, Uint::ZERO),
&MOD::MODULUS,
&MOD::MODULUS.0,
MOD::MOD_NEG_INV,
)
}
Expand Down Expand Up @@ -204,7 +182,7 @@ where
{
#[inline]
fn random(rng: &mut impl CryptoRngCore) -> Self {
Self::new(&Uint::random_mod(rng, &NonZero::from_uint(MOD::MODULUS)))
Self::new(&Uint::random_mod(rng, &MOD::MODULUS))
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/modular/residue/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
montgomery_form: add_montgomery_form(
&self.montgomery_form,
&rhs.montgomery_form,
&MOD::MODULUS,
&MOD::MODULUS.0,
),
phantom: core::marker::PhantomData,
}
Expand Down
2 changes: 1 addition & 1 deletion src/modular/residue/inv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
pub const fn invert(&self) -> (Self, CtChoice) {
let (montgomery_form, is_some) = inv_montgomery_form(
&self.montgomery_form,
&MOD::MODULUS,
&MOD::MODULUS.0,
&MOD::R3,
MOD::MOD_NEG_INV,
);
Expand Down
15 changes: 8 additions & 7 deletions src/modular/residue/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,25 +20,26 @@ macro_rules! impl_modulus {
$uint_type: $crate::ConcatMixed<MixedOutput = $crate::Uint<DLIMBS>>,
{
const LIMBS: usize = <$uint_type>::LIMBS;
const MODULUS: $uint_type = {
const MODULUS: $crate::NonZero<$uint_type> = {
let res = <$uint_type>::from_be_hex($value);

// Check that the modulus is odd
if res.as_limbs()[0].0 & 1 == 0 {
panic!("modulus must be odd");
}

res
// Can unwrap `NonZero::const_new()` here since `res` was asserted to be odd.
$crate::NonZero::<$uint_type>::const_new(res).0
};

const R: $uint_type = $crate::Uint::MAX
.const_rem(&Self::MODULUS)
.0
.rem(&Self::MODULUS)
.wrapping_add(&$crate::Uint::ONE);
const R2: $uint_type =
$crate::Uint::const_rem_wide(Self::R.square_wide(), &Self::MODULUS).0;
const R2: $uint_type = $crate::Uint::rem_wide(Self::R.square_wide(), &Self::MODULUS);
const MOD_NEG_INV: $crate::Limb = $crate::Limb(
$crate::Word::MIN.wrapping_sub(
Self::MODULUS
.as_ref()
.inv_mod2k_vartime($crate::Word::BITS)
.0
.as_limbs()[0]
Expand All @@ -47,7 +48,7 @@ macro_rules! impl_modulus {
);
const R3: $uint_type = $crate::modular::montgomery_reduction(
&Self::R2.square_wide(),
&Self::MODULUS,
Self::MODULUS.as_ref(),
Self::MOD_NEG_INV,
);
}
Expand Down
4 changes: 2 additions & 2 deletions src/modular/residue/mul.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
montgomery_form: mul_montgomery_form(
&self.montgomery_form,
&rhs.montgomery_form,
&MOD::MODULUS,
&MOD::MODULUS.0,
MOD::MOD_NEG_INV,
),
phantom: PhantomData,
Expand All @@ -31,7 +31,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
Self {
montgomery_form: square_montgomery_form(
&self.montgomery_form,
&MOD::MODULUS,
&MOD::MODULUS.0,
MOD::MOD_NEG_INV,
),
phantom: PhantomData,
Expand Down
2 changes: 1 addition & 1 deletion src/modular/residue/pow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
&self.montgomery_form,
exponent,
exponent_bits,
&MOD::MODULUS,
&MOD::MODULUS.0,
&MOD::R,
MOD::MOD_NEG_INV,
),
Expand Down
2 changes: 1 addition & 1 deletion src/modular/residue/sub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ impl<MOD: ResidueParams<LIMBS>, const LIMBS: usize> Residue<MOD, LIMBS> {
montgomery_form: sub_montgomery_form(
&self.montgomery_form,
&rhs.montgomery_form,
&MOD::MODULUS,
&MOD::MODULUS.0,
),
phantom: core::marker::PhantomData,
}
Expand Down
5 changes: 5 additions & 0 deletions src/non_zero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ where
CtOption::new(Self(n), !is_zero)
}

/// Provides access to the contents of `NonZero` in a `const` context.
pub const fn as_ref(&self) -> &T {
&self.0
}

/// Returns the inner value.
pub fn get(self) -> T {
self.0
Expand Down
Loading