Skip to content
Open
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
81 changes: 51 additions & 30 deletions ml-dsa/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,18 @@ impl<P: MlDsaParams> CtEq for SigningKey<P> {
}
}

#[cfg(feature = "zeroize")]
impl<P: MlDsaParams> Drop for SigningKey<P> {
fn drop(&mut self) {
// `signing_key` is zeroized by its own `Drop` impl. Zeroize the seed,
// which is private key material (it regenerates the signing key).
self.seed.zeroize();
}
}

#[cfg(feature = "zeroize")]
impl<P: MlDsaParams> ZeroizeOnDrop for SigningKey<P> {}

/// An ML-DSA signing key
#[derive(Clone)]
pub struct ExpandedSigningKey<P: MlDsaParams> {
Expand Down Expand Up @@ -357,9 +369,32 @@ impl<P: MlDsaParams> ExpandedSigningKey<P> {
/// This method reflects the ML-DSA.KeyGen_internal algorithm from FIPS 204, but only returns a
/// signing key.
#[must_use]
pub fn from_seed(seed: &Seed) -> Self {
let kp = P::from_seed(seed);
kp.signing_key
pub fn from_seed(xi: &Seed) -> Self {
// Derive seeds
let mut h = H::default()
.absorb(xi)
.absorb(&[P::K::U8])
.absorb(&[P::L::U8]);

let rho: B32 = h.squeeze_new();
let rhop: B64 = h.squeeze_new();
let K: B32 = h.squeeze_new();

// Sample private key components
let A_hat = expand_a::<P::K, P::L>(&rho);
let s1 = expand_s::<P::L>(&rhop, P::Eta::ETA, 0);
let s2 = expand_s::<P::K>(&rhop, P::Eta::ETA, P::L::USIZE);

// Compute derived values
let As1_hat = &A_hat * &s1.ntt();
let t = &As1_hat.ntt_inverse() + &s2;

// Compress and encode
let (t1, t0) = t.power2round();

let enc = VerifyingKey::<P>::encode_internal(&rho, &t1);
let tr: B64 = H::default().absorb(&enc).squeeze_new();
ExpandedSigningKey::new(rho, K, tr, s1, s2, t0, A_hat)
}

/// This method reflects the ML-DSA.Sign_internal algorithm from FIPS 204. It does not
Expand Down Expand Up @@ -947,34 +982,8 @@ where
where
P: MlDsaParams,
{
// Derive seeds
let mut h = H::default()
.absorb(xi)
.absorb(&[P::K::U8])
.absorb(&[P::L::U8]);

let rho: B32 = h.squeeze_new();
let rhop: B64 = h.squeeze_new();
let K: B32 = h.squeeze_new();

// Sample private key components
let A_hat = expand_a::<P::K, P::L>(&rho);
let s1 = expand_s::<P::L>(&rhop, P::Eta::ETA, 0);
let s2 = expand_s::<P::K>(&rhop, P::Eta::ETA, P::L::USIZE);

// Compute derived values
let As1_hat = &A_hat * &s1.ntt();
let t = &As1_hat.ntt_inverse() + &s2;

// Compress and encode
let (t1, t0) = t.power2round();

let enc = VerifyingKey::<P>::encode_internal(&rho, &t1);
let tr: B64 = H::default().absorb(&enc).squeeze_new();
let signing_key = ExpandedSigningKey::new(rho, K, tr, s1, s2, t0, A_hat);

SigningKey {
signing_key,
signing_key: ExpandedSigningKey::<P>::from_seed(xi),
seed: xi.clone(),
}
}
Expand Down Expand Up @@ -1258,6 +1267,18 @@ mod test {
test_derived_vk::<MlDsa87>();
}

#[test]
#[cfg(feature = "zeroize")]
fn zeroize_on_drop_impls() {
fn assert_zeroize_on_drop<T: ZeroizeOnDrop>() {}
assert_zeroize_on_drop::<SigningKey<MlDsa44>>();
assert_zeroize_on_drop::<SigningKey<MlDsa65>>();
assert_zeroize_on_drop::<SigningKey<MlDsa87>>();
assert_zeroize_on_drop::<ExpandedSigningKey<MlDsa44>>();
assert_zeroize_on_drop::<ExpandedSigningKey<MlDsa65>>();
assert_zeroize_on_drop::<ExpandedSigningKey<MlDsa87>>();
}

#[test]
#[cfg(feature = "alloc")]
fn debug_implementations() {
Expand Down
16 changes: 14 additions & 2 deletions ml-dsa/src/pkcs8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,9 +151,21 @@ where
type Error = ::pkcs8::Error;

fn try_from(private_key_info: ::pkcs8::PrivateKeyInfoRef<'_>) -> ::pkcs8::Result<Self> {
let keypair = SigningKey::try_from(private_key_info)?;
private_key_info
.algorithm
.assert_algorithm_oid(P::ALGORITHM_IDENTIFIER.oid)?;

let mut reader = der::SliceReader::new(private_key_info.private_key.as_bytes())?;
let seed_string = SeedString::decode_implicit(&mut reader, SEED_TAG_NUMBER)?
.ok_or(pkcs8::Error::KeyMalformed)?;
let seed = seed_string
.value
.as_bytes()
.try_into()
.map_err(|_| pkcs8::Error::KeyMalformed)?;
reader.finish()?;

Ok(keypair.signing_key)
Ok(ExpandedSigningKey::<P>::from_seed(&seed))
}
}

Expand Down
Loading