Skip to content

Commit fa5b737

Browse files
doublegateclaude
andcommitted
fix(ci): upgrade ml-dsa to 0.1.0-rc.5 and fix --all-features build
Resolves CI failures caused by ml-dsa v0.0.4 breaking under --all-features (unconditional pkcs8-gated code requiring missing der/spki crates) and a RUSTSEC advisory requiring >=0.1.0-rc.3. Also fixes missing key_commitment field in benchmark exposed by --all-features enabling key-commitment feature. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 668d8ae commit fa5b737

File tree

3 files changed

+23
-20
lines changed

3 files changed

+23
-20
lines changed

crates/wraith-crypto/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ subtle = { version = "2.5", default-features = false }
2929
curve25519-elligator2 = { version = "0.1.0-alpha.2", features = ["elligator2"], default-features = false }
3030
ml-kem = { version = "0.2.2", default-features = false }
3131
kem = "0.3.0-pre.0"
32-
ml-dsa = { version = "0.0.4", default-features = false, features = ["alloc", "rand_core"], optional = true }
32+
ml-dsa = { version = "0.1.0-rc.5", default-features = false, features = ["alloc", "rand_core"], optional = true }
3333
signature = { version = "3.0.0-rc.9", default-features = false, optional = true }
3434

3535
[dev-dependencies]

crates/wraith-crypto/benches/crypto_bench.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -417,6 +417,7 @@ fn bench_message_header_serialize(c: &mut Criterion) {
417417
dh_public,
418418
prev_chain_length: 100,
419419
message_number: 42,
420+
key_commitment: None,
420421
};
421422

422423
c.bench_function("message_header_serialize", |b| {

crates/wraith-crypto/src/mldsa.rs

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,6 @@
1111
//! definitions and a trait interface but no implementation, allowing downstream
1212
//! code to be written against the interface without requiring the dependency.
1313
14-
#[cfg(feature = "pq-signatures")]
15-
use ml_dsa::{KeyGen, MlDsa65};
16-
17-
#[cfg(feature = "pq-signatures")]
18-
use rand_core::{CryptoRng, RngCore};
19-
2014
use crate::error::CryptoError;
2115
use alloc::vec::Vec;
2216

@@ -68,9 +62,10 @@ impl MlDsa65VerifyingKey {
6862
/// Returns [`CryptoError::InvalidSignature`] if the signature is invalid.
6963
#[cfg(feature = "pq-signatures")]
7064
pub fn verify(&self, message: &[u8], signature: &MlDsa65Signature) -> Result<(), CryptoError> {
71-
use ml_dsa::Verifier;
72-
let vk = ml_dsa::VerifyingKey::<ml_dsa::MlDsa65>::try_from(self.bytes.as_slice())
65+
use ml_dsa::signature::Verifier;
66+
let enc = ml_dsa::EncodedVerifyingKey::<ml_dsa::MlDsa65>::try_from(self.bytes.as_slice())
7367
.map_err(|_| CryptoError::InvalidPublicKey)?;
68+
let vk = ml_dsa::VerifyingKey::<ml_dsa::MlDsa65>::decode(&enc);
7469
let sig = ml_dsa::Signature::<ml_dsa::MlDsa65>::try_from(signature.as_bytes())
7570
.map_err(|_| CryptoError::InvalidSignature)?;
7671
vk.verify(message, &sig)
@@ -95,8 +90,8 @@ impl MlDsa65VerifyingKey {
9590
/// ML-DSA-65 signing key.
9691
#[allow(dead_code)]
9792
pub struct MlDsa65SigningKey {
98-
/// Raw signing key bytes.
99-
bytes: Vec<u8>,
93+
/// 32-byte seed for deterministic key regeneration.
94+
seed: Vec<u8>,
10095
/// Corresponding verifying (public) key.
10196
verifying_key: MlDsa65VerifyingKey,
10297
}
@@ -108,13 +103,18 @@ impl MlDsa65SigningKey {
108103
///
109104
/// Returns [`CryptoError::InvalidState`] when the `pq-signatures` feature is not enabled.
110105
#[cfg(feature = "pq-signatures")]
111-
pub fn generate<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
112-
use signature::Keypair;
113-
let kp = MlDsa65::key_gen(rng);
114-
let sk_bytes: Vec<u8> = kp.signing_key().to_bytes().to_vec();
115-
let vk_bytes: Vec<u8> = kp.verifying_key().to_bytes().to_vec();
106+
pub fn generate<R: rand_core::RngCore + rand_core::CryptoRng>(rng: &mut R) -> Self {
107+
// Generate a 32-byte seed using the caller's RNG (rand_core 0.6).
108+
// Then use from_seed which avoids the rand_core version mismatch.
109+
let mut seed = [0u8; 32];
110+
rng.fill_bytes(&mut seed);
111+
112+
let seed_array = ml_dsa::Seed::try_from(seed.as_slice()).expect("seed is exactly 32 bytes");
113+
let sk = ml_dsa::SigningKey::<ml_dsa::MlDsa65>::from_seed(&seed_array);
114+
let vk = sk.verifying_key();
115+
let vk_bytes: Vec<u8> = vk.encode().to_vec();
116116
Self {
117-
bytes: sk_bytes,
117+
seed: seed.to_vec(),
118118
verifying_key: MlDsa65VerifyingKey::from_bytes(vk_bytes),
119119
}
120120
}
@@ -136,10 +136,12 @@ impl MlDsa65SigningKey {
136136
/// Returns [`CryptoError::InvalidState`] when the `pq-signatures` feature is not enabled.
137137
#[cfg(feature = "pq-signatures")]
138138
pub fn sign(&self, message: &[u8]) -> Result<MlDsa65Signature, CryptoError> {
139-
use ml_dsa::Signer;
140-
let sk = ml_dsa::SigningKey::<ml_dsa::MlDsa65>::try_from(self.bytes.as_slice())
139+
use ml_dsa::signature::Signer;
140+
let seed = ml_dsa::Seed::try_from(self.seed.as_slice())
141141
.map_err(|_| CryptoError::InvalidKeyMaterial)?;
142-
let sig = sk.sign(message);
142+
let sk = ml_dsa::SigningKey::<ml_dsa::MlDsa65>::from_seed(&seed);
143+
let sig: ml_dsa::Signature<ml_dsa::MlDsa65> = sk.sign(message);
144+
use ml_dsa::signature::SignatureEncoding;
143145
Ok(MlDsa65Signature::from_bytes(sig.to_bytes().to_vec()))
144146
}
145147

0 commit comments

Comments
 (0)