Key agreement: macros for finite-field Diffie-Hellman, ECDH

Declare macros to represent key agreement algorithms.
diff --git a/include/psa/crypto.h b/include/psa/crypto.h
index f344e14..515e65f 100644
--- a/include/psa/crypto.h
+++ b/include/psa/crypto.h
@@ -1218,6 +1218,73 @@
 
 #define PSA_ALG_KEY_AGREEMENT_GET_BASE(alg)                              \
     ((alg) & ~PSA_ALG_KEY_DERIVATION_MASK)
+
+#define PSA_ALG_FFDH_BASE                       ((psa_algorithm_t)0x22100000)
+/** The Diffie-Hellman key agreement algorithm.
+ *
+ * This algorithm combines the finite-field Diffie-Hellman-Merkle key
+ * agreement to produce a shared secret from a private key and the peer's
+ * public key, with a key selection or key derivation algorithm to produce
+ * one or more shared keys and other shared cryptographic material.
+ *
+ * \param kdf_alg       A key derivation algorithm (\c PSA_ALG_XXX value such
+ *                      that #PSA_ALG_IS_KEY_DERIVATION(\p hash_alg) is true)
+ *                      or a key selection algorithm (\c PSA_ALG_XXX value such
+ *                      that #PSA_ALG_IS_SELECTION(\p hash_alg) is true).
+ *
+ * \return              The Diffie-Hellman algorithm with the specified
+ *                      selection or derivation algorithm.
+ */
+#define PSA_ALG_FFDH(kdf_alg) \
+    (PSA_ALG_FFDH_BASE | ((kdf_alg) & PSA_ALG_KEY_DERIVATION_MASK))
+/** Whether the specified algorithm is a finite field Diffie-Hellman algorithm.
+ *
+ * This includes every supported key selection or key agreement algorithm
+ * for the output of the Diffie-Hellman calculation.
+ *
+ * \param alg An algorithm identifier (value of type #psa_algorithm_t).
+ *
+ * \return 1 if \c alg is a finite field Diffie-Hellman algorithm, 0 otherwise.
+ *         This macro may return either 0 or 1 if \c alg is not a supported
+ *         key agreement algorithm identifier.
+ */
+#define PSA_ALG_IS_FFDH(alg) \
+    (PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) == PSA_ALG_FFDH_BASE)
+
+#define PSA_ALG_ECDH_BASE                       ((psa_algorithm_t)0x22200000)
+/** The elliptic curve Diffie-Hellman key agreement algorithm.
+ *
+ * This algorithm combines the elliptic curve Diffie-Hellman key
+ * agreement to produce a shared secret from a private key and the peer's
+ * public key, with a key selection or key derivation algorithm to produce
+ * one or more shared keys and other shared cryptographic material.
+ *
+ * \param kdf_alg       A key derivation algorithm (\c PSA_ALG_XXX value such
+ *                      that #PSA_ALG_IS_KEY_DERIVATION(\p hash_alg) is true)
+ *                      or a selection algorithm (\c PSA_ALG_XXX value such
+ *                      that #PSA_ALG_IS_KEY_SELECTION(\p hash_alg) is true).
+ *
+ * \return              The Diffie-Hellman algorithm with the specified
+ *                      selection or derivation algorithm.
+ */
+#define PSA_ALG_ECDH(kdf_alg) \
+    (PSA_ALG_ECDH_BASE | ((kdf_alg) & PSA_ALG_KEY_DERIVATION_MASK))
+/** Whether the specified algorithm is an elliptic curve Diffie-Hellman
+ * algorithm.
+ *
+ * This includes every supported key selection or key agreement algorithm
+ * for the output of the Diffie-Hellman calculation.
+ *
+ * \param alg An algorithm identifier (value of type #psa_algorithm_t).
+ *
+ * \return 1 if \c alg is an elliptic curve Diffie-Hellman algorithm,
+ *         0 otherwise.
+ *         This macro may return either 0 or 1 if \c alg is not a supported
+ *         key agreement algorithm identifier.
+ */
+#define PSA_ALG_IS_ECDH(alg) \
+    (PSA_ALG_KEY_AGREEMENT_GET_BASE(alg) == PSA_ALG_ECDH_BASE)
+
 /**@}*/
 
 /** \defgroup key_management Key management
diff --git a/tests/suites/test_suite_psa_crypto_metadata.data b/tests/suites/test_suite_psa_crypto_metadata.data
index 09544f4..b61d8e1 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.data
+++ b/tests/suites/test_suite_psa_crypto_metadata.data
@@ -244,6 +244,23 @@
 
 Key selection: raw
 key_selection_algorithm:PSA_ALG_SELECT_RAW:0
+
+Key agreement: FFDH, raw output
+depends_on:MBEDTLS_DHM_C
+key_agreement_algorithm:PSA_ALG_FFDH( PSA_ALG_SELECT_RAW ):ALG_IS_FFDH:PSA_ALG_SELECT_RAW
+
+Key agreement: FFDH, HKDF using SHA-256
+depends_on:MBEDTLS_DHM_C
+key_agreement_algorithm:PSA_ALG_FFDH( PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ):ALG_IS_FFDH:PSA_ALG_HKDF( PSA_ALG_SHA_256 )
+
+Key agreement: ECDH, raw output
+depends_on:MBEDTLS_ECDH_C
+key_agreement_algorithm:PSA_ALG_ECDH( PSA_ALG_SELECT_RAW ):ALG_IS_ECDH:PSA_ALG_SELECT_RAW
+
+Key agreement: ECDH, HKDF using SHA-256
+depends_on:MBEDTLS_ECDH_C
+key_agreement_algorithm:PSA_ALG_ECDH( PSA_ALG_HKDF( PSA_ALG_SHA_256 ) ):ALG_IS_ECDH:PSA_ALG_HKDF( PSA_ALG_SHA_256 )
+
 Key type: raw data
 key_type:PSA_KEY_TYPE_RAW_DATA:KEY_TYPE_IS_UNSTRUCTURED
 
diff --git a/tests/suites/test_suite_psa_crypto_metadata.function b/tests/suites/test_suite_psa_crypto_metadata.function
index 4faa434..a8316c4 100644
--- a/tests/suites/test_suite_psa_crypto_metadata.function
+++ b/tests/suites/test_suite_psa_crypto_metadata.function
@@ -31,6 +31,8 @@
 #define ALG_IS_RANDOMIZED_ECDSA         ( 1u << 13 )
 #define ALG_IS_RSA_OAEP                 ( 1u << 14 )
 #define ALG_IS_HKDF                     ( 1u << 15 )
+#define ALG_IS_FFDH                     ( 1u << 16 )
+#define ALG_IS_ECDH                     ( 1u << 17 )
 
 /* Flags for key type classification macros. There is a flag for every
  * key type classification macro PSA_KEY_TYPE_IS_xxx except for some that
@@ -357,6 +359,12 @@
     TEST_ASSERT( PSA_ALG_IS_KEY_DERIVATION( alg ) );
     TEST_ASSERT( ! PSA_ALG_IS_KEY_SELECTION( alg ) );
     algorithm_classification( alg, classification_flags );
+
+    /* Check combinations with key agreements */
+    TEST_ASSERT( PSA_ALG_IS_KEY_AGREEMENT( PSA_ALG_FFDH( alg ) ) );
+    TEST_ASSERT( PSA_ALG_IS_KEY_AGREEMENT( PSA_ALG_ECDH( alg ) ) );
+    TEST_ASSERT( PSA_ALG_KEY_AGREEMENT_GET_KDF( PSA_ALG_ECDH( alg ) ) == alg );
+    TEST_ASSERT( PSA_ALG_KEY_AGREEMENT_GET_KDF( PSA_ALG_FFDH( alg ) ) == alg );
 }
 /* END_CASE */
 
@@ -376,6 +384,12 @@
     TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
     TEST_ASSERT( PSA_ALG_IS_KEY_SELECTION( alg ) );
     algorithm_classification( alg, classification_flags );
+
+    /* Check combinations with key agreements */
+    TEST_ASSERT( PSA_ALG_IS_KEY_AGREEMENT( PSA_ALG_FFDH( alg ) ) );
+    TEST_ASSERT( PSA_ALG_IS_KEY_AGREEMENT( PSA_ALG_ECDH( alg ) ) );
+    TEST_ASSERT( PSA_ALG_KEY_AGREEMENT_GET_KDF( PSA_ALG_ECDH( alg ) ) == alg );
+    TEST_ASSERT( PSA_ALG_KEY_AGREEMENT_GET_KDF( PSA_ALG_FFDH( alg ) ) == alg );
 }
 /* END_CASE */