Updated to curve25519-dalek rc0
This commit is contained in:
parent
ce3b8d3689
commit
88cc32b687
14
Cargo.toml
14
Cargo.toml
@ -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" }
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
Loading…
x
Reference in New Issue
Block a user