Updated to curve25519-dalek rc0

This commit is contained in:
Michael Rosenberg 2023-01-29 04:29:07 -05:00
parent ce3b8d3689
commit 88cc32b687
No known key found for this signature in database
3 changed files with 37 additions and 60 deletions

View file

@ -35,10 +35,10 @@ travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"}
features = ["nightly", "reusable_secrets", "serde"] features = ["nightly", "reusable_secrets", "serde"]
[dependencies] [dependencies]
curve25519-dalek = { version = "4.0.0-pre.2", default-features = false } curve25519-dalek = { version = "4.0.0-rc.0", default-features = false }
rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } rand_core = { version = "0.6", default-features = false, features = ["getrandom"] }
serde = { version = "1", default-features = false, optional = true, features = ["derive"] } serde = { version = "1", default-features = false, optional = true, features = ["derive"] }
zeroize = { version = "1", default-features = false, features = ["zeroize_derive"] } zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] }
[dev-dependencies] [dev-dependencies]
bincode = "1" bincode = "1"
@ -49,11 +49,9 @@ name = "x25519"
harness = false harness = false
[features] [features]
default = ["alloc"] default = ["alloc", "precomputed-tables", "zeroize"]
zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"]
serde = ["dep:serde", "curve25519-dalek/serde"] serde = ["dep:serde", "curve25519-dalek/serde"]
alloc = ["curve25519-dalek/alloc", "serde?/alloc"] alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"]
precomputed-tables = ["curve25519-dalek/precomputed-tables"]
reusable_secrets = [] reusable_secrets = []
[patch.crates-io]
curve25519-dalek = { git = "https://github.com/dalek-cryptography/curve25519-dalek", branch = "release/4.0" }

View file

