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
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion elliptic-curve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ features = ["hybrid-array", "rand_core", "subtle", "zeroize"]
[dependencies]
array = { package = "hybrid-array", version = "0.4", default-features = false, features = ["zeroize"] }
base16ct = "1"
common = { package = "crypto-common", version = "0.2.0-rc.9", features = ["rand_core"], path = "../crypto-common" }
rand_core = { version = "0.10.0-rc-3", default-features = false }
subtle = { version = "2.6", default-features = false }
zeroize = { version = "1.7", default-features = false }
Expand Down Expand Up @@ -69,7 +70,7 @@ critical-section = ["basepoint-table", "once_cell/critical-section"]
bits = ["arithmetic", "ff/bits"]
dev = ["arithmetic", "dep:hex-literal", "pem", "pkcs8"]
ecdh = ["arithmetic", "digest", "dep:hkdf"]
getrandom = ["dep:getrandom", "arithmetic", "bigint/getrandom"]
getrandom = ["dep:getrandom", "arithmetic", "bigint/getrandom", "common/getrandom"]
group = ["dep:group", "ff"]
pkcs8 = ["dep:pkcs8", "sec1"]
pem = ["dep:pem-rfc7468", "alloc", "arithmetic", "pkcs8/pem", "sec1/pem"]
Expand Down
4 changes: 4 additions & 0 deletions elliptic-curve/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
scalar::{FromUintUnchecked, IsHigh},
};
use bigint::modular::Retrieve;
use common::Generate;
use core::fmt::Debug;
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};
use zeroize::DefaultIsZeroes;
Expand All @@ -27,6 +28,7 @@ pub trait CurveArithmetic: Curve {
+ DefaultIsZeroes
+ Eq
+ From<NonIdentity<Self::AffinePoint>>
+ Generate
+ PartialEq
+ Sized
+ Send
Expand All @@ -52,6 +54,7 @@ pub trait CurveArithmetic: Curve {
+ DefaultIsZeroes
+ From<Self::AffinePoint>
+ From<NonIdentity<Self::ProjectivePoint>>
+ Generate
+ Into<Self::AffinePoint>
+ LinearCombination<[(Self::ProjectivePoint, Self::Scalar)]>
+ LinearCombination<[(Self::ProjectivePoint, Self::Scalar); 2]>
Expand All @@ -78,6 +81,7 @@ pub trait CurveArithmetic: Curve {
+ From<NonZeroScalar<Self>>
+ From<ScalarValue<Self>>
+ FromUintUnchecked<Uint = Self::Uint>
+ Generate
+ Into<FieldBytes<Self>>
+ Into<ScalarValue<Self>>
+ Into<Self::Uint>
Expand Down
27 changes: 26 additions & 1 deletion elliptic-curve/src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! the traits in this crate.

use crate::{
BatchNormalize, Curve, CurveArithmetic, CurveGroup, FieldBytesEncoding, PrimeCurve,
BatchNormalize, Curve, CurveArithmetic, CurveGroup, FieldBytesEncoding, Generate, PrimeCurve,
array::typenum::U32,
bigint::{Limb, Odd, U256, modular::Retrieve},
ctutils,
Expand All @@ -31,6 +31,7 @@ use alloc::vec::Vec;

#[cfg(feature = "bits")]
use ff::PrimeFieldBits;
use rand_core::TryCryptoRng;

/// Pseudo-coordinate for fixed-based scalar mult output
pub const PSEUDO_COORDINATE_FIXED_BASE_MUL: [u8; 32] =
Expand Down Expand Up @@ -176,6 +177,14 @@ impl PrimeFieldBits for Scalar {
}
}

impl Generate for Scalar {
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
rng: &mut R,
) -> core::result::Result<Self, R::Error> {
ScalarValue::try_generate_from_rng(rng).map(Self)
}
}

impl AsRef<Scalar> for Scalar {
fn as_ref(&self) -> &Scalar {
self
Expand Down Expand Up @@ -548,6 +557,14 @@ impl From<NonIdentity<AffinePoint>> for AffinePoint {
}
}

impl Generate for AffinePoint {
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
_rng: &mut R,
) -> core::result::Result<Self, R::Error> {
unimplemented!()
}
}

impl FromEncodedPoint<MockCurve> for AffinePoint {
fn from_encoded_point(encoded_point: &EncodedPoint) -> ctutils::CtOption<Self> {
let point = if encoded_point.is_identity() {
Expand Down Expand Up @@ -686,6 +703,14 @@ impl From<ProjectivePoint> for AffinePoint {
}
}

impl Generate for ProjectivePoint {
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
_rng: &mut R,
) -> core::result::Result<Self, R::Error> {
unimplemented!()
}
}

impl FromEncodedPoint<MockCurve> for ProjectivePoint {
fn from_encoded_point(_point: &EncodedPoint) -> ctutils::CtOption<Self> {
unimplemented!();
Expand Down
38 changes: 21 additions & 17 deletions elliptic-curve/src/ecdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,10 @@ use crate::{
AffinePoint, Curve, CurveArithmetic, CurveGroup, FieldBytes, NonZeroScalar, ProjectivePoint,
PublicKey, point::AffineCoordinates,
};
use common::Generate;
use core::{borrow::Borrow, fmt};
use hkdf::Hkdf;
use rand_core::TryCryptoRng;
use rand_core::{CryptoRng, TryCryptoRng};
use zeroize::{Zeroize, ZeroizeOnDrop};

/// Low-level Elliptic Curve Diffie-Hellman (ECDH) function.
Expand Down Expand Up @@ -71,16 +72,15 @@ where

/// Ephemeral Diffie-Hellman Secret.
///
/// These are ephemeral "secret key" values which are deliberately designed
/// to avoid being persisted.
/// These are ephemeral "secret key" values which are deliberately designed to avoid persistence.
///
/// To perform an ephemeral Diffie-Hellman exchange, do the following:
///
/// - Have each participant generate an [`EphemeralSecret`] value
/// - Have each participant generate an [`EphemeralSecret`] value using the [`Generate`] trait
/// - Compute the [`PublicKey`] for that value
/// - Have each peer provide their [`PublicKey`] to their counterpart
/// - Use [`EphemeralSecret`] and the other participant's [`PublicKey`]
/// to compute a [`SharedSecret`] value.
/// to compute a [`SharedSecret`] value using the [`EphemeralSecret::diffie_hellman`] function
///
/// # ⚠️ SECURITY WARNING ⚠️
///
Expand All @@ -103,25 +103,21 @@ impl<C: CurveArithmetic> fmt::Debug for EphemeralSecret<C> {
}
}

impl<C> EphemeralSecret<C>
impl<C> Generate for EphemeralSecret<C>
where
C: CurveArithmetic,
{
/// Generate a cryptographically random [`EphemeralSecret`].
#[cfg(feature = "getrandom")]
pub fn generate() -> Self {
Self {
scalar: NonZeroScalar::generate(),
}
}

/// Generate a cryptographically random [`EphemeralSecret`].
pub fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
Ok(Self {
scalar: NonZeroScalar::try_from_rng(rng)?,
scalar: NonZeroScalar::try_generate_from_rng(rng)?,
})
}
}

impl<C> EphemeralSecret<C>
where
C: CurveArithmetic,
{
/// Get the public key associated with this ephemeral secret.
///
/// The `compress` flag enables point compression.
Expand All @@ -134,6 +130,14 @@ where
pub fn diffie_hellman(&self, public_key: &PublicKey<C>) -> SharedSecret<C> {
diffie_hellman(self.scalar, public_key.as_affine())
}

/// DEPRECATED: Generate a cryptographically random [`EphemeralSecret`].
///
/// Use the [`Generate`] trait instead.
#[deprecated(since = "0.14.0", note = "use the `Generate` trait instead")]
pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
Self::generate_from_rng(rng)
}
}

impl<C> From<&EphemeralSecret<C>> for PublicKey<C>
Expand Down
2 changes: 2 additions & 0 deletions elliptic-curve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ pub use array;
pub use array::typenum::consts;
pub use bigint;
pub use bigint::ctutils;
pub use common;
pub use common::Generate;
pub use rand_core;
pub use subtle;
pub use zeroize;
Expand Down
62 changes: 23 additions & 39 deletions elliptic-curve/src/scalar/nonzero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
scalar::IsHigh,
};
use base16ct::HexDisplay;
use common::Generate;
use core::{
fmt,
ops::{Deref, Mul, MulAssign, Neg},
Expand Down Expand Up @@ -50,45 +51,6 @@ impl<C> NonZeroScalar<C>
where
C: CurveArithmetic,
{
/// Generate a random [`NonZeroScalar`].
///
/// # Panics
///
/// If the system's cryptographically secure RNG has an internal error.
#[cfg(feature = "getrandom")]
pub fn generate() -> Self {
// Use rejection sampling to eliminate invalid values
// While this method isn't constant-time, the attacker shouldn't learn
// anything about unrelated outputs so long as `rng` is a secure `CryptoRng`.
loop {
let mut repr = FieldBytes::<C>::default();
getrandom::fill(&mut repr).expect("RNG failure");
if let Some(result) = Self::from_repr(repr).into() {
break result;
}
}
}

/// Generate a random [`NonZeroScalar`].
pub fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
// Use rejection sampling to eliminate zero values.
// While this method isn't constant-time, the attacker shouldn't learn
// anything about unrelated outputs so long as `rng` is a secure `CryptoRng`.
loop {
if let Some(result) = Self::new(Scalar::<C>::try_from_rng(rng)?).into() {
break Ok(result);
}
}
}

/// Deprecated: Generate a random [`NonZeroScalar`].
#[cfg(feature = "arithmetic")]
#[deprecated(since = "0.14.0", note = "use `generate` or `try_from_rng` instead")]
pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
let Ok(ret) = Self::try_from_rng(rng);
ret
}

/// Create a [`NonZeroScalar`] from a scalar.
pub fn new(scalar: Scalar<C>) -> CtOption<Self> {
CtOption::new(Self { scalar }, !scalar.is_zero())
Expand Down Expand Up @@ -124,6 +86,12 @@ where
&*(scalars as *const [NonZeroScalar<C>] as *const [Scalar<C>])
}
}

