Upgrade ml-kem from 0.2 to 0.3.0-rc.0 (#421)
This commit is contained in:
@@ -26,7 +26,7 @@ jobs:
|
|||||||
- --features serde
|
- --features serde
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.85.0
|
- 1.87.0
|
||||||
name: test
|
name: test
|
||||||
env:
|
env:
|
||||||
PKCS11_MODULE: /usr/lib/softhsm/libsofthsm2.so
|
PKCS11_MODULE: /usr/lib/softhsm/libsofthsm2.so
|
||||||
@@ -95,7 +95,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.85.0
|
- 1.87.0
|
||||||
name: test simple_login command-line example
|
name: test simple_login command-line example
|
||||||
steps:
|
steps:
|
||||||
- name: install expect
|
- name: install expect
|
||||||
@@ -118,7 +118,7 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.85.0
|
- 1.87.0
|
||||||
name: test digital_locker command-line example
|
name: test digital_locker command-line example
|
||||||
steps:
|
steps:
|
||||||
- name: install expect
|
- name: install expect
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 4.1.0-pre.2 (March 26, 2026)
|
||||||
|
* Upgraded ml-kem from 0.2 to 0.3.0-rc.0
|
||||||
|
* Increased MSRV to 1.87
|
||||||
|
|
||||||
## 4.1.0-pre.1 (November 17, 2025)
|
## 4.1.0-pre.1 (November 17, 2025)
|
||||||
* Added ml-kem re-export behind the kem feature
|
* Added ml-kem re-export behind the kem feature
|
||||||
|
|
||||||
|
|||||||
+6
-5
@@ -9,8 +9,8 @@ license = "Apache-2.0 OR MIT"
|
|||||||
name = "opaque-ke"
|
name = "opaque-ke"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
repository = "https://github.com/facebook/opaque-ke"
|
repository = "https://github.com/facebook/opaque-ke"
|
||||||
rust-version = "1.85"
|
rust-version = "1.87"
|
||||||
version = "4.1.0-pre.1"
|
version = "4.1.0-pre.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
argon2 = ["dep:argon2"]
|
argon2 = ["dep:argon2"]
|
||||||
@@ -18,7 +18,7 @@ curve25519 = ["dep:curve25519-dalek"]
|
|||||||
default = ["ristretto255", "serde"]
|
default = ["ristretto255", "serde"]
|
||||||
ecdsa = ["dep:ecdsa", "dep:rfc6979"]
|
ecdsa = ["dep:ecdsa", "dep:rfc6979"]
|
||||||
ed25519 = ["dep:curve25519-dalek", "dep:ed25519-dalek"]
|
ed25519 = ["dep:curve25519-dalek", "dep:ed25519-dalek"]
|
||||||
kem = ["dep:ml-kem"]
|
kem = ["dep:ml-kem", "dep:rand_core_10"]
|
||||||
ristretto255 = ["dep:curve25519-dalek", "voprf/ristretto255-ciphersuite"]
|
ristretto255 = ["dep:curve25519-dalek", "voprf/ristretto255-ciphersuite"]
|
||||||
serde = [
|
serde = [
|
||||||
"dep:serde",
|
"dep:serde",
|
||||||
@@ -54,10 +54,11 @@ elliptic-curve = { version = "0.13", features = ["hash2curve", "sec1"] }
|
|||||||
generic-array = "=0.14.7" # pinned to avoid deprecation warnings
|
generic-array = "=0.14.7" # pinned to avoid deprecation warnings
|
||||||
hkdf = "0.12"
|
hkdf = "0.12"
|
||||||
hmac = "0.12"
|
hmac = "0.12"
|
||||||
ml-kem = { version = "0.2", default-features = false, features = [
|
ml-kem = { version = "0.3.0-rc.0", default-features = false, features = [
|
||||||
"zeroize",
|
"zeroize",
|
||||||
], optional = true }
|
], optional = true }
|
||||||
rand = { version = "0.8", default-features = false }
|
rand = { version = "0.8", default-features = false }
|
||||||
|
rand_core_10 = { package = "rand_core", version = "0.10", default-features = false, optional = true }
|
||||||
rfc6979 = { version = "0.4", optional = true }
|
rfc6979 = { version = "0.4", optional = true }
|
||||||
serde = { version = "1", default-features = false, features = [
|
serde = { version = "1", default-features = false, features = [
|
||||||
"derive",
|
"derive",
|
||||||
@@ -73,7 +74,7 @@ getrandom = { version = "0.2", features = ["js"], optional = true }
|
|||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
bincode = "1"
|
bincode = "1"
|
||||||
chacha20poly1305 = "0.10"
|
chacha20poly1305 = "0.10"
|
||||||
criterion = "0.7"
|
criterion = "0.8"
|
||||||
cryptoki = "0.9"
|
cryptoki = "0.9"
|
||||||
elliptic-curve = { version = "0.13", features = ["alloc", "pkcs8"] }
|
elliptic-curve = { version = "0.13", features = ["alloc", "pkcs8"] }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
|
|||||||
@@ -22,12 +22,12 @@ Installation
|
|||||||
Add the following line to the dependencies of your `Cargo.toml`:
|
Add the following line to the dependencies of your `Cargo.toml`:
|
||||||
|
|
||||||
```
|
```
|
||||||
opaque-ke = "4.1.0-pre.1"
|
opaque-ke = "4.1.0-pre.2"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Minimum Supported Rust Version
|
### Minimum Supported Rust Version
|
||||||
|
|
||||||
Rust **1.85** or higher.
|
Rust **1.87** or higher.
|
||||||
|
|
||||||
Audit
|
Audit
|
||||||
-----
|
-----
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
//! the generic `ml-kem` abstractions into the existing OPAQUE key-exchange
|
//! the generic `ml-kem` abstractions into the existing OPAQUE key-exchange
|
||||||
//! pipeline.
|
//! pipeline.
|
||||||
|
|
||||||
use core::convert::TryFrom;
|
|
||||||
use core::fmt::Debug;
|
use core::fmt::Debug;
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
@@ -29,9 +28,11 @@ use digest::{Digest, Output};
|
|||||||
use generic_array::sequence::Concat;
|
use generic_array::sequence::Concat;
|
||||||
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
|
use generic_array::typenum::{IsLess, Le, NonZero, Sum, U256};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use ml_kem::kem::{Decapsulate, Encapsulate};
|
#[allow(deprecated)]
|
||||||
use ml_kem::{
|
use ml_kem::ExpandedKeyEncoding;
|
||||||
Ciphertext as MlKemCiphertext, Encoded, EncodedSizeUser, KemCore, SharedKey as MlKemSharedKey,
|
use ml_kem::kem::{
|
||||||
|
Ciphertext as MlKemCiphertext, Decapsulate, Encapsulate, Kem as MlKemTrait, KeyExport,
|
||||||
|
KeySizeUser, TryKeyInit,
|
||||||
};
|
};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand::{CryptoRng, RngCore};
|
||||||
use subtle::{ConstantTimeEq, CtOption};
|
use subtle::{ConstantTimeEq, CtOption};
|
||||||
@@ -44,7 +45,7 @@ use super::{
|
|||||||
SerializedIdentifiers,
|
SerializedIdentifiers,
|
||||||
};
|
};
|
||||||
use crate::ciphersuite::{CipherSuite, KeGroup};
|
use crate::ciphersuite::{CipherSuite, KeGroup};
|
||||||
use crate::errors::{InternalError, ProtocolError};
|
use crate::errors::ProtocolError;
|
||||||
use crate::hash::{Hash, OutputSize, ProxyHash};
|
use crate::hash::{Hash, OutputSize, ProxyHash};
|
||||||
use crate::key_exchange::group::Group;
|
use crate::key_exchange::group::Group;
|
||||||
use crate::keypair::{PrivateKey, PublicKey};
|
use crate::keypair::{PrivateKey, PublicKey};
|
||||||
@@ -115,16 +116,42 @@ pub trait KemCoreWrapper {
|
|||||||
) -> Result<GenericArray<u8, Self::SharedSecretLen>, ProtocolError>;
|
) -> Result<GenericArray<u8, Self::SharedSecretLen>, ProtocolError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
type RcEncapsulationKeyLen<K> = <<K as KemCore>::EncapsulationKey as EncodedSizeUser>::EncodedSize;
|
/// Adapter to bridge `rand 0.8` (`rand_core 0.6`) RNGs to `rand_core 0.10`
|
||||||
type RcDecapsulationKeyLen<K> = <<K as KemCore>::DecapsulationKey as EncodedSizeUser>::EncodedSize;
|
/// which is required by `ml-kem 0.3.x`.
|
||||||
type RcCiphertextLen<K> = <K as KemCore>::CiphertextSize;
|
struct RngCompat<'a, R>(&'a mut R);
|
||||||
type RcSharedSecretLen<K> = <K as KemCore>::SharedKeySize;
|
|
||||||
|
|
||||||
|
impl<R: RngCore> rand_core_10::TryRng for RngCompat<'_, R> {
|
||||||
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
|
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
|
||||||
|
Ok(self.0.next_u32())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
|
||||||
|
Ok(self.0.next_u64())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
|
||||||
|
self.0.fill_bytes(dst);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: RngCore + CryptoRng> rand_core_10::TryCryptoRng for RngCompat<'_, R> {}
|
||||||
|
|
||||||
|
type RcEncapsulationKeyLen<K> = <<K as MlKemTrait>::EncapsulationKey as KeySizeUser>::KeySize;
|
||||||
|
#[allow(deprecated)]
|
||||||
|
type RcDecapsulationKeyLen<K> =
|
||||||
|
<<K as MlKemTrait>::DecapsulationKey as ExpandedKeyEncoding>::EncodedSize;
|
||||||
|
type RcCiphertextLen<K> = <K as MlKemTrait>::CiphertextSize;
|
||||||
|
type RcSharedSecretLen<K> = <K as MlKemTrait>::SharedKeySize;
|
||||||
|
|
||||||
|
#[allow(deprecated)]
|
||||||
impl<K> KemCoreWrapper for K
|
impl<K> KemCoreWrapper for K
|
||||||
where
|
where
|
||||||
K: KemCore,
|
K: MlKemTrait,
|
||||||
K::EncapsulationKey: Encapsulate<MlKemCiphertext<K>, MlKemSharedKey<K>> + Clone,
|
K::EncapsulationKey: Encapsulate<Kem = K> + KeyExport + TryKeyInit + Clone,
|
||||||
K::DecapsulationKey: Decapsulate<MlKemCiphertext<K>, MlKemSharedKey<K>> + Clone + ZeroizeOnDrop,
|
K::DecapsulationKey: Decapsulate<Kem = K> + ExpandedKeyEncoding + Clone + ZeroizeOnDrop,
|
||||||
RcEncapsulationKeyLen<K>: ArrayLength<u8>,
|
RcEncapsulationKeyLen<K>: ArrayLength<u8>,
|
||||||
RcDecapsulationKeyLen<K>: ArrayLength<u8>,
|
RcDecapsulationKeyLen<K>: ArrayLength<u8>,
|
||||||
RcCiphertextLen<K>: ArrayLength<u8>,
|
RcCiphertextLen<K>: ArrayLength<u8>,
|
||||||
@@ -140,13 +167,13 @@ where
|
|||||||
fn generate<R: RngCore + CryptoRng>(
|
fn generate<R: RngCore + CryptoRng>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError> {
|
) -> Result<(Self::DecapsulationKey, Self::EncapsulationKey), ProtocolError> {
|
||||||
Ok(K::generate(rng))
|
Ok(K::generate_keypair_from_rng(&mut RngCompat(rng)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_encapsulation_key(
|
fn serialize_encapsulation_key(
|
||||||
key: &Self::EncapsulationKey,
|
key: &Self::EncapsulationKey,
|
||||||
) -> GenericArray<u8, Self::EncapsulationKeyLen> {
|
) -> GenericArray<u8, Self::EncapsulationKeyLen> {
|
||||||
GenericArray::clone_from_slice(key.as_bytes().as_slice())
|
GenericArray::clone_from_slice(key.to_bytes().as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_encapsulation_key(
|
fn deserialize_encapsulation_key(
|
||||||
@@ -154,15 +181,15 @@ where
|
|||||||
) -> Result<Self::EncapsulationKey, ProtocolError> {
|
) -> Result<Self::EncapsulationKey, ProtocolError> {
|
||||||
let bytes: GenericArray<u8, RcEncapsulationKeyLen<K>> =
|
let bytes: GenericArray<u8, RcEncapsulationKeyLen<K>> =
|
||||||
input.take_array("kem encapsulation key")?;
|
input.take_array("kem encapsulation key")?;
|
||||||
let encoded = Encoded::<K::EncapsulationKey>::try_from(bytes.as_slice())
|
let key = ml_kem::array::Array::try_from(bytes.as_slice())
|
||||||
.map_err(|_| ProtocolError::SerializationError)?;
|
.map_err(|_| ProtocolError::SerializationError)?;
|
||||||
Ok(K::EncapsulationKey::from_bytes(&encoded))
|
TryKeyInit::new(&key).map_err(|_| ProtocolError::SerializationError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_decapsulation_key(
|
fn serialize_decapsulation_key(
|
||||||
key: &Self::DecapsulationKey,
|
key: &Self::DecapsulationKey,
|
||||||
) -> GenericArray<u8, Self::DecapsulationKeyLen> {
|
) -> GenericArray<u8, Self::DecapsulationKeyLen> {
|
||||||
GenericArray::clone_from_slice(key.as_bytes().as_slice())
|
GenericArray::clone_from_slice(key.to_expanded_bytes().as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_decapsulation_key(
|
fn deserialize_decapsulation_key(
|
||||||
@@ -170,9 +197,10 @@ where
|
|||||||
) -> Result<Self::DecapsulationKey, ProtocolError> {
|
) -> Result<Self::DecapsulationKey, ProtocolError> {
|
||||||
let bytes: GenericArray<u8, RcDecapsulationKeyLen<K>> =
|
let bytes: GenericArray<u8, RcDecapsulationKeyLen<K>> =
|
||||||
input.take_array("kem decapsulation key")?;
|
input.take_array("kem decapsulation key")?;
|
||||||
let encoded = Encoded::<K::DecapsulationKey>::try_from(bytes.as_slice())
|
let key = ml_kem::array::Array::try_from(bytes.as_slice())
|
||||||
.map_err(|_| ProtocolError::SerializationError)?;
|
.map_err(|_| ProtocolError::SerializationError)?;
|
||||||
Ok(K::DecapsulationKey::from_bytes(&encoded))
|
K::DecapsulationKey::from_expanded_bytes(&key)
|
||||||
|
.map_err(|_| ProtocolError::SerializationError)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn encapsulate<R: RngCore + CryptoRng>(
|
fn encapsulate<R: RngCore + CryptoRng>(
|
||||||
@@ -185,14 +213,11 @@ where
|
|||||||
),
|
),
|
||||||
ProtocolError,
|
ProtocolError,
|
||||||
> {
|
> {
|
||||||
key.encapsulate(rng)
|
let (ciphertext, shared) = key.encapsulate_with_rng(&mut RngCompat(rng));
|
||||||
.map(|(ciphertext, shared)| {
|
Ok((
|
||||||
(
|
GenericArray::clone_from_slice(ciphertext.as_slice()),
|
||||||
GenericArray::clone_from_slice(ciphertext.as_slice()),
|
GenericArray::clone_from_slice(shared.as_slice()),
|
||||||
GenericArray::clone_from_slice(shared.as_slice()),
|
))
|
||||||
)
|
|
||||||
})
|
|
||||||
.map_err(|_| ProtocolError::LibraryError(InternalError::KemError))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decapsulate(
|
fn decapsulate(
|
||||||
@@ -201,9 +226,8 @@ where
|
|||||||
) -> Result<GenericArray<u8, Self::SharedSecretLen>, ProtocolError> {
|
) -> Result<GenericArray<u8, Self::SharedSecretLen>, ProtocolError> {
|
||||||
let ciphertext = MlKemCiphertext::<K>::try_from(encapsulated_key.as_slice())
|
let ciphertext = MlKemCiphertext::<K>::try_from(encapsulated_key.as_slice())
|
||||||
.map_err(|_| ProtocolError::SerializationError)?;
|
.map_err(|_| ProtocolError::SerializationError)?;
|
||||||
key.decapsulate(&ciphertext)
|
let shared = key.decapsulate(&ciphertext);
|
||||||
.map(|shared| GenericArray::clone_from_slice(shared.as_slice()))
|
Ok(GenericArray::clone_from_slice(shared.as_slice()))
|
||||||
.map_err(|_| ProtocolError::LibraryError(InternalError::KemError))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Triple Diffie-Hellman-style key exchange that offloads the second hop to a
|
/// Triple Diffie-Hellman-style key exchange that offloads the second hop to a
|
||||||
|
|||||||
+3
-2
@@ -11,7 +11,7 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Minimum Supported Rust Version
|
//! ### Minimum Supported Rust Version
|
||||||
//!
|
//!
|
||||||
//! Rust **1.85** or higher.
|
//! Rust **1.87** or higher.
|
||||||
//!
|
//!
|
||||||
//! # Overview
|
//! # Overview
|
||||||
//!
|
//!
|
||||||
@@ -1383,9 +1383,10 @@ mod tests;
|
|||||||
|
|
||||||
#[cfg(feature = "argon2")]
|
#[cfg(feature = "argon2")]
|
||||||
pub use argon2;
|
pub use argon2;
|
||||||
|
pub use generic_array;
|
||||||
#[cfg(feature = "kem")]
|
#[cfg(feature = "kem")]
|
||||||
pub use ml_kem;
|
pub use ml_kem;
|
||||||
pub use {generic_array, rand};
|
pub use rand;
|
||||||
|
|
||||||
pub use crate::ciphersuite::CipherSuite;
|
pub use crate::ciphersuite::CipherSuite;
|
||||||
#[cfg(feature = "curve25519")]
|
#[cfg(feature = "curve25519")]
|
||||||
|
|||||||
Reference in New Issue
Block a user