/*
 * Copyright 2015-2016, Freescale Semiconductor, Inc.
 * Copyright 2017 NXP
 * All rights reserved.
 *
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif

#include "fsl_common.h"

#if defined(FSL_FEATURE_SOC_LTC_COUNT) && (FSL_FEATURE_SOC_LTC_COUNT > 0)
#include "fsl_ltc.h"
#endif
#if defined(FSL_FEATURE_SOC_CAAM_COUNT) && (FSL_FEATURE_SOC_CAAM_COUNT > 0)
#include "fsl_caam.h"
#endif
#if defined(FSL_FEATURE_SOC_CAU3_COUNT) && (FSL_FEATURE_SOC_CAU3_COUNT > 0)
#include "fsl_cau3.h"
#endif
#if defined(FSL_FEATURE_SOC_DCP_COUNT) && (FSL_FEATURE_SOC_DCP_COUNT > 0)
#include "fsl_dcp.h"
#endif
#if defined(FSL_FEATURE_SOC_HASHCRYPT_COUNT) && (FSL_FEATURE_SOC_HASHCRYPT_COUNT > 0)
#include "fsl_hashcrypt.h"
#endif
#if defined(FSL_FEATURE_SOC_CASPER_COUNT) && (FSL_FEATURE_SOC_CASPER_COUNT > 0)
#include "fsl_casper.h"
#endif
#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0)
#include "fsl_trng.h"
#elif defined(FSL_FEATURE_SOC_RNG_COUNT) && (FSL_FEATURE_SOC_RNG_COUNT > 0)
#include "fsl_rnga.h"
#elif defined(FSL_FEATURE_SOC_LPC_RNG1_COUNT) && (FSL_FEATURE_SOC_LPC_RNG1_COUNT > 0)
#include "fsl_rng.h"
#endif

#define CLEAN_RETURN(value) \
    {                       \
        ret = (value);        \
        goto cleanup;       \
    }

#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
#include "fsl_cache.h"

SDK_L1DCACHE_ALIGN(uint8_t input_buff[FSL_FEATURE_L1DCACHE_LINESIZE_BYTE]);
SDK_L1DCACHE_ALIGN(uint8_t output_buff[FSL_FEATURE_L1DCACHE_LINESIZE_BYTE]);

#define DTCM_START  0x20000000U /* Start of  DTCM memory */

/* Get NONCACHED region info from linker files */
#if defined(__CC_ARM) || defined(__ARMCC_VERSION)
extern uint32_t Image$$RW_m_ncache$$Base[];
/* RW_m_ncache_unused is a auxiliary region which is used to get the whole size of noncache section */
extern uint32_t Image$$RW_m_ncache_unused$$Base[];
extern uint32_t Image$$RW_m_ncache_unused$$ZI$$Limit[];
uint32_t nonCacheStart = (uint32_t)Image$$RW_m_ncache$$Base;
uint32_t nonCacheEnd  =  (uint32_t)Image$$RW_m_ncache_unused$$Base;
#define nonCacheSize  nonCacheEnd- nonCacheStart		
#elif defined(__MCUXPRESSO)
extern uint32_t __base_NCACHE_REGION;
extern uint32_t __top_NCACHE_REGION;
uint32_t nonCacheStart = (uint32_t)(&__base_NCACHE_REGION);
uint32_t nonCacheEnd = (uint32_t)(&__top_NCACHE_REGION);
#define nonCacheSize  nonCacheEnd- nonCacheStart
#elif defined(__ICCARM__) || defined(__GNUC__)
extern uint32_t __NCACHE_REGION_START[];
extern uint32_t __NCACHE_REGION_SIZE[];
uint32_t nonCacheStart = (uint32_t)__NCACHE_REGION_START;
uint32_t nonCacheSize  = (uint32_t)__NCACHE_REGION_SIZE;
#endif

/* Returns TRUE if in noncached, FALSE otherwise */
bool static IS_IN_NONCACHED(uint32_t addr, uint32_t size)
{
    /* Check if data are in DTCM (non-cached) memory */
#if defined(__DTCM_PRESENT) && (__DTCM_PRESENT == 1U)
    uint8_t DTCMSZ = 0U;
    uint32_t DTCM_SIZE = 0, DTCM_END = 0U;
    /* Get DTCM size configuration from GPR14 */
    DTCMSZ = (uint8_t)((IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_MASK & IOMUXC_GPR->GPR14) >> IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_SHIFT);
    
    switch (DTCMSZ)
    {
        case 0x0: /* no DTCM */
            DTCM_SIZE = 0U;
            break;
        case 0x3: /* 4KB */
            DTCM_SIZE = 0x1000;
            break;
        case 0x4: /* 8KB */
            DTCM_SIZE = 0x2000;
            break;
        case 0x5: /* 16KB */
            DTCM_SIZE = 0x4000;
            break;
        case 0x6: /* 32KB */
            DTCM_SIZE = 0x8000;
            break;
        case 0x7: /* 64KB */
            DTCM_SIZE = 0x10000;
            break;
        case 0x8: /* 128KB */
            DTCM_SIZE = 0x20000;
            break;
        case 0x9: /* 256KB */
            DTCM_SIZE = 0x40000;
            break;
        case 0xA: /* 512KB */
            DTCM_SIZE = 0x80000;
            break;
        default:
            /* All the cases have been listed above, the default clause should not be reached. */
            break;    
    }
    
    DTCM_END = DTCM_START + DTCM_SIZE;
    
    if((addr >= DTCM_START) && (addr+size < DTCM_END))
    {
        return true;
    }
#endif /* __DTCM_PRESENT */
    /* If not in DTCM, check non-cached section based linker file */
    if((addr >= nonCacheStart) && ((addr+size) < (nonCacheStart + nonCacheSize)))
    {
        return true;
    }

    return false;
}

/* Returns 1 if aligned, 0 otherwise */
#define IS_CACHE_ALIGNED(addr) (!((uint32_t)(addr) & ((uint32_t)FSL_FEATURE_L1DCACHE_LINESIZE_BYTE - 1U)))

#define MBEDTLS_ERR_DCACHE_ALIGMENT_FAILED  MBEDTLS_ERR_AES_HW_ACCEL_FAILED

#endif /* __DCACHE_PRESENT */

/******************************************************************************/
/*************************** CAAM *********************************************/
/******************************************************************************/
#if defined(FSL_FEATURE_SOC_CAAM_COUNT) && (FSL_FEATURE_SOC_CAAM_COUNT > 0) && defined(CRYPTO_USE_DRIVER_CAAM)
static caam_handle_t s_caamHandle = {.jobRing = kCAAM_JobRing0};

/*! @brief CAAM job ring interface 0 in system memory. */
static caam_job_ring_interface_t s_jrif0;

/*! @brief CAAM job ring interface 1 in system memory. */
static caam_job_ring_interface_t s_jrif1;

/*! @brief CAAM job ring interface 2 in system memory. */
static caam_job_ring_interface_t s_jrif2;

/*! @brief CAAM job ring interface 3 in system memory. */
static caam_job_ring_interface_t s_jrif3;

#endif

/******************************************************************************/
/*************************** CAU3 *********************************************/
/******************************************************************************/
#if defined(FSL_FEATURE_SOC_CAU3_COUNT) && (FSL_FEATURE_SOC_CAU3_COUNT > 0)
static cau3_handle_t s_cau3Handle = {.taskDone = MBEDTLS_CAU3_COMPLETION_SIGNAL, .keySlot = kCAU3_KeySlot0};
#endif

/******************************************************************************/
/**************************** DCP *********************************************/
/******************************************************************************/
#if defined(FSL_FEATURE_SOC_DCP_COUNT) && (FSL_FEATURE_SOC_DCP_COUNT > 0)
static dcp_handle_t s_dcpHandle = {.channel = kDCP_Channel0, .keySlot = kDCP_KeySlot0, .swapConfig = (uint32_t)kDCP_NoSwap};
#endif

/******************************************************************************/
/************************* Key slot management ********************************/
/******************************************************************************/
#if (defined(FSL_FEATURE_SOC_CAU3_COUNT) && (FSL_FEATURE_SOC_CAU3_COUNT > 0)) || (defined(MBEDTLS_FREESCALE_DCP_AES))
static const void *s_mbedtlsCtx[4] = {0};

static void crypto_attach_ctx_to_key_slot(const void *ctx, uint8_t keySlot)
{
    s_mbedtlsCtx[keySlot] = ctx;
}

static void crypto_detach_ctx_from_key_slot(const void *ctx)
{
    for (int i = 0; i < 4; i++)
    {
        if (ctx == s_mbedtlsCtx[i])
        {
            s_mbedtlsCtx[i] = NULL;
            break;
        }
    }
}

static bool crypto_key_is_loaded(const void *ctx)
{
    bool ret = false;
    for (int i = 0; i < 4; i++)
    {
        if (ctx == s_mbedtlsCtx[i])
        {
            ret = true;
            break;
        }
    }
    return ret;
}
#endif

#if defined(MBEDTLS_SHA1_ALT) || defined(MBEDTLS_SHA256_ALT)
/* Implementation that should never be optimized out by the compiler */
static void mbedtls_zeroize(void *v, size_t n)
{
    volatile unsigned char *p = v;
    while (0U != n--)
    {
        *p++ = 0;
    }    
}
#endif /* MBEDTLS_SHA1_ALT || MBEDTLS_SHA256_ALT */

/******************************************************************************/
/******************** CRYPTO_InitHardware **************************************/
/******************************************************************************/
/*!
 * @brief Application init for various Crypto blocks.
 *
 * This function is provided to be called by MCUXpresso SDK applications.
 * It calls basic init for Crypto Hw acceleration and Hw entropy modules.
 */
void CRYPTO_InitHardware(void)
{
#if defined(FSL_FEATURE_SOC_LTC_COUNT) && (FSL_FEATURE_SOC_LTC_COUNT > 0)
    /* Initialize LTC driver.
     * This enables clocking and resets the module to a known state. */
    LTC_Init(LTC0);
#endif
#if defined(FSL_FEATURE_SOC_CAAM_COUNT) && (FSL_FEATURE_SOC_CAAM_COUNT > 0) && defined(CRYPTO_USE_DRIVER_CAAM)
    /* Initialize CAAM driver. */
    caam_config_t caamConfig;

    CAAM_GetDefaultConfig(&caamConfig);
    caamConfig.jobRingInterface[0] = &s_jrif0;
    caamConfig.jobRingInterface[1] = &s_jrif1;
    caamConfig.jobRingInterface[2] = &s_jrif2;
    caamConfig.jobRingInterface[3] = &s_jrif3;

    CAAM_Init(CAAM, &caamConfig);
#endif
#if defined(FSL_FEATURE_SOC_CAU3_COUNT) && (FSL_FEATURE_SOC_CAU3_COUNT > 0)
    /* Initialize CAU3 */
    CAU3_Init(CAU3);
#endif
#if defined(FSL_FEATURE_SOC_DCP_COUNT) && (FSL_FEATURE_SOC_DCP_COUNT > 0)
    /* Initialize DCP */
    dcp_config_t dcpConfig;

    DCP_GetDefaultConfig(&dcpConfig);
    DCP_Init(DCP, &dcpConfig);
#endif
#if defined(FSL_FEATURE_SOC_CASPER_COUNT) && (FSL_FEATURE_SOC_CASPER_COUNT > 0)
    /* Initialize CASPER */
    CASPER_Init(CASPER);
#endif
#if defined(FSL_FEATURE_SOC_HASHCRYPT_COUNT) && (FSL_FEATURE_SOC_HASHCRYPT_COUNT > 0)
    /* Initialize HASHCRYPT */
    HASHCRYPT_Init(HASHCRYPT);
#endif
    { /* Init RNG module.*/
#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0)
#if defined(TRNG)
#define TRNG0 TRNG
#endif
        trng_config_t trngConfig;

        (void)TRNG_GetDefaultConfig(&trngConfig);
        /* Set sample mode of the TRNG ring oscillator to Von Neumann, for better random data.*/
        /* Initialize TRNG */
        (void)TRNG_Init(TRNG0, &trngConfig);
#elif defined(FSL_FEATURE_SOC_RNG_COUNT) && (FSL_FEATURE_SOC_RNG_COUNT > 0)
        RNGA_Init(RNG);
        RNGA_Seed(RNG, SIM->UIDL);
#endif
    }
}

/******************************************************************************/
/*************************** DES **********************************************/
/******************************************************************************/

#if defined(MBEDTLS_DES_C)

#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_MMCAU_DES) || \
    defined(MBEDTLS_FREESCALE_CAAM_DES) || defined(MBEDTLS_FREESCALE_CAU3_DES)

#include "mbedtls/des.h"

#if defined(MBEDTLS_FREESCALE_MMCAU_DES)
const unsigned char parityLookup[128] = {1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0,
                                         0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1,
                                         0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1,
                                         1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
                                         0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0};
#endif

#if defined(MBEDTLS_FREESCALE_MMCAU_DES) || defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES)
/*
 * DES key schedule (56-bit, encryption)
 */
int mbedtls_des_setkey_enc(mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE])
{
#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES)
    memcpy(ctx->sk, key, MBEDTLS_DES_KEY_SIZE);
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    int i;
    unsigned char *sk_b = (unsigned char *)ctx->sk;

    /* fix key parity, if needed */
    for (i = 0; i < MBEDTLS_DES_KEY_SIZE; i++)
    {
        sk_b[i] = (uint8_t)((key[i] & 0xFEU) | parityLookup[key[i] >> 1]);
    }
#endif
    ctx->mode = MBEDTLS_DES_ENCRYPT;

    return (0);
}

/*
 * DES key schedule (56-bit, decryption)
 */
int mbedtls_des_setkey_dec(mbedtls_des_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE])
{
#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES)
    memcpy(ctx->sk, key, MBEDTLS_DES_KEY_SIZE);
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    int i;
    unsigned char *sk_b = (unsigned char *)ctx->sk;

    /* fix key parity, if needed */
    for (i = 0; i < MBEDTLS_DES_KEY_SIZE; i++)
    {
        sk_b[i] = (uint8_t)((key[i] & 0xFEU) | parityLookup[key[i] >> 1]);
    }
#endif
    ctx->mode = MBEDTLS_DES_DECRYPT;

    return (0);
}
#endif /* MBEDTLS_FREESCALE_MMCAU_DES || MBEDTLS_FREESCALE_LTC_DES || MBEDTLS_FREESCALE_CAAM_DES */

/*
 * Triple-DES key schedule (112-bit, encryption)
 */
int mbedtls_des3_set2key_enc(mbedtls_des3_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2])
{
#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES) || defined(MBEDTLS_FREESCALE_CAU3_DES)
    memcpy(ctx->sk, key, MBEDTLS_DES_KEY_SIZE * 2);
    memcpy(&ctx->sk[4], key, MBEDTLS_DES_KEY_SIZE); /* K3 = K1 */
#if defined(MBEDTLS_FREESCALE_CAU3_DES)
    crypto_detach_ctx_from_key_slot(ctx);
#endif
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    int i;
    unsigned char *sk_b = (unsigned char *)ctx->sk;

    /* fix key parity, if needed */
    for (i = 0; i < MBEDTLS_DES_KEY_SIZE * 2; i++)
    {
        sk_b[i] = (uint8_t)((key[i] & 0xFEU) | parityLookup[key[i] >> 1]);
    }
    for (i = MBEDTLS_DES_KEY_SIZE * 2; i < MBEDTLS_DES_KEY_SIZE * 3; i++)
    {
        sk_b[i] = ((key[i - MBEDTLS_DES_KEY_SIZE * 2] & 0xFEU) | parityLookup[key[i - MBEDTLS_DES_KEY_SIZE * 2] >> 1]);
    }
#endif
    ctx->mode = MBEDTLS_DES_ENCRYPT;

    return (0);
}

/*
 * Triple-DES key schedule (112-bit, decryption)
 */
int mbedtls_des3_set2key_dec(mbedtls_des3_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE * 2])
{
#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES) || defined(MBEDTLS_FREESCALE_CAU3_DES)
    memcpy(ctx->sk, key, MBEDTLS_DES_KEY_SIZE * 2);
    memcpy(&ctx->sk[4], key, MBEDTLS_DES_KEY_SIZE); /* K3 = K1 */
#if defined(MBEDTLS_FREESCALE_CAU3_DES)
    crypto_detach_ctx_from_key_slot(ctx);
#endif
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    int i;
    unsigned char *sk_b = (unsigned char *)ctx->sk;

    /* fix key parity, if needed */
    for (i = 0; i < MBEDTLS_DES_KEY_SIZE * 2; i++)
    {
        sk_b[i] = (uint8_t)((key[i] & 0xFEU) | parityLookup[key[i] >> 1]);
    }
    for (i = MBEDTLS_DES_KEY_SIZE * 2; i < MBEDTLS_DES_KEY_SIZE * 3; i++)
    {
        sk_b[i] = ((key[i - MBEDTLS_DES_KEY_SIZE * 2] & 0xFEU) | parityLookup[key[i - MBEDTLS_DES_KEY_SIZE * 2] >> 1]);
    }
#endif
    ctx->mode = MBEDTLS_DES_DECRYPT;

    return (0);
}

