Unify the code to shorten expressions

The output of generate_psa_tests.py is almost unchanged: the differences are
only spaces after commas (now consistently omitted).

Signed-off-by: Gilles Peskine <Gilles.Peskine@arm.com>
diff --git a/scripts/mbedtls_dev/crypto_knowledge.py b/scripts/mbedtls_dev/crypto_knowledge.py
index 82487d9..f277526 100644
--- a/scripts/mbedtls_dev/crypto_knowledge.py
+++ b/scripts/mbedtls_dev/crypto_knowledge.py
@@ -25,6 +25,20 @@
 from mbedtls_dev.asymmetric_key_data import ASYMMETRIC_KEY_DATA
 
 
+def short_expression(original: str) -> str:
+    """Abbreviate the expression, keeping it human-readable.
+
+    If `level` is 0, just remove parts that are implicit from context,
+    such as a leading ``PSA_KEY_TYPE_``.
+    For larger values of `level`, also abbreviate some names in an
+    unambiguous, but ad hoc way.
+    """
+    short = original
+    short = re.sub(r'\bPSA_(?:ALG|ECC_FAMILY|KEY_[A-Z]+)_', r'', short)
+    short = re.sub(r' +', r'', short)
+    return short
+
+
 BLOCK_CIPHERS = frozenset(['AES', 'ARIA', 'CAMELLIA', 'DES'])
 BLOCK_MAC_MODES = frozenset(['CBC_MAC', 'CMAC'])
 BLOCK_CIPHER_MODES = frozenset([
@@ -104,6 +118,13 @@
         `self.name`.
         """
 
+    def short_expression(self) -> str:
+        """Abbreviate the expression, keeping it human-readable.
+
+        See `crypto_knowledge.short_expression`.
+        """
+        return short_expression(self.expression)
+
     def is_public(self) -> bool:
         """Whether the key type is for public keys."""
         return self.name.endswith('_PUBLIC_KEY')
@@ -376,6 +397,14 @@
         # Assume kdf_alg is either a valid KDF or 0.
         return not re.match(r'(?:0[Xx])?0+\s*\Z', kdf_alg)
 
+
+    def short_expression(self) -> str:
+        """Abbreviate the expression, keeping it human-readable.
+
+        See `crypto_knowledge.short_expression`.
+        """
+        return short_expression(self.expression)
+
     def can_do(self, category: AlgorithmCategory) -> bool:
         """Whether this algorithm fits the specified operation category."""
         if category == self.category:
diff --git a/tests/scripts/generate_psa_tests.py b/tests/scripts/generate_psa_tests.py
index 4875cf9..68cd714 100755
--- a/tests/scripts/generate_psa_tests.py
+++ b/tests/scripts/generate_psa_tests.py
@@ -145,7 +145,7 @@
     """
     hack_dependencies_not_implemented(dependencies)
     tc = test_case.TestCase()
-    short_key_type = re.sub(r'PSA_(KEY_TYPE|ECC_FAMILY)_', r'', key_type)
+    short_key_type = crypto_knowledge.short_expression(key_type)
     adverb = 'not' if dependencies else 'never'
     if param_descr:
         adverb = param_descr + ' ' + adverb
@@ -243,7 +243,7 @@
     """
     hack_dependencies_not_implemented(dependencies)
     tc = test_case.TestCase()
-    short_key_type = re.sub(r'PSA_(KEY_TYPE|ECC_FAMILY)_', r'', key_type)
+    short_key_type = crypto_knowledge.short_expression(key_type)
     tc.set_description('PSA {} {}-bit'
                        .format(short_key_type, bits))
     tc.set_dependencies(dependencies)
@@ -335,7 +335,7 @@
         """Construct a failure test case for a one-key or keyless operation."""
         #pylint: disable=too-many-arguments,too-many-locals
         tc = test_case.TestCase()
-        pretty_alg = re.sub(r'PSA_ALG_', r'', alg.expression)
+        pretty_alg = alg.short_expression()
         if reason == self.Reason.NOT_SUPPORTED:
             short_deps = [re.sub(r'PSA_WANT_ALG_', r'', dep)
                           for dep in not_deps]
@@ -344,7 +344,7 @@
             pretty_reason = reason.name.lower()
         if kt:
             key_type = kt.expression
-            pretty_type = re.sub(r'PSA_KEY_TYPE_', r'', key_type)
+            pretty_type = kt.short_expression()
         else:
             key_type = ''
             pretty_type = ''
@@ -568,7 +568,7 @@
         short = lifetime
         short = re.sub(r'PSA_KEY_LIFETIME_FROM_PERSISTENCE_AND_LOCATION',
                        r'', short)
-        short = re.sub(r'PSA_KEY_[A-Z]+_', r'', short)
+        short = crypto_knowledge.short_expression(short)
         description = 'lifetime: ' + short
         key = StorageTestData(version=self.version,
                               id=1, lifetime=lifetime,
@@ -610,8 +610,8 @@
                                material=b'K',
                                description=description)
         if short is None:
-            key1.description += re.sub(r'\bPSA_KEY_USAGE_', r'',
-                                       key1.expected_usage.string)
+            usage_expr = key1.expected_usage.string
+            key1.description += crypto_knowledge.short_expression(usage_expr)
         else:
             key1.description += short
         return key1
@@ -648,12 +648,9 @@
         alg1 = 0 if alg is None else alg.expression #type: psa_storage.Exprable
         alg2 = 0
         key_material = kt.key_material(bits)
-        short_expression = re.sub(r'\bPSA_(?:KEY_TYPE|ECC_FAMILY)_',
-                                  r'',
-                                  kt.expression)
-        description = 'type: {} {}-bit'.format(short_expression, bits)
+        description = 'type: {} {}-bit'.format(kt.short_expression(), bits)
         if alg is not None:
-            description += ', ' + re.sub(r'PSA_ALG_', r'', alg.expression)
+            description += ', ' + alg.short_expression()
         key = StorageTestData(version=self.version,
                               id=1, lifetime=0x00000001,
                               type=kt.expression, bits=bits,
@@ -696,8 +693,7 @@
         # whether the key read from storage is suitable for an operation.
         # `keys_for_types` generate read tests with an algorithm and a
         # compatible key.
-        descr = re.sub(r'PSA_ALG_', r'', alg)
-        descr = re.sub(r',', r', ', re.sub(r' +', r'', descr))
+        descr = crypto_knowledge.short_expression(alg)
         usage = ['PSA_KEY_USAGE_EXPORT']
         key1 = StorageTestData(version=self.version,
                                id=1, lifetime=0x00000001,
@@ -776,12 +772,9 @@
         expected_usage_flags = material_usage_flags + [implicit_usage]
         alg2 = 0
         key_material = key_type.key_material(bits)
-        usage_expression = re.sub(r'PSA_KEY_USAGE_', r'', implyer_usage)
-        alg_expression = re.sub(r'PSA_ALG_', r'', alg)
-        alg_expression = re.sub(r',', r', ', re.sub(r' +', r'', alg_expression))
-        key_type_expression = re.sub(r'\bPSA_(?:KEY_TYPE|ECC_FAMILY)_',
-                                     r'',
-                                     key_type.expression)
+        usage_expression = crypto_knowledge.short_expression(implyer_usage)
+        alg_expression = crypto_knowledge.short_expression(alg)
+        key_type_expression = key_type.short_expression()
         description = 'implied by {}: {} {} {}-bit'.format(
             usage_expression, alg_expression, key_type_expression, bits)
         key = StorageTestData(version=self.version,