1#![no_std]
124#![forbid(unsafe_code)]
125
126use core::fmt;
127use core::sync::atomic::{AtomicU8, Ordering};
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131#[repr(u8)]
132pub enum State {
133 PowerOff = 0,
135 SelfTest = 1,
138 Operational = 2,
141 Error = 3,
147}
148
149impl State {
150 const fn from_u8(raw: u8) -> Self {
151 match raw {
152 0 => Self::PowerOff,
153 1 => Self::SelfTest,
154 2 => Self::Operational,
155 _ => Self::Error,
161 }
162 }
163}
164
165impl fmt::Display for State {
166 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
167 let s = match self {
168 Self::PowerOff => "PowerOff",
169 Self::SelfTest => "SelfTest",
170 Self::Operational => "Operational",
171 Self::Error => "Error",
172 };
173 f.write_str(s)
174 }
175}
176
177static STATE: AtomicU8 = AtomicU8::new(State::PowerOff as u8);
180
181pub fn state() -> State {
183 State::from_u8(STATE.load(Ordering::Acquire))
184}
185
186pub fn is_operational() -> bool {
189 state() == State::Operational
190}
191
192pub fn require_operational() -> Result<(), Error> {
197 let current = state();
198 if current == State::Operational {
199 Ok(())
200 } else {
201 Err(Error::NotOperational { current })
202 }
203}
204
205#[derive(Debug, Clone, Copy, PartialEq, Eq)]
212pub enum Error {
213 NotOperational {
216 current: State,
218 },
219 SelfTestFailed {
222 test: &'static str,
225 },
226 ConditionalTestFailed {
229 reason: &'static str,
231 },
232 AlreadyInitialized,
238 InvalidInput,
246 AlgorithmRestricted {
252 service: Service,
254 },
255 NotImplemented,
262}
263
264impl fmt::Display for Error {
265 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266 match self {
267 Self::NotOperational { current } => {
268 write!(f, "FIPS module not operational (state = {current})")
269 }
270 Self::SelfTestFailed { test } => {
271 write!(f, "FIPS power-up self-test failed: {test}")
272 }
273 Self::ConditionalTestFailed { reason } => {
274 write!(f, "FIPS conditional self-test failed: {reason}")
275 }
276 Self::AlreadyInitialized => f.write_str("FIPS module already initialized"),
277 Self::InvalidInput => f.write_str("invalid input to FIPS service"),
278 Self::AlgorithmRestricted { service } => {
279 write!(
280 f,
281 "algorithm {service} is not permitted under the {} profile",
282 active_profile()
283 )
284 }
285 Self::NotImplemented => f.write_str("algorithm not yet implemented"),
286 }
287 }
288}
289
290#[derive(Debug, Clone, Copy, PartialEq, Eq)]
299pub struct SelfTestFailure;
300
301impl fmt::Display for SelfTestFailure {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 f.write_str("self-test failure")
304 }
305}
306
307pub trait SelfTest {
319 const NAME: &'static str;
322
323 fn run() -> Result<(), SelfTestFailure>;
327}
328
329#[derive(Debug, Clone, Copy)]
342pub struct KatEntry {
343 pub name: &'static str,
347 pub run: fn() -> Result<(), SelfTestFailure>,
349}
350
351pub fn initialize() -> Result<(), Error> {
360 initialize_with_tests(&[])
361}
362
363pub fn initialize_with_tests(tests: &[KatEntry]) -> Result<(), Error> {
382 let cas = STATE.compare_exchange(
385 State::PowerOff as u8,
386 State::SelfTest as u8,
387 Ordering::AcqRel,
388 Ordering::Acquire,
389 );
390 if cas.is_err() {
391 while STATE.load(Ordering::Acquire) == State::SelfTest as u8 {
396 core::hint::spin_loop();
397 }
398 return Err(Error::AlreadyInitialized);
399 }
400
401 for entry in tests {
402 let result = (entry.run)();
403 if result.is_err() {
404 STATE.store(State::Error as u8, Ordering::Release);
408 return Err(Error::SelfTestFailed { test: entry.name });
409 }
410 }
411
412 STATE.store(State::Operational as u8, Ordering::Release);
413 Ok(())
414}
415
416pub fn enter_error_state(_reason: &'static str) {
428 STATE.store(State::Error as u8, Ordering::Release);
429}
430
431#[derive(Debug, Clone, Copy, PartialEq, Eq)]
445#[repr(u8)]
446pub enum AlgorithmProfile {
447 Unrestricted = 0,
451 Cnsa2 = 1,
457 Cnsa1 = 2,
460}
461
462impl AlgorithmProfile {
463 const fn from_u8(raw: u8) -> Self {
464 match raw {
465 0 => Self::Unrestricted,
466 2 => Self::Cnsa1,
467 _ => Self::Cnsa2,
470 }
471 }
472}
473
474impl fmt::Display for AlgorithmProfile {
475 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
476 let s = match self {
477 Self::Unrestricted => "Unrestricted",
478 Self::Cnsa2 => "CNSA 2.0",
479 Self::Cnsa1 => "CNSA 1.0",
480 };
481 f.write_str(s)
482 }
483}
484
485static PROFILE: AtomicU8 = AtomicU8::new(AlgorithmProfile::Unrestricted as u8);
488
489pub fn active_profile() -> AlgorithmProfile {
491 AlgorithmProfile::from_u8(PROFILE.load(Ordering::Acquire))
492}
493
494pub fn initialize_with_profile(tests: &[KatEntry], profile: AlgorithmProfile) -> Result<(), Error> {
506 PROFILE.store(profile as u8, Ordering::Release);
510 initialize_with_tests(tests)
511}
512
513#[derive(Debug, Clone, Copy, PartialEq, Eq)]
524#[repr(u16)]
525#[allow(missing_docs)]
526pub enum Service {
527 Sha1 = 0,
529 Sha224 = 1,
530 Sha256 = 2,
531 Sha384 = 3,
532 Sha512 = 4,
533 Sha512_224 = 5,
534 Sha512_256 = 6,
535
536 Sha3_224 = 10,
537 Sha3_256 = 11,
538 Sha3_384 = 12,
539 Sha3_512 = 13,
540
541 Shake128 = 20,
543 Shake256 = 21,
544 CShake128 = 22,
545 CShake256 = 23,
546 Kmac128 = 24,
547 Kmac256 = 25,
548 KmacXof128 = 26,
549 KmacXof256 = 27,
550 TupleHash128 = 28,
551 TupleHash256 = 29,
552 TupleHashXof128 = 30,
553 TupleHashXof256 = 31,
554 ParallelHash128 = 32,
555 ParallelHash256 = 33,
556 ParallelHashXof128 = 34,
557 ParallelHashXof256 = 35,
558
559 HmacSha1 = 40,
561 HmacSha224 = 41,
562 HmacSha256 = 42,
563 HmacSha384 = 43,
564 HmacSha512 = 44,
565 HmacSha512_224 = 45,
566 HmacSha512_256 = 46,
567 HmacSha3_224 = 47,
568 HmacSha3_256 = 48,
569 HmacSha3_384 = 49,
570 HmacSha3_512 = 50,
571
572 CmacAes128 = 60,
574 CmacAes192 = 61,
575 CmacAes256 = 62,
576
577 Aes128Ecb = 70,
579 Aes128Cbc = 71,
580 Aes128Ctr = 72,
581 Aes128Gcm = 73,
582 Aes128Ccm = 74,
583 Aes128Kw = 75,
584 Aes128Kwp = 76,
585 Aes192Ecb = 80,
586 Aes192Cbc = 81,
587 Aes192Ctr = 82,
588 Aes192Gcm = 83,
589 Aes192Ccm = 84,
590 Aes192Kw = 85,
591 Aes192Kwp = 86,
592 Aes256Ecb = 90,
593 Aes256Cbc = 91,
594 Aes256Ctr = 92,
595 Aes256Gcm = 93,
596 Aes256Ccm = 94,
597 Aes256Kw = 95,
598 Aes256Kwp = 96,
599
600 Aes128 = 97,
607 Aes192 = 98,
609 Aes256 = 99,
611
612 CtrDrbgAes128 = 100,
614 CtrDrbgAes192 = 101,
615 CtrDrbgAes256 = 102,
616 HashDrbgSha256 = 103,
617 HashDrbgSha384 = 104,
618 HashDrbgSha512 = 105,
619 HmacDrbgSha256 = 106,
620 HmacDrbgSha384 = 107,
621 HmacDrbgSha512 = 108,
622
623 HkdfSha1 = 120,
625 HkdfSha256 = 121,
626 HkdfSha384 = 122,
627 HkdfSha512 = 123,
628 KbkdfHmacSha256 = 130,
629 KbkdfHmacSha384 = 131,
630 KbkdfHmacSha512 = 132,
631 KbkdfCmacAes128 = 133,
632 KbkdfCmacAes192 = 134,
633 KbkdfCmacAes256 = 135,
634 Pbkdf2HmacSha1 = 140,
635 Pbkdf2HmacSha224 = 141,
636 Pbkdf2HmacSha256 = 142,
637 Pbkdf2HmacSha384 = 143,
638 Pbkdf2HmacSha512 = 144,
639
640 RsaKeygen2048 = 150,
642 RsaPkcs1v15Sign2048 = 151,
643 RsaPssSign2048 = 152,
644 RsaOaep2048 = 153,
645 RsaPkcs1v15Verify2048 = 154,
646 RsaPssVerify2048 = 155,
647 RsaKeygen3072 = 160,
648 RsaPkcs1v15Sign3072 = 161,
649 RsaPssSign3072 = 162,
650 RsaOaep3072 = 163,
651 RsaPkcs1v15Verify3072 = 164,
652 RsaPssVerify3072 = 165,
653 RsaKeygen4096 = 170,
654 RsaPkcs1v15Sign4096 = 171,
655 RsaPssSign4096 = 172,
656 RsaOaep4096 = 173,
657 RsaPkcs1v15Verify4096 = 174,
658 RsaPssVerify4096 = 175,
659
660 EcdsaP256Sign = 200,
662 EcdsaP256Verify = 201,
663 EcdsaP256Keygen = 202,
664 EcdsaP384Sign = 210,
665 EcdsaP384Verify = 211,
666 EcdsaP384Keygen = 212,
667
668 EcdhP256 = 220,
670 EcdhP384 = 221,
671
672 Ed25519Sign = 230,
674 Ed25519Verify = 231,
675 Ed25519Keygen = 232,
676
677 Tls12Kdf = 240,
679 Tls13Kdf = 241,
680
681 MlKem1024Encaps = 300,
683 MlKem1024Decaps = 301,
684 MlKem1024Keygen = 302,
685 MlKem512Encaps = 303,
686 MlKem512Decaps = 304,
687 MlKem512Keygen = 305,
688 MlKem768Encaps = 306,
689 MlKem768Decaps = 307,
690 MlKem768Keygen = 308,
691
692 MlDsa87Sign = 310,
694 MlDsa87Verify = 311,
695 MlDsa87Keygen = 312,
696 MlDsa44Sign = 313,
697 MlDsa44Verify = 314,
698 MlDsa44Keygen = 315,
699 MlDsa65Sign = 316,
700 MlDsa65Verify = 317,
701 MlDsa65Keygen = 318,
702
703 SlhDsaSha2256sKeygen = 320,
708 SlhDsaSha2256sSign = 321,
709 SlhDsaSha2256sVerify = 322,
710 SlhDsaSha2128sKeygen = 323,
711 SlhDsaSha2128sSign = 324,
712 SlhDsaSha2128sVerify = 325,
713 SlhDsaSha2128fKeygen = 326,
714 SlhDsaSha2128fSign = 327,
715 SlhDsaSha2128fVerify = 328,
716 SlhDsaSha2192sKeygen = 329,
717 SlhDsaSha2192sSign = 330,
718 SlhDsaSha2192sVerify = 331,
719 SlhDsaSha2192fKeygen = 332,
720 SlhDsaSha2192fSign = 333,
721 SlhDsaSha2192fVerify = 334,
722 SlhDsaSha2256fKeygen = 335,
723 SlhDsaSha2256fSign = 336,
724 SlhDsaSha2256fVerify = 337,
725 SlhDsaShake128sKeygen = 338,
726 SlhDsaShake128sSign = 339,
727 SlhDsaShake128sVerify = 340,
728 SlhDsaShake128fKeygen = 341,
729 SlhDsaShake128fSign = 342,
730 SlhDsaShake128fVerify = 343,
731 SlhDsaShake192sKeygen = 344,
732 SlhDsaShake192sSign = 345,
733 SlhDsaShake192sVerify = 346,
734 SlhDsaShake192fKeygen = 347,
735 SlhDsaShake192fSign = 348,
736 SlhDsaShake192fVerify = 349,
737 SlhDsaShake256sKeygen = 350,
738 SlhDsaShake256sSign = 351,
739 SlhDsaShake256sVerify = 352,
740 SlhDsaShake256fKeygen = 353,
741 SlhDsaShake256fSign = 354,
742 SlhDsaShake256fVerify = 355,
743
744 LmsSha256M32H5W1Sign = 500,
755 LmsSha256M32H5W1Verify = 501,
756 LmsSha256M32H5W2Sign = 502,
757 LmsSha256M32H5W2Verify = 503,
758 LmsSha256M32H5W4Sign = 504,
759 LmsSha256M32H5W4Verify = 505,
760 LmsSha256M32H5W8Sign = 506,
761 LmsSha256M32H5W8Verify = 507,
762 LmsSha256M32H10W1Sign = 508,
763 LmsSha256M32H10W1Verify = 509,
764 LmsSha256M32H10W2Sign = 510,
765 LmsSha256M32H10W2Verify = 511,
766 LmsSha256M32H10W4Sign = 512,
767 LmsSha256M32H10W4Verify = 513,
768 LmsSha256M32H10W8Sign = 514,
769 LmsSha256M32H10W8Verify = 515,
770 LmsSha256M32H15W1Sign = 516,
771 LmsSha256M32H15W1Verify = 517,
772 LmsSha256M32H15W2Sign = 518,
773 LmsSha256M32H15W2Verify = 519,
774 LmsSha256M32H15W4Sign = 520,
775 LmsSha256M32H15W4Verify = 521,
776 LmsSha256M32H15W8Sign = 522,
777 LmsSha256M32H15W8Verify = 523,
778 LmsSha256M32H20W1Sign = 524,
779 LmsSha256M32H20W1Verify = 525,
780 LmsSha256M32H20W2Sign = 526,
781 LmsSha256M32H20W2Verify = 527,
782 LmsSha256M32H20W4Sign = 528,
783 LmsSha256M32H20W4Verify = 529,
784 LmsSha256M32H20W8Sign = 530,
785 LmsSha256M32H20W8Verify = 531,
786 LmsSha256M32H25W1Sign = 532,
787 LmsSha256M32H25W1Verify = 533,
788 LmsSha256M32H25W2Sign = 534,
789 LmsSha256M32H25W2Verify = 535,
790 LmsSha256M32H25W4Sign = 536,
791 LmsSha256M32H25W4Verify = 537,
792 LmsSha256M32H25W8Sign = 538,
793 LmsSha256M32H25W8Verify = 539,
794
795 LmsSha256M24H5W1Sign = 540,
797 LmsSha256M24H5W1Verify = 541,
798 LmsSha256M24H5W2Sign = 542,
799 LmsSha256M24H5W2Verify = 543,
800 LmsSha256M24H5W4Sign = 544,
801 LmsSha256M24H5W4Verify = 545,
802 LmsSha256M24H5W8Sign = 546,
803 LmsSha256M24H5W8Verify = 547,
804 LmsSha256M24H10W1Sign = 548,
805 LmsSha256M24H10W1Verify = 549,
806 LmsSha256M24H10W2Sign = 550,
807 LmsSha256M24H10W2Verify = 551,
808 LmsSha256M24H10W4Sign = 552,
809 LmsSha256M24H10W4Verify = 553,
810 LmsSha256M24H10W8Sign = 554,
811 LmsSha256M24H10W8Verify = 555,
812 LmsSha256M24H15W1Sign = 556,
813 LmsSha256M24H15W1Verify = 557,
814 LmsSha256M24H15W2Sign = 558,
815 LmsSha256M24H15W2Verify = 559,
816 LmsSha256M24H15W4Sign = 560,
817 LmsSha256M24H15W4Verify = 561,
818 LmsSha256M24H15W8Sign = 562,
819 LmsSha256M24H15W8Verify = 563,
820 LmsSha256M24H20W1Sign = 564,
821 LmsSha256M24H20W1Verify = 565,
822 LmsSha256M24H20W2Sign = 566,
823 LmsSha256M24H20W2Verify = 567,
824 LmsSha256M24H20W4Sign = 568,
825 LmsSha256M24H20W4Verify = 569,
826 LmsSha256M24H20W8Sign = 570,
827 LmsSha256M24H20W8Verify = 571,
828 LmsSha256M24H25W1Sign = 572,
829 LmsSha256M24H25W1Verify = 573,
830 LmsSha256M24H25W2Sign = 574,
831 LmsSha256M24H25W2Verify = 575,
832 LmsSha256M24H25W4Sign = 576,
833 LmsSha256M24H25W4Verify = 577,
834 LmsSha256M24H25W8Sign = 578,
835 LmsSha256M24H25W8Verify = 579,
836
837 LmsShakeM32H5W1Sign = 580,
839 LmsShakeM32H5W1Verify = 581,
840 LmsShakeM32H5W2Sign = 582,
841 LmsShakeM32H5W2Verify = 583,
842 LmsShakeM32H5W4Sign = 584,
843 LmsShakeM32H5W4Verify = 585,
844 LmsShakeM32H5W8Sign = 586,
845 LmsShakeM32H5W8Verify = 587,
846 LmsShakeM32H10W1Sign = 588,
847 LmsShakeM32H10W1Verify = 589,
848 LmsShakeM32H10W2Sign = 590,
849 LmsShakeM32H10W2Verify = 591,
850 LmsShakeM32H10W4Sign = 592,
851 LmsShakeM32H10W4Verify = 593,
852 LmsShakeM32H10W8Sign = 594,
853 LmsShakeM32H10W8Verify = 595,
854 LmsShakeM32H15W1Sign = 596,
855 LmsShakeM32H15W1Verify = 597,
856 LmsShakeM32H15W2Sign = 598,
857 LmsShakeM32H15W2Verify = 599,
858 LmsShakeM32H15W4Sign = 600,
859 LmsShakeM32H15W4Verify = 601,
860 LmsShakeM32H15W8Sign = 602,
861 LmsShakeM32H15W8Verify = 603,
862 LmsShakeM32H20W1Sign = 604,
863 LmsShakeM32H20W1Verify = 605,
864 LmsShakeM32H20W2Sign = 606,
865 LmsShakeM32H20W2Verify = 607,
866 LmsShakeM32H20W4Sign = 608,
867 LmsShakeM32H20W4Verify = 609,
868 LmsShakeM32H20W8Sign = 610,
869 LmsShakeM32H20W8Verify = 611,
870 LmsShakeM32H25W1Sign = 612,
871 LmsShakeM32H25W1Verify = 613,
872 LmsShakeM32H25W2Sign = 614,
873 LmsShakeM32H25W2Verify = 615,
874 LmsShakeM32H25W4Sign = 616,
875 LmsShakeM32H25W4Verify = 617,
876 LmsShakeM32H25W8Sign = 618,
877 LmsShakeM32H25W8Verify = 619,
878
879 LmsShakeM24H5W1Sign = 620,
881 LmsShakeM24H5W1Verify = 621,
882 LmsShakeM24H5W2Sign = 622,
883 LmsShakeM24H5W2Verify = 623,
884 LmsShakeM24H5W4Sign = 624,
885 LmsShakeM24H5W4Verify = 625,
886 LmsShakeM24H5W8Sign = 626,
887 LmsShakeM24H5W8Verify = 627,
888 LmsShakeM24H10W1Sign = 628,
889 LmsShakeM24H10W1Verify = 629,
890 LmsShakeM24H10W2Sign = 630,
891 LmsShakeM24H10W2Verify = 631,
892 LmsShakeM24H10W4Sign = 632,
893 LmsShakeM24H10W4Verify = 633,
894 LmsShakeM24H10W8Sign = 634,
895 LmsShakeM24H10W8Verify = 635,
896 LmsShakeM24H15W1Sign = 636,
897 LmsShakeM24H15W1Verify = 637,
898 LmsShakeM24H15W2Sign = 638,
899 LmsShakeM24H15W2Verify = 639,
900 LmsShakeM24H15W4Sign = 640,
901 LmsShakeM24H15W4Verify = 641,
902 LmsShakeM24H15W8Sign = 642,
903 LmsShakeM24H15W8Verify = 643,
904 LmsShakeM24H20W1Sign = 644,
905 LmsShakeM24H20W1Verify = 645,
906 LmsShakeM24H20W2Sign = 646,
907 LmsShakeM24H20W2Verify = 647,
908 LmsShakeM24H20W4Sign = 648,
909 LmsShakeM24H20W4Verify = 649,
910 LmsShakeM24H20W8Sign = 650,
911 LmsShakeM24H20W8Verify = 651,
912 LmsShakeM24H25W1Sign = 652,
913 LmsShakeM24H25W1Verify = 653,
914 LmsShakeM24H25W2Sign = 654,
915 LmsShakeM24H25W2Verify = 655,
916 LmsShakeM24H25W4Sign = 656,
917 LmsShakeM24H25W4Verify = 657,
918 LmsShakeM24H25W8Sign = 658,
919 LmsShakeM24H25W8Verify = 659,
920
921 XmssSign = 370,
924 XmssVerify = 371,
925
926 Dh3072 = 380,
929}
930
931impl fmt::Display for Service {
932 #[allow(clippy::too_many_lines)]
936 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
937 let name = match self {
938 Self::Sha1 => "SHA-1",
939 Self::Sha224 => "SHA-224",
940 Self::Sha256 => "SHA-256",
941 Self::Sha384 => "SHA-384",
942 Self::Sha512 => "SHA-512",
943 Self::Sha512_224 => "SHA-512/224",
944 Self::Sha512_256 => "SHA-512/256",
945 Self::Sha3_224 => "SHA3-224",
946 Self::Sha3_256 => "SHA3-256",
947 Self::Sha3_384 => "SHA3-384",
948 Self::Sha3_512 => "SHA3-512",
949 Self::Shake128 => "SHAKE128",
950 Self::Shake256 => "SHAKE256",
951 Self::CShake128 => "cSHAKE128",
952 Self::CShake256 => "cSHAKE256",
953 Self::Kmac128 => "KMAC128",
954 Self::Kmac256 => "KMAC256",
955 Self::KmacXof128 => "KMACXOF128",
956 Self::KmacXof256 => "KMACXOF256",
957 Self::TupleHash128 => "TupleHash128",
958 Self::TupleHash256 => "TupleHash256",
959 Self::TupleHashXof128 => "TupleHashXOF128",
960 Self::TupleHashXof256 => "TupleHashXOF256",
961 Self::ParallelHash128 => "ParallelHash128",
962 Self::ParallelHash256 => "ParallelHash256",
963 Self::ParallelHashXof128 => "ParallelHashXOF128",
964 Self::ParallelHashXof256 => "ParallelHashXOF256",
965 Self::HmacSha1 => "HMAC-SHA-1",
966 Self::HmacSha224 => "HMAC-SHA-224",
967 Self::HmacSha256 => "HMAC-SHA-256",
968 Self::HmacSha384 => "HMAC-SHA-384",
969 Self::HmacSha512 => "HMAC-SHA-512",
970 Self::HmacSha512_224 => "HMAC-SHA-512/224",
971 Self::HmacSha512_256 => "HMAC-SHA-512/256",
972 Self::HmacSha3_224 => "HMAC-SHA3-224",
973 Self::HmacSha3_256 => "HMAC-SHA3-256",
974 Self::HmacSha3_384 => "HMAC-SHA3-384",
975 Self::HmacSha3_512 => "HMAC-SHA3-512",
976 Self::CmacAes128 => "CMAC-AES-128",
977 Self::CmacAes192 => "CMAC-AES-192",
978 Self::CmacAes256 => "CMAC-AES-256",
979 Self::Aes128Ecb => "AES-128-ECB",
980 Self::Aes128Cbc => "AES-128-CBC",
981 Self::Aes128Ctr => "AES-128-CTR",
982 Self::Aes128Gcm => "AES-128-GCM",
983 Self::Aes128Ccm => "AES-128-CCM",
984 Self::Aes128Kw => "AES-128-KW",
985 Self::Aes128Kwp => "AES-128-KWP",
986 Self::Aes192Ecb => "AES-192-ECB",
987 Self::Aes192Cbc => "AES-192-CBC",
988 Self::Aes192Ctr => "AES-192-CTR",
989 Self::Aes192Gcm => "AES-192-GCM",
990 Self::Aes192Ccm => "AES-192-CCM",
991 Self::Aes192Kw => "AES-192-KW",
992 Self::Aes192Kwp => "AES-192-KWP",
993 Self::Aes256Ecb => "AES-256-ECB",
994 Self::Aes256Cbc => "AES-256-CBC",
995 Self::Aes256Ctr => "AES-256-CTR",
996 Self::Aes256Gcm => "AES-256-GCM",
997 Self::Aes256Ccm => "AES-256-CCM",
998 Self::Aes256Kw => "AES-256-KW",
999 Self::Aes256Kwp => "AES-256-KWP",
1000 Self::Aes128 => "AES-128",
1001 Self::Aes192 => "AES-192",
1002 Self::Aes256 => "AES-256",
1003 Self::CtrDrbgAes128 => "CTR_DRBG-AES-128",
1004 Self::CtrDrbgAes192 => "CTR_DRBG-AES-192",
1005 Self::CtrDrbgAes256 => "CTR_DRBG-AES-256",
1006 Self::HashDrbgSha256 => "Hash_DRBG-SHA-256",
1007 Self::HashDrbgSha384 => "Hash_DRBG-SHA-384",
1008 Self::HashDrbgSha512 => "Hash_DRBG-SHA-512",
1009 Self::HmacDrbgSha256 => "HMAC_DRBG-SHA-256",
1010 Self::HmacDrbgSha384 => "HMAC_DRBG-SHA-384",
1011 Self::HmacDrbgSha512 => "HMAC_DRBG-SHA-512",
1012 Self::HkdfSha1 => "HKDF-SHA-1",
1013 Self::HkdfSha256 => "HKDF-SHA-256",
1014 Self::HkdfSha384 => "HKDF-SHA-384",
1015 Self::HkdfSha512 => "HKDF-SHA-512",
1016 Self::KbkdfHmacSha256 => "KBKDF-HMAC-SHA-256",
1017 Self::KbkdfHmacSha384 => "KBKDF-HMAC-SHA-384",
1018 Self::KbkdfHmacSha512 => "KBKDF-HMAC-SHA-512",
1019 Self::KbkdfCmacAes128 => "KBKDF-CMAC-AES-128",
1020 Self::KbkdfCmacAes192 => "KBKDF-CMAC-AES-192",
1021 Self::KbkdfCmacAes256 => "KBKDF-CMAC-AES-256",
1022 Self::Pbkdf2HmacSha1 => "PBKDF2-HMAC-SHA-1",
1023 Self::Pbkdf2HmacSha224 => "PBKDF2-HMAC-SHA-224",
1024 Self::Pbkdf2HmacSha256 => "PBKDF2-HMAC-SHA-256",
1025 Self::Pbkdf2HmacSha384 => "PBKDF2-HMAC-SHA-384",
1026 Self::Pbkdf2HmacSha512 => "PBKDF2-HMAC-SHA-512",
1027 Self::RsaKeygen2048 => "RSA-2048 keygen",
1028 Self::RsaPkcs1v15Sign2048 => "RSA-PKCS1v1.5-Sign-2048",
1029 Self::RsaPssSign2048 => "RSA-PSS-Sign-2048",
1030 Self::RsaOaep2048 => "RSA-OAEP-2048",
1031 Self::RsaPkcs1v15Verify2048 => "RSA-PKCS1v1.5-Verify-2048",
1032 Self::RsaPssVerify2048 => "RSA-PSS-Verify-2048",
1033 Self::RsaKeygen3072 => "RSA-3072 keygen",
1034 Self::RsaPkcs1v15Sign3072 => "RSA-PKCS1v1.5-Sign-3072",
1035 Self::RsaPssSign3072 => "RSA-PSS-Sign-3072",
1036 Self::RsaOaep3072 => "RSA-OAEP-3072",
1037 Self::RsaPkcs1v15Verify3072 => "RSA-PKCS1v1.5-Verify-3072",
1038 Self::RsaPssVerify3072 => "RSA-PSS-Verify-3072",
1039 Self::RsaKeygen4096 => "RSA-4096 keygen",
1040 Self::RsaPkcs1v15Sign4096 => "RSA-PKCS1v1.5-Sign-4096",
1041 Self::RsaPssSign4096 => "RSA-PSS-Sign-4096",
1042 Self::RsaOaep4096 => "RSA-OAEP-4096",
1043 Self::RsaPkcs1v15Verify4096 => "RSA-PKCS1v1.5-Verify-4096",
1044 Self::RsaPssVerify4096 => "RSA-PSS-Verify-4096",
1045 Self::EcdsaP256Sign => "ECDSA-P256 sign",
1046 Self::EcdsaP256Verify => "ECDSA-P256 verify",
1047 Self::EcdsaP256Keygen => "ECDSA-P256 keygen",
1048 Self::EcdsaP384Sign => "ECDSA-P384 sign",
1049 Self::EcdsaP384Verify => "ECDSA-P384 verify",
1050 Self::EcdsaP384Keygen => "ECDSA-P384 keygen",
1051 Self::EcdhP256 => "ECDH-P256",
1052 Self::EcdhP384 => "ECDH-P384",
1053 Self::Ed25519Sign => "Ed25519 sign",
1054 Self::Ed25519Verify => "Ed25519 verify",
1055 Self::Ed25519Keygen => "Ed25519 keygen",
1056 Self::Tls12Kdf => "TLS 1.2 KDF",
1057 Self::Tls13Kdf => "TLS 1.3 KDF",
1058 Self::MlKem1024Encaps => "ML-KEM-1024 encaps",
1059 Self::MlKem1024Decaps => "ML-KEM-1024 decaps",
1060 Self::MlKem1024Keygen => "ML-KEM-1024 keygen",
1061 Self::MlKem512Encaps => "ML-KEM-512 encaps",
1062 Self::MlKem512Decaps => "ML-KEM-512 decaps",
1063 Self::MlKem512Keygen => "ML-KEM-512 keygen",
1064 Self::MlKem768Encaps => "ML-KEM-768 encaps",
1065 Self::MlKem768Decaps => "ML-KEM-768 decaps",
1066 Self::MlKem768Keygen => "ML-KEM-768 keygen",
1067 Self::MlDsa87Sign => "ML-DSA-87 sign",
1068 Self::MlDsa87Verify => "ML-DSA-87 verify",
1069 Self::MlDsa87Keygen => "ML-DSA-87 keygen",
1070 Self::MlDsa44Sign => "ML-DSA-44 sign",
1071 Self::MlDsa44Verify => "ML-DSA-44 verify",
1072 Self::MlDsa44Keygen => "ML-DSA-44 keygen",
1073 Self::MlDsa65Sign => "ML-DSA-65 sign",
1074 Self::MlDsa65Verify => "ML-DSA-65 verify",
1075 Self::MlDsa65Keygen => "ML-DSA-65 keygen",
1076 Self::SlhDsaSha2256sKeygen => "SLH-DSA-SHA2-256s keygen",
1077 Self::SlhDsaSha2256sSign => "SLH-DSA-SHA2-256s sign",
1078 Self::SlhDsaSha2256sVerify => "SLH-DSA-SHA2-256s verify",
1079 Self::SlhDsaSha2128sKeygen => "SLH-DSA-SHA2-128s keygen",
1080 Self::SlhDsaSha2128sSign => "SLH-DSA-SHA2-128s sign",
1081 Self::SlhDsaSha2128sVerify => "SLH-DSA-SHA2-128s verify",
1082 Self::SlhDsaSha2128fKeygen => "SLH-DSA-SHA2-128f keygen",
1083 Self::SlhDsaSha2128fSign => "SLH-DSA-SHA2-128f sign",
1084 Self::SlhDsaSha2128fVerify => "SLH-DSA-SHA2-128f verify",
1085 Self::SlhDsaSha2192sKeygen => "SLH-DSA-SHA2-192s keygen",
1086 Self::SlhDsaSha2192sSign => "SLH-DSA-SHA2-192s sign",
1087 Self::SlhDsaSha2192sVerify => "SLH-DSA-SHA2-192s verify",
1088 Self::SlhDsaSha2192fKeygen => "SLH-DSA-SHA2-192f keygen",
1089 Self::SlhDsaSha2192fSign => "SLH-DSA-SHA2-192f sign",
1090 Self::SlhDsaSha2192fVerify => "SLH-DSA-SHA2-192f verify",
1091 Self::SlhDsaSha2256fKeygen => "SLH-DSA-SHA2-256f keygen",
1092 Self::SlhDsaSha2256fSign => "SLH-DSA-SHA2-256f sign",
1093 Self::SlhDsaSha2256fVerify => "SLH-DSA-SHA2-256f verify",
1094 Self::SlhDsaShake128sKeygen => "SLH-DSA-SHAKE-128s keygen",
1095 Self::SlhDsaShake128sSign => "SLH-DSA-SHAKE-128s sign",
1096 Self::SlhDsaShake128sVerify => "SLH-DSA-SHAKE-128s verify",
1097 Self::SlhDsaShake128fKeygen => "SLH-DSA-SHAKE-128f keygen",
1098 Self::SlhDsaShake128fSign => "SLH-DSA-SHAKE-128f sign",
1099 Self::SlhDsaShake128fVerify => "SLH-DSA-SHAKE-128f verify",
1100 Self::SlhDsaShake192sKeygen => "SLH-DSA-SHAKE-192s keygen",
1101 Self::SlhDsaShake192sSign => "SLH-DSA-SHAKE-192s sign",
1102 Self::SlhDsaShake192sVerify => "SLH-DSA-SHAKE-192s verify",
1103 Self::SlhDsaShake192fKeygen => "SLH-DSA-SHAKE-192f keygen",
1104 Self::SlhDsaShake192fSign => "SLH-DSA-SHAKE-192f sign",
1105 Self::SlhDsaShake192fVerify => "SLH-DSA-SHAKE-192f verify",
1106 Self::SlhDsaShake256sKeygen => "SLH-DSA-SHAKE-256s keygen",
1107 Self::SlhDsaShake256sSign => "SLH-DSA-SHAKE-256s sign",
1108 Self::SlhDsaShake256sVerify => "SLH-DSA-SHAKE-256s verify",
1109 Self::SlhDsaShake256fKeygen => "SLH-DSA-SHAKE-256f keygen",
1110 Self::SlhDsaShake256fSign => "SLH-DSA-SHAKE-256f sign",
1111 Self::SlhDsaShake256fVerify => "SLH-DSA-SHAKE-256f verify",
1112 Self::LmsSha256M32H5W1Sign => "LMS SHA-256 M=32 H=5 W=1 sign",
1113 Self::LmsSha256M32H5W1Verify => "LMS SHA-256 M=32 H=5 W=1 verify",
1114 Self::LmsSha256M32H5W2Sign => "LMS SHA-256 M=32 H=5 W=2 sign",
1115 Self::LmsSha256M32H5W2Verify => "LMS SHA-256 M=32 H=5 W=2 verify",
1116 Self::LmsSha256M32H5W4Sign => "LMS SHA-256 M=32 H=5 W=4 sign",
1117 Self::LmsSha256M32H5W4Verify => "LMS SHA-256 M=32 H=5 W=4 verify",
1118 Self::LmsSha256M32H5W8Sign => "LMS SHA-256 M=32 H=5 W=8 sign",
1119 Self::LmsSha256M32H5W8Verify => "LMS SHA-256 M=32 H=5 W=8 verify",
1120 Self::LmsSha256M32H10W1Sign => "LMS SHA-256 M=32 H=10 W=1 sign",
1121 Self::LmsSha256M32H10W1Verify => "LMS SHA-256 M=32 H=10 W=1 verify",
1122 Self::LmsSha256M32H10W2Sign => "LMS SHA-256 M=32 H=10 W=2 sign",
1123 Self::LmsSha256M32H10W2Verify => "LMS SHA-256 M=32 H=10 W=2 verify",
1124 Self::LmsSha256M32H10W4Sign => "LMS SHA-256 M=32 H=10 W=4 sign",
1125 Self::LmsSha256M32H10W4Verify => "LMS SHA-256 M=32 H=10 W=4 verify",
1126 Self::LmsSha256M32H10W8Sign => "LMS SHA-256 M=32 H=10 W=8 sign",
1127 Self::LmsSha256M32H10W8Verify => "LMS SHA-256 M=32 H=10 W=8 verify",
1128 Self::LmsSha256M32H15W1Sign => "LMS SHA-256 M=32 H=15 W=1 sign",
1129 Self::LmsSha256M32H15W1Verify => "LMS SHA-256 M=32 H=15 W=1 verify",
1130 Self::LmsSha256M32H15W2Sign => "LMS SHA-256 M=32 H=15 W=2 sign",
1131 Self::LmsSha256M32H15W2Verify => "LMS SHA-256 M=32 H=15 W=2 verify",
1132 Self::LmsSha256M32H15W4Sign => "LMS SHA-256 M=32 H=15 W=4 sign",
1133 Self::LmsSha256M32H15W4Verify => "LMS SHA-256 M=32 H=15 W=4 verify",
1134 Self::LmsSha256M32H15W8Sign => "LMS SHA-256 M=32 H=15 W=8 sign",
1135 Self::LmsSha256M32H15W8Verify => "LMS SHA-256 M=32 H=15 W=8 verify",
1136 Self::LmsSha256M32H20W1Sign => "LMS SHA-256 M=32 H=20 W=1 sign",
1137 Self::LmsSha256M32H20W1Verify => "LMS SHA-256 M=32 H=20 W=1 verify",
1138 Self::LmsSha256M32H20W2Sign => "LMS SHA-256 M=32 H=20 W=2 sign",
1139 Self::LmsSha256M32H20W2Verify => "LMS SHA-256 M=32 H=20 W=2 verify",
1140 Self::LmsSha256M32H20W4Sign => "LMS SHA-256 M=32 H=20 W=4 sign",
1141 Self::LmsSha256M32H20W4Verify => "LMS SHA-256 M=32 H=20 W=4 verify",
1142 Self::LmsSha256M32H20W8Sign => "LMS SHA-256 M=32 H=20 W=8 sign",
1143 Self::LmsSha256M32H20W8Verify => "LMS SHA-256 M=32 H=20 W=8 verify",
1144 Self::LmsSha256M32H25W1Sign => "LMS SHA-256 M=32 H=25 W=1 sign",
1145 Self::LmsSha256M32H25W1Verify => "LMS SHA-256 M=32 H=25 W=1 verify",
1146 Self::LmsSha256M32H25W2Sign => "LMS SHA-256 M=32 H=25 W=2 sign",
1147 Self::LmsSha256M32H25W2Verify => "LMS SHA-256 M=32 H=25 W=2 verify",
1148 Self::LmsSha256M32H25W4Sign => "LMS SHA-256 M=32 H=25 W=4 sign",
1149 Self::LmsSha256M32H25W4Verify => "LMS SHA-256 M=32 H=25 W=4 verify",
1150 Self::LmsSha256M32H25W8Sign => "LMS SHA-256 M=32 H=25 W=8 sign",
1151 Self::LmsSha256M32H25W8Verify => "LMS SHA-256 M=32 H=25 W=8 verify",
1152 Self::LmsSha256M24H5W1Sign => "LMS SHA-256 M=24 H=5 W=1 sign",
1153 Self::LmsSha256M24H5W1Verify => "LMS SHA-256 M=24 H=5 W=1 verify",
1154 Self::LmsSha256M24H5W2Sign => "LMS SHA-256 M=24 H=5 W=2 sign",
1155 Self::LmsSha256M24H5W2Verify => "LMS SHA-256 M=24 H=5 W=2 verify",
1156 Self::LmsSha256M24H5W4Sign => "LMS SHA-256 M=24 H=5 W=4 sign",
1157 Self::LmsSha256M24H5W4Verify => "LMS SHA-256 M=24 H=5 W=4 verify",
1158 Self::LmsSha256M24H5W8Sign => "LMS SHA-256 M=24 H=5 W=8 sign",
1159 Self::LmsSha256M24H5W8Verify => "LMS SHA-256 M=24 H=5 W=8 verify",
1160 Self::LmsSha256M24H10W1Sign => "LMS SHA-256 M=24 H=10 W=1 sign",
1161 Self::LmsSha256M24H10W1Verify => "LMS SHA-256 M=24 H=10 W=1 verify",
1162 Self::LmsSha256M24H10W2Sign => "LMS SHA-256 M=24 H=10 W=2 sign",
1163 Self::LmsSha256M24H10W2Verify => "LMS SHA-256 M=24 H=10 W=2 verify",
1164 Self::LmsSha256M24H10W4Sign => "LMS SHA-256 M=24 H=10 W=4 sign",
1165 Self::LmsSha256M24H10W4Verify => "LMS SHA-256 M=24 H=10 W=4 verify",
1166 Self::LmsSha256M24H10W8Sign => "LMS SHA-256 M=24 H=10 W=8 sign",
1167 Self::LmsSha256M24H10W8Verify => "LMS SHA-256 M=24 H=10 W=8 verify",
1168 Self::LmsSha256M24H15W1Sign => "LMS SHA-256 M=24 H=15 W=1 sign",
1169 Self::LmsSha256M24H15W1Verify => "LMS SHA-256 M=24 H=15 W=1 verify",
1170 Self::LmsSha256M24H15W2Sign => "LMS SHA-256 M=24 H=15 W=2 sign",
1171 Self::LmsSha256M24H15W2Verify => "LMS SHA-256 M=24 H=15 W=2 verify",
1172 Self::LmsSha256M24H15W4Sign => "LMS SHA-256 M=24 H=15 W=4 sign",
1173 Self::LmsSha256M24H15W4Verify => "LMS SHA-256 M=24 H=15 W=4 verify",
1174 Self::LmsSha256M24H15W8Sign => "LMS SHA-256 M=24 H=15 W=8 sign",
1175 Self::LmsSha256M24H15W8Verify => "LMS SHA-256 M=24 H=15 W=8 verify",
1176 Self::LmsSha256M24H20W1Sign => "LMS SHA-256 M=24 H=20 W=1 sign",
1177 Self::LmsSha256M24H20W1Verify => "LMS SHA-256 M=24 H=20 W=1 verify",
1178 Self::LmsSha256M24H20W2Sign => "LMS SHA-256 M=24 H=20 W=2 sign",
1179 Self::LmsSha256M24H20W2Verify => "LMS SHA-256 M=24 H=20 W=2 verify",
1180 Self::LmsSha256M24H20W4Sign => "LMS SHA-256 M=24 H=20 W=4 sign",
1181 Self::LmsSha256M24H20W4Verify => "LMS SHA-256 M=24 H=20 W=4 verify",
1182 Self::LmsSha256M24H20W8Sign => "LMS SHA-256 M=24 H=20 W=8 sign",
1183 Self::LmsSha256M24H20W8Verify => "LMS SHA-256 M=24 H=20 W=8 verify",
1184 Self::LmsSha256M24H25W1Sign => "LMS SHA-256 M=24 H=25 W=1 sign",
1185 Self::LmsSha256M24H25W1Verify => "LMS SHA-256 M=24 H=25 W=1 verify",
1186 Self::LmsSha256M24H25W2Sign => "LMS SHA-256 M=24 H=25 W=2 sign",
1187 Self::LmsSha256M24H25W2Verify => "LMS SHA-256 M=24 H=25 W=2 verify",
1188 Self::LmsSha256M24H25W4Sign => "LMS SHA-256 M=24 H=25 W=4 sign",
1189 Self::LmsSha256M24H25W4Verify => "LMS SHA-256 M=24 H=25 W=4 verify",
1190 Self::LmsSha256M24H25W8Sign => "LMS SHA-256 M=24 H=25 W=8 sign",
1191 Self::LmsSha256M24H25W8Verify => "LMS SHA-256 M=24 H=25 W=8 verify",
1192 Self::LmsShakeM32H5W1Sign => "LMS SHAKE M=32 H=5 W=1 sign",
1193 Self::LmsShakeM32H5W1Verify => "LMS SHAKE M=32 H=5 W=1 verify",
1194 Self::LmsShakeM32H5W2Sign => "LMS SHAKE M=32 H=5 W=2 sign",
1195 Self::LmsShakeM32H5W2Verify => "LMS SHAKE M=32 H=5 W=2 verify",
1196 Self::LmsShakeM32H5W4Sign => "LMS SHAKE M=32 H=5 W=4 sign",
1197 Self::LmsShakeM32H5W4Verify => "LMS SHAKE M=32 H=5 W=4 verify",
1198 Self::LmsShakeM32H5W8Sign => "LMS SHAKE M=32 H=5 W=8 sign",
1199 Self::LmsShakeM32H5W8Verify => "LMS SHAKE M=32 H=5 W=8 verify",
1200 Self::LmsShakeM32H10W1Sign => "LMS SHAKE M=32 H=10 W=1 sign",
1201 Self::LmsShakeM32H10W1Verify => "LMS SHAKE M=32 H=10 W=1 verify",
1202 Self::LmsShakeM32H10W2Sign => "LMS SHAKE M=32 H=10 W=2 sign",
1203 Self::LmsShakeM32H10W2Verify => "LMS SHAKE M=32 H=10 W=2 verify",
1204 Self::LmsShakeM32H10W4Sign => "LMS SHAKE M=32 H=10 W=4 sign",
1205 Self::LmsShakeM32H10W4Verify => "LMS SHAKE M=32 H=10 W=4 verify",
1206 Self::LmsShakeM32H10W8Sign => "LMS SHAKE M=32 H=10 W=8 sign",
1207 Self::LmsShakeM32H10W8Verify => "LMS SHAKE M=32 H=10 W=8 verify",
1208 Self::LmsShakeM32H15W1Sign => "LMS SHAKE M=32 H=15 W=1 sign",
1209 Self::LmsShakeM32H15W1Verify => "LMS SHAKE M=32 H=15 W=1 verify",
1210 Self::LmsShakeM32H15W2Sign => "LMS SHAKE M=32 H=15 W=2 sign",
1211 Self::LmsShakeM32H15W2Verify => "LMS SHAKE M=32 H=15 W=2 verify",
1212 Self::LmsShakeM32H15W4Sign => "LMS SHAKE M=32 H=15 W=4 sign",
1213 Self::LmsShakeM32H15W4Verify => "LMS SHAKE M=32 H=15 W=4 verify",
1214 Self::LmsShakeM32H15W8Sign => "LMS SHAKE M=32 H=15 W=8 sign",
1215 Self::LmsShakeM32H15W8Verify => "LMS SHAKE M=32 H=15 W=8 verify",
1216 Self::LmsShakeM32H20W1Sign => "LMS SHAKE M=32 H=20 W=1 sign",
1217 Self::LmsShakeM32H20W1Verify => "LMS SHAKE M=32 H=20 W=1 verify",
1218 Self::LmsShakeM32H20W2Sign => "LMS SHAKE M=32 H=20 W=2 sign",
1219 Self::LmsShakeM32H20W2Verify => "LMS SHAKE M=32 H=20 W=2 verify",
1220 Self::LmsShakeM32H20W4Sign => "LMS SHAKE M=32 H=20 W=4 sign",
1221 Self::LmsShakeM32H20W4Verify => "LMS SHAKE M=32 H=20 W=4 verify",
1222 Self::LmsShakeM32H20W8Sign => "LMS SHAKE M=32 H=20 W=8 sign",
1223 Self::LmsShakeM32H20W8Verify => "LMS SHAKE M=32 H=20 W=8 verify",
1224 Self::LmsShakeM32H25W1Sign => "LMS SHAKE M=32 H=25 W=1 sign",
1225 Self::LmsShakeM32H25W1Verify => "LMS SHAKE M=32 H=25 W=1 verify",
1226 Self::LmsShakeM32H25W2Sign => "LMS SHAKE M=32 H=25 W=2 sign",
1227 Self::LmsShakeM32H25W2Verify => "LMS SHAKE M=32 H=25 W=2 verify",
1228 Self::LmsShakeM32H25W4Sign => "LMS SHAKE M=32 H=25 W=4 sign",
1229 Self::LmsShakeM32H25W4Verify => "LMS SHAKE M=32 H=25 W=4 verify",
1230 Self::LmsShakeM32H25W8Sign => "LMS SHAKE M=32 H=25 W=8 sign",
1231 Self::LmsShakeM32H25W8Verify => "LMS SHAKE M=32 H=25 W=8 verify",
1232 Self::LmsShakeM24H5W1Sign => "LMS SHAKE M=24 H=5 W=1 sign",
1233 Self::LmsShakeM24H5W1Verify => "LMS SHAKE M=24 H=5 W=1 verify",
1234 Self::LmsShakeM24H5W2Sign => "LMS SHAKE M=24 H=5 W=2 sign",
1235 Self::LmsShakeM24H5W2Verify => "LMS SHAKE M=24 H=5 W=2 verify",
1236 Self::LmsShakeM24H5W4Sign => "LMS SHAKE M=24 H=5 W=4 sign",
1237 Self::LmsShakeM24H5W4Verify => "LMS SHAKE M=24 H=5 W=4 verify",
1238 Self::LmsShakeM24H5W8Sign => "LMS SHAKE M=24 H=5 W=8 sign",
1239 Self::LmsShakeM24H5W8Verify => "LMS SHAKE M=24 H=5 W=8 verify",
1240 Self::LmsShakeM24H10W1Sign => "LMS SHAKE M=24 H=10 W=1 sign",
1241 Self::LmsShakeM24H10W1Verify => "LMS SHAKE M=24 H=10 W=1 verify",
1242 Self::LmsShakeM24H10W2Sign => "LMS SHAKE M=24 H=10 W=2 sign",
1243 Self::LmsShakeM24H10W2Verify => "LMS SHAKE M=24 H=10 W=2 verify",
1244 Self::LmsShakeM24H10W4Sign => "LMS SHAKE M=24 H=10 W=4 sign",
1245 Self::LmsShakeM24H10W4Verify => "LMS SHAKE M=24 H=10 W=4 verify",
1246 Self::LmsShakeM24H10W8Sign => "LMS SHAKE M=24 H=10 W=8 sign",
1247 Self::LmsShakeM24H10W8Verify => "LMS SHAKE M=24 H=10 W=8 verify",
1248 Self::LmsShakeM24H15W1Sign => "LMS SHAKE M=24 H=15 W=1 sign",
1249 Self::LmsShakeM24H15W1Verify => "LMS SHAKE M=24 H=15 W=1 verify",
1250 Self::LmsShakeM24H15W2Sign => "LMS SHAKE M=24 H=15 W=2 sign",
1251 Self::LmsShakeM24H15W2Verify => "LMS SHAKE M=24 H=15 W=2 verify",
1252 Self::LmsShakeM24H15W4Sign => "LMS SHAKE M=24 H=15 W=4 sign",
1253 Self::LmsShakeM24H15W4Verify => "LMS SHAKE M=24 H=15 W=4 verify",
1254 Self::LmsShakeM24H15W8Sign => "LMS SHAKE M=24 H=15 W=8 sign",
1255 Self::LmsShakeM24H15W8Verify => "LMS SHAKE M=24 H=15 W=8 verify",
1256 Self::LmsShakeM24H20W1Sign => "LMS SHAKE M=24 H=20 W=1 sign",
1257 Self::LmsShakeM24H20W1Verify => "LMS SHAKE M=24 H=20 W=1 verify",
1258 Self::LmsShakeM24H20W2Sign => "LMS SHAKE M=24 H=20 W=2 sign",
1259 Self::LmsShakeM24H20W2Verify => "LMS SHAKE M=24 H=20 W=2 verify",
1260 Self::LmsShakeM24H20W4Sign => "LMS SHAKE M=24 H=20 W=4 sign",
1261 Self::LmsShakeM24H20W4Verify => "LMS SHAKE M=24 H=20 W=4 verify",
1262 Self::LmsShakeM24H20W8Sign => "LMS SHAKE M=24 H=20 W=8 sign",
1263 Self::LmsShakeM24H20W8Verify => "LMS SHAKE M=24 H=20 W=8 verify",
1264 Self::LmsShakeM24H25W1Sign => "LMS SHAKE M=24 H=25 W=1 sign",
1265 Self::LmsShakeM24H25W1Verify => "LMS SHAKE M=24 H=25 W=1 verify",
1266 Self::LmsShakeM24H25W2Sign => "LMS SHAKE M=24 H=25 W=2 sign",
1267 Self::LmsShakeM24H25W2Verify => "LMS SHAKE M=24 H=25 W=2 verify",
1268 Self::LmsShakeM24H25W4Sign => "LMS SHAKE M=24 H=25 W=4 sign",
1269 Self::LmsShakeM24H25W4Verify => "LMS SHAKE M=24 H=25 W=4 verify",
1270 Self::LmsShakeM24H25W8Sign => "LMS SHAKE M=24 H=25 W=8 sign",
1271 Self::LmsShakeM24H25W8Verify => "LMS SHAKE M=24 H=25 W=8 verify",
1272 Self::XmssSign => "XMSS sign",
1273 Self::XmssVerify => "XMSS verify",
1274 Self::Dh3072 => "DH-3072",
1275 };
1276 f.write_str(name)
1277 }
1278}
1279
1280pub fn require_allowed(service: Service) -> Result<(), Error> {
1296 let profile = active_profile();
1297 if is_allowed(profile, service) {
1298 Ok(())
1299 } else {
1300 Err(Error::AlgorithmRestricted { service })
1301 }
1302}
1303
1304const fn is_allowed(profile: AlgorithmProfile, service: Service) -> bool {
1307 match profile {
1308 AlgorithmProfile::Unrestricted => true,
1309 AlgorithmProfile::Cnsa2 => is_cnsa2_allowed(service),
1310 AlgorithmProfile::Cnsa1 => is_cnsa1_allowed(service),
1311 }
1312}
1313
1314const fn is_lms_service(service: Service) -> bool {
1323 lms_block_contains(service as u16)
1324}
1325
1326const fn lms_block_contains(discriminant: u16) -> bool {
1335 discriminant >= Service::LmsSha256M32H5W1Sign as u16
1336 && discriminant <= Service::LmsShakeM24H25W8Verify as u16
1337}
1338
1339const fn is_cnsa2_allowed(service: Service) -> bool {
1344 matches!(
1345 service,
1346 Service::Aes256Ecb
1348 | Service::Aes256Cbc
1349 | Service::Aes256Ctr
1350 | Service::Aes256Gcm
1351 | Service::Aes256Ccm
1352 | Service::Aes256Kw
1353 | Service::Aes256Kwp
1354 | Service::Aes256
1355 | Service::Sha384
1357 | Service::Sha512
1358 | Service::Sha3_384
1360 | Service::Sha3_512
1361 | Service::Shake256
1363 | Service::CShake256
1365 | Service::Kmac256
1366 | Service::KmacXof256
1367 | Service::TupleHash256
1368 | Service::TupleHashXof256
1369 | Service::ParallelHash256
1370 | Service::ParallelHashXof256
1371 | Service::HmacSha384
1373 | Service::HmacSha512
1374 | Service::HmacSha3_384
1375 | Service::HmacSha3_512
1376 | Service::CmacAes256
1378 | Service::CtrDrbgAes256
1380 | Service::HashDrbgSha384
1381 | Service::HashDrbgSha512
1382 | Service::HmacDrbgSha384
1383 | Service::HmacDrbgSha512
1384 | Service::HkdfSha384
1386 | Service::HkdfSha512
1387 | Service::KbkdfHmacSha384
1388 | Service::KbkdfHmacSha512
1389 | Service::KbkdfCmacAes256
1390 | Service::Pbkdf2HmacSha384
1391 | Service::Pbkdf2HmacSha512
1392 | Service::Tls13Kdf
1394 | Service::MlKem1024Encaps
1396 | Service::MlKem1024Decaps
1397 | Service::MlKem1024Keygen
1398 | Service::MlDsa87Sign
1399 | Service::MlDsa87Verify
1400 | Service::MlDsa87Keygen
1401 | Service::XmssSign
1403 | Service::XmssVerify
1404 )
1405 || is_lms_service(service)
1412}
1413
1414const fn is_cnsa1_allowed(service: Service) -> bool {
1421 matches!(
1422 service,
1423 Service::Aes256Ecb
1425 | Service::Aes256Cbc
1426 | Service::Aes256Ctr
1427 | Service::Aes256Gcm
1428 | Service::Aes256Ccm
1429 | Service::Aes256Kw
1430 | Service::Aes256Kwp
1431 | Service::Aes256
1432 | Service::Sha256
1434 | Service::Sha384
1435 | Service::Sha512
1436 | Service::Sha3_256
1438 | Service::Sha3_384
1439 | Service::Sha3_512
1440 | Service::Shake256
1442 | Service::CShake256
1444 | Service::Kmac256
1445 | Service::KmacXof256
1446 | Service::TupleHash256
1447 | Service::TupleHashXof256
1448 | Service::ParallelHash256
1449 | Service::ParallelHashXof256
1450 | Service::HmacSha256
1452 | Service::HmacSha384
1453 | Service::HmacSha512
1454 | Service::HmacSha3_256
1455 | Service::HmacSha3_384
1456 | Service::HmacSha3_512
1457 | Service::CmacAes256
1459 | Service::CtrDrbgAes256
1461 | Service::HashDrbgSha256
1462 | Service::HashDrbgSha384
1463 | Service::HashDrbgSha512
1464 | Service::HmacDrbgSha256
1465 | Service::HmacDrbgSha384
1466 | Service::HmacDrbgSha512
1467 | Service::HkdfSha256
1469 | Service::HkdfSha384
1470 | Service::HkdfSha512
1471 | Service::KbkdfHmacSha256
1472 | Service::KbkdfHmacSha384
1473 | Service::KbkdfHmacSha512
1474 | Service::KbkdfCmacAes256
1475 | Service::Pbkdf2HmacSha256
1476 | Service::Pbkdf2HmacSha384
1477 | Service::Pbkdf2HmacSha512
1478 | Service::EcdsaP384Sign
1480 | Service::EcdsaP384Verify
1481 | Service::EcdsaP384Keygen
1482 | Service::EcdhP384
1483 | Service::RsaKeygen3072
1485 | Service::RsaPkcs1v15Sign3072
1486 | Service::RsaPssSign3072
1487 | Service::RsaOaep3072
1488 | Service::RsaPkcs1v15Verify3072
1489 | Service::RsaPssVerify3072
1490 | Service::RsaKeygen4096
1491 | Service::RsaPkcs1v15Sign4096
1492 | Service::RsaPssSign4096
1493 | Service::RsaOaep4096
1494 | Service::RsaPkcs1v15Verify4096
1495 | Service::RsaPssVerify4096
1496 | Service::Dh3072
1498 | Service::Tls13Kdf
1502 | Service::MlKem1024Encaps
1504 | Service::MlKem1024Decaps
1505 | Service::MlKem1024Keygen
1506 | Service::MlDsa87Sign
1507 | Service::MlDsa87Verify
1508 | Service::MlDsa87Keygen
1509 | Service::XmssSign
1511 | Service::XmssVerify
1512 )
1513 || is_lms_service(service)
1516}
1517
1518#[cfg(test)]
1547pub(crate) mod state_lock {
1548 use super::{AlgorithmProfile, Ordering, PROFILE, STATE, State};
1549
1550 static STATE_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
1551
1552 #[must_use]
1555 pub(crate) struct StateGuard(
1556 #[allow(dead_code)]
1559 std::sync::MutexGuard<'static, ()>,
1560 );
1561
1562 impl StateGuard {
1563 #[allow(clippy::unused_self)]
1567 pub(crate) fn reset(&self) {
1568 STATE.store(State::PowerOff as u8, Ordering::Release);
1569 PROFILE.store(AlgorithmProfile::Unrestricted as u8, Ordering::Release);
1570 }
1571 }
1572
1573 pub(crate) fn reset_for_test() -> StateGuard {
1590 let guard = StateGuard(
1591 STATE_LOCK
1592 .lock()
1593 .unwrap_or_else(std::sync::PoisonError::into_inner),
1594 );
1595 guard.reset();
1596 guard
1597 }
1598}
1599
1600#[cfg(test)]
1601extern crate alloc;
1602
1603#[cfg(test)]
1604extern crate std;
1605
1606#[cfg(test)]
1607#[allow(clippy::unwrap_used, clippy::panic)]
1608mod tests {
1609 use super::state_lock::reset_for_test;
1610 use super::{
1611 AlgorithmProfile, Error, KatEntry, SelfTest, SelfTestFailure, Service, State,
1612 active_profile, enter_error_state, initialize, initialize_with_profile,
1613 initialize_with_tests, is_allowed, is_lms_service, is_operational, lms_block_contains,
1614 require_allowed, require_operational, state,
1615 };
1616 use alloc::string::ToString;
1617
1618 #[allow(clippy::unnecessary_wraps)]
1622 fn always_pass() -> Result<(), SelfTestFailure> {
1623 Ok(())
1624 }
1625 fn always_fail() -> Result<(), SelfTestFailure> {
1626 Err(SelfTestFailure)
1627 }
1628
1629 #[test]
1634 fn initial_state_is_power_off() {
1635 let _guard = reset_for_test();
1636 assert_eq!(state(), State::PowerOff);
1637 assert!(!is_operational());
1638 }
1639
1640 #[test]
1641 fn initialize_transitions_to_operational() {
1642 let _guard = reset_for_test();
1643 initialize().unwrap();
1644 assert_eq!(state(), State::Operational);
1645 assert!(is_operational());
1646 require_operational().unwrap();
1647 }
1648
1649 #[test]
1650 fn second_initialize_reports_already_initialized() {
1651 let _guard = reset_for_test();
1652 initialize().unwrap();
1653 match initialize() {
1654 Err(Error::AlreadyInitialized) => {}
1655 other => panic!("expected AlreadyInitialized, got {other:?}"),
1656 }
1657 }
1658
1659 #[test]
1660 fn require_operational_rejects_power_off() {
1661 let _guard = reset_for_test();
1662 match require_operational() {
1663 Err(Error::NotOperational {
1664 current: State::PowerOff,
1665 }) => {}
1666 other => panic!("expected NotOperational{{PowerOff}}, got {other:?}"),
1667 }
1668 }
1669
1670 #[test]
1671 fn enter_error_state_is_terminal_for_require_operational() {
1672 let _guard = reset_for_test();
1673 initialize().unwrap();
1674 assert!(is_operational());
1675 enter_error_state("unit-test forced failure");
1676 assert_eq!(state(), State::Error);
1677 match require_operational() {
1678 Err(Error::NotOperational {
1679 current: State::Error,
1680 }) => {}
1681 other => panic!("expected NotOperational{{Error}}, got {other:?}"),
1682 }
1683 }
1684
1685 #[test]
1686 fn state_display_is_stable() {
1687 assert_eq!(State::PowerOff.to_string(), "PowerOff");
1690 assert_eq!(State::SelfTest.to_string(), "SelfTest");
1691 assert_eq!(State::Operational.to_string(), "Operational");
1692 assert_eq!(State::Error.to_string(), "Error");
1693 }
1694
1695 #[test]
1696 fn registry_runs_passing_tests_and_reaches_operational() {
1697 let _guard = reset_for_test();
1698 let tests = [
1699 KatEntry {
1700 name: "dummy-pass-a",
1701 run: always_pass,
1702 },
1703 KatEntry {
1704 name: "dummy-pass-b",
1705 run: always_pass,
1706 },
1707 ];
1708 initialize_with_tests(&tests).unwrap();
1709 assert_eq!(state(), State::Operational);
1710 }
1711
1712 #[test]
1713 fn registry_failing_test_latches_error_and_returns_name() {
1714 let _guard = reset_for_test();
1715 let tests = [
1716 KatEntry {
1717 name: "dummy-pass",
1718 run: always_pass,
1719 },
1720 KatEntry {
1721 name: "dummy-fail",
1722 run: always_fail,
1723 },
1724 KatEntry {
1726 name: "dummy-unreached",
1727 run: always_pass,
1728 },
1729 ];
1730 match initialize_with_tests(&tests) {
1731 Err(Error::SelfTestFailed { test: "dummy-fail" }) => {}
1732 other => panic!("expected SelfTestFailed{{dummy-fail}}, got {other:?}"),
1733 }
1734 assert_eq!(state(), State::Error);
1735 assert!(matches!(
1737 require_operational(),
1738 Err(Error::NotOperational {
1739 current: State::Error
1740 })
1741 ));
1742 }
1743
1744 struct DummyTest;
1747 impl SelfTest for DummyTest {
1748 const NAME: &'static str = "dummy-trait-vector";
1749 fn run() -> Result<(), SelfTestFailure> {
1750 Ok(())
1751 }
1752 }
1753
1754 #[test]
1755 fn dummy_self_test_trait_is_usable() {
1756 assert_eq!(DummyTest::NAME, "dummy-trait-vector");
1757 DummyTest::run().unwrap();
1758 }
1759
1760 #[test]
1765 fn default_profile_is_unrestricted() {
1766 let _guard = reset_for_test();
1767 assert_eq!(active_profile(), AlgorithmProfile::Unrestricted);
1768 }
1769
1770 #[test]
1771 fn initialize_with_profile_sets_cnsa2() {
1772 let _guard = reset_for_test();
1773 initialize_with_profile(&[], AlgorithmProfile::Cnsa2).unwrap();
1774 assert_eq!(active_profile(), AlgorithmProfile::Cnsa2);
1775 assert!(is_operational());
1776 }
1777
1778 #[test]
1779 fn initialize_with_profile_sets_cnsa1() {
1780 let _guard = reset_for_test();
1781 initialize_with_profile(&[], AlgorithmProfile::Cnsa1).unwrap();
1782 assert_eq!(active_profile(), AlgorithmProfile::Cnsa1);
1783 assert!(is_operational());
1784 }
1785
1786 #[test]
1787 fn unrestricted_allows_all_services() {
1788 let spot = [
1790 Service::Sha1,
1791 Service::Sha256,
1792 Service::Aes128Ecb,
1793 Service::Aes256Gcm,
1794 Service::CtrDrbgAes128,
1795 Service::EcdsaP256Sign,
1796 Service::Ed25519Sign,
1797 Service::RsaPssSign2048,
1798 Service::MlKem1024Encaps,
1799 Service::LmsSha256M32H10W4Sign,
1800 Service::Dh3072,
1801 Service::SlhDsaSha2256sSign,
1802 Service::Tls12Kdf,
1803 Service::Tls13Kdf,
1804 ];
1805 for svc in spot {
1806 assert!(
1807 is_allowed(AlgorithmProfile::Unrestricted, svc),
1808 "{svc} should be allowed in Unrestricted"
1809 );
1810 }
1811 }
1812
1813 #[test]
1814 fn cnsa2_allows_aes256_and_pq() {
1815 let allowed = [
1816 Service::Aes256Gcm,
1817 Service::Aes256Cbc,
1818 Service::Sha384,
1819 Service::Sha512,
1820 Service::Sha3_384,
1821 Service::Sha3_512,
1822 Service::HmacSha384,
1823 Service::HmacSha512,
1824 Service::CtrDrbgAes256,
1825 Service::HashDrbgSha384,
1826 Service::HmacDrbgSha512,
1827 Service::Kmac256,
1828 Service::KmacXof256,
1829 Service::MlKem1024Encaps,
1830 Service::MlKem1024Decaps,
1831 Service::MlKem1024Keygen,
1832 Service::MlDsa87Sign,
1833 Service::MlDsa87Verify,
1834 Service::MlDsa87Keygen,
1835 Service::LmsSha256M32H10W4Sign,
1836 Service::LmsSha256M32H10W4Verify,
1837 Service::XmssSign,
1838 Service::XmssVerify,
1839 Service::Tls13Kdf,
1840 ];
1841 for svc in allowed {
1842 assert!(
1843 is_allowed(AlgorithmProfile::Cnsa2, svc),
1844 "{svc} should be allowed in CNSA 2.0"
1845 );
1846 }
1847 }
1848
1849 #[test]
1850 fn cnsa2_blocks_classical_and_small_keys() {
1851 let blocked = [
1852 Service::Sha1,
1853 Service::Sha224,
1854 Service::Sha256,
1855 Service::Sha512_224,
1856 Service::Sha512_256,
1857 Service::Sha3_224,
1858 Service::Sha3_256,
1859 Service::Shake128,
1860 Service::Kmac128,
1861 Service::Aes128Ecb,
1862 Service::Aes128Gcm,
1863 Service::Aes192Cbc,
1864 Service::CtrDrbgAes128,
1865 Service::CtrDrbgAes192,
1866 Service::HashDrbgSha256,
1867 Service::HmacDrbgSha256,
1868 Service::HmacSha1,
1869 Service::HmacSha256,
1870 Service::CmacAes128,
1871 Service::CmacAes192,
1872 Service::EcdsaP256Sign,
1873 Service::EcdsaP256Verify,
1874 Service::EcdhP256,
1875 Service::Ed25519Sign,
1876 Service::Ed25519Verify,
1877 Service::RsaPssSign2048,
1878 Service::RsaOaep2048,
1879 Service::Tls12Kdf,
1880 Service::SlhDsaSha2128sSign,
1882 Service::MlDsa44Sign,
1883 Service::MlDsa44Verify,
1884 Service::MlDsa44Keygen,
1885 Service::MlDsa65Sign,
1886 Service::MlDsa65Verify,
1887 Service::MlDsa65Keygen,
1888 ];
1889 for svc in blocked {
1890 assert!(
1891 !is_allowed(AlgorithmProfile::Cnsa2, svc),
1892 "{svc} should be BLOCKED in CNSA 2.0"
1893 );
1894 }
1895 }
1896
1897 #[test]
1898 fn cnsa1_allows_p384_rsa3072_and_pq() {
1899 let allowed = [
1900 Service::Aes256Gcm,
1901 Service::Sha384,
1902 Service::Sha256,
1903 Service::EcdsaP384Sign,
1904 Service::EcdsaP384Verify,
1905 Service::EcdsaP384Keygen,
1906 Service::EcdhP384,
1907 Service::RsaPssSign3072,
1908 Service::RsaOaep3072,
1909 Service::RsaPssSign4096,
1910 Service::Dh3072,
1911 Service::MlKem1024Encaps,
1912 Service::LmsSha256M32H10W4Sign,
1913 Service::Tls13Kdf,
1914 ];
1915 for svc in allowed {
1916 assert!(
1917 is_allowed(AlgorithmProfile::Cnsa1, svc),
1918 "{svc} should be allowed in CNSA 1.0"
1919 );
1920 }
1921 }
1922
1923 #[test]
1924 fn cnsa1_blocks_small_keys_and_ed25519() {
1925 let blocked = [
1926 Service::Sha1,
1927 Service::Sha224,
1928 Service::Aes128Ecb,
1929 Service::Aes192Gcm,
1930 Service::CtrDrbgAes128,
1931 Service::EcdsaP256Sign,
1932 Service::EcdhP256,
1933 Service::Ed25519Sign,
1934 Service::Ed25519Verify,
1935 Service::RsaPssSign2048,
1936 Service::RsaOaep2048,
1937 Service::Tls12Kdf,
1938 ];
1939 for svc in blocked {
1940 assert!(
1941 !is_allowed(AlgorithmProfile::Cnsa1, svc),
1942 "{svc} should be BLOCKED in CNSA 1.0"
1943 );
1944 }
1945 }
1946
1947 #[allow(clippy::too_many_lines)]
1951 fn lms_all_160() -> [Service; 160] {
1952 [
1953 Service::LmsSha256M32H5W1Sign,
1955 Service::LmsSha256M32H5W1Verify,
1956 Service::LmsSha256M32H5W2Sign,
1957 Service::LmsSha256M32H5W2Verify,
1958 Service::LmsSha256M32H5W4Sign,
1959 Service::LmsSha256M32H5W4Verify,
1960 Service::LmsSha256M32H5W8Sign,
1961 Service::LmsSha256M32H5W8Verify,
1962 Service::LmsSha256M32H10W1Sign,
1963 Service::LmsSha256M32H10W1Verify,
1964 Service::LmsSha256M32H10W2Sign,
1965 Service::LmsSha256M32H10W2Verify,
1966 Service::LmsSha256M32H10W4Sign,
1967 Service::LmsSha256M32H10W4Verify,
1968 Service::LmsSha256M32H10W8Sign,
1969 Service::LmsSha256M32H10W8Verify,
1970 Service::LmsSha256M32H15W1Sign,
1971 Service::LmsSha256M32H15W1Verify,
1972 Service::LmsSha256M32H15W2Sign,
1973 Service::LmsSha256M32H15W2Verify,
1974 Service::LmsSha256M32H15W4Sign,
1975 Service::LmsSha256M32H15W4Verify,
1976 Service::LmsSha256M32H15W8Sign,
1977 Service::LmsSha256M32H15W8Verify,
1978 Service::LmsSha256M32H20W1Sign,
1979 Service::LmsSha256M32H20W1Verify,
1980 Service::LmsSha256M32H20W2Sign,
1981 Service::LmsSha256M32H20W2Verify,
1982 Service::LmsSha256M32H20W4Sign,
1983 Service::LmsSha256M32H20W4Verify,
1984 Service::LmsSha256M32H20W8Sign,
1985 Service::LmsSha256M32H20W8Verify,
1986 Service::LmsSha256M32H25W1Sign,
1987 Service::LmsSha256M32H25W1Verify,
1988 Service::LmsSha256M32H25W2Sign,
1989 Service::LmsSha256M32H25W2Verify,
1990 Service::LmsSha256M32H25W4Sign,
1991 Service::LmsSha256M32H25W4Verify,
1992 Service::LmsSha256M32H25W8Sign,
1993 Service::LmsSha256M32H25W8Verify,
1994 Service::LmsSha256M24H5W1Sign,
1996 Service::LmsSha256M24H5W1Verify,
1997 Service::LmsSha256M24H5W2Sign,
1998 Service::LmsSha256M24H5W2Verify,
1999 Service::LmsSha256M24H5W4Sign,
2000 Service::LmsSha256M24H5W4Verify,
2001 Service::LmsSha256M24H5W8Sign,
2002 Service::LmsSha256M24H5W8Verify,
2003 Service::LmsSha256M24H10W1Sign,
2004 Service::LmsSha256M24H10W1Verify,
2005 Service::LmsSha256M24H10W2Sign,
2006 Service::LmsSha256M24H10W2Verify,
2007 Service::LmsSha256M24H10W4Sign,
2008 Service::LmsSha256M24H10W4Verify,
2009 Service::LmsSha256M24H10W8Sign,
2010 Service::LmsSha256M24H10W8Verify,
2011 Service::LmsSha256M24H15W1Sign,
2012 Service::LmsSha256M24H15W1Verify,
2013 Service::LmsSha256M24H15W2Sign,
2014 Service::LmsSha256M24H15W2Verify,
2015 Service::LmsSha256M24H15W4Sign,
2016 Service::LmsSha256M24H15W4Verify,
2017 Service::LmsSha256M24H15W8Sign,
2018 Service::LmsSha256M24H15W8Verify,
2019 Service::LmsSha256M24H20W1Sign,
2020 Service::LmsSha256M24H20W1Verify,
2021 Service::LmsSha256M24H20W2Sign,
2022 Service::LmsSha256M24H20W2Verify,
2023 Service::LmsSha256M24H20W4Sign,
2024 Service::LmsSha256M24H20W4Verify,
2025 Service::LmsSha256M24H20W8Sign,
2026 Service::LmsSha256M24H20W8Verify,
2027 Service::LmsSha256M24H25W1Sign,
2028 Service::LmsSha256M24H25W1Verify,
2029 Service::LmsSha256M24H25W2Sign,
2030 Service::LmsSha256M24H25W2Verify,
2031 Service::LmsSha256M24H25W4Sign,
2032 Service::LmsSha256M24H25W4Verify,
2033 Service::LmsSha256M24H25W8Sign,
2034 Service::LmsSha256M24H25W8Verify,
2035 Service::LmsShakeM32H5W1Sign,
2037 Service::LmsShakeM32H5W1Verify,
2038 Service::LmsShakeM32H5W2Sign,
2039 Service::LmsShakeM32H5W2Verify,
2040 Service::LmsShakeM32H5W4Sign,
2041 Service::LmsShakeM32H5W4Verify,
2042 Service::LmsShakeM32H5W8Sign,
2043 Service::LmsShakeM32H5W8Verify,
2044 Service::LmsShakeM32H10W1Sign,
2045 Service::LmsShakeM32H10W1Verify,
2046 Service::LmsShakeM32H10W2Sign,
2047 Service::LmsShakeM32H10W2Verify,
2048 Service::LmsShakeM32H10W4Sign,
2049 Service::LmsShakeM32H10W4Verify,
2050 Service::LmsShakeM32H10W8Sign,
2051 Service::LmsShakeM32H10W8Verify,
2052 Service::LmsShakeM32H15W1Sign,
2053 Service::LmsShakeM32H15W1Verify,
2054 Service::LmsShakeM32H15W2Sign,
2055 Service::LmsShakeM32H15W2Verify,
2056 Service::LmsShakeM32H15W4Sign,
2057 Service::LmsShakeM32H15W4Verify,
2058 Service::LmsShakeM32H15W8Sign,
2059 Service::LmsShakeM32H15W8Verify,
2060 Service::LmsShakeM32H20W1Sign,
2061 Service::LmsShakeM32H20W1Verify,
2062 Service::LmsShakeM32H20W2Sign,
2063 Service::LmsShakeM32H20W2Verify,
2064 Service::LmsShakeM32H20W4Sign,
2065 Service::LmsShakeM32H20W4Verify,
2066 Service::LmsShakeM32H20W8Sign,
2067 Service::LmsShakeM32H20W8Verify,
2068 Service::LmsShakeM32H25W1Sign,
2069 Service::LmsShakeM32H25W1Verify,
2070 Service::LmsShakeM32H25W2Sign,
2071 Service::LmsShakeM32H25W2Verify,
2072 Service::LmsShakeM32H25W4Sign,
2073 Service::LmsShakeM32H25W4Verify,
2074 Service::LmsShakeM32H25W8Sign,
2075 Service::LmsShakeM32H25W8Verify,
2076 Service::LmsShakeM24H5W1Sign,
2078 Service::LmsShakeM24H5W1Verify,
2079 Service::LmsShakeM24H5W2Sign,
2080 Service::LmsShakeM24H5W2Verify,
2081 Service::LmsShakeM24H5W4Sign,
2082 Service::LmsShakeM24H5W4Verify,
2083 Service::LmsShakeM24H5W8Sign,
2084 Service::LmsShakeM24H5W8Verify,
2085 Service::LmsShakeM24H10W1Sign,
2086 Service::LmsShakeM24H10W1Verify,
2087 Service::LmsShakeM24H10W2Sign,
2088 Service::LmsShakeM24H10W2Verify,
2089 Service::LmsShakeM24H10W4Sign,
2090 Service::LmsShakeM24H10W4Verify,
2091 Service::LmsShakeM24H10W8Sign,
2092 Service::LmsShakeM24H10W8Verify,
2093 Service::LmsShakeM24H15W1Sign,
2094 Service::LmsShakeM24H15W1Verify,
2095 Service::LmsShakeM24H15W2Sign,
2096 Service::LmsShakeM24H15W2Verify,
2097 Service::LmsShakeM24H15W4Sign,
2098 Service::LmsShakeM24H15W4Verify,
2099 Service::LmsShakeM24H15W8Sign,
2100 Service::LmsShakeM24H15W8Verify,
2101 Service::LmsShakeM24H20W1Sign,
2102 Service::LmsShakeM24H20W1Verify,
2103 Service::LmsShakeM24H20W2Sign,
2104 Service::LmsShakeM24H20W2Verify,
2105 Service::LmsShakeM24H20W4Sign,
2106 Service::LmsShakeM24H20W4Verify,
2107 Service::LmsShakeM24H20W8Sign,
2108 Service::LmsShakeM24H20W8Verify,
2109 Service::LmsShakeM24H25W1Sign,
2110 Service::LmsShakeM24H25W1Verify,
2111 Service::LmsShakeM24H25W2Sign,
2112 Service::LmsShakeM24H25W2Verify,
2113 Service::LmsShakeM24H25W4Sign,
2114 Service::LmsShakeM24H25W4Verify,
2115 Service::LmsShakeM24H25W8Sign,
2116 Service::LmsShakeM24H25W8Verify,
2117 ]
2118 }
2119
2120 #[test]
2121 fn lms_gating_is_exhaustive_across_all_160_variants() {
2122 let all_160 = lms_all_160();
2129 assert_eq!(all_160.len(), 160, "LMS enumeration drift");
2130
2131 for svc in all_160 {
2132 assert!(
2134 is_allowed(AlgorithmProfile::Unrestricted, svc),
2135 "{svc} must be allowed in Unrestricted"
2136 );
2137
2138 assert!(
2141 is_allowed(AlgorithmProfile::Cnsa2, svc),
2142 "{svc} must be allowed in CNSA 2.0"
2143 );
2144
2145 assert!(
2147 is_allowed(AlgorithmProfile::Cnsa1, svc),
2148 "{svc} must be allowed in CNSA 1.0"
2149 );
2150 }
2151 }
2152
2153 #[test]
2154 fn lms_discriminant_block_is_contiguous_and_pure() {
2155 let mut discriminants = [0u16; 160];
2161 for (slot, svc) in discriminants.iter_mut().zip(lms_all_160()) {
2162 *slot = svc as u16;
2163 }
2164 discriminants.sort_unstable();
2165
2166 let mut compared = 0usize;
2170 for pair in discriminants.windows(2) {
2171 let [lo, hi] = pair else {
2172 unreachable!("windows(2) yields two-element slices")
2173 };
2174 assert!(hi > lo, "duplicate LMS discriminant {lo}");
2175 compared += 1;
2176 }
2177 assert_eq!(compared, 159, "distinctness sweep did not run in full");
2178
2179 let (Some(&first), Some(&last)) = (discriminants.first(), discriminants.last()) else {
2180 unreachable!("the array holds 160 elements")
2181 };
2182 assert_eq!(first, 500, "LMS block does not start at 500");
2183 assert_eq!(last, 659, "LMS block does not end at 659");
2184 assert_eq!(last - first + 1, 160, "LMS block is not contiguous");
2187
2188 for svc in lms_all_160() {
2189 assert!(is_lms_service(svc), "{svc} must be inside the LMS range");
2190 }
2191
2192 for svc in [
2195 Service::SlhDsaShake256fVerify,
2196 Service::XmssSign,
2197 Service::XmssVerify,
2198 Service::Dh3072,
2199 ] {
2200 assert!(!is_lms_service(svc), "{svc} must be outside the LMS range");
2201 }
2202 }
2203
2204 #[test]
2205 fn slh_dsa_gating_is_exhaustive_across_all_36_variants() {
2206 let all_36 = [
2214 Service::SlhDsaSha2256sKeygen,
2216 Service::SlhDsaSha2256sSign,
2217 Service::SlhDsaSha2256sVerify,
2218 Service::SlhDsaSha2128sKeygen,
2219 Service::SlhDsaSha2128sSign,
2220 Service::SlhDsaSha2128sVerify,
2221 Service::SlhDsaSha2128fKeygen,
2222 Service::SlhDsaSha2128fSign,
2223 Service::SlhDsaSha2128fVerify,
2224 Service::SlhDsaSha2192sKeygen,
2225 Service::SlhDsaSha2192sSign,
2226 Service::SlhDsaSha2192sVerify,
2227 Service::SlhDsaSha2192fKeygen,
2228 Service::SlhDsaSha2192fSign,
2229 Service::SlhDsaSha2192fVerify,
2230 Service::SlhDsaSha2256fKeygen,
2231 Service::SlhDsaSha2256fSign,
2232 Service::SlhDsaSha2256fVerify,
2233 Service::SlhDsaShake128sKeygen,
2235 Service::SlhDsaShake128sSign,
2236 Service::SlhDsaShake128sVerify,
2237 Service::SlhDsaShake128fKeygen,
2238 Service::SlhDsaShake128fSign,
2239 Service::SlhDsaShake128fVerify,
2240 Service::SlhDsaShake192sKeygen,
2241 Service::SlhDsaShake192sSign,
2242 Service::SlhDsaShake192sVerify,
2243 Service::SlhDsaShake192fKeygen,
2244 Service::SlhDsaShake192fSign,
2245 Service::SlhDsaShake192fVerify,
2246 Service::SlhDsaShake256sKeygen,
2247 Service::SlhDsaShake256sSign,
2248 Service::SlhDsaShake256sVerify,
2249 Service::SlhDsaShake256fKeygen,
2250 Service::SlhDsaShake256fSign,
2251 Service::SlhDsaShake256fVerify,
2252 ];
2253 assert_eq!(all_36.len(), 36, "SLH-DSA enumeration drift");
2254
2255 for svc in all_36 {
2256 assert!(
2258 is_allowed(AlgorithmProfile::Unrestricted, svc),
2259 "{svc} must be allowed in Unrestricted"
2260 );
2261
2262 assert!(
2264 !is_allowed(AlgorithmProfile::Cnsa1, svc),
2265 "{svc} must be BLOCKED in CNSA 1.0"
2266 );
2267
2268 assert!(
2272 !is_allowed(AlgorithmProfile::Cnsa2, svc),
2273 "{svc} must be BLOCKED in CNSA 2.0"
2274 );
2275 }
2276 }
2277
2278 #[test]
2279 fn require_allowed_returns_restricted_error_under_cnsa2() {
2280 let _guard = reset_for_test();
2281 initialize_with_profile(&[], AlgorithmProfile::Cnsa2).unwrap();
2282 match require_allowed(Service::Aes128Ecb) {
2283 Err(Error::AlgorithmRestricted {
2284 service: Service::Aes128Ecb,
2285 }) => {}
2286 other => panic!("expected AlgorithmRestricted(Aes128Ecb), got {other:?}"),
2287 }
2288 }
2289
2290 #[test]
2291 fn require_allowed_passes_permitted_services() {
2292 let _guard = reset_for_test();
2293 initialize_with_profile(&[], AlgorithmProfile::Cnsa2).unwrap();
2294 require_allowed(Service::Aes256Gcm).unwrap();
2295 require_allowed(Service::Sha384).unwrap();
2296 require_allowed(Service::MlKem1024Encaps).unwrap();
2297 }
2298
2299 #[test]
2300 fn require_allowed_passes_everything_in_unrestricted() {
2301 let _guard = reset_for_test();
2302 initialize().unwrap();
2303 require_allowed(Service::Sha1).unwrap();
2305 require_allowed(Service::Aes128Ecb).unwrap();
2306 require_allowed(Service::Ed25519Sign).unwrap();
2307 require_allowed(Service::MlKem1024Encaps).unwrap();
2308 }
2309
2310 #[test]
2316 fn require_allowed_refuses_every_slh_dsa_service_under_cnsa2() {
2317 let guard = reset_for_test();
2318 for profile in [AlgorithmProfile::Cnsa2, AlgorithmProfile::Cnsa1] {
2319 guard.reset();
2320 initialize_with_profile(&[], profile).unwrap();
2321 for svc in [
2322 Service::SlhDsaSha2256sKeygen,
2323 Service::SlhDsaSha2256sSign,
2324 Service::SlhDsaSha2256sVerify,
2325 Service::SlhDsaShake128fVerify,
2326 ] {
2327 match require_allowed(svc) {
2328 Err(Error::AlgorithmRestricted { service }) => assert_eq!(service, svc),
2329 other => {
2330 panic!("expected AlgorithmRestricted({svc}) under {profile}, got {other:?}")
2331 }
2332 }
2333 }
2334 }
2335 }
2336
2337 #[test]
2341 fn require_allowed_admits_lms_m24_under_both_cnsa_profiles() {
2342 let guard = reset_for_test();
2343 for profile in [AlgorithmProfile::Cnsa2, AlgorithmProfile::Cnsa1] {
2344 guard.reset();
2345 initialize_with_profile(&[], profile).unwrap();
2346 for svc in [
2347 Service::LmsSha256M24H5W1Sign,
2348 Service::LmsSha256M24H25W8Verify,
2349 Service::LmsShakeM24H10W4Sign,
2350 Service::LmsShakeM24H25W8Verify,
2351 ] {
2352 require_allowed(svc)
2353 .unwrap_or_else(|e| panic!("{svc} must be allowed under {profile}: {e:?}"));
2354 }
2355 }
2356 }
2357
2358 #[test]
2365 fn lms_block_boundaries_are_exact() {
2366 assert!(!lms_block_contains(499), "499 is below the LMS block");
2367 assert!(lms_block_contains(500), "500 is the first LMS discriminant");
2368 assert!(lms_block_contains(659), "659 is the last LMS discriminant");
2369 assert!(!lms_block_contains(660), "660 is above the LMS block");
2370
2371 assert_eq!(Service::LmsSha256M32H5W1Sign as u16, 500);
2373 assert_eq!(Service::LmsShakeM24H25W8Verify as u16, 659);
2374 }
2375
2376 #[test]
2381 fn require_allowed_distinguishes_cnsa1_from_cnsa2() {
2382 let guard = reset_for_test();
2383
2384 initialize_with_profile(&[], AlgorithmProfile::Cnsa1).unwrap();
2385 require_allowed(Service::EcdsaP384Sign)
2386 .unwrap_or_else(|e| panic!("P-384 ECDSA must be permitted under CNSA 1.0: {e:?}"));
2387
2388 guard.reset();
2389 initialize_with_profile(&[], AlgorithmProfile::Cnsa2).unwrap();
2390 match require_allowed(Service::EcdsaP384Sign) {
2391 Err(Error::AlgorithmRestricted {
2392 service: Service::EcdsaP384Sign,
2393 }) => {}
2394 other => panic!("expected P-384 ECDSA refused under CNSA 2.0, got {other:?}"),
2395 }
2396 }
2397
2398 #[test]
2399 fn algorithm_profile_display() {
2400 assert_eq!(AlgorithmProfile::Unrestricted.to_string(), "Unrestricted");
2401 assert_eq!(AlgorithmProfile::Cnsa2.to_string(), "CNSA 2.0");
2402 assert_eq!(AlgorithmProfile::Cnsa1.to_string(), "CNSA 1.0");
2403 }
2404
2405 #[test]
2406 fn algorithm_restricted_error_display() {
2407 let _guard = reset_for_test();
2408 initialize_with_profile(&[], AlgorithmProfile::Cnsa2).unwrap();
2409 let err = Error::AlgorithmRestricted {
2410 service: Service::Aes128Ecb,
2411 };
2412 let msg = err.to_string();
2413 assert!(msg.contains("AES-128-ECB"), "got: {msg}");
2414 assert!(msg.contains("CNSA 2.0"), "got: {msg}");
2415 }
2416
2417 #[test]
2418 fn not_implemented_error_display() {
2419 let err = Error::NotImplemented;
2420 assert_eq!(err.to_string(), "algorithm not yet implemented");
2421 }
2422
2423 #[test]
2424 fn service_display_is_stable() {
2425 assert_eq!(Service::Sha256.to_string(), "SHA-256");
2427 assert_eq!(Service::Aes256Gcm.to_string(), "AES-256-GCM");
2428 assert_eq!(Service::MlKem1024Encaps.to_string(), "ML-KEM-1024 encaps");
2429 assert_eq!(Service::Ed25519Sign.to_string(), "Ed25519 sign");
2430 }
2431}