/* BEGIN_HEADER */
/* Test macros that provide metadata about algorithms and key types.
 * This test suite only contains tests that don't require executing
 * code. Other test suites validate macros that require creating a key
 * and using it. */

#if defined(MBEDTLS_PSA_CRYPTO_SPM)
#include "spm/psa_defs.h"
#endif

#include "psa/crypto.h"

/* Flags for algorithm classification macros. There is a flag for every
 * algorithm classification macro PSA_ALG_IS_xxx except for the
 * category test macros, which are hard-coded in each
 * category-specific function. The name of the flag is the name of the
 * classification macro without the PSA_ prefix. */
#define ALG_IS_VENDOR_DEFINED           ( 1u << 0 )
#define ALG_IS_HMAC                     ( 1u << 1 )
#define ALG_IS_BLOCK_CIPHER_MAC         ( 1u << 2 )
#define ALG_IS_STREAM_CIPHER            ( 1u << 3 )
#define ALG_IS_RSA_PKCS1V15_SIGN        ( 1u << 4 )
#define ALG_IS_RSA_PSS                  ( 1u << 5 )
#define ALG_IS_DSA                      ( 1u << 6 )
#define ALG_DSA_IS_DETERMINISTIC        ( 1u << 7 )
#define ALG_IS_DETERMINISTIC_DSA        ( 1u << 8 )
#define ALG_IS_RANDOMIZED_DSA           ( 1u << 9 )
#define ALG_IS_ECDSA                    ( 1u << 10 )
#define ALG_ECDSA_IS_DETERMINISTIC      ( 1u << 11 )
#define ALG_IS_DETERMINISTIC_ECDSA      ( 1u << 12 )
#define ALG_IS_RANDOMIZED_ECDSA         ( 1u << 13 )
#define ALG_IS_HASH_AND_SIGN            ( 1u << 14 )
#define ALG_IS_RSA_OAEP                 ( 1u << 15 )
#define ALG_IS_HKDF                     ( 1u << 16 )
#define ALG_IS_FFDH                     ( 1u << 17 )
#define ALG_IS_ECDH                     ( 1u << 18 )
#define ALG_IS_WILDCARD                 ( 1u << 19 )
#define ALG_IS_RAW_KEY_AGREEMENT        ( 1u << 20 )
#define ALG_IS_AEAD_ON_BLOCK_CIPHER     ( 1u << 21 )
#define ALG_IS_TLS12_PRF                ( 1u << 22 )
#define ALG_IS_TLS12_PSK_TO_MS          ( 1u << 23 )

/* 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
 * are tested as derived from other macros. The name of the flag is
 * the name of the classification macro without the PSA_ prefix. */
#define KEY_TYPE_IS_VENDOR_DEFINED      ( 1u << 0 )
#define KEY_TYPE_IS_UNSTRUCTURED        ( 1u << 1 )
#define KEY_TYPE_IS_PUBLIC_KEY          ( 1u << 2 )
#define KEY_TYPE_IS_KEY_PAIR             ( 1u << 3 )
#define KEY_TYPE_IS_RSA                 ( 1u << 4 )
#define KEY_TYPE_IS_DSA                 ( 1u << 5 )
#define KEY_TYPE_IS_ECC                 ( 1u << 6 )
#define KEY_TYPE_IS_DH                  ( 1u << 7 )

