Skip to content

Commit

Permalink
bigint/rsa: Avoid constructing Montgomery constant for d.
Browse files Browse the repository at this point in the history
We never multiply modulo `d` so avoid constructing `n0` for it.
Although `n0` is almost free to construct now, that might change in the
future. Also it is better to minimize the amount of processing on the
secret value.

```
git difftool HEAD^1:src/arithmetic/bigint/modulus.rs src/arithmetic/bigint/modulusvalue.rs
```
  • Loading branch information
briansmith committed Dec 5, 2024
1 parent d68bd9c commit 45ff856
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 54 deletions.
6 changes: 5 additions & 1 deletion src/arithmetic/bigint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
use self::boxed_limbs::BoxedLimbs;
pub(crate) use self::{
modulus::{Modulus, OwnedModulus, MODULUS_MAX_LIMBS},
modulusvalue::OwnedModulusValue,
private_exponent::PrivateExponent,
};
use crate::{
Expand All @@ -52,6 +53,7 @@ use core::{marker::PhantomData, num::NonZeroU64};

mod boxed_limbs;
mod modulus;
mod modulusvalue;
mod private_exponent;

pub trait PublicModulus {}
Expand Down Expand Up @@ -866,7 +868,9 @@ mod tests {

fn consume_modulus<M>(test_case: &mut test::TestCase, name: &str) -> OwnedModulus<M> {
let value = test_case.consume_bytes(name);
OwnedModulus::from_be_bytes(untrusted::Input::from(&value)).unwrap()
OwnedModulus::from(
OwnedModulusValue::from_be_bytes(untrusted::Input::from(&value)).unwrap(),
)
}

fn assert_elem_eq<M, E>(a: &Elem<M, E>, b: &Elem<M, E>) {
Expand Down
66 changes: 17 additions & 49 deletions src/arithmetic/bigint/modulus.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2015-2023 Brian Smith.
// Copyright 2015-2024 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
Expand All @@ -12,11 +12,11 @@
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::{BoxedLimbs, Elem, PublicModulus, Unencoded, N0};
use super::{super::montgomery::Unencoded, BoxedLimbs, Elem, OwnedModulusValue, PublicModulus, N0};
use crate::{
bits::BitLength,
cpu, error,
limb::{self, Limb, LimbMask, LIMB_BITS},
limb::{self, Limb, LIMB_BITS},
polyfill::LeadingZerosStripped,
};
use core::marker::PhantomData;
Expand All @@ -35,7 +35,7 @@ pub const MODULUS_MAX_LIMBS: usize = super::super::BIGINT_MODULUS_MAX_LIMBS;
/// and larger than 2. The larger-than-1 requirement is imposed, at least, by
/// the modular inversion code.
pub struct OwnedModulus<M> {
limbs: BoxedLimbs<M>, // Also `value >= 3`.
inner: OwnedModulusValue<M>,

// n0 * N == -1 (mod r).
//
Expand Down Expand Up @@ -73,36 +73,19 @@ pub struct OwnedModulus<M> {
// ones that don't, we could use a shorter `R` value and use faster `Limb`
// calculations instead of double-precision `u64` calculations.
n0: N0,

len_bits: BitLength,
}

impl<M: PublicModulus> Clone for OwnedModulus<M> {
fn clone(&self) -> Self {
Self {
limbs: self.limbs.clone(),
inner: self.inner.clone(),
n0: self.n0,
len_bits: self.len_bits,
}
}
}

impl<M> OwnedModulus<M> {
pub(crate) fn from_be_bytes(input: untrusted::Input) -> Result<Self, error::KeyRejected> {
let n = BoxedLimbs::positive_minimal_width_from_be_bytes(input)?;
if n.len() > MODULUS_MAX_LIMBS {
return Err(error::KeyRejected::too_large());
}
if n.len() < MODULUS_MIN_LIMBS {
return Err(error::KeyRejected::unexpected_error());
}
if limb::limbs_are_even_constant_time(&n) != LimbMask::False {
return Err(error::KeyRejected::invalid_component());
}
if limb::limbs_less_than_limb_constant_time(&n, 3) != LimbMask::False {
return Err(error::KeyRejected::unexpected_error());
}

pub(crate) fn from(n: OwnedModulusValue<M>) -> Self {
// n_mod_r = n % r. As explained in the documentation for `n0`, this is
// done by taking the lowest `N0::LIMBS_USED` limbs of `n`.
#[allow(clippy::useless_conversion)]
Expand All @@ -112,63 +95,48 @@ impl<M> OwnedModulus<M> {
}

// XXX: u64::from isn't guaranteed to be constant time.
let mut n_mod_r: u64 = u64::from(n[0]);
let mut n_mod_r: u64 = u64::from(n.limbs()[0]);

if N0::LIMBS_USED == 2 {
// XXX: If we use `<< LIMB_BITS` here then 64-bit builds
// fail to compile because of `deny(exceeding_bitshifts)`.
debug_assert_eq!(LIMB_BITS, 32);
n_mod_r |= u64::from(n[1]) << 32;
n_mod_r |= u64::from(n.limbs()[1]) << 32;
}
N0::precalculated(unsafe { bn_neg_inv_mod_r_u64(n_mod_r) })
};

let len_bits = limb::limbs_minimal_bits(&n);

Ok(Self {
limbs: n,
n0,
len_bits,
})
}

pub fn verify_less_than<L>(&self, l: &Modulus<L>) -> Result<(), error::Unspecified> {
if self.len_bits() > l.len_bits()
|| (self.limbs.len() == l.limbs().len()
&& limb::limbs_less_than_limbs_consttime(&self.limbs, l.limbs()) != LimbMask::True)
{
return Err(error::Unspecified);
}
Ok(())
Self { inner: n, n0 }
}

pub fn to_elem<L>(&self, l: &Modulus<L>) -> Result<Elem<L, Unencoded>, error::Unspecified> {
self.verify_less_than(l)?;
let mut limbs = BoxedLimbs::zero(l.limbs.len());
limbs[..self.limbs.len()].copy_from_slice(&self.limbs);
self.inner.verify_less_than(l)?;
let mut limbs = BoxedLimbs::zero(l.limbs().len());
limbs[..self.inner.limbs().len()].copy_from_slice(self.inner.limbs());
Ok(Elem {
limbs,
encoding: PhantomData,
})
}

pub(crate) fn modulus(&self, cpu_features: cpu::Features) -> Modulus<M> {
Modulus {
limbs: &self.limbs,
limbs: self.inner.limbs(),
n0: self.n0,
len_bits: self.len_bits,
len_bits: self.len_bits(),
m: PhantomData,
cpu_features,
}
}

pub fn len_bits(&self) -> BitLength {
self.len_bits
self.inner.len_bits()
}
}

impl<M: PublicModulus> OwnedModulus<M> {
pub fn be_bytes(&self) -> LeadingZerosStripped<impl ExactSizeIterator<Item = u8> + Clone + '_> {
LeadingZerosStripped::new(limb::unstripped_be_bytes(&self.limbs))
LeadingZerosStripped::new(limb::unstripped_be_bytes(self.inner.limbs()))
}
}

Expand Down
80 changes: 80 additions & 0 deletions src/arithmetic/bigint/modulusvalue.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
// Copyright 2015-2024 Brian Smith.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

use super::{
modulus::{MODULUS_MAX_LIMBS, MODULUS_MIN_LIMBS},
BoxedLimbs, Modulus, PublicModulus,
};
use crate::{
bits::BitLength,
error,
limb::{self, Limb, LimbMask},
};

/// `OwnedModulus`, without the overhead of Montgomery multiplication support.
pub(crate) struct OwnedModulusValue<M> {
limbs: BoxedLimbs<M>, // Also `value >= 3`.

len_bits: BitLength,
}

impl<M: PublicModulus> Clone for OwnedModulusValue<M> {
fn clone(&self) -> Self {
Self {
limbs: self.limbs.clone(),
len_bits: self.len_bits,
}
}
}

impl<M> OwnedModulusValue<M> {
pub(crate) fn from_be_bytes(input: untrusted::Input) -> Result<Self, error::KeyRejected> {
let n = BoxedLimbs::positive_minimal_width_from_be_bytes(input)?;
if n.len() > MODULUS_MAX_LIMBS {
return Err(error::KeyRejected::too_large());
}
if n.len() < MODULUS_MIN_LIMBS {
return Err(error::KeyRejected::unexpected_error());
}
if limb::limbs_are_even_constant_time(&n) != LimbMask::False {
return Err(error::KeyRejected::invalid_component());
}
if limb::limbs_less_than_limb_constant_time(&n, 3) != LimbMask::False {
return Err(error::KeyRejected::unexpected_error());
}

let len_bits = limb::limbs_minimal_bits(&n);

Ok(Self { limbs: n, len_bits })
}

pub fn verify_less_than<L>(&self, l: &Modulus<L>) -> Result<(), error::Unspecified> {
if self.len_bits() > l.len_bits()
|| (self.limbs.len() == l.limbs().len()
&& limb::limbs_less_than_limbs_consttime(&self.limbs, l.limbs()) != LimbMask::True)
{
return Err(error::Unspecified);
}
Ok(())
}

pub fn len_bits(&self) -> BitLength {
self.len_bits
}

#[inline]
pub(super) fn limbs(&self) -> &[Limb] {
&self.limbs
}
}
6 changes: 3 additions & 3 deletions src/rsa/keypair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ impl KeyPair {
// First, validate `2**half_n_bits < d`. Since 2**half_n_bits has a bit
// length of half_n_bits + 1, this check gives us 2**half_n_bits <= d,
// and knowing d is odd makes the inequality strict.
let d = bigint::OwnedModulus::<D>::from_be_bytes(d)
let d = bigint::OwnedModulusValue::<D>::from_be_bytes(d)
.map_err(|_| KeyRejected::invalid_component())?;
if !(n_bits.half_rounded_up() < d.len_bits()) {
return Err(KeyRejected::inconsistent_components());
Expand Down Expand Up @@ -416,7 +416,7 @@ impl<M> PrivatePrime<M> {
n_bits: BitLength,
cpu_features: cpu::Features,
) -> Result<Self, KeyRejected> {
let p = bigint::OwnedModulus::from_be_bytes(p)?;
let p = bigint::OwnedModulusValue::from_be_bytes(p)?;

// 5.c / 5.g:
//
Expand All @@ -437,7 +437,7 @@ impl<M> PrivatePrime<M> {
// TODO: Step 5.h: Verify GCD(q - 1, e) == 1.

// Steps 5.e and 5.f are omitted as explained above.

let p = bigint::OwnedModulus::from(p);
let oneRR = bigint::One::newRR(&p.modulus(cpu_features));

Ok(Self { modulus: p, oneRR })
Expand Down
3 changes: 2 additions & 1 deletion src/rsa/public_modulus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ impl PublicModulus {
const MIN_BITS: bits::BitLength = bits::BitLength::from_bits(1024);

// Step 3 / Step c for `n` (out of order).
let value = bigint::OwnedModulus::from_be_bytes(n)?;
let value = bigint::OwnedModulusValue::from_be_bytes(n)?;
let bits = value.len_bits();

// Step 1 / Step a. XXX: SP800-56Br1 and SP800-89 require the length of
Expand All @@ -53,6 +53,7 @@ impl PublicModulus {
if bits > max_bits {
return Err(error::KeyRejected::too_large());
}
let value = bigint::OwnedModulus::from(value);
let oneRR = bigint::One::newRR(&value.modulus(cpu_features));

Ok(Self { value, oneRR })
Expand Down

0 comments on commit 45ff856

Please sign in to comment.