/*
 * Triple-DES key schedule (168-bit, encryption)
 */
int mbedtls_des3_set3key_enc(mbedtls_des3_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3])
{
#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES) || defined(MBEDTLS_FREESCALE_CAU3_DES)
    memcpy(ctx->sk, key, MBEDTLS_DES_KEY_SIZE * 3);
#if defined(MBEDTLS_FREESCALE_CAU3_DES)
    crypto_detach_ctx_from_key_slot(ctx);
#endif
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    int i;
    unsigned char *sk_b = (unsigned char *)ctx->sk;

    /* fix key parity, if needed */
    for (i = 0; i < MBEDTLS_DES_KEY_SIZE * 3; i++)
    {
        sk_b[i] = (uint8_t)((key[i] & 0xFEU) | parityLookup[key[i] >> 1]);
    }
#endif
    ctx->mode = MBEDTLS_DES_ENCRYPT;

    return (0);
}

/*
 * Triple-DES key schedule (168-bit, decryption)
 */
int mbedtls_des3_set3key_dec(mbedtls_des3_context *ctx, const unsigned char key[MBEDTLS_DES_KEY_SIZE * 3])
{
#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES) || defined(MBEDTLS_FREESCALE_CAU3_DES)
    memcpy(ctx->sk, key, MBEDTLS_DES_KEY_SIZE * 3);
#if defined(MBEDTLS_FREESCALE_CAU3_DES)
    crypto_detach_ctx_from_key_slot(ctx);
#endif
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    int i;
    unsigned char *sk_b = (unsigned char *)ctx->sk;

    /* fix key parity, if needed */
    for (i = 0; i < MBEDTLS_DES_KEY_SIZE * 3; i++)
    {
        sk_b[i] = (uint8_t)((key[i] & 0xFEU) | parityLookup[key[i] >> 1]);
    }
#endif
    ctx->mode = MBEDTLS_DES_DECRYPT;
    return (0);
}

#if defined(MBEDTLS_FREESCALE_LTC_DES) || defined(MBEDTLS_FREESCALE_MMCAU_DES) || defined(MBEDTLS_FREESCALE_CAAM_DES)
/*
 * DES-ECB block encryption/decryption
 */
int mbedtls_des_crypt_ecb(mbedtls_des_context *ctx, const unsigned char input[8], unsigned char output[8])
{
    uint8_t *key = (uint8_t *)ctx->sk;
#if defined(MBEDTLS_FREESCALE_LTC_DES)
    if (ctx->mode == MBEDTLS_DES_ENCRYPT)
    {
        LTC_DES_EncryptEcb(LTC_INSTANCE, input, output, 8, key);
    }
    else
    {
        LTC_DES_DecryptEcb(LTC_INSTANCE, input, output, 8, key);
    }
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    if (ctx->mode == MBEDTLS_DES_ENCRYPT)
    {
        (void)MMCAU_DES_EncryptEcb(input, key, output);
    }
    else
    {
        (void)MMCAU_DES_DecryptEcb(input, key, output);
    }
#elif defined(MBEDTLS_FREESCALE_CAAM_DES)
    if (ctx->mode == MBEDTLS_DES_ENCRYPT)
    {
        CAAM_DES_EncryptEcb(CAAM_INSTANCE, &s_caamHandle, input, output, 8, key);
    }
    else
    {
        CAAM_DES_DecryptEcb(CAAM_INSTANCE, &s_caamHandle, input, output, 8, key);
    }
#endif
    return (0);
}
#endif /* MBEDTLS_FREESCALE_LTC_DES || MBEDTLS_FREESCALE_MMCAU_DES || MBEDTLS_FREESCALE_CAAM_DES */

/*
 * 3DES-ECB block encryption/decryption
 */
int mbedtls_des3_crypt_ecb(mbedtls_des3_context *ctx, const unsigned char input[8], unsigned char output[8])
{
    uint8_t *key = (uint8_t *)ctx->sk;
#if defined(MBEDTLS_FREESCALE_LTC_DES)
    if (ctx->mode == MBEDTLS_DES_ENCRYPT)
    {
        LTC_DES3_EncryptEcb(LTC_INSTANCE, input, output, 8, key, key + 8, key + 16);
    }
    else
    {
        LTC_DES3_DecryptEcb(LTC_INSTANCE, input, output, 8, key, key + 8, key + 16);
    }
#elif defined(MBEDTLS_FREESCALE_MMCAU_DES)
    if (ctx->mode == MBEDTLS_DES_ENCRYPT)
    {
        (void)MMCAU_DES_EncryptEcb(input, key, output);
        (void)MMCAU_DES_DecryptEcb(output, key + 8, output);
        (void)MMCAU_DES_EncryptEcb(output, key + 16, output);
    }
    else
    {
        (void)MMCAU_DES_DecryptEcb(input, key + 16, output);
        (void)MMCAU_DES_EncryptEcb(output, key + 8, output);
        (void)MMCAU_DES_DecryptEcb(output, key, output);
    }
#elif defined(MBEDTLS_FREESCALE_CAAM_DES)
    if (ctx->mode == MBEDTLS_DES_ENCRYPT)
    {
        CAAM_DES3_EncryptEcb(CAAM_INSTANCE, &s_caamHandle, input, output, 8, key, key + 8, key + 16);
    }
    else
    {
        CAAM_DES3_DecryptEcb(CAAM_INSTANCE, &s_caamHandle, input, output, 8, key, key + 8, key + 16);
    }
#elif defined(MBEDTLS_FREESCALE_CAU3_DES)
    if (!crypto_key_is_loaded(ctx))
    {
        CAU3_TDES_SetKey(CAU3, &s_cau3Handle, key, 24);
        crypto_attach_ctx_to_key_slot(ctx, s_cau3Handle.keySlot);
    }

    if (ctx->mode == MBEDTLS_DES_ENCRYPT)
    {
        CAU3_TDES_Encrypt(CAU3, &s_cau3Handle, input, output);
    }
    else
    {
        CAU3_TDES_Decrypt(CAU3, &s_cau3Handle, input, output);
    }
#endif
    return (0);
}

#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
 * DES-CBC buffer encryption/decryption
 */
#if defined(MBEDTLS_FREESCALE_LTC_DES)
int mbedtls_des_crypt_cbc(mbedtls_des_context *ctx,
                          int mode,
                          size_t length,
                          unsigned char iv[8],
                          const unsigned char *input,
                          unsigned char *output)
{
    unsigned char temp[8];
    uint8_t *key = (uint8_t *)ctx->sk;

    if (length % 8)
        return (MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH);

    if (mode == MBEDTLS_DES_ENCRYPT)
    {
        LTC_DES_EncryptCbc(LTC_INSTANCE, input, output, length, iv, key);
        memcpy(iv, output + length - 8, 8);
    }
    else /* MBEDTLS_DES_DECRYPT */
    {
        memcpy(temp, input + length - 8, 8);
        LTC_DES_DecryptCbc(LTC_INSTANCE, input, output, length, iv, key);
        memcpy(iv, temp, 8);
    }
    return (0);
}

/*
 * 3DES-CBC buffer encryption/decryption
 */
int mbedtls_des3_crypt_cbc(mbedtls_des3_context *ctx,
                           int mode,
                           size_t length,
                           unsigned char iv[8],
                           const unsigned char *input,
                           unsigned char *output)
{
    unsigned char temp[8];
    uint8_t *key = (uint8_t *)ctx->sk;

    if (length % 8)
        return (MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH);

    if (mode == MBEDTLS_DES_ENCRYPT)
    {
        LTC_DES3_EncryptCbc(LTC_INSTANCE, input, output, length, iv, key, key + 8, key + 16);
        memcpy(iv, output + length - 8, 8);
    }
    else /* MBEDTLS_DES_DECRYPT */
    {
        memcpy(temp, input + length - 8, 8);
        LTC_DES3_DecryptCbc(LTC_INSTANCE, input, output, length, iv, key, key + 8, key + 16);
        memcpy(iv, temp, 8);
    }

    return (0);
}
#elif defined(MBEDTLS_FREESCALE_CAAM_DES)
int mbedtls_des_crypt_cbc(mbedtls_des_context *ctx,
                          int mode,
                          size_t length,
                          unsigned char iv[8],
                          const unsigned char *input,
                          unsigned char *output)
{
    unsigned char temp[8];
    uint8_t *key = (uint8_t *)ctx->sk;

    if (length % 8)
        return (MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH);

    if (mode == MBEDTLS_DES_ENCRYPT)
    {
        CAAM_DES_EncryptCbc(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, key);
        memcpy(iv, output + length - 8, 8);
    }
    else /* MBEDTLS_DES_DECRYPT */
    {
        memcpy(temp, input + length - 8, 8);
        CAAM_DES_DecryptCbc(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, key);
        memcpy(iv, temp, 8);
    }
    return (0);
}

/*
 * 3DES-CBC buffer encryption/decryption
 */
int mbedtls_des3_crypt_cbc(mbedtls_des3_context *ctx,
                           int mode,
                           size_t length,
                           unsigned char iv[8],
                           const unsigned char *input,
                           unsigned char *output)
{
    unsigned char temp[8];
    uint8_t *key = (uint8_t *)ctx->sk;

    if (length % 8)
        return (MBEDTLS_ERR_DES_INVALID_INPUT_LENGTH);

    if (mode == MBEDTLS_DES_ENCRYPT)
    {
        CAAM_DES3_EncryptCbc(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, key, key + 8, key + 16);
        memcpy(iv, output + length - 8, 8);
    }
    else /* MBEDTLS_DES_DECRYPT */
    {
        memcpy(temp, input + length - 8, 8);
        CAAM_DES3_DecryptCbc(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, key, key + 8, key + 16);
        memcpy(iv, temp, 8);
    }

    return (0);
}

#endif /* MBEDTLS_FREESCALE_LTC_DES */
#endif /* MBEDTLS_CIPHER_MODE_CBC */

#endif /*MBEDTLS_FREESCALE_LTC_DES || MBEDTLS_FREESCALE_MMCAU_DES || MBEDTLS_FREESCALE_CAAM_DES*/

#endif /* MBEDTLS_DES_C */

/******************************************************************************/
/*************************** AES **********************************************/
/******************************************************************************/

#if defined(MBEDTLS_AES_C)

#if defined(MBEDTLS_FREESCALE_LTC_AES) || defined(MBEDTLS_FREESCALE_MMCAU_AES) || \
    defined(MBEDTLS_FREESCALE_LPC_AES) || defined(MBEDTLS_FREESCALE_CAU3_AES) ||  \
    defined(MBEDTLS_FREESCALE_CAAM_AES) || defined(MBEDTLS_FREESCALE_DCP_AES)

#include "mbedtls/aes.h"

/*
 * AES key schedule (encryption)
 */
int mbedtls_aes_setkey_enc(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits)
{
    uint32_t *RK;
    
#ifdef MBEDTLS_AES_ALT_NO_192
    if (keybits == 192u)
    {
        return (MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE);
    }
#endif

#ifdef MBEDTLS_AES_ALT_NO_256
    if (keybits == 256u)
    {
        return (MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE);
    }
#endif

#if defined(MBEDTLS_FREESCALE_LTC_AES) || defined(MBEDTLS_FREESCALE_LPC_AES) || defined(MBEDTLS_FREESCALE_CAU3_AES) || \
    defined(MBEDTLS_FREESCALE_CAAM_AES) || defined(MBEDTLS_FREESCALE_DCP_AES)
    const unsigned char *key_tmp = key;    
    ctx->rk = RK = ctx->buf;
    (void)memcpy(RK, (const uint32_t *)(uintptr_t)key_tmp, keybits / 8U);

#if defined(MBEDTLS_FREESCALE_CAU3_AES) || defined(MBEDTLS_FREESCALE_DCP_AES)
    crypto_detach_ctx_from_key_slot(ctx);
#endif /* MBEDTLS_FREESCALE_CAU3_AES || MBEDTLS_FREESCALE_DCP_AES */
    
    /* Set keysize in bytes.*/
    switch (keybits)
    { 
        case 128:
            ctx->nr = 16;
            break;
        case 192:
            ctx->nr = 24;
            break;
        case 256:
            ctx->nr = 32;
            break;
        default:
            return (MBEDTLS_ERR_AES_INVALID_KEY_LENGTH);
    }
#elif defined(MBEDTLS_FREESCALE_MMCAU_AES)
    ctx->rk = RK = ctx->buf;

    switch (keybits)
    {
        case 128:
            ctx->nr = 10;
            break;
        case 192:
            ctx->nr = 12;
            break;
        case 256:
            ctx->nr = 14;
            break;
        default:
            return (MBEDTLS_ERR_AES_INVALID_KEY_LENGTH);
    }

    MMCAU_AES_SetKey(key, keybits / 8, (uint8_t *)RK);
#endif

    return (0);
}

/*
 * AES key schedule (decryption)
 */
int mbedtls_aes_setkey_dec(mbedtls_aes_context *ctx, const unsigned char *key, unsigned int keybits)
{
    uint32_t *RK;
    
#ifdef MBEDTLS_AES_ALT_NO_192
    if (keybits == 192u)
    {
        return (MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE);
    }
#endif

#ifdef MBEDTLS_AES_ALT_NO_256
    if (keybits == 256u)
    {
        return (MBEDTLS_ERR_AES_FEATURE_UNAVAILABLE);
    }
#endif

    ctx->rk = RK = ctx->buf;

#if defined(MBEDTLS_FREESCALE_LTC_AES) || defined(MBEDTLS_FREESCALE_LPC_AES) || defined(MBEDTLS_FREESCALE_CAU3_AES) || \
    defined(MBEDTLS_FREESCALE_CAAM_AES) || defined(MBEDTLS_FREESCALE_DCP_AES)
    const unsigned char *key_tmp = key;
    (void)memcpy(RK, (const uint32_t *)(uintptr_t)key_tmp, keybits / 8U);

#if defined(MBEDTLS_FREESCALE_CAU3_AES) || defined(MBEDTLS_FREESCALE_DCP_AES)
    crypto_detach_ctx_from_key_slot(ctx);
#endif /* MBEDTLS_FREESCALE_CAU3_AES || MBEDTLS_FREESCALE_DCP_AES */

    switch (keybits)
    {
        case 128:
            ctx->nr = 16;
            break;
        case 192:
            ctx->nr = 24;
            break;
        case 256:
            ctx->nr = 32;
            break;
        default:
            return (MBEDTLS_ERR_AES_INVALID_KEY_LENGTH);
    }
#elif defined(MBEDTLS_FREESCALE_MMCAU_AES)
    ctx->rk = RK = ctx->buf;

    switch (keybits)
    {
        case 128:
            ctx->nr = 10;
            break;
        case 192:
            ctx->nr = 12;
            break;
        case 256:
            ctx->nr = 14;
            break;
        default:
            return (MBEDTLS_ERR_AES_INVALID_KEY_LENGTH);
    }

    MMCAU_AES_SetKey(key, keybits / 8, (uint8_t *)RK);
#endif

    return 0;
}

/*
 * AES-ECB block encryption
 */
