Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 0 additions & 3 deletions dhkem/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ readme = "README.md"
kem = "0.4.0-rc.4"
rand_core = "0.10.0-rc-5"

# TODO(tarcieri): remove this and get these from `kem`
common = { package = "crypto-common", version = "0.2.0-rc.12" }

# optional dependencies
elliptic-curve = { version = "0.14.0-rc.23", optional = true, default-features = false }
k256 = { version = "0.14.0-rc.5", optional = true, default-features = false, features = ["arithmetic"] }
Expand Down
22 changes: 6 additions & 16 deletions dhkem/src/ecdh_kem.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
//! Generic Elliptic Curve Diffie-Hellman KEM adapter.

use crate::{DhDecapsulator, DhEncapsulator, DhKem};
use core::{convert::Infallible, marker::PhantomData};
use core::marker::PhantomData;
use elliptic_curve::{
AffinePoint,
CurveArithmetic,
FieldBytesSize,
Generate,
PublicKey,
common::InvalidKey, // TODO(tarcieri): get from `kem` crate
AffinePoint, CurveArithmetic, FieldBytesSize, Generate, PublicKey,
ecdh::{EphemeralSecret, SharedSecret},
sec1::{
FromEncodedPoint, ModulusSize, ToEncodedPoint, UncompressedPoint, UncompressedPointSize,
},
};
use kem::{Decapsulate, Encapsulate, KeyExport, KeySizeUser, TryKeyInit};
use kem::{Decapsulate, Encapsulate, InvalidKey, KeyExport, KeySizeUser, TryKeyInit};
use rand_core::{CryptoRng, TryCryptoRng};

