Skip to content

Commit

Permalink
elliptic-curve: add AffineXCoordinate trait (#817)
Browse files Browse the repository at this point in the history
Protocols like ECDH and ECDSA rely on x-coordinate access.

We've tried various ways of trying to keep affine coordinate access out
of the public API, but it complicates generic implementations of these
protocols.

Most recently RustCrypto/signatures#395 attempted to add a trait which
encapsulated ECDSA signing, but a similar (or expaned version of the
same) trait is needed for verification.

All of these problems go away, and can be expressed with simple trait
bounds, if there is some way to access the x-coordinate of an
`AffinePoint` as serialized `FieldBytes`.

This commit adds such a trait: `AffineXCoordinate`, which is a mandatory
bound of `AffineArithmetic::AffinePoint`.
  • Loading branch information
tarcieri authored Nov 17, 2021
1 parent f484ed6 commit 7d81302
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 22 deletions.
3 changes: 2 additions & 1 deletion elliptic-curve/src/arithmetic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Elliptic curve arithmetic traits.
use crate::{Curve, FieldBytes, IsHigh, PrimeCurve, ScalarCore};
use crate::{AffineXCoordinate, Curve, FieldBytes, IsHigh, PrimeCurve, ScalarCore};
use core::fmt::Debug;
use subtle::{ConditionallySelectable, ConstantTimeEq};
use zeroize::DefaultIsZeroes;
Expand All @@ -10,6 +10,7 @@ use zeroize::DefaultIsZeroes;
pub trait AffineArithmetic: Curve + ScalarArithmetic {
/// Elliptic curve point in affine coordinates.
type AffinePoint: 'static
+ AffineXCoordinate<Self>
+ Copy
+ Clone
+ ConditionallySelectable
Expand Down
10 changes: 8 additions & 2 deletions elliptic-curve/src/dev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ use crate::{
sec1::{FromEncodedPoint, ToEncodedPoint},
subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption},
zeroize::DefaultIsZeroes,
AffineArithmetic, AlgorithmParameters, Curve, IsHigh, PrimeCurve, ProjectiveArithmetic,
ScalarArithmetic,
AffineArithmetic, AffineXCoordinate, AlgorithmParameters, Curve, IsHigh, PrimeCurve,
ProjectiveArithmetic, ScalarArithmetic,
};
use core::{
iter::Sum,
Expand Down Expand Up @@ -368,6 +368,12 @@ pub enum AffinePoint {
Other(EncodedPoint),
}

impl AffineXCoordinate<MockCurve> for AffinePoint {
fn x(&self) -> FieldBytes {
unimplemented!();
}
}

impl ConstantTimeEq for AffinePoint {
fn ct_eq(&self, _other: &Self) -> Choice {
unimplemented!();
Expand Down
23 changes: 15 additions & 8 deletions elliptic-curve/src/ecdh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
//! [SIGMA]: https://webee.technion.ac.il/~hugo/sigma-pdf.pdf
use crate::{
AffinePoint, Curve, FieldBytes, NonZeroScalar, ProjectiveArithmetic, ProjectivePoint, PublicKey,
AffineArithmetic, AffinePoint, AffineXCoordinate, Curve, FieldBytes, NonZeroScalar,
ProjectiveArithmetic, ProjectivePoint, PublicKey,
};
use core::borrow::Borrow;
use group::Curve as _;
Expand Down Expand Up @@ -60,13 +61,10 @@ pub fn diffie_hellman<C>(
) -> SharedSecret<C>
where
C: Curve + ProjectiveArithmetic,
SharedSecret<C>: for<'a> From<&'a AffinePoint<C>>,
{
let public_point = ProjectivePoint::<C>::from(*public_key.borrow());
let mut secret_point = (public_point * secret_key.borrow().as_ref()).to_affine();
let shared_secret = SharedSecret::from(&secret_point);
secret_point.zeroize();
shared_secret
let secret_point = (public_point * secret_key.borrow().as_ref()).to_affine();
SharedSecret::new(secret_point)
}

/// Ephemeral Diffie-Hellman Secret.
Expand Down Expand Up @@ -100,7 +98,6 @@ where
impl<C> EphemeralSecret<C>
where
C: Curve + ProjectiveArithmetic,
SharedSecret<C>: for<'a> From<&'a AffinePoint<C>>,
{
/// Generate a cryptographically random [`EphemeralSecret`].
pub fn random(rng: impl CryptoRng + RngCore) -> Self {
Expand All @@ -126,7 +123,6 @@ where
impl<C> From<&EphemeralSecret<C>> for PublicKey<C>
where
C: Curve + ProjectiveArithmetic,
SharedSecret<C>: for<'a> From<&'a AffinePoint<C>>,
{
fn from(ephemeral_secret: &EphemeralSecret<C>) -> Self {
ephemeral_secret.public_key()
Expand Down Expand Up @@ -172,6 +168,17 @@ pub struct SharedSecret<C: Curve> {
}

impl<C: Curve> SharedSecret<C> {
/// Create a new [`SharedSecret`] from an [`AffinePoint`] for this curve.
#[inline]
fn new(point: AffinePoint<C>) -> Self
where
C: AffineArithmetic,
{
Self {
secret_bytes: point.x(),
}
}

/// Shared secret value, serialized as bytes.
///
/// As noted in the comments for this struct, this value is non-uniform and
Expand Down
4 changes: 3 additions & 1 deletion elliptic-curve/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ mod jwk;

pub use crate::{
error::{Error, Result},
point::{DecompactPoint, DecompressPoint, PointCompaction, PointCompression},
point::{
AffineXCoordinate, DecompactPoint, DecompressPoint, PointCompaction, PointCompression,
},
scalar::{core::ScalarCore, IsHigh},
secret_key::SecretKey,
};
Expand Down
26 changes: 16 additions & 10 deletions elliptic-curve/src/point.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,10 @@
use crate::{Curve, FieldBytes};
use subtle::{Choice, CtOption};

/// Point compression settings.
pub trait PointCompression {
/// Should point compression be applied by default?
const COMPRESS_POINTS: bool;
}

/// Point compaction settings.
pub trait PointCompaction {
/// Should point compaction be applied by default?
const COMPACT_POINTS: bool;
/// Obtain the affine x-coordinate of an elliptic curve point.
pub trait AffineXCoordinate<C: Curve> {
/// Get the affine x-coordinate as a serialized field element.
fn x(&self) -> FieldBytes<C>;
}

/// Attempt to decompress an elliptic curve point from its x-coordinate and
Expand All @@ -27,3 +21,15 @@ pub trait DecompactPoint<C: Curve>: Sized {
/// Attempt to decompact an elliptic curve point
fn decompact(x: &FieldBytes<C>) -> CtOption<Self>;
}

/// Point compression settings.
pub trait PointCompression {
/// Should point compression be applied by default?
const COMPRESS_POINTS: bool;
}

/// Point compaction settings.
pub trait PointCompaction {
/// Should point compaction be applied by default?
const COMPACT_POINTS: bool;
}

0 comments on commit 7d81302

Please sign in to comment.