/// Deprecated: Generate a random [`NonZeroScalar`].
#[deprecated(since = "0.14.0", note = "use the `Generate` trait instead")]
pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
Self::generate_from_rng(rng)
}
}

impl<C> AsRef<Scalar<C>> for NonZeroScalar<C>
Expand Down Expand Up @@ -268,6 +236,22 @@ where
}
}

impl<C> Generate for NonZeroScalar<C>
where
C: CurveArithmetic,
{
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
// Use rejection sampling to eliminate zero values.
// While this method isn't constant-time, the attacker shouldn't learn
// anything about unrelated outputs so long as `rng` is a secure `CryptoRng`.
loop {
if let Some(result) = Self::new(Scalar::<C>::try_generate_from_rng(rng)?).into() {
break Ok(result);
}
}
}
}

impl<C> Invert for NonZeroScalar<C>
where
C: CurveArithmetic,
Expand Down
51 changes: 32 additions & 19 deletions elliptic-curve/src/scalar/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,14 @@ use crate::{
scalar::{FromUintUnchecked, IsHigh},
};
use base16ct::HexDisplay;
use common::Generate;
use core::{
cmp::Ordering,
fmt,
ops::{Add, AddAssign, Neg, ShrAssign, Sub, SubAssign},
str,
};
use rand_core::CryptoRng;
use rand_core::{CryptoRng, TryCryptoRng};
use subtle::{
Choice, ConditionallySelectable, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess,
CtOption,
Expand Down Expand Up @@ -63,13 +64,6 @@ where
/// Scalar modulus.
pub const MODULUS: Odd<C::Uint> = C::ORDER;

/// Generate a random [`ScalarValue`].
pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
Self {
inner: C::Uint::random_mod_vartime(rng, Self::MODULUS.as_nz_ref()),
}
}

