diff --git a/ml-dsa/benches/ml_dsa.rs b/ml-dsa/benches/ml_dsa.rs index 0d2d1e8b..69055abc 100644 --- a/ml-dsa/benches/ml_dsa.rs +++ b/ml-dsa/benches/ml_dsa.rs @@ -15,7 +15,7 @@ fn criterion_benchmark(c: &mut Criterion) { let m: B32 = rand(&mut rng); let ctx: B32 = rand(&mut rng); - let kp = MlDsa65::key_gen_internal(&xi); + let kp = MlDsa65::from_seed(&xi); let sk = kp.signing_key(); let vk = kp.verifying_key(); let sig = sk.sign_deterministic(&m, &ctx).unwrap(); @@ -27,7 +27,7 @@ fn criterion_benchmark(c: &mut Criterion) { // Key generation c.bench_function("keygen", |b| { b.iter(|| { - let kp = MlDsa65::key_gen_internal(&xi); + let kp = MlDsa65::from_seed(&xi); let _sk_bytes = kp.signing_key().encode(); let _vk_bytes = kp.verifying_key().encode(); }) @@ -53,7 +53,7 @@ fn criterion_benchmark(c: &mut Criterion) { // Round trip c.bench_function("round_trip", |b| { b.iter(|| { - let kp = MlDsa65::key_gen_internal(&xi); + let kp = MlDsa65::from_seed(&xi); let sig = kp.signing_key().sign_deterministic(&m, &ctx).unwrap(); let _ver = kp.verifying_key().verify_with_context(&m, &ctx, &sig); }) diff --git a/ml-dsa/src/lib.rs b/ml-dsa/src/lib.rs index 17dd7336..fb381af7 100644 --- a/ml-dsa/src/lib.rs +++ b/ml-dsa/src/lib.rs @@ -237,7 +237,7 @@ where let seed = Array::try_from(private_key_info.private_key.as_bytes()) .map_err(|_| pkcs8::Error::KeyMalformed)?; - Ok(P::key_gen_internal(&seed)) + Ok(P::from_seed(&seed)) } } @@ -352,6 +352,16 @@ impl SigningKey

{ } } + /// Deterministically generate a signing key from the specified seed. + /// + /// 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: &B32) -> Self { + let kp = P::from_seed(seed); + kp.signing_key + } + /// This method reflects the ML-DSA.Sign_internal algorithm from FIPS 204. It does not /// include the domain separator that distinguishes between the normal and pre-hashed cases, /// and it does not separate the context string from the rest of the message. @@ -913,8 +923,9 @@ pub trait KeyGen: MlDsaParams { fn key_gen(rng: &mut R) -> Self::KeyPair; /// Deterministically generate a signing key pair from the specified seed - // TODO(RLB): Only expose this based on a feature. - fn key_gen_internal(xi: &B32) -> Self::KeyPair; + /// + /// This method reflects the ML-DSA.KeyGen_internal algorithm from FIPS 204. + fn from_seed(xi: &B32) -> Self::KeyPair; } impl

KeyGen for P @@ -929,12 +940,14 @@ where fn key_gen(rng: &mut R) -> KeyPair

{ let mut xi = B32::default(); rng.fill_bytes(&mut xi); - Self::key_gen_internal(&xi) + Self::from_seed(&xi) } /// Deterministically generate a signing key pair from the specified seed + /// + /// This method reflects the ML-DSA.KeyGen_internal algorithm from FIPS 204. // Algorithm 6 ML-DSA.KeyGen_internal - fn key_gen_internal(xi: &B32) -> KeyPair

+ fn from_seed(xi: &B32) -> KeyPair

where P: MlDsaParams, { @@ -1001,7 +1014,7 @@ mod test { where P: MlDsaParams + PartialEq, { - let kp = P::key_gen_internal(&Array::default()); + let kp = P::from_seed(&Array::default()); let sk = kp.signing_key; let vk = kp.verifying_key; @@ -1032,7 +1045,7 @@ mod test { where P: MlDsaParams + PartialEq, { - let kp = P::key_gen_internal(&Array::default()); + let kp = P::from_seed(&Array::default()); let sk = kp.signing_key; let vk = kp.verifying_key; let vk_derived = sk.verifying_key(); @@ -1051,7 +1064,7 @@ mod test { where P: MlDsaParams, { - let kp = P::key_gen_internal(&Array::default()); + let kp = P::from_seed(&Array::default()); let sk = kp.signing_key; let vk = kp.verifying_key; @@ -1084,7 +1097,7 @@ mod test { let seed_data: &mut [u8] = seed.as_mut(); rng.fill(seed_data); - let kp = P::key_gen_internal(&seed); + let kp = P::from_seed(&seed); let sk = kp.signing_key; let vk = kp.verifying_key; @@ -1113,7 +1126,7 @@ mod test { where P: MlDsaParams, { - let kp = P::key_gen_internal(&Array::default()); + let kp = P::from_seed(&Array::default()); let sk = kp.signing_key; let vk = kp.verifying_key; @@ -1135,7 +1148,7 @@ mod test { where P: MlDsaParams, { - let kp = P::key_gen_internal(&Array::default()); + let kp = P::from_seed(&Array::default()); let sk = kp.signing_key; let vk = kp.verifying_key; @@ -1157,7 +1170,7 @@ mod test { where P: MlDsaParams, { - let kp = P::key_gen_internal(&Array::default()); + let kp = P::from_seed(&Array::default()); let sk = kp.signing_key; let vk = kp.verifying_key; @@ -1172,4 +1185,22 @@ mod test { sign_internal_verify_mu::(); sign_internal_verify_mu::(); } + + #[test] + fn from_seed_implementations_match() { + fn assert_from_seed_equality

() + where + P: MlDsaParams, + { + let seed = Array([0u8; 32]); + let kp1 = P::from_seed(&seed); + let sk1 = SigningKey::

::from_seed(&seed); + let vk1 = sk1.verifying_key(); + assert_eq!(kp1.signing_key, sk1); + assert_eq!(kp1.verifying_key, vk1); + } + assert_from_seed_equality::(); + assert_from_seed_equality::(); + assert_from_seed_equality::(); + } } diff --git a/ml-dsa/tests/key-gen.rs b/ml-dsa/tests/key-gen.rs index 5cdc478a..464c05da 100644 --- a/ml-dsa/tests/key-gen.rs +++ b/ml-dsa/tests/key-gen.rs @@ -31,7 +31,7 @@ fn verify(tc: &acvp::TestCase) { let vk_bytes = EncodedVerifyingKey::

::try_from(tc.pk.as_slice()).unwrap(); let sk_bytes = EncodedSigningKey::

::try_from(tc.sk.as_slice()).unwrap(); - let kp = P::key_gen_internal(&seed); + let kp = P::from_seed(&seed); let sk = kp.signing_key().clone(); let vk = kp.verifying_key().clone(); diff --git a/ml-dsa/tests/proptests.rs b/ml-dsa/tests/proptests.rs index c80f1c63..8e62fca2 100644 --- a/ml-dsa/tests/proptests.rs +++ b/ml-dsa/tests/proptests.rs @@ -11,17 +11,17 @@ const MSG: &[u8] = b"Hello world"; // Keypairs prop_compose! { fn mldsa44_keypair()(seed_bytes in any::<[u8; 32]>()) -> KeyPair { - MlDsa44::key_gen_internal(seed_bytes.as_array_ref()) + MlDsa44::from_seed(seed_bytes.as_array_ref()) } } prop_compose! { fn mldsa65_keypair()(seed_bytes in any::<[u8; 32]>()) -> KeyPair { - MlDsa65::key_gen_internal(seed_bytes.as_array_ref()) + MlDsa65::from_seed(seed_bytes.as_array_ref()) } } prop_compose! { fn mldsa87_keypair()(seed_bytes in any::<[u8; 32]>()) -> KeyPair { - MlDsa87::key_gen_internal(seed_bytes.as_array_ref()) + MlDsa87::from_seed(seed_bytes.as_array_ref()) } }