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
2 changes: 1 addition & 1 deletion crypto-bigint/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
3 changes: 3 additions & 0 deletions crypto-bigint/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
75 changes: 75 additions & 0 deletions crypto-bigint/src/traits.rs
Original file line number Diff line number Diff line change
@@ -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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why no requirements for Add, Mul etc?

Copy link
Member Author

@tarcieri tarcieri Sep 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those traits are presently only impl'd for Wrapping<UInt<_>> in order to be explicit about the wrapping vs checked behavior.

However, it would be possible to bound on Wrapping<Self> impl'ing them.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, in elliptic-curve I end up bounding on the modular arithmetic traits: https://github.com/RustCrypto/traits/pull/732/files#diff-58bf09549ae77b47fcc1f18c3335fd0f6a4eb49a1e3cee51332fe40dcfd66daaR113-R120

type UInt: bigint::AddMod<Output = Self::UInt>
        + bigint::Integer
        + bigint::NegMod<Output = Self::UInt>
        + bigint::Random
        + bigint::RandomMod
        + bigint::SubMod<Output = Self::UInt>
        + zeroize::Zeroize;

They could potentially be included in the Integer bounds.

Copy link
Member Author

@tarcieri tarcieri Sep 3, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I didn't add bounds on *Mod initially because they are only impl'd for a subset of the supported integer values

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah makes sens to wait for adding those bound, until we have a more complete set

'static
+ AsRef<[Limb]>
+ Copy
+ ConditionallySelectable
+ ConstantTimeEq
+ ConstantTimeGreater
+ ConstantTimeLess
+ Debug
+ Default
+ Encoding
+ Eq
+ From<u64>
+ 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<Rhs = Self> {
Expand Down
23 changes: 16 additions & 7 deletions crypto-bigint/src/uint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -105,6 +105,19 @@ impl<const LIMBS: usize> Default for UInt<LIMBS> {
}
}

impl<const LIMBS: usize> Integer for UInt<LIMBS>
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<const LIMBS: usize> fmt::Display for UInt<LIMBS> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::UpperHex::fmt(self, f)
Expand All @@ -131,11 +144,7 @@ impl<const LIMBS: usize> fmt::UpperHex for UInt<LIMBS> {

#[cfg(feature = "zeroize")]
#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
impl<const LIMBS: usize> Zeroize for UInt<LIMBS> {
fn zeroize(&mut self) {
self.limbs.zeroize();
}
}
impl<const LIMBS: usize> DefaultIsZeroes for UInt<LIMBS> {}

// TODO(tarcieri): use `const_evaluatable_checked` when stable to make generic around bits.
impl_uint_aliases! {
Expand Down
18 changes: 17 additions & 1 deletion crypto-bigint/src/uint/rand.rs
Original file line number Diff line number Diff line change
@@ -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<const LIMBS: usize> UInt<LIMBS> {
/// Generate a cryptographically secure random [`UInt`].
Expand Down Expand Up @@ -39,3 +41,17 @@ impl<const LIMBS: usize> UInt<LIMBS> {
}
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
impl<const LIMBS: usize> Random for UInt<LIMBS> {
fn random(rng: impl CryptoRng + RngCore) -> Self {
Self::random(rng)
}
}

#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
impl<const LIMBS: usize> RandomMod for UInt<LIMBS> {
fn random_mod(rng: impl CryptoRng + RngCore, modulus: &Self) -> Self {
Self::random_mod(rng, modulus)
}
}