mirror of
https://github.com/RustCrypto/signatures
synced 2026-06-21 13:45:42 +00:00
ml-dsa: lower stack size of KeyGen::from_seed by up to 207kb (#1261)
This reworks the API to make KeyGen::from_seed return a `SeededSigningKey` instead of a `KeyPair`. The `SeededSigningKey` effectively replaces the `KeyPair`, and instead of eagerly generating the VerifyingKey (implementing `signature::KeypairRef`), it implements `signature::Keypair` and makes the verifying key when requested. This reduces the depth of the stack when calling from_seed and reduces the size of the stack by 207kb using ML-DSA-87 in debug/tests builds (the heaviest consumers). This is an API break.
This commit is contained in:
@@ -1,7 +1,9 @@
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use getrandom::SysRng;
|
||||
use hybrid_array::{Array, ArraySize};
|
||||
use ml_dsa::{B32, KeyGen, MlDsa65, Signature, SigningKey, VerifyingKey};
|
||||
use ml_dsa::{
|
||||
B32, ExpandedSigningKey, KeyGen, MlDsa65, Signature, VerifyingKey, signature::Keypair,
|
||||
};
|
||||
use rand_core::{CryptoRng, UnwrapErr};
|
||||
|
||||
pub fn rand<L: ArraySize, R: CryptoRng + ?Sized>(rng: &mut R) -> Array<u8, L> {
|
||||
@@ -38,7 +40,7 @@ fn criterion_benchmark(c: &mut Criterion) {
|
||||
// Signing
|
||||
c.bench_function("sign", |b| {
|
||||
b.iter(|| {
|
||||
let sk = SigningKey::<MlDsa65>::from_expanded(&sk_bytes);
|
||||
let sk = ExpandedSigningKey::<MlDsa65>::from_expanded(&sk_bytes);
|
||||
let _sig = sk.sign_deterministic(&m, &ctx);
|
||||
})
|
||||
});
|
||||
|
||||
+98
-110
@@ -45,7 +45,9 @@ mod param;
|
||||
pub mod pkcs8;
|
||||
mod sampling;
|
||||
|
||||
pub use crate::param::{EncodedSignature, EncodedVerifyingKey, ExpandedSigningKey, MlDsaParams};
|
||||
pub use crate::param::{
|
||||
EncodedSignature, EncodedVerifyingKey, ExpandedSigningKeyBytes, MlDsaParams,
|
||||
};
|
||||
pub use signature::{self, Error};
|
||||
|
||||
use crate::algebra::{AlgebraExt, Elem, NttMatrix, NttVector, Vector};
|
||||
@@ -54,7 +56,7 @@ use crate::hint::Hint;
|
||||
use crate::ntt::{Ntt, NttInverse};
|
||||
use crate::param::{ParameterSet, QMinus1, SamplingSize, SpecQ};
|
||||
use crate::sampling::{expand_a, expand_mask, expand_s, sample_in_ball};
|
||||
use core::convert::{AsRef, TryFrom, TryInto};
|
||||
use core::convert::{TryFrom, TryInto};
|
||||
use core::fmt;
|
||||
use hybrid_array::{
|
||||
Array,
|
||||
@@ -184,31 +186,23 @@ impl AsMut<Shake256> for MuBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// An ML-DSA key pair
|
||||
pub struct KeyPair<P: MlDsaParams> {
|
||||
/// An ML-DSA signing key initialized through a seed
|
||||
pub struct SigningKey<P: MlDsaParams> {
|
||||
/// The signing key of the key pair
|
||||
signing_key: SigningKey<P>,
|
||||
|
||||
/// The verifying key of the key pair
|
||||
verifying_key: VerifyingKey<P>,
|
||||
signing_key: ExpandedSigningKey<P>,
|
||||
|
||||
/// The seed this signing key was derived from
|
||||
seed: B32,
|
||||
}
|
||||
|
||||
impl<P: MlDsaParams> KeyPair<P> {
|
||||
impl<P: MlDsaParams> SigningKey<P> {
|
||||
/// The signing key of the key pair
|
||||
pub fn signing_key(&self) -> &SigningKey<P> {
|
||||
pub fn signing_key(&self) -> &ExpandedSigningKey<P> {
|
||||
&self.signing_key
|
||||
}
|
||||
|
||||
/// The verifying key of the key pair
|
||||
pub fn verifying_key(&self) -> &VerifyingKey<P> {
|
||||
&self.verifying_key
|
||||
}
|
||||
|
||||
/// Serialize the [`Seed`] value: 32-bytes which can be used to reconstruct the
|
||||
/// [`KeyPair`].
|
||||
/// [`SigningKey`].
|
||||
///
|
||||
/// # ⚠️ Warning!
|
||||
///
|
||||
@@ -219,43 +213,38 @@ impl<P: MlDsaParams> KeyPair<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: MlDsaParams> AsRef<VerifyingKey<P>> for KeyPair<P> {
|
||||
fn as_ref(&self) -> &VerifyingKey<P> {
|
||||
&self.verifying_key
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: MlDsaParams> fmt::Debug for KeyPair<P> {
|
||||
impl<P: MlDsaParams> fmt::Debug for SigningKey<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("KeyPair")
|
||||
.field("verifying_key", &self.verifying_key)
|
||||
.finish_non_exhaustive()
|
||||
f.debug_struct("SigningKey").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: MlDsaParams> signature::KeypairRef for KeyPair<P> {
|
||||
impl<P: MlDsaParams> signature::Keypair for SigningKey<P> {
|
||||
type VerifyingKey = VerifyingKey<P>;
|
||||
fn verifying_key(&self) -> VerifyingKey<P> {
|
||||
self.signing_key.verifying_key()
|
||||
}
|
||||
}
|
||||
|
||||
/// The `Signer` implementation for `KeyPair` uses the optional deterministic variant of ML-DSA, and
|
||||
/// The `Signer` implementation for `SigningKey` uses the optional deterministic variant of ML-DSA, and
|
||||
/// only supports signing with an empty context string.
|
||||
impl<P: MlDsaParams> Signer<Signature<P>> for KeyPair<P> {
|
||||
impl<P: MlDsaParams> Signer<Signature<P>> for SigningKey<P> {
|
||||
fn try_sign(&self, msg: &[u8]) -> Result<Signature<P>, Error> {
|
||||
self.try_multipart_sign(&[msg])
|
||||
}
|
||||
}
|
||||
|
||||
/// The `Signer` implementation for `KeyPair` uses the optional deterministic variant of ML-DSA, and
|
||||
/// The `Signer` implementation for `SigningKey` uses the optional deterministic variant of ML-DSA, and
|
||||
/// only supports signing with an empty context string.
|
||||
impl<P: MlDsaParams> MultipartSigner<Signature<P>> for KeyPair<P> {
|
||||
impl<P: MlDsaParams> MultipartSigner<Signature<P>> for SigningKey<P> {
|
||||
fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result<Signature<P>, Error> {
|
||||
self.signing_key.raw_sign_deterministic(msg, &[])
|
||||
}
|
||||
}
|
||||
|
||||
/// The `DigestSigner` implementation for `KeyPair` uses the optional deterministic variant of ML-DSA
|
||||
/// The `DigestSigner` implementation for `SigningKey` uses the optional deterministic variant of ML-DSA
|
||||
/// with a pre-computed μ, and only supports signing with an empty context string.
|
||||
impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for KeyPair<P> {
|
||||
impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for SigningKey<P> {
|
||||
fn try_sign_digest<F: Fn(&mut Shake256) -> Result<(), Error>>(
|
||||
&self,
|
||||
f: F,
|
||||
@@ -266,7 +255,7 @@ impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for KeyPair<P> {
|
||||
|
||||
/// An ML-DSA signing key
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct SigningKey<P: MlDsaParams> {
|
||||
pub struct ExpandedSigningKey<P: MlDsaParams> {
|
||||
rho: B32,
|
||||
K: B32,
|
||||
tr: B64,
|
||||
@@ -281,14 +270,14 @@ pub struct SigningKey<P: MlDsaParams> {
|
||||
A_hat: NttMatrix<P::K, P::L>,
|
||||
}
|
||||
|
||||
impl<P: MlDsaParams> fmt::Debug for SigningKey<P> {
|
||||
impl<P: MlDsaParams> fmt::Debug for ExpandedSigningKey<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("SigningKey").finish_non_exhaustive()
|
||||
f.debug_struct("ExpandedSigningKey").finish_non_exhaustive()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl<P: MlDsaParams> Drop for SigningKey<P> {
|
||||
impl<P: MlDsaParams> Drop for ExpandedSigningKey<P> {
|
||||
fn drop(&mut self) {
|
||||
self.rho.zeroize();
|
||||
self.K.zeroize();
|
||||
@@ -300,9 +289,9 @@ impl<P: MlDsaParams> Drop for SigningKey<P> {
|
||||
}
|
||||
|
||||
#[cfg(feature = "zeroize")]
|
||||
impl<P: MlDsaParams> ZeroizeOnDrop for SigningKey<P> {}
|
||||
impl<P: MlDsaParams> ZeroizeOnDrop for ExpandedSigningKey<P> {}
|
||||
|
||||
impl<P: MlDsaParams> SigningKey<P> {
|
||||
impl<P: MlDsaParams> ExpandedSigningKey<P> {
|
||||
fn new(
|
||||
rho: B32,
|
||||
K: B32,
|
||||
@@ -501,14 +490,14 @@ impl<P: MlDsaParams> SigningKey<P> {
|
||||
}
|
||||
|
||||
/// This auxiliary function derives a `VerifyingKey` from a bare
|
||||
/// `SigningKey` (even in the absence of the original seed).
|
||||
/// `ExpandedSigningKey` (even in the absence of the original seed).
|
||||
///
|
||||
/// This is a utility function that is useful when importing the private key
|
||||
/// from an external source which does not export the seed and does not
|
||||
/// provide the precomputed public key associated with the private key
|
||||
/// itself.
|
||||
///
|
||||
/// `SigningKey` implements `signature::Keypair`: this inherent method is
|
||||
/// `ExpandedSigningKey` implements `signature::Keypair`: this inherent method is
|
||||
/// retained for convenience, so it is available for callers even when the
|
||||
/// `signature::Keypair` trait is out-of-scope.
|
||||
pub fn verifying_key(&self) -> VerifyingKey<P> {
|
||||
@@ -518,7 +507,7 @@ impl<P: MlDsaParams> SigningKey<P> {
|
||||
|
||||
/// DEPRECATED: decode the key from an appropriately sized byte array.
|
||||
///
|
||||
/// Note that this form is deprecated in practice; prefer to use [`SigningKey::from_seed`].
|
||||
/// Note that this form is deprecated in practice; prefer to use [`ExpandedSigningKey::from_seed`].
|
||||
///
|
||||
/// <div class="warning">
|
||||
/// <b>Panics</b>
|
||||
@@ -526,11 +515,11 @@ impl<P: MlDsaParams> SigningKey<P> {
|
||||
/// This API does not validate expanded signing keys and can potentially panic if keys are
|
||||
/// malformed or maliciously generated.
|
||||
///
|
||||
/// To avoid panics, use [`SigningKey::from_seed`] instead.
|
||||
/// To avoid panics, use [`ExpandedSigningKey::from_seed`] instead.
|
||||
/// </div>
|
||||
// Algorithm 25 skDecode
|
||||
#[deprecated(since = "0.1.0", note = "use `SigningKey::from_seed` instead")]
|
||||
pub fn from_expanded(enc: &ExpandedSigningKey<P>) -> Self
|
||||
#[deprecated(since = "0.1.0", note = "use `ExpandedSigningKey::from_seed` instead")]
|
||||
pub fn from_expanded(enc: &ExpandedSigningKeyBytes<P>) -> Self
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
@@ -547,10 +536,10 @@ impl<P: MlDsaParams> SigningKey<P> {
|
||||
|
||||
/// DEPRECATED: encode the key in a fixed-size byte array.
|
||||
///
|
||||
/// Note that this form is deprecated in practice; prefer to use [`KeyPair::to_seed`].
|
||||
/// Note that this form is deprecated in practice; prefer to use [`SigningKey:to_seed`].
|
||||
// Algorithm 24 skEncode
|
||||
#[deprecated(since = "0.1.0", note = "use `KeyPair::to_seed` instead")]
|
||||
pub fn to_expanded(&self) -> ExpandedSigningKey<P>
|
||||
#[deprecated(since = "0.1.0", note = "use `SigningKey::to_seed` instead")]
|
||||
pub fn to_expanded(&self) -> ExpandedSigningKeyBytes<P>
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
@@ -568,28 +557,28 @@ impl<P: MlDsaParams> SigningKey<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `Signer` implementation for `SigningKey` uses the optional deterministic variant of ML-DSA, and
|
||||
/// The `Signer` implementation for `ExpandedSigningKey` uses the optional deterministic variant of ML-DSA, and
|
||||
/// only supports signing with an empty context string. If you would like to include a context
|
||||
/// string, use the [`SigningKey::sign_deterministic`] method.
|
||||
impl<P: MlDsaParams> Signer<Signature<P>> for SigningKey<P> {
|
||||
/// string, use the [`ExpandedSigningKey::sign_deterministic`] method.
|
||||
impl<P: MlDsaParams> Signer<Signature<P>> for ExpandedSigningKey<P> {
|
||||
fn try_sign(&self, msg: &[u8]) -> Result<Signature<P>, Error> {
|
||||
self.try_multipart_sign(&[msg])
|
||||
}
|
||||
}
|
||||
|
||||
/// The `Signer` implementation for `SigningKey` uses the optional deterministic variant of ML-DSA, and
|
||||
/// The `Signer` implementation for `ExpandedSigningKey` uses the optional deterministic variant of ML-DSA, and
|
||||
/// only supports signing with an empty context string. If you would like to include a context
|
||||
/// string, use the [`SigningKey::sign_deterministic`] method.
|
||||
impl<P: MlDsaParams> MultipartSigner<Signature<P>> for SigningKey<P> {
|
||||
/// string, use the [`ExpandedSigningKey::sign_deterministic`] method.
|
||||
impl<P: MlDsaParams> MultipartSigner<Signature<P>> for ExpandedSigningKey<P> {
|
||||
fn try_multipart_sign(&self, msg: &[&[u8]]) -> Result<Signature<P>, Error> {
|
||||
self.raw_sign_deterministic(msg, &[])
|
||||
}
|
||||
}
|
||||
|
||||
/// The `Signer` implementation for `SigningKey` uses the optional deterministic variant of ML-DSA
|
||||
/// The `Signer` implementation for `ExpandedSigningKey` uses the optional deterministic variant of ML-DSA
|
||||
/// with a pre-computed µ, and only supports signing with an empty context string. If you would
|
||||
/// like to include a context string, use the [`SigningKey::sign_mu_deterministic`] method.
|
||||
impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for SigningKey<P> {
|
||||
/// like to include a context string, use the [`ExpandedSigningKey::sign_mu_deterministic`] method.
|
||||
impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for ExpandedSigningKey<P> {
|
||||
fn try_sign_digest<F: Fn(&mut Shake256) -> Result<(), Error>>(
|
||||
&self,
|
||||
f: F,
|
||||
@@ -602,9 +591,9 @@ impl<P: MlDsaParams> DigestSigner<Shake256, Signature<P>> for SigningKey<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `KeyPair` implementation for `SigningKey` allows to derive a `VerifyingKey` from
|
||||
/// a bare `SigningKey` (even in the absence of the original seed).
|
||||
impl<P: MlDsaParams> signature::Keypair for SigningKey<P> {
|
||||
/// The [`signature::KeyPair`] implementation for `ExpandedSigningKey` allows to derive a `VerifyingKey` from
|
||||
/// a bare `ExpandedSigningKey` (even in the absence of the original seed).
|
||||
impl<P: MlDsaParams> signature::Keypair for ExpandedSigningKey<P> {
|
||||
type VerifyingKey = VerifyingKey<P>;
|
||||
|
||||
/// This is a utility function that is useful when importing the private key
|
||||
@@ -622,11 +611,11 @@ impl<P: MlDsaParams> signature::Keypair for SigningKey<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `RandomizedSigner` implementation for `SigningKey` only supports signing with an empty
|
||||
/// The `RandomizedSigner` implementation for `ExpandedSigningKey` only supports signing with an empty
|
||||
/// context string. If you would like to include a context string, use the
|
||||
/// [`SigningKey::sign_randomized`] method.
|
||||
/// [`ExpandedSigningKey::sign_randomized`] method.
|
||||
#[cfg(feature = "rand_core")]
|
||||
impl<P: MlDsaParams> RandomizedSigner<Signature<P>> for SigningKey<P> {
|
||||
impl<P: MlDsaParams> RandomizedSigner<Signature<P>> for ExpandedSigningKey<P> {
|
||||
fn try_sign_with_rng<R: TryCryptoRng + ?Sized>(
|
||||
&self,
|
||||
rng: &mut R,
|
||||
@@ -636,11 +625,11 @@ impl<P: MlDsaParams> RandomizedSigner<Signature<P>> for SigningKey<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `RandomizedSigner` implementation for `SigningKey` only supports signing with an empty
|
||||
/// The `RandomizedSigner` implementation for `ExpandedSigningKey` only supports signing with an empty
|
||||
/// context string. If you would like to include a context string, use the
|
||||
/// [`SigningKey::sign_randomized`] method.
|
||||
/// [`ExpandedSigningKey::sign_randomized`] method.
|
||||
#[cfg(feature = "rand_core")]
|
||||
impl<P: MlDsaParams> RandomizedMultipartSigner<Signature<P>> for SigningKey<P> {
|
||||
impl<P: MlDsaParams> RandomizedMultipartSigner<Signature<P>> for ExpandedSigningKey<P> {
|
||||
fn try_multipart_sign_with_rng<R: TryCryptoRng + ?Sized>(
|
||||
&self,
|
||||
rng: &mut R,
|
||||
@@ -650,11 +639,11 @@ impl<P: MlDsaParams> RandomizedMultipartSigner<Signature<P>> for SigningKey<P> {
|
||||
}
|
||||
}
|
||||
|
||||
/// The `RandomizedSigner` implementation for `SigningKey` only supports signing with an empty
|
||||
/// The `RandomizedSigner` implementation for `ExpandedSigningKey` only supports signing with an empty
|
||||
/// context string. If you would like to include a context string, use the
|
||||
/// [`SigningKey::sign_mu_randomized`] method.
|
||||
/// [`ExpandedSigningKey::sign_mu_randomized`] method.
|
||||
#[cfg(feature = "rand_core")]
|
||||
impl<P: MlDsaParams> RandomizedDigestSigner<Shake256, Signature<P>> for SigningKey<P> {
|
||||
impl<P: MlDsaParams> RandomizedDigestSigner<Shake256, Signature<P>> for ExpandedSigningKey<P> {
|
||||
fn try_sign_digest_with_rng<
|
||||
R: TryCryptoRng + ?Sized,
|
||||
F: Fn(&mut Shake256) -> Result<(), Error>,
|
||||
@@ -902,12 +891,12 @@ impl<P> KeyGen for P
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
type KeyPair = KeyPair<P>;
|
||||
type KeyPair = SigningKey<P>;
|
||||
|
||||
/// Generate a signing key pair from the specified RNG
|
||||
// Algorithm 1 ML-DSA.KeyGen()
|
||||
#[cfg(feature = "rand_core")]
|
||||
fn key_gen<R: CryptoRng + ?Sized>(rng: &mut R) -> KeyPair<P> {
|
||||
fn key_gen<R: CryptoRng + ?Sized>(rng: &mut R) -> SigningKey<P> {
|
||||
let mut xi = B32::default();
|
||||
rng.fill_bytes(&mut xi);
|
||||
Self::from_seed(&xi)
|
||||
@@ -917,7 +906,7 @@ where
|
||||
///
|
||||
/// This method reflects the ML-DSA.KeyGen_internal algorithm from FIPS 204.
|
||||
// Algorithm 6 ML-DSA.KeyGen_internal
|
||||
fn from_seed(xi: &Seed) -> KeyPair<P>
|
||||
fn from_seed(xi: &Seed) -> SigningKey<P>
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
@@ -943,12 +932,12 @@ where
|
||||
// Compress and encode
|
||||
let (t1, t0) = t.power2round();
|
||||
|
||||
let verifying_key = VerifyingKey::new(rho, t1, A_hat.clone(), None);
|
||||
let signing_key = SigningKey::new(rho, K, verifying_key.tr.clone(), s1, s2, t0, A_hat);
|
||||
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);
|
||||
|
||||
KeyPair {
|
||||
SigningKey {
|
||||
signing_key,
|
||||
verifying_key,
|
||||
seed: xi.clone(),
|
||||
}
|
||||
}
|
||||
@@ -958,6 +947,7 @@ where
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::param::*;
|
||||
use signature::Keypair;
|
||||
|
||||
#[test]
|
||||
fn output_sizes() {
|
||||
@@ -983,11 +973,11 @@ mod test {
|
||||
P: MlDsaParams + PartialEq,
|
||||
{
|
||||
let seed = Array::default();
|
||||
let kp = P::from_seed(&seed);
|
||||
assert_eq!(kp.to_seed(), seed);
|
||||
let ssk = P::from_seed(&seed);
|
||||
assert_eq!(ssk.to_seed(), seed);
|
||||
|
||||
let sk = kp.signing_key;
|
||||
let vk = kp.verifying_key;
|
||||
let sk = &ssk.signing_key;
|
||||
let vk = ssk.verifying_key();
|
||||
|
||||
let vk_bytes = vk.encode();
|
||||
let vk2 = VerifyingKey::<P>::decode(&vk_bytes);
|
||||
@@ -996,8 +986,8 @@ mod test {
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
let sk_bytes = sk.to_expanded();
|
||||
let sk2 = SigningKey::<P>::from_expanded(&sk_bytes);
|
||||
assert!(sk == sk2);
|
||||
let sk2 = ExpandedSigningKey::<P>::from_expanded(&sk_bytes);
|
||||
assert!(sk == &sk2);
|
||||
|
||||
let M = b"Hello world";
|
||||
let rnd = Array([0u8; 32]);
|
||||
@@ -1019,9 +1009,9 @@ mod test {
|
||||
where
|
||||
P: MlDsaParams + PartialEq,
|
||||
{
|
||||
let kp = P::from_seed(&Array::default());
|
||||
let sk = kp.signing_key;
|
||||
let vk = kp.verifying_key;
|
||||
let ssk = P::from_seed(&Array::default());
|
||||
let sk = &ssk.signing_key;
|
||||
let vk = ssk.verifying_key();
|
||||
let vk_derived = sk.verifying_key();
|
||||
|
||||
assert!(vk == vk_derived);
|
||||
@@ -1038,9 +1028,9 @@ mod test {
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
let kp = P::from_seed(&Array::default());
|
||||
let sk = kp.signing_key;
|
||||
let vk = kp.verifying_key;
|
||||
let ssk = P::from_seed(&Array::default());
|
||||
let sk = &ssk.signing_key;
|
||||
let vk = ssk.verifying_key();
|
||||
|
||||
let M = b"Hello world";
|
||||
let rnd = Array([0u8; 32]);
|
||||
@@ -1062,9 +1052,9 @@ mod test {
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
let kp = P::from_seed(&Array::default());
|
||||
let sk = kp.signing_key;
|
||||
let vk = kp.verifying_key;
|
||||
let ssk = P::from_seed(&Array::default());
|
||||
let sk = &ssk.signing_key;
|
||||
let vk = ssk.verifying_key();
|
||||
|
||||
let M = b"Hello world";
|
||||
let rnd = Array([0u8; 32]);
|
||||
@@ -1084,9 +1074,9 @@ mod test {
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
let kp = P::from_seed(&Array::default());
|
||||
let sk = kp.signing_key;
|
||||
let vk = kp.verifying_key;
|
||||
let ssk = P::from_seed(&Array::default());
|
||||
let sk = &ssk.signing_key;
|
||||
let vk = ssk.verifying_key();
|
||||
|
||||
let M = b"Hello world";
|
||||
let rnd = Array([0u8; 32]);
|
||||
@@ -1106,9 +1096,9 @@ mod test {
|
||||
where
|
||||
P: MlDsaParams,
|
||||
{
|
||||
let kp = P::from_seed(&Array::default());
|
||||
let sk = kp.signing_key;
|
||||
let vk = kp.verifying_key;
|
||||
let ssk = P::from_seed(&Array::default());
|
||||
let sk = &ssk.signing_key;
|
||||
let vk = ssk.verifying_key();
|
||||
|
||||
let M = b"Hello world";
|
||||
let rnd = Array([0u8; 32]);
|
||||
@@ -1129,11 +1119,9 @@ mod test {
|
||||
P: MlDsaParams,
|
||||
{
|
||||
let seed = Seed::default();
|
||||
let kp1 = P::from_seed(&seed);
|
||||
let sk1 = SigningKey::<P>::from_seed(&seed);
|
||||
let vk1 = sk1.verifying_key();
|
||||
assert_eq!(kp1.signing_key, sk1);
|
||||
assert_eq!(kp1.verifying_key, vk1);
|
||||
let ssk = P::from_seed(&seed);
|
||||
let sk1 = ExpandedSigningKey::<P>::from_seed(&seed);
|
||||
assert_eq!(ssk.signing_key, sk1);
|
||||
}
|
||||
assert_from_seed_equality::<MlDsa44>();
|
||||
assert_from_seed_equality::<MlDsa65>();
|
||||
@@ -1194,9 +1182,9 @@ mod test {
|
||||
#[test]
|
||||
fn context_length_validation() {
|
||||
fn test_ctx_length<P: MlDsaParams>() {
|
||||
let kp = P::from_seed(&Array::default());
|
||||
let sk = kp.signing_key();
|
||||
let vk = kp.verifying_key();
|
||||
let ssk = P::from_seed(&Array::default());
|
||||
let sk = ssk.signing_key();
|
||||
let vk = ssk.verifying_key();
|
||||
|
||||
let msg = b"Hello world";
|
||||
let long_ctx = [0u8; 256];
|
||||
@@ -1217,8 +1205,8 @@ mod test {
|
||||
fn derived_verifying_key_validates_signatures() {
|
||||
fn test_derived_vk<P: MlDsaParams>() {
|
||||
let seed = Array([42u8; 32]);
|
||||
let kp = P::from_seed(&seed);
|
||||
let sk = kp.signing_key();
|
||||
let ssk = P::from_seed(&seed);
|
||||
let sk = ssk.signing_key();
|
||||
let derived_vk = sk.verifying_key();
|
||||
|
||||
let msg = b"Test message for derived key";
|
||||
@@ -1226,7 +1214,7 @@ mod test {
|
||||
let sig = sk.sign_internal(&[msg], &rnd);
|
||||
|
||||
assert!(derived_vk.verify_internal(msg, &sig));
|
||||
assert_eq!(derived_vk.encode(), kp.verifying_key().encode());
|
||||
assert_eq!(derived_vk.encode(), ssk.verifying_key().encode());
|
||||
}
|
||||
test_derived_vk::<MlDsa44>();
|
||||
test_derived_vk::<MlDsa65>();
|
||||
@@ -1244,11 +1232,11 @@ mod test {
|
||||
|
||||
let mut kp_debug = alloc::string::String::new();
|
||||
write!(&mut kp_debug, "{:?}", kp).unwrap();
|
||||
assert!(kp_debug.contains("KeyPair"));
|
||||
assert!(kp_debug.contains("SigningKey"));
|
||||
|
||||
let mut sk_debug = alloc::string::String::new();
|
||||
write!(&mut sk_debug, "{:?}", kp.signing_key()).unwrap();
|
||||
assert!(sk_debug.contains("SigningKey"));
|
||||
assert!(sk_debug.contains("ExpandedSigningKey"));
|
||||
}
|
||||
test_debug::<MlDsa44>();
|
||||
test_debug::<MlDsa65>();
|
||||
|
||||
+5
-5
@@ -135,9 +135,9 @@ pub trait SigningKeyParams: ParameterSet {
|
||||
s1: EncodedS1<Self>,
|
||||
s2: EncodedS2<Self>,
|
||||
t0: EncodedT0<Self>,
|
||||
) -> ExpandedSigningKey<Self>;
|
||||
) -> ExpandedSigningKeyBytes<Self>;
|
||||
fn split_sk(
|
||||
enc: &ExpandedSigningKey<Self>,
|
||||
enc: &ExpandedSigningKeyBytes<Self>,
|
||||
) -> (
|
||||
&B32,
|
||||
&B32,
|
||||
@@ -155,7 +155,7 @@ pub(crate) type EncodedT0<P> = Array<u8, <P as SigningKeyParams>::T0Size>;
|
||||
pub(crate) type SigningKeySize<P> = <P as SigningKeyParams>::SigningKeySize;
|
||||
|
||||
/// A signing key encoded as a byte array
|
||||
pub type ExpandedSigningKey<P> = Array<u8, SigningKeySize<P>>;
|
||||
pub type ExpandedSigningKeyBytes<P> = Array<u8, SigningKeySize<P>>;
|
||||
|
||||
impl<P> SigningKeyParams for P
|
||||
where
|
||||
@@ -248,12 +248,12 @@ where
|
||||
s1: EncodedS1<Self>,
|
||||
s2: EncodedS2<Self>,
|
||||
t0: EncodedT0<Self>,
|
||||
) -> ExpandedSigningKey<Self> {
|
||||
) -> ExpandedSigningKeyBytes<Self> {
|
||||
rho.concat(K).concat(tr).concat(s1).concat(s2).concat(t0)
|
||||
}
|
||||
|
||||
fn split_sk(
|
||||
enc: &ExpandedSigningKey<Self>,
|
||||
enc: &ExpandedSigningKeyBytes<Self>,
|
||||
) -> (
|
||||
&B32,
|
||||
&B32,
|
||||
|
||||
+8
-8
@@ -3,8 +3,8 @@
|
||||
#![cfg(feature = "pkcs8")]
|
||||
|
||||
use crate::{
|
||||
EncodedVerifyingKey, KeyGen, KeyPair, MlDsa44, MlDsa65, MlDsa87, MlDsaParams, Signature,
|
||||
SigningKey, VerifyingKey,
|
||||
EncodedVerifyingKey, ExpandedSigningKey, KeyGen, MlDsa44, MlDsa65, MlDsa87, MlDsaParams,
|
||||
Signature, SigningKey, VerifyingKey,
|
||||
};
|
||||
pub use ::pkcs8::*;
|
||||
use ::pkcs8::{
|
||||
@@ -75,7 +75,7 @@ impl<P: MlDsaParams> SignatureBitStringEncoding for Signature<P> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> SignatureAlgorithmIdentifier for KeyPair<P>
|
||||
impl<P> SignatureAlgorithmIdentifier for SigningKey<P>
|
||||
where
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
@@ -86,7 +86,7 @@ where
|
||||
Signature::<P>::ALGORITHM_IDENTIFIER;
|
||||
}
|
||||
|
||||
impl<P> TryFrom<PrivateKeyInfoRef<'_>> for KeyPair<P>
|
||||
impl<P> TryFrom<PrivateKeyInfoRef<'_>> for SigningKey<P>
|
||||
where
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
@@ -113,7 +113,7 @@ where
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<P> EncodePrivateKey for KeyPair<P>
|
||||
impl<P> EncodePrivateKey for SigningKey<P>
|
||||
where
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
@@ -132,7 +132,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<P> SignatureAlgorithmIdentifier for SigningKey<P>
|
||||
impl<P> SignatureAlgorithmIdentifier for ExpandedSigningKey<P>
|
||||
where
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
@@ -143,7 +143,7 @@ where
|
||||
Signature::<P>::ALGORITHM_IDENTIFIER;
|
||||
}
|
||||
|
||||
impl<P> TryFrom<PrivateKeyInfoRef<'_>> for SigningKey<P>
|
||||
impl<P> TryFrom<PrivateKeyInfoRef<'_>> for ExpandedSigningKey<P>
|
||||
where
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
@@ -151,7 +151,7 @@ where
|
||||
type Error = ::pkcs8::Error;
|
||||
|
||||
fn try_from(private_key_info: ::pkcs8::PrivateKeyInfoRef<'_>) -> ::pkcs8::Result<Self> {
|
||||
let keypair = KeyPair::try_from(private_key_info)?;
|
||||
let keypair = SigningKey::try_from(private_key_info)?;
|
||||
|
||||
Ok(keypair.signing_key)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use ml_dsa::*;
|
||||
|
||||
use hybrid_array::Array;
|
||||
use signature::Keypair;
|
||||
use std::{fs::read_to_string, path::PathBuf};
|
||||
|
||||
#[test]
|
||||
@@ -29,11 +30,11 @@ fn verify<P: MlDsaParams>(tc: &acvp::TestCase) {
|
||||
// Import test data into the relevant array structures
|
||||
let seed = Array::try_from(tc.seed.as_slice()).unwrap();
|
||||
let vk_bytes = EncodedVerifyingKey::<P>::try_from(tc.pk.as_slice()).unwrap();
|
||||
let sk_bytes = ExpandedSigningKey::<P>::try_from(tc.sk.as_slice()).unwrap();
|
||||
let sk_bytes = ExpandedSigningKeyBytes::<P>::try_from(tc.sk.as_slice()).unwrap();
|
||||
|
||||
let kp = P::from_seed(&seed);
|
||||
let sk = kp.signing_key().clone();
|
||||
let vk = kp.verifying_key().clone();
|
||||
let ssk = P::from_seed(&seed);
|
||||
let sk = ssk.signing_key().clone();
|
||||
let vk = ssk.verifying_key().clone();
|
||||
|
||||
assert_eq!(vk.encode(), vk_bytes);
|
||||
assert!(vk == VerifyingKey::<P>::decode(&vk_bytes));
|
||||
@@ -42,7 +43,7 @@ fn verify<P: MlDsaParams>(tc: &acvp::TestCase) {
|
||||
#[allow(deprecated)]
|
||||
{
|
||||
assert_eq!(sk.to_expanded(), sk_bytes);
|
||||
assert!(sk == SigningKey::<P>::from_expanded(&sk_bytes));
|
||||
assert!(sk == ExpandedSigningKey::<P>::from_expanded(&sk_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+10
-6
@@ -1,7 +1,10 @@
|
||||
#![cfg(all(feature = "pkcs8", feature = "alloc"))]
|
||||
|
||||
use core::ops::Deref;
|
||||
use ml_dsa::{KeyPair, MlDsa44, MlDsa65, MlDsa87, MlDsaParams, SigningKey, VerifyingKey};
|
||||
use ml_dsa::{
|
||||
ExpandedSigningKey, MlDsa44, MlDsa65, MlDsa87, MlDsaParams, SigningKey, VerifyingKey,
|
||||
signature::Keypair,
|
||||
};
|
||||
use pkcs8::{
|
||||
DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey,
|
||||
der::{AnyRef, pem::LineEnding},
|
||||
@@ -15,11 +18,11 @@ fn private_key_serialization() {
|
||||
P: MlDsaParams,
|
||||
P: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
|
||||
{
|
||||
let sk = SigningKey::<P>::from_pkcs8_pem(private_bytes).expect("parse private key");
|
||||
let kp = KeyPair::<P>::from_pkcs8_pem(private_bytes).expect("parse private key");
|
||||
assert!(sk == *kp.signing_key());
|
||||
let sk = ExpandedSigningKey::<P>::from_pkcs8_pem(private_bytes).expect("parse private key");
|
||||
let ssk = SigningKey::<P>::from_pkcs8_pem(private_bytes).expect("parse private key");
|
||||
assert!(sk == *ssk.signing_key());
|
||||
assert_eq!(
|
||||
kp.to_pkcs8_pem(LineEnding::LF)
|
||||
ssk.to_pkcs8_pem(LineEnding::LF)
|
||||
.expect("serialize private seed")
|
||||
.deref(),
|
||||
private_bytes
|
||||
@@ -33,7 +36,8 @@ fn private_key_serialization() {
|
||||
public_bytes
|
||||
);
|
||||
|
||||
assert_eq!(kp.verifying_key(), &pk);
|
||||
assert_eq!(sk.verifying_key(), pk);
|
||||
assert_eq!(ssk.verifying_key(), pk);
|
||||
}
|
||||
|
||||
test_roundtrip::<MlDsa44>(
|
||||
|
||||
@@ -14,7 +14,7 @@ macro_rules! mldsa_proptests {
|
||||
mod $name {
|
||||
use ml_dsa::{
|
||||
KeyGen, Signature,
|
||||
signature::{DigestSigner, DigestVerifier, digest::Update},
|
||||
signature::{DigestSigner, DigestVerifier, Keypair, digest::Update},
|
||||
$alg,
|
||||
};
|
||||
use proptest::{collection, prelude::*};
|
||||
|
||||
@@ -26,10 +26,10 @@ fn acvp_sig_gen() {
|
||||
|
||||
fn verify<P: MlDsaParams>(tc: &acvp::TestCase, deterministic: bool) {
|
||||
// Import the signing key
|
||||
let sk_bytes = ExpandedSigningKey::<P>::try_from(tc.sk.as_slice()).unwrap();
|
||||
let sk_bytes = ExpandedSigningKeyBytes::<P>::try_from(tc.sk.as_slice()).unwrap();
|
||||
|
||||
#[allow(deprecated)]
|
||||
let sk = SigningKey::<P>::from_expanded(&sk_bytes);
|
||||
let sk = ExpandedSigningKey::<P>::from_expanded(&sk_bytes);
|
||||
|
||||
// Verify correctness
|
||||
let rnd = if deterministic {
|
||||
|
||||
Reference in New Issue
Block a user