#define TEST_CLASSIFICATION_MACRO( flag, alg, flags )           \
    TEST_ASSERT( PSA_##flag( alg ) == !! ( ( flags ) & flag ) )

/* Check the parity of value.
 * Return 0 if value has even parity and a nonzero value otherwise. */
int test_parity( uint32_t value )
{
    value ^= value >> 16;
    value ^= value >> 8;
    value ^= value >> 4;
    return( 0x9669 & 1 << ( value & 0xf ) );
}
#define TEST_PARITY( value )                    \
    TEST_ASSERT( test_parity( value ) )

void algorithm_classification( psa_algorithm_t alg, unsigned flags )
{
    TEST_CLASSIFICATION_MACRO( ALG_IS_VENDOR_DEFINED, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_HMAC, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_BLOCK_CIPHER_MAC, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_STREAM_CIPHER, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_RSA_PKCS1V15_SIGN, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_RSA_PSS, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_DSA, alg, flags );
    if ( PSA_ALG_IS_DSA( alg ) )
        TEST_CLASSIFICATION_MACRO( ALG_DSA_IS_DETERMINISTIC, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_DETERMINISTIC_DSA, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_RANDOMIZED_DSA, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_ECDSA, alg, flags );
    if ( PSA_ALG_IS_ECDSA( alg ) )
        TEST_CLASSIFICATION_MACRO( ALG_ECDSA_IS_DETERMINISTIC, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_DETERMINISTIC_ECDSA, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_RANDOMIZED_ECDSA, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_HASH_AND_SIGN, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_RSA_OAEP, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_HKDF, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_WILDCARD, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_ECDH, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_FFDH, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_RAW_KEY_AGREEMENT, alg, flags );
    TEST_CLASSIFICATION_MACRO( ALG_IS_AEAD_ON_BLOCK_CIPHER, alg, flags );
exit: ;
}

void key_type_classification( psa_key_type_t type, unsigned flags )
{
    /* Macros tested based on the test case parameter */
    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_VENDOR_DEFINED, type, flags );
    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_UNSTRUCTURED, type, flags );
    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_PUBLIC_KEY, type, flags );
    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_KEY_PAIR, type, flags );
    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_RSA, type, flags );
    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_ECC, type, flags );
    TEST_CLASSIFICATION_MACRO( KEY_TYPE_IS_DH, type, flags );

    /* Macros with derived semantics */
    TEST_EQUAL( PSA_KEY_TYPE_IS_ASYMMETRIC( type ),
                ( PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ||
                  PSA_KEY_TYPE_IS_KEY_PAIR( type ) ) );
    TEST_EQUAL( PSA_KEY_TYPE_IS_ECC_KEY_PAIR( type ),
                ( PSA_KEY_TYPE_IS_ECC( type ) &&
                  PSA_KEY_TYPE_IS_KEY_PAIR( type ) ) );
    TEST_EQUAL( PSA_KEY_TYPE_IS_ECC_PUBLIC_KEY( type ),
                ( PSA_KEY_TYPE_IS_ECC( type ) &&
                  PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ) );
    TEST_EQUAL( PSA_KEY_TYPE_IS_DH_KEY_PAIR( type ),
                ( PSA_KEY_TYPE_IS_DH( type ) &&
                  PSA_KEY_TYPE_IS_KEY_PAIR( type ) ) );
    TEST_EQUAL( PSA_KEY_TYPE_IS_DH_PUBLIC_KEY( type ),
                ( PSA_KEY_TYPE_IS_DH( type ) &&
                  PSA_KEY_TYPE_IS_PUBLIC_KEY( type ) ) );

    TEST_PARITY( type );

exit: ;
}

void mac_algorithm_core( psa_algorithm_t alg, int classification_flags,
                         psa_key_type_t key_type, size_t key_bits,
                         size_t length )
{
    /* Algorithm classification */
    TEST_ASSERT( ! PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, classification_flags );

    /* Length */
    TEST_EQUAL( length, PSA_MAC_FINAL_SIZE( key_type, key_bits, alg ) );

exit: ;
}

void aead_algorithm_core( psa_algorithm_t alg, int classification_flags,
                          size_t tag_length )
{
    /* Algorithm classification */
    TEST_ASSERT( ! PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, classification_flags );

    /* Tag length */
    TEST_EQUAL( tag_length, PSA_AEAD_TAG_LENGTH( alg ) );

exit: ;
}

/* END_HEADER */

/* BEGIN_DEPENDENCIES
 * depends_on:MBEDTLS_PSA_CRYPTO_C
 * END_DEPENDENCIES
 */

/* BEGIN_CASE */
void hash_algorithm( int alg_arg, int length_arg )
{
    psa_algorithm_t alg = alg_arg;
    size_t length = length_arg;
    psa_algorithm_t hmac_alg = PSA_ALG_HMAC( alg );
    psa_algorithm_t rsa_pkcs1v15_sign_alg = PSA_ALG_RSA_PKCS1V15_SIGN( alg );
    psa_algorithm_t rsa_pss_alg = PSA_ALG_RSA_PSS( alg );
    psa_algorithm_t dsa_alg = PSA_ALG_DSA( alg );
    psa_algorithm_t deterministic_dsa_alg = PSA_ALG_DETERMINISTIC_DSA( alg );
    psa_algorithm_t ecdsa_alg = PSA_ALG_ECDSA( alg );
    psa_algorithm_t deterministic_ecdsa_alg = PSA_ALG_DETERMINISTIC_ECDSA( alg );
    psa_algorithm_t rsa_oaep_alg = PSA_ALG_RSA_OAEP( alg );
    psa_algorithm_t hkdf_alg = PSA_ALG_HKDF( alg );

    /* Algorithm classification */
    TEST_ASSERT( PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, 0 );

    /* Dependent algorithms */
    TEST_EQUAL( PSA_ALG_HMAC_GET_HASH( hmac_alg ), alg );
    TEST_EQUAL( PSA_ALG_SIGN_GET_HASH( rsa_pkcs1v15_sign_alg ), alg );
    TEST_EQUAL( PSA_ALG_SIGN_GET_HASH( rsa_pss_alg ), alg );
    TEST_EQUAL( PSA_ALG_SIGN_GET_HASH( dsa_alg ), alg );
    TEST_EQUAL( PSA_ALG_SIGN_GET_HASH( deterministic_dsa_alg ), alg );
    TEST_EQUAL( PSA_ALG_SIGN_GET_HASH( ecdsa_alg ), alg );
    TEST_EQUAL( PSA_ALG_SIGN_GET_HASH( deterministic_ecdsa_alg ), alg );
    TEST_EQUAL( PSA_ALG_RSA_OAEP_GET_HASH( rsa_oaep_alg ), alg );
    TEST_EQUAL( PSA_ALG_HKDF_GET_HASH( hkdf_alg ), alg );

    /* Hash length */
    TEST_EQUAL( length, PSA_HASH_SIZE( alg ) );
    TEST_ASSERT( length <= PSA_HASH_MAX_SIZE );
}
/* END_CASE */

