Skip to main content

dhkem/
lib.rs

1#![no_std]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![doc = include_str!("../README.md")]
4#![doc(
5    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
6    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
7)]
8
9//! # Diffie-Hellman (DH) based Key Encapsulation Mechanisms (KEM)
10//!
11//! This crate provides a KEM interface for DH protocols as specified in [RFC9180]
12//! without the shared secret extraction process.
13//!
14//! In particular, `Encaps(pk)` in the RFC returns the encapsulated key and an extracted shared
15//! secret, while our implementation leaves the extraction process up to the user.
16//!
17//! This type of KEM construction is currently being used in HPKE, as per the RFC, and in the
18//! current draft of the [TLS KEM combiner].
19//!
20//! ## Supported elliptic curves
21//!
22//! Support for specific elliptic curves is gated behind the following features:
23//!
24//! - `k256`: secp256k1
25//! - `p256`: NIST P-256
26//! - `p384`: NIST P-384
27//! - `p521`: NIST P-521
28//!
29//! [RFC9180]: https://datatracker.ietf.org/doc/html/rfc9180#name-dh-based-kem-dhkem
30//! [TLS KEM combiner]: https://datatracker.ietf.org/doc/html/draft-ietf-tls-hybrid-design-10
31
32mod expander;
33
34pub use expander::{Expander, InvalidLength};
35pub use kem::{self, Decapsulator, Encapsulate, Generate, Kem, TryDecapsulate};
36
37#[cfg(feature = "ecdh")]
38mod ecdh_kem;
39#[cfg(feature = "x25519")]
40mod x25519_kem;
41
42#[cfg(feature = "ecdh")]
43pub use ecdh_kem::{EcdhDecapsulationKey, EcdhEncapsulationKey, EcdhKem};
44#[cfg(feature = "x25519")]
45pub use x25519_kem::{X25519DecapsulationKey, X25519EncapsulationKey, X25519Kem};
46
47#[cfg(feature = "ecdh")]
48use elliptic_curve::{
49    CurveArithmetic, PublicKey, bigint,
50    sec1::{self, FromSec1Point, ToSec1Point},
51};
52
53#[cfg(feature = "zeroize")]
54use zeroize::{Zeroize, ZeroizeOnDrop};
55
56/// Newtype for a piece of data that may be decapsulated
57#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
58pub struct DecapsulationKey<DK, EK> {
59    /// Decapsulation key
60    dk: DK,
61    /// Encapsulation key
62    ek: EncapsulationKey<EK>,
63}
64
65impl<DK, EK> DecapsulationKey<DK, EK> {
66    /// Consumes `self` and returns the wrapped value
67    pub fn into_inner(self) -> DK {
68        self.dk
69    }
70}
71
72impl<DK, EK> AsRef<EncapsulationKey<EK>> for DecapsulationKey<DK, EK> {
73    fn as_ref(&self) -> &EncapsulationKey<EK> {
74        &self.ek
75    }
76}
77
78impl<DK, EK> From<DK> for DecapsulationKey<DK, EK>
79where
80    EK: for<'a> From<&'a DK>,
81{
82    fn from(dk: DK) -> Self {
83        let ek = EncapsulationKey(EK::from(&dk));
84        Self { dk, ek }
85    }
86}
87
88/// Newtype for a piece of data that may be encapsulated
89#[derive(Clone, Copy, Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Default)]
90pub struct EncapsulationKey<EK>(EK);
91
92impl<EK> EncapsulationKey<EK> {
93    /// Consumes `self` and returns the wrapped value
94    pub fn into_inner(self) -> EK {
95        self.0
96    }
97}
98
99impl<EK> From<EK> for EncapsulationKey<EK> {
100    fn from(inner: EK) -> Self {
101        Self(inner)
102    }
103}
104
105#[cfg(feature = "ecdh")]
106impl<C> FromSec1Point<C> for EcdhEncapsulationKey<C>
107where
108    C: CurveArithmetic,
109    C::FieldBytesSize: sec1::ModulusSize,
110    PublicKey<C>: FromSec1Point<C>,
111{
112    fn from_sec1_point(point: &sec1::Sec1Point<C>) -> bigint::CtOption<Self> {
113        PublicKey::<C>::from_sec1_point(point).map(Into::into)
114    }
115}
116
117#[cfg(feature = "ecdh")]
118impl<C> ToSec1Point<C> for EcdhEncapsulationKey<C>
119where
120    C: CurveArithmetic,
121    C::FieldBytesSize: sec1::ModulusSize,
122    PublicKey<C>: ToSec1Point<C>,
123{
124    fn to_sec1_point(&self, compress: bool) -> sec1::Sec1Point<C> {
125        self.0.to_sec1_point(compress)
126    }
127}
128
129#[cfg(feature = "zeroize")]
130impl<DK: Zeroize, EK> Zeroize for DecapsulationKey<DK, EK> {
131    fn zeroize(&mut self) {
132        self.dk.zeroize();
133    }
134}
135
136#[cfg(feature = "zeroize")]
137impl<DK: ZeroizeOnDrop, EK> ZeroizeOnDrop for DecapsulationKey<DK, EK> {}
138
139/// NIST P-256 DHKEM.
140#[cfg(feature = "p256")]
141pub type NistP256Kem = EcdhKem<p256::NistP256>;
142/// NIST P-256 ECDH Decapsulation Key.
143#[cfg(feature = "p256")]
144pub type NistP256DecapsulationKey = EcdhDecapsulationKey<p256::NistP256>;
145/// NIST P-256 ECDH Encapsulation Key.
146#[cfg(feature = "p256")]
147pub type NistP256EncapsulationKey = EcdhEncapsulationKey<p256::NistP256>;
148
149/// NIST P-256 DHKEM.
150#[cfg(feature = "p384")]
151pub type NistP384Kem = EcdhKem<p384::NistP384>;
152/// NIST P-384 ECDH Decapsulation Key.
153#[cfg(feature = "p384")]
154pub type NistP384DecapsulationKey = EcdhDecapsulationKey<p384::NistP384>;
155/// NIST P-384 ECDH Encapsulation Key.
156#[cfg(feature = "p384")]
157pub type NistP384EncapsulationKey = EcdhEncapsulationKey<p384::NistP384>;
158
159/// NIST P-521 DHKEM.
160#[cfg(feature = "p521")]
161pub type NistP521Kem = EcdhKem<p521::NistP521>;
162/// NIST P-521 ECDH Decapsulation Key.
163#[cfg(feature = "p521")]
164pub type NistP521DecapsulationKey = EcdhDecapsulationKey<p521::NistP521>;
165/// NIST P-521 ECDH Encapsulation Key.
166#[cfg(feature = "p521")]
167pub type NistP521EncapsulationKey = EcdhEncapsulationKey<p521::NistP521>;
168
169/// secp256k1 DHKEM.
170#[cfg(feature = "p521")]
171pub type Secp256k1Kem = EcdhKem<k256::Secp256k1>;
172/// secp256k1 ECDH Decapsulation Key.
173#[cfg(feature = "k256")]
174pub type Secp256k1DecapsulationKey = EcdhDecapsulationKey<k256::Secp256k1>;
175/// secp256k1 ECDH Encapsulation Key.
176#[cfg(feature = "k256")]
177pub type Secp256k1EncapsulationKey = EcdhEncapsulationKey<k256::Secp256k1>;