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
18 changes: 9 additions & 9 deletions elliptic-curve/src/ecdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use crate::{
scalar::NonZeroScalar,
sec1::{self, FromEncodedPoint, UncompressedPointSize, UntaggedPointSize},
weierstrass::Curve,
Arithmetic, ElementBytes, Error, Generate,
Arithmetic, ElementBytes, Error,
};
use core::ops::{Add, Mul};
use rand_core::{CryptoRng, RngCore};
Expand All @@ -45,23 +45,23 @@ pub type PublicKey<C> = sec1::EncodedPoint<C>;
pub struct EphemeralSecret<C>
where
C: Curve + Arithmetic,
C::Scalar: Generate + Zeroize,
C::Scalar: Zeroize,
{
scalar: NonZeroScalar<C>,
}

impl<C> EphemeralSecret<C>
where
C: Curve + Arithmetic,
C::Scalar: Clone + Generate + Zeroize,
C::Scalar: Clone + Zeroize,
C::AffinePoint: FromEncodedPoint<C> + Mul<NonZeroScalar<C>, Output = C::AffinePoint> + Zeroize,
PublicKey<C>: From<C::AffinePoint>,
UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
UncompressedPointSize<C>: ArrayLength<u8>,
{
/// Generate a new [`EphemeralSecret`].
pub fn generate(rng: impl CryptoRng + RngCore) -> Self {
let scalar = NonZeroScalar::generate(rng);
/// Generate a cryptographically random [`EphemeralSecret`].
pub fn random(rng: impl CryptoRng + RngCore) -> Self {
let scalar = NonZeroScalar::random(rng);
Self { scalar }
}

Expand Down Expand Up @@ -89,7 +89,7 @@ where
impl<C> From<&EphemeralSecret<C>> for PublicKey<C>
where
C: Curve + Arithmetic,
C::Scalar: Clone + Generate + Zeroize,
C::Scalar: Clone + Zeroize,
C::AffinePoint: FromEncodedPoint<C> + Mul<NonZeroScalar<C>, Output = C::AffinePoint> + Zeroize,
PublicKey<C>: From<C::AffinePoint>,
UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
Expand All @@ -103,7 +103,7 @@ where
impl<C> Zeroize for EphemeralSecret<C>
where
C: Curve + Arithmetic,
C::Scalar: Generate + Zeroize,
C::Scalar: Zeroize,
{
fn zeroize(&mut self) {
self.scalar.zeroize()
Expand All @@ -113,7 +113,7 @@ where
impl<C> Drop for EphemeralSecret<C>
where
C: Curve + Arithmetic,
C::Scalar: Generate + Zeroize,
C::Scalar: Zeroize,
{
fn drop(&mut self) {
self.zeroize();
Expand Down
9 changes: 0 additions & 9 deletions elliptic-curve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ pub use zeroize;

use core::{fmt::Debug, ops::Add};
use generic_array::{typenum::Unsigned, ArrayLength, GenericArray};
use rand_core::{CryptoRng, RngCore};
use subtle::{ConditionallySelectable, CtOption};

#[cfg(feature = "arithmetic")]
Expand Down Expand Up @@ -124,14 +123,6 @@ pub trait FromBytes: ConditionallySelectable + Sized {
fn from_bytes(bytes: &GenericArray<u8, Self::Size>) -> CtOption<Self>;
}

/// Randomly generate a value.
///
/// Primarily intended for use with scalar types for a particular curve.
pub trait Generate {
/// Generate a random element of this type using the provided [`CryptoRng`]
fn generate(rng: impl CryptoRng + RngCore) -> Self;
}

/// Instantiate this type from the output of a digest.
///
/// This can be used for implementing hash-to-scalar (e.g. as in ECDSA) or
Expand Down
11 changes: 10 additions & 1 deletion elliptic-curve/src/ops.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Traits for arithmetic operations on elliptic curve field elements

pub use core::ops::{Add, Mul};
pub use core::ops::{Add, AddAssign, Mul, Neg, Sub, SubAssign};

use subtle::CtOption;

Expand All @@ -12,3 +12,12 @@ pub trait Invert {
/// Invert a field element.
fn invert(&self) -> CtOption<Self::Output>;
}

#[cfg(feature = "arithmetic")]
impl<F: ff::Field> Invert for F {
type Output = F;

fn invert(&self) -> CtOption<F> {
ff::Field::invert(self)
}
}
36 changes: 16 additions & 20 deletions elliptic-curve/src/scalar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
use crate::{
ops::Invert,
rand_core::{CryptoRng, RngCore},
Arithmetic, Curve, ElementBytes, FromBytes, Generate,
Arithmetic, Curve, ElementBytes, FromBytes,
};
use bitvec::{array::BitArray, order::Lsb0};
use core::ops::Deref;
use ff::Field;
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption};

#[cfg(feature = "zeroize")]
Expand All @@ -32,6 +33,18 @@ impl<C> NonZeroScalar<C>
where
C: Curve + Arithmetic,
{
/// Generate a random `NonZeroScalar`
pub fn random(mut rng: impl CryptoRng + RngCore) -> Self {
// Use rejection sampling to eliminate zero values
loop {
let result = Self::new(C::Scalar::random(&mut rng));

if result.is_some().into() {
break result.unwrap();
}
}
}

/// Create a [`NonZeroScalar`] from a scalar, performing a constant-time
/// check that it's non-zero.
pub fn new(scalar: C::Scalar) -> CtOption<Self> {
Expand Down Expand Up @@ -103,28 +116,11 @@ where
C: Curve + Arithmetic,
C::Scalar: Invert,
{
type Output = <C::Scalar as Invert>::Output;
type Output = C::Scalar;

/// Perform a scalar inversion
fn invert(&self) -> CtOption<Self::Output> {
self.scalar.invert()
}
}

impl<C> Generate for NonZeroScalar<C>
where
C: Curve + Arithmetic,
C::Scalar: Generate,
{
fn generate(mut rng: impl CryptoRng + RngCore) -> Self {
// Use rejection sampling to eliminate zero values
loop {
let result = Self::new(C::Scalar::generate(&mut rng));

if result.is_some().into() {
break result.unwrap();
}
}
ff::Field::invert(&self.scalar)
}
}

Expand Down
28 changes: 13 additions & 15 deletions elliptic-curve/src/secret_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use core::{
use generic_array::{typenum::Unsigned, GenericArray};

#[cfg(feature = "arithmetic")]
use crate::{scalar::NonZeroScalar, Arithmetic, Generate};
use crate::{scalar::NonZeroScalar, Arithmetic};
#[cfg(feature = "arithmetic")]
use rand_core::{CryptoRng, RngCore};

Expand All @@ -31,6 +31,18 @@ pub struct SecretKey<C: Curve> {
}

impl<C: Curve> SecretKey<C> {
/// Generate a random [`SecretKey`]
#[cfg(feature = "arithmetic")]
#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
pub fn random(rng: impl CryptoRng + RngCore) -> Self
where
C: Arithmetic,
{
Self {
scalar: NonZeroScalar::<C>::random(rng).into(),
}
}

/// Create a new secret key from a serialized scalar value
pub fn new(bytes: ElementBytes<C>) -> Self {
Self { scalar: bytes }
Expand Down Expand Up @@ -67,20 +79,6 @@ impl<C: Curve> Debug for SecretKey<C> {
}
}

#[cfg(feature = "arithmetic")]
impl<C> Generate for SecretKey<C>
where
C: Curve + Arithmetic,
C::Scalar: Generate + Into<ElementBytes<C>>,
{
/// Generate a new [`SecretKey`]
fn generate(rng: impl CryptoRng + RngCore) -> Self {
Self {
scalar: NonZeroScalar::<C>::generate(rng).into(),
}
}
}

#[cfg(feature = "zeroize")]
impl<C: Curve> Drop for SecretKey<C> {
fn drop(&mut self) {
Expand Down