@ -14,14 +14,14 @@
//! This implements x25519 key exchange as specified by Mike Hamburg //! This implements x25519 key exchange as specified by Mike Hamburg
//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). //! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748).
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::{
use curve25519_dalek::montgomery::MontgomeryPoint; edwards::EdwardsPoint, montgomery::MontgomeryPoint, scalar::Scalar, traits::IsIdentity,
use curve25519_dalek::scalar::Scalar; };
use curve25519_dalek::traits::IsIdentity;
use rand_core::CryptoRng; use rand_core::CryptoRng;
use rand_core::RngCore; use rand_core::RngCore;
#[cfg(feature = "zeroize")]
use zeroize::Zeroize; use zeroize::Zeroize;
/// A Diffie-Hellman public key, corresponding to an [`EphemeralSecret`] or /// A Diffie-Hellman public key, corresponding to an [`EphemeralSecret`] or
@ -32,7 +32,8 @@ use zeroize::Zeroize;
/// (in this crate) does *not* automatically happen, but either must be derived /// (in this crate) does *not* automatically happen, but either must be derived
/// for Drop or explicitly called. /// for Drop or explicitly called.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug, Zeroize)] #[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub struct PublicKey(pub(crate) MontgomeryPoint); pub struct PublicKey(pub(crate) MontgomeryPoint);
impl From<[u8; 32]> for PublicKey { impl From<[u8; 32]> for PublicKey {
@ -64,8 +65,8 @@ impl PublicKey {
/// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be /// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be
/// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks /// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks
/// that the resulting secret is used at most once. /// that the resulting secret is used at most once.
#[derive(Zeroize)] #[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[zeroize(drop)] #[cfg_attr(feature = "zeroize", zeroize(drop))]
pub struct EphemeralSecret(pub(crate) Scalar); pub struct EphemeralSecret(pub(crate) Scalar);
impl EphemeralSecret { impl EphemeralSecret {
@ -81,14 +82,14 @@ impl EphemeralSecret {
csprng.fill_bytes(&mut bytes); csprng.fill_bytes(&mut bytes);
EphemeralSecret(clamp_scalar(bytes)) EphemeralSecret(Scalar::from_bits_clamped(bytes))
} }
} }
impl<'a> From<&'a EphemeralSecret> for PublicKey { impl<'a> From<&'a EphemeralSecret> for PublicKey {
/// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`]. /// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`].
fn from(secret: &'a EphemeralSecret) -> PublicKey { fn from(secret: &'a EphemeralSecret) -> PublicKey {
PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery())
} }
} }
@ -111,8 +112,9 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey {
/// secret keys are never reused, which can have very serious security /// secret keys are never reused, which can have very serious security
/// implications for many protocols. /// implications for many protocols.
#[cfg(feature = "reusable_secrets")] #[cfg(feature = "reusable_secrets")]
#[derive(Clone, Zeroize)] #[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[zeroize(drop)] #[cfg_attr(feature = "zeroize", zeroize(drop))]
#[derive(Clone)]
pub struct ReusableSecret(pub(crate) Scalar); pub struct ReusableSecret(pub(crate) Scalar);
#[cfg(feature = "reusable_secrets")] #[cfg(feature = "reusable_secrets")]
@ -129,7 +131,7 @@ impl ReusableSecret {
csprng.fill_bytes(&mut bytes); csprng.fill_bytes(&mut bytes);
ReusableSecret(clamp_scalar(bytes)) ReusableSecret(Scalar::from_bits_clamped(bytes))
} }
} }
@ -137,7 +139,7 @@ impl ReusableSecret {
impl<'a> From<&'a ReusableSecret> for PublicKey { impl<'a> From<&'a ReusableSecret> for PublicKey {
/// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`PublicKey`]. /// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`PublicKey`].
fn from(secret: &'a ReusableSecret) -> PublicKey { fn from(secret: &'a ReusableSecret) -> PublicKey {
PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery())
} }
} }
@ -156,8 +158,9 @@ impl<'a> From<&'a ReusableSecret> for PublicKey {
/// secret keys are never reused, which can have very serious security /// secret keys are never reused, which can have very serious security
/// implications for many protocols. /// implications for many protocols.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Zeroize)] #[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[zeroize(drop)] #[cfg_attr(feature = "zeroize", zeroize(drop))]
#[derive(Clone)]
pub struct StaticSecret( pub struct StaticSecret(
#[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar, #[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar,
); );
@ -175,7 +178,7 @@ impl StaticSecret {
csprng.fill_bytes(&mut bytes); csprng.fill_bytes(&mut bytes);
StaticSecret(clamp_scalar(bytes)) StaticSecret(Scalar::from_bits_clamped(bytes))
} }
/// Extract this key's bytes for serialization. /// Extract this key's bytes for serialization.
@ -187,14 +190,14 @@ impl StaticSecret {
impl From<[u8; 32]> for StaticSecret { impl From<[u8; 32]> for StaticSecret {
/// Load a secret key from a byte array. /// Load a secret key from a byte array.
fn from(bytes: [u8; 32]) -> StaticSecret { fn from(bytes: [u8; 32]) -> StaticSecret {
StaticSecret(clamp_scalar(bytes)) StaticSecret(Scalar::from_bits_clamped(bytes))
} }
} }
impl<'a> From<&'a StaticSecret> for PublicKey { impl<'a> From<&'a StaticSecret> for PublicKey {
/// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`]. /// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`].
fn from(secret: &'a StaticSecret) -> PublicKey { fn from(secret: &'a StaticSecret) -> PublicKey {
PublicKey((&ED25519_BASEPOINT_TABLE * &secret.0).to_montgomery()) PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery())
} }
} }
@ -202,8 +205,8 @@ impl<'a> From<&'a StaticSecret> for PublicKey {
/// ///
/// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their /// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their
/// counterparty's [`PublicKey`]. /// counterparty's [`PublicKey`].
#[derive(Zeroize)] #[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[zeroize(drop)] #[cfg_attr(feature = "zeroize", zeroize(drop))]
pub struct SharedSecret(pub(crate) MontgomeryPoint); pub struct SharedSecret(pub(crate) MontgomeryPoint);
impl SharedSecret { impl SharedSecret {
@ -258,22 +261,6 @@ impl SharedSecret {
} }
} }
/// "Decode" a scalar from a 32-byte array.
///
/// By "decode" here, what is really meant is applying key clamping by twiddling
/// some bits.
///
/// # Returns
///
/// A `Scalar`.
fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar {
scalar[0] &= 248;
scalar[31] &= 127;
scalar[31] |= 64;
Scalar::from_bits(scalar)
}
/// The bare, byte-oriented x25519 function, exactly as specified in RFC7748. /// The bare, byte-oriented x25519 function, exactly as specified in RFC7748.
/// ///
/// This can be used with [`X25519_BASEPOINT_BYTES`] for people who /// This can be used with [`X25519_BASEPOINT_BYTES`] for people who
@ -305,7 +292,7 @@ fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar {
/// assert_eq!(alice_shared, bob_shared); /// assert_eq!(alice_shared, bob_shared);
/// ``` /// ```
pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] {
(clamp_scalar(k) * MontgomeryPoint(u)).to_bytes() (Scalar::from_bits_clamped(k) * MontgomeryPoint(u)).to_bytes()
} }
/// The X25519 basepoint, for use with the bare, byte-oriented x25519 /// The X25519 basepoint, for use with the bare, byte-oriented x25519
@ -325,6 +312,6 @@ struct AllowUnreducedScalarBytes(
); );
impl From<AllowUnreducedScalarBytes> for Scalar { impl From<AllowUnreducedScalarBytes> for Scalar {
fn from(bytes: AllowUnreducedScalarBytes) -> Scalar { fn from(bytes: AllowUnreducedScalarBytes) -> Scalar {
clamp_scalar(bytes.0) Scalar::from_bits_clamped(bytes.0)
} }
} }

View file

@ -1,16 +1,7 @@
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE; use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar};
use curve25519_dalek::scalar::Scalar;
use x25519_dalek::*; use x25519_dalek::*;
fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar {
scalar[0] &= 248;
scalar[31] &= 127;
scalar[31] |= 64;
Scalar::from_bits(scalar)
}
#[test] #[test]
fn byte_basepoint_matches_edwards_scalar_mul() { fn byte_basepoint_matches_edwards_scalar_mul() {
let mut scalar_bytes = [0x37; 32]; let mut scalar_bytes = [0x37; 32];
@ -20,9 +11,10 @@ fn byte_basepoint_matches_edwards_scalar_mul() {
let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES); let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES);
let expected = (&ED25519_BASEPOINT_TABLE * &clamp_scalar(scalar_bytes)) let expected = {
.to_montgomery() let scalar = Scalar::from_bits_clamped(scalar_bytes);
.to_bytes(); EdwardsPoint::mul_base(&scalar).to_montgomery().to_bytes()
};
assert_eq!(result, expected); assert_eq!(result, expected);
} }
@ -72,7 +64,7 @@ fn serde_bincode_static_secret_matches_from_bytes() {
use bincode; use bincode;
let expected = StaticSecret::from([0x24; 32]); let expected = StaticSecret::from([0x24; 32]);
let clamped_bytes = clamp_scalar([0x24; 32]).to_bytes(); let clamped_bytes = Scalar::from_bits_clamped([0x24; 32]).to_bytes();
let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap(); let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap();
assert_eq!(decoded.to_bytes(), expected.to_bytes()); assert_eq!(decoded.to_bytes(), expected.to_bytes());