/// Create a new scalar from [`Curve::Uint`].
pub fn new(uint: C::Uint) -> CtOption<Self> {
CtOption::new(
Expand Down Expand Up @@ -123,6 +117,23 @@ where
pub fn to_uint(&self) -> C::Uint {
self.inner
}

/// Deprecated: Generate a random [`ScalarValue`].
#[deprecated(since = "0.14.0", note = "use the `Generate` trait instead")]
pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
Self::generate_from_rng(rng)
}
}

impl<C> From<u64> for ScalarValue<C>
where
C: Curve,
{
fn from(n: u64) -> Self {
Self {
inner: C::Uint::from(n),
}
}
}

impl<C> FromUintUnchecked for ScalarValue<C>
Expand All @@ -136,6 +147,19 @@ where
}
}

impl<C> Generate for ScalarValue<C>
where
C: Curve,
{
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(
rng: &mut R,
) -> core::result::Result<Self, R::Error> {
Ok(Self {
inner: C::Uint::try_random_mod_vartime(rng, Self::MODULUS.as_nz_ref())?,
})
}
}

#[cfg(feature = "arithmetic")]
impl<C> ScalarValue<C>
where
Expand Down Expand Up @@ -264,17 +288,6 @@ where
}
}

impl<C> From<u64> for ScalarValue<C>
where
C: Curve,
{
fn from(n: u64) -> Self {
Self {
inner: C::Uint::from(n),
}
}
}

impl<C> Add<ScalarValue<C>> for ScalarValue<C>
where
C: Curve,
Expand Down
Loading