mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-04 20:24:10 +00:00
Update to new Scalar API (#120)
* Updated to new curve25519 scalar API * Removed clamping from constructors; clamping is always done during scalar-point multiplication * Updated test to reflect new functionality * Updated changelog
This commit is contained in:
parent
cccf389467
commit
25fa593df2
5 changed files with 35 additions and 51 deletions
|
|
@ -4,6 +4,11 @@ Entries are listed in reverse chronological order.
|
|||
|
||||
# 2.x Series
|
||||
|
||||
|
||||
## 2.0.0-rc.3
|
||||
|
||||
* Change: `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication.
|
||||
|
||||
## 2.0.0-rc.2
|
||||
|
||||
* Update MSRV to 1.60.
|
||||
|
|
|
|||
3
Cargo.lock
generated
3
Cargo.lock
generated
|
|
@ -188,8 +188,7 @@ dependencies = [
|
|||
[[package]]
|
||||
name = "curve25519-dalek"
|
||||
version = "4.0.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03d928d978dbec61a1167414f5ec534f24bea0d7a0d24dd9b6233d3d8223e585"
|
||||
source = "git+https://github.com/dalek-cryptography/curve25519-dalek.git?rev=f460ae149b0000695205cc78f560d74a2d3918eb#f460ae149b0000695205cc78f560d74a2d3918eb"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fiat-crypto",
|
||||
|
|
|
|||
|
|
@ -61,3 +61,7 @@ alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"]
|
|||
precomputed-tables = ["curve25519-dalek/precomputed-tables"]
|
||||
reusable_secrets = []
|
||||
static_secrets = []
|
||||
|
||||
[patch.crates-io.curve25519-dalek]
|
||||
git = "https://github.com/dalek-cryptography/curve25519-dalek.git"
|
||||
rev = "f460ae149b0000695205cc78f560d74a2d3918eb"
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@
|
|||
//! This implements x25519 key exchange as specified by Mike Hamburg
|
||||
//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748).
|
||||
|
||||
use curve25519_dalek::{
|
||||
edwards::EdwardsPoint, montgomery::MontgomeryPoint, scalar::Scalar, traits::IsIdentity,
|
||||
};
|
||||
use curve25519_dalek::{edwards::EdwardsPoint, montgomery::MontgomeryPoint, traits::IsIdentity};
|
||||
|
||||
use rand_core::CryptoRng;
|
||||
use rand_core::RngCore;
|
||||
|
|
@ -74,13 +72,13 @@ impl AsRef<[u8]> for PublicKey {
|
|||
/// secret is used at most once.
|
||||
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "zeroize", zeroize(drop))]
|
||||
pub struct EphemeralSecret(pub(crate) Scalar);
|
||||
pub struct EphemeralSecret(pub(crate) [u8; 32]);
|
||||
|
||||
impl EphemeralSecret {
|
||||
/// Perform a Diffie-Hellman key agreement between `self` and
|
||||
/// `their_public` key to produce a [`SharedSecret`].
|
||||
pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret {
|
||||
SharedSecret(self.0 * their_public.0)
|
||||
SharedSecret(their_public.0.mul_clamped(self.0))
|
||||
}
|
||||
|
||||
/// Generate a new [`EphemeralSecret`] with the supplied RNG.
|
||||
|
|
@ -94,11 +92,10 @@ impl EphemeralSecret {
|
|||
|
||||
/// Generate a new [`EphemeralSecret`] with the supplied RNG.
|
||||
pub fn random_from_rng<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
|
||||
// The secret key is random bytes. Clamping is done later.
|
||||
let mut bytes = [0u8; 32];
|
||||
|
||||
csprng.fill_bytes(&mut bytes);
|
||||
|
||||
EphemeralSecret(Scalar::from_bits_clamped(bytes))
|
||||
EphemeralSecret(bytes)
|
||||
}
|
||||
|
||||
/// Generate a new [`EphemeralSecret`].
|
||||
|
|
@ -111,7 +108,7 @@ impl EphemeralSecret {
|
|||
impl<'a> From<&'a EphemeralSecret> for PublicKey {
|
||||
/// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`].
|
||||
fn from(secret: &'a EphemeralSecret) -> PublicKey {
|
||||
PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery())
|
||||
PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -137,14 +134,14 @@ impl<'a> From<&'a EphemeralSecret> for PublicKey {
|
|||
#[cfg_attr(feature = "zeroize", derive(Zeroize))]
|
||||
#[cfg_attr(feature = "zeroize", zeroize(drop))]
|
||||
#[derive(Clone)]
|
||||
pub struct ReusableSecret(pub(crate) Scalar);
|
||||
pub struct ReusableSecret(pub(crate) [u8; 32]);
|
||||
|
||||
#[cfg(feature = "reusable_secrets")]
|
||||
impl ReusableSecret {
|
||||
/// Perform a Diffie-Hellman key agreement between `self` and
|
||||
/// `their_public` key to produce a [`SharedSecret`].
|
||||
pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret {
|
||||
SharedSecret(self.0 * their_public.0)
|
||||
SharedSecret(their_public.0.mul_clamped(self.0))
|
||||
}
|
||||
|
||||
/// Generate a new [`ReusableSecret`] with the supplied RNG.
|
||||
|
|
@ -158,11 +155,10 @@ impl ReusableSecret {
|
|||
|
||||
/// Generate a new [`ReusableSecret`] with the supplied RNG.
|
||||
pub fn random_from_rng<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
|
||||
// The secret key is random bytes. Clamping is done later.
|
||||
let mut bytes = [0u8; 32];
|
||||
|
||||
csprng.fill_bytes(&mut bytes);
|
||||
|
||||
ReusableSecret(Scalar::from_bits_clamped(bytes))
|
||||
ReusableSecret(bytes)
|
||||
}
|
||||
|
||||
/// Generate a new [`ReusableSecret`].
|
||||
|
|
@ -176,7 +172,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(EdwardsPoint::mul_base(&secret.0).to_montgomery())
|
||||
PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -199,16 +195,14 @@ impl<'a> From<&'a ReusableSecret> for PublicKey {
|
|||
#[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,
|
||||
);
|
||||
pub struct StaticSecret([u8; 32]);
|
||||
|
||||
#[cfg(feature = "static_secrets")]
|
||||
impl StaticSecret {
|
||||
/// Perform a Diffie-Hellman key agreement between `self` and
|
||||
/// `their_public` key to produce a `SharedSecret`.
|
||||
pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret {
|
||||
SharedSecret(self.0 * their_public.0)
|
||||
SharedSecret(their_public.0.mul_clamped(self.0))
|
||||
}
|
||||
|
||||
/// Generate a new [`StaticSecret`] with the supplied RNG.
|
||||
|
|
@ -222,11 +216,10 @@ impl StaticSecret {
|
|||
|
||||
/// Generate a new [`StaticSecret`] with the supplied RNG.
|
||||
pub fn random_from_rng<T: RngCore + CryptoRng>(mut csprng: T) -> Self {
|
||||
// The secret key is random bytes. Clamping is done later.
|
||||
let mut bytes = [0u8; 32];
|
||||
|
||||
csprng.fill_bytes(&mut bytes);
|
||||
|
||||
StaticSecret(Scalar::from_bits_clamped(bytes))
|
||||
StaticSecret(bytes)
|
||||
}
|
||||
|
||||
/// Generate a new [`StaticSecret`].
|
||||
|
|
@ -238,13 +231,13 @@ impl StaticSecret {
|
|||
/// Extract this key's bytes for serialization.
|
||||
#[inline]
|
||||
pub fn to_bytes(&self) -> [u8; 32] {
|
||||
self.0.to_bytes()
|
||||
self.0
|
||||
}
|
||||
|
||||
/// View this key as a byte array.
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8; 32] {
|
||||
self.0.as_bytes()
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -252,7 +245,7 @@ impl StaticSecret {
|
|||
impl From<[u8; 32]> for StaticSecret {
|
||||
/// Load a secret key from a byte array.
|
||||
fn from(bytes: [u8; 32]) -> StaticSecret {
|
||||
StaticSecret(Scalar::from_bits_clamped(bytes))
|
||||
StaticSecret(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -260,7 +253,7 @@ impl From<[u8; 32]> for StaticSecret {
|
|||
impl<'a> From<&'a StaticSecret> for PublicKey {
|
||||
/// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`].
|
||||
fn from(secret: &'a StaticSecret) -> PublicKey {
|
||||
PublicKey(EdwardsPoint::mul_base(&secret.0).to_montgomery())
|
||||
PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -373,7 +366,7 @@ impl AsRef<[u8]> for SharedSecret {
|
|||
/// assert_eq!(alice_shared, bob_shared);
|
||||
/// ```
|
||||
pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] {
|
||||
(Scalar::from_bits_clamped(k) * MontgomeryPoint(u)).to_bytes()
|
||||
MontgomeryPoint(u).mul_clamped(k).to_bytes()
|
||||
}
|
||||
|
||||
/// The X25519 basepoint, for use with the bare, byte-oriented x25519
|
||||
|
|
@ -382,17 +375,3 @@ pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] {
|
|||
pub const X25519_BASEPOINT_BYTES: [u8; 32] = [
|
||||
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
|
||||
/// Derived serialization methods will not work on a StaticSecret because x25519 requires
|
||||
/// non-canonical scalars which are rejected by curve25519-dalek. Thus we provide a way to convert
|
||||
/// the bytes directly to a scalar using Serde's remote derive functionality.
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(remote = "Scalar"))]
|
||||
struct AllowUnreducedScalarBytes(
|
||||
#[cfg_attr(feature = "serde", serde(getter = "Scalar::to_bytes"))] [u8; 32],
|
||||
);
|
||||
impl From<AllowUnreducedScalarBytes> for Scalar {
|
||||
fn from(bytes: AllowUnreducedScalarBytes) -> Scalar {
|
||||
Scalar::from_bits_clamped(bytes.0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use curve25519_dalek::{edwards::EdwardsPoint, scalar::Scalar};
|
||||
use curve25519_dalek::edwards::EdwardsPoint;
|
||||
|
||||
use x25519_dalek::*;
|
||||
|
||||
|
|
@ -10,11 +10,9 @@ fn byte_basepoint_matches_edwards_scalar_mul() {
|
|||
scalar_bytes[i] += 2;
|
||||
|
||||
let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES);
|
||||
|
||||
let expected = {
|
||||
let scalar = Scalar::from_bits_clamped(scalar_bytes);
|
||||
EdwardsPoint::mul_base(&scalar).to_montgomery().to_bytes()
|
||||
};
|
||||
let expected = EdwardsPoint::mul_base_clamped(scalar_bytes)
|
||||
.to_montgomery()
|
||||
.to_bytes();
|
||||
|
||||
assert_eq!(result, expected);
|
||||
}
|
||||
|
|
@ -64,8 +62,7 @@ fn serde_bincode_static_secret_matches_from_bytes() {
|
|||
use bincode;
|
||||
|
||||
let expected = StaticSecret::from([0x24; 32]);
|
||||
let clamped_bytes = Scalar::from_bits_clamped([0x24; 32]).to_bytes();
|
||||
let decoded: StaticSecret = bincode::deserialize(&clamped_bytes).unwrap();
|
||||
let decoded: StaticSecret = bincode::deserialize(&[0x24; 32]).unwrap();
|
||||
|
||||
assert_eq!(decoded.to_bytes(), expected.to_bytes());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue