/*--------------------------------------------------------------------------*/
/* Copyright 2021 NXP                                                       */
/*                                                                          */
/* NXP Confidential. This software is owned or controlled by NXP and may    */
/* only be used strictly in accordance with the applicable license terms.   */
/* By expressly accepting such terms or by downloading, installing,         */
/* activating and/or otherwise using the software, you are agreeing that    */
/* you have read, and that you agree to comply with and are bound by, such  */
/* license terms. If you do not agree to be bound by the applicable license */
/* terms, then you may not retain, install, activate or otherwise use the   */
/* software.                                                                */
/*--------------------------------------------------------------------------*/

/**
 * @file  mcuxClEcc_Mont_example.c
 * @brief Example for the mcuxClEcc component
 *
 * @example mcuxClEcc_Mont_example.c
 * @brief   Example for the mcuxClEcc component Curve25519 related functions
 */

#include <mcuxClCss.h>
#include <mcuxClEcc.h>
#include <mcuxClKey.h>
#include <mcuxClKey_KeyTypes.h>
#include <mcuxClPkc_Types.h>

#define RAM_START_ADDRESS MCUXCLPKC_RAM_START_ADDRESS
#define MAX_CPUWA_SIZE ((MCUXCLECC_MONT_DHKEYGENERATION_WACPU_SIZE >= MCUXCLECC_MONT_DHKEYAGREEMENT_WACPU_SIZE) ? MCUXCLECC_MONT_DHKEYGENERATION_WACPU_SIZE : MCUXCLECC_MONT_DHKEYAGREEMENT_WACPU_SIZE)
#define MAX_PKCWA_SIZE ((MCUXCLECC_MONT_DHKEYGENERATION_CURVE25519_WAPKC_SIZE >= MCUXCLECC_MONT_DHKEYAGREEMENT_CURVE25519_WAPKC_SIZE) ? MCUXCLECC_MONT_DHKEYGENERATION_CURVE25519_WAPKC_SIZE : MCUXCLECC_MONT_DHKEYAGREEMENT_CURVE25519_WAPKC_SIZE)

