Skip to content

Commit 9025578

Browse files
alexclaude
andauthored
Add MLKEM1024-P384 hybrid KEM support in HPKE (pyca#14722)
* Add MLKEM1024-P384 hybrid KEM support in HPKE Implements the MLKEM1024-P384 hybrid KEM (KEM ID 0x0051) as specified in draft-ietf-hpke-pq. This combines ML-KEM-1024 with ECDH over NIST P-384, using the QSF-style SHA3-256 combiner: ss = SHA3-256(ss_PQ || ss_T || ct_T || ek_T || "MLKEM1024-P384") Exposes MLKEM1024P384PrivateKey / MLKEM1024P384PublicKey, which accept an MLKEM1024Private/PublicKey plus a SECP384R1 EllipticCurvePrivate/ PublicKey, and wires them through the new KEM.MLKEM1024_P384 variant. Validated end-to-end against the draft-ietf-hpke-pq test vectors via test_vector_decryption. https://claude.ai/code/session_01WMt6uNpXMN2skhuiEtEMx7 * Address review comments on pyca#14722 - Consolidate mlkem768_x25519_combine and mlkem1024_p384_combine into a single hybrid_kem_combine helper that takes the label as an argument. Both KEMs use the same QSF-style SHA3-256 combiner structure (ss_PQ || ss_T || ct_T || ek_T || Label), so the duplication wasn't pulling its weight. - Move MLKEM1024P384Private/PublicKey assignments under the MLKEM768X25519 ones in cryptography/hazmat/primitives/hpke.py to match the ordering of __all__. https://claude.ai/code/session_01WMt6uNpXMN2skhuiEtEMx7 --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent ef66de4 commit 9025578

5 files changed

Lines changed: 540 additions & 41 deletions

File tree

docs/hazmat/primitives/hpke.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,13 @@ specifying auxiliary authenticated information.
110110
Public and private keys are :class:`MLKEM768X25519PublicKey` and
111111
:class:`MLKEM768X25519PrivateKey`.
112112

113+
.. attribute:: MLKEM1024_P384
114+
115+
A hybrid KEM combining ML-KEM-1024 with P-384. Post-quantum secure.
116+
Only available on backends that support ML-KEM. Public and private
117+
keys are :class:`MLKEM1024P384PublicKey` and
118+
:class:`MLKEM1024P384PrivateKey`.
119+
113120
.. class:: MLKEM768X25519PrivateKey(mlkem_key, x25519_key)
114121

115122
.. versionadded:: 47.0.0
@@ -148,6 +155,44 @@ specifying auxiliary authenticated information.
148155
:param x25519_key: The X25519 public key component.
149156
:type x25519_key: :class:`~cryptography.hazmat.primitives.asymmetric.x25519.X25519PublicKey`
150157

158+
.. class:: MLKEM1024P384PrivateKey(mlkem_key, p384_key)
159+
160+
.. versionadded:: 47.0.0
161+
162+
A hybrid ML-KEM-1024 / P-384 private key for use with
163+
:attr:`KEM.MLKEM1024_P384`. Combines an
164+
:class:`~cryptography.hazmat.primitives.asymmetric.mlkem.MLKEM1024PrivateKey`
165+
and an
166+
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`
167+
on the SECP384R1 curve into a single recipient key.
168+
169+
:param mlkem_key: The ML-KEM-1024 private key component.
170+
:type mlkem_key: :class:`~cryptography.hazmat.primitives.asymmetric.mlkem.MLKEM1024PrivateKey`
171+
172+
:param p384_key: The P-384 private key component.
173+
:type p384_key: :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePrivateKey`
174+
175+
.. method:: public_key()
176+
177+
:returns: :class:`MLKEM1024P384PublicKey`
178+
179+
.. class:: MLKEM1024P384PublicKey(mlkem_key, p384_key)
180+
181+
.. versionadded:: 47.0.0
182+
183+
A hybrid ML-KEM-1024 / P-384 public key for use with
184+
:attr:`KEM.MLKEM1024_P384`. Combines an
185+
:class:`~cryptography.hazmat.primitives.asymmetric.mlkem.MLKEM1024PublicKey`
186+
and an
187+
:class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`
188+
on the SECP384R1 curve into a single recipient key.
189+
190+
:param mlkem_key: The ML-KEM-1024 public key component.
191+
:type mlkem_key: :class:`~cryptography.hazmat.primitives.asymmetric.mlkem.MLKEM1024PublicKey`
192+
193+
:param p384_key: The P-384 public key component.
194+
:type p384_key: :class:`~cryptography.hazmat.primitives.asymmetric.ec.EllipticCurvePublicKey`
195+
151196
.. class:: KDF
152197

153198
An enumeration of key derivation functions.

src/cryptography/hazmat/bindings/_rust/openssl/hpke.pyi

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class KEM:
1313
MLKEM768: KEM
1414
MLKEM1024: KEM
1515
MLKEM768_X25519: KEM
16+
MLKEM1024_P384: KEM
1617

1718
class KDF:
1819
HKDF_SHA256: KDF
@@ -41,6 +42,21 @@ class MLKEM768X25519PublicKey:
4142
x25519_key: x25519.X25519PublicKey,
4243
) -> None: ...
4344

45+
class MLKEM1024P384PrivateKey:
46+
def __init__(
47+
self,
48+
mlkem_key: mlkem.MLKEM1024PrivateKey,
49+
p384_key: ec.EllipticCurvePrivateKey,
50+
) -> None: ...
51+
def public_key(self) -> MLKEM1024P384PublicKey: ...
52+
53+
class MLKEM1024P384PublicKey:
54+
def __init__(
55+
self,
56+
mlkem_key: mlkem.MLKEM1024PublicKey,
57+
p384_key: ec.EllipticCurvePublicKey,
58+
) -> None: ...
59+
4460
class Suite:
4561
def __init__(self, kem: KEM, kdf: KDF, aead: AEAD) -> None: ...
4662
def encrypt(
@@ -50,7 +66,8 @@ class Suite:
5066
| ec.EllipticCurvePublicKey
5167
| mlkem.MLKEM768PublicKey
5268
| mlkem.MLKEM1024PublicKey
53-
| MLKEM768X25519PublicKey,
69+
| MLKEM768X25519PublicKey
70+
| MLKEM1024P384PublicKey,
5471
info: Buffer | None = None,
5572
) -> bytes: ...
5673
def decrypt(
@@ -60,7 +77,8 @@ class Suite:
6077
| ec.EllipticCurvePrivateKey
6178
| mlkem.MLKEM768PrivateKey
6279
| mlkem.MLKEM1024PrivateKey
63-
| MLKEM768X25519PrivateKey,
80+
| MLKEM768X25519PrivateKey
81+
| MLKEM1024P384PrivateKey,
6482
info: Buffer | None = None,
6583
) -> bytes: ...
6684

@@ -71,7 +89,8 @@ def _encrypt_with_aad(
7189
| ec.EllipticCurvePublicKey
7290
| mlkem.MLKEM768PublicKey
7391
| mlkem.MLKEM1024PublicKey
74-
| MLKEM768X25519PublicKey,
92+
| MLKEM768X25519PublicKey
93+
| MLKEM1024P384PublicKey,
7594
info: Buffer | None = None,
7695
aad: Buffer | None = None,
7796
) -> bytes: ...
@@ -82,7 +101,8 @@ def _decrypt_with_aad(
82101
| ec.EllipticCurvePrivateKey
83102
| mlkem.MLKEM768PrivateKey
84103
| mlkem.MLKEM1024PrivateKey
85-
| MLKEM768X25519PrivateKey,
104+
| MLKEM768X25519PrivateKey
105+
| MLKEM1024P384PrivateKey,
86106
info: Buffer | None = None,
87107
aad: Buffer | None = None,
88108
) -> bytes: ...

src/cryptography/hazmat/primitives/hpke.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
KEM = rust_openssl.hpke.KEM
1212
MLKEM768X25519PrivateKey = rust_openssl.hpke.MLKEM768X25519PrivateKey
1313
MLKEM768X25519PublicKey = rust_openssl.hpke.MLKEM768X25519PublicKey
14+
MLKEM1024P384PrivateKey = rust_openssl.hpke.MLKEM1024P384PrivateKey
15+
MLKEM1024P384PublicKey = rust_openssl.hpke.MLKEM1024P384PublicKey
1416
Suite = rust_openssl.hpke.Suite
1517

1618
__all__ = [
@@ -19,5 +21,7 @@
1921
"KEM",
2022
"MLKEM768X25519PrivateKey",
2123
"MLKEM768X25519PublicKey",
24+
"MLKEM1024P384PrivateKey",
25+
"MLKEM1024P384PublicKey",
2226
"Suite",
2327
]

0 commit comments

Comments
 (0)