Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify KEM API #1509

Merged
merged 6 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

38 changes: 19 additions & 19 deletions kem/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
[package]
name = "kem"
description = "Traits for key encapsulation mechanisms"
version = "0.3.0-pre"
authors = ["RustCrypto Developers"]
license = "Apache-2.0 OR MIT"
name = "kem"
description = "Traits for key encapsulation mechanisms"
version = "0.3.0-pre"
authors = ["RustCrypto Developers"]
license = "Apache-2.0 OR MIT"
documentation = "https://docs.rs/kem"
repository = "https://github.com/RustCrypto/traits/tree/master/kem"
readme = "README.md"
edition = "2021"
keywords = ["crypto"]
categories = ["cryptography", "no-std"]
rust-version = "1.66"
repository = "https://github.com/RustCrypto/traits/tree/master/kem"
readme = "README.md"
edition = "2021"
keywords = ["crypto"]
categories = ["cryptography", "no-std"]
rust-version = "1.66"

[dependencies]
rand_core = "0.6"
generic-array = "0.14"
zeroize = { version = "1.7", default-features = false }

[dev-dependencies]
hpke = "0.10"
p256 = { version = "0.9", features = [ "ecdsa" ] }
pqcrypto = { version = "0.15", default-features = false, features = [ "pqcrypto-saber" ] }
p256 = { version = "0.9", features = ["ecdsa"] }
pqcrypto = { version = "0.15", default-features = false, features = [
"pqcrypto-saber",
] }
pqcrypto-traits = "0.3"
rand = { version = "0.8", features = [ "getrandom" ] }
rand = { version = "0.8" }
x3dh-ke = "0.1"

[features]
default = []
std = []

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[lib]
doctest = false
61 changes: 60 additions & 1 deletion kem/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,66 @@

This crate provides a common set of traits for [key encapsulation mechanisms][1]—algorithms for non-interactively establishing secrets between peers. This is intended to be implemented by libraries which produce or contain implementations of key encapsulation mechanisms, and used by libraries which want to produce or consume encapsulated secrets while generically supporting any compatible backend.

The crate exposes four traits, `Encapsulator`, `Decapsulator`, `AuthEncapsulator`, and `AuthDecapsulator`. These traits represent the ability to initiate a key exchange and complete a key exchange, in the case where the sender is authenticated to the receiver and in the case where the sender is not.
The crate exposes two traits, `Encapsulate` and `Decapsulate`, which are both generic over the encapsulated key type and the shared secret type. They are also agnostic about the structure of `Self`. For example, a simple Saber implementation may just impl `Encapsulate` for a single public key:
```rust
// Must make a newtype to implement the trait
struct MyPubkey(SaberPublicKey);

impl Encapsulate<SaberEncappedKey, SaberSharedSecret> for MyPubkey {
// Encapsulation is infallible
type Error = !;

fn encapsulate(
&self,
csprng: impl CryptoRngCore,
) -> Result<(SaberEncappedKey, SaberSharedSecret), !> {
let (ss, ek) = saber_encapsulate(&csprng, &self.0);
Ok((ek, ss))
}
}
```
And on the other end of complexity, an [X3DH](https://www.signal.org/docs/specifications/x3dh/) implementation might impl `Encapsulate` for a public key bundle plus a sender identity key:
```rust
struct PubkeyBundle {
ik: IdentityPubkey,
spk: SignedPrePubkey,
sig: Signature,
opk: OneTimePrePubkey,
}

// Encap context is the recipient's pubkeys and the sender's identity key
struct EncapContext(PubkeyBundle, IdentityPrivkey);

impl Encapsulate<EphemeralKey, SharedSecret> for EncapContext {
// Encapsulation fails if signature verification fails
type Error = SigError;

fn encapsulate(
&self,
csprng: impl CryptoRngCore,
) -> Result<(EphemeralKey, SharedSecret), Self::Error> {
// Make a new ephemeral key. This will be the encapped key
let ek = EphemeralKey::gen(&mut csprng);

// Deconstruct the recipient's pubkey bundle
let PubkeyBundle {
ref ik,
ref spk,
ref sig,
ref opk,
} = self.0;
let my_ik = &self.1;

// Verify the signature
self.0.verify(&sig, &some_sig_pubkey)?;

// Do the X3DH operation to get the shared secret
let shared_secret = x3dh_a(sig, my_ik, spk, &ek, ik, opk)?;

Ok((ek, shared_secret))
}
}
```

[Documentation][docs-link]

Expand Down
17 changes: 0 additions & 17 deletions kem/src/errors.rs

This file was deleted.

100 changes: 0 additions & 100 deletions kem/src/kem.rs

This file was deleted.

28 changes: 22 additions & 6 deletions kem/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,27 @@
#![forbid(unsafe_code)]
#![warn(missing_docs, unused_qualifications, missing_debug_implementations)]

#[cfg(feature = "std")]
extern crate std;
use core::fmt::Debug;
use rand_core::CryptoRngCore;

mod errors;
mod kem;
/// A value that can be encapsulated to. 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<EK, SS> {
/// Encapsulation error
type Error: Debug;

pub use crate::{errors::*, kem::*};
pub use generic_array;
/// Encapsulates a fresh shared secret
fn encapsulate(&self, rng: &mut impl CryptoRngCore) -> Result<(EK, SS), Self::Error>;
}

/// A value that can be used to decapsulate an encapsulated key. Often, this will just be a secret
/// key. But, as with [`Encapsulate`], it can be a bundle of secret keys, or it can include a
/// sender's private key for authenticated encapsulation.
pub trait Decapsulate<EK, SS> {
/// Decapsulation error
type Error: Debug;

/// Decapsulates the given encapsulated key
fn decapsulate(&self, encapsulated_key: &EK) -> Result<SS, Self::Error>;
}