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
72 changes: 46 additions & 26 deletions elliptic-curve/src/ecdh.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Elliptic Curve Diffie-Hellman (Ephemeral) Support.
//!
//! This module contains a generic ECDH implementation which is usable with
//! any elliptic curve which implements the [`Arithmetic`] trait (presently
//! any elliptic curve which implements the [`ProjectiveArithmetic`] trait (presently
//! the `k256` and `p256` crates)
//!
//! # Usage
Expand All @@ -23,13 +23,14 @@
use crate::{
consts::U1,
generic_array::ArrayLength,
point::Generator,
scalar::NonZeroScalar,
sec1::{self, FromEncodedPoint, UncompressedPointSize, UntaggedPointSize},
weierstrass::Curve,
Arithmetic, Error, FieldBytes,
AffinePoint, Error, FieldBytes, ProjectiveArithmetic, Scalar,
};
use core::ops::{Add, Mul};
use ff::PrimeField;
use group::{Curve as _, Group};
use rand_core::{CryptoRng, RngCore};
use zeroize::Zeroize;

Expand All @@ -44,38 +45,43 @@ pub type PublicKey<C> = sec1::EncodedPoint<C>;
/// to avoid being persisted.
pub struct EphemeralSecret<C>
where
C: Curve + Arithmetic,
C::Scalar: Zeroize,
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>> + Zeroize,
{
scalar: NonZeroScalar<C>,
}

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

/// Get the public key associated with this ephemeral secret.
///
/// The `compress` flag enables point compression.
pub fn public_key(&self) -> PublicKey<C> {
PublicKey::from(C::AffinePoint::generator() * self.scalar)
(C::ProjectivePoint::generator() * &self.scalar)
.to_affine()
.into()
}

