1use 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub enum HpkeComponentSupport {
22 Executable,
24 RegisteredUnavailable,
26}
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30#[repr(u16)]
31pub enum HpkeKemId {
32 DhKemP256HkdfSha256 = HPKE_KEM_DHKEM_P256_HKDF_SHA256,
34 DhKemP384HkdfSha384 = HPKE_KEM_DHKEM_P384_HKDF_SHA384,
36 DhKemP521HkdfSha512 = HPKE_KEM_DHKEM_P521_HKDF_SHA512,
38 DhKemCp256HkdfSha256 = HPKE_KEM_DHKEM_CP256_HKDF_SHA256,
40 DhKemCp384HkdfSha384 = HPKE_KEM_DHKEM_CP384_HKDF_SHA384,
42 DhKemCp521HkdfSha512 = HPKE_KEM_DHKEM_CP521_HKDF_SHA512,
44 DhKemSecp256k1HkdfSha256 = HPKE_KEM_DHKEM_SECP256K1_HKDF_SHA256,
46 DhKemX25519HkdfSha256 = HPKE_KEM_DHKEM_X25519_HKDF_SHA256,
48 DhKemX448HkdfSha512 = HPKE_KEM_DHKEM_X448_HKDF_SHA512,
50 DhKemX25519ElligatorHkdfSha256 = HPKE_KEM_DHKEM_X25519_ELLIGATOR_HKDF_SHA256,
52 X25519Kyber768Draft00 = HPKE_KEM_X25519_KYBER768_DRAFT00,
54 MlKem512 = HPKE_KEM_ML_KEM_512,
56 MlKem768 = HPKE_KEM_ML_KEM_768,
58 MlKem1024 = HPKE_KEM_ML_KEM_1024,
60 MlKem768P256 = HPKE_KEM_ML_KEM_768_P256,
62 MlKem1024P384 = HPKE_KEM_ML_KEM_1024_P384,
64 XWing = HPKE_KEM_X_WING,
66}
67
68impl HpkeKemId {
69 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152#[repr(u16)]
153pub enum HpkeKdfId {
154 HkdfSha256 = HPKE_KDF_HKDF_SHA256,
156 HkdfSha384 = HPKE_KDF_HKDF_SHA384,
158 HkdfSha512 = HPKE_KDF_HKDF_SHA512,
160 Shake128 = HPKE_KDF_SHAKE128,
162 Shake256 = HPKE_KDF_SHAKE256,
164 TurboShake128 = HPKE_KDF_TURBO_SHAKE128,
166 TurboShake256 = HPKE_KDF_TURBO_SHAKE256,
168}
169
170impl HpkeKdfId {
171 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
214#[repr(u16)]
215pub enum HpkeAeadId {
216 Aes128Gcm = HPKE_AEAD_AES_128_GCM,
218 Aes256Gcm = HPKE_AEAD_AES_256_GCM,
220 ChaCha20Poly1305 = HPKE_AEAD_CHACHA20_POLY1305,
222 ExportOnly = HPKE_AEAD_EXPORT_ONLY,
224}
225
226impl HpkeAeadId {
227 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
249pub 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
270pub 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
281pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
305pub struct HpkeSuite {
306 pub kem: HpkeKemId,
308 pub kdf: HpkeKdfId,
310 pub aead: HpkeAeadId,
312}
313
314impl HpkeSuite {
315 pub const fn new(kem: HpkeKemId, kdf: HpkeKdfId, aead: HpkeAeadId) -> Self {
317 Self { kem, kdf, aead }
318 }
319
320 pub const fn kem_id(self) -> u16 {
322 self.kem as u16
323 }
324
325 pub const fn kdf_id(self) -> u16 {
327 self.kdf as u16
328 }
329
330 pub const fn aead_id(self) -> u16 {
332 self.aead as u16
333 }
334
335 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
346pub const HPKE_DHKEM_P256_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
348 HpkeKemId::DhKemP256HkdfSha256,
349 HpkeKdfId::HkdfSha256,
350 HpkeAeadId::Aes128Gcm,
351);
352pub const HPKE_DHKEM_P256_HKDF_SHA256_AES256GCM: HpkeSuite = HpkeSuite::new(
354 HpkeKemId::DhKemP256HkdfSha256,
355 HpkeKdfId::HkdfSha256,
356 HpkeAeadId::Aes256Gcm,
357);
358pub const HPKE_DHKEM_P384_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
360 HpkeKemId::DhKemP384HkdfSha384,
361 HpkeKdfId::HkdfSha384,
362 HpkeAeadId::Aes256Gcm,
363);
364pub const HPKE_DHKEM_P521_HKDF_SHA512_AES256GCM: HpkeSuite = HpkeSuite::new(
366 HpkeKemId::DhKemP521HkdfSha512,
367 HpkeKdfId::HkdfSha512,
368 HpkeAeadId::Aes256Gcm,
369);
370pub const HPKE_DHKEM_X25519_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
372 HpkeKemId::DhKemX25519HkdfSha256,
373 HpkeKdfId::HkdfSha256,
374 HpkeAeadId::Aes128Gcm,
375);
376pub const HPKE_DHKEM_X25519_HKDF_SHA256_CHACHA20POLY1305: HpkeSuite = HpkeSuite::new(
378 HpkeKemId::DhKemX25519HkdfSha256,
379 HpkeKdfId::HkdfSha256,
380 HpkeAeadId::ChaCha20Poly1305,
381);
382pub const HPKE_MLKEM512_HKDF_SHA256_AES128GCM: HpkeSuite = HpkeSuite::new(
387 HpkeKemId::MlKem512,
388 HpkeKdfId::HkdfSha256,
389 HpkeAeadId::Aes128Gcm,
390);
391pub const HPKE_XWING_HKDF_SHA256_CHACHA20POLY1305: HpkeSuite = HpkeSuite::new(
393 HpkeKemId::XWing,
394 HpkeKdfId::HkdfSha256,
395 HpkeAeadId::ChaCha20Poly1305,
396);
397pub const HPKE_MLKEM768_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
399 HpkeKemId::MlKem768,
400 HpkeKdfId::Shake256,
401 HpkeAeadId::Aes256Gcm,
402);
403pub const HPKE_MLKEM1024_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
405 HpkeKemId::MlKem1024,
406 HpkeKdfId::Shake256,
407 HpkeAeadId::Aes256Gcm,
408);
409pub const HPKE_MLKEM1024_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
411 HpkeKemId::MlKem1024,
412 HpkeKdfId::HkdfSha384,
413 HpkeAeadId::Aes256Gcm,
414);
415pub const HPKE_MLKEM768P256_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
417 HpkeKemId::MlKem768P256,
418 HpkeKdfId::Shake256,
419 HpkeAeadId::Aes256Gcm,
420);
421pub const HPKE_MLKEM1024P384_SHAKE256_AES256GCM: HpkeSuite = HpkeSuite::new(
423 HpkeKemId::MlKem1024P384,
424 HpkeKdfId::Shake256,
425 HpkeAeadId::Aes256Gcm,
426);
427pub const HPKE_MLKEM1024P384_HKDF_SHA384_AES256GCM: HpkeSuite = HpkeSuite::new(
429 HpkeKemId::MlKem1024P384,
430 HpkeKdfId::HkdfSha384,
431 HpkeAeadId::Aes256Gcm,
432);
433pub const MLS_192_MLKEM1024_AES256GCM_SHA384_P384: HpkeSuite = HPKE_MLKEM1024_HKDF_SHA384_AES256GCM;
439pub const MLS_256_MLKEM1024_AES256GCM_SHA384_MLDSA87: HpkeSuite =
444 HPKE_MLKEM1024_HKDF_SHA384_AES256GCM;
445pub const MLS_192_MLKEM1024P384_AES256GCM_SHA384_P384: HpkeSuite =
451 HPKE_MLKEM1024P384_HKDF_SHA384_AES256GCM;