diff --git a/pq_logic/keys/abstract_pq.py b/pq_logic/keys/abstract_pq.py index bdd93700..70d40b82 100644 --- a/pq_logic/keys/abstract_pq.py +++ b/pq_logic/keys/abstract_pq.py @@ -88,6 +88,11 @@ def sig_size(self) -> int: """Return the size of the signature.""" return self._sig_method.details["length_signature"] + @property + def nist_level(self) -> int: + """Return the claimed NIST security level as int.""" + return int(self._sig_method.details["claimed_nist_level"]) + class PQSignaturePrivateKey(PQPrivateKey, ABC): """Abstract base class for Post-Quantum Signature Private Keys.""" @@ -162,6 +167,11 @@ def from_private_bytes(cls, data: bytes, name: str) -> "PQSignaturePrivateKey": raise ValueError(f"Invalid key size expected {key.key_size}, but got: {len(data)}") return key + @property + def nist_level(self) -> int: + """Return the claimed NIST security level as int.""" + return self.public_key().nist_level + class PQKEMPublicKey(PQPublicKey, KEMPublicKey, ABC): """Abstract base class for Post-Quantum KEM Public Keys.""" @@ -204,7 +214,7 @@ def encaps(self) -> Tuple[bytes, bytes]: @property def nist_level(self) -> int: - """Return the claimed NIST security level as string.""" + """Return the claimed NIST security level as int.""" return int(self._kem_method.details["claimed_nist_level"]) @@ -272,7 +282,7 @@ def public_key(self) -> PQKEMPublicKey: @property def nist_level(self) -> int: - """Return the claimed NIST security level as string.""" + """Return the claimed NIST security level as int.""" return self.public_key().nist_level @staticmethod diff --git a/pq_logic/keys/abstract_stateful_hash_sig.py b/pq_logic/keys/abstract_stateful_hash_sig.py index a63ab54d..e81b2946 100644 --- a/pq_logic/keys/abstract_stateful_hash_sig.py +++ b/pq_logic/keys/abstract_stateful_hash_sig.py @@ -73,6 +73,11 @@ def max_sig_size(self) -> int: def hash_alg(self) -> str: """Return the hash algorithm used by this public key.""" + @property + @abstractmethod + def key_bit_security(self) -> int: + """Return the estimated security strength in bits.""" + class PQHashStatefulSigPrivateKey(PQPrivateKey, ABC): """Abstract base class for Post-Quantum Hash Stateful Signature Private Keys.""" @@ -131,3 +136,8 @@ def used_keys(self) -> list[bytes]: def hash_alg(self) -> str: """Return the hash algorithm used by this private key.""" return self.public_key().hash_alg + + @property + def key_bit_security(self) -> int: + """Return the estimated security strength in bits.""" + return self.public_key().key_bit_security diff --git a/pq_logic/keys/sig_keys.py b/pq_logic/keys/sig_keys.py index 8cbd2719..6e870ea1 100644 --- a/pq_logic/keys/sig_keys.py +++ b/pq_logic/keys/sig_keys.py @@ -187,6 +187,12 @@ def from_public_bytes(cls, data: bytes, name: str) -> "MLDSAPublicKey": ) return key + @property + def nist_level(self) -> int: + """Return the NIST security level of the ML-DSA algorithm.""" + nist_levels = {"ml-dsa-44": 2, "ml-dsa-65": 3, "ml-dsa-87": 5} + return nist_levels[self.name] + ML_DSA_PRIVATE_KEY_SIZE = {"ml-dsa-44": 2560, "ml-dsa-65": 4032, "ml-dsa-87": 4896} @@ -405,6 +411,10 @@ def seed_size(self) -> int: """Return the size of the seed used for ML-DSA key generation.""" return self._seed_size(name=self.name) + def nist_level(self) -> int: + """Return the NIST security level of the ML-DSA algorithm.""" + return self.public_key().nist_level + ########################## # SLH-DSA @@ -562,6 +572,19 @@ def from_public_bytes(cls, data: bytes, name: str) -> "SLHDSAPublicKey": raise ValueError(f"Invalid public key size. Expected: {_n}, got: {len(data)}") return key + @property + def nist_level(self) -> int: + """Return the NIST security level of the SLH-DSA algorithm.""" + if oqs is not None: + return super().nist_level + if self.name.endswith("128s") or self.name.endswith("128f"): + return 1 + if self.name.endswith("192s") or self.name.endswith("192f"): + return 3 + if self.name.endswith("256s") or self.name.endswith("256f"): + return 5 + raise ValueError(f"Cannot determine NIST level for SLH-DSA algorithm: {self.name}") + class SLHDSAPrivateKey(PQSignaturePrivateKey): """Represents an SLH-DSA private key.""" @@ -805,6 +828,10 @@ def seed_size(self) -> int: """Return the size of the seed used for SLH-DSA key generation.""" return self._seed_size(name=self.name) + def nist_level(self) -> int: + """Return the NIST security level of the SLH-DSA algorithm.""" + return self.public_key().nist_level + ########################## # Falcon diff --git a/pq_logic/keys/stateful_sig_keys.py b/pq_logic/keys/stateful_sig_keys.py index 816efed0..f2db9231 100644 --- a/pq_logic/keys/stateful_sig_keys.py +++ b/pq_logic/keys/stateful_sig_keys.py @@ -20,6 +20,7 @@ from pyhsslms.pyhsslms import LenI from pyhsslms.pyhsslms import lmots_params as PYHSSLMS_LMOTS_PARAMS from pyhsslms.pyhsslms import lms_params as PYHSSLMS_LMS_PARAMS +from robot.api.deco import not_keyword from pq_logic.keys.abstract_stateful_hash_sig import PQHashStatefulSigPrivateKey, PQHashStatefulSigPublicKey from resources.exceptions import InvalidKeyData @@ -284,6 +285,7 @@ def _compute_hss_signature_length(details: Dict[str, int], levels: int) -> int: return 4 + max(levels - 1, 0) * (per_sig + per_pub) + per_sig +@not_keyword def compute_hss_signature_index(signature: bytes, key: Union["HSSPrivateKey", "HSSPublicKey"]) -> int: """Return the global HSS signature index and the encoded depth.""" # TODO fix, if needed for different LMS and LMOTS key types. @@ -508,6 +510,12 @@ def hash_alg(self) -> str: return "shake128" return XMSS_ALG_DETAILS[self.name.lower()]["hash_alg"] + @property + def key_bit_security(self) -> int: + """Return the traditional bit security of the XMSS public key.""" + # Approximate bit security based on the hash output size + return int(self.name.split("_")[-1]) // 2 + class XMSSPrivateKey(PQHashStatefulSigPrivateKey): """Class representing an XMSS private key.""" @@ -772,6 +780,12 @@ def hash_alg(self) -> str: """Return the hash algorithm used by this XMSSMT public key.""" return XMSSMT_ALG_DETAILS[self.name.lower()]["hash_alg"] + @property + def key_bit_security(self) -> int: + """Return the pq bit security of the XMSSMT public key.""" + # Approximate bit security based on the hash output size + return XMSSMT_ALG_DETAILS[self.name.lower()]["n"] * 4 + class XMSSMTPrivateKey(PQHashStatefulSigPrivateKey): """Class representing an XMSSMT private key.""" @@ -1085,6 +1099,15 @@ def get_level_names(self) -> Sequence[Tuple[str, str]]: levels = [(lms_name, lmots_name)] * num_levels return levels + @property + def key_bit_security(self) -> int: + """Return the key bit security of this HSS key.""" + # TODO fix for multiple levels with different parameters. + n = self._details["n"] + if n == 24: + return 96 + return 128 + class HSSPrivateKey(PQHashStatefulSigPrivateKey): """Representation of an HSS private key.""" diff --git a/resources/keyutils.py b/resources/keyutils.py index 04e5f4df..e4f0376d 100644 --- a/resources/keyutils.py +++ b/resources/keyutils.py @@ -81,6 +81,7 @@ TRAD_SIG_NAME_2_OID, TRAD_STR_OID_TO_KEY_NAME, ) +from resources.security_utils import estimate_key_security_strength from resources.suiteenums import KeySaveType from resources.typingutils import PrivateKey, PublicKey, SignKey, TradPrivateKey, TradSignKey, TradVerifyKey, VerifyKey @@ -1453,3 +1454,33 @@ def get_pq_stateful_sig_index_from_sig( # noqa D417 undocumented-params return key.get_leaf_index(signature) raise NotImplementedError(f"Unsupported key type for signature index extraction. Got: {type(key).__name__}") + + +@keyword(name="Get Key Security Strength") +def get_key_security_strength( # noqa D417 undocumented-params + key: Union[PrivateKey, PublicKey], +) -> int: + """Return the estimated security strength (in bits) for the provided key. + + Arguments: + --------- + - `key`: The key instance to estimate the security strength for. + + Returns: + ------- + - The estimated security strength in bits. + + Raises: + ------ + - `ValueError`: If the security strength cannot be estimated for the given key type. + - `NotImplementedError`: If the key type is not supported for security strength estimation. + + Examples: + -------- + | ${strength}= | Get Key Security Strength | ${public_key} | + + """ + strength = estimate_key_security_strength(key) + if strength == 0: + raise ValueError(f"Could not estimate security strength for key type: {type(key)}") + return strength diff --git a/resources/oidutils.py b/resources/oidutils.py index 2f939462..a23aef49 100644 --- a/resources/oidutils.py +++ b/resources/oidutils.py @@ -447,7 +447,7 @@ KM_KA_ALG.update(ECMQV) KM_KA_ALG_NAME_2_OID = {y: x for x, y in KM_KA_ALG.items()} -KM_KD_ALG = {rfc9481.id_PBKDF2: "pbkdf2"} # As per Section 4.4 in RFC 9481 +KM_KD_ALG: Dict[univ.ObjectIdentifier, str] = {rfc9481.id_PBKDF2: "pbkdf2"} # As per Section 4.4 in RFC 9481 KM_KW_ALG = { rfc9481.id_aes128_wrap: "aes128_wrap", rfc9481.id_aes192_wrap: "aes192_wrap", @@ -469,6 +469,7 @@ ALL_KNOWN_OIDS_2_NAME.update({rfc6664.id_ecPublicKey: "ecPublicKey"}) ALL_KNOWN_OIDS_2_NAME.update(RFC9481_OID_2_NAME) ALL_KNOWN_OIDS_2_NAME.update(HMAC_NAME_2_OID) +ALL_KNOWN_OIDS_2_NAME.update(OID_HASH_MAP) ########################### @@ -490,7 +491,7 @@ HKDF_OID_2_NAME = {v: k for k, v in HKDF_NAME_2_OID.items()} -KDF_OID_2_NAME = {} +KDF_OID_2_NAME: Dict[univ.ObjectIdentifier, str] = {} KDF_OID_2_NAME.update(KM_KD_ALG) KDF_OID_2_NAME.update(HKDF_OID_2_NAME) KDF_OID_2_NAME.update({rfc9690.id_kdf_kdf3: "kdf3", rfc9690.id_kdf_kdf2: "kdf2"}) diff --git a/resources/security_utils.py b/resources/security_utils.py new file mode 100644 index 00000000..6301eb67 --- /dev/null +++ b/resources/security_utils.py @@ -0,0 +1,195 @@ +# SPDX-FileCopyrightText: Copyright 2025 Siemens AG +# +# SPDX-License-Identifier: Apache-2.0 +# + +"""Contain security-related utility functions, like getting the bit string of a used key.""" + +from typing import Optional, Union + +from cryptography.hazmat.primitives.asymmetric import dsa, ed448, ed25519, rsa, x448, x25519 +from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey +from robot.api.deco import not_keyword + +from pq_logic.keys.abstract_pq import PQKEMPublicKey, PQSignaturePublicKey +from pq_logic.keys.abstract_stateful_hash_sig import PQHashStatefulSigPublicKey +from pq_logic.keys.abstract_wrapper_keys import HybridPublicKey, TradKEMPublicKey +from pq_logic.keys.stateful_sig_keys import HSSPublicKey, XMSSMTPublicKey, XMSSPublicKey +from resources.typingutils import PrivateKey, PublicKey + +# Security strength values follow NIST SP 800-57 Part 1 Revision 5, Tables 2 and 4. +# Table 2 provides the traditional key equivalence for RSA/DSA and ECC key sizes, +# while Table 4 lists the target security strengths for the NIST PQC levels. +_NIST_LEVEL_TO_STRENGTH = { + 1: 128, + 2: 192, + 3: 192, + 4: 256, + 5: 256, +} + +HASH_ALG_TO_STRENGTH = { + "sha1": 80, + "sha224": 112, + "sha256": 128, + "sha384": 192, + "sha512": 256, + "sha3_224": 112, + "sha3_256": 128, + "sha3_384": 192, + "sha3_512": 256, + "shake128": 128, # Uses in CMP 32 Byte as output size. According to RFC 9481. + "shake256": 256, # Uses in CMP 64 Byte as output size. According to RFC 9481. +} + + +def _rsa_security_strength(key_size: int) -> int: + """Return an approximate security strength (in bits) for an RSA and DSA key size. + + Mapping follows NIST SP 800-57 Part 1 Rev. 5 Table 2. + """ + if key_size < 1024: + return 64 + + if key_size <= 1024: + return 80 + + if key_size <= 2048: + return 112 + + if key_size <= 3072: + return 128 + + if key_size <= 7680: + return 192 + + if key_size <= 15360: + return 256 + + return 256 + + +def _ecc_security_strength(key_size: int) -> int: + """Return the security strength (in bits) for an ECC curve size. + + Mapping follows NIST SP 800-57 Part 1 Rev. 5 Table 2. + """ + # Table 2 (ECC column: f is the field size in bits): + # - f = 160–223 -> strength 80 + # - f = 224–255 -> strength 112 + # - f = 256–383 -> strength 128 + # - f = 384–511 -> strength 192 + # - f = 512+ -> strength 256 + if key_size <= 223: + return 80 + + if key_size <= 255: + return 112 + + if key_size <= 383: + return 128 + + if key_size <= 511: + return 192 + + return 256 + + +def _get_pq_stfl_nist_security_strength(key: PQHashStatefulSigPublicKey) -> int: + """Return the PQ security strength (in bits) for a PQ stateful signature key. + + XMSS and XMSS^MT security strength is determined by the hash function output size. + According to RFC 8391 Section 5. Parameter Sets. + The security strength is halved when considering PQ security strength, because of the `Grover` algorithm. + The HSS key size is determined by the used parameter sets. + + :param key: The PQ stateful signature public key. + :return: The security strength in bits. + :raises NotImplementedError: If the key type is not supported. + """ + if isinstance(key, XMSSPublicKey): + return key.key_bit_security + if isinstance(key, XMSSMTPublicKey): + return key.key_bit_security + if isinstance(key, HSSPublicKey): + return key.key_bit_security + + raise NotImplementedError( + f"Security strength estimation is only implemented for XMSS, XMSSMT and HSS keys. Got: {type(key)}" + ) + + +def _nist_level_strength(level: Optional[int]) -> int: + """Convert a claimed NIST level into an approximate security strength. + + Mapping follows NIST SP 800-57 Part 1 Rev. 5 Table 4. + """ + if level is None: + return 0 + + return _NIST_LEVEL_TO_STRENGTH.get(int(level), 0) + + +@not_keyword +def estimate_key_security_strength(key: Union[PrivateKey, PublicKey]) -> int: + """Estimate the security strength of a key in bits. + + :param key: The key to estimate the security strength for. + :return: The estimated security strength in bits. + :raises NotImplementedError: If the key type is not supported for security strength estimation. + """ + if isinstance(key, PrivateKey): + key = key.public_key() + + if isinstance(key, PQHashStatefulSigPublicKey): + return _get_pq_stfl_nist_security_strength(key) + + if isinstance( + key, + ( + PQKEMPublicKey, + PQSignaturePublicKey, + ), + ): + return _nist_level_strength(key.nist_level) + + if hasattr(key, "nist_level"): + return _nist_level_strength(getattr(key, "nist_level")) + + if isinstance(key, rsa.RSAPublicKey): + return _rsa_security_strength(key.key_size) + + if isinstance(key, dsa.DSAPublicKey): + return _rsa_security_strength(key.key_size) + + if isinstance(key, EllipticCurvePublicKey): + return _ecc_security_strength(key.curve.key_size) + + if isinstance( + key, + ( + ed25519.Ed25519PublicKey, + x25519.X25519PublicKey, + ), + ): + return 128 + + if isinstance( + key, + ( + ed448.Ed448PublicKey, + x448.X448PublicKey, + ), + ): + return 224 + + if isinstance(key, TradKEMPublicKey): + return estimate_key_security_strength(key._public_key) + + if isinstance(key, HybridPublicKey): + pq_strength = estimate_key_security_strength(getattr(key, "pq_key")) + trad_strength = estimate_key_security_strength(getattr(key, "trad_key")) + return min(pq_strength, trad_strength) + + else: + raise NotImplementedError(f"Security strength estimation not implemented for key type: {type(key)}") diff --git a/unit_tests/tests_security_strength_related/__init__.py b/unit_tests/tests_security_strength_related/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/unit_tests/tests_security_strength_related/test_get_key_security_strength.py b/unit_tests/tests_security_strength_related/test_get_key_security_strength.py new file mode 100644 index 00000000..3f3d0a76 --- /dev/null +++ b/unit_tests/tests_security_strength_related/test_get_key_security_strength.py @@ -0,0 +1,208 @@ +import unittest + +from resources.keyutils import generate_key, get_key_security_strength + + +# TODO add test cases to get the security strength for HSS keys with different digest output sizes. + +class TestGetKeySecurityStrength(unittest.TestCase): + + def test_rsa_2048_key_strength(self): + """ + GIVEN an RSA 2048 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 112 bits. + """ + key = generate_key("rsa", length=2048) + self.assertEqual(get_key_security_strength(key), 112) + self.assertEqual(get_key_security_strength(key.public_key()), 112) + + def test_rsa_kem_2048_key_strength(self): + """ + GIVEN an RSA-KEM-2048 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 112 bits. + """ + key = generate_key("rsa-kem", length=2048) + self.assertEqual(get_key_security_strength(key), 112) + self.assertEqual(get_key_security_strength(key.public_key()), 112) + + def test_rsa_3072_key_strength(self): + """ + GIVEN an RSA 3072 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 128 bits. + """ + key = generate_key("rsa", length=3072) + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_ecc_p256_key_strength(self): + """ + GIVEN an ECC P-256 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 128 bits. + """ + key = generate_key("ecc", curve="secp256r1") + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_ecc_p384_key_strength(self): + """ + GIVEN an ECC P-384 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 192 bits. + """ + key = generate_key("ecc", curve="secp384r1") + self.assertEqual(get_key_security_strength(key), 192) + self.assertEqual(get_key_security_strength(key.public_key()), 192) + + def test_ed25519_key_strength(self): + """ + GIVEN an Ed25519 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 128 bits. + """ + key = generate_key("ed25519") + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_x25519_key_strength(self): + """ + GIVEN an X25519 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 128 bits. + """ + key = generate_key("x25519") + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_ed448_key_strength(self): + key = generate_key("ed448") + self.assertEqual(get_key_security_strength(key), 224) + self.assertEqual(get_key_security_strength(key.public_key()), 224) + + def test_x448_key_strength(self): + """ + GIVEN an X448 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 224 bits. + """ + key = generate_key("x448") + self.assertEqual(get_key_security_strength(key), 224) + self.assertEqual(get_key_security_strength(key.public_key()), 224) + + def test_xmss_key_sha256_strength(self): + """ + GIVEN an XMSS-SHA2-10-256 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 128 bits. + """ + key = generate_key("xmss-sha2_10_256") + # ensure that the pq_streng flag is always considered. + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_xmss_key_sha192_strength(self): + """ + GIVEN an XMSS-SHA2-10-192 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 96 bits. + """ + key = generate_key("xmss-sha2_10_192") + self.assertEqual(get_key_security_strength(key), 96) + self.assertEqual(get_key_security_strength(key.public_key()), 96) + + def test_hss_key_shake_n24_m24_strength(self): + """ + GIVEN an HSS-SHAKE with LMS and LMOTS digest output size set to 24 bytes. + WHEN get_key_security_strength is called, + THEN is the returned security strength 96 bits. + """ + key = generate_key("hss_lms_shake_m24_h5_lmots_shake_n24_w4") + self.assertEqual(get_key_security_strength(key), 96) + self.assertEqual(get_key_security_strength(key.public_key()), 96) + + def test_hss_key_shake_n32_m32_strength(self): + """ + GIVEN an HSS-SHAKE with LMS and LMOTS digest output size set to 32 bytes. + WHEN get_key_security_strength is called, + THEN is the returned security strength 128 bits. + """ + key = generate_key("hss_lms_shake_m32_h5_lmots_shake_n32_w4") + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_hss_key_sha2_n24_m24_strength(self): + """ + GIVEN an HSS-SHA2 with LMS and LMOTS digest output size set to 24 bytes. + WHEN get_key_security_strength is called, + THEN is the returned security strength 96 bits. + """ + key = generate_key("hss_lms_sha256_m24_h5_lmots_sha256_n24_w8") + self.assertEqual(get_key_security_strength(key), 96) + self.assertEqual(get_key_security_strength(key.public_key()), 96) + + def test_hss_key_sha2_n32_m32_strength(self): + """ + GIVEN an HSS-SHA2 with LMS and LMOTS digest output size set to 32 bytes. + WHEN get_key_security_strength is called, + THEN is the returned security strength 256 bits. + """ + key = generate_key("hss_lms_sha256_m32_h5_lmots_sha256_n32_w8") + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_ml_kem_1024_key_strength(self): + """ + GIVEN an ML-KEM-1024 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 256 bits. + """ + key = generate_key("ml-kem-1024") + self.assertEqual(get_key_security_strength(key), 256) + self.assertEqual(get_key_security_strength(key.public_key()), 256) + + def test_ml_dsa_44_key_strength(self): + """ + GIVEN an ML-DSA-44 key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 256 bits. + """ + key = generate_key("ml-dsa-44") + self.assertEqual(get_key_security_strength(key), 192) + self.assertEqual(get_key_security_strength(key.public_key()), 192) + + def test_slh_dsa_sha2_128f_key_strength(self): + """ + GIVEN an SLH-DSA-SHA2-128f key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 128 bits. + """ + key = generate_key("slh-dsa-sha2-128f") + self.assertEqual(get_key_security_strength(key), 128) + self.assertEqual(get_key_security_strength(key.public_key()), 128) + + def test_slh_dsa_sha2_192f_key_strength(self): + """ + GIVEN an SLH-DSA-SHA2-192f key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 192 bits. + """ + key = generate_key("slh-dsa-sha2-192f") + self.assertEqual(get_key_security_strength(key), 192) + self.assertEqual(get_key_security_strength(key.public_key()), 192) + + def test_slh_dsa_sha2_256f_key_strength(self): + """ + GIVEN an SLH-DSA-SHA2-256f key. + WHEN get_key_security_strength is called, + THEN is the returned security strength 256 bits. + """ + key = generate_key("slh-dsa-sha2-256f") + self.assertEqual(get_key_security_strength(key), 256) + self.assertEqual(get_key_security_strength(key.public_key()), 256) + + +if __name__ == "__main__": + unittest.main()