int mbedtls_internal_aes_encrypt(mbedtls_aes_context *ctx, const unsigned char input[16], unsigned char output[16])
{
    uint8_t *key;

    key = (uint8_t *)ctx->rk;
#if defined(MBEDTLS_FREESCALE_LTC_AES)
    LTC_AES_EncryptEcb(LTC_INSTANCE, input, output, 16, key, ctx->nr);
#elif defined(MBEDTLS_FREESCALE_MMCAU_AES)
    MMCAU_AES_EncryptEcb(input, key, ctx->nr, output);
#elif defined(MBEDTLS_FREESCALE_CAU3_AES)
    if (!crypto_key_is_loaded(ctx))
    {
        CAU3_AES_SetKey(CAU3, &s_cau3Handle, key, ctx->nr);
        crypto_attach_ctx_to_key_slot(ctx, s_cau3Handle.keySlot);
    }
    CAU3_AES_Encrypt(CAU3, &s_cau3Handle, input, output);
#elif defined(MBEDTLS_FREESCALE_LPC_AES)
    AES_SetKey(AES_INSTANCE, key, ctx->nr);
    AES_EncryptEcb(AES_INSTANCE, input, output, 16);
#elif defined(MBEDTLS_FREESCALE_CAAM_AES)
    CAAM_AES_EncryptEcb(CAAM_INSTANCE, &s_caamHandle, input, output, 16, key, ctx->nr);
#elif defined(MBEDTLS_FREESCALE_DCP_AES)
    if (!crypto_key_is_loaded(ctx))
    {
        (void)DCP_AES_SetKey(DCP, &s_dcpHandle, key, (uint32_t)ctx->nr);
        crypto_attach_ctx_to_key_slot(ctx, (uint8_t)s_dcpHandle.keySlot);
    }
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
    uint32_t *inputPtr = NULL;
    uint32_t *outputPtr = NULL;
    
    
    /* If input is not cache line aligned, use internal aligned buffer */
    if(IS_CACHE_ALIGNED(input))
    {
        inputPtr = (uint32_t*)(uintptr_t)input;
        DCACHE_CleanByRange((uint32_t)inputPtr, 16); /* will clean 32 bytes granularity */
    }
    else
    {
        inputPtr = (uint32_t*)(uintptr_t)input_buff;
        (void)memcpy(input_buff, input, 16);
        DCACHE_CleanByRange((uint32_t)inputPtr, 16);
    }
 
    /* If output buffer is same as input, use it. Otherwise check if aligned. */
    /* If not use also internal aligned output buffer */
    if (input == output)
    {
        outputPtr = inputPtr;
    }
    else if(IS_CACHE_ALIGNED(output))
    {
        outputPtr = (uint32_t*)(uintptr_t)output;
        DCACHE_CleanByRange((uint32_t)outputPtr, 16); /* will clean 32 bytes granularity */
    }
    else
    {
        outputPtr = (uint32_t*)(uintptr_t)output_buff;
    }
    
    
    (void)DCP_AES_EncryptEcb(DCP, &s_dcpHandle, (uint8_t*)inputPtr ,(uint8_t*) outputPtr, 16);
    
    /* Ivalidate output */
    DCACHE_InvalidateByRange((uint32_t)outputPtr, 16);
    
    /* If output is not aligned we used internal buffer, so we have to copy data to output */
    if(!IS_CACHE_ALIGNED(output))
    {
        (void)memmove(output, (uint8_t *)outputPtr, 16);
    }
    
#else /* __DCACHE_PRESENT && DCP_USE_DCACHE */
    DCP_AES_EncryptEcb(DCP, &s_dcpHandle, input, output, 16);
#endif /* __DCACHE_PRESENT && DCP_USE_DCACHE */
#endif

    return (0);
}

/*
 * AES-ECB block decryption
 */
int mbedtls_internal_aes_decrypt(mbedtls_aes_context *ctx, const unsigned char input[16], unsigned char output[16])
{
    uint8_t *key;

    key = (uint8_t *)ctx->rk;
#if defined(MBEDTLS_FREESCALE_LTC_AES)
    LTC_AES_DecryptEcb(LTC_INSTANCE, input, output, 16, key, ctx->nr, kLTC_EncryptKey);
#elif defined(MBEDTLS_FREESCALE_MMCAU_AES)
    MMCAU_AES_DecryptEcb(input, key, ctx->nr, output);
#elif defined(MBEDTLS_FREESCALE_CAU3_AES)
    if (!crypto_key_is_loaded(ctx))
    {
        CAU3_AES_SetKey(CAU3, &s_cau3Handle, key, ctx->nr);
        crypto_attach_ctx_to_key_slot(ctx, s_cau3Handle.keySlot);
    }
    CAU3_AES_Decrypt(CAU3, &s_cau3Handle, input, output);
#elif defined(MBEDTLS_FREESCALE_LPC_AES)
    AES_SetKey(AES_INSTANCE, key, ctx->nr);
    AES_DecryptEcb(AES_INSTANCE, input, output, 16);
#elif defined(MBEDTLS_FREESCALE_CAAM_AES)
    CAAM_AES_DecryptEcb(CAAM_INSTANCE, &s_caamHandle, input, output, 16, key, ctx->nr);
#elif defined(MBEDTLS_FREESCALE_DCP_AES)
    if (!crypto_key_is_loaded(ctx))
    {
        (void)DCP_AES_SetKey(DCP, &s_dcpHandle, key, (uint32_t)ctx->nr);
        crypto_attach_ctx_to_key_slot(ctx, (uint8_t)s_dcpHandle.keySlot);
    }
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
    uint32_t *inputPtr = NULL;
    uint32_t *outputPtr = NULL;
    
    /* If input is not cache line aligned, use internal aligned buffer */
    if(IS_CACHE_ALIGNED(input))
    {
        inputPtr = (uint32_t*)(uintptr_t)input;
        DCACHE_CleanByRange((uint32_t)inputPtr, 16); /* will clean 32 bytes granularity */
    }
    else
    {
        inputPtr = (uint32_t*)(uintptr_t)input_buff;
        (void)memcpy(input_buff, input, 16);
        DCACHE_CleanByRange((uint32_t)inputPtr, 16);
    }
    
    /* If output buffer is same as input, use it. Otherwise check if aligned. */
    /* If not use also internal aligned output buffer */
    if (input == output)
    {
        outputPtr = inputPtr;
    }
    else if(IS_CACHE_ALIGNED(output))
    {
        outputPtr = (uint32_t*)(uintptr_t)output;
        DCACHE_CleanByRange((uint32_t)outputPtr, 16); /* will clean 32 bytes granularity */
    }
    else
    {
        outputPtr = (uint32_t*)(uintptr_t)output_buff;
    }
    
    
    (void)DCP_AES_DecryptEcb(DCP, &s_dcpHandle, (uint8_t*)inputPtr , (uint8_t*) outputPtr, 16);

    /* Ivalidate output */
    DCACHE_InvalidateByRange((uint32_t)outputPtr, 16);
    /* If output is not aligned we used internal buffer, so we have to copy data to output */
    if(!IS_CACHE_ALIGNED(output))
    {
        (void)memmove(output, (uint8_t *)outputPtr, 16);
    }
    
#else /* __DCACHE_PRESENT && DCP_USE_DCACHE */
    DCP_AES_DecryptEcb(DCP, &s_dcpHandle, input, output, 16);
#endif /* __DCACHE_PRESENT && DCP_USE_DCACHE */
#endif

    return (0);
}

#if defined(MBEDTLS_CIPHER_MODE_CBC)
/*
 * AES-CBC buffer encryption/decryption
 */
#if defined(MBEDTLS_FREESCALE_LTC_AES)
int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx,
                          int mode,
                          size_t length,
                          unsigned char iv[16],
                          const unsigned char *input,
                          unsigned char *output)
{
    uint8_t *key = (uint8_t *)ctx->rk;
    uint32_t keySize = ctx->nr;

    if (length % 16)
        return (MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH);

    if (mode == MBEDTLS_AES_DECRYPT)
    {
        uint8_t tmp[16];
        memcpy(tmp, input + length - 16, 16);
        LTC_AES_DecryptCbc(LTC_INSTANCE, input, output, length, iv, key, keySize, kLTC_EncryptKey);
        memcpy(iv, tmp, 16);
    }
    else
    {
        LTC_AES_EncryptCbc(LTC_INSTANCE, input, output, length, iv, key, keySize);
        memcpy(iv, output + length - 16, 16);
    }

    return (0);
}
#elif defined(MBEDTLS_FREESCALE_LPC_AES)
int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx,
                          int mode,
                          size_t length,
                          unsigned char iv[16],
                          const unsigned char *input,
                          unsigned char *output)
{
    uint8_t *key;
    size_t keySize;

    if (length % 16)
        return (MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH);

    key = (uint8_t *)ctx->rk;
    keySize = (size_t)ctx->nr;
    AES_SetKey(AES_INSTANCE, key, keySize);

    if (mode == MBEDTLS_AES_DECRYPT)
    {
        uint8_t tmp[16];
        memcpy(tmp, input + length - 16, 16);
        AES_DecryptCbc(AES_INSTANCE, tmp, output, length, iv);
        memcpy(iv, tmp, 16);
    }
    else
    {
        AES_EncryptCbc(AES_INSTANCE, input, output, length, iv);
        memcpy(iv, output + length - 16, 16);
    }

    return (0);
}
#elif defined(MBEDTLS_FREESCALE_CAAM_AES)
int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx,
                          int mode,
                          size_t length,
                          unsigned char iv[16],
                          const unsigned char *input,
                          unsigned char *output)
{
    uint8_t *key = (uint8_t *)ctx->rk;
    uint32_t keySize = ctx->nr;

    if (length % 16)
        return (MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH);

    if (mode == MBEDTLS_AES_DECRYPT)
    {
        uint8_t tmp[16];
        memcpy(tmp, input + length - 16, 16);
        CAAM_AES_DecryptCbc(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, key, keySize);
        memcpy(iv, tmp, 16);
    }
    else
    {
        CAAM_AES_EncryptCbc(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, key, keySize);
        memcpy(iv, output + length - 16, 16);
    }

    return (0);
}
#elif defined(MBEDTLS_FREESCALE_DCP_AES)
int mbedtls_aes_crypt_cbc(mbedtls_aes_context *ctx,
                          int mode,
                          size_t length,
                          unsigned char iv[16],
                          const unsigned char *input,
                          unsigned char *output)
{
    uint8_t *key;

    if (0U !=(length % 16U))
        return (MBEDTLS_ERR_AES_INVALID_INPUT_LENGTH);

#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
    if((!IS_IN_NONCACHED((uint32_t)input, length)) && (!IS_CACHE_ALIGNED((uint32_t)input)))
    {
        return MBEDTLS_ERR_DCACHE_ALIGMENT_FAILED;
    }
    
    if((!IS_IN_NONCACHED((uint32_t)output, length)) && (!IS_CACHE_ALIGNED((uint32_t)output)))
    {
        return MBEDTLS_ERR_DCACHE_ALIGMENT_FAILED;
    }
#endif /* __DCACHE_PRESENT && DCP_USE_DCACHE */
    
    key = (uint8_t *)ctx->rk;
    if (!crypto_key_is_loaded(ctx))
    {
        (void)DCP_AES_SetKey(DCP, &s_dcpHandle, key, (uint32_t)ctx->nr);
        crypto_attach_ctx_to_key_slot(ctx, (uint8_t)s_dcpHandle.keySlot);
    }

    if (mode == MBEDTLS_AES_DECRYPT)
    {
        uint8_t tmp[16];
        (void)memcpy(tmp, input + length - 16, 16);
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
        DCACHE_CleanByRange((uint32_t)input, length);
        DCACHE_CleanByRange((uint32_t)iv, 16);
#endif /* __DCACHE_PRESENT && DCP_USE_DCACHE */
        (void)DCP_AES_DecryptCbc(DCP, &s_dcpHandle, input, output, length, iv);
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
        DCACHE_InvalidateByRange((uint32_t)output, length);
#endif /* __DCACHE_PRESENT && DCP_USE_DCACHE */
        (void)memcpy(iv, tmp, 16);
    }
    else
    {
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
        DCACHE_CleanByRange((uint32_t)input, length);
        DCACHE_CleanByRange((uint32_t)iv, 16);
#endif /* __DCACHE_PRESENT && DCP_USE_DCACHE */
        (void)DCP_AES_EncryptCbc(DCP, &s_dcpHandle, input, output, length, iv);
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
        DCACHE_InvalidateByRange((uint32_t)output, length);
#endif /* __DCACHE_PRESENT && DCP_USE_DCACHE */
        (void)memcpy(iv, output + length - 16, 16);
    }

    return (0);
}
#endif
#endif /* MBEDTLS_CIPHER_MODE_CBC */

#if defined(MBEDTLS_CIPHER_MODE_CFB)
#if defined(MBEDTLS_FREESCALE_LPC_AES)
/*
 * AES-CFB128 buffer encryption/decryption
 */
int mbedtls_aes_crypt_cfb128(mbedtls_aes_context *ctx,
                             int mode,
                             size_t length,
                             size_t *iv_off,
                             unsigned char iv[16],
                             const unsigned char *input,
                             unsigned char *output)
{
    uint8_t *key;
    size_t keySize;

    key = (uint8_t *)ctx->rk;
    keySize = (size_t)ctx->nr;
    AES_SetKey(AES_INSTANCE, key, keySize);

    if (mode == MBEDTLS_AES_DECRYPT)
    {
        AES_DecryptCfb(AES_INSTANCE, input, output, length, iv);
    }
    else
    {
        AES_EncryptCfb(AES_INSTANCE, input, output, length, iv);
    }

    return (0);
}

/*
 * AES-CFB8 buffer encryption/decryption
 */
int mbedtls_aes_crypt_cfb8(mbedtls_aes_context *ctx,
                           int mode,
                           size_t length,
                           unsigned char iv[16],
                           const unsigned char *input,
                           unsigned char *output)
{
    int status;
    unsigned char c;
    unsigned char ov[17];

    while (length--)
    {
        memcpy(ov, iv, 16);
        status = mbedtls_aes_crypt_ecb(ctx, MBEDTLS_AES_ENCRYPT, iv, iv);
        if (status != 0)
        {
            return status;
        }

        if (mode == MBEDTLS_AES_DECRYPT)
            ov[16] = *input;

        c = *output++ = (unsigned char)(iv[0] ^ *input++);

        if (mode == MBEDTLS_AES_ENCRYPT)
            ov[16] = c;

        memcpy(iv, ov + 1, 16);
    }

    return (0);
}
#endif /* MBEDTLS_FREESCALE_LPC_AES */
#endif /* MBEDTLS_CIPHER_MODE_CFB */

#if defined(MBEDTLS_CIPHER_MODE_CTR)
/*
 * AES-CTR buffer encryption/decryption
 */
#if defined(MBEDTLS_FREESCALE_LTC_AES)
int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx,
                          size_t length,
                          size_t *nc_off,
                          unsigned char nonce_counter[16],
                          unsigned char stream_block[16],
                          const unsigned char *input,
                          unsigned char *output)
{
    uint8_t *key;
    uint32_t keySize;

    key = (uint8_t *)ctx->rk;
    keySize = ctx->nr;
    LTC_AES_CryptCtr(LTC_INSTANCE, input, output, length, nonce_counter, key, keySize, stream_block,
                     (uint32_t *)nc_off);

    return (0);
}
#elif defined(MBEDTLS_FREESCALE_LPC_AES)
int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx,
                          size_t length,
                          size_t *nc_off,
                          unsigned char nonce_counter[16],
                          unsigned char stream_block[16],
                          const unsigned char *input,
                          unsigned char *output)
{
    uint8_t *key;
    size_t keySize;

    key = (uint8_t *)ctx->rk;
    keySize = (size_t)ctx->nr;

    AES_SetKey(AES_INSTANCE, key, keySize);
    AES_CryptCtr(AES_INSTANCE, input, output, length, nonce_counter, stream_block, nc_off);

    return (0);
}
#elif defined(MBEDTLS_FREESCALE_CAAM_AES)
int mbedtls_aes_crypt_ctr(mbedtls_aes_context *ctx,
                          size_t length,
                          size_t *nc_off,
                          unsigned char nonce_counter[16],
                          unsigned char stream_block[16],
                          const unsigned char *input,
                          unsigned char *output)
{
    uint8_t *key;
    uint32_t keySize;

    key = (uint8_t *)ctx->rk;
    keySize = ctx->nr;

    CAAM_AES_CryptCtr(CAAM_INSTANCE, &s_caamHandle, input, output, length, nonce_counter, key, keySize, stream_block,
                      nc_off);

    return (0);
}
#endif
#endif /* MBEDTLS_CIPHER_MODE_CTR */

#if defined(MBEDTLS_CIPHER_CMAC_ALT) && defined(MBEDTLS_CMAC_C)

#include "mbedtls/cipher.h"
#include "mbedtls/cmac.h"

