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"]
[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"] }
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]
bincode = "1"
@ -49,11 +49,9 @@ name = "x25519"
harness = false
[features]
default = ["alloc"]
default = ["alloc", "precomputed-tables", "zeroize"]
zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"]
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 = []
[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
//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748).
use curve25519_dalek::constants::ED25519_BASEPOINT_TABLE;
use curve25519_dalek::montgomery::MontgomeryPoint;
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::IsIdentity;
use curve25519_dalek::{
edwards::EdwardsPoint, montgomery::MontgomeryPoint, scalar::Scalar, traits::IsIdentity,
};
use rand_core::CryptoRng;
use rand_core::RngCore;
#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
/// 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
/// for Drop or explicitly called.
#[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);
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
/// generated from fresh randomness by [`EphemeralSecret::new`] and the compiler statically checks
/// that the resulting secret is used at most once.
#[derive(Zeroize)]
#[zeroize(drop)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[cfg_attr(feature = "zeroize", zeroize(drop))]
pub struct EphemeralSecret(pub(crate) Scalar);
impl EphemeralSecret {
@ -81,14 +82,14 @@ impl EphemeralSecret {
csprng.fill_bytes(&mut bytes);
EphemeralSecret(clamp_scalar(bytes))
EphemeralSecret(Scalar::from_bits_clamped(bytes))
}
}
impl<'a> From<&'a EphemeralSecret> for PublicKey {
/// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`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
/// implications for many protocols.
#[cfg(feature = "reusable_secrets")]
#[derive(Clone, Zeroize)]
#[zeroize(drop)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[cfg_attr(feature = "zeroize", zeroize(drop))]
#[derive(Clone)]
pub struct ReusableSecret(pub(crate) Scalar);
#[cfg(feature = "reusable_secrets")]
@ -129,7 +131,7 @@ impl ReusableSecret {
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 {
/// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`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
/// implications for many protocols.
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone, Zeroize)]
#[zeroize(drop)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[cfg_attr(feature = "zeroize", zeroize(drop))]
#[derive(Clone)]
pub struct StaticSecret(
#[cfg_attr(feature = "serde", serde(with = "AllowUnreducedScalarBytes"))] pub(crate) Scalar,
);
@ -175,7 +178,7 @@ impl StaticSecret {
csprng.fill_bytes(&mut bytes);
StaticSecret(clamp_scalar(bytes))
StaticSecret(Scalar::from_bits_clamped(bytes))
}
/// Extract this key's bytes for serialization.
@ -187,14 +190,14 @@ impl StaticSecret {
impl From<[u8; 32]> for StaticSecret {
/// Load a secret key from a byte array.
fn from(bytes: [u8; 32]) -> StaticSecret {
StaticSecret(clamp_scalar(bytes))
StaticSecret(Scalar::from_bits_clamped(bytes))
}
}
impl<'a> From<&'a StaticSecret> for PublicKey {
/// Given an x25519 [`StaticSecret`] key, compute its corresponding [`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
/// counterparty's [`PublicKey`].
#[derive(Zeroize)]
#[zeroize(drop)]
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
#[cfg_attr(feature = "zeroize", zeroize(drop))]
pub struct SharedSecret(pub(crate) MontgomeryPoint);
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.
///
/// 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);
/// ```
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
@ -325,6 +312,6 @@ struct AllowUnreducedScalarBytes(
);
impl From<AllowUnreducedScalarBytes> for 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::scalar::Scalar;
use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar};
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]
fn byte_basepoint_matches_edwards_scalar_mul() {
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 expected = (&ED25519_BASEPOINT_TABLE * &clamp_scalar(scalar_bytes))
.to_montgomery()
.to_bytes();
let expected = {
let scalar = Scalar::from_bits_clamped(scalar_bytes);
EdwardsPoint::mul_base(&scalar).to_montgomery().to_bytes()
};
assert_eq!(result, expected);
}
@ -72,7 +64,7 @@ fn serde_bincode_static_secret_matches_from_bytes() {
use bincode;
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();
assert_eq!(decoded.to_bytes(), expected.to_bytes());