/* BEGIN_CASE */
void mac_algorithm( int alg_arg, int classification_flags,
                    int length_arg,
                    int key_type_arg, int key_bits_arg )
{
    psa_algorithm_t alg = alg_arg;
    size_t length = length_arg;
    size_t n;
    size_t key_type = key_type_arg;
    size_t key_bits = key_bits_arg;

    mac_algorithm_core( alg, classification_flags,
                        key_type, key_bits, length );
    TEST_EQUAL( PSA_ALG_FULL_LENGTH_MAC( alg ), alg );
    TEST_ASSERT( length <= PSA_MAC_MAX_SIZE );

    /* Truncated versions */
    for( n = 1; n <= length; n++ )
    {
        psa_algorithm_t truncated_alg = PSA_ALG_TRUNCATED_MAC( alg, n );
        mac_algorithm_core( truncated_alg, classification_flags,
                            key_type, key_bits, n );
        TEST_EQUAL( PSA_ALG_FULL_LENGTH_MAC( truncated_alg ), alg );
        /* Check that calling PSA_ALG_TRUNCATED_MAC twice gives the length
         * of the outer truncation (even if the outer length is smaller than
         * the inner length). */
        TEST_EQUAL( PSA_ALG_TRUNCATED_MAC( truncated_alg, 1 ),
                    PSA_ALG_TRUNCATED_MAC( alg, 1 ) );
        TEST_EQUAL( PSA_ALG_TRUNCATED_MAC( truncated_alg, length - 1 ),
                    PSA_ALG_TRUNCATED_MAC( alg, length - 1) );
        TEST_EQUAL( PSA_ALG_TRUNCATED_MAC( truncated_alg, length ),
                    PSA_ALG_TRUNCATED_MAC( alg, length ) );
    }
}
/* END_CASE */

/* BEGIN_CASE */
void hmac_algorithm( int alg_arg,
                     int length_arg,
                     int block_size_arg )
{
    psa_algorithm_t alg = alg_arg;
    psa_algorithm_t hash_alg = PSA_ALG_HMAC_GET_HASH( alg );
    size_t block_size = block_size_arg;
    size_t length = length_arg;
    size_t n;

    TEST_ASSERT( PSA_ALG_IS_HASH( hash_alg ) );
    TEST_EQUAL( PSA_ALG_HMAC( hash_alg ), alg );

    TEST_ASSERT( block_size <= PSA_HMAC_MAX_HASH_BLOCK_SIZE );

    test_mac_algorithm( alg_arg, ALG_IS_HMAC, length,
                        PSA_KEY_TYPE_HMAC, PSA_BYTES_TO_BITS( length ) );

    for( n = 1; n <= length; n++ )
    {
        psa_algorithm_t truncated_alg = PSA_ALG_TRUNCATED_MAC( alg, n );
        TEST_EQUAL( PSA_ALG_HMAC_GET_HASH( truncated_alg ), hash_alg );
    }
}
/* END_CASE */

/* BEGIN_CASE */
void cipher_algorithm( int alg_arg, int classification_flags )
{
    psa_algorithm_t alg = alg_arg;

    /* Algorithm classification */
    TEST_ASSERT( ! PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, classification_flags );
}
/* END_CASE */