#if defined(MBEDTLS_FREESCALE_CAU3_CIPHER_CMAC)
int mbedtls_cipher_cmac(const mbedtls_cipher_info_t *cipher_info,
                        const unsigned char *key,
                        size_t keylen,
                        const unsigned char *input,
                        size_t ilen,
                        unsigned char *output)
{
    mbedtls_cipher_context_t ctx;
    int ret;

    if (cipher_info == NULL || key == NULL || input == NULL || output == NULL)
        return (MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA);

    mbedtls_cipher_init(&ctx);

    if ((ret = mbedtls_cipher_setup(&ctx, cipher_info)) != 0)
        goto exit;

    ret = mbedtls_cipher_cmac_starts(&ctx, key, keylen);
    if (ret != 0)
        goto exit;

    /* AES-CMAC-128 is directly supported by CAU3 firmware */
    if (cipher_info->type == MBEDTLS_CIPHER_AES_128_ECB)
    {
        status_t status;
        uint8_t mac[16];

        status = CAU3_AES_SetKey(CAU3, &s_cau3Handle, key, keylen / 8u);
        if (status != kStatus_Success)
        {
            ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
            goto exit;
        }
        status = CAU3_AES_Cmac(CAU3, &s_cau3Handle, input, ilen, mac);
        if (status != kStatus_Success)
        {
            ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
            goto exit;
        }
        memcpy(output, mac, 16);
    }
#if defined(MBEDTLS_CIPHER_CMAC_TDES_ENABLED) || defined(MBEDTLS_CIPHER_CMAC_AES_256_ENABLED)
    else if (cipher_info->type == MBEDTLS_CIPHER_AES_192_ECB)
    {
        /* CAU3 initial firmware does not support AES 192 */
        ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
        goto exit;
    }
    else
    {
        /* AES-CMAC-256 and TDES-CMAC.
         * If both MBEDTLS_DES_C and MBEDTLS_CIPHER_CMAC_WANTS_AES_256 are undefined,
         * this does not compile
         */
        ret = mbedtls_cipher_cmac_update(&ctx, input, ilen);
        if (ret != 0)
            goto exit;

        ret = mbedtls_cipher_cmac_finish(&ctx, output);
    }
#else
    else
    {
        ret = MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA;
        goto exit;
    }
#endif /* MBEDTLS_CIPHER_CMAC_TDES_ENABLED || MBEDTLS_CIPHER_CMAC_AES_256_ENABLED */

exit:
    mbedtls_cipher_free(&ctx);

    return (ret);
}
#endif /* MBEDTLS_FREESCALE_CAU3_CIPHER_CMAC */
#endif /* MBEDTLS_CIPHER_CMAC_ALT && MBEDTLS_CMAC_C */

#if defined(MBEDTLS_CCM_C)

#include "mbedtls/ccm.h"

#define CCM_ENCRYPT 0
#define CCM_DECRYPT 1

/*
 * Authenticated encryption or decryption
 */
#if defined(MBEDTLS_FREESCALE_LTC_AES)
static int ccm_auth_crypt(mbedtls_ccm_context *ctx,
                          int mode,
                          size_t length,
                          const unsigned char *iv,
                          size_t iv_len,
                          const unsigned char *add,
                          size_t add_len,
                          const unsigned char *input,
                          unsigned char *output,
                          unsigned char *tag,
                          size_t tag_len)
{
    status_t status;
    const uint8_t *key;
    uint8_t keySize;
    mbedtls_aes_context *aes_ctx;

    aes_ctx = (mbedtls_aes_context *)ctx->cipher_ctx.cipher_ctx;
    key = (uint8_t *)aes_ctx->rk;
    keySize = aes_ctx->nr;
    if (mode == CCM_ENCRYPT)
    {
        status = LTC_AES_EncryptTagCcm(LTC_INSTANCE, input, output, length, iv, iv_len, add, add_len, key, keySize, tag,
                                       tag_len);
    }
    else
    {
        status = LTC_AES_DecryptTagCcm(LTC_INSTANCE, input, output, length, iv, iv_len, add, add_len, key, keySize, tag,
                                       tag_len);
    }

    if (status == kStatus_InvalidArgument)
    {
        return MBEDTLS_ERR_CCM_BAD_INPUT;
    }
    else if (status != kStatus_Success)
    {
        return MBEDTLS_ERR_CCM_AUTH_FAILED;
    }

    return (0);
}
#elif defined(MBEDTLS_FREESCALE_CAAM_AES)
static int ccm_auth_crypt(mbedtls_ccm_context *ctx,
                          int mode,
                          size_t length,
                          const unsigned char *iv,
                          size_t iv_len,
                          const unsigned char *add,
                          size_t add_len,
                          const unsigned char *input,
                          unsigned char *output,
                          unsigned char *tag,
                          size_t tag_len)
{
    status_t status;
    const uint8_t *key;
    uint8_t keySize;
    mbedtls_aes_context *aes_ctx;

    aes_ctx = (mbedtls_aes_context *)ctx->cipher_ctx.cipher_ctx;
    key = (uint8_t *)aes_ctx->rk;
    keySize = aes_ctx->nr;
    if (mode == CCM_ENCRYPT)
    {
        status = CAAM_AES_EncryptTagCcm(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, iv_len, add, add_len,
                                        key, keySize, tag, tag_len);
    }
    else
    {
        status = CAAM_AES_DecryptTagCcm(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, iv_len, add, add_len,
                                        key, keySize, tag, tag_len);
    }

    if (status == kStatus_InvalidArgument)
    {
        return MBEDTLS_ERR_CCM_BAD_INPUT;
    }
    else if (status != kStatus_Success)
    {
        return MBEDTLS_ERR_CCM_AUTH_FAILED;
    }

    return (0);
}
#endif /* MBEDTLS_FREESCALE_LTC_AES */

#if defined(MBEDTLS_FREESCALE_LTC_AES) || defined(MBEDTLS_FREESCALE_CAAM_AES)
/*
 * Authenticated encryption
 */
int mbedtls_ccm_encrypt_and_tag(mbedtls_ccm_context *ctx,
                                size_t length,
                                const unsigned char *iv,
                                size_t iv_len,
                                const unsigned char *add,
                                size_t add_len,
                                const unsigned char *input,
                                unsigned char *output,
                                unsigned char *tag,
                                size_t tag_len)
{
    return (ccm_auth_crypt(ctx, CCM_ENCRYPT, length, iv, iv_len, add, add_len, input, output, tag, tag_len));
}

/*
 * Authenticated decryption
 */
int mbedtls_ccm_auth_decrypt(mbedtls_ccm_context *ctx,
                             size_t length,
                             const unsigned char *iv,
                             size_t iv_len,
                             const unsigned char *add,
                             size_t add_len,
                             const unsigned char *input,
                             unsigned char *output,
                             const unsigned char *tag,
                             size_t tag_len)
{
    unsigned char tagCopy[16];
    unsigned char *actTag = NULL;
    if (tag)
    {
        memcpy(tagCopy, tag, tag_len);
        actTag = tagCopy;
    }
    return (ccm_auth_crypt(ctx, CCM_DECRYPT, length, iv, iv_len, add, add_len, input, output, actTag, tag_len));
}
#endif /* MBEDTLS_FREESCALE_LTC_AES || MBEDTLS_FREESCALE_CAAM_AES */
#endif /* MBEDTLS_CCM_C */

#if defined(MBEDTLS_GCM_C)
#if defined(MBEDTLS_FREESCALE_LTC_AES_GCM)

#include "mbedtls/gcm.h"

int mbedtls_gcm_crypt_and_tag(mbedtls_gcm_context *ctx,
                              int mode,
                              size_t length,
                              const unsigned char *iv,
                              size_t iv_len,
                              const unsigned char *add,
                              size_t add_len,
                              const unsigned char *input,
                              unsigned char *output,
                              size_t tag_len,
                              unsigned char *tag)
{
    status_t status;
    uint8_t *key;
    uint32_t keySize;
    mbedtls_aes_context *aes_ctx;

    ctx->len = length;
    ctx->add_len = add_len;
    aes_ctx = (mbedtls_aes_context *)ctx->cipher_ctx.cipher_ctx;
    key = (uint8_t *)aes_ctx->rk;
    keySize = aes_ctx->nr;
    if (mode == MBEDTLS_GCM_ENCRYPT)
    {
        status = LTC_AES_EncryptTagGcm(LTC_INSTANCE, input, output, length, iv, iv_len, add, add_len, key, keySize, tag,
                                       tag_len);
    }
    else
    {
        status = LTC_AES_DecryptTagGcm(LTC_INSTANCE, input, output, length, iv, iv_len, add, add_len, key, keySize, tag,
                                       tag_len);
    }

    if (status == kStatus_InvalidArgument)
    {
        return MBEDTLS_ERR_GCM_BAD_INPUT;
    }
    else if (status != kStatus_Success)
    {
        return MBEDTLS_ERR_GCM_AUTH_FAILED;
    }

    return 0;
}

int mbedtls_gcm_auth_decrypt(mbedtls_gcm_context *ctx,
                             size_t length,
                             const unsigned char *iv,
                             size_t iv_len,
                             const unsigned char *add,
                             size_t add_len,
                             const unsigned char *tag,
                             size_t tag_len,
                             const unsigned char *input,
                             unsigned char *output)
{
    unsigned char tag_copy[16];
    unsigned char *actTag = NULL;
    if (tag)
    {
        memcpy(tag_copy, tag, tag_len);
        actTag = tag_copy;
    }
    return (mbedtls_gcm_crypt_and_tag(ctx, MBEDTLS_GCM_DECRYPT, length, iv, iv_len, add, add_len, input, output,
                                      tag_len, actTag));
}

#elif defined(MBEDTLS_FREESCALE_LPC_AES_GCM)

#include "mbedtls/gcm.h"

int mbedtls_gcm_crypt_and_tag(mbedtls_gcm_context *ctx,
                              int mode,
                              size_t length,
                              const unsigned char *iv,
                              size_t iv_len,
                              const unsigned char *add,
                              size_t add_len,
                              const unsigned char *input,
                              unsigned char *output,
                              size_t tag_len,
                              unsigned char *tag)
{
    status_t status;
    uint8_t *key;
    size_t keySize;
    mbedtls_aes_context *aes_ctx;

    ctx->len = length;
    ctx->add_len = add_len;
    aes_ctx = (mbedtls_aes_context *)ctx->cipher_ctx.cipher_ctx;
    key = (uint8_t *)aes_ctx->rk;
    keySize = (size_t)aes_ctx->nr;

    status = AES_SetKey(AES_INSTANCE, key, keySize);
    if (status != kStatus_Success)
    {
        return MBEDTLS_ERR_GCM_BAD_INPUT;
    }

    if (mode == MBEDTLS_GCM_ENCRYPT)
    {
        status = AES_EncryptTagGcm(AES_INSTANCE, input, output, length, iv, iv_len, add, add_len, tag, tag_len);
    }
    else
    {
        status = AES_DecryptTagGcm(AES_INSTANCE, input, output, length, iv, iv_len, add, add_len, tag, tag_len);
    }

    if (status == kStatus_InvalidArgument)
    {
        return MBEDTLS_ERR_GCM_BAD_INPUT;
    }
    else if (status != kStatus_Success)
    {
        return MBEDTLS_ERR_GCM_AUTH_FAILED;
    }

    return 0;
}

int mbedtls_gcm_auth_decrypt(mbedtls_gcm_context *ctx,
                             size_t length,
                             const unsigned char *iv,
                             size_t iv_len,
                             const unsigned char *add,
                             size_t add_len,
                             const unsigned char *tag,
                             size_t tag_len,
                             const unsigned char *input,
                             unsigned char *output)
{
    unsigned char tag_copy[16];

    memcpy(tag_copy, tag, tag_len);
    return (mbedtls_gcm_crypt_and_tag(ctx, MBEDTLS_GCM_DECRYPT, length, iv, iv_len, add, add_len, input, output,
                                      tag_len, tag_copy));
}

#elif defined(MBEDTLS_FREESCALE_CAAM_AES_GCM)

#include "mbedtls/gcm.h"

int mbedtls_gcm_crypt_and_tag(mbedtls_gcm_context *ctx,
                              int mode,
                              size_t length,
                              const unsigned char *iv,
                              size_t iv_len,
                              const unsigned char *add,
                              size_t add_len,
                              const unsigned char *input,
                              unsigned char *output,
                              size_t tag_len,
                              unsigned char *tag)
{
    status_t status;
    uint8_t *key;
    uint32_t keySize;
    mbedtls_aes_context *aes_ctx;

    ctx->len = length;
    ctx->add_len = add_len;
    aes_ctx = (mbedtls_aes_context *)ctx->cipher_ctx.cipher_ctx;
    key = (uint8_t *)aes_ctx->rk;
    keySize = aes_ctx->nr;
    if (mode == MBEDTLS_GCM_ENCRYPT)
    {
        status = CAAM_AES_EncryptTagGcm(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, iv_len, add, add_len,
                                        key, keySize, tag, tag_len);
    }
    else
    {
        status = CAAM_AES_DecryptTagGcm(CAAM_INSTANCE, &s_caamHandle, input, output, length, iv, iv_len, add, add_len,
                                        key, keySize, tag, tag_len);
    }

    if (status == kStatus_InvalidArgument)
    {
        return MBEDTLS_ERR_GCM_BAD_INPUT;
    }
    else if (status != kStatus_Success)
    {
        return MBEDTLS_ERR_GCM_AUTH_FAILED;
    }

    return 0;
}

int mbedtls_gcm_auth_decrypt(mbedtls_gcm_context *ctx,
                             size_t length,
                             const unsigned char *iv,
                             size_t iv_len,
                             const unsigned char *add,
                             size_t add_len,
                             const unsigned char *tag,
                             size_t tag_len,
                             const unsigned char *input,
                             unsigned char *output)
{
    unsigned char tag_copy[16];
    unsigned char *actTag = NULL;
    if (tag)
    {
        memcpy(tag_copy, tag, tag_len);
        actTag = tag_copy;
    }
    return (mbedtls_gcm_crypt_and_tag(ctx, MBEDTLS_GCM_DECRYPT, length, iv, iv_len, add, add_len, input, output,
                                      tag_len, actTag));
}
#endif
#endif /* MBEDTLS_GCM_C */

#endif /* MBEDTLS_FREESCALE_LTC_AES || MBEDTLS_FREESCALE_MMCAU_AES || MBEDTLS_FREESCALE_LPC_AES */

#endif /* MBEDTLS_AES_C */

/******************************************************************************/
/*************************** PKHA *********************************************/
/******************************************************************************/

#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA) || defined(MBEDTLS_FREESCALE_CAAM_PKHA)

#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif

static void ltc_reverse_array(uint8_t *src, size_t src_len)
{
    int i;

    for (i = 0; i < src_len / 2; i++)
    {
        uint8_t tmp;

        tmp = src[i];
        src[i] = src[src_len - 1 - i];
        src[src_len - 1 - i] = tmp;
    }
}

#if defined(MBEDTLS_BIGNUM_C)

#include "mbedtls/bignum.h"

#if defined(MBEDTLS_FREESCALE_CAU3_PKHA)
#define LTC_PKHA_ModAdd CAU3_PKHA_ModAdd
#define LTC_PKHA_ModSub1 CAU3_PKHA_ModSub1
#define LTC_PKHA_ModMul CAU3_PKHA_ModMul
#define LTC_PKHA_ModRed CAU3_PKHA_ModRed
#define LTC_PKHA_ModExp CAU3_PKHA_ModExp
#define LTC_PKHA_GCD CAU3_PKHA_ModGcd
#define LTC_PKHA_ModInv CAU3_PKHA_ModInv
#define LTC_PKHA_PrimalityTest CAU3_PKHA_PrimalityTest
#define LTC_INSTANCE ((CAU3_Type *)CAU3_BASE)

#define kLTC_PKHA_IntegerArith kCAU3_PKHA_IntegerArith
#define kLTC_PKHA_NormalValue kCAU3_PKHA_NormalValue
#define kLTC_PKHA_TimingEqualized kCAU3_PKHA_TimingEqualized

#define cau3_reverse_array ltc_reverse_array
#define cau3_get_from_mbedtls_mpi ltc_get_from_mbedtls_mpi
#endif

#if defined(MBEDTLS_FREESCALE_LTC_PKHA)
typedef uint16_t pkha_size_t;
#else
typedef size_t pkha_size_t;
#endif

#if defined(MBEDTLS_MPI_ADD_ABS_ALT)

/* Access to original version of mbedtls_mpi_add_abs function. */
int mbedtls_mpi_add_abs_orig(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B);

