diff --git a/src/modular/boxed_monty_form.rs b/src/modular/boxed_monty_form.rs index 9f6355763..6ea411e60 100644 --- a/src/modular/boxed_monty_form.rs +++ b/src/modular/boxed_monty_form.rs @@ -11,7 +11,7 @@ mod sub; use super::{ConstMontyParams, Retrieve, div_by_2}; use mul::BoxedMontyMultiplier; -use crate::{BoxedUint, Limb, Monty, Odd, Word}; +use crate::{BoxedUint, Limb, Monty, Odd, Resize, Word}; use alloc::sync::Arc; use subtle::Choice; @@ -58,8 +58,8 @@ impl BoxedMontyParams { // `R^2 mod modulus`, used to convert integers to Montgomery form. let r2 = one .square() - .rem(&modulus.as_nz_ref().widen(bits_precision * 2)) - .shorten(bits_precision); + .rem(&modulus.as_nz_ref().resize_unchecked(bits_precision * 2)) + .resize_unchecked(bits_precision); // The modular inverse should always exist, because it was ensured odd above, which also ensures it's non-zero let (inv_mod_limb, inv_mod_limb_exists) = modulus.inv_mod2k_vartime(Word::BITS); @@ -102,10 +102,7 @@ impl BoxedMontyParams { .wrapping_add(&BoxedUint::one()); // `R^2 mod modulus`, used to convert integers to Montgomery form. - let r2 = one - .square() - .rem_vartime(&modulus.as_nz_ref().widen(bits_precision * 2)) - .shorten(bits_precision); + let r2 = one.square().rem_vartime(modulus.as_nz_ref()); // The modular inverse should always exist, because it was ensured odd above, which also ensures it's non-zero let (inv_mod_limb, inv_mod_limb_exists) = modulus.inv_mod2k_full_vartime(Word::BITS); diff --git a/src/modular/safegcd/boxed.rs b/src/modular/safegcd/boxed.rs index 934768c8e..a9653f174 100644 --- a/src/modular/safegcd/boxed.rs +++ b/src/modular/safegcd/boxed.rs @@ -4,7 +4,7 @@ //! See parent module for more information. use super::{Matrix, inv_mod2_62, iterations, jump}; -use crate::{BoxedUint, Inverter, Limb, Odd, Word}; +use crate::{BoxedUint, Inverter, Limb, Odd, Resize, Word}; use alloc::boxed::Box; use core::{ cmp::max, @@ -34,7 +34,7 @@ impl BoxedSafeGcdInverter { pub fn new(modulus: &Odd, adjuster: &BoxedUint) -> Self { Self { modulus: BoxedUnsatInt::from(&modulus.0), - adjuster: BoxedUnsatInt::from(&adjuster.widen(modulus.bits_precision())), + adjuster: BoxedUnsatInt::from(&adjuster.resize(modulus.bits_precision())), inverse: inv_mod2_62(modulus.0.as_words()), } } @@ -339,7 +339,7 @@ impl BoxedUnsatInt { if shorten { debug_assert!(ret.bits_vartime() <= 32); - ret.shorten(32) + ret.resize(32) } else { ret } diff --git a/src/odd.rs b/src/odd.rs index b442a6326..b39e15f0a 100644 --- a/src/odd.rs +++ b/src/odd.rs @@ -5,7 +5,7 @@ use core::{cmp::Ordering, fmt, ops::Deref}; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; #[cfg(feature = "alloc")] -use crate::BoxedUint; +use crate::{BoxedUint, Resize}; #[cfg(feature = "rand_core")] use crate::{Random, rand_core::TryRngCore}; @@ -150,6 +150,32 @@ impl PartialOrd> for BoxedUint { } } +#[cfg(feature = "alloc")] +impl Resize for Odd { + type Output = Self; + + fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output { + Odd(self.0.resize_unchecked(at_least_bits_precision)) + } + + fn try_resize(self, at_least_bits_precision: u32) -> Option { + self.0.try_resize(at_least_bits_precision).map(Odd) + } +} + +#[cfg(feature = "alloc")] +impl Resize for &Odd { + type Output = Odd; + + fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output { + Odd((&self.0).resize_unchecked(at_least_bits_precision)) + } + + fn try_resize(self, at_least_bits_precision: u32) -> Option { + (&self.0).try_resize(at_least_bits_precision).map(Odd) + } +} + #[cfg(feature = "rand_core")] impl Random for Odd> { /// Generate a random `Odd>`. diff --git a/src/traits.rs b/src/traits.rs index d95adbf8d..f20ca6c63 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -851,6 +851,34 @@ pub trait ShrVartime: Sized { fn wrapping_shr_vartime(&self, shift: u32) -> Self; } +/// Methods for resizing the allocated storage. +pub trait Resize: Sized { + /// The result of the resizing. + type Output; + + /// Resizes to the minimum storage that fits `at_least_bits_precision` + /// without checking if the bit size of `self` is larger than `at_least_bits_precision`. + /// + /// Variable-time w.r.t. `at_least_bits_precision`. + fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output; + + /// Resizes to the minimum storage that fits `at_least_bits_precision` + /// returning `None` if the bit size of `self` is larger than `at_least_bits_precision`. + /// + /// Variable-time w.r.t. `at_least_bits_precision`. + fn try_resize(self, at_least_bits_precision: u32) -> Option; + + /// Resizes to the minimum storage that fits `at_least_bits_precision` + /// panicking if the bit size of `self` is larger than `at_least_bits_precision`. + /// + /// Variable-time w.r.t. `at_least_bits_precision`. + fn resize(self, at_least_bits_precision: u32) -> Self::Output { + self.try_resize(at_least_bits_precision).unwrap_or_else(|| { + panic!("The bit size of `self` is larger than `at_least_bits_precision`") + }) + } +} + /// A representation of an integer optimized for the performance of modular operations. pub trait Monty: 'static diff --git a/src/uint/boxed.rs b/src/uint/boxed.rs index 026406d43..0358ce4be 100644 --- a/src/uint/boxed.rs +++ b/src/uint/boxed.rs @@ -28,7 +28,7 @@ mod sub_mod; #[cfg(feature = "rand_core")] mod rand; -use crate::{Integer, Limb, NonZero, Odd, UintRef, Word, Zero, modular::BoxedMontyForm}; +use crate::{Integer, Limb, NonZero, Odd, Resize, UintRef, Word, Zero, modular::BoxedMontyForm}; use alloc::{boxed::Box, vec, vec::Vec}; use core::fmt; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; @@ -199,6 +199,7 @@ impl BoxedUint { /// /// Panics if `at_least_bits_precision` is smaller than the current precision. #[must_use] + #[deprecated(since = "0.7.0", note = "please use `resize` instead")] pub fn widen(&self, at_least_bits_precision: u32) -> BoxedUint { assert!(at_least_bits_precision >= self.bits_precision()); @@ -211,6 +212,7 @@ impl BoxedUint { /// /// Panics if `at_least_bits_precision` is larger than the current precision. #[must_use] + #[deprecated(since = "0.7.0", note = "please use `resize` instead")] pub fn shorten(&self, at_least_bits_precision: u32) -> BoxedUint { assert!(at_least_bits_precision <= self.bits_precision()); let mut ret = BoxedUint::zero_with_precision(at_least_bits_precision); @@ -271,14 +273,76 @@ impl BoxedUint { limbs[i] = Limb::conditional_select(&limbs[i], &Limb::ZERO, choice); } } + + /// Returns `true` if the integer's bit size is smaller or equal to `bits`. + pub(crate) fn is_within_bits(&self, bits: u32) -> bool { + bits >= self.bits_precision() || bits >= self.bits() + } } -impl NonZero { - /// Widen this type's precision to the given number of bits. - /// - /// See [`BoxedUint::widen`] for more information, including panic conditions. - pub fn widen(&self, bits_precision: u32) -> Self { - NonZero(self.0.widen(bits_precision)) +impl Resize for BoxedUint { + type Output = BoxedUint; + + fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output { + let new_len = Self::limbs_for_precision(at_least_bits_precision); + if new_len == self.limbs.len() { + self + } else { + let mut limbs = self.limbs.into_vec(); + limbs.resize(new_len, Limb::ZERO); + Self::from(limbs) + } + } + + fn try_resize(self, at_least_bits_precision: u32) -> Option { + if self.is_within_bits(at_least_bits_precision) { + Some(self.resize_unchecked(at_least_bits_precision)) + } else { + None + } + } +} + +impl Resize for &BoxedUint { + type Output = BoxedUint; + + fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output { + let mut ret = BoxedUint::zero_with_precision(at_least_bits_precision); + let num_limbs_to_copy = core::cmp::min(ret.limbs.len(), self.limbs.len()); + ret.limbs[..num_limbs_to_copy].copy_from_slice(&self.limbs[..num_limbs_to_copy]); + ret + } + + fn try_resize(self, at_least_bits_precision: u32) -> Option { + if self.is_within_bits(at_least_bits_precision) { + Some(self.resize_unchecked(at_least_bits_precision)) + } else { + None + } + } +} + +impl Resize for NonZero { + type Output = Self; + + fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output { + NonZero(self.0.resize_unchecked(at_least_bits_precision)) + } + + fn try_resize(self, at_least_bits_precision: u32) -> Option { + self.0.try_resize(at_least_bits_precision).map(NonZero) + } +} + +impl Resize for &NonZero { + type Output = NonZero; + + fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output { + NonZero((&self.0).resize_unchecked(at_least_bits_precision)) + } + + fn try_resize(self, at_least_bits_precision: u32) -> Option { + (&self.0).try_resize(at_least_bits_precision).map(NonZero) } } diff --git a/src/uint/boxed/add.rs b/src/uint/boxed/add.rs index 183f7c611..ba6ac69e9 100644 --- a/src/uint/boxed/add.rs +++ b/src/uint/boxed/add.rs @@ -231,6 +231,7 @@ impl AddAssign for BoxedUint { #[allow(clippy::unwrap_used)] mod tests { use super::{BoxedUint, CheckedAdd, Limb}; + use crate::Resize; #[test] fn adc_no_carry() { @@ -267,7 +268,7 @@ mod tests { #[test] fn add_assign() { - let mut h = BoxedUint::one().widen(1024); + let mut h = BoxedUint::one().resize(1024); h += BoxedUint::one(); } diff --git a/src/uint/boxed/gcd.rs b/src/uint/boxed/gcd.rs index 2d2794a4a..9e50198f9 100644 --- a/src/uint/boxed/gcd.rs +++ b/src/uint/boxed/gcd.rs @@ -46,7 +46,7 @@ impl Gcd for Odd { #[cfg(test)] mod tests { - use crate::{BoxedUint, Gcd}; + use crate::{BoxedUint, Gcd, Resize}; #[test] fn gcd_relatively_prime() { @@ -95,7 +95,7 @@ mod tests { #[test] fn gcd_different_sizes() { // Test that gcd works for boxed Uints with different numbers of limbs - let f = BoxedUint::from(4391633u32).widen(128).to_odd().unwrap(); + let f = BoxedUint::from(4391633u32).resize(128).to_odd().unwrap(); let g = BoxedUint::from(2022161u32); let gcd = f.gcd(&g); assert_eq!(gcd, BoxedUint::from(1763u32)); @@ -104,7 +104,7 @@ mod tests { #[test] fn gcd_vartime_different_sizes() { // Test that gcd works for boxed Uints with different numbers of limbs - let f = BoxedUint::from(4391633u32).widen(128).to_odd().unwrap(); + let f = BoxedUint::from(4391633u32).resize(128).to_odd().unwrap(); let g = BoxedUint::from(2022161u32); let gcd = f.gcd_vartime(&g); assert_eq!(gcd, BoxedUint::from(1763u32)); diff --git a/src/uint/boxed/mul.rs b/src/uint/boxed/mul.rs index 862807ca1..7a082a11a 100644 --- a/src/uint/boxed/mul.rs +++ b/src/uint/boxed/mul.rs @@ -1,7 +1,7 @@ //! [`BoxedUint`] multiplication operations. use crate::{ - BoxedUint, CheckedMul, Limb, WideningMul, Wrapping, WrappingMul, Zero, + BoxedUint, CheckedMul, Limb, Resize, WideningMul, Wrapping, WrappingMul, Zero, uint::mul::{ karatsuba::{KARATSUBA_MIN_STARTING_LIMBS, karatsuba_mul_limbs, karatsuba_square_limbs}, mul_limbs, square_limbs, @@ -33,7 +33,7 @@ impl BoxedUint { /// Perform wrapping multiplication, wrapping to the width of `self`. pub fn wrapping_mul(&self, rhs: &Self) -> Self { - self.mul(rhs).shorten(self.bits_precision()) + self.mul(rhs).resize_unchecked(self.bits_precision()) } /// Multiply `self` by itself. diff --git a/src/uint/boxed/sub.rs b/src/uint/boxed/sub.rs index bd0c1d089..4ba912d2c 100644 --- a/src/uint/boxed/sub.rs +++ b/src/uint/boxed/sub.rs @@ -236,6 +236,7 @@ impl SubAssign for BoxedUint { #[allow(clippy::unwrap_used)] mod tests { use super::{BoxedUint, CheckedSub, Limb}; + use crate::Resize; #[test] fn sbb_no_borrow() { @@ -276,7 +277,7 @@ mod tests { #[test] fn sub_assign() { - let mut h = BoxedUint::one().widen(1024); + let mut h = BoxedUint::one().resize(1024); h -= BoxedUint::one(); } } diff --git a/tests/boxed_monty_form.rs b/tests/boxed_monty_form.rs index 93eb08538..ee99978cc 100644 --- a/tests/boxed_monty_form.rs +++ b/tests/boxed_monty_form.rs @@ -6,31 +6,22 @@ mod common; use common::to_biguint; use crypto_bigint::{ - BoxedUint, Integer, Inverter, Limb, Odd, PrecomputeInverter, + BoxedUint, Integer, Inverter, Limb, Odd, PrecomputeInverter, Resize, modular::{BoxedMontyForm, BoxedMontyParams}, }; use num_bigint::BigUint; use num_integer::Integer as _; use num_modular::ModularUnaryOps; use proptest::prelude::*; -use std::cmp::Ordering; fn retrieve_biguint(monty_form: &BoxedMontyForm) -> BigUint { to_biguint(&monty_form.retrieve()) } fn reduce(n: &BoxedUint, p: BoxedMontyParams) -> BoxedMontyForm { - let bits_precision = p.modulus().bits_precision(); - - let n = match n.bits_precision().cmp(&bits_precision) { - Ordering::Less => n.widen(bits_precision), - Ordering::Equal => n.clone(), - Ordering::Greater => n.shorten(bits_precision), - }; - let n_reduced = n .rem_vartime(p.modulus().as_nz_ref()) - .widen(p.bits_precision()); + .resize(p.bits_precision()); BoxedMontyForm::new(n_reduced, p) } diff --git a/tests/boxed_uint.rs b/tests/boxed_uint.rs index ccacea40d..5f34ef7d2 100644 --- a/tests/boxed_uint.rs +++ b/tests/boxed_uint.rs @@ -5,8 +5,7 @@ mod common; use common::to_biguint; -use core::cmp::Ordering; -use crypto_bigint::{BitOps, BoxedUint, CheckedAdd, Gcd, Integer, Limb, NonZero}; +use crypto_bigint::{BitOps, BoxedUint, CheckedAdd, Gcd, Integer, Limb, NonZero, Resize}; use num_bigint::BigUint; use num_integer::Integer as _; use num_modular::ModularUnaryOps; @@ -25,16 +24,7 @@ fn to_uint(big_uint: BigUint) -> BoxedUint { fn reduce(x: &BoxedUint, n: &BoxedUint) -> BoxedUint { let bits_precision = n.bits_precision(); let modulus = NonZero::new(n.clone()).expect("odd n"); - - let x = match x.bits_precision().cmp(&bits_precision) { - Ordering::Less => x.widen(bits_precision), - Ordering::Equal => x.clone(), - Ordering::Greater => x.shorten(bits_precision), - }; - - let x_reduced = x.rem_vartime(&modulus); - debug_assert_eq!(x_reduced.bits_precision(), bits_precision); - x_reduced + x.rem_vartime(&modulus).resize(bits_precision) } prop_compose! { @@ -48,17 +38,9 @@ prop_compose! { } prop_compose! { /// Generate a pair of random `BoxedUint`s with the same precision. - fn uint_pair()(mut a in uint(), mut b in uint()) -> (BoxedUint, BoxedUint) { - match a.bits_precision().cmp(&b.bits_precision()) { - Ordering::Greater => { - b = b.widen(a.bits_precision()); - } - Ordering::Less => { - a = a.widen(b.bits_precision()); - }, - _ => () - }; - (a, b) + fn uint_pair()(a in uint(), b in uint()) -> (BoxedUint, BoxedUint) { + let bits_precision = core::cmp::max(a.bits_precision(), b.bits_precision()); + (a.resize(bits_precision), b.resize(bits_precision)) } } prop_compose! { diff --git a/tests/safegcd.rs b/tests/safegcd.rs index 628582015..cba97732b 100644 --- a/tests/safegcd.rs +++ b/tests/safegcd.rs @@ -10,7 +10,7 @@ use num_traits::One; use proptest::prelude::*; #[cfg(feature = "alloc")] -use crypto_bigint::BoxedUint; +use crypto_bigint::{BoxedUint, Resize}; /// Example prime number (NIST P-256 curve order) const P: Odd = @@ -62,7 +62,7 @@ proptest! { #[test] fn boxed_inv_mod(x in boxed_uint()) { let p = Odd::::from(&P); - let x = x.rem_vartime(p.as_nz_ref()).widen(p.bits_precision()); + let x = x.rem_vartime(p.as_nz_ref()).resize(p.bits_precision()); let x_bi = to_biguint(&x); let p_bi = to_biguint(&P);