bool mcuxClEcc_Mont_example(void)
{

	MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Enable_Async()); // Enable the CSSv2.
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Enable_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
    {
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_Enable_Async operation to complete.
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
    {
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* PRNG needs to be initialized; this can be done by calling mcuxClCss_KeyDelete_Async (delete any key slot, can be empty) */
	MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_KeyDelete_Async(0));
    if ((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_KeyDelete_Async) != token) || (MCUXCLCSS_STATUS_OK_WAIT != result))
    {
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_WaitForOperation(MCUXCLCSS_ERROR_FLAGS_CLEAR)); // Wait for the mcuxClCss_Enable_Async operation to complete.
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
	{
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* Setup one session to be used by all functions called */
    mcuxClSession_Descriptor_t session;

    uint8_t pCpuWa[MAX_CPUWA_SIZE];
    /* Initialize session with pkcWA on the beginning of PKC RAM */
    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(si_status, si_token, mcuxClSession_init(&session,(uint32_t *) pCpuWa, MAX_CPUWA_SIZE,
                             (uint32_t *) RAM_START_ADDRESS, MAX_PKCWA_SIZE));


    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_init) != si_token) || (MCUXCLSESSION_STATUS_OK != si_status))
    {
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* Create and fill common structures for both Alice and Bob */
    mcuxClKey_Type_t type;
    type.algoId = (MCUXCLKEY_ALGO_ID_ECC_MONT_GFP | MCUXCLKEY_ALGO_ID_KEY_PAIR);
    type.size = MCUXCLKEY_SIZE_NOTUSED;
    type.info = (void *) &mcuxClEcc_Mont_DomainParams_Curve25519;

    /* Prepare input for Alice key generation */
    mcuxClKey_Descriptor_t alicePrivKeyHandler;
    mcuxClKey_Descriptor_t alicePubKeyHandler;
    uint8_t alicePrivKeyBuffer[MCUXCLECC_MONT_CURVE25519_SIZE_PRIVATEKEY]={0};
    uint8_t alicePubKeyBuffer[MCUXCLECC_MONT_CURVE25519_SIZE_PUBLICKEY]={0};
    uint32_t alicePrivKeySize = 0u;
    uint32_t alicePubKeySize = 0u;

    /* Call Dh KeyGeneration for Alice keys generation and check FP and return code */
	MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(alice_keygeneration_result, alice_keygeneration_token, mcuxClEcc_Mont_DhKeyGeneration(&session, type, mcuxClKey_protection_none,
                                                         (mcuxClKey_Handle_t)&alicePrivKeyHandler, alicePrivKeyBuffer, &alicePrivKeySize,
                                                         (mcuxClKey_Handle_t)&alicePubKeyHandler, alicePubKeyBuffer, &alicePubKeySize));
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEcc_Mont_DhKeyGeneration) != alice_keygeneration_token) || (MCUXCLECC_STATUS_MONT_DHKEYGENERATION_OK != alice_keygeneration_result))
    {
		return false;
	}
	MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* Prepare input for Bob key generation */
    mcuxClKey_Descriptor_t bobPrivKeyHandler;
    mcuxClKey_Descriptor_t bobPubKeyHandler;
    uint8_t bobPrivKeyBuffer[MCUXCLECC_MONT_CURVE25519_SIZE_PRIVATEKEY]={0};
    uint8_t bobPubKeyBuffer[MCUXCLECC_MONT_CURVE25519_SIZE_PUBLICKEY]={0};
    uint32_t bobPrivKeySize = 0u;
    uint32_t bobPubKeySize = 0u;

    /* Call Dh KeyGeneration for Bob keys generation and check FP and return code */
	MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(bob_keygeneration_result, bob_keygeneration_token, mcuxClEcc_Mont_DhKeyGeneration(&session, type, mcuxClKey_protection_none,
                                                         (mcuxClKey_Handle_t)&bobPrivKeyHandler, bobPrivKeyBuffer, &bobPrivKeySize,
                                                         (mcuxClKey_Handle_t)&bobPubKeyHandler, bobPubKeyBuffer, &bobPubKeySize));
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEcc_Mont_DhKeyGeneration) != bob_keygeneration_token) || (MCUXCLECC_STATUS_MONT_DHKEYGENERATION_OK != bob_keygeneration_result))
    {
		return false;
	}
	MCUX_CSSL_FP_FUNCTION_CALL_END();



    /* Prepare input for Alice shared secret calculation */
    uint8_t aliceSharedSecret[MCUXCLECC_MONT_CURVE25519_SIZE_SHAREDSECRET];
    uint32_t aliceSharedSecretSize;
    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(alice_keyagreement_result, alice_keyagreement_token, mcuxClEcc_Mont_DhKeyAgreement(&session,
                         (mcuxClKey_Handle_t)&alicePrivKeyHandler, (mcuxClKey_Handle_t)&bobPubKeyHandler,
                          aliceSharedSecret, &aliceSharedSecretSize));
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEcc_Mont_DhKeyAgreement) != alice_keyagreement_token) || (MCUXCLECC_STATUS_MONT_DHKEYAGREEMENT_OK != alice_keyagreement_result))
    {
		return false;
	}
	MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* Prepare input for Bob shared secret calculation */
    uint8_t bobSharedSecret[MCUXCLECC_MONT_CURVE25519_SIZE_SHAREDSECRET];
    uint32_t bobSharedSecretSize;
    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(bob_keyagreement_result, bob_keyagreement_token, mcuxClEcc_Mont_DhKeyAgreement(&session,
                         (mcuxClKey_Handle_t)&bobPrivKeyHandler, (mcuxClKey_Handle_t)&alicePubKeyHandler,
                          bobSharedSecret, &bobSharedSecretSize));
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClEcc_Mont_DhKeyAgreement) != bob_keyagreement_token) || (MCUXCLECC_STATUS_MONT_DHKEYAGREEMENT_OK != bob_keyagreement_result))
    {
		return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    /* Alice's shared secret shall be equal to Bob's shared secret */

	MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(cleanup_result, cleanup_token, mcuxClSession_cleanup(&session));
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_cleanup) != cleanup_token) || (MCUXCLSESSION_STATUS_OK != cleanup_result))
    {
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(destroy_result, destroy_token, mcuxClSession_destroy(&session));
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_destroy) != destroy_token) || (MCUXCLSESSION_STATUS_OK != destroy_result))
    {
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

	MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Disable()); // Disable the CSSv2.
    // mcuxClCss_Disable is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Disable) != token) || (MCUXCLCSS_STATUS_OK != result))
    {
        return false;
	}
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    return true;
}