/*
 * Unsigned addition: X = |A| + |B|  (HAC 14.7)
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);
    pkha_size_t sizeN = FREESCALE_PKHA_INT_MAX_BYTES;

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    /*
     * Perform HW acceleration only if the size in bytes is less than maximum.
     * Since modular add is used below, the result would be wrong
     * if the real sum of operands exceeded LTC maximum number value.
     */
    if ((sizeA < sizeN) && (sizeB < sizeN))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *N = mbedtls_calloc(4, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrA = N + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == N)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        memset(N, 0xFF, sizeN);

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        ltc_reverse_array(ptrA, sizeA);

        mbedtls_mpi_write_binary(B, ptrB, sizeB);
        ltc_reverse_array(ptrB, sizeB);

        ret = (int)LTC_PKHA_ModAdd(LTC_INSTANCE, ptrA, sizeA, ptrB, sizeB, N, sizeN, ptrC, &sizeC,
                                   kLTC_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        ltc_reverse_array(ptrC, sizeC);
        mbedtls_mpi_read_binary(X, ptrC, sizeC);
        X->s = 1;
    cleanup:
        if (N)
        {
            mbedtls_free(N);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_add_abs_orig(X, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_add_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);
    pkha_size_t sizeN = FREESCALE_PKHA_INT_MAX_BYTES;

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    /*
     * Perform HW acceleration only if the size in bytes is less than maximum.
     * Since modular add is used below, the result would be wrong
     * if the real sum of operands exceeded CAAM maximum number value.
     */
    if ((sizeA < sizeN) && (sizeB < sizeN))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *N = mbedtls_calloc(4, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrA = N + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == N)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        memset(N, 0xFF, sizeN);

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        mbedtls_mpi_write_binary(B, ptrB, sizeB);

        ret = (int)CAAM_PKHA_ModAdd(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrB, sizeB, N, sizeN, ptrC, &sizeC,
                                    kCAAM_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        mbedtls_mpi_read_binary(X, ptrC, sizeC);
        X->s = 1;
    cleanup:
        if (N)
        {
            mbedtls_free(N);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_add_abs_orig(X, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_ADD_ABS_ALT */

#if defined(MBEDTLS_MPI_SUB_ABS_ALT)

/* Access to original version of mbedtls_mpi_sub_abs function. */
int mbedtls_mpi_sub_abs_orig(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B);

/*
 * Unsigned subtraction: X = |A| - |B|  (HAC 14.9)
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);
    pkha_size_t sizeN = FREESCALE_PKHA_INT_MAX_BYTES;

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    /*
     * Perform HW acceleration only if |A| >= |B|. Since modular subtraction is used below,
     * the result would be wrong if the real sum of operands exceeded maximum.
     */
    if ((sizeA <= sizeN) && (sizeB <= sizeN) && (mbedtls_mpi_cmp_abs(A, B) >= 0))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *N = mbedtls_calloc(4, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrA = N + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == N)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        memset(N, 0xFF, sizeN);

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        ltc_reverse_array(ptrA, sizeA);

        mbedtls_mpi_write_binary(B, ptrB, sizeB);
        ltc_reverse_array(ptrB, sizeB);

        ret = (int)LTC_PKHA_ModSub1(LTC_INSTANCE, ptrA, sizeA, ptrB, sizeB, N, sizeN, ptrC, &sizeC);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        ltc_reverse_array(ptrC, sizeC);
        mbedtls_mpi_read_binary(X, ptrC, sizeC);
        X->s = 1;
    cleanup:
        if (N)
        {
            mbedtls_free(N);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_sub_abs_orig(X, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_sub_abs(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);
    pkha_size_t sizeN = FREESCALE_PKHA_INT_MAX_BYTES;

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    /*
     * Perform HW acceleration only if |A| >= |B|. Since modular subtraction is used below,
     * the result would be wrong if the real sum of operands exceeded maximum.
     */
    if ((sizeA <= sizeN) && (sizeB <= sizeN) && (mbedtls_mpi_cmp_abs(A, B) >= 0))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *N = mbedtls_calloc(4, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrA = N + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == N)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        memset(N, 0xFF, sizeN);

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        mbedtls_mpi_write_binary(B, ptrB, sizeB);

        ret = (int)CAAM_PKHA_ModSub1(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrB, sizeB, N, sizeN, ptrC, &sizeC);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        mbedtls_mpi_read_binary(X, ptrC, sizeC);
        X->s = 1;
    cleanup:
        if (N)
        {
            mbedtls_free(N);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_sub_abs_orig(X, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_SUB_ABS_ALT */

#if defined(MBEDTLS_MPI_MUL_MPI_ALT)

/* Access to original version of mbedtls_mpi_mul_mpi function. */
int mbedtls_mpi_mul_mpi_orig(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B);

/*
 * Baseline multiplication: X = A * B  (HAC 14.12)
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);
    pkha_size_t sizeN = FREESCALE_PKHA_INT_MAX_BYTES;

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    /*
     * Should be "if ((sizeA + sizeB) <= sizeN)", but if the multiplication result
     * would be maximum LTC number (the same value as the modulus N below),
     * zero would be returned instead, which is wrong value.
     */
    if ((sizeA + sizeB) < sizeN)
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        int sign = A->s * B->s;

        uint8_t *N = mbedtls_calloc(4, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrA = N + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == N)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        memset(N, 0xFF, sizeN);

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        ltc_reverse_array(ptrA, sizeA);

        mbedtls_mpi_write_binary(B, ptrB, sizeB);
        ltc_reverse_array(ptrB, sizeB);

        /*
         * Modular multiplication operation is used here. Since the modulus N is larger
         * than the expected result of A * B, the effect is normal multiplication.
         * TODO use PKHA MUL_IM_OM instead.
         */
        ret =
            (int)LTC_PKHA_ModMul(LTC_INSTANCE, ptrA, sizeA, ptrB, sizeB, N, sizeN, ptrC, &sizeC, kLTC_PKHA_IntegerArith,
                                 kLTC_PKHA_NormalValue, kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        ltc_reverse_array(ptrC, sizeC);
        mbedtls_mpi_read_binary(X, ptrC, sizeC);
        X->s = sign;
    cleanup:
        if (N)
        {
            mbedtls_free(N);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_mul_mpi_orig(X, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_mul_mpi(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);
    pkha_size_t sizeN = FREESCALE_PKHA_INT_MAX_BYTES;

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    /*
     * Should be "if ((sizeA + sizeB) <= sizeN)", but if the multiplication result
     * would be maximum CAAM number (the same value as the modulus N below),
     * zero would be returned instead, which is wrong value.
     */
    if ((sizeA + sizeB) < sizeN)
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        int sign = A->s * B->s;

        uint8_t *N = mbedtls_calloc(4, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrA = N + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == N)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        memset(N, 0xFF, sizeN);

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        mbedtls_mpi_write_binary(B, ptrB, sizeB);

        /*
         * Modular multiplication operation is used here. Since the modulus N is larger
         * than the expected result of A * B, the effect is normal multiplication.
         * TODO use PKHA MUL_IM_OM instead.
         */
        ret = (int)CAAM_PKHA_ModMul(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrB, sizeB, N, sizeN, ptrC, &sizeC,
                                    kCAAM_PKHA_IntegerArith, kCAAM_PKHA_NormalValue, kCAAM_PKHA_NormalValue,
                                    kCAAM_PKHA_TimingEqualized);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        mbedtls_mpi_read_binary(X, ptrC, sizeC);
        X->s = sign;
    cleanup:
        if (N)
        {
            mbedtls_free(N);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_mul_mpi_orig(X, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_MUL_MPI_ALT */

#if defined(MBEDTLS_MPI_MOD_MPI_ALT)

/* Access to original version of mbedtls_mpi_mod_mpi function. */
int mbedtls_mpi_mod_mpi_orig(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B);

/*
 * Modulo: R = A mod B
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeA <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeB <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        int sign = A->s;
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        ltc_reverse_array(ptrA, sizeA);

        mbedtls_mpi_write_binary(B, ptrB, sizeB);
        ltc_reverse_array(ptrB, sizeB);

        ret = (int)LTC_PKHA_ModRed(LTC_INSTANCE, ptrA, sizeA, ptrB, sizeB, ptrC, &sizeC, kLTC_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        ltc_reverse_array(ptrC, sizeC);
        mbedtls_mpi_read_binary(R, ptrC, sizeC);
        R->s = sign;

        while (mbedtls_mpi_cmp_int(R, 0) < 0)
            mbedtls_mpi_add_mpi(R, R, B); /* MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) ); */

        while (mbedtls_mpi_cmp_mpi(R, B) >= 0)
            mbedtls_mpi_sub_mpi(R, R, B); /* MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) ); cleanup:*/
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_mod_mpi_orig(R, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_mod_mpi(mbedtls_mpi *R, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeA <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeB <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        int sign = A->s;
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        mbedtls_mpi_write_binary(B, ptrB, sizeB);

        ret = (int)CAAM_PKHA_ModRed(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrB, sizeB, ptrC, &sizeC,
                                    kCAAM_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        mbedtls_mpi_read_binary(R, ptrC, sizeC);
        R->s = sign;

        while (mbedtls_mpi_cmp_int(R, 0) < 0)
            mbedtls_mpi_add_mpi(R, R, B); /* MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( R, R, B ) ); */

        while (mbedtls_mpi_cmp_mpi(R, B) >= 0)
            mbedtls_mpi_sub_mpi(R, R, B); /* MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( R, R, B ) ); cleanup:*/
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_mod_mpi_orig(R, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_MOD_MPI_ALT */

#if defined(MBEDTLS_MPI_EXP_MOD_ALT)

/* Access to original version of mbedtls_mpi_exp_mod function. */
int mbedtls_mpi_exp_mod_orig(
    mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR);

/*
 * Sliding-window exponentiation: X = A^E mod N  (HAC 14.85)
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_exp_mod(
    mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR)
{
    int ret;
    pkha_size_t sizeE = mbedtls_mpi_size(E);
    pkha_size_t sizeN = mbedtls_mpi_size(N);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeE <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeN <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif                   /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        mbedtls_mpi *AA; // TODO rename etc.

        /*
         * If number is greater than modulus, we must first reduce it due to LTC requirement
         * on modular exponentiaton that it needs number less than modulus.
         * We can take advantage of modular arithmetic rule that: A^B mod C = ( (A mod C)^B ) mod C.
         * So we do (A mod N) first and if the size of A in bytes fits into LTC, it will be done in LTC
         * (here LTC does not give size requirement on A versus N), otherwise it will be done in SW
         * and since the size of N fits into LTC, the result of (A mod N) will also fit into LTC.
         * Then we can do modular exponentiation in LTC.
         */
        if (mbedtls_mpi_cmp_mpi(A, N) >= 0)
        {
            /* A >= N, perform X = (A mod N). */
            ret = mbedtls_mpi_mod_mpi(X, A, N);

            if (ret != kStatus_Success)
                return (MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

            /* Exponenciation will be performed with X. */
            AA = X;
        }
        else
        {
            /* Exponentiation will be performed with original A. */
            AA = (mbedtls_mpi *)A;
        }

        pkha_size_t sizeA = mbedtls_mpi_size(AA);
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrE = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrN = ptrE + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(AA, ptrA, sizeA);
        ltc_reverse_array(ptrA, sizeA);

        mbedtls_mpi_write_binary(E, ptrE, sizeE);
        ltc_reverse_array(ptrE, sizeE);

        mbedtls_mpi_write_binary(N, ptrN, sizeN);
        ltc_reverse_array(ptrN, sizeN);

        ret = (int)LTC_PKHA_ModExp(LTC_INSTANCE, ptrA, sizeA, ptrN, sizeN, ptrE, sizeE, ptrN, &sizeN,
                                   kLTC_PKHA_IntegerArith, kLTC_PKHA_NormalValue, kLTC_PKHA_TimingEqualized);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        ltc_reverse_array(ptrN, sizeN);
        mbedtls_mpi_read_binary(X, ptrN, sizeN);
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_exp_mod_orig(X, A, E, N, _RR);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_exp_mod(
    mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *E, const mbedtls_mpi *N, mbedtls_mpi *_RR)
{
    int ret;
    pkha_size_t sizeE = mbedtls_mpi_size(E);
    pkha_size_t sizeN = mbedtls_mpi_size(N);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeE <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeN <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        mbedtls_mpi *AA; // TODO rename etc.

        /*
         * If number is greater than modulus, we must first reduce it due to CAAM requirement
         * on modular exponentiaton that it needs number less than modulus.
         * We can take advantage of modular arithmetic rule that: A^B mod C = ( (A mod C)^B ) mod C.
         * So we do (A mod N) first and if the size of A in bytes fits into CAAM, it will be done in CAAM
         * (here CAAM does not give size requirement on A versus N), otherwise it will be done in SW
         * and since the size of N fits into CAAM, the result of (A mod N) will also fit into CAAM.
         * Then we can do modular exponentiation in CAAM.
         */
        if (mbedtls_mpi_cmp_mpi(A, N) >= 0)
        {
            /* A >= N, perform X = (A mod N). */
            ret = mbedtls_mpi_mod_mpi(X, A, N);

            if (ret != kStatus_Success)
                return (MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

            /* Exponenciation will be performed with X. */
            AA = X;
        }
        else
        {
            /* Exponentiation will be performed with original A. */
            AA = (mbedtls_mpi *)A;
        }

        pkha_size_t sizeA = mbedtls_mpi_size(AA);
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrE = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrN = ptrE + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(AA, ptrA, sizeA);
        mbedtls_mpi_write_binary(E, ptrE, sizeE);
        mbedtls_mpi_write_binary(N, ptrN, sizeN);

        ret = (int)CAAM_PKHA_ModExp(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrN, sizeN, ptrE, sizeE, ptrN, &sizeN,
                                    kCAAM_PKHA_IntegerArith, kCAAM_PKHA_NormalValue, kCAAM_PKHA_TimingEqualized);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        mbedtls_mpi_read_binary(X, ptrN, sizeN);
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_exp_mod_orig(X, A, E, N, _RR);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_EXP_MOD_ALT */

#if defined(MBEDTLS_MPI_GCD_ALT)

/* Access to original version of mbedtls_mpi_gcd function. */
int mbedtls_mpi_gcd_orig(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B);

/*
 * Greatest common divisor: G = gcd(A, B)  (HAC 14.54)
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeA <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeB <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        ltc_reverse_array(ptrA, sizeA);

        mbedtls_mpi_write_binary(B, ptrB, sizeB);
        ltc_reverse_array(ptrB, sizeB);

        if (mbedtls_mpi_cmp_mpi(A, B) >= 0)
        {
            ret = (int)LTC_PKHA_ModRed(LTC_INSTANCE, ptrA, sizeA, ptrB, sizeB, ptrA, &sizeA, kLTC_PKHA_IntegerArith);

            if (ret != kStatus_Success)
                CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }

        ret = (int)LTC_PKHA_GCD(LTC_INSTANCE, ptrA, sizeA, ptrB, sizeB, ptrC, &sizeC, kLTC_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        ltc_reverse_array(ptrC, sizeC);
        mbedtls_mpi_read_binary(G, ptrC, sizeC);
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_gcd_orig(G, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_gcd(mbedtls_mpi *G, const mbedtls_mpi *A, const mbedtls_mpi *B)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeB = mbedtls_mpi_size(B);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeA <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeB <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrB = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrB + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        mbedtls_mpi_write_binary(B, ptrB, sizeB);

        if (mbedtls_mpi_cmp_mpi(A, B) >= 0)
        {
            ret = (int)CAAM_PKHA_ModRed(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrB, sizeB, ptrA, &sizeA,
                                        kCAAM_PKHA_IntegerArith);

            if (ret != kStatus_Success)
                CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }

        ret = (int)CAAM_PKHA_ModGcd(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrB, sizeB, ptrC, &sizeC,
                                    kCAAM_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        mbedtls_mpi_read_binary(G, ptrC, sizeC);
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_gcd_orig(G, A, B);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_GCD_ALT */

#if defined(MBEDTLS_MPI_INV_MOD_ALT)

/* Access to original version of mbedtls_mpi_inv_mod function. */
int mbedtls_mpi_inv_mod_orig(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N);

/*
 * Modular inverse: X = A^-1 mod N  (HAC 14.61 / 14.64)
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeN = mbedtls_mpi_size(N);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeA <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeN <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrN = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrN + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        /* N cannot be negative */
        if (N->s < 0 || mbedtls_mpi_cmp_int(N, 0) == 0)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_BAD_INPUT_DATA);
        }

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        ltc_reverse_array(ptrA, sizeA);

        mbedtls_mpi_write_binary(N, ptrN, sizeN);
        ltc_reverse_array(ptrN, sizeN);

        if (mbedtls_mpi_cmp_mpi(A, N) >= 0)
        {
            ret = (int)LTC_PKHA_ModRed(LTC_INSTANCE, ptrA, sizeA, ptrN, sizeN, ptrA, &sizeA, kLTC_PKHA_IntegerArith);

            if (ret != kStatus_Success)
                CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }

        ret = (int)LTC_PKHA_ModInv(LTC_INSTANCE, ptrA, sizeA, ptrN, sizeN, ptrC, &sizeC, kLTC_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        ltc_reverse_array(ptrC, sizeC);
        mbedtls_mpi_read_binary(X, ptrC, sizeC);
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_inv_mod_orig(X, A, N);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_inv_mod(mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *N)
{
    pkha_size_t sizeA = mbedtls_mpi_size(A);
    pkha_size_t sizeN = mbedtls_mpi_size(N);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if ((sizeA <= FREESCALE_PKHA_INT_MAX_BYTES) && (sizeN <= FREESCALE_PKHA_INT_MAX_BYTES))
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        pkha_size_t sizeC;
        uint8_t *ptrA = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
        uint8_t *ptrN = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;
        uint8_t *ptrC = ptrN + FREESCALE_PKHA_INT_MAX_BYTES;
        if (NULL == ptrA)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        /* N cannot be negative */
        if (N->s < 0 || mbedtls_mpi_cmp_int(N, 0) == 0)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_BAD_INPUT_DATA);
        }

        mbedtls_mpi_write_binary(A, ptrA, sizeA);
        mbedtls_mpi_write_binary(N, ptrN, sizeN);

        if (mbedtls_mpi_cmp_mpi(A, N) >= 0)
        {
            ret = (int)CAAM_PKHA_ModRed(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrN, sizeN, ptrA, &sizeA,
                                        kCAAM_PKHA_IntegerArith);

            if (ret != kStatus_Success)
                CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }

        ret = (int)CAAM_PKHA_ModInv(CAAM_INSTANCE, &s_caamHandle, ptrA, sizeA, ptrN, sizeN, ptrC, &sizeC,
                                    kCAAM_PKHA_IntegerArith);

        if (ret != kStatus_Success)
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);

        mbedtls_mpi_read_binary(X, ptrC, sizeC);
    cleanup:
        if (ptrA)
        {
            mbedtls_free(ptrA);
        }
        return (ret);
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_inv_mod_orig(X, A, N);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_INV_MOD_ALT */

#if defined(MBEDTLS_MPI_IS_PRIME_ALT)

/* Access to original version of mbedtls_mpi_is_prime function. */
int mbedtls_mpi_is_prime_orig(const mbedtls_mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng);

/*
 * Pseudo-primality test: small factors, then Miller-Rabin
 */
#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int mbedtls_mpi_is_prime(const mbedtls_mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
    pkha_size_t sizeX = mbedtls_mpi_size(X);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if (sizeX <= FREESCALE_PKHA_INT_MAX_BYTES)
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        int random;
        bool result = false;
        uint8_t *ptrX = mbedtls_calloc(1, FREESCALE_PKHA_INT_MAX_BYTES);
        if (NULL == ptrX)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(X, ptrX, FREESCALE_PKHA_INT_MAX_BYTES);
        ltc_reverse_array(ptrX, FREESCALE_PKHA_INT_MAX_BYTES);

        // Get the random seed number
        f_rng(p_rng, (unsigned char *)(&random), sizeof(random));

        ret = (int)LTC_PKHA_PrimalityTest(LTC_INSTANCE, (unsigned char *)&random, sizeof(random), (const uint8_t *)"1",
                                          1u, ptrX, sizeX, &result);

        if (ret != kStatus_Success)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }

        if (result == false)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }
    cleanup:
        if (ptrX)
        {
            mbedtls_free(ptrX);
        }
        return ret;
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_is_prime_orig(X, f_rng, p_rng);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int mbedtls_mpi_is_prime(const mbedtls_mpi *X, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng)
{
    pkha_size_t sizeX = mbedtls_mpi_size(X);

#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    if (sizeX <= FREESCALE_PKHA_INT_MAX_BYTES)
    {
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
        int ret;
        int random;
        bool result = false;
        uint8_t *ptrX = mbedtls_calloc(1, FREESCALE_PKHA_INT_MAX_BYTES);
        if (NULL == ptrX)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
        }

        mbedtls_mpi_write_binary(X, ptrX, FREESCALE_PKHA_INT_MAX_BYTES);

        // Get the random seed number
        f_rng(p_rng, (unsigned char *)(&random), sizeof(random));

        ret = (int)CAAM_PKHA_PrimalityTest(CAAM_INSTANCE, &s_caamHandle, (unsigned char *)&random, sizeof(random),
                                           (const uint8_t *)"1", 1u, ptrX, sizeX, &result);

        if (ret != kStatus_Success)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }

        if (result == false)
        {
            CLEAN_RETURN(MBEDTLS_ERR_MPI_NOT_ACCEPTABLE);
        }
    cleanup:
        if (ptrX)
        {
            mbedtls_free(ptrX);
        }
        return ret;
#if defined(FREESCALE_PKHA_LONG_OPERANDS_ENABLE)
    }
    else
    {
        return mbedtls_mpi_is_prime_orig(X, f_rng, p_rng);
    }
#endif /* FREESCALE_PKHA_LONG_OPERANDS_ENABLE */
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA || MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_MPI_IS_PRIME_ALT */

#endif /* MBEDTLS_BIGNUM_C */

#if defined(MBEDTLS_ECP_C)

#include "mbedtls/ecp.h"

#define LTC_MAX_ECC (512)
#define CAAM_MAX_ECC (528)
#define CAU3_MAX_ECC (512)

typedef enum
{
    kBigEndian = 0U,
    kLittleEndian = 1U
} endian_t;

/* convert from mbedtls_mpi to LTC or CAAM integer, as array of bytes of size sz.
 * if mbedtls_mpi has less bytes than sz, add zero bytes at most significant byte positions.
 * This is when for example modulus is 32 bytes (P-256 curve)
 * and mbedtls_mpi has only 31 bytes, we add leading zeroes
 * so that result array has 32 bytes, same as modulus (sz).
 */
#if defined(MBEDTLS_ECP_MUL_COMB_ALT) || defined(MBEDTLS_ECP_ADD_ALT)
static int get_and_extend_mbedtls_mpi(uint8_t *dst, const mbedtls_mpi *a, size_t sz, endian_t endian)
{
    size_t szbin;
    int offset;
    int ret;

    /* check how many bytes are in the mbedtls_mpi */
    szbin = mbedtls_mpi_size(a);

    /* compute offset from dst */
    offset = sz - szbin;
    if (offset < 0)
        offset = 0;
    if (offset > sz)
        offset = sz;

    /* add leading zeroes */
    if (offset)
        memset(dst, 0, offset);

    /* convert mbedtls_mpi to array of bytes */
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(a, dst + offset, szbin));

    /* reverse array for LTC direct use */
    if (endian == kLittleEndian)
        ltc_reverse_array(dst, sz);
cleanup:
    return (ret);
}

#if defined(MBEDTLS_FREESCALE_LTC_PKHA) || defined(MBEDTLS_FREESCALE_CAU3_PKHA)
static int ltc_get_from_mbedtls_mpi(uint8_t *dst, const mbedtls_mpi *a, size_t sz)
{
    return get_and_extend_mbedtls_mpi(dst, a, sz, kLittleEndian);
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
static int caam_get_from_mbedtls_mpi(uint8_t *dst, const mbedtls_mpi *a, size_t sz)
{
    return get_and_extend_mbedtls_mpi(dst, a, sz, kBigEndian);
}
#endif /* MBEDTLS_FREESCALE_LTC_PKHA */
#endif /* MBEDTLS_ECP_MUL_COMB_ALT || MBEDTLS_ECP_ADD_ALT */

/*
 * Multiplication using the comb method,
 * for curves in short Weierstrass form
 */
#if defined(MBEDTLS_ECP_MUL_COMB_ALT)
#if defined(MBEDTLS_FREESCALE_LTC_PKHA)
int ecp_mul_comb(mbedtls_ecp_group *grp,
                 mbedtls_ecp_point *R,
                 const mbedtls_mpi *m,
                 const mbedtls_ecp_point *P,
                 int (*f_rng)(void *, unsigned char *, size_t),
                 void *p_rng)
{
    int ret;
    bool is_inf;
    size_t size;
    size_t size_bin;
    int sign = m->s;

    ltc_pkha_ecc_point_t A;
    ltc_pkha_ecc_point_t result;

    /* Allocate 7 elements with size of (LTC_MAX_ECC / 8) plus ptrE with size of FREESCALE_PKHA_INT_MAX_BYTES */
    uint8_t *ptrAX = mbedtls_calloc((7 * (LTC_MAX_ECC / 8)) + FREESCALE_PKHA_INT_MAX_BYTES, 1);
    uint8_t *ptrAY = ptrAX + (LTC_MAX_ECC / 8);
    uint8_t *ptrRX = ptrAY + (LTC_MAX_ECC / 8);
    uint8_t *ptrRY = ptrRX + (LTC_MAX_ECC / 8);
    uint8_t *ptrN = ptrRY + (LTC_MAX_ECC / 8);
    uint8_t *ptrParamA = ptrN + (LTC_MAX_ECC / 8);
    uint8_t *ptrParamB = ptrParamA + (LTC_MAX_ECC / 8);
    uint8_t *ptrE = ptrParamB + (LTC_MAX_ECC / 8);
    if (NULL == ptrAX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    A.X = ptrAX;
    A.Y = ptrAY;
    result.X = ptrRX;
    result.Y = ptrRY;
    size = mbedtls_mpi_size(&grp->P);
    if (mbedtls_mpi_size(&P->X) > (LTC_MAX_ECC / 8) || (mbedtls_mpi_get_bit(&grp->N, 0) != 1))
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert multi precision integers to arrays */
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(A.X, &P->X, size));
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(A.Y, &P->Y, size));
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(ptrParamA, &grp->A, size));
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(ptrParamB, &grp->B, size));

    /* scalar multiplier integer of any size */
    size_bin = mbedtls_mpi_size(m);
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(m, ptrE, size_bin));
    ltc_reverse_array(ptrE, size_bin);

    /* modulus */
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&grp->P, ptrN, size));
    ltc_reverse_array(ptrN, size);

    /* Multiply */
    LTC_PKHA_ECC_PointMul(LTC_INSTANCE, &A, ptrE, size_bin, ptrN, NULL, ptrParamA, ptrParamB, size,
                          kLTC_PKHA_TimingEqualized, kLTC_PKHA_IntegerArith, &result, &is_inf);
    /* Convert result */
    ltc_reverse_array(ptrRX, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->X, ptrRX, size));
    ltc_reverse_array(ptrRY, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->Y, ptrRY, size));
    /* if the integer multiplier is negative, the computation happens with abs() value
     * and the result (x,y) is changed to (x, -y)
     */
    R->Y.s = sign;
    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));

cleanup:
    if (ptrAX)
    {
        mbedtls_free(ptrAX);
    }
    return (ret);
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int ecp_mul_comb(mbedtls_ecp_group *grp,
                 mbedtls_ecp_point *R,
                 const mbedtls_mpi *m,
                 const mbedtls_ecp_point *P,
                 int (*f_rng)(void *, unsigned char *, size_t),
                 void *p_rng)
{
    int ret;
    size_t size;
    size_t size_bin;
    int sign = m->s;

    caam_pkha_ecc_point_t A;
    caam_pkha_ecc_point_t result;

    /* Allocate 7 elements with size of (CAAM_MAX_ECC / 8) plus ptrE with size of FREESCALE_PKHA_INT_MAX_BYTES */
    uint8_t *ptrAX = mbedtls_calloc((7 * (CAAM_MAX_ECC / 8)) + FREESCALE_PKHA_INT_MAX_BYTES, 1);
    uint8_t *ptrAY = ptrAX + (CAAM_MAX_ECC / 8);
    uint8_t *ptrRX = ptrAY + (CAAM_MAX_ECC / 8);
    uint8_t *ptrRY = ptrRX + (CAAM_MAX_ECC / 8);
    uint8_t *ptrN = ptrRY + (CAAM_MAX_ECC / 8);
    uint8_t *ptrParamA = ptrN + (CAAM_MAX_ECC / 8);
    uint8_t *ptrParamB = ptrParamA + (CAAM_MAX_ECC / 8);
    uint8_t *ptrE = ptrParamB + (CAAM_MAX_ECC / 8);
    if (NULL == ptrAX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    A.X = ptrAX;
    A.Y = ptrAY;
    result.X = ptrRX;
    result.Y = ptrRY;
    size = mbedtls_mpi_size(&grp->P);
    if (mbedtls_mpi_size(&P->X) > (CAAM_MAX_ECC / 8) || (mbedtls_mpi_get_bit(&grp->N, 0) != 1))
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert multi precision integers to arrays */
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(A.X, &P->X, size));
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(A.Y, &P->Y, size));
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(ptrParamA, &grp->A, size));
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(ptrParamB, &grp->B, size));

    /* scalar multiplier integer of any size */
    size_bin = mbedtls_mpi_size(m);
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(m, ptrE, size_bin));

    /* modulus */
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&grp->P, ptrN, size));

    /* Multiply */
    CAAM_PKHA_ECC_PointMul(CAAM_INSTANCE, &s_caamHandle, &A, ptrE, size_bin, ptrN, NULL, ptrParamA, ptrParamB, size,
                           kCAAM_PKHA_TimingEqualized, kCAAM_PKHA_IntegerArith, &result);
    /* Convert result */
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->X, ptrRX, size));
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->Y, ptrRY, size));
    /* if the integer multiplier is negative, the computation happens with abs() value
     * and the result (x,y) is changed to (x, -y)
     */
    R->Y.s = sign;
    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));