/// Generic Elliptic Curve Diffie-Hellman KEM adapter compatible with curves implemented using
Expand Down Expand Up @@ -86,12 +81,10 @@ where
FieldBytesSize<C>: ModulusSize,
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
{
type Error = Infallible;

fn encapsulate_with_rng<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
) -> Result<(PublicKey<C>, SharedSecret<C>), Self::Error> {
) -> Result<(PublicKey<C>, SharedSecret<C>), R::Error> {
// ECDH encapsulation involves creating a new ephemeral key pair and then doing DH
// TODO(tarcieri): propagate RNG errors
let sk = EphemeralSecret::try_generate_from_rng(rng).expect("RNG failure");
Expand All @@ -109,12 +102,9 @@ where
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
{
type Encapsulator = DhEncapsulator<PublicKey<C>>;
type Error = Infallible;

fn decapsulate(&self, encapsulated_key: &PublicKey<C>) -> Result<SharedSecret<C>, Self::Error> {
let ss = self.0.diffie_hellman(encapsulated_key);

Ok(ss)
fn decapsulate(&self, encapsulated_key: &PublicKey<C>) -> SharedSecret<C> {
self.0.diffie_hellman(encapsulated_key)
}

fn encapsulator(&self) -> DhEncapsulator<PublicKey<C>> {
Expand Down
17 changes: 6 additions & 11 deletions dhkem/src/x25519_kem.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
use crate::{DhDecapsulator, DhEncapsulator, DhKem};
use core::convert::Infallible;
use kem::{Decapsulate, Encapsulate, KeyExport, KeySizeUser, TryKeyInit, consts::U32};
use kem::{
Decapsulate, Encapsulate, InvalidKey, Key, KeyExport, KeySizeUser, TryKeyInit, consts::U32,
};
use rand_core::{CryptoRng, TryCryptoRng, UnwrapErr};
use x25519::{PublicKey, ReusableSecret, SharedSecret};

// TODO(tarcieri): get these from `kem`
use common::{InvalidKey, Key};

/// X22519 Diffie-Hellman KEM adapter.
///
/// Implements a KEM interface that internally uses X25519 ECDH.
Expand Down Expand Up @@ -50,12 +48,10 @@ impl KeyExport for DhEncapsulator<PublicKey> {
}

impl Encapsulate<PublicKey, SharedSecret> for DhEncapsulator<PublicKey> {
type Error = Infallible;

fn encapsulate_with_rng<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
) -> Result<(PublicKey, SharedSecret), Self::Error> {
) -> Result<(PublicKey, SharedSecret), R::Error> {
// ECDH encapsulation involves creating a new ephemeral key pair and then doing DH
let sk = ReusableSecret::random_from_rng(&mut UnwrapErr(rng));
let pk = PublicKey::from(&sk);
Expand All @@ -67,10 +63,9 @@ impl Encapsulate<PublicKey, SharedSecret> for DhEncapsulator<PublicKey> {

impl Decapsulate<PublicKey, SharedSecret> for DhDecapsulator<ReusableSecret> {
type Encapsulator = DhEncapsulator<PublicKey>;
type Error = Infallible;

fn decapsulate(&self, encapsulated_key: &PublicKey) -> Result<SharedSecret, Self::Error> {
Ok(self.0.diffie_hellman(encapsulated_key))
fn decapsulate(&self, encapsulated_key: &PublicKey) -> SharedSecret {
self.0.diffie_hellman(encapsulated_key)
}

fn encapsulator(&self) -> DhEncapsulator<PublicKey> {
Expand Down
2 changes: 1 addition & 1 deletion dhkem/tests/hpke_p256_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ fn test_dhkem_p256_hkdf_sha256() {
.expect("never fails");
assert_eq!(pke.to_encoded_point(false).as_bytes(), &pke_hex);

let ss2 = skr.decapsulate(&pke).expect("never fails");
let ss2 = skr.decapsulate(&pke);

assert_eq!(ss1.raw_secret_bytes(), ss2.raw_secret_bytes());

Expand Down
2 changes: 1 addition & 1 deletion dhkem/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ where
let mut rng = SysRng.unwrap_err();
let (sk, pk) = K::random_keypair(&mut rng);
let (ek, ss1) = pk.encapsulate_with_rng(&mut rng).expect("never fails");
let ss2 = sk.decapsulate(&ek).expect("never fails");
let ss2 = sk.decapsulate(&ek);

assert_eq!(ss1.as_slice(), ss2.as_slice());
}
Expand Down
5 changes: 1 addition & 4 deletions ml-kem/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,12 @@ pkcs8 = ["dep:const-oid", "dep:pkcs8"]
zeroize = ["dep:zeroize"]

[dependencies]
array = { package = "hybrid-array", version = "0.4.4", features = ["extra-sizes", "subtle"] }
kem = "0.4.0-rc.4"
hybrid-array = { version = "0.4.4", features = ["extra-sizes", "subtle"] }
rand_core = "0.10.0-rc-5"
sha3 = { version = "0.11.0-rc.3", default-features = false }
subtle = { version = "2", default-features = false }

# TODO(tarcieri): remove this and get these from `kem`
common = { package = "crypto-common", version = "0.2.0-rc.12" }

# optional dependencies
const-oid = { version = "0.10.1", optional = true, default-features = false, features = ["db"] }
pkcs8 = { version = "0.11.0-rc.8", optional = true, default-features = false }
Expand Down
4 changes: 2 additions & 2 deletions ml-kem/benches/mlkem.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ fn criterion_benchmark(c: &mut Criterion) {

c.bench_function("decapsulate", |b| {
b.iter(|| {
dk.decapsulate(&ct).unwrap();
dk.decapsulate(&ct);
})
});

Expand All @@ -42,7 +42,7 @@ fn criterion_benchmark(c: &mut Criterion) {
let dk = ml_kem_768::DecapsulationKey::generate_from_rng(&mut rng);
let ek = dk.encapsulator();
let (ct, _sk) = ek.encapsulate_with_rng(&mut rng).unwrap();
dk.decapsulate(&ct).unwrap();
dk.decapsulate(&ct);
})
});
}
Expand Down
4 changes: 2 additions & 2 deletions ml-kem/src/algebra.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use array::{Array, typenum::U256};
use core::ops::{Add, Mul, Sub};
use hybrid_array::{Array, typenum::U256};
use sha3::digest::XofReader;
use subtle::{Choice, ConstantTimeEq};

Expand Down Expand Up @@ -525,7 +525,7 @@ impl<K: ArraySize> NttMatrix<K> {
mod test {
use super::*;
use crate::util::Flatten;
use hybrid_array::typenum::{U2, U3, U8};
use array::typenum::{U2, U3, U8};

// Multiplication in R_q, modulo X^256 + 1
impl Mul<&Polynomial> for &Polynomial {
Expand Down
2 changes: 1 addition & 1 deletion ml-kem/src/compress.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ impl<K: ArraySize> Compress for PolynomialVector<K> {
#[cfg(test)]
pub(crate) mod test {
use super::*;
use hybrid_array::typenum::{U1, U4, U5, U6, U10, U11, U12};
use array::typenum::{U1, U4, U5, U6, U10, U11, U12};
use num_rational::Ratio;

#[allow(clippy::cast_possible_truncation)]
Expand Down
2 changes: 1 addition & 1 deletion ml-kem/src/crypto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,8 @@ pub fn XOF(rho: &B32, i: u8, j: u8) -> impl XofReader {
#[cfg(test)]
mod test {
use super::*;
use array::typenum::{U2, U3};
use hex_literal::hex;
use hybrid_array::typenum::{U2, U3};

#[test]
fn g() {
Expand Down
6 changes: 3 additions & 3 deletions ml-kem/src/encode.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use hybrid_array::{
use array::{
Array,
typenum::{U256, Unsigned},
};
Expand Down Expand Up @@ -144,10 +144,10 @@ where
#[cfg(test)]
pub(crate) mod test {
use super::*;
use core::{fmt::Debug, ops::Rem};
use hybrid_array::typenum::{
use array::typenum::{
U1, U2, U3, U4, U5, U6, U8, U10, U11, U12, marker_traits::Zero, operator_aliases::Mod,
};
use core::{fmt::Debug, ops::Rem};
use rand_core::{RngCore, TryRngCore};

use crate::param::EncodedPolynomialVector;
Expand Down
13 changes: 0 additions & 13 deletions ml-kem/src/error.rs

This file was deleted.

46 changes: 19 additions & 27 deletions ml-kem/src/kem.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//!
//! Key encapsulation mechanism implementation.

// Re-export traits from the `kem` crate
pub use ::kem::{Decapsulate, Encapsulate, Generate, KeyExport, KeySizeUser, TryKeyInit};
pub use ::kem::{
Decapsulate, Encapsulate, Generate, InvalidKey, Key, KeyExport, KeyInit, KeySizeUser,
TryKeyInit,
};

use crate::{
Encoded, EncodedSizeUser, Error, Seed,
Encoded, EncodedSizeUser, Seed,
crypto::{G, H, J},
param::{
DecapsulationKeySize, EncapsulationKeySize, EncodedCiphertext, ExpandedDecapsulationKey,
Expand All @@ -13,14 +16,13 @@ use crate::{
pke::{DecryptionKey, EncryptionKey},
util::B32,
};
use core::{convert::Infallible, marker::PhantomData};
use hybrid_array::typenum::{U32, U64};
use array::typenum::{U32, U64};
use core::marker::PhantomData;
use rand_core::{CryptoRng, TryCryptoRng, TryRngCore};
use subtle::{ConditionallySelectable, ConstantTimeEq};

// TODO(tarcieri): get these from `kem`
use common::{InvalidKey, Key, KeyInit};

#[cfg(feature = "deterministic")]
use core::convert::Infallible;
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};

Expand Down Expand Up @@ -80,7 +82,7 @@ where
{
type EncodedSize = DecapsulationKeySize<P>;

fn from_encoded_bytes(expanded: &Encoded<Self>) -> Result<Self, Error> {
fn from_encoded_bytes(expanded: &Encoded<Self>) -> Result<Self, InvalidKey> {
#[allow(deprecated)]
Self::from_expanded(expanded)
}
Expand Down Expand Up @@ -126,21 +128,13 @@ where
P: KemParams,
{
type Encapsulator = EncapsulationKey<P>;
type Error = Infallible;

fn decapsulate(
&self,
encapsulated_key: &EncodedCiphertext<P>,
) -> Result<SharedKey, Self::Error> {
fn decapsulate(&self, encapsulated_key: &EncodedCiphertext<P>) -> SharedKey {
let mp = self.dk_pke.decrypt(encapsulated_key);
let (Kp, rp) = G(&[&mp, &self.ek.h]);
let Kbar = J(&[self.z.as_slice(), encapsulated_key.as_ref()]);
let cp = self.ek.ek_pke.encrypt(&mp, &rp);
Ok(B32::conditional_select(
&Kbar,
&Kp,
cp.ct_eq(encapsulated_key),
))
B32::conditional_select(&Kbar, &Kp, cp.ct_eq(encapsulated_key))
}

fn encapsulator(&self) -> EncapsulationKey<P> {
Expand All @@ -166,9 +160,9 @@ where
/// [`DecapsulationKey::from_seed`].
///
/// # Errors
/// - Returns [`Error`] in the event the expanded key failed validation
/// - Returns [`InvalidKey`] in the event the expanded key failed validation
#[deprecated(since = "0.3.0", note = "use `DecapsulationKey::from_seed` instead")]
pub fn from_expanded(enc: &ExpandedDecapsulationKey<P>) -> Result<Self, Error> {
pub fn from_expanded(enc: &ExpandedDecapsulationKey<P>) -> Result<Self, InvalidKey> {
let (dk_pke, ek_pke, h, z) = P::split_dk(enc);
let ek_pke = EncryptionKey::from_bytes(ek_pke)?;

Expand Down Expand Up @@ -260,7 +254,7 @@ where
{
type EncodedSize = EncapsulationKeySize<P>;

fn from_encoded_bytes(enc: &Encoded<Self>) -> Result<Self, Error> {
fn from_encoded_bytes(enc: &Encoded<Self>) -> Result<Self, InvalidKey> {
Ok(Self::new(EncryptionKey::from_bytes(enc)?))
}

Expand Down Expand Up @@ -300,13 +294,11 @@ impl<P> Encapsulate<EncodedCiphertext<P>, SharedKey> for EncapsulationKey<P>
where
P: KemParams,
{
type Error = Error;

fn encapsulate_with_rng<R: TryCryptoRng + ?Sized>(
&self,
rng: &mut R,
) -> Result<(EncodedCiphertext<P>, SharedKey), Self::Error> {
let m = B32::try_generate_from_rng(rng).map_err(|_| Error)?;
) -> Result<(EncodedCiphertext<P>, SharedKey), R::Error> {
let m = B32::try_generate_from_rng(rng)?;
Ok(self.encapsulate_deterministic_inner(&m))
}
}
Expand Down Expand Up @@ -379,7 +371,7 @@ mod test {
let ek = dk.encapsulation_key();

let (ct, k_send) = ek.encapsulate_with_rng(&mut rng).unwrap();
let k_recv = dk.decapsulate(&ct).unwrap();
let k_recv = dk.decapsulate(&ct);
assert_eq!(k_send, k_recv);
}

Expand Down
Loading