Skip to content

Conversation

@tarcieri
Copy link
Member

@tarcieri tarcieri commented Nov 21, 2025

Adds a trait providing fallible key initialization, similar to the existing KeyInit trait, but designed to handle the case that not all bytestrings of a given length represent valid keys.

This is primarily useful in the context of public-key cryptography, e.g. scalars representing elliptic curve private keys.

The API and method names are duplicated from KeyInit. It is assumed that KeyInit and TryKeyInit have an either-or relationship, i.e. types will not impl both KeyInit and TryKeyInit, and consumers of code which is generic over these traits will not be attempting to abstract over the KeyInit/TryKeyInit distinction, but one or the other will make sense in a given context (e.g. symmetric cryptography uses KeyInit, ECC uses TryKeyInit)

Key generation methods are provided which generically implement rejection sampling as a reasonabe baseline for unbiased random sampling of potential keys. As a provided method, implementers of TryKeyInit can override it if they can provide more efficient means of generating keys.

Closes #1897

Adds a trait providing fallible key initialization, similar to the
existing `KeyInit` trait, but designed to handle the case that not all
bytestrings of a given length represent valid keys.

This is primarily useful in the context of public-key cryptography, e.g.
scalars representing elliptic curve private keys.

The API and method names are duplicated from `KeyInit`. It is assumed
that `KeyInit` and `TryKeyInit` have an either-or relationship, i.e.
types will not impl both `KeyInit` and `TryKeyInit`, and consumers of
code which is generic over these traits will not be attempting to
abstract over the `KeyInit`/`TryKeyInit` distinction, but one or the
other will make sense in a given context (e.g. symmetric cryptography
uses `KeyInit`, ECC uses `TryKeyInit`)

Key generation methods are provided which generically implement
rejection sampling as a reasonabe baseline for unbiased random sampling
of potential keys. As a provided method, implementers of `TryKeyInit`
can override it if they can provide more efficient means of generating
keys.
@tarcieri tarcieri requested a review from newpavlov November 21, 2025 21:03
@tarcieri
Copy link
Member Author

KeyInit and TryKeyInit have an either-or relationship, i.e. types will not impl both KeyInit and TryKeyInit [...] ECC uses TryKeyInit

There is a counterexample to this: the Ed25519 signature system uses a seed to derive the private scalar as the result of SHA-512 acting as a KDF, along with "clamping" to ensure the scalar is in range. So Ed25519 keys could use KeyInit.

But for ECDSA keys, or secp256k1 Schnorr, we'd want TryKeyInit. So perhaps having a way to abstract over the distinction should be considered.

(There is also a similar concern for X25519 static keys)

Comment on lines +352 to +362
fn generate_key() -> Result<Key<Self>, getrandom::Error> {
// Use rejection sampling to find a key which initializes successfully in an unbiased manner
loop {
let mut key = Key::<Self>::default();
getrandom::fill(&mut key)?;

if Self::new(&key).is_ok() {
return Ok(key);
}
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

re: #2060 implementing random bytestring generation in hybrid-array (which I still think is an independently good idea) won't suffice for these use cases, since they need algorithm-specific logic to select valid keys.

The approach in this PR is able to provide a generic unbiased key generation implementation which can have algorithm-specific overrides to improve efficiency.

I think we could potentially drop the keygen for KeyInit and point to hybrid-array for such cases, but having generic keygen for TryKeyInit is still independently useful, IMO.

@tarcieri
Copy link
Member Author

With #2096 I think the RNG code in this PR can be substantially improved.

It would be nice to retain a generic implementation of rejection sampling though. Perhaps it could work with a blanket impl and a marker trait, e.g. pub trait RejectionSamplingRng: TryKeyInit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

crypto-common: fallible alternative to KeyInit

2 participants