cleanup:
    if (ptrAX)
    {
        mbedtls_free(ptrAX);
    }
    return (ret);
}

#elif defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int ecp_mul_comb(mbedtls_ecp_group *grp,
                 mbedtls_ecp_point *R,
                 const mbedtls_mpi *m,
                 const mbedtls_ecp_point *P,
                 int (*f_rng)(void *, unsigned char *, size_t),
                 void *p_rng)
{
    int ret;
    status_t status;
    size_t size;
    size_t size_bin;
    int sign = m->s;

    cau3_pkha_ecc_point_t A;
    cau3_pkha_ecc_point_t result;

    /* Allocate 7 elements with size of (CAU3_MAX_ECC / 8) plus ptrE with size of FREESCALE_PKHA_INT_MAX_BYTES */
    uint8_t *ptrAX = mbedtls_calloc((7 * (CAU3_MAX_ECC / 8)) + FREESCALE_PKHA_INT_MAX_BYTES, 1);
    uint8_t *ptrAY = ptrAX + (CAU3_MAX_ECC / 8);
    uint8_t *ptrRX = ptrAY + (CAU3_MAX_ECC / 8);
    uint8_t *ptrRY = ptrRX + (CAU3_MAX_ECC / 8);
    uint8_t *ptrN = ptrRY + (CAU3_MAX_ECC / 8);
    uint8_t *ptrParamA = ptrN + (CAU3_MAX_ECC / 8);
    uint8_t *ptrParamB = ptrParamA + (CAU3_MAX_ECC / 8);
    uint8_t *ptrE = ptrParamB + (CAU3_MAX_ECC / 8);
    if (NULL == ptrAX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    A.X = ptrAX;
    A.Y = ptrAY;
    result.X = ptrRX;
    result.Y = ptrRY;
    size = mbedtls_mpi_size(&grp->P);
    if (mbedtls_mpi_size(&P->X) > (CAU3_MAX_ECC / 8) || (mbedtls_mpi_get_bit(&grp->N, 0) != 1))
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert multi precision integers to arrays */
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(A.X, &P->X, size));
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(A.Y, &P->Y, size));
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(ptrParamA, &grp->A, size));
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(ptrParamB, &grp->B, size));

    /* scalar multiplier integer of any size */
    size_bin = mbedtls_mpi_size(m);
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(m, ptrE, size_bin));
    cau3_reverse_array(ptrE, size_bin);

    /* modulus */
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&grp->P, ptrN, size));
    cau3_reverse_array(ptrN, size);

    /* Multiply */
    status = CAU3_PKHA_ECC_PointMul(CAU3, &A, ptrE, size_bin, ptrN, NULL, ptrParamA, ptrParamB, size,
                                    kCAU3_PKHA_TimingEqualized, kCAU3_PKHA_IntegerArith, &result);

    if (status != kStatus_Success)
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert result */
    cau3_reverse_array(ptrRX, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->X, ptrRX, size));
    cau3_reverse_array(ptrRY, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->Y, ptrRY, size));
    /* if the integer multiplier is negative, the computation happens with abs() value
     * and the result (x,y) is changed to (x, -y)
     */
    R->Y.s = sign;
    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));

cleanup:
    if (ptrAX)
    {
        mbedtls_free(ptrAX);
    }
    return (ret);
}

#endif /* MBEDTLS_FREESCALE_LTC_PKHA */
#endif /* MBEDTLS_ECP_MUL_COMB_ALT */

/*
 * Curve types: internal for now, might be exposed later
 */
typedef enum
{
    ECP_TYPE_NONE = 0,
    ECP_TYPE_SHORT_WEIERSTRASS, /* y^2 = x^3 + a x + b      */
    ECP_TYPE_MONTGOMERY,        /* y^2 = x^3 + a x^2 + x    */
} ecp_curve_type;
/*
 * Get the type of a curve
 */
static inline ecp_curve_type ecp_get_type(const mbedtls_ecp_group *grp)
{
    if (grp->G.X.p == NULL)
        return (ECP_TYPE_NONE);

    if (grp->G.Y.p == NULL)
        return (ECP_TYPE_MONTGOMERY);
    else
        return (ECP_TYPE_SHORT_WEIERSTRASS);
}

/*
 * Addition: R = P + Q, result's coordinates normalized
 */
