Skip to content

Conversation

@tarcieri
Copy link
Member

@tarcieri tarcieri commented Jan 29, 2026

Adds a Kem trait intended to be impl'd by ZSTs that describe the whole type family, including the decapsulation key, encapsulation key, and the sizes of the ciphertext and shared secret previously defined on the KemParams trait (which this subsumes).

The remaining traits have been changed to be generic around K: Kem and now use it to source their constants or relevant types.

DecapsulationKey<K> and EncapsulationKey<K> type aliases have been added, similar to the ones in elliptic-curve, which take care of doing K as Kem for you when accessing the associated types.

The design of this trait largely matches the bespoke traits that people were defining different but similarly shaped-versions of in individual crates in https://github.com/RustCrypto/KEMs

cc @rozbb

Edit: companion PR: RustCrypto/KEMs#223

Adds a `Kem` trait intended to be impl'd by ZSTs that describe the whole
type family, including the decapsulation key, encapsulation key, and the
sizes of the ciphertext and shared secret previously defined on the
`KemParams` trait (which this subsumes).

The remaining traits have been changed to be generic around `K: Kem` and
now use it to source their constants or relevant types.

`DecapsulationKey<K>` and `EncapsulationKey<K>` type aliases have been
added, similar to the ones in `elliptic-curve`, which take care of doing
`K as Kem` for you when accessing the associated types.

The design of this trait largely matches the bespoke traits that people
were defining different but similarly shaped-versions of in individual
crates in https://github.com/RustCrypto/KEMs
/// Often, this will just be a public key. However, it can also be a bundle of public keys, or it
/// can include a sender's private key for authenticated encapsulation.
pub trait Encapsulate: KemParams + TryKeyInit + KeyExport {
pub trait Encapsulate<K: Kem>: TryKeyInit + KeyExport {
Copy link
Member Author

Choose a reason for hiding this comment

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

Now that I think about it, these generic parameters are important for binding an impl of Encapsulate/(Try)Decapsulate to a specific KEM algorithm, e.g. if an HSM library wanted to add one.

Unlike signature we can't infer the algorithm from the return type.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm also kind of torn using a generic here. There will probably be only one impl per type, so we don't need overlapping bounds.

It means that everyone needs to notate it in the downstream bounds, which is a little annoying, but they'll need to bound on Kem anyway since it's the trait holding everything together.

If we moved it to an associated type it would get out of the way, but then we should probably get rid of the Decapsulator trait so we don't have to worry about both Decapsulator and Decapsulate defining an associated Kem type.

We would, however, still have to worry about both Decapsulate and TryDecapsulate defining associated Kem types, and if we moved encapsulator to those traits they would then have overlapping encapsulator methods (which is the problem Decapsaulator exists to solve in the first place)

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, it's kind of annoying having multiple generics here. A thought: what about putting all methods inside Kem, and just removing all the other traits? Instead of ek.encap(...), you'd call K::encap(ek, ...). Benefits: single generic parameter to manage, one place to define an entire KEM. Downside: it's not clear how to handle TryDecapsulate anymore. For what it's worth, I think it might be fine to make decapsulation always fallible (as of today, the only possible error in any known KEM is ciphertext deserialization). If someone wants to convey it's infallible, they can set Kem::DecapError = Infallible. Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

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

What's nice about the current approach is it's flexible to permit a Decapsulate or TryDecapsulate impl on a hardware-backed decapsulation key, where you can still retrieve its associated encapsulation key using a software implementation.

But also: we still need types to hold the state of decoded decapsulation/encapsulation keys. This trait is intended to be impl'd on a ZST.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahh, ok. So some simplifications that remain are: absorb Encapsulate into Kem, and merge Decapsulate and TryDecapsulate. I don't feel strongly about either though. Just thoughts

@tarcieri
Copy link
Member Author

I'm going to try this out on https://github.com/RustCrypto/KEMs and if it looks good I'll mark the PR as ready for review

pub trait KemParams {
/// Size of the ciphertext (a.k.a. "encapsulated key") produced by [`Encapsulate::encapsulate`].
/// This trait describes the entire type family used by a KEM.
pub trait Kem: Copy + Clone + Debug + Default + Eq + Ord + Send + Sync + 'static {
Copy link
Member Author

Choose a reason for hiding this comment

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

These are the same bounds as elliptic_curve::Curve. They're important when a type that impls Kem is used as a generic parameter on other types, so custom derive works because it doesn't freak out about the bounds of the ZST it's generic around.

- Bound `DecapsulationKey` on `TryDecapsulate` as it's the supertrait
- Remove `From<&Self::DecapsulationKey>` bound
- Remove `Decapsulator` trait, replace it with an
  `AsRef<Self::EncapsulationKey>` bound on `TryDecapsulate`
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
@tarcieri tarcieri changed the title [WIP] kem: Kem trait for the whole algorithm type family kem: Kem trait for the whole algorithm type family Jan 30, 2026
@tarcieri tarcieri marked this pull request as ready for review January 30, 2026 19:03
@tarcieri
Copy link
Member Author

Alright, after a few tweaks I now have RustCrypto/KEMs#223 building against this. Gonna land it and do a crate release, then update the PR.

@tarcieri tarcieri merged commit b5cfb05 into master Jan 30, 2026
10 checks passed
@tarcieri tarcieri deleted the kem/kem-trait branch January 30, 2026 19:04
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
tarcieri added a commit to RustCrypto/KEMs that referenced this pull request Jan 30, 2026
Companion PR to RustCrypto/traits#2243

This implements a trait which describes a whole KEM type family, with a
similar shape to the former `dhkem::DhKem` and `ml_kem::KemCore` traits
(both of which have been removed and replaced with `kem::Kem`).

As part of this, the `*Params` types in `ml_kem` have been merged with
the former type aliases of the `ml_kem::Kem` type (which have also been
removed), and now `MlKem512`, `MlKem768`, and `MlKem1024` are the one
true ZSTs for describing ML-KEM parameters.
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.

3 participants