1use crate::aux_functions::sample_poly_CBD;
4use crate::low_memory_helpers::{
5 compress_u_row, compute_A_hat_dot_y_hat, compute_t_hat_dot_y_hat_row, unpack_ciphertext_u_row,
6 unpack_ciphertext_v, unpack_t_hat_row,
7};
8use crate::mlkem_keys::{
9 MLKEM512PrivateKey, MLKEM512PublicKey, MLKEM768PrivateKey, MLKEM768PublicKey,
10 MLKEM1024PrivateKey, MLKEM1024PublicKey,
11};
12use crate::mlkem_keys::{MLKEMPrivateKeyInternalTrait, MLKEMPrivateKeyTrait};
13use crate::mlkem_keys::{MLKEMPublicKeyInternalTrait, MLKEMPublicKeyTrait};
14use crate::polynomial::Polynomial;
15use bouncycastle_core::errors::{KEMError, RNGError};
16use bouncycastle_core::key_material::{
17 KeyMaterial, KeyMaterialTrait, KeyType, do_hazardous_operations,
18};
19use bouncycastle_core::traits::{
20 Algorithm, AlgorithmOID, Hash, KEMDecapsulator, KEMEncapsulator, RNG, SecurityStrength, XOF,
21};
22use bouncycastle_rng::HashDRBG_SHA512;
23use bouncycastle_sha3::{SHA3_256, SHA3_512, SHAKE256};
24use bouncycastle_utils::ct::{conditional_copy_bytes, ct_eq_bytes};
25use bouncycastle_utils::secret::Secret;
26use core::marker::PhantomData;
27pub const ML_KEM_512_NAME: &str = "ML-KEM-512";
31pub const ML_KEM_768_NAME: &str = "ML-KEM-768";
33pub const ML_KEM_1024_NAME: &str = "ML-KEM-1024";
35
36pub const MLKEM_SEED_LEN: usize = 64;
41pub const MLKEM_RND_LEN: usize = 32;
43pub const MLKEM_SS_LEN: usize = 32;
45pub(crate) const N: usize = 256;
46pub(crate) const q: i16 = 3329;
47pub(crate) const q_inv: i32 = 62209;
48pub(crate) const ETA2: i16 = 2;
49pub(crate) const POLY_BYTES: usize = 384;
50
51pub const MLKEM512_PK_LEN: usize = 800;
55pub const MLKEM512_SK_LEN: usize = MLKEM_SEED_LEN;
57pub const MLKEM512_FULL_SK_LEN: usize = 1632;
59pub const MLKEM512_CT_LEN: usize = 768;
61pub(crate) const MLKEM512_k: usize = 2;
62pub(crate) const MLKEM512_ETA1: i16 = 3;
63pub(crate) const MLKEM512_DU: i16 = 10;
64pub(crate) const MLKEM512_DV: i16 = 4;
65pub(crate) const MLKEM512_LAMBDA: i16 = 128;
67
68pub(crate) const MLKEM512_T_PACKED_LEN: usize = 12 * MLKEM512_k * 32;
70
71pub const MLKEM768_PK_LEN: usize = 1184;
75pub const MLKEM768_SK_LEN: usize = MLKEM_SEED_LEN;
77pub const MLKEM768_FULL_SK_LEN: usize = 2400;
79pub const MLKEM768_CT_LEN: usize = 1088;
81pub(crate) const MLKEM768_k: usize = 3;
82pub(crate) const MLKEM768_ETA1: i16 = 2;
83pub(crate) const MLKEM768_DU: i16 = 10;
84pub(crate) const MLKEM768_DV: i16 = 4;
85pub(crate) const MLKEM768_LAMBDA: i16 = 192;
87
88pub(crate) const MLKEM768_T_PACKED_LEN: usize = 12 * MLKEM768_k * 32;
90
91pub const MLKEM1024_PK_LEN: usize = 1568;
95pub const MLKEM1024_SK_LEN: usize = MLKEM_SEED_LEN;
97pub const MLKEM1024_FULL_SK_LEN: usize = 3168;
99pub const MLKEM1024_CT_LEN: usize = 1568;
101pub(crate) const MLKEM1024_k: usize = 4;
102pub(crate) const MLKEM1024_ETA1: i16 = 2;
103pub(crate) const MLKEM1024_DU: i16 = 11;
104pub(crate) const MLKEM1024_DV: i16 = 5;
105pub(crate) const MLKEM1024_LAMBDA: i16 = 256;
107
108pub(crate) const MLKEM1024_T_PACKED_LEN: usize = 12 * MLKEM1024_k * 32;
110
111pub(crate) type G = SHA3_512;
113pub(crate) type H = SHA3_256;
114pub(crate) type J = SHAKE256;
115
116pub type MLKEM512 = MLKEM<
120 MLKEM512_PK_LEN,
121 MLKEM512_SK_LEN,
122 MLKEM512_FULL_SK_LEN,
123 MLKEM512_CT_LEN,
124 MLKEM_SS_LEN,
125 MLKEM512PublicKey,
126 MLKEM512PrivateKey,
127 MLKEM512_k,
128 MLKEM512_ETA1,
129 MLKEM512_DU,
130 MLKEM512_DV,
131 MLKEM512_LAMBDA,
132 MLKEM512_T_PACKED_LEN,
133>;
134
135impl Algorithm for MLKEM512 {
136 const ALG_NAME: &'static str = ML_KEM_512_NAME;
137 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_128bit;
138}
139impl AlgorithmOID for MLKEM512 {
141 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 4, 1];
142 const OID_DER: &'static [u8] =
143 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x01];
144}
145
146pub type MLKEM768 = MLKEM<
148 MLKEM768_PK_LEN,
149 MLKEM768_SK_LEN,
150 MLKEM768_FULL_SK_LEN,
151 MLKEM768_CT_LEN,
152 MLKEM_SS_LEN,
153 MLKEM768PublicKey,
154 MLKEM768PrivateKey,
155 MLKEM768_k,
156 MLKEM768_ETA1,
157 MLKEM768_DU,
158 MLKEM768_DV,
159 MLKEM768_LAMBDA,
160 MLKEM768_T_PACKED_LEN,
161>;
162
163impl Algorithm for MLKEM768 {
164 const ALG_NAME: &'static str = ML_KEM_768_NAME;
165 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_192bit;
166}
167impl AlgorithmOID for MLKEM768 {
169 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 4, 2];
170 const OID_DER: &'static [u8] =
171 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x02];
172}
173
174pub type MLKEM1024 = MLKEM<
176 MLKEM1024_PK_LEN,
177 MLKEM1024_SK_LEN,
178 MLKEM1024_FULL_SK_LEN,
179 MLKEM1024_CT_LEN,
180 MLKEM_SS_LEN,
181 MLKEM1024PublicKey,
182 MLKEM1024PrivateKey,
183 MLKEM1024_k,
184 MLKEM1024_ETA1,
185 MLKEM1024_DU,
186 MLKEM1024_DV,
187 MLKEM1024_LAMBDA,
188 MLKEM1024_T_PACKED_LEN,
189>;
190
191impl Algorithm for MLKEM1024 {
192 const ALG_NAME: &'static str = ML_KEM_1024_NAME;
193 const MAX_SECURITY_STRENGTH: SecurityStrength = SecurityStrength::_256bit;
194}
195impl AlgorithmOID for MLKEM1024 {
197 const OID: &'static [u32] = &[2, 16, 840, 1, 101, 3, 4, 4, 3];
198 const OID_DER: &'static [u8] =
199 &[0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x04, 0x03];
200}
201
202pub struct MLKEM<
207 const PK_LEN: usize,
208 const SK_LEN: usize,
209 const FULL_SK_LEN: usize,
210 const CT_LEN: usize,
211 const SS_LEN: usize,
212 PK: MLKEMPublicKeyTrait<k, PK_LEN, T_PACKED_LEN>
213 + MLKEMPublicKeyInternalTrait<k, T_PACKED_LEN, PK_LEN>,
214 SK: MLKEMPrivateKeyTrait<k, SK_LEN, FULL_SK_LEN, PK_LEN, T_PACKED_LEN>
215 + MLKEMPrivateKeyInternalTrait<k, SK_LEN, PK_LEN, T_PACKED_LEN>,
216 const k: usize,
217 const eta1: i16,
218 const du: i16,
219 const dv: i16,
220 const LAMBDA: i16,
221 const T_PACKED_LEN: usize,
222> {
223 _phantom: PhantomData<(PK, SK)>,
224}
225
226impl<
227 const PK_LEN: usize,
228 const SK_LEN: usize,
229 const FULL_SK_LEN: usize,
230 const CT_LEN: usize,
231 const SS_LEN: usize,
232 PK: MLKEMPublicKeyTrait<k, PK_LEN, T_PACKED_LEN>
233 + MLKEMPublicKeyInternalTrait<k, T_PACKED_LEN, PK_LEN>,
234 SK: MLKEMPrivateKeyTrait<k, SK_LEN, FULL_SK_LEN, PK_LEN, T_PACKED_LEN>
235 + MLKEMPrivateKeyInternalTrait<k, SK_LEN, PK_LEN, T_PACKED_LEN>,
236 const k: usize,
237 const eta1: i16,
238 const du: i16,
239 const dv: i16,
240 const LAMBDA: i16,
241 const T_PACKED_LEN: usize,
242>
243 MLKEM<
244 PK_LEN,
245 SK_LEN,
246 FULL_SK_LEN,
247 CT_LEN,
248 SS_LEN,
249 PK,
250 SK,
251 k,
252 eta1,
253 du,
254 dv,
255 LAMBDA,
256 T_PACKED_LEN,
257 >
258{
259 pub(crate) fn keygen_internal(seed: &KeyMaterial<64>) -> Result<(PK, SK), KEMError> {
268 let sk = SK::from_keymaterial(seed)?;
269 let pk = sk.pk();
270 let pk = PK::new(pk.t_hat_packed, pk.rho); Ok((pk, sk))
272 }
273
274 fn pke_encrypt(
281 t_hat_packed: &[u8; T_PACKED_LEN],
282 rho: &[u8; 32],
283 m: [u8; 32],
284 r: &[u8; 32],
285 ) -> [u8; CT_LEN] {
286 let mut ct = [0u8; CT_LEN];
287
288 for i in 0..k {
301 let mut u_i = compute_A_hat_dot_y_hat::<k, eta1>(rho, &r, i);
302
303 let e1_i = sample_poly_CBD::<ETA2>(&r, (k + i) as u8);
304 u_i.add(&e1_i);
305 u_i.poly_reduce();
306
307 compress_u_row::<du, CT_LEN>(u_i, i, &mut ct);
308 }
309
310 {
315 let mut v = compute_t_hat_dot_y_hat_row::<k, eta1>(
317 &r,
318 &unpack_t_hat_row(t_hat_packed, 0),
319 0,
320 );
321
322 for i in 1..k {
323 let v_i = compute_t_hat_dot_y_hat_row::<k, eta1>(
324 &r,
325 &unpack_t_hat_row(t_hat_packed, i),
326 i,
327 );
328 v.add(&v_i);
329 }
330
331 let e2 = sample_poly_CBD::<ETA2>(&r, 2 * k as u8);
333 v.add(&e2);
334
335 let mu = Polynomial::from_msg(m);
336 v.add(&mu);
337
338 v.poly_reduce();
339
340 v.compress_poly::<dv>(&mut ct[CT_LEN - (N * (dv as usize) / 8)..]);
341 }
342
343 ct
344 }
345
346 pub fn encaps_internal(ek: &PK, m: [u8; 32]) -> ([u8; 32], [u8; CT_LEN]) {
370 debug_assert_eq!(CT_LEN, 32 * ((du as usize) * k + (dv as usize)));
371
372 let K: [u8; MLKEM_SS_LEN];
375 let r: [u8; 32];
376 (K, r) = {
377 let mut g = G::new();
378 g.do_update(&m);
379 g.do_update(&ek.compute_hash());
380 let mut buf = [0u8; 64];
381 let bytes_written = g.do_final_out(&mut buf);
382 debug_assert_eq!(bytes_written, 64);
383
384 (buf[..32].try_into().unwrap(), buf[32..64].try_into().unwrap())
385 };
386
387 let ct = Self::pke_encrypt(ek.t_hat_packed(), ek.rho(), m, &r);
391
392 (K, ct)
393 }
394
395 fn pke_decrypt(dk: &SK, ct: [u8; CT_LEN]) -> [u8; 32] {
401 let v1 = {
410 let mut v1 = {
412 let mut s_hat_i = dk.compute_s_hat_row(0);
413 {
414 let mut u_prime_i = unpack_ciphertext_u_row::<du, CT_LEN>(0, &ct);
415 u_prime_i.ntt();
416 s_hat_i.base_mult_montgomery(&u_prime_i);
417 }
418 s_hat_i.inv_ntt();
419
420 s_hat_i
421 };
422
423 for i in 1..k {
424 let mut s_hat_i = dk.compute_s_hat_row(i);
425 {
426 let mut u_prime_i = unpack_ciphertext_u_row::<du, CT_LEN>(i, &ct);
427 u_prime_i.ntt();
428 s_hat_i.base_mult_montgomery(&u_prime_i);
429 }
430 s_hat_i.inv_ntt();
431 v1.add(&s_hat_i);
432 }
433
434 v1
435 };
436
437 let w = {
440 let mut v_prime = unpack_ciphertext_v::<k, CT_LEN, du, dv>(&ct);
443
444 v_prime.sub(&v1);
445 v_prime.poly_reduce();
446
447 v_prime };
449
450 w.to_msg()
453 }
454
455 fn decaps_internal(dk: &SK, c: [u8; CT_LEN]) -> [u8; MLKEM_SS_LEN] {
461 let m_prime = Self::pke_decrypt(&dk, c);
473
474 let K_prime: Secret<[u8; MLKEM_SS_LEN]>;
477 let r_prime: [u8; 32];
478 (K_prime, r_prime) = {
479 let mut buf: Secret<[u8; 64]> = Secret::new();
480 let mut g = G::new();
481 g.do_update(&m_prime);
482 g.do_update(&dk.pk().compute_hash());
483 let bytes_written = g.do_final_out(&mut *buf);
484 debug_assert_eq!(bytes_written, 64);
485
486 let mut K_prime: Secret<[u8; MLKEM_SS_LEN]> = Secret::new();
487 K_prime.copy_from_slice(&buf[..32]);
488 (K_prime, buf[32..64].try_into().unwrap())
489 };
490
491 let K_bar: Secret<[u8; MLKEM_SS_LEN]>;
498 K_bar = {
499 let mut K_bar: Secret<[u8; MLKEM_SS_LEN]> = Secret::new();
500 let mut j = J::new();
501 j.absorb(dk.z()).expect("absorb before squeeze is infallible");
502 j.absorb(&c).expect("absorb before squeeze is infallible");
503 let bytes_written = j.squeeze_out(&mut *K_bar);
504 debug_assert_eq!(bytes_written, MLKEM_SS_LEN);
505
506 K_bar
507 };
508
509 let c_prime = Self::pke_encrypt(&dk.t_hat_packed(), dk.rho(), m_prime, &r_prime);
512
513 let mut K_out = [0u8; MLKEM_SS_LEN];
517 conditional_copy_bytes(&K_prime, &K_bar, &mut K_out, ct_eq_bytes(&c, &c_prime));
518
519 K_out
520 }
521
522 pub fn decaps_from_seed(
525 seed: &KeyMaterial<64>,
526 ct: &[u8],
527 ) -> Result<KeyMaterial<SS_LEN>, KEMError> {
528 let sk = SK::from_keymaterial(seed)?;
529
530 Self::decaps(&sk, ct)
531 }
532}
533
534impl<
535 const PK_LEN: usize,
536 const SK_LEN: usize,
537 const FULL_SK_LEN: usize,
538 const CT_LEN: usize,
539 const SS_LEN: usize,
540 PK: MLKEMPublicKeyTrait<k, PK_LEN, T_PACKED_LEN>
541 + MLKEMPublicKeyInternalTrait<k, T_PACKED_LEN, PK_LEN>,
542 SK: MLKEMPrivateKeyTrait<k, SK_LEN, FULL_SK_LEN, PK_LEN, T_PACKED_LEN>
543 + MLKEMPrivateKeyInternalTrait<k, SK_LEN, PK_LEN, T_PACKED_LEN>,
544 const k: usize,
545 const eta1: i16,
546 const du: i16,
547 const dv: i16,
548 const LAMBDA: i16,
549 const T_PACKED_LEN: usize,
550>
551 MLKEMTrait<
552 PK_LEN,
553 SK_LEN,
554 FULL_SK_LEN,
555 CT_LEN,
556 SS_LEN,
557 PK,
558 SK,
559 k,
560 eta1,
561 du,
562 dv,
563 LAMBDA,
564 T_PACKED_LEN,
565 >
566 for MLKEM<
567 PK_LEN,
568 SK_LEN,
569 FULL_SK_LEN,
570 CT_LEN,
571 SS_LEN,
572 PK,
573 SK,
574 k,
575 eta1,
576 du,
577 dv,
578 LAMBDA,
579 T_PACKED_LEN,
580 >
581{
582 fn keygen_from_seed(seed: &KeyMaterial<64>) -> Result<(PK, SK), KEMError> {
584 Self::keygen_internal(seed)
585 }
586 fn keygen_from_seed_and_encoded(
593 seed: &KeyMaterial<64>,
594 encoded_sk: &[u8; SK_LEN],
595 ) -> Result<(PK, SK), KEMError> {
596 let (pk, sk) = Self::keygen_internal(seed)?;
597
598 let sk_from_bytes = SK::sk_decode(encoded_sk);
599
600 if sk != sk_from_bytes {
602 return Err(KEMError::KeyGenError("Encoded key does not match generated key"));
603 }
604
605 Ok((pk, sk))
606 }
607 fn keypair_consistency_check(pk: &PK, sk: &SK) -> Result<(), KEMError> {
616 let derived_pk = sk.pk();
617 if derived_pk.compute_hash() == pk.compute_hash() {
618 Ok(())
619 } else {
620 Err(KEMError::ConsistencyCheckFailed(""))
621 }
622 }
623}
624
625pub trait MLKEMTrait<
627 const PK_LEN: usize,
628 const SK_LEN: usize,
629 const FULL_SK_LEN: usize,
630 const CT_LEN: usize,
631 const SS_LEN: usize,
632 PK: MLKEMPublicKeyTrait<k, PK_LEN, T_PACKED_LEN>
633 + MLKEMPublicKeyInternalTrait<k, T_PACKED_LEN, PK_LEN>,
634 SK: MLKEMPrivateKeyTrait<k, SK_LEN, FULL_SK_LEN, PK_LEN, T_PACKED_LEN>
635 + MLKEMPrivateKeyInternalTrait<k, SK_LEN, PK_LEN, T_PACKED_LEN>,
636 const k: usize,
637 const eta: i16,
638 const du: i16,
639 const dv: i16,
640 const LAMBDA: i16,
641 const T_PACKED_LEN: usize,
642>: Sized
643{
644 fn keygen() -> Result<(PK, SK), KEMError> {
646 let mut os_rng = HashDRBG_SHA512::new_from_os();
647 Self::keygen_from_rng(&mut os_rng)
648 }
649 fn keygen_from_rng(rng: &mut dyn RNG) -> Result<(PK, SK), KEMError> {
652 if rng.security_strength() < SecurityStrength::from_bits(LAMBDA as usize) {
654 return Err(RNGError::SecurityStrengthInsufficientForAlgorithm)?;
655 }
656 let mut seed = KeyMaterial::<64>::new();
657 rng.fill_keymaterial_out(&mut seed)?;
658 Self::keygen_from_seed(&seed)
659 }
660 fn keygen_from_seed(seed: &KeyMaterial<64>) -> Result<(PK, SK), KEMError>;
662 fn keygen_from_seed_and_encoded(
669 seed: &KeyMaterial<64>,
670 encoded_sk: &[u8; SK_LEN],
671 ) -> Result<(PK, SK), KEMError>;
672 fn keypair_consistency_check(pk: &PK, sk: &SK) -> Result<(), KEMError>;
681}
682
683impl<
684 const PK_LEN: usize,
685 const SK_LEN: usize,
686 const FULL_SK_LEN: usize,
687 const CT_LEN: usize,
688 const SS_LEN: usize,
689 PK: MLKEMPublicKeyTrait<k, PK_LEN, T_PACKED_LEN>
690 + MLKEMPublicKeyInternalTrait<k, T_PACKED_LEN, PK_LEN>,
691 SK: MLKEMPrivateKeyTrait<k, SK_LEN, FULL_SK_LEN, PK_LEN, T_PACKED_LEN>
692 + MLKEMPrivateKeyInternalTrait<k, SK_LEN, PK_LEN, T_PACKED_LEN>,
693 const k: usize,
694 const eta: i16,
695 const du: i16,
696 const dv: i16,
697 const LAMBDA: i16,
698 const T_PACKED_LEN: usize,
699> KEMEncapsulator<PK, PK_LEN, CT_LEN, SS_LEN>
700 for MLKEM<
701 PK_LEN,
702 SK_LEN,
703 FULL_SK_LEN,
704 CT_LEN,
705 SS_LEN,
706 PK,
707 SK,
708 k,
709 eta,
710 du,
711 dv,
712 LAMBDA,
713 T_PACKED_LEN,
714 >
715{
716 fn encaps(pk: &PK) -> Result<(KeyMaterial<SS_LEN>, [u8; CT_LEN]), KEMError> {
717 let mut os_rng = HashDRBG_SHA512::new_from_os();
718 Self::encaps_rng(pk, &mut os_rng)
719 }
720
721 fn encaps_rng(
722 pk: &PK,
723 rng: &mut dyn RNG,
724 ) -> Result<(KeyMaterial<SS_LEN>, [u8; CT_LEN]), KEMError> {
725 if rng.security_strength() < SecurityStrength::from_bits(LAMBDA as usize) {
727 return Err(RNGError::SecurityStrengthInsufficientForAlgorithm)?;
728 }
729 let mut m = [0u8; 32];
730 rng.next_bytes_out(&mut m)?;
731
732 let (ss_bytes, ct) = Self::encaps_internal(pk, m);
733
734 let mut ss_keymaterial =
735 KeyMaterial::<SS_LEN>::from_bytes_as_type(&ss_bytes, KeyType::CryptographicRandom)?;
736 do_hazardous_operations(&mut ss_keymaterial, |ss_keymaterial| {
737 ss_keymaterial.set_security_strength(SecurityStrength::from_bits(LAMBDA as usize))
738 })?;
739
740 Ok((ss_keymaterial, ct))
741 }
742}
743
744impl<
745 const PK_LEN: usize,
746 const SK_LEN: usize,
747 const FULL_SK_LEN: usize,
748 const CT_LEN: usize,
749 const SS_LEN: usize,
750 PK: MLKEMPublicKeyTrait<k, PK_LEN, T_PACKED_LEN>
751 + MLKEMPublicKeyInternalTrait<k, T_PACKED_LEN, PK_LEN>,
752 SK: MLKEMPrivateKeyTrait<k, SK_LEN, FULL_SK_LEN, PK_LEN, T_PACKED_LEN>
753 + MLKEMPrivateKeyInternalTrait<k, SK_LEN, PK_LEN, T_PACKED_LEN>,
754 const k: usize,
755 const eta: i16,
756 const du: i16,
757 const dv: i16,
758 const LAMBDA: i16,
759 const T_PACKED_LEN: usize,
760> KEMDecapsulator<SK, SK_LEN, CT_LEN, SS_LEN>
761 for MLKEM<
762 PK_LEN,
763 SK_LEN,
764 FULL_SK_LEN,
765 CT_LEN,
766 SS_LEN,
767 PK,
768 SK,
769 k,
770 eta,
771 du,
772 dv,
773 LAMBDA,
774 T_PACKED_LEN,
775 >
776{
777 fn decaps(sk: &SK, ct: &[u8]) -> Result<KeyMaterial<SS_LEN>, KEMError> {
783 if ct.len() != CT_LEN {
784 return Err(KEMError::LengthError("Invalid ciphertext length"));
785 }
786
787 let ss_bytes = Self::decaps_internal(sk, ct.try_into().unwrap());
788
789 let mut ss_keymaterial =
790 KeyMaterial::<SS_LEN>::from_bytes_as_type(&ss_bytes, KeyType::CryptographicRandom)?;
791 do_hazardous_operations(&mut ss_keymaterial, |ss_keymaterial| {
792 ss_keymaterial.set_security_strength(SecurityStrength::from_bits(LAMBDA as usize))
793 })?;
794
795 Ok(ss_keymaterial)
796 }
797}