#if defined(MBEDTLS_ECP_ADD_ALT)
#if defined(MBEDTLS_FREESCALE_LTC_PKHA)
int ecp_add(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q)
{
    int ret;
    size_t size;
    ltc_pkha_ecc_point_t A;
    ltc_pkha_ecc_point_t B;
    ltc_pkha_ecc_point_t result;

    uint8_t *ptrAX = mbedtls_calloc(9, (LTC_MAX_ECC / 8));
    uint8_t *ptrAY = ptrAX + (LTC_MAX_ECC / 8);
    uint8_t *ptrBX = ptrAY + (LTC_MAX_ECC / 8);
    uint8_t *ptrBY = ptrBX + (LTC_MAX_ECC / 8);
    uint8_t *ptrRX = ptrBY + (LTC_MAX_ECC / 8);
    uint8_t *ptrRY = ptrRX + (LTC_MAX_ECC / 8);
    uint8_t *ptrN = ptrRY + (LTC_MAX_ECC / 8);
    uint8_t *ptrParamA = ptrN + (LTC_MAX_ECC / 8);
    uint8_t *ptrParamB = ptrParamA + (LTC_MAX_ECC / 8);
    if (NULL == ptrAX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    if (ecp_get_type(grp) != ECP_TYPE_SHORT_WEIERSTRASS)
        CLEAN_RETURN(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE);

    A.X = ptrAX;
    A.Y = ptrAY;
    B.X = ptrBX;
    B.Y = ptrBY;
    result.X = ptrRX;
    result.Y = ptrRY;
    size = mbedtls_mpi_size(&grp->P);
    if (mbedtls_mpi_size(&P->X) > (LTC_MAX_ECC / 8) || (mbedtls_mpi_get_bit(&grp->P, 0) != 1))
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert multi precision integers to arrays */
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(A.X, &P->X, size));
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(A.Y, &P->Y, size));
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(B.X, &Q->X, size));
    MBEDTLS_MPI_CHK(ltc_get_from_mbedtls_mpi(B.Y, &Q->Y, size));
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&grp->P, ptrN, size));
    ltc_reverse_array(ptrN, size);
    /* Multiply */
    LTC_PKHA_ECC_PointAdd(LTC_INSTANCE, &A, &B, ptrN, NULL, ptrParamA, ptrParamB, size, kLTC_PKHA_IntegerArith,
                          &result);
    /* Convert result */
    ltc_reverse_array(ptrRX, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->X, ptrRX, size));
    ltc_reverse_array(ptrRY, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->Y, ptrRY, size));
    R->X.s = P->X.s;
    R->Y.s = P->Y.s;
    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));

cleanup:
    if (ptrAX)
    {
        mbedtls_free(ptrAX);
    }
    return (ret);
}

#elif defined(MBEDTLS_FREESCALE_CAAM_PKHA)
int ecp_add(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q)
{
    int ret;
    size_t size;
    caam_pkha_ecc_point_t A;
    caam_pkha_ecc_point_t B;
    caam_pkha_ecc_point_t result;

    uint8_t *ptrAX = mbedtls_calloc(9, (CAAM_MAX_ECC / 8));
    uint8_t *ptrAY = ptrAX + (CAAM_MAX_ECC / 8);
    uint8_t *ptrBX = ptrAY + (CAAM_MAX_ECC / 8);
    uint8_t *ptrBY = ptrBX + (CAAM_MAX_ECC / 8);
    uint8_t *ptrRX = ptrBY + (CAAM_MAX_ECC / 8);
    uint8_t *ptrRY = ptrRX + (CAAM_MAX_ECC / 8);
    uint8_t *ptrN = ptrRY + (CAAM_MAX_ECC / 8);
    uint8_t *ptrParamA = ptrN + (CAAM_MAX_ECC / 8);
    uint8_t *ptrParamB = ptrParamA + (CAAM_MAX_ECC / 8);
    if (NULL == ptrAX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    if (ecp_get_type(grp) != ECP_TYPE_SHORT_WEIERSTRASS)
        CLEAN_RETURN(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE);

    A.X = ptrAX;
    A.Y = ptrAY;
    B.X = ptrBX;
    B.Y = ptrBY;
    result.X = ptrRX;
    result.Y = ptrRY;
    size = mbedtls_mpi_size(&grp->P);
    if (mbedtls_mpi_size(&P->X) > (CAAM_MAX_ECC / 8) || (mbedtls_mpi_get_bit(&grp->P, 0) != 1))
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert multi precision integers to arrays */
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(A.X, &P->X, size));
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(A.Y, &P->Y, size));
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(B.X, &Q->X, size));
    MBEDTLS_MPI_CHK(caam_get_from_mbedtls_mpi(B.Y, &Q->Y, size));
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&grp->P, ptrN, size));

    /* Multiply */
    CAAM_PKHA_ECC_PointAdd(CAAM_INSTANCE, &s_caamHandle, &A, &B, ptrN, NULL, ptrParamA, ptrParamB, size,
                           kCAAM_PKHA_IntegerArith, &result);
    /* Convert result */
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->X, ptrRX, size));
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->Y, ptrRY, size));
    R->X.s = P->X.s;
    R->Y.s = P->Y.s;
    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));

cleanup:
    if (ptrAX)
    {
        mbedtls_free(ptrAX);
    }
    return (ret);
}

#elif defined(MBEDTLS_FREESCALE_CAU3_PKHA)
int ecp_add(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q)
{
    int ret;
    status_t status;
    size_t size;
    cau3_pkha_ecc_point_t A;
    cau3_pkha_ecc_point_t B;
    cau3_pkha_ecc_point_t result;

    uint8_t *ptrAX = mbedtls_calloc(9, (CAU3_MAX_ECC / 8));
    uint8_t *ptrAY = ptrAX + (CAU3_MAX_ECC / 8);
    uint8_t *ptrBX = ptrAY + (CAU3_MAX_ECC / 8);
    uint8_t *ptrBY = ptrBX + (CAU3_MAX_ECC / 8);
    uint8_t *ptrRX = ptrBY + (CAU3_MAX_ECC / 8);
    uint8_t *ptrRY = ptrRX + (CAU3_MAX_ECC / 8);
    uint8_t *ptrN = ptrRY + (CAU3_MAX_ECC / 8);
    uint8_t *ptrParamA = ptrN + (CAU3_MAX_ECC / 8);
    uint8_t *ptrParamB = ptrParamA + (CAU3_MAX_ECC / 8);
    if (NULL == ptrAX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    if (ecp_get_type(grp) != ECP_TYPE_SHORT_WEIERSTRASS)
        CLEAN_RETURN(MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE);

    A.X = ptrAX;
    A.Y = ptrAY;
    B.X = ptrBX;
    B.Y = ptrBY;
    result.X = ptrRX;
    result.Y = ptrRY;
    size = mbedtls_mpi_size(&grp->P);
    if (mbedtls_mpi_size(&P->X) > (CAU3_MAX_ECC / 8) || (mbedtls_mpi_get_bit(&grp->P, 0) != 1))
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert multi precision integers to arrays */
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(A.X, &P->X, size));
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(A.Y, &P->Y, size));
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(B.X, &Q->X, size));
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(B.Y, &Q->Y, size));
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&grp->P, ptrN, size));
    cau3_reverse_array(ptrN, size);
    /* Multiply */
    status =
        CAU3_PKHA_ECC_PointAdd(CAU3, &A, &B, ptrN, NULL, ptrParamA, ptrParamB, size, kCAU3_PKHA_IntegerArith, &result);

    if (status != kStatus_Success)
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert result */
    cau3_reverse_array(ptrRX, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->X, ptrRX, size));
    cau3_reverse_array(ptrRY, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->Y, ptrRY, size));
    R->X.s = P->X.s;
    R->Y.s = P->Y.s;
    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));

cleanup:
    if (ptrAX)
    {
        mbedtls_free(ptrAX);
    }
    return (ret);
}

#endif /* MBEDTLS_FREESCALE_LTC_PKHA */

#endif /* MBEDTLS_ECP_ADD_ALT */

#if defined(MBEDTLS_ECP_MUL_MXZ_ALT)
#if defined(MBEDTLS_FREESCALE_CAU3_PKHA)

/* curve25519 params - in little endian for CAU3 */
static const uint8_t s_curve25519_A24[] = {0x42, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                           0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

static const uint8_t s_curve25519_N[] = {0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
                                         0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f};

static const uint8_t s_curve25519_R2modN[] = {0xa4, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                                              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

int ecp_mul_mxz(mbedtls_ecp_group *grp,
                mbedtls_ecp_point *R,
                const mbedtls_mpi *m,
                const mbedtls_ecp_point *P,
                int (*f_rng)(void *, unsigned char *, size_t),
                void *p_rng)
{
    int ret;
    status_t status;
    size_t size;
    size_t size_bin;

    cau3_pkha_ecc_point_t A;
    cau3_pkha_ecc_point_t result;

    /* Allocate 2 elements with size of (CAU3_MAX_ECC / 8) plus ptrE with size of FREESCALE_PKHA_INT_MAX_BYTES */
    uint8_t *ptrAX = mbedtls_calloc((2 * (CAU3_MAX_ECC / 8)) + FREESCALE_PKHA_INT_MAX_BYTES, 1);
    uint8_t *ptrRX = ptrAX + (CAU3_MAX_ECC / 8);
    uint8_t *ptrE = ptrRX + (CAU3_MAX_ECC / 8);
    if (NULL == ptrAX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    A.X = ptrAX;
    result.X = ptrRX;
    size = mbedtls_mpi_size(&grp->P);
    if (mbedtls_mpi_size(&P->X) > (CAAM_MAX_ECC / 8))
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert multi precision integers to arrays */
    MBEDTLS_MPI_CHK(cau3_get_from_mbedtls_mpi(A.X, &P->X, size));

    /* scalar multiplier integer of any size */
    size_bin = mbedtls_mpi_size(m);
    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(m, ptrE, size_bin));
    cau3_reverse_array(ptrE, size_bin);

    /* Multiply */
    status = CAU3_PKHA_ECM_PointMul(CAU3, ptrE, size_bin, A.X, s_curve25519_A24, s_curve25519_N, s_curve25519_R2modN,
                                    size, kCAU3_PKHA_TimingEqualized, result.X);

    if (status != kStatus_Success)
    {
        CLEAN_RETURN(MBEDTLS_ERR_ECP_BAD_INPUT_DATA);
    }

    /* Convert result */
    cau3_reverse_array(ptrRX, size);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&R->X, ptrRX, size));
    MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));

cleanup:
    if (ptrAX)
    {
        mbedtls_free(ptrAX);
    }
    return (ret);
}

#endif /* MBEDTLS_FREESCALE_CAU3_PKHA */
#endif /* MBEDTLS_ECP_MUL_MXZ_ALT */

#endif /* MBEDTLS_ECP_C */

#endif /* MBEDTLS_FREESCALE_LTC_PKHA */

#if defined(MBEDTLS_RSA_PUBLIC_ALT)
#if defined(MBEDTLS_FREESCALE_CASPER_PKHA)

#if defined(MBEDTLS_PLATFORM_C)
#include "mbedtls/platform.h"
#else
#include <stdio.h>
#define mbedtls_calloc calloc
#define mbedtls_free free
#endif

#include "mbedtls/bignum.h"
#include "mbedtls/rsa.h"

static void reverse_array(uint8_t *src, size_t src_len)
{
    int i;

    for (i = 0; i < src_len / 2; i++)
    {
        uint8_t tmp;

        tmp = src[i];
        src[i] = src[src_len - 1 - i];
        src[src_len - 1 - i] = tmp;
    }
}
/*
 * Do an RSA public key operation
 */
static int mbedtls_mpi_exp_mod_shim(mbedtls_mpi *X,
                                    const mbedtls_mpi *A,
                                    const mbedtls_mpi *E,
                                    const mbedtls_mpi *N /*, mbedtls_mpi *_RR */)
{
    int ret = MBEDTLS_ERR_MPI_ALLOC_FAILED;
    size_t sizeA = mbedtls_mpi_size(A);
    size_t sizeN = mbedtls_mpi_size(N);
    uint8_t *ptrX = mbedtls_calloc(3, FREESCALE_PKHA_INT_MAX_BYTES);
    uint8_t *ptrA = ptrX + FREESCALE_PKHA_INT_MAX_BYTES;
    uint8_t *ptrN = ptrA + FREESCALE_PKHA_INT_MAX_BYTES;

    if (NULL == ptrX)
    {
        CLEAN_RETURN(MBEDTLS_ERR_MPI_ALLOC_FAILED);
    }

    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(A, ptrA, sizeA));
    reverse_array(ptrA, sizeA);

    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(N, ptrN, sizeN));
    reverse_array(ptrN, sizeN);

    CASPER_ModExp(CASPER, ptrA, ptrN, sizeN / 4U, E->p[0], ptrX);

    reverse_array(ptrX, sizeN);
    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(X, ptrX, sizeN));
cleanup:
    if (ptrX != NULL)
    {
        mbedtls_free(ptrX);
    }

    return ret;
}

int mbedtls_rsa_public(mbedtls_rsa_context *ctx, const unsigned char *input, unsigned char *output)
{
    int ret;
    size_t olen;
    mbedtls_mpi T;

    mbedtls_mpi_init(&T);

#if defined(MBEDTLS_THREADING_C)
    if ((ret = mbedtls_mutex_lock(&ctx->mutex)) != 0)
      {
        return (ret);
      }  
#endif

    MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&T, input, ctx->len));

    if (mbedtls_mpi_cmp_mpi(&T, &ctx->N) >= 0)
    {
        ret = MBEDTLS_ERR_MPI_BAD_INPUT_DATA;
        goto cleanup;
    }

    olen = ctx->len;

    MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod_shim(&T, &T, &ctx->E, &ctx->N /*, &ctx->RN */));

    MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&T, output, olen));

cleanup:
#if defined(MBEDTLS_THREADING_C)
    if (mbedtls_mutex_unlock(&ctx->mutex) != 0)
      {
        return (MBEDTLS_ERR_THREADING_MUTEX_ERROR);
       } 
#endif

    mbedtls_mpi_free(&T);

    if (ret != 0)
        return (MBEDTLS_ERR_RSA_PUBLIC_FAILED + ret);

    return (0);
}

#endif /* MBEDTLS_FREESCALE_CASPER_PKHA */
#endif /* MBEDTLS_RSA_PUBLIC_ALT */

/******************************************************************************/
/*************************** MD5 **********************************************/
/******************************************************************************/

#if defined(MBEDTLS_MD5_C)

#if defined(MBEDTLS_FREESCALE_MMCAU_MD5)

#include "mbedtls/md5.h"

int mbedtls_internal_md5_process(mbedtls_md5_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = MMCAU_MD5_HashN(data, 1, ctx->state);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_MD5_HW_ACCEL_FAILED;
    }
    return 0;
}

#endif /* MBEDTLS_FREESCALE_MMCAU_MD5 */

#endif /* MBEDTLS_MD5_C */

/******************************************************************************/
/*************************** SHA1 *********************************************/
/******************************************************************************/

#if defined(MBEDTLS_SHA1_C)

#if defined(MBEDTLS_FREESCALE_LTC_SHA1)
#include "mbedtls/sha1.h"

void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_clone(mbedtls_sha1_context *dst, const mbedtls_sha1_context *src)
{
    memcpy(dst, src, sizeof(mbedtls_sha1_context));
}

/*
 * SHA-1 context setup
 */
int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx)
{
    status_t ret = kStatus_Fail;
    ret = LTC_HASH_Init(LTC_INSTANCE, ctx, kLTC_Sha1, NULL, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = LTC_HASH_Update(ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 process buffer
 */
int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = LTC_HASH_Update(ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 final digest
 */
int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20])
{
    status_t ret = kStatus_Fail;
    ret = LTC_HASH_Finish(ctx, output, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_MMCAU_SHA1)

#include "mbedtls/sha1.h"

int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = MMCAU_SHA1_HashN(data, 1, ctx->state);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_LPC_SHA1)
#include "mbedtls/sha1.h"

void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_clone(mbedtls_sha1_context *dst, const mbedtls_sha1_context *src)
{
    memcpy(dst, src, sizeof(mbedtls_sha1_context));
}

/*
 * SHA-1 context setup
 */
int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx)
{
    status_t ret = kStatus_Fail;
    ret = SHA_Init(SHA_INSTANCE, ctx, kSHA_Sha1);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = SHA_Update(SHA_INSTANCE, ctx, data, 64, MANUAL_LOAD_SHA_INPUT);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 process buffer
 */
int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = SHA_Update(SHA_INSTANCE, ctx, input, ilen, MANUAL_LOAD_SHA_INPUT);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 final digest
 */
int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20])
{
    size_t outputSize = 20u;
    status_t ret = kStatus_Fail;
    ret = SHA_Finish(SHA_INSTANCE, ctx, output, &outputSize);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}
#elif defined(MBEDTLS_FREESCALE_CAAM_SHA1)
#include "mbedtls/sha1.h"

void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_clone(mbedtls_sha1_context *dst, const mbedtls_sha1_context *src)
{
    memcpy(dst, src, sizeof(mbedtls_sha1_context));
}

