From 7b6aca158614c5a329837002a9eea8ccd59073d2 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Fri, 3 Sep 2021 07:34:57 -0600 Subject: [PATCH] crypto-bigint: `Integer` trait Adds a trait encompassing the interesting bounds of `UInt`. Since traits like `elliptic_curve::Curve` can't yet be generic over `const LIMBS`, this trait provides a convenient way of wrapping up `UInt` behavior such that it's still usable without spelling out all of these bounds explicitly. --- crypto-bigint/Cargo.toml | 2 +- crypto-bigint/src/lib.rs | 3 ++ crypto-bigint/src/traits.rs | 75 ++++++++++++++++++++++++++++++++++ crypto-bigint/src/uint.rs | 23 +++++++---- crypto-bigint/src/uint/rand.rs | 18 +++++++- 5 files changed, 112 insertions(+), 9 deletions(-) diff --git a/crypto-bigint/Cargo.toml b/crypto-bigint/Cargo.toml index dd19664e..5a1e4406 100644 --- a/crypto-bigint/Cargo.toml +++ b/crypto-bigint/Cargo.toml @@ -20,7 +20,7 @@ subtle = { version = "2.4", default-features = false } # optional dependencies rand_core = { version = "0.6", optional = true } -zeroize = { version = "1", optional = true, default-features = false } +zeroize = { version = ">=1, <1.5", optional = true, default-features = false } [dev-dependencies] hex-literal = "0.3" diff --git a/crypto-bigint/src/lib.rs b/crypto-bigint/src/lib.rs index c438a992..1e4ad46b 100644 --- a/crypto-bigint/src/lib.rs +++ b/crypto-bigint/src/lib.rs @@ -63,6 +63,9 @@ pub use { generic_array::{self, typenum::consts}, }; +#[cfg(feature = "zeroize")] +pub use zeroize; + /// Number of bytes in a [`Limb`]. #[cfg(target_pointer_width = "32")] #[deprecated(since = "0.2.2", note = "use `Limb::BYTE_SIZE` instead")] diff --git a/crypto-bigint/src/traits.rs b/crypto-bigint/src/traits.rs index 085ae1de..b3551476 100644 --- a/crypto-bigint/src/traits.rs +++ b/crypto-bigint/src/traits.rs @@ -1,6 +1,81 @@ //! Traits provided by this crate use crate::Limb; +use core::fmt::Debug; +use subtle::{ + Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, +}; + +#[cfg(feature = "rand")] +use rand_core::{CryptoRng, RngCore}; + +/// Integer type. +pub trait Integer: + 'static + + AsRef<[Limb]> + + Copy + + ConditionallySelectable + + ConstantTimeEq + + ConstantTimeGreater + + ConstantTimeLess + + Debug + + Default + + Encoding + + Eq + + From + + Ord + + Send + + Sized + + Sync +{ + /// The value `0`. + const ZERO: Self; + + /// The value `1`. + const ONE: Self; + + /// Maximum value this integer can express. + const MAX: Self; + + /// Is this integer value equal to zero? + fn is_zero(&self) -> Choice { + self.ct_eq(&Self::ZERO) + } + + /// Is this integer value an odd number? + fn is_odd(&self) -> Choice; + + /// Is this integer value an even number? + fn is_even(&self) -> Choice { + !self.is_odd() + } +} + +/// Random number generation support. +#[cfg(feature = "rand")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand")))] +pub trait Random: Sized { + /// Generate a cryptographically secure random value. + fn random(rng: impl CryptoRng + RngCore) -> Self; +} + +/// Modular random number generation support. +#[cfg(feature = "rand")] +#[cfg_attr(docsrs, doc(cfg(feature = "rand")))] +pub trait RandomMod: Sized { + /// Generate a cryptographically secure random number which is less than + /// a given `modulus`. + /// + /// This function uses rejection sampling, a method which produces an + /// unbiased distribution of in-range values provided the underlying + /// [`CryptoRng`] is unbiased, but runs in variable-time. + /// + /// The variable-time nature of the algorithm should not pose a security + /// issue so long as the underlying random number generator is truly a + /// [`CryptoRng`], where previous outputs are unrelated to subsequent + /// outputs and do not reveal information about the RNG's internal state. + fn random_mod(rng: impl CryptoRng + RngCore, modulus: &Self) -> Self; +} /// Compute `self + rhs mod p`. pub trait AddMod { diff --git a/crypto-bigint/src/uint.rs b/crypto-bigint/src/uint.rs index f00a62a5..ead66d9c 100644 --- a/crypto-bigint/src/uint.rs +++ b/crypto-bigint/src/uint.rs @@ -26,12 +26,12 @@ mod array; #[cfg(feature = "rand")] mod rand; -use crate::{Concat, Encoding, Limb, Split}; +use crate::{Concat, Encoding, Integer, Limb, Split}; use core::fmt; use subtle::{Choice, ConditionallySelectable}; #[cfg(feature = "zeroize")] -use zeroize::Zeroize; +use zeroize::DefaultIsZeroes; /// Big unsigned integer. /// @@ -105,6 +105,19 @@ impl Default for UInt { } } +impl Integer for UInt +where + Self: Encoding, +{ + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; + const MAX: Self = Self::MAX; + + fn is_odd(&self) -> Choice { + self.is_odd() + } +} + impl fmt::Display for UInt { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::UpperHex::fmt(self, f) @@ -131,11 +144,7 @@ impl fmt::UpperHex for UInt { #[cfg(feature = "zeroize")] #[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))] -impl Zeroize for UInt { - fn zeroize(&mut self) { - self.limbs.zeroize(); - } -} +impl DefaultIsZeroes for UInt {} // TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits. impl_uint_aliases! { diff --git a/crypto-bigint/src/uint/rand.rs b/crypto-bigint/src/uint/rand.rs index 683dd652..86813cca 100644 --- a/crypto-bigint/src/uint/rand.rs +++ b/crypto-bigint/src/uint/rand.rs @@ -1,10 +1,12 @@ //! Random number generator support +// TODO(tarcieri): use `Random` and `RandomMod` impls exclusively in next breaking release use super::UInt; -use crate::Limb; +use crate::{Limb, Random, RandomMod}; use rand_core::{CryptoRng, RngCore}; use subtle::ConstantTimeLess; +// TODO(tarcieri): replace this `impl` block with `impl Random`/`impl RandomMod` #[cfg_attr(docsrs, doc(cfg(feature = "rand")))] impl UInt { /// Generate a cryptographically secure random [`UInt`]. @@ -39,3 +41,17 @@ impl UInt { } } } + +#[cfg_attr(docsrs, doc(cfg(feature = "rand")))] +impl Random for UInt { + fn random(rng: impl CryptoRng + RngCore) -> Self { + Self::random(rng) + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "rand")))] +impl RandomMod for UInt { + fn random_mod(rng: impl CryptoRng + RngCore, modulus: &Self) -> Self { + Self::random_mod(rng, modulus) + } +}