/* BEGIN_CASE */
void aead_algorithm( int alg_arg, int classification_flags,
                     int tag_length_arg )
{
    psa_algorithm_t alg = alg_arg;
    size_t tag_length = tag_length_arg;
    size_t n;

    aead_algorithm_core( alg, classification_flags, tag_length );

    /* Truncated versions */
    for( n = 1; n <= tag_length; n++ )
    {
        psa_algorithm_t truncated_alg = PSA_ALG_AEAD_WITH_TAG_LENGTH( alg, n );
        aead_algorithm_core( truncated_alg, classification_flags, n );
        TEST_EQUAL( PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH( truncated_alg ),
                    alg );
        /* Check that calling PSA_ALG_AEAD_WITH_DEFAULT_TAG_LENGTH twice gives
         * the length of the outer truncation (even if the outer length is
         * smaller than the inner length). */
        TEST_EQUAL( PSA_ALG_AEAD_WITH_TAG_LENGTH( truncated_alg, 1 ),
                    PSA_ALG_AEAD_WITH_TAG_LENGTH( alg, 1 ) );
        TEST_EQUAL( PSA_ALG_AEAD_WITH_TAG_LENGTH( truncated_alg, tag_length - 1 ),
                    PSA_ALG_AEAD_WITH_TAG_LENGTH( alg, tag_length - 1) );
        TEST_EQUAL( PSA_ALG_AEAD_WITH_TAG_LENGTH( truncated_alg, tag_length ),
                    PSA_ALG_AEAD_WITH_TAG_LENGTH( alg, tag_length ) );
    }
}
/* END_CASE */

/* BEGIN_CASE */
void asymmetric_signature_algorithm( int alg_arg, int classification_flags )
{
    psa_algorithm_t alg = alg_arg;

    /* Algorithm classification */
    TEST_ASSERT( ! PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, classification_flags );
}
/* END_CASE */

/* BEGIN_CASE */
void asymmetric_signature_wildcard( int alg_arg, int classification_flags )
{
    classification_flags |= ALG_IS_HASH_AND_SIGN | ALG_IS_WILDCARD;
    test_asymmetric_signature_algorithm( alg_arg, classification_flags );
    /* Any failure of this test function comes from
     * asymmetric_signature_algorithm. Pacify -Werror=unused-label. */
    goto exit;
}
/* END_CASE */

/* BEGIN_CASE */
void asymmetric_encryption_algorithm( int alg_arg, int classification_flags )
{
    psa_algorithm_t alg = alg_arg;

    /* Algorithm classification */
    TEST_ASSERT( ! PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, classification_flags );
}
/* END_CASE */

/* BEGIN_CASE */
void key_derivation_algorithm( int alg_arg, int classification_flags )
{
    psa_algorithm_t alg = alg_arg;
    psa_algorithm_t ecdh_alg = PSA_ALG_KEY_AGREEMENT( PSA_ALG_ECDH, alg );
    psa_algorithm_t ffdh_alg = PSA_ALG_KEY_AGREEMENT( PSA_ALG_FFDH, alg );

    /* Algorithm classification */
    TEST_ASSERT( ! PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, classification_flags );

    /* Check combinations with key agreements */
    TEST_ASSERT( PSA_ALG_IS_KEY_AGREEMENT( ecdh_alg ) );
    TEST_ASSERT( PSA_ALG_IS_KEY_AGREEMENT( ffdh_alg ) );
    TEST_EQUAL( PSA_ALG_KEY_AGREEMENT_GET_KDF( ecdh_alg ), alg );
    TEST_EQUAL( PSA_ALG_KEY_AGREEMENT_GET_KDF( ffdh_alg ), alg );
}
/* END_CASE */