/*
 * SHA-1 context setup
 */
int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx)
{
    status_t ret = kStatus_Fail;
    ret = CAAM_HASH_Init(CAAM_INSTANCE, &s_caamHandle, ctx, kCAAM_Sha1, NULL, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = CAAM_HASH_Update(ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 process buffer
 */
int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = CAAM_HASH_Update(ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 final digest
 */
int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20])
{
    status_t ret = kStatus_Fail;
    ret = CAAM_HASH_Finish(ctx, output, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_CAU3_SHA1)
#include "mbedtls/sha1.h"

void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_clone(mbedtls_sha1_context *dst, const mbedtls_sha1_context *src)
{
    memcpy(dst, src, sizeof(mbedtls_sha1_context));
}

/*
 * SHA-1 context setup
 */
int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx)
{
    status_t ret = kStatus_Fail;
    ret = CAU3_HASH_Init(CAU3, ctx, kCAU3_Sha1);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = CAU3_HASH_Update(CAU3, ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 process buffer
 */
int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = CAU3_HASH_Update(CAU3, ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 final digest
 */
int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20])
{
    status_t ret = kStatus_Fail;
    ret = CAU3_HASH_Finish(CAU3, ctx, output, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_DCP_SHA1)
#include "mbedtls/sha1.h"

void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
{
    (void)memset(ctx, 0, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_clone(mbedtls_sha1_context *dst, const mbedtls_sha1_context *src)
{
    (void)memcpy(dst, src, sizeof(mbedtls_sha1_context));
}

/*
 * SHA-1 context setup
 */
int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx)
{
    status_t ret = kStatus_Fail;
    ret = DCP_HASH_Init(DCP, &s_dcpHandle, ctx, kDCP_Sha1);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
    DCACHE_CleanByRange((uint32_t)data, 64u);
#endif /* __DCACHE_PRESENT & DCP_USE_DCACHE */ 
    ret = DCP_HASH_Update(DCP, ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 process buffer
 */
int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
    DCACHE_CleanByRange((uint32_t)input, ilen);
#endif /* __DCACHE_PRESENT & DCP_USE_DCACHE */ 
    ret = DCP_HASH_Update(DCP, ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 final digest
 */
int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20])
{
    status_t ret = kStatus_Fail;
    ret = DCP_HASH_Finish(DCP, ctx, output, NULL);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_HASHCRYPT_SHA1)
#include "mbedtls/sha1.h"

void mbedtls_sha1_init(mbedtls_sha1_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_free(mbedtls_sha1_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha1_context));
}

void mbedtls_sha1_clone(mbedtls_sha1_context *dst, const mbedtls_sha1_context *src)
{
    memcpy(dst, src, sizeof(mbedtls_sha1_context));
}

/*
 * SHA-1 context setup
 */
int mbedtls_sha1_starts_ret(mbedtls_sha1_context *ctx)
{
    status_t ret = kStatus_Fail;
    ret = HASHCRYPT_SHA_Init(HASHCRYPT, ctx, kHASHCRYPT_Sha1);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = HASHCRYPT_SHA_Update(HASHCRYPT, ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 process buffer
 */
int mbedtls_sha1_update_ret(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = HASHCRYPT_SHA_Update(HASHCRYPT, ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-1 final digest
 */
int mbedtls_sha1_finish_ret(mbedtls_sha1_context *ctx, unsigned char output[20])
{
    status_t ret = kStatus_Fail;
    size_t outputSize = 20;
    ret = HASHCRYPT_SHA_Finish(HASHCRYPT, ctx, output, &outputSize);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA1_HW_ACCEL_FAILED;
    }
    return 0;
}
#endif /* MBEDTLS_FREESCALE_LPC_SHA1 */
#if !defined(MBEDTLS_DEPRECATED_REMOVED) && defined(MBEDTLS_SHA1_ALT)
#include "mbedtls/sha1.h"

void mbedtls_sha1_starts(mbedtls_sha1_context *ctx)
{
    (void)mbedtls_sha1_starts_ret(ctx);
}

void mbedtls_sha1_update(mbedtls_sha1_context *ctx, const unsigned char *input, size_t ilen)
{
    (void)mbedtls_sha1_update_ret(ctx, input, ilen);
}

void mbedtls_sha1_finish(mbedtls_sha1_context *ctx, unsigned char output[20])
{
    (void)mbedtls_sha1_finish_ret(ctx, output);
}

void mbedtls_sha1_process(mbedtls_sha1_context *ctx, const unsigned char data[64])
{
    (void)mbedtls_internal_sha1_process(ctx, data);
}
#endif /* MBEDTLS_DEPRECATED_REMOVED */
#endif /* MBEDTLS_SHA1_C */

/******************************************************************************/
/*************************** SHA256********************************************/
/******************************************************************************/

#if defined(MBEDTLS_SHA256_C)

#if defined(MBEDTLS_FREESCALE_LTC_SHA256)
#include "mbedtls/sha256.h"

void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_clone(mbedtls_sha256_context *dst, const mbedtls_sha256_context *src)
{
    memcpy(dst, src, sizeof(*dst));
}

/*
 * SHA-256 context setup
 */
int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224)
{
    status_t ret = kStatus_Fail;
    if (is224)
    {
        ret = LTC_HASH_Init(LTC_INSTANCE, ctx, kLTC_Sha224, NULL, 0);
    }
    else
    {
        ret = LTC_HASH_Init(LTC_INSTANCE, ctx, kLTC_Sha256, NULL, 0);
    }

    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = LTC_HASH_Update(ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 process buffer
 */
int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = LTC_HASH_Update(ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 final digest
 */
int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32])
{
    status_t ret = kStatus_Fail;
    ret = LTC_HASH_Finish(ctx, output, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_MMCAU_SHA256)

#include "mbedtls/sha256.h"

int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = MMCAU_SHA256_HashN(data, 1, ctx->state);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_CAU3_SHA256)

#include "mbedtls/sha256.h"

void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_clone(mbedtls_sha256_context *dst, const mbedtls_sha256_context *src)
{
    memcpy(dst, src, sizeof(*dst));
}

/*
 * SHA-256 context setup
 */
int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224)
{
    status_t ret = kStatus_Fail;
    if (!is224) /* SHA-224 not supported at the moment */
    {
        ret = CAU3_HASH_Init(CAU3, ctx, kCAU3_Sha256);
    }
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = CAU3_HASH_Update(CAU3, ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 process buffer
 */
int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = CAU3_HASH_Update(CAU3, ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 final digest
 */
int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32])
{
    status_t ret = kStatus_Fail;
    ret = CAU3_HASH_Finish(CAU3, ctx, output, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_LPC_SHA256)
#include "mbedtls/sha256.h"

void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_clone(mbedtls_sha256_context *dst, const mbedtls_sha256_context *src)
{
    memcpy(dst, src, sizeof(*dst));
}

/*
 * SHA-256 context setup
 */
int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224)
{
    status_t ret = kStatus_Fail;
    if (!is224) /* SHA-224 not supported */
    {
        ret = SHA_Init(SHA_INSTANCE, ctx, kSHA_Sha256);
    }
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = SHA_Update(SHA_INSTANCE, ctx, data, 64, MANUAL_LOAD_SHA_INPUT);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 process buffer
 */
int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = SHA_Update(SHA_INSTANCE, ctx, input, ilen, MANUAL_LOAD_SHA_INPUT);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 final digest
 */
int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32])
{
    size_t outputSize = 32u;
    status_t ret = kStatus_Fail;
    ret = SHA_Finish(SHA_INSTANCE, ctx, output, &outputSize);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_CAAM_SHA256)
#include "mbedtls/sha256.h"

void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_clone(mbedtls_sha256_context *dst, const mbedtls_sha256_context *src)
{
    memcpy(dst, src, sizeof(*dst));
}

/*
 * SHA-256 context setup
 */
int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224)
{
    status_t ret = kStatus_Fail;
    if (is224)
    {
        ret = CAAM_HASH_Init(CAAM_INSTANCE, &s_caamHandle, ctx, kCAAM_Sha224, NULL, 0);
    }
    else
    {
        ret = CAAM_HASH_Init(CAAM_INSTANCE, &s_caamHandle, ctx, kCAAM_Sha256, NULL, 0);
    }
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = CAAM_HASH_Update(ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 process buffer
 */
int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = CAAM_HASH_Update(ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 final digest
 */
int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32])
{
    status_t ret = kStatus_Fail;
    ret = CAAM_HASH_Finish(ctx, output, 0);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_DCP_SHA256)
#include "mbedtls/sha256.h"

void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
{
    (void)memset(ctx, 0, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_clone(mbedtls_sha256_context *dst, const mbedtls_sha256_context *src)
{
    (void)memcpy(dst, src, sizeof(*dst));
}

/*
 * SHA-256 context setup
 */
int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224)
{
    status_t ret = kStatus_Fail;
    if (0 == is224)
    {
        ret = DCP_HASH_Init(DCP, &s_dcpHandle, ctx, kDCP_Sha256);
    }
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
    DCACHE_CleanByRange((uint32_t)data, 64u);
#endif /* __DCACHE_PRESENT & DCP_USE_DCACHE */
    ret = DCP_HASH_Update(DCP, ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 process buffer
 */
int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
#if defined(__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U) && defined(DCP_USE_DCACHE) && (DCP_USE_DCACHE == 1U)
    DCACHE_CleanByRange((uint32_t)input, ilen);
#endif /* __DCACHE_PRESENT & DCP_USE_DCACHE */ 
    ret = DCP_HASH_Update(DCP, ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 final digest
 */
int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32])
{
    status_t ret = kStatus_Fail;
    ret = DCP_HASH_Finish(DCP, ctx, output, NULL);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

#elif defined(MBEDTLS_FREESCALE_HASHCRYPT_SHA256)
#include "mbedtls/sha256.h"

void mbedtls_sha256_init(mbedtls_sha256_context *ctx)
{
    memset(ctx, 0, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_free(mbedtls_sha256_context *ctx)
{
    if (ctx == NULL)
        return;

    mbedtls_zeroize(ctx, sizeof(mbedtls_sha256_context));
}

void mbedtls_sha256_clone(mbedtls_sha256_context *dst, const mbedtls_sha256_context *src)
{
    memcpy(dst, src, sizeof(*dst));
}

/*
 * SHA-256 context setup
 */
int mbedtls_sha256_starts_ret(mbedtls_sha256_context *ctx, int is224)
{
    status_t ret = kStatus_Fail;
    if (!is224) /* SHA-224 not supported */
    {
        ret = HASHCRYPT_SHA_Init(HASHCRYPT, ctx, kHASHCRYPT_Sha256);
    }
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

int mbedtls_internal_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    status_t ret = kStatus_Fail;
    ret = HASHCRYPT_SHA_Update(HASHCRYPT, ctx, data, 64);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 process buffer
 */
int mbedtls_sha256_update_ret(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
    status_t ret = kStatus_Fail;
    ret = HASHCRYPT_SHA_Update(HASHCRYPT, ctx, input, ilen);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}

/*
 * SHA-256 final digest
 */
int mbedtls_sha256_finish_ret(mbedtls_sha256_context *ctx, unsigned char output[32])
{
    status_t ret = kStatus_Fail;
    size_t outputSize = 32;
    ret = HASHCRYPT_SHA_Finish(HASHCRYPT, ctx, output, &outputSize);
    if (ret != kStatus_Success)
    {
        return MBEDTLS_ERR_SHA256_HW_ACCEL_FAILED;
    }
    return 0;
}
#endif /* MBEDTLS_FREESCALE_LTC_SHA256 */
#if !defined(MBEDTLS_DEPRECATED_REMOVED) && defined(MBEDTLS_SHA256_ALT)
#include "mbedtls/sha256.h"

void mbedtls_sha256_starts(mbedtls_sha256_context *ctx, int is224)
{
    (void)mbedtls_sha256_starts_ret(ctx, is224);
}

void mbedtls_sha256_update(mbedtls_sha256_context *ctx, const unsigned char *input, size_t ilen)
{
    (void)mbedtls_sha256_update_ret(ctx, input, ilen);
}

void mbedtls_sha256_finish(mbedtls_sha256_context *ctx, unsigned char output[32])
{
    (void)mbedtls_sha256_finish_ret(ctx, output);
}

void mbedtls_sha256_process(mbedtls_sha256_context *ctx, const unsigned char data[64])
{
    (void)mbedtls_internal_sha256_process(ctx, data);
}
#endif /* MBEDTLS_DEPRECATED_REMOVED */
#endif /* MBEDTLS_SHA256_C */

/* Entropy poll callback for a hardware source */
#if defined(MBEDTLS_ENTROPY_HARDWARE_ALT)

#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0)
#include "fsl_trng.h"
#elif defined(FSL_FEATURE_SOC_RNG_COUNT) && (FSL_FEATURE_SOC_RNG_COUNT > 0)
#include "fsl_rnga.h"
#elif defined(FSL_FEATURE_SOC_LPC_RNG_COUNT) && (FSL_FEATURE_SOC_LPC_RNG_COUNT > 0)
#include "fsl_rng.h"
#elif defined(FSL_FEATURE_SOC_LPC_RNG1_COUNT) && (FSL_FEATURE_SOC_LPC_RNG1_COUNT > 0)
#include "fsl_rng.h"
#endif

int mbedtls_hardware_poll(void *data, unsigned char *output, size_t len, size_t *olen)
{
    status_t result = kStatus_Success;

#if defined(FSL_FEATURE_SOC_TRNG_COUNT) && (FSL_FEATURE_SOC_TRNG_COUNT > 0)
#ifndef TRNG0
#define TRNG0 TRNG
#endif
    result = TRNG_GetRandomData(TRNG0, output, len);
#elif defined(FSL_FEATURE_SOC_RNG_COUNT) && (FSL_FEATURE_SOC_RNG_COUNT > 0)
    result = RNGA_GetRandomData(RNG, (void *)output, len);
#elif defined(FSL_FEATURE_SOC_CAAM_COUNT) && (FSL_FEATURE_SOC_CAAM_COUNT > 0) && defined(CRYPTO_USE_DRIVER_CAAM)
    result = CAAM_RNG_GetRandomData(CAAM_INSTANCE, &s_caamHandle, kCAAM_RngStateHandle0, output, len, kCAAM_RngDataAny,
                                    NULL);
#elif defined(FSL_FEATURE_SOC_LPC_RNG_COUNT) && (FSL_FEATURE_SOC_LPC_RNG_COUNT > 0)
    uint32_t rn;
    size_t length;
    int i;

    length = len;

    while (length > 0U)
    {
        rn = RNG_GetRandomData();

        if (length >= sizeof(uint32_t))
        {
            (void)memcpy(output, (uint8_t *)&rn, sizeof(uint32_t));
            length -= sizeof(uint32_t);
            output += sizeof(uint32_t);
        }
        else
        {
            (void)memcpy(output, (uint8_t *)&rn, length);
            output += length;
            len = 0U;
        }

        /* Discard next 32 random words for better entropy */
        for (i = 0; i < 32; i++)
        {
            (void)RNG_GetRandomData();
        }
    }

    result = kStatus_Success;
#elif defined(FSL_FEATURE_SOC_LPC_RNG1_COUNT) && (FSL_FEATURE_SOC_LPC_RNG1_COUNT > 0)
    status_t status = kStatus_Fail;

    while(status != kStatus_Success)
    {
        status = RNG_GetRandomData(RNG, output, len);

        if(status == kStatus_Fail)
        {
            RNG_Init(RNG);
        }
    }

    result = status;
#endif
    if (result == kStatus_Success)
    {
        *olen = len;
        return 0;
    }
    else
    {
        return result;
    }
}

#endif

/******************************************************************************/
/*************************** FreeRTOS ********************************************/
/******************************************************************************/
#if defined(USE_RTOS) && defined(FSL_RTOS_FREE_RTOS) && defined(MBEDTLS_FREESCALE_FREERTOS_CALLOC_ALT)
#include <stdlib.h>
#include "FreeRTOS.h"
#include "task.h"

/*---------HEAP_3 calloc --------------------------------------------------*/

void *pvPortCalloc(size_t num, size_t size)
{
    void *pvReturn;

    vTaskSuspendAll();
    {
        pvReturn = calloc(num, size);
        traceMALLOC(pvReturn, xWantedSize);
    }
    (void)xTaskResumeAll();

#if (configUSE_MALLOC_FAILED_HOOK == 1)
    {
        if (pvReturn == NULL)
        {
            extern void vApplicationMallocFailedHook(void);
            vApplicationMallocFailedHook();
        }
    }
#endif

    return pvReturn;
}
#endif /* USE_RTOS && defined(FSL_RTOS_FREE_RTOS) && defined(MBEDTLS_FREESCALE_FREERTOS_CALLOC_ALT) */
