/*--------------------------------------------------------------------------*/
/* Copyright 2020 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.                                                                */
/*--------------------------------------------------------------------------*/

#include <mcuxClCss.h> // Interface to the entire mcuxClCss component
#include <mcuxClSession.h> // Interface to the entire mcuxClSession component
#include <mcuxClHash.h> // Interface to the entire mcuxClHash component
#include <mcuxCsslFlowProtection.h> // Code flow protection
#include <toolchain.h> // memory segment definitions
#include <stdbool.h>  // bool type for the example's return code

static const uint8_t data[3] CSS_CONST_SEGMENT = {
    0x61u, 0x62u, 0x63u
};

static const uint8_t hashExpected[32] CSS_CONST_SEGMENT = {
    0xbau, 0x78u, 0x16u, 0xbfu, 0x8fu, 0x01u, 0xcfu, 0xeau,
    0x41u, 0x41u, 0x40u, 0xdeu, 0x5du, 0xaeu, 0x22u, 0x23u,
    0xb0u, 0x03u, 0x61u, 0xa3u, 0x96u, 0x17u, 0x7au, 0x9cu,
    0xb4u, 0x10u, 0xffu, 0x61u, 0xf2u, 0x00u, 0x15u, 0xadu

};

static const uint8_t rtfExpected[32] CSS_CONST_SEGMENT = {
    0x58u, 0x9Fu, 0x9Fu, 0xFEu, 0xD4u, 0xC4u, 0x77u, 0x96u,
    0x6Bu, 0xFBu, 0x8Du, 0x41u, 0xF3u, 0x78u, 0x95u, 0xB0u,
    0x8Cu, 0x69u, 0x04u, 0x7Du, 0xF8u, 0xF9u, 0x11u, 0xD6u,
    0xF3u, 0xB5u, 0x7Fu, 0xBEu, 0x08u, 0xFAu, 0xEEu, 0x8Du
};

bool mcuxCl_Hash_example(
    void)
{
    /**************************************************************************/
    /* Preparation                                                            */
    /**************************************************************************/
    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Enable_Async()); // Enable the CSSv2.
    // mcuxClCss_Enable_Async is a flow-protected function: Check the protection token and the return value
    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.
    // mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClCss_Reset_Async(MCUXCLCSS_RESET_DO_NOT_CANCEL)); // Enable the CSSv2.
    // mcuxClCss_Enable_Async is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_Reset_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.
    // mcuxClCss_WaitForOperation is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClCss_WaitForOperation) != token) || (MCUXCLCSS_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    #define CPU_WA_BUFFER_SIZE MCUXCLHASH_WA_SIZE_MAX
    uint32_t cpuWaBuffer[CPU_WA_BUFFER_SIZE];

    mcuxClSession_Descriptor_t sessionDesc;
    mcuxClSession_Handle_t session = &sessionDesc;

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(si_status, token, mcuxClSession_init(
            /* mcuxClSession_Handle_t session:      */ session,
            /* uint32_t * const cpuWaBuffer:       */ cpuWaBuffer,
            /* uint32_t cpuWaSize:                 */ CPU_WA_BUFFER_SIZE,
            /* uint32_t * const pkcWaBuffer:       */ NULL,
            /* uint32_t pkcWaSize:                 */ 0
            )); // Enable the CSSv2.
    // mcuxClCss_Enable_Async is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_init) != token) || (MCUXCLSESSION_STATUS_OK != si_status))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(sr_status, token, mcuxClSession_setRtf(
            /* mcuxClSession_Handle_t session:      */ session,
            /* mcuxClSession_Rtf RtfOptions:        */ MCUXCLSESSION_RTF_UPDATE_TRUE
            )); // Enable the CSSv2.
    // mcuxClCss_Enable_Async is a flow-protected function: Check the protection token and the return value
    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClSession_setRtf) != token) || (MCUXCLSESSION_STATUS_OK != sr_status))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();

    /**************************************************************************/
    /* Hash computation                                                       */
    /**************************************************************************/

    uint8_t hash[32];
    uint8_t rtf[32];
    MCUX_CSSL_FP_FUNCTION_CALL_BEGIN(result, token, mcuxClHash_compute(
    /* mcuxClSession_Handle_t session: */ session,
    /* const mcuxClHash_Algo_t algo:   */ &mcuxClHash_AlgoSHA256,
    /* const uint8_t *const in:       */ data,
    /* uint32_t inSize:               */ sizeof(data),
    /* uint32_t *const hash           */ hash,
    /* uint32_t *const rtf            */ rtf
    ));

    if((MCUX_CSSL_FP_FUNCTION_CALLED(mcuxClHash_compute) != token) || (MCUXCLHASH_STATUS_OK != result))
        return false;
    MCUX_CSSL_FP_FUNCTION_CALL_END();


    /**************************************************************************/
    /* Verification                                                           */
    /**************************************************************************/
    for (size_t i = 0U; i < sizeof(hash); i++)
    {
        if (hash[i] != hashExpected[i]) // Expect that the resulting hash matches our expected output
        {
            return false;
        }
    }


    for (size_t i = 0U; i < sizeof(hash); i++)
    {
        if (rtf[i] != rtfExpected[i]) // Expect that the resulting rtf matches our expected output
        {
            return false;
        }
    }

    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;
}