/* BEGIN_CASE */
void key_agreement_algorithm( int alg_arg, int classification_flags,
                              int ka_alg_arg, int kdf_alg_arg )
{
    psa_algorithm_t alg = alg_arg;
    psa_algorithm_t actual_ka_alg = PSA_ALG_KEY_AGREEMENT_GET_BASE( alg );
    psa_algorithm_t expected_ka_alg = ka_alg_arg;
    psa_algorithm_t actual_kdf_alg = PSA_ALG_KEY_AGREEMENT_GET_KDF( alg );
    psa_algorithm_t expected_kdf_alg = kdf_alg_arg;

    /* Algorithm classification */
    TEST_ASSERT( ! PSA_ALG_IS_HASH( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_MAC( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_CIPHER( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_AEAD( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_SIGN( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_ASYMMETRIC_ENCRYPTION( alg ) );
    TEST_ASSERT( PSA_ALG_IS_KEY_AGREEMENT( alg ) );
    TEST_ASSERT( ! PSA_ALG_IS_KEY_DERIVATION( alg ) );
    algorithm_classification( alg, classification_flags );

    /* Shared secret derivation properties */
    TEST_EQUAL( actual_ka_alg, expected_ka_alg );
    TEST_EQUAL( actual_kdf_alg, expected_kdf_alg );
}
/* END_CASE */

/* BEGIN_CASE */
void key_type( int type_arg, int classification_flags )
{
    psa_key_type_t type = type_arg;

    key_type_classification( type, classification_flags );

    /* For asymmetric types, check the corresponding pair/public type */
    if( classification_flags & KEY_TYPE_IS_PUBLIC_KEY )
    {
        psa_key_type_t pair_type = PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY( type );
        TEST_EQUAL( PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( pair_type ), type );
        key_type_classification( pair_type,
                                 ( classification_flags
                                   & ~KEY_TYPE_IS_PUBLIC_KEY )
                                 | KEY_TYPE_IS_KEY_PAIR );
        TEST_EQUAL( PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( type ), type );
    }
    if( classification_flags & KEY_TYPE_IS_KEY_PAIR )
    {
        psa_key_type_t public_type = PSA_KEY_TYPE_PUBLIC_KEY_OF_KEY_PAIR( type );
        TEST_EQUAL( PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY( public_type ), type );
        key_type_classification( public_type,
                                 ( classification_flags
                                   & ~KEY_TYPE_IS_KEY_PAIR )
                                 | KEY_TYPE_IS_PUBLIC_KEY );
        TEST_EQUAL( PSA_KEY_TYPE_KEY_PAIR_OF_PUBLIC_KEY( type ), type );
    }
}
/* END_CASE */

/* BEGIN_CASE */
void block_cipher_key_type( int type_arg, int block_size_arg )
{
    psa_key_type_t type = type_arg;
    size_t block_size = block_size_arg;

    test_key_type( type_arg, KEY_TYPE_IS_UNSTRUCTURED );

    TEST_EQUAL( type & PSA_KEY_TYPE_CATEGORY_MASK,
                PSA_KEY_TYPE_CATEGORY_SYMMETRIC );
    TEST_EQUAL( PSA_BLOCK_CIPHER_BLOCK_SIZE( type ), block_size );
}
/* END_CASE */

/* BEGIN_CASE */
void stream_cipher_key_type( int type_arg )
{
    psa_key_type_t type = type_arg;

    test_key_type( type_arg, KEY_TYPE_IS_UNSTRUCTURED );

    TEST_EQUAL( type & PSA_KEY_TYPE_CATEGORY_MASK,
                PSA_KEY_TYPE_CATEGORY_SYMMETRIC );
    TEST_EQUAL( PSA_BLOCK_CIPHER_BLOCK_SIZE( type ), 1 );
}
/* END_CASE */

/* BEGIN_CASE depends_on:MBEDTLS_ECP_C */
void ecc_key_family( int curve_arg )
{
    psa_ecc_family_t curve = curve_arg;
    psa_key_type_t public_type = PSA_KEY_TYPE_ECC_PUBLIC_KEY( curve );
    psa_key_type_t pair_type = PSA_KEY_TYPE_ECC_KEY_PAIR( curve );

    test_parity( curve );

    test_key_type( public_type, KEY_TYPE_IS_ECC | KEY_TYPE_IS_PUBLIC_KEY );
    test_key_type( pair_type, KEY_TYPE_IS_ECC | KEY_TYPE_IS_KEY_PAIR );

    TEST_EQUAL( PSA_KEY_TYPE_ECC_GET_FAMILY( public_type ), curve );
    TEST_EQUAL( PSA_KEY_TYPE_ECC_GET_FAMILY( pair_type ), curve );
}
/* END_CASE */

/* BEGIN_CASE depends_on:MBEDTLS_DHM_C */
void dh_key_family( int group_arg )
{
    psa_dh_family_t group = group_arg;
    psa_key_type_t public_type = PSA_KEY_TYPE_DH_PUBLIC_KEY( group );
    psa_key_type_t pair_type = PSA_KEY_TYPE_DH_KEY_PAIR( group );

    test_parity( group );

    test_key_type( public_type, KEY_TYPE_IS_DH | KEY_TYPE_IS_PUBLIC_KEY );
    test_key_type( pair_type, KEY_TYPE_IS_DH | KEY_TYPE_IS_KEY_PAIR );

    TEST_EQUAL( PSA_KEY_TYPE_DH_GET_FAMILY( public_type ), group );
    TEST_EQUAL( PSA_KEY_TYPE_DH_GET_FAMILY( pair_type ), group );
}
/* END_CASE */