Skip to main content

crypto_hpke/
identifiers.rs

1// SPDX-FileCopyrightText: Copyright © 2026 ReallyMe LLC. All rights reserved
2//
3// SPDX-License-Identifier: Apache-2.0
4
5use crate::constants::{
6    HPKE_AEAD_AES_128_GCM, HPKE_AEAD_AES_256_GCM, HPKE_AEAD_CHACHA20_POLY1305,
7    HPKE_AEAD_EXPORT_ONLY, HPKE_AEAD_TAG_LEN, HPKE_KDF_HKDF_SHA256, HPKE_KDF_HKDF_SHA384,
8    HPKE_KDF_HKDF_SHA512, HPKE_KDF_SHAKE128, HPKE_KDF_SHAKE256, HPKE_KDF_TURBO_SHAKE128,
9    HPKE_KDF_TURBO_SHAKE256, HPKE_KEM_DHKEM_CP256_HKDF_SHA256, HPKE_KEM_DHKEM_CP384_HKDF_SHA384,
10    HPKE_KEM_DHKEM_CP521_HKDF_SHA512, HPKE_KEM_DHKEM_P256_HKDF_SHA256,
11    HPKE_KEM_DHKEM_P384_HKDF_SHA384, HPKE_KEM_DHKEM_P521_HKDF_SHA512,
12    HPKE_KEM_DHKEM_SECP256K1_HKDF_SHA256, HPKE_KEM_DHKEM_X25519_ELLIGATOR_HKDF_SHA256,
13    HPKE_KEM_DHKEM_X25519_HKDF_SHA256, HPKE_KEM_DHKEM_X448_HKDF_SHA512, HPKE_KEM_ML_KEM_1024,
14    HPKE_KEM_ML_KEM_1024_P384, HPKE_KEM_ML_KEM_512, HPKE_KEM_ML_KEM_768, HPKE_KEM_ML_KEM_768_P256,
15    HPKE_KEM_X25519_KYBER768_DRAFT00, HPKE_KEM_X_WING,
16};
17use crate::error::HpkeError;
18
19/// Runtime availability of an IANA-registered HPKE component in this build.
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum HpkeComponentSupport {
22    /// The component is implemented by this crate's selected backend.
23    Executable,
24    /// The identifier is recognized, but this crate has no reviewed backend.
25    RegisteredUnavailable,
26}
27
28/// Registered HPKE KEM identifier.
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30#[repr(u16)]
31pub enum HpkeKemId {
32    /// DHKEM(P-256, HKDF-SHA256).
33    DhKemP256HkdfSha256 = HPKE_KEM_DHKEM_P256_HKDF_SHA256,
34    /// DHKEM(P-384, HKDF-SHA384).
35    DhKemP384HkdfSha384 = HPKE_KEM_DHKEM_P384_HKDF_SHA384,
36    /// DHKEM(P-521, HKDF-SHA512).
37    DhKemP521HkdfSha512 = HPKE_KEM_DHKEM_P521_HKDF_SHA512,
38    /// DHKEM(CP-256, HKDF-SHA256).
39    DhKemCp256HkdfSha256 = HPKE_KEM_DHKEM_CP256_HKDF_SHA256,
40    /// DHKEM(CP-384, HKDF-SHA384).
41    DhKemCp384HkdfSha384 = HPKE_KEM_DHKEM_CP384_HKDF_SHA384,
42    /// DHKEM(CP-521, HKDF-SHA512).
43    DhKemCp521HkdfSha512 = HPKE_KEM_DHKEM_CP521_HKDF_SHA512,
44    /// DHKEM(secp256k1, HKDF-SHA256).
45    DhKemSecp256k1HkdfSha256 = HPKE_KEM_DHKEM_SECP256K1_HKDF_SHA256,
46    /// DHKEM(X25519, HKDF-SHA256).
47    DhKemX25519HkdfSha256 = HPKE_KEM_DHKEM_X25519_HKDF_SHA256,
48    /// DHKEM(X448, HKDF-SHA512).
49    DhKemX448HkdfSha512 = HPKE_KEM_DHKEM_X448_HKDF_SHA512,
50    /// DHKEM(X25519+Elligator, HKDF-SHA256).
51    DhKemX25519ElligatorHkdfSha256 = HPKE_KEM_DHKEM_X25519_ELLIGATOR_HKDF_SHA256,
52    /// X25519Kyber768Draft00.
53    X25519Kyber768Draft00 = HPKE_KEM_X25519_KYBER768_DRAFT00,
54    /// ML-KEM-512.
55    MlKem512 = HPKE_KEM_ML_KEM_512,
56    /// ML-KEM-768.
57    MlKem768 = HPKE_KEM_ML_KEM_768,
58    /// ML-KEM-1024.
59    MlKem1024 = HPKE_KEM_ML_KEM_1024,
60    /// MLKEM768-P256.
61    MlKem768P256 = HPKE_KEM_ML_KEM_768_P256,
62    /// MLKEM1024-P384.
63    MlKem1024P384 = HPKE_KEM_ML_KEM_1024_P384,
64    /// X-Wing.
65    XWing = HPKE_KEM_X_WING,
66}
67
68impl HpkeKemId {
69    /// Reports whether this registered KEM has a reviewed implementation.
70    pub const fn support(self) -> HpkeComponentSupport {
71        match self {
72            Self::DhKemP256HkdfSha256 if cfg!(feature = "kem-dh-p256") => {
73                HpkeComponentSupport::Executable
74            }
75            Self::DhKemP384HkdfSha384 if cfg!(feature = "kem-dh-p384") => {
76                HpkeComponentSupport::Executable
77            }
78            Self::DhKemP521HkdfSha512 if cfg!(feature = "kem-dh-p521") => {
79                HpkeComponentSupport::Executable
80            }
81            Self::DhKemSecp256k1HkdfSha256 if cfg!(feature = "kem-secp256k1") => {
82                HpkeComponentSupport::Executable
83            }
84            Self::DhKemX25519HkdfSha256 if cfg!(feature = "kem-x25519") => {
85                HpkeComponentSupport::Executable
86            }
87            Self::DhKemX448HkdfSha512 if cfg!(feature = "kem-x448") => {
88                HpkeComponentSupport::Executable
89            }
90            Self::MlKem512 if cfg!(feature = "kem-ml-kem-512") => HpkeComponentSupport::Executable,
91            Self::MlKem768 if cfg!(feature = "kem-ml-kem-768") => HpkeComponentSupport::Executable,
92            Self::MlKem1024 if cfg!(feature = "kem-ml-kem-1024") => {
93                HpkeComponentSupport::Executable
94            }
95            Self::MlKem768P256 if cfg!(feature = "kem-ml-kem-768-p256") => {
96                HpkeComponentSupport::Executable
97            }
98            Self::MlKem1024P384 if cfg!(feature = "kem-ml-kem-1024-p384") => {
99                HpkeComponentSupport::Executable
100            }
101            Self::XWing if cfg!(feature = "kem-x-wing") => HpkeComponentSupport::Executable,
102            Self::DhKemCp256HkdfSha256
103            | Self::DhKemCp384HkdfSha384
104            | Self::DhKemCp521HkdfSha512
105            | Self::DhKemX25519ElligatorHkdfSha256
106            | Self::X25519Kyber768Draft00
107            | Self::DhKemP256HkdfSha256
108            | Self::DhKemP384HkdfSha384
109            | Self::DhKemP521HkdfSha512
110            | Self::DhKemSecp256k1HkdfSha256
111            | Self::DhKemX25519HkdfSha256
112            | Self::DhKemX448HkdfSha512
113            | Self::MlKem512
114            | Self::MlKem768
115            | Self::MlKem1024
116            | Self::MlKem768P256
117            | Self::MlKem1024P384
118            | Self::XWing => HpkeComponentSupport::RegisteredUnavailable,
119        }
120    }
121}
122
123impl TryFrom<u16> for HpkeKemId {
124    type Error = HpkeError;
125
126    fn try_from(value: u16) -> Result<Self, Self::Error> {
127        match value {
128            HPKE_KEM_DHKEM_P256_HKDF_SHA256 => Ok(Self::DhKemP256HkdfSha256),
129            HPKE_KEM_DHKEM_P384_HKDF_SHA384 => Ok(Self::DhKemP384HkdfSha384),
130            HPKE_KEM_DHKEM_P521_HKDF_SHA512 => Ok(Self::DhKemP521HkdfSha512),
131            HPKE_KEM_DHKEM_CP256_HKDF_SHA256 => Ok(Self::DhKemCp256HkdfSha256),
132            HPKE_KEM_DHKEM_CP384_HKDF_SHA384 => Ok(Self::DhKemCp384HkdfSha384),
133            HPKE_KEM_DHKEM_CP521_HKDF_SHA512 => Ok(Self::DhKemCp521HkdfSha512),
134            HPKE_KEM_DHKEM_SECP256K1_HKDF_SHA256 => Ok(Self::DhKemSecp256k1HkdfSha256),
135            HPKE_KEM_DHKEM_X25519_HKDF_SHA256 => Ok(Self::DhKemX25519HkdfSha256),
136            HPKE_KEM_DHKEM_X448_HKDF_SHA512 => Ok(Self::DhKemX448HkdfSha512),
137            HPKE_KEM_DHKEM_X25519_ELLIGATOR_HKDF_SHA256 => Ok(Self::DhKemX25519ElligatorHkdfSha256),
138            HPKE_KEM_X25519_KYBER768_DRAFT00 => Ok(Self::X25519Kyber768Draft00),
139            HPKE_KEM_ML_KEM_512 => Ok(Self::MlKem512),
140            HPKE_KEM_ML_KEM_768 => Ok(Self::MlKem768),
141            HPKE_KEM_ML_KEM_1024 => Ok(Self::MlKem1024),
142            HPKE_KEM_ML_KEM_768_P256 => Ok(Self::MlKem768P256),
143            HPKE_KEM_ML_KEM_1024_P384 => Ok(Self::MlKem1024P384),
144            HPKE_KEM_X_WING => Ok(Self::XWing),
145            _ => Err(HpkeError::UnsupportedKem),
146        }
147    }
148}
149
150/// Registered HPKE KDF identifier.
151#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152#[repr(u16)]
153pub enum HpkeKdfId {
154    /// HKDF-SHA256.
155    HkdfSha256 = HPKE_KDF_HKDF_SHA256,
156    /// HKDF-SHA384.
157    HkdfSha384 = HPKE_KDF_HKDF_SHA384,
158    /// HKDF-SHA512.
159    HkdfSha512 = HPKE_KDF_HKDF_SHA512,
160    /// SHAKE128 single-stage KDF.
161    Shake128 = HPKE_KDF_SHAKE128,
162    /// SHAKE256 single-stage KDF.
163    Shake256 = HPKE_KDF_SHAKE256,
164    /// TurboSHAKE128 single-stage KDF.
165    TurboShake128 = HPKE_KDF_TURBO_SHAKE128,
166    /// TurboSHAKE256 single-stage KDF.
167    TurboShake256 = HPKE_KDF_TURBO_SHAKE256,
168}
169
170impl HpkeKdfId {
171    /// Reports whether this registered KDF has a reviewed implementation.
172    pub const fn support(self) -> HpkeComponentSupport {
173        match self {
174            Self::HkdfSha256 if cfg!(feature = "kdf-hkdf-sha256") => {
175                HpkeComponentSupport::Executable
176            }
177            Self::HkdfSha384 if cfg!(feature = "kdf-hkdf-sha384") => {
178                HpkeComponentSupport::Executable
179            }
180            Self::HkdfSha512 if cfg!(feature = "kdf-hkdf-sha512") => {
181                HpkeComponentSupport::Executable
182            }
183            Self::Shake256 if cfg!(feature = "kdf-shake256") => HpkeComponentSupport::Executable,
184            Self::HkdfSha256
185            | Self::HkdfSha384
186            | Self::HkdfSha512
187            | Self::Shake128
188            | Self::Shake256
189            | Self::TurboShake128
190            | Self::TurboShake256 => HpkeComponentSupport::RegisteredUnavailable,
191        }
192    }
193}
194
195impl TryFrom<u16> for HpkeKdfId {
196    type Error = HpkeError;
197
198    fn try_from(value: u16) -> Result<Self, Self::Error> {
199        match value {
200            HPKE_KDF_HKDF_SHA256 => Ok(Self::HkdfSha256),
201            HPKE_KDF_HKDF_SHA384 => Ok(Self::HkdfSha384),
202            HPKE_KDF_HKDF_SHA512 => Ok(Self::HkdfSha512),
203            HPKE_KDF_SHAKE128 => Ok(Self::Shake128),
204            HPKE_KDF_SHAKE256 => Ok(Self::Shake256),
205            HPKE_KDF_TURBO_SHAKE128 => Ok(Self::TurboShake128),
206            HPKE_KDF_TURBO_SHAKE256 => Ok(Self::TurboShake256),
207            _ => Err(HpkeError::UnsupportedKdf),
208        }
209    }
210}
211
212/// Registered HPKE AEAD identifier.
213#[derive(Debug, Clone, Copy, PartialEq, Eq)]
214#[repr(u16)]
215pub enum HpkeAeadId {
216    /// AES-128-GCM.
217    Aes128Gcm = HPKE_AEAD_AES_128_GCM,
218    /// AES-256-GCM.
219    Aes256Gcm = HPKE_AEAD_AES_256_GCM,
220    /// ChaCha20-Poly1305.
221    ChaCha20Poly1305 = HPKE_AEAD_CHACHA20_POLY1305,
222    /// Export-only mode.
223    ExportOnly = HPKE_AEAD_EXPORT_ONLY,
224}
225
226impl HpkeAeadId {
227    /// Reports whether this registered AEAD has a reviewed implementation.
228    pub const fn support(self) -> HpkeComponentSupport {
229        match self {
230            Self::Aes128Gcm if cfg!(feature = "aead-aes128-gcm") => {
231                HpkeComponentSupport::Executable
232            }
233            Self::Aes256Gcm if cfg!(feature = "aead-aes256-gcm") => {
234                HpkeComponentSupport::Executable
235            }
236            Self::ChaCha20Poly1305 if cfg!(feature = "aead-chacha20-poly1305") => {
237                HpkeComponentSupport::Executable
238            }
239            Self::ExportOnly if cfg!(feature = "aead-export-only") => {
240                HpkeComponentSupport::Executable
241            }
242            Self::Aes128Gcm | Self::Aes256Gcm | Self::ChaCha20Poly1305 | Self::ExportOnly => {
243                HpkeComponentSupport::RegisteredUnavailable
244            }
245        }
246    }
247}
248
249/// Complete IANA HPKE KEM registry snapshot supported by the `0.3.3` contract.
250pub const HPKE_REGISTERED_KEMS: [HpkeKemId; 17] = [
251    HpkeKemId::DhKemP256HkdfSha256,
252    HpkeKemId::DhKemP384HkdfSha384,
253    HpkeKemId::DhKemP521HkdfSha512,
254    HpkeKemId::DhKemCp256HkdfSha256,
255    HpkeKemId::DhKemCp384HkdfSha384,
256    HpkeKemId::DhKemCp521HkdfSha512,
257    HpkeKemId::DhKemSecp256k1HkdfSha256,
258    HpkeKemId::DhKemX25519HkdfSha256,
259    HpkeKemId::DhKemX448HkdfSha512,
260    HpkeKemId::DhKemX25519ElligatorHkdfSha256,
261    HpkeKemId::X25519Kyber768Draft00,
262    HpkeKemId::MlKem512,
263    HpkeKemId::MlKem768,
264    HpkeKemId::MlKem1024,
265    HpkeKemId::MlKem768P256,
266    HpkeKemId::MlKem1024P384,
267    HpkeKemId::XWing,
268];
269
270/// Complete IANA HPKE KDF registry snapshot supported by the `0.3.3` contract.
271pub const HPKE_REGISTERED_KDFS: [HpkeKdfId; 7] = [
272    HpkeKdfId::HkdfSha256,
273    HpkeKdfId::HkdfSha384,
274    HpkeKdfId::HkdfSha512,
275    HpkeKdfId::Shake128,
276    HpkeKdfId::Shake256,
277    HpkeKdfId::TurboShake128,
278    HpkeKdfId::TurboShake256,
279];
280
281/// Complete IANA HPKE AEAD registry snapshot supported by the `0.3.3` contract.
282pub const HPKE_REGISTERED_AEADS: [HpkeAeadId; 4] = [
283    HpkeAeadId::Aes128Gcm,
284    HpkeAeadId::Aes256Gcm,
285    HpkeAeadId::ChaCha20Poly1305,
286    HpkeAeadId::ExportOnly,
287];
288
289impl TryFrom<u16> for HpkeAeadId {
290    type Error = HpkeError;
291
292    fn try_from(value: u16) -> Result<Self, Self::Error> {
293        match value {
294            HPKE_AEAD_AES_128_GCM => Ok(Self::Aes128Gcm),
295            HPKE_AEAD_AES_256_GCM => Ok(Self::Aes256Gcm),
296            HPKE_AEAD_CHACHA20_POLY1305 => Ok(Self::ChaCha20Poly1305),
297            HPKE_AEAD_EXPORT_ONLY => Ok(Self::ExportOnly),
298            _ => Err(HpkeError::UnsupportedAead),
299        }
300    }
301}
302
303/// A typed HPKE ciphersuite identifier.
304#[derive(Debug, Clone, Copy, PartialEq, Eq)]
305pub struct HpkeSuite {
306    /// KEM component.
307    pub kem: HpkeKemId,
308    /// KDF component.
309    pub kdf: HpkeKdfId,
310    /// AEAD component.
311    pub aead: HpkeAeadId,
312}
313
314impl HpkeSuite {
315    /// Constructs a suite from registered component identifiers.
316    pub const fn new(kem: HpkeKemId, kdf: HpkeKdfId, aead: HpkeAeadId) -> Self {
317        Self { kem, kdf, aead }
318    }
319
320    /// HPKE KEM identifier.
321    pub const fn kem_id(self) -> u16 {
322        self.kem as u16
323    }
324
325    /// HPKE KDF identifier.
326    pub const fn kdf_id(self) -> u16 {
327        self.kdf as u16
328    }
329
330    /// HPKE AEAD identifier.
331    pub const fn aead_id(self) -> u16 {
332        self.aead as u16
333    }
334
335    /// AEAD tag length, or zero for export-only mode.
336    pub const fn tag_len(self) -> usize {
337        match self.aead {
338            HpkeAeadId::ExportOnly => 0,
339            HpkeAeadId::Aes128Gcm | HpkeAeadId::Aes256Gcm | HpkeAeadId::ChaCha20Poly1305 => {
340                HPKE_AEAD_TAG_LEN
341            }
342        }
343    }
344}
345
346/// DHKEM(P-256), HKDF-SHA256, AES-128-GCM.
347pub const HPKE_DHKEM_P256_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
348    HpkeKemId::DhKemP256HkdfSha256,
349    HpkeKdfId::HkdfSha256,
350    HpkeAeadId::Aes128Gcm,
351);
352/// DHKEM(P-256), HKDF-SHA256, AES-256-GCM.
353pub const HPKE_DHKEM_P256_HKDF_SHA256_AES256GCM: HpkeSuite = HpkeSuite::new(
354    HpkeKemId::DhKemP256HkdfSha256,
355    HpkeKdfId::HkdfSha256,
356    HpkeAeadId::Aes256Gcm,
357);
358/// DHKEM(P-384), HKDF-SHA384, AES-256-GCM.
359pub const HPKE_DHKEM_P384_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
360    HpkeKemId::DhKemP384HkdfSha384,
361    HpkeKdfId::HkdfSha384,
362    HpkeAeadId::Aes256Gcm,
363);
364/// DHKEM(P-521), HKDF-SHA512, AES-256-GCM.
365pub const HPKE_DHKEM_P521_HKDF_SHA512_AES256GCM: HpkeSuite = HpkeSuite::new(
366    HpkeKemId::DhKemP521HkdfSha512,
367    HpkeKdfId::HkdfSha512,
368    HpkeAeadId::Aes256Gcm,
369);
370/// DHKEM(X25519), HKDF-SHA256, AES-128-GCM.
371pub const HPKE_DHKEM_X25519_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
372    HpkeKemId::DhKemX25519HkdfSha256,
373    HpkeKdfId::HkdfSha256,
374    HpkeAeadId::Aes128Gcm,
375);
376/// DHKEM(X25519), HKDF-SHA256, ChaCha20-Poly1305.
377pub const HPKE_DHKEM_X25519_HKDF_SHA256_CHACHA20POLY1305: HpkeSuite = HpkeSuite::new(
378    HpkeKemId::DhKemX25519HkdfSha256,
379    HpkeKdfId::HkdfSha256,
380    HpkeAeadId::ChaCha20Poly1305,
381);
382/// ML-KEM-512, HKDF-SHA256, AES-128-GCM.
383///
384/// ML-KEM-512 targets NIST security category 1. Prefer ML-KEM-768,
385/// ML-KEM-1024, or a hybrid KEM unless a constrained profile requires it.
386pub const HPKE_MLKEM512_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
387    HpkeKemId::MlKem512,
388    HpkeKdfId::HkdfSha256,
389    HpkeAeadId::Aes128Gcm,
390);
391/// X-Wing, HKDF-SHA256, ChaCha20-Poly1305.
392pub const HPKE_XWING_HKDF_SHA256_CHACHA20POLY1305: HpkeSuite = HpkeSuite::new(
393    HpkeKemId::XWing,
394    HpkeKdfId::HkdfSha256,
395    HpkeAeadId::ChaCha20Poly1305,
396);
397/// ML-KEM-768, SHAKE256, AES-256-GCM.
398pub const HPKE_MLKEM768_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
399    HpkeKemId::MlKem768,
400    HpkeKdfId::Shake256,
401    HpkeAeadId::Aes256Gcm,
402);
403/// ML-KEM-1024, SHAKE256, AES-256-GCM.
404pub const HPKE_MLKEM1024_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
405    HpkeKemId::MlKem1024,
406    HpkeKdfId::Shake256,
407    HpkeAeadId::Aes256Gcm,
408);
409/// ML-KEM-1024, HKDF-SHA384, AES-256-GCM.
410pub const HPKE_MLKEM1024_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
411    HpkeKemId::MlKem1024,
412    HpkeKdfId::HkdfSha384,
413    HpkeAeadId::Aes256Gcm,
414);
415/// MLKEM768-P256, SHAKE256, AES-256-GCM.
416pub const HPKE_MLKEM768P256_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
417    HpkeKemId::MlKem768P256,
418    HpkeKdfId::Shake256,
419    HpkeAeadId::Aes256Gcm,
420);
421/// MLKEM1024-P384, SHAKE256, AES-256-GCM.
422pub const HPKE_MLKEM1024P384_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
423    HpkeKemId::MlKem1024P384,
424    HpkeKdfId::Shake256,
425    HpkeAeadId::Aes256Gcm,
426);
427/// MLKEM1024-P384, HKDF-SHA384, AES-256-GCM.
428pub const HPKE_MLKEM1024P384_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
429    HpkeKemId::MlKem1024P384,
430    HpkeKdfId::HkdfSha384,
431    HpkeAeadId::Aes256Gcm,
432);
433/// MLS 192-bit profile: ML-KEM-1024, HKDF-SHA384, AES-256-GCM, and P-384 signatures.
434///
435/// The profile's MLS transcript hash and HPKE KDF both use SHA-384, but they
436/// remain distinct protocol components. The P-384 suffix identifies the MLS
437/// signature algorithm and does not alter the HPKE ciphersuite triple.
438pub const MLS_192_MLKEM1024_AES256GCM_SHA384_P384: HpkeSuite = HPKE_MLKEM1024_HKDF_SHA384_AES256GCM;
439/// MLS 256-bit profile: ML-KEM-1024, HKDF-SHA384, AES-256-GCM, and ML-DSA-87 signatures.
440///
441/// The ML-DSA-87 suffix identifies the MLS signature algorithm and does not
442/// alter the HPKE ciphersuite triple represented by this value.
443pub const MLS_256_MLKEM1024_AES256GCM_SHA384_MLDSA87: HpkeSuite =
444    HPKE_MLKEM1024_HKDF_SHA384_AES256GCM;
445/// MLS 192-bit profile: MLKEM1024-P384, HKDF-SHA384, AES-256-GCM, and P-384 signatures.
446///
447/// The profile's MLS transcript hash and HPKE KDF both use SHA-384, but they
448/// remain distinct protocol components. The final P-384 suffix identifies the
449/// MLS signature algorithm rather than an additional HPKE component.
450pub const MLS_192_MLKEM1024P384_AES256GCM_SHA384_P384: HpkeSuite =
451    HPKE_MLKEM1024P384_HKDF_SHA384_AES256GCM;