/// Compute a Diffie-Hellman shared secret from an ephemeral secret and the
/// public key of the other participant in the exchange.
pub fn diffie_hellman(&self, public_key: &PublicKey<C>) -> Result<SharedSecret<C>, Error> {
let affine_point = C::AffinePoint::from_encoded_point(public_key);
let affine_point = AffinePoint::<C>::from_encoded_point(public_key);

if affine_point.is_some().into() {
let shared_secret = affine_point.unwrap() * self.scalar;
Expand All @@ -88,10 +94,11 @@ where

impl<C> From<&EphemeralSecret<C>> for PublicKey<C>
where
C: Curve + Arithmetic,
C::Scalar: Clone + Zeroize,
C::AffinePoint: FromEncodedPoint<C> + Mul<NonZeroScalar<C>, Output = C::AffinePoint> + Zeroize,
PublicKey<C>: From<C::AffinePoint>,
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>> + Clone + Zeroize,
AffinePoint<C>: FromEncodedPoint<C> + Mul<NonZeroScalar<C>, Output = AffinePoint<C>> + Zeroize,
PublicKey<C>: From<AffinePoint<C>>,
UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
UncompressedPointSize<C>: ArrayLength<u8>,
{
Expand All @@ -102,8 +109,9 @@ where

impl<C> Zeroize for EphemeralSecret<C>
where
C: Curve + Arithmetic,
C::Scalar: Zeroize,
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>> + Zeroize,
{
fn zeroize(&mut self) {
self.scalar.zeroize()
Expand All @@ -112,8 +120,9 @@ where

impl<C> Drop for EphemeralSecret<C>
where
C: Curve + Arithmetic,
C::Scalar: Zeroize,
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>> + Zeroize,
{
fn drop(&mut self) {
self.zeroize();
Expand All @@ -133,15 +142,22 @@ where
///
/// Instead, the resulting value should be used as input to a Key Derivation
/// Function (KDF) or cryptographic hash function to produce a symmetric key.
pub struct SharedSecret<C: Curve + Arithmetic> {
pub struct SharedSecret<C>
where
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>,
{
/// Computed secret value
secret_bytes: FieldBytes<C>,
}

impl<C> SharedSecret<C>
where
C: Curve + Arithmetic,
C::AffinePoint: Zeroize,
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>,
AffinePoint<C>: Zeroize,
UntaggedPointSize<C>: Add<U1> + ArrayLength<u8>,
UncompressedPointSize<C>: ArrayLength<u8>,
{
Expand All @@ -165,7 +181,9 @@ where

impl<C> Zeroize for SharedSecret<C>
where
C: Curve + Arithmetic,
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>,
{
fn zeroize(&mut self) {
self.secret_bytes.zeroize()
Expand All @@ -174,7 +192,9 @@ where

impl<C> Drop for SharedSecret<C>
where
C: Curve + Arithmetic,
C: Curve + ProjectiveArithmetic,
FieldBytes<C>: From<Scalar<C>> + for<'r> From<&'r Scalar<C>>,
Scalar<C>: PrimeField<Repr = FieldBytes<C>>,
{
fn drop(&mut self) {
self.zeroize();
Expand Down
53 changes: 13 additions & 40 deletions elliptic-curve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ extern crate std;

pub mod error;
pub mod ops;
pub mod point;
pub mod sec1;
pub mod util;
pub mod weierstrass;

#[cfg(feature = "arithmetic")]
#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
pub mod point;
#[cfg(feature = "arithmetic")]
#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
pub mod scalar;
Expand All @@ -50,13 +52,17 @@ pub use generic_array::{self, typenum::consts};
pub use rand_core;
pub use subtle;

// TODO(tarcieri): source this via ff crate: https://github.com/zkcrypto/ff/pull/40
#[cfg(feature = "arithmetic")]
pub use bitvec::view::BitView;
pub use self::{
point::{AffinePoint, ProjectiveArithmetic, ProjectivePoint},
scalar::Scalar,
};
#[cfg(feature = "arithmetic")]
pub use bitvec::view::BitView; // TODO: https://github.com/zkcrypto/ff/pull/40
#[cfg(feature = "arithmetic")]
pub use ff;
pub use ff::{self, Field};
#[cfg(feature = "arithmetic")]
pub use group;
pub use group::{self, Group};

#[cfg(feature = "digest")]
pub use digest::{self, Digest};
Expand All @@ -71,15 +77,6 @@ pub use zeroize;

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

#[cfg(feature = "arithmetic")]
use core::ops::Mul;
#[cfg(feature = "arithmetic")]
use subtle::ConstantTimeEq;

/// Byte representation of a base/scalar field element of a given curve.
pub type FieldBytes<C> = GenericArray<u8, <C as Curve>::FieldSize>;

/// Elliptic curve.
///
Expand All @@ -98,32 +95,8 @@ pub trait Curve: Clone + Debug + Default + Eq + Ord + Send + Sync {
type FieldSize: ArrayLength<u8> + Add + Eq + Ord + Unsigned;
}

/// Elliptic curve with arithmetic implementation.
#[cfg(feature = "arithmetic")]
#[cfg_attr(docsrs, doc(cfg(feature = "arithmetic")))]
pub trait Arithmetic: Curve {
/// Scalar field element modulo the curve's order.
type Scalar: ff::PrimeField
+ ConstantTimeEq
+ Default
+ FromFieldBytes<Self>
+ Into<FieldBytes<Self>>;

/// Elliptic curve point in affine coordinates.
type AffinePoint: ConditionallySelectable
+ Mul<scalar::NonZeroScalar<Self>, Output = Self::AffinePoint>
+ point::Generator;

/// Elliptic curve point in projective coordinates.
type ProjectivePoint: group::Curve<AffineRepr = Self::AffinePoint>
+ group::Group<Scalar = Self::Scalar>;
}

/// Decode the given serialized field element
pub trait FromFieldBytes<C: Curve>: ConditionallySelectable + Sized {
/// Try to decode this object from bytes
fn from_field_bytes(bytes: &FieldBytes<C>) -> CtOption<Self>;
}
/// Byte representation of a base/scalar field element of a given curve.
pub type FieldBytes<C> = GenericArray<u8, <C as Curve>::FieldSize>;

/// Instantiate this type from the output of a digest.
///
Expand Down
29 changes: 19 additions & 10 deletions elliptic-curve/src/point.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
//! Traits for elliptic curve points
//! Elliptic curve points.

/// Point compression settings
pub trait Compression {
/// Should point compression be applied by default?
const COMPRESS_POINTS: bool;
}
use crate::{Curve, FieldBytes, Scalar};

/// Obtain the generator point.
pub trait Generator {
/// Get the generator point for this elliptic curve
fn generator() -> Self;
/// Elliptic curve with projective arithmetic implementation.
pub trait ProjectiveArithmetic: Curve
where
FieldBytes<Self>: From<Scalar<Self>> + for<'r> From<&'r Scalar<Self>>,
Scalar<Self>: ff::PrimeField<Repr = FieldBytes<Self>>,
{
/// Elliptic curve point in projective coordinates.
type ProjectivePoint: group::Curve;
}

/// Affine point type for a given curve with a [`ProjectiveArithmetic`]
/// implementation.
pub type AffinePoint<C> =
<<C as ProjectiveArithmetic>::ProjectivePoint as group::Curve>::AffineRepr;

/// Projective point type for a given curve with a [`ProjectiveArithmetic`]
/// implementation.
pub type ProjectivePoint<C> = <C as ProjectiveArithmetic>::ProjectivePoint;
Loading