diff --git a/src/arithmetic/bigint.rs b/src/arithmetic/bigint.rs index c4fc37ce82..65b9f90227 100644 --- a/src/arithmetic/bigint.rs +++ b/src/arithmetic/bigint.rs @@ -36,7 +36,7 @@ //! [Static checking of units in Servo]: //! https://blog.mozilla.org/research/2014/06/23/static-checking-of-units-in-servo/ -use self::n0::N0; +use self::{boxed_limbs::BoxedLimbs, n0::N0}; pub(crate) use self::{ modulus::{Modulus, PartialModulus, MODULUS_MAX_LIMBS}, private_exponent::PrivateExponent, @@ -45,17 +45,14 @@ pub(crate) use super::nonnegative::Nonnegative; use crate::{ arithmetic::montgomery::*, bits, bssl, c, cpu, error, - limb::{self, Limb, LimbMask, LIMB_BITS, LIMB_BYTES}, + limb::{self, Limb, LimbMask, LIMB_BITS}, polyfill::u64_from_usize, }; -use alloc::{borrow::ToOwned as _, boxed::Box, vec}; -use core::{ - marker::PhantomData, - num::NonZeroU64, - ops::{Deref, DerefMut}, -}; +use alloc::vec; +use core::{marker::PhantomData, num::NonZeroU64}; mod bn_mul_mont_fallback; +mod boxed_limbs; mod modulus; mod n0; mod private_exponent; @@ -79,103 +76,6 @@ struct Width { m: PhantomData, } -/// All `BoxedLimbs` are stored in the same number of limbs. -struct BoxedLimbs { - limbs: Box<[Limb]>, - - /// The modulus *m* that determines the size of `limbx`. - m: PhantomData, -} - -impl Deref for BoxedLimbs { - type Target = [Limb]; - #[inline] - fn deref(&self) -> &Self::Target { - &self.limbs - } -} - -impl DerefMut for BoxedLimbs { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.limbs - } -} - -// TODO: `derive(Clone)` after https://github.com/rust-lang/rust/issues/26925 -// is resolved or restrict `M: Clone`. -impl Clone for BoxedLimbs { - fn clone(&self) -> Self { - Self { - limbs: self.limbs.clone(), - m: self.m, - } - } -} - -impl BoxedLimbs { - fn positive_minimal_width_from_be_bytes( - input: untrusted::Input, - ) -> Result { - // Reject leading zeros. Also reject the value zero ([0]) because zero - // isn't positive. - if untrusted::Reader::new(input).peek(0) { - return Err(error::KeyRejected::invalid_encoding()); - } - let num_limbs = (input.len() + LIMB_BYTES - 1) / LIMB_BYTES; - let mut r = Self::zero(Width { - num_limbs, - m: PhantomData, - }); - limb::parse_big_endian_and_pad_consttime(input, &mut r) - .map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?; - Ok(r) - } - - fn minimal_width_from_unpadded(limbs: &[Limb]) -> Self { - debug_assert_ne!(limbs.last(), Some(&0)); - Self { - limbs: limbs.to_owned().into_boxed_slice(), - m: PhantomData, - } - } - - fn from_be_bytes_padded_less_than( - input: untrusted::Input, - m: &Modulus, - ) -> Result { - let mut r = Self::zero(m.width()); - limb::parse_big_endian_and_pad_consttime(input, &mut r)?; - if limb::limbs_less_than_limbs_consttime(&r, m.limbs()) != LimbMask::True { - return Err(error::Unspecified); - } - Ok(r) - } - - #[inline] - fn is_zero(&self) -> bool { - limb::limbs_are_zero_constant_time(&self.limbs) == LimbMask::True - } - - fn zero(width: Width) -> Self { - Self { - limbs: vec![0; width.num_limbs].into_boxed_slice(), - m: PhantomData, - } - } - - fn width(&self) -> Width { - Width { - num_limbs: self.limbs.len(), - m: PhantomData, - } - } - - fn into_limbs(self) -> Box<[Limb]> { - self.limbs - } -} - /// A modulus *s* that is smaller than another modulus *l* so every element of /// ℤ/sℤ is also an element of ℤ/lℤ. /// @@ -342,10 +242,7 @@ pub fn elem_reduced_once>( assert!(r.len() <= m.limbs().len()); limb::limbs_reduce_once_constant_time(&mut r, m.limbs()); Elem { - limbs: BoxedLimbs { - limbs: r.limbs, - m: PhantomData, - }, + limbs: BoxedLimbs::new_unchecked(r.into_limbs()), encoding: PhantomData, } } @@ -636,6 +533,8 @@ pub fn elem_exp_consttime( exponent: &PrivateExponent, m: &Modulus, ) -> Result, error::Unspecified> { + use crate::limb::LIMB_BYTES; + // Pretty much all the math here requires CPU feature detection to have // been done. `cpu_features` isn't threaded through all the internal // functions, so just make it clear that it has been done at this point. @@ -1020,7 +919,7 @@ prefixed_extern! { #[cfg(test)] mod tests { use super::{modulus::MODULUS_MIN_LIMBS, *}; - use crate::test; + use crate::{limb::LIMB_BYTES, test}; use alloc::format; // Type-level representation of an arbitrary modulus. diff --git a/src/arithmetic/bigint/boxed_limbs.rs b/src/arithmetic/bigint/boxed_limbs.rs new file mode 100644 index 0000000000..0d5bba121b --- /dev/null +++ b/src/arithmetic/bigint/boxed_limbs.rs @@ -0,0 +1,130 @@ +// Copyright 2015-2023 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, Width}; +use crate::{ + error, + limb::{self, Limb, LimbMask, LIMB_BYTES}, +}; +use alloc::{borrow::ToOwned, boxed::Box, vec}; +use core::{ + marker::PhantomData, + ops::{Deref, DerefMut}, +}; + +/// All `BoxedLimbs` are stored in the same number of limbs. +pub(super) struct BoxedLimbs { + limbs: Box<[Limb]>, + + /// The modulus *m* that determines the size of `limbx`. + m: PhantomData, +} + +impl Deref for BoxedLimbs { + type Target = [Limb]; + #[inline] + fn deref(&self) -> &Self::Target { + &self.limbs + } +} + +impl DerefMut for BoxedLimbs { + #[inline] + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.limbs + } +} + +// TODO: `derive(Clone)` after https://github.com/rust-lang/rust/issues/26925 +// is resolved or restrict `M: Clone`. +impl Clone for BoxedLimbs { + fn clone(&self) -> Self { + Self { + limbs: self.limbs.clone(), + m: self.m, + } + } +} + +impl BoxedLimbs { + // The caller must ensure that `limbs.len()` is the same width as the + // modulus. + pub(super) fn new_unchecked(limbs: Box<[Limb]>) -> Self { + Self { + limbs, + m: PhantomData, + } + } + + pub(super) fn positive_minimal_width_from_be_bytes( + input: untrusted::Input, + ) -> Result { + // Reject leading zeros. Also reject the value zero ([0]) because zero + // isn't positive. + if untrusted::Reader::new(input).peek(0) { + return Err(error::KeyRejected::invalid_encoding()); + } + let num_limbs = (input.len() + LIMB_BYTES - 1) / LIMB_BYTES; + let mut r = Self::zero(Width { + num_limbs, + m: PhantomData, + }); + limb::parse_big_endian_and_pad_consttime(input, &mut r) + .map_err(|error::Unspecified| error::KeyRejected::unexpected_error())?; + Ok(r) + } + + pub(super) fn minimal_width_from_unpadded(limbs: &[Limb]) -> Self { + debug_assert_ne!(limbs.last(), Some(&0)); + Self { + limbs: limbs.to_owned().into_boxed_slice(), + m: PhantomData, + } + } + + pub(super) fn from_be_bytes_padded_less_than( + input: untrusted::Input, + m: &Modulus, + ) -> Result { + let mut r = Self::zero(m.width()); + limb::parse_big_endian_and_pad_consttime(input, &mut r)?; + if limb::limbs_less_than_limbs_consttime(&r, m.limbs()) != LimbMask::True { + return Err(error::Unspecified); + } + Ok(r) + } + + #[inline] + pub(super) fn is_zero(&self) -> bool { + limb::limbs_are_zero_constant_time(&self.limbs) == LimbMask::True + } + + pub(super) fn zero(width: Width) -> Self { + Self { + limbs: vec![0; width.num_limbs].into_boxed_slice(), + m: PhantomData, + } + } + + pub(super) fn width(&self) -> Width { + Width { + num_limbs: self.limbs.len(), + m: PhantomData, + } + } + + pub(super) fn into_limbs(self) -> Box<[Limb]> { + self.limbs + } +} diff --git a/src/arithmetic/bigint/modulus.rs b/src/arithmetic/bigint/modulus.rs index 5fbf1e9178..ca0724cc2c 100644 --- a/src/arithmetic/bigint/modulus.rs +++ b/src/arithmetic/bigint/modulus.rs @@ -115,10 +115,7 @@ impl Modulus { n: Nonnegative, cpu_features: cpu::Features, ) -> Result<(Self, bits::BitLength), error::KeyRejected> { - let limbs = BoxedLimbs { - limbs: n.into_limbs(), - m: PhantomData, - }; + let limbs = BoxedLimbs::new_unchecked(n.into_limbs()); Self::from_boxed_limbs(limbs, cpu_features) } @@ -173,10 +170,10 @@ impl Modulus { N0::from(unsafe { bn_neg_inv_mod_r_u64(n_mod_r) }) }; - let bits = limb::limbs_minimal_bits(&n.limbs); + let bits = limb::limbs_minimal_bits(&n); let oneRR = { let partial = PartialModulus { - limbs: &n.limbs, + limbs: &n, n0: n0.clone(), m: PhantomData, cpu_features, @@ -240,12 +237,8 @@ impl Modulus { { // TODO: Encode this assertion into the `where` above. assert_eq!(self.width().num_limbs, l.width().num_limbs); - let limbs = self.limbs.clone(); Elem { - limbs: BoxedLimbs { - limbs: limbs.limbs, - m: PhantomData, - }, + limbs: BoxedLimbs::new_unchecked(self.limbs.clone().into_limbs()), encoding: PhantomData, } }