Skip to content

Commit e7f6a60

Browse files
authored
ml-dsa: precompute VerifyingKeys when alloc enabled (#1346)
Adds an `alloc`-gated `verifying_key` field to `SigningKey`, and when the feature is enabled precomputes the key at the time the `SigningKey` is initialized. We previously used to do this but stopped to optimize stack usage (see the changes in #1259 and #1261), however when `alloc` is enabled this isn't an issue since we've moved the relevant data to the heap in this case (see #1344 and #1345), so stack usage is no longer an issue. This makes it possible to implement `signature::KeypairRef` for `SigningKey` which still provides a blanket `signature::Keypair` impl, so we can always depend on the latter being availble but take advantage of the former when `alloc` is enabled.
1 parent c3ded0c commit e7f6a60

1 file changed

Lines changed: 27 additions & 2 deletions

File tree

ml-dsa/src/signing.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ pub struct SigningKey<P: MlDsaParams> {
4141

4242
/// The seed this signing key was derived from
4343
seed: MaybeBox<Seed>,
44+
45+
/// When the `alloc` feature is available, precompute the [`VerifyingKey`].
46+
#[cfg(feature = "alloc")]
47+
verifying_key: VerifyingKey<P>,
4448
}
4549

4650
impl<P: MlDsaParams> SigningKey<P> {
@@ -73,11 +77,16 @@ impl<P: MlDsaParams> SigningKey<P> {
7377

7478
let enc = VerifyingKey::<P>::encode_internal(&rho, &t1);
7579
let tr: B64 = H::default().absorb(&enc).squeeze_new();
76-
let signing_key = ExpandedSigningKey::new(rho, K, tr, s1, s2, t0, A_hat);
80+
let expanded_key = ExpandedSigningKey::new(rho, K, tr, s1, s2, t0, A_hat);
81+
82+
#[cfg(feature = "alloc")]
83+
let verifying_key = expanded_key.verifying_key();
7784

7885
SigningKey {
79-
expanded_key: MaybeBox::new(signing_key),
86+
expanded_key: MaybeBox::new(expanded_key),
8087
seed: MaybeBox::new(xi.clone()),
88+
#[cfg(feature = "alloc")]
89+
verifying_key,
8190
}
8291
}
8392

@@ -134,13 +143,29 @@ impl<P: MlDsaParams> fmt::Debug for SigningKey<P> {
134143
}
135144
}
136145

146+
// NOTE: when the `alloc` feature is enabled, we receive a blanket impl of `Keypair` via the impl
147+
// of the `KeypairRef` trait which simply clones the precomputed verifying key, providing equivalent
148+
// functionality and thus this is actually still an additive use of features.
149+
#[cfg(not(feature = "alloc"))]
137150
impl<P: MlDsaParams> signature::Keypair for SigningKey<P> {
138151
type VerifyingKey = VerifyingKey<P>;
139152
fn verifying_key(&self) -> VerifyingKey<P> {
140153
self.expanded_key.verifying_key()
141154
}
142155
}
143156

157+
#[cfg(feature = "alloc")]
158+
impl<P: MlDsaParams> AsRef<VerifyingKey<P>> for SigningKey<P> {
159+
fn as_ref(&self) -> &VerifyingKey<P> {
160+
&self.verifying_key
161+
}
162+
}
163+
164+
#[cfg(feature = "alloc")]
165+
impl<P: MlDsaParams> signature::KeypairRef for SigningKey<P> {
166+
type VerifyingKey = VerifyingKey<P>;
167+
}
168+
144169
/// The `Signer` implementation for `SigningKey` uses the optional deterministic variant of ML-DSA, and
145170
/// only supports signing with an empty context string.
146171
impl<P: MlDsaParams> Signer<Signature<P>> for SigningKey<P> {

0 commit comments

Comments
 (0)