1use crypto::{Hash, curve25519::x25519, p256, p521};
4
5use super::{
6 HpkeError,
7 kdf::{HkdfSha256, HkdfSha512, Kdf, Shake256 as Shake256Kdf},
8 wipe,
9};
10
11pub trait Kem: Sized {
45 const HPKE_KEM_ID: u16;
48
49 const SHARED_SECRET_SIZE: usize;
53
54 const ENCAPPED_KEY_SIZE: usize;
56
57 const PUBLIC_KEY_SIZE: usize;
59
60 const SECRET_KEY_SIZE: usize;
62
63 const RANDOMNESS_SIZE: usize = Self::SECRET_KEY_SIZE;
70
71 type PublicKey: Clone;
73
74 type SecretKey: Clone;
76
77 type EncappedKey: Clone;
80
81 fn derive_keypair(input_keying_material: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), HpkeError>;
94
95 #[cfg(feature = "random")]
103 fn generate_keypair() -> Result<(Self::SecretKey, Self::PublicKey), HpkeError> {
104 const MAX_SECRET_KEY_SIZE: usize = 66;
108 const {
109 assert!(
110 Self::SECRET_KEY_SIZE <= MAX_SECRET_KEY_SIZE,
111 "SECRET_KEY_SIZE is too large; override generate_keypair"
112 )
113 };
114
115 let mut input_keying_material = [0u8; MAX_SECRET_KEY_SIZE];
116 crypto::random::fill(&mut input_keying_material[..Self::SECRET_KEY_SIZE])?;
117 return Self::derive_keypair(&input_keying_material[..Self::SECRET_KEY_SIZE]);
118 }
119
120 fn derive_public_key(secret_key: &Self::SecretKey) -> Self::PublicKey;
122
123 fn public_key_to_bytes(out: &mut [u8], public_key: &Self::PublicKey) -> Result<(), HpkeError>;
131
132 fn public_key_from_bytes(bytes: &[u8]) -> Result<Self::PublicKey, HpkeError>;
140
141 fn secret_key_to_bytes(out: &mut [u8], secret_key: &Self::SecretKey) -> Result<(), HpkeError>;
149
150 fn secret_key_from_bytes(bytes: &[u8]) -> Result<Self::SecretKey, HpkeError>;
158
159 fn encapped_key_to_bytes(out: &mut [u8], encapped_key: &Self::EncappedKey) -> Result<(), HpkeError>;
167
168 fn encapped_key_from_bytes(bytes: &[u8]) -> Result<Self::EncappedKey, HpkeError>;
176
177 fn encap_with_ephemeral(
190 ephemeral_secret_key: &Self::SecretKey,
191 recipient_public_key: &Self::PublicKey,
192 ) -> Result<(Hash, Self::EncappedKey), HpkeError>;
193
194 #[cfg(feature = "random")]
203 fn encap(recipient_public_key: &Self::PublicKey) -> Result<(Hash, Self::EncappedKey), HpkeError> {
204 let (ephemeral_secret_key, _ephemeral_public_key) = Self::generate_keypair()?;
205 return Self::encap_with_ephemeral(&ephemeral_secret_key, recipient_public_key);
206 }
207
208 fn encap_deterministic(
229 recipient_public_key: &Self::PublicKey,
230 randomness: &[u8],
231 ) -> Result<(Hash, Self::EncappedKey), HpkeError> {
232 if randomness.len() != Self::RANDOMNESS_SIZE {
233 return Err(HpkeError::DeserializeError);
234 }
235 let (ephemeral_secret_key, _ephemeral_public_key) = Self::derive_keypair(randomness)?;
236 return Self::encap_with_ephemeral(&ephemeral_secret_key, recipient_public_key);
237 }
238
239 fn decap(encapped_key: &Self::EncappedKey, recipient_secret_key: &Self::SecretKey) -> Result<Hash, HpkeError>;
247}
248
249#[derive(Clone, Copy, Debug, PartialEq, Eq)]
283pub struct MLKEM768X25519;
284
285impl Kem for MLKEM768X25519 {
286 const HPKE_KEM_ID: u16 = 0x647a;
287 const SHARED_SECRET_SIZE: usize = crypto::xwing::SHARED_SECRET_SIZE;
288 const ENCAPPED_KEY_SIZE: usize = crypto::xwing::CIPHERTEXT_SIZE;
289 const PUBLIC_KEY_SIZE: usize = crypto::xwing::PUBLIC_KEY_SIZE;
290 const SECRET_KEY_SIZE: usize = crypto::xwing::SECRET_KEY_SIZE;
291 const RANDOMNESS_SIZE: usize = 64;
292
293 type PublicKey = crypto::xwing::PublicKey;
294 type SecretKey = crypto::xwing::SecretKey;
295 type EncappedKey = [u8; crypto::xwing::CIPHERTEXT_SIZE];
296
297 fn derive_keypair(input_keying_material: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), HpkeError> {
298 let suite_id = kem_suite_id(Self::HPKE_KEM_ID);
302 let mut seed = [0u8; crypto::xwing::SECRET_KEY_SIZE];
303 <Shake256Kdf as Kdf>::labeled_derive(&mut seed, &[input_keying_material], &suite_id, b"DeriveKeyPair", &[])?;
304
305 let keypair = crypto::xwing::generate_keypair_derand(&seed);
306 wipe(&mut seed);
307 return Ok(keypair);
308 }
309
310 #[cfg(feature = "random")]
311 fn generate_keypair() -> Result<(Self::SecretKey, Self::PublicKey), HpkeError> {
312 return crypto::xwing::generate_keypair().map_err(HpkeError::from);
313 }
314
315 fn derive_public_key(secret_key: &Self::SecretKey) -> Self::PublicKey {
316 return secret_key.public_key();
317 }
318
319 fn public_key_to_bytes(out: &mut [u8], public_key: &Self::PublicKey) -> Result<(), HpkeError> {
320 if out.len() != Self::PUBLIC_KEY_SIZE {
321 return Err(HpkeError::DeserializeError);
322 }
323 out.copy_from_slice(&public_key.to_bytes());
324 return Ok(());
325 }
326
327 fn public_key_from_bytes(bytes: &[u8]) -> Result<Self::PublicKey, HpkeError> {
328 let bytes: &[u8; Self::PUBLIC_KEY_SIZE] = bytes.try_into().map_err(|_| HpkeError::DeserializeError)?;
329 return crypto::xwing::PublicKey::from_bytes(bytes).map_err(HpkeError::from);
330 }
331
332 fn secret_key_to_bytes(out: &mut [u8], secret_key: &Self::SecretKey) -> Result<(), HpkeError> {
333 if out.len() != Self::SECRET_KEY_SIZE {
334 return Err(HpkeError::DeserializeError);
335 }
336 out.copy_from_slice(&secret_key.to_bytes());
337 return Ok(());
338 }
339
340 fn secret_key_from_bytes(bytes: &[u8]) -> Result<Self::SecretKey, HpkeError> {
341 let bytes: &[u8; Self::SECRET_KEY_SIZE] = bytes.try_into().map_err(|_| HpkeError::DeserializeError)?;
342 return Ok(crypto::xwing::generate_keypair_derand(bytes).0);
343 }
344
345 fn encapped_key_to_bytes(out: &mut [u8], encapped_key: &Self::EncappedKey) -> Result<(), HpkeError> {
346 if out.len() != Self::ENCAPPED_KEY_SIZE {
347 return Err(HpkeError::DeserializeError);
348 }
349 out.copy_from_slice(encapped_key);
350 return Ok(());
351 }
352
353 fn encapped_key_from_bytes(bytes: &[u8]) -> Result<Self::EncappedKey, HpkeError> {
354 let bytes: &[u8; Self::ENCAPPED_KEY_SIZE] = bytes.try_into().map_err(|_| HpkeError::DeserializeError)?;
355 return Ok(*bytes);
356 }
357
358 #[cfg(feature = "random")]
359 fn encap(recipient_public_key: &Self::PublicKey) -> Result<(Hash, Self::EncappedKey), HpkeError> {
360 let mut randomness = [0u8; Self::RANDOMNESS_SIZE];
361 crypto::random::fill(&mut randomness)?;
362 let result = Self::encap_deterministic(recipient_public_key, &randomness);
363 wipe(&mut randomness);
364 return result;
365 }
366
367 fn encap_deterministic(
368 recipient_public_key: &Self::PublicKey,
369 randomness: &[u8],
370 ) -> Result<(Hash, Self::EncappedKey), HpkeError> {
371 let randomness: &[u8; 64] = randomness.try_into().map_err(|_| HpkeError::DeserializeError)?;
375 let (shared_secret, encapped_key) = recipient_public_key.encapsulate_derand(randomness);
376 return Ok((Hash::from(shared_secret), encapped_key));
377 }
378
379 fn encap_with_ephemeral(
380 ephemeral_secret_key: &Self::SecretKey,
381 recipient_public_key: &Self::PublicKey,
382 ) -> Result<(Hash, Self::EncappedKey), HpkeError> {
383 let mut encapsulation_seed = [0u8; 64];
387 crypto::sha3::Shake256::hash(&ephemeral_secret_key.to_bytes(), &mut encapsulation_seed);
388
389 let (shared_secret, encapped_key) = recipient_public_key.encapsulate_derand(&encapsulation_seed);
390 wipe(&mut encapsulation_seed);
391 return Ok((Hash::from(shared_secret), encapped_key));
392 }
393
394 fn decap(encapped_key: &Self::EncappedKey, recipient_secret_key: &Self::SecretKey) -> Result<Hash, HpkeError> {
395 let shared_secret = recipient_secret_key
396 .decapsulate(encapped_key)
397 .map_err(|_| HpkeError::DecapError)?;
398 return Ok(Hash::from(shared_secret));
399 }
400}
401
402const MAX_PUBLIC_KEY_SIZE: usize = 133;
408const MAX_DIFFIE_HELLMAN_OUTPUT_SIZE: usize = 66;
411const MAX_KEM_CONTEXT: usize = 2 * MAX_PUBLIC_KEY_SIZE;
413
414fn kem_suite_id(kem_id: u16) -> [u8; 5] {
417 let mut suite_id = [0u8; 5];
418 suite_id[..3].copy_from_slice(b"KEM");
419 suite_id[3] = (kem_id >> 8) as u8;
420 suite_id[4] = (kem_id & 0xff) as u8;
421 return suite_id;
422}
423
424trait DiffieHellmanGroup: Copy + Clone {
431 const DIFFIE_HELLMAN_OUTPUT_SIZE: usize;
433 const PUBLIC_KEY_SIZE: usize;
435 const SECRET_KEY_SIZE: usize;
437 const BITMASK: u8;
439 const REJECTION_SAMPLING: bool;
442
443 type SecretKey: Clone;
444 type PublicKey: Clone;
445
446 fn diffie_hellman(secret_key: &Self::SecretKey, public_key: &Self::PublicKey, out: &mut [u8]) -> Result<(), ()>;
451
452 fn derive_public_key(secret_key: &Self::SecretKey) -> Self::PublicKey;
454
455 fn serialize_public_key(out: &mut [u8], public_key: &Self::PublicKey) -> Result<(), HpkeError>;
457
458 fn deserialize_public_key(bytes: &[u8]) -> Result<Self::PublicKey, HpkeError>;
460
461 fn serialize_secret_key(out: &mut [u8], secret_key: &Self::SecretKey) -> Result<(), HpkeError>;
463
464 fn deserialize_secret_key(bytes: &[u8]) -> Result<Self::SecretKey, HpkeError>;
466
467 fn scalar_from_candidate(bytes: &[u8]) -> Result<Self::SecretKey, ()>;
470}
471
472#[derive(Clone, Copy, Debug, PartialEq, Eq)]
473struct X25519Group;
474
475impl DiffieHellmanGroup for X25519Group {
476 const DIFFIE_HELLMAN_OUTPUT_SIZE: usize = x25519::SHARED_SECRET_SIZE;
477 const PUBLIC_KEY_SIZE: usize = x25519::KEY_SIZE;
478 const SECRET_KEY_SIZE: usize = x25519::KEY_SIZE;
479 const BITMASK: u8 = 0xff;
480 const REJECTION_SAMPLING: bool = false;
481
482 type SecretKey = x25519::SecretKey;
483 type PublicKey = x25519::PublicKey;
484
485 fn diffie_hellman(secret_key: &Self::SecretKey, public_key: &Self::PublicKey, out: &mut [u8]) -> Result<(), ()> {
486 let shared = secret_key.ecdh(public_key).map_err(|_| ())?;
489 out.copy_from_slice(&shared);
490 return Ok(());
491 }
492
493 fn derive_public_key(secret_key: &Self::SecretKey) -> Self::PublicKey {
494 return secret_key.public_key();
495 }
496
497 fn serialize_public_key(out: &mut [u8], public_key: &Self::PublicKey) -> Result<(), HpkeError> {
498 if out.len() != Self::PUBLIC_KEY_SIZE {
499 return Err(HpkeError::DeserializeError);
500 }
501 out.copy_from_slice(&public_key.to_bytes());
502 return Ok(());
503 }
504
505 fn deserialize_public_key(bytes: &[u8]) -> Result<Self::PublicKey, HpkeError> {
506 let bytes: &[u8; Self::PUBLIC_KEY_SIZE] = bytes.try_into().map_err(|_| HpkeError::DeserializeError)?;
507 return Ok(x25519::PublicKey::from_bytes(bytes));
508 }
509
510 fn serialize_secret_key(out: &mut [u8], secret_key: &Self::SecretKey) -> Result<(), HpkeError> {
511 if out.len() != Self::SECRET_KEY_SIZE {
512 return Err(HpkeError::DeserializeError);
513 }
514 out.copy_from_slice(&secret_key.to_bytes());
518 return Ok(());
519 }
520
521 fn deserialize_secret_key(bytes: &[u8]) -> Result<Self::SecretKey, HpkeError> {
522 let bytes: &[u8; Self::SECRET_KEY_SIZE] = bytes.try_into().map_err(|_| HpkeError::DeserializeError)?;
523 return Ok(x25519::SecretKey::from_bytes(bytes));
524 }
525
526 fn scalar_from_candidate(bytes: &[u8]) -> Result<Self::SecretKey, ()> {
527 let bytes: &[u8; Self::SECRET_KEY_SIZE] = bytes.try_into().map_err(|_| ())?;
528 return Ok(x25519::SecretKey::from_bytes(bytes));
529 }
530}
531
532#[derive(Clone, Copy, Debug, PartialEq, Eq)]
533struct P256Group;
534
535impl DiffieHellmanGroup for P256Group {
536 const DIFFIE_HELLMAN_OUTPUT_SIZE: usize = p256::ECDH_SHARED_SECRET_SIZE;
537 const PUBLIC_KEY_SIZE: usize = p256::PUBLIC_KEY_UNCOMPRESSED_SIZE;
538 const SECRET_KEY_SIZE: usize = p256::SECRET_KEY_SIZE;
539 const BITMASK: u8 = 0xff;
540 const REJECTION_SAMPLING: bool = true;
541
542 type SecretKey = p256::SecretKey;
543 type PublicKey = p256::PublicKey;
544
545 fn diffie_hellman(secret_key: &Self::SecretKey, public_key: &Self::PublicKey, out: &mut [u8]) -> Result<(), ()> {
546 let shared = secret_key.ecdh(public_key).map_err(|_| ())?;
547 out.copy_from_slice(&shared);
548 return Ok(());
549 }
550
551 fn derive_public_key(secret_key: &Self::SecretKey) -> Self::PublicKey {
552 return secret_key.public_key();
553 }
554
555 fn serialize_public_key(out: &mut [u8], public_key: &Self::PublicKey) -> Result<(), HpkeError> {
556 if out.len() != Self::PUBLIC_KEY_SIZE {
557 return Err(HpkeError::DeserializeError);
558 }
559 out.copy_from_slice(&public_key.to_bytes());
560 return Ok(());
561 }
562
563 fn deserialize_public_key(bytes: &[u8]) -> Result<Self::PublicKey, HpkeError> {
564 if bytes.len() != Self::PUBLIC_KEY_SIZE || bytes[0] != 0x04 {
566 return Err(HpkeError::DeserializeError);
567 }
568 return p256::PublicKey::from_bytes(bytes).map_err(|_| HpkeError::DeserializeError);
569 }
570
571 fn serialize_secret_key(out: &mut [u8], secret_key: &Self::SecretKey) -> Result<(), HpkeError> {
572 if out.len() != Self::SECRET_KEY_SIZE {
573 return Err(HpkeError::DeserializeError);
574 }
575 out.copy_from_slice(&secret_key.to_bytes());
576 return Ok(());
577 }
578
579 fn deserialize_secret_key(bytes: &[u8]) -> Result<Self::SecretKey, HpkeError> {
580 let bytes: &[u8; Self::SECRET_KEY_SIZE] = bytes.try_into().map_err(|_| HpkeError::DeserializeError)?;
581 return p256::SecretKey::from_bytes(bytes).map_err(|_| HpkeError::DeserializeError);
582 }
583
584 fn scalar_from_candidate(bytes: &[u8]) -> Result<Self::SecretKey, ()> {
585 let bytes: &[u8; Self::SECRET_KEY_SIZE] = bytes.try_into().map_err(|_| ())?;
586 return p256::SecretKey::from_bytes(bytes).map_err(|_| ());
587 }
588}
589
590#[derive(Clone, Copy, Debug, PartialEq, Eq)]
591struct P521Group;
592
593impl DiffieHellmanGroup for P521Group {
594 const DIFFIE_HELLMAN_OUTPUT_SIZE: usize = p521::ECDH_SHARED_SECRET_SIZE;
595 const PUBLIC_KEY_SIZE: usize = p521::PUBLIC_KEY_UNCOMPRESSED_SIZE;
596 const SECRET_KEY_SIZE: usize = p521::SECRET_KEY_SIZE;
597 const BITMASK: u8 = 0x01;
598 const REJECTION_SAMPLING: bool = true;
599
600 type SecretKey = p521::SecretKey;
601 type PublicKey = p521::PublicKey;
602
603 fn diffie_hellman(secret_key: &Self::SecretKey, public_key: &Self::PublicKey, out: &mut [u8]) -> Result<(), ()> {
604 let shared = secret_key.ecdh(public_key).map_err(|_| ())?;
605 out.copy_from_slice(&shared);
606 return Ok(());
607 }
608
609 fn derive_public_key(secret_key: &Self::SecretKey) -> Self::PublicKey {
610 return secret_key.public_key();
611 }
612
613 fn serialize_public_key(out: &mut [u8], public_key: &Self::PublicKey) -> Result<(), HpkeError> {
614 if out.len() != Self::PUBLIC_KEY_SIZE {
615 return Err(HpkeError::DeserializeError);
616 }
617 out.copy_from_slice(&public_key.to_bytes());
618 return Ok(());
619 }
620
621 fn deserialize_public_key(bytes: &[u8]) -> Result<Self::PublicKey, HpkeError> {
622 if bytes.len() != Self::PUBLIC_KEY_SIZE || bytes[0] != 0x04 {
623 return Err(HpkeError::DeserializeError);
624 }
625 return p521::PublicKey::from_bytes(bytes).map_err(|_| HpkeError::DeserializeError);
626 }
627
628 fn serialize_secret_key(out: &mut [u8], secret_key: &Self::SecretKey) -> Result<(), HpkeError> {
629 if out.len() != Self::SECRET_KEY_SIZE {
630 return Err(HpkeError::DeserializeError);
631 }
632 out.copy_from_slice(&secret_key.to_bytes());
633 return Ok(());
634 }
635
636 fn deserialize_secret_key(bytes: &[u8]) -> Result<Self::SecretKey, HpkeError> {
637 let bytes: &[u8; Self::SECRET_KEY_SIZE] = bytes.try_into().map_err(|_| HpkeError::DeserializeError)?;
638 return p521::SecretKey::from_bytes(bytes).map_err(|_| HpkeError::DeserializeError);
639 }
640
641 fn scalar_from_candidate(bytes: &[u8]) -> Result<Self::SecretKey, ()> {
642 let bytes: &[u8; Self::SECRET_KEY_SIZE] = bytes.try_into().map_err(|_| ())?;
643 return p521::SecretKey::from_bytes(bytes).map_err(|_| ());
644 }
645}
646
647fn extract_and_expand<K: Kdf>(kem_id: u16, diffie_hellman: &[u8], kem_context: &[u8]) -> Result<Hash, HpkeError> {
649 const { assert!(K::OUTPUT_SIZE <= crypto::MAX_HASH_OUTPUT_SIZE) };
650
651 let suite_id = kem_suite_id(kem_id);
652 let mut pseudorandom_key = K::labeled_extract(b"", &suite_id, b"eae_prk", diffie_hellman);
653
654 let mut shared_secret_bytes = [0u8; crypto::MAX_HASH_OUTPUT_SIZE];
655 K::labeled_expand(
656 &mut shared_secret_bytes[..K::OUTPUT_SIZE],
657 &pseudorandom_key,
658 &suite_id,
659 b"shared_secret",
660 kem_context,
661 )?;
662 let shared_secret =
663 Hash::try_from(&shared_secret_bytes[..K::OUTPUT_SIZE]).expect("SHARED_SECRET_SIZE fits in a Hash");
664
665 wipe(&mut shared_secret_bytes);
666 wipe(pseudorandom_key.as_mut());
667 return Ok(shared_secret);
668}
669
670fn diffie_hellman_kem_derive_keypair<G: DiffieHellmanGroup, K: Kdf>(
672 kem_id: u16,
673 input_keying_material: &[u8],
674) -> Result<(G::SecretKey, G::PublicKey), HpkeError> {
675 const { assert!(G::SECRET_KEY_SIZE <= MAX_DIFFIE_HELLMAN_OUTPUT_SIZE && G::PUBLIC_KEY_SIZE <= MAX_PUBLIC_KEY_SIZE) };
676
677 let suite_id = kem_suite_id(kem_id);
678 let mut derive_key_pair_pseudorandom_key = K::labeled_extract(b"", &suite_id, b"dkp_prk", input_keying_material);
679
680 if G::REJECTION_SAMPLING {
681 let mut candidate = [0u8; MAX_DIFFIE_HELLMAN_OUTPUT_SIZE];
682 for counter in 0..=255u8 {
683 K::labeled_expand(
684 &mut candidate[..G::SECRET_KEY_SIZE],
685 &derive_key_pair_pseudorandom_key,
686 &suite_id,
687 b"candidate",
688 &[counter],
689 )?;
690 candidate[0] &= G::BITMASK;
691
692 if let Ok(secret_key) = G::scalar_from_candidate(&candidate[..G::SECRET_KEY_SIZE]) {
693 let public_key = G::derive_public_key(&secret_key);
694 wipe(&mut candidate);
695 wipe(derive_key_pair_pseudorandom_key.as_mut());
696 return Ok((secret_key, public_key));
697 }
698 }
699 wipe(&mut candidate);
700 wipe(derive_key_pair_pseudorandom_key.as_mut());
701 return Err(HpkeError::DeriveKeyPairError);
702 }
703
704 let mut secret_key_bytes = [0u8; MAX_DIFFIE_HELLMAN_OUTPUT_SIZE];
705 K::labeled_expand(
706 &mut secret_key_bytes[..G::SECRET_KEY_SIZE],
707 &derive_key_pair_pseudorandom_key,
708 &suite_id,
709 b"sk",
710 b"",
711 )?;
712 let secret_key =
713 G::scalar_from_candidate(&secret_key_bytes[..G::SECRET_KEY_SIZE]).map_err(|_| HpkeError::DeriveKeyPairError)?;
714 let public_key = G::derive_public_key(&secret_key);
715 wipe(&mut secret_key_bytes);
716 wipe(derive_key_pair_pseudorandom_key.as_mut());
717 return Ok((secret_key, public_key));
718}
719
720fn diffie_hellman_kem_encap_with_ephemeral<G: DiffieHellmanGroup, K: Kdf>(
722 kem_id: u16,
723 ephemeral_secret_key: &G::SecretKey,
724 recipient_public_key: &G::PublicKey,
725) -> Result<(Hash, G::PublicKey), HpkeError> {
726 const { assert!(G::SECRET_KEY_SIZE <= MAX_DIFFIE_HELLMAN_OUTPUT_SIZE && G::PUBLIC_KEY_SIZE <= MAX_PUBLIC_KEY_SIZE) };
727
728 let mut diffie_hellman = [0u8; MAX_DIFFIE_HELLMAN_OUTPUT_SIZE];
729 G::diffie_hellman(
730 ephemeral_secret_key,
731 recipient_public_key,
732 &mut diffie_hellman[..G::DIFFIE_HELLMAN_OUTPUT_SIZE],
733 )
734 .map_err(|_| HpkeError::EncapError)?;
735
736 let ephemeral_public_key = G::derive_public_key(ephemeral_secret_key);
737 let mut kem_context = [0u8; MAX_KEM_CONTEXT];
738 G::serialize_public_key(&mut kem_context[..G::PUBLIC_KEY_SIZE], &ephemeral_public_key)?;
739 G::serialize_public_key(
740 &mut kem_context[G::PUBLIC_KEY_SIZE..2 * G::PUBLIC_KEY_SIZE],
741 recipient_public_key,
742 )?;
743
744 let shared_secret = extract_and_expand::<K>(
745 kem_id,
746 &diffie_hellman[..G::DIFFIE_HELLMAN_OUTPUT_SIZE],
747 &kem_context[..2 * G::PUBLIC_KEY_SIZE],
748 )?;
749 wipe(&mut diffie_hellman);
750 return Ok((shared_secret, ephemeral_public_key));
751}
752
753fn diffie_hellman_kem_decap<G: DiffieHellmanGroup, K: Kdf>(
755 kem_id: u16,
756 encapped_key: &G::PublicKey,
757 recipient_secret_key: &G::SecretKey,
758) -> Result<Hash, HpkeError> {
759 const { assert!(G::SECRET_KEY_SIZE <= MAX_DIFFIE_HELLMAN_OUTPUT_SIZE && G::PUBLIC_KEY_SIZE <= MAX_PUBLIC_KEY_SIZE) };
760
761 let mut diffie_hellman = [0u8; MAX_DIFFIE_HELLMAN_OUTPUT_SIZE];
762 G::diffie_hellman(
763 recipient_secret_key,
764 encapped_key,
765 &mut diffie_hellman[..G::DIFFIE_HELLMAN_OUTPUT_SIZE],
766 )
767 .map_err(|_| HpkeError::DecapError)?;
768
769 let recipient_public_key = G::derive_public_key(recipient_secret_key);
770 let mut kem_context = [0u8; MAX_KEM_CONTEXT];
771 G::serialize_public_key(&mut kem_context[..G::PUBLIC_KEY_SIZE], encapped_key)?;
772 G::serialize_public_key(
773 &mut kem_context[G::PUBLIC_KEY_SIZE..2 * G::PUBLIC_KEY_SIZE],
774 &recipient_public_key,
775 )?;
776
777 let shared_secret = extract_and_expand::<K>(
778 kem_id,
779 &diffie_hellman[..G::DIFFIE_HELLMAN_OUTPUT_SIZE],
780 &kem_context[..2 * G::PUBLIC_KEY_SIZE],
781 )?;
782 wipe(&mut diffie_hellman);
783 return Ok(shared_secret);
784}
785
786macro_rules! diffie_hellman_kem {
789 (
790 $(#[$meta:meta])*
791 $name:ident, $group:ty, $kdf:ty, $id:literal, $secret_key:ty, $public_key:ty
792 ) => {
793 $(#[$meta])*
794 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
795 pub struct $name;
796
797 impl Kem for $name {
798 const HPKE_KEM_ID: u16 = $id;
799 const SHARED_SECRET_SIZE: usize = <$kdf as Kdf>::OUTPUT_SIZE;
800 const ENCAPPED_KEY_SIZE: usize = <$group as DiffieHellmanGroup>::PUBLIC_KEY_SIZE;
801 const PUBLIC_KEY_SIZE: usize = <$group as DiffieHellmanGroup>::PUBLIC_KEY_SIZE;
802 const SECRET_KEY_SIZE: usize = <$group as DiffieHellmanGroup>::SECRET_KEY_SIZE;
803
804 type PublicKey = $public_key;
805 type SecretKey = $secret_key;
806 type EncappedKey = $public_key;
807
808 fn derive_keypair(input_keying_material: &[u8]) -> Result<(Self::SecretKey, Self::PublicKey), HpkeError> {
809 return diffie_hellman_kem_derive_keypair::<$group, $kdf>($id, input_keying_material);
810 }
811
812 fn derive_public_key(secret_key: &Self::SecretKey) -> Self::PublicKey {
813 return <$group as DiffieHellmanGroup>::derive_public_key(secret_key);
814 }
815
816 fn public_key_to_bytes(out: &mut [u8], public_key: &Self::PublicKey) -> Result<(), HpkeError> {
817 return <$group as DiffieHellmanGroup>::serialize_public_key(out, public_key);
818 }
819
820 fn public_key_from_bytes(bytes: &[u8]) -> Result<Self::PublicKey, HpkeError> {
821 return <$group as DiffieHellmanGroup>::deserialize_public_key(bytes);
822 }
823
824 fn secret_key_to_bytes(out: &mut [u8], secret_key: &Self::SecretKey) -> Result<(), HpkeError> {
825 return <$group as DiffieHellmanGroup>::serialize_secret_key(out, secret_key);
826 }
827
828 fn secret_key_from_bytes(bytes: &[u8]) -> Result<Self::SecretKey, HpkeError> {
829 return <$group as DiffieHellmanGroup>::deserialize_secret_key(bytes);
830 }
831
832 fn encapped_key_to_bytes(out: &mut [u8], encapped_key: &Self::EncappedKey) -> Result<(), HpkeError> {
833 return <$group as DiffieHellmanGroup>::serialize_public_key(out, encapped_key);
834 }
835
836 fn encapped_key_from_bytes(bytes: &[u8]) -> Result<Self::EncappedKey, HpkeError> {
837 return <$group as DiffieHellmanGroup>::deserialize_public_key(bytes);
838 }
839
840 fn encap_with_ephemeral(
841 ephemeral_secret_key: &Self::SecretKey,
842 recipient_public_key: &Self::PublicKey,
843 ) -> Result<(Hash, Self::EncappedKey), HpkeError> {
844 return diffie_hellman_kem_encap_with_ephemeral::<$group, $kdf>($id, ephemeral_secret_key, recipient_public_key);
845 }
846
847 fn decap(encapped_key: &Self::EncappedKey, recipient_secret_key: &Self::SecretKey) -> Result<Hash, HpkeError> {
848 return diffie_hellman_kem_decap::<$group, $kdf>($id, encapped_key, recipient_secret_key);
849 }
850 }
851 };
852}
853
854diffie_hellman_kem!(
855 X25519HkdfSha256,
861 X25519Group,
862 HkdfSha256,
863 0x0020,
864 x25519::SecretKey,
865 x25519::PublicKey
866);
867
868diffie_hellman_kem!(
869 P256HkdfSha256,
875 P256Group,
876 HkdfSha256,
877 0x0010,
878 p256::SecretKey,
879 p256::PublicKey
880);
881
882diffie_hellman_kem!(
883 P521HkdfSha512,
889 P521Group,
890 HkdfSha512,
891 0x0012,
892 p521::SecretKey,
893 p521::PublicKey
894);