Marco Zecchini / Mbed OS Example_RTOS
Revision:
0:9fca2b23d0ba
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-os/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_ecp.c	Sat Feb 23 12:13:36 2019 +0000
@@ -0,0 +1,1725 @@
+/*
+ *  Elliptic curves over GF(p): CRYPTO hw acceleration functions
+ *
+ *  Copyright (C) 2016, Silicon Labs, http://www.silabs.com
+ *  SPDX-License-Identifier: Apache-2.0
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License"); you may
+ *  not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+/*
+ * This file includes alternative plugin implementations of various
+ * functions in ecp.c using the CRYPTO hardware accelerator incorporated
+ * in MCU devices from Silicon Laboratories.
+ */
+/*
+ * References:
+ *
+ * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
+ * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone
+ * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf
+ * RFC 4492 for the related TLS structures and constants
+ *
+ * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf
+ *
+ * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis
+ *     for elliptic curve cryptosystems. In : Cryptographic Hardware and
+ *     Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302.
+ *     <http://link.springer.com/chapter/10.1007/3-540-48059-5_25>
+ *
+ * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to
+ *     render ECC resistant against Side Channel Attacks. IACR Cryptology
+ *     ePrint Archive, 2004, vol. 2004, p. 342.
+ *     <http://eprint.iacr.org/2004/342.pdf>
+ */
+
+#if !defined(MBEDTLS_CONFIG_FILE)
+#include "mbedtls/config.h"
+#else
+#include MBEDTLS_CONFIG_FILE
+#endif
+
+#include "em_device.h"
+
+#if defined( CRYPTO_PRESENT )
+
+#if defined( MBEDTLS_ECP_C )
+#if defined( MBEDTLS_ECP_INTERNAL_ALT )
+
+#include "mbedtls/ecp.h"
+#include "mbedtls/ecp_internal.h"
+#include "mbedtls/platform.h"
+#include "em_crypto.h"
+#include "em_core.h"
+#include "crypto_management.h"
+
+#include <stdbool.h>
+#include <string.h>
+
+/** ECC big integer type. */
+#define ECC_BIGINT_SIZE_IN_BITS        (256)
+#define ECC_BIGINT_SIZE_IN_BYTES       (ECC_BIGINT_SIZE_IN_BITS/8)
+#define ECC_BIGINT_SIZE_IN_32BIT_WORDS (ECC_BIGINT_SIZE_IN_BYTES/sizeof(uint32_t))
+#define EC_BIGINT_COPY(X, Y) memcpy((X), (Y), sizeof(ecc_bigint_t));
+typedef uint32_t ecc_bigint_t[ECC_BIGINT_SIZE_IN_32BIT_WORDS];
+
+#define SLCL_ECP_CHK(f) do { if( ( ret = (f) ) != 0 ) goto cleanup; } while( 0 )
+
+#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) || defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
+#define MPI_TO_BIGINT(bigint, mpi) mpitobigint((bigint), (mpi));
+
+/***************************************************************************//**
+ * @brief
+ *   Convert an mpi number representation to a 32bit word array used by crypto.
+ ******************************************************************************/
+__STATIC_INLINE void mpitobigint( ecc_bigint_t bigint, const mbedtls_mpi* mpi )
+{
+    uint32_t* bi = bigint;
+
+    if ( mpi->n < ECC_BIGINT_SIZE_IN_32BIT_WORDS )
+    {
+      memcpy(bigint, mpi->p, mpi->n * sizeof(uint32_t));
+      memset(&bi[mpi->n],
+             0,
+             ECC_BIGINT_SIZE_IN_BYTES - ( mpi->n * sizeof(uint32_t) ) );
+    }
+    else
+    {
+      /* mpi has more room than bigint, so only store up to sizeof(bigint) */
+      memcpy(bigint, mpi->p, ECC_BIGINT_SIZE_IN_BYTES);
+    }
+}
+
+/***************************************************************************//**
+ * @brief
+ *   Returns true if the value of the DDATA0 register is equal to zero.
+ ******************************************************************************/
+__STATIC_INLINE bool crypto_ddata0_is_zero(CRYPTO_TypeDef* crypto,
+                                           uint32_t*       status_reg)
+{
+  CORE_DECLARE_IRQ_STATE;
+  CORE_ENTER_CRITICAL();
+  CRYPTO_EXECUTE_3(crypto,
+                   CRYPTO_CMD_INSTR_CCLR,
+                   CRYPTO_CMD_INSTR_DEC,  /* Decrement by one which will set
+                                             carry bit if DDATA0 is zero. */
+                   CRYPTO_CMD_INSTR_INC   /* Increment in order to restore
+                                             original value. */
+                   );
+
+  *status_reg = crypto->DSTATUS;
+  CORE_EXIT_CRITICAL();
+
+  return (*status_reg & CRYPTO_DSTATUS_CARRY) == CRYPTO_DSTATUS_CARRY;
+}
+
+/***************************************************************************//**
+ * @brief
+ *   Modular division using CRYPTO hardware acceleration.
+ *
+ * @details
+ *   This function computes R = X/Y mod(N) using CRYPTO hardware acceleration.
+ *   The implementation is not a direct replacement plugin, i.e. alternative
+ *   implementation, of an existing mbedtls function. This function is used
+ *   internally in other CRYPTO plugin functions indirectly replacing
+ *   mbedtls_mpi_inv_mod.
+ *
+ *  @param[in]  X        Dividend of modular division operation
+ *  @param[in]  Y        Divisor of  modular division operation
+ *  @param[in]  N        Modulus
+ *  @param[out] R        The destination of the result
+ *
+ * @return N/A
+ ******************************************************************************/
+static void crypto_mpi_div_mod(CRYPTO_TypeDef *crypto,
+                               ecc_bigint_t   X,
+                               ecc_bigint_t   Y,
+                               ecc_bigint_t   N,
+                               ecc_bigint_t   R)
+{
+    uint32_t            D[9];
+    uint32_t            status_reg;
+    uint8_t             rdata;
+    uint8_t             lsb_C;
+    uint8_t             lsb_D;
+    uint8_t             lsb_U;
+    int                 t;
+    int                 k;
+    CORE_DECLARE_IRQ_STATE;
+
+    /************** Initialize and organize data in crypto module **************/
+
+    /*
+    ** Register usage:
+    **
+    ** DDATA0 - holds temporary results and loads 260 bit variables in/out
+    ** DDATA1 - variable referred to as 'C' in the following algorithm
+    ** DDATA2 - variable referred to as 'U' in the following algorithm
+    ** DDATA3 - variable referred to as 'D' in the following algorithm
+    ** DDATA4 - variable referred to as 'W' in the following algorithm
+    */
+
+    EC_BIGINT_COPY(D, N);             /* D will hold the modulus (n) initially */
+    D[8]=0;                           /* Set MSWord of D to 0. */
+
+    CORE_ENTER_CRITICAL();
+    CRYPTO_DDataWrite(&crypto->DDATA1, Y);  /* Set C to Y (divisor) initially */
+    CRYPTO_DDataWrite(&crypto->DDATA2, X);  /* Set U to X (dividend)initially */
+    CRYPTO_DDataWrite(&crypto->DDATA3, N);  /* Set D to modulus p initially   */
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_3(crypto,
+                     CRYPTO_CMD_INSTR_CLR,            /* DDATA0 = 0 */
+                     CRYPTO_CMD_INSTR_DDATA0TODDATA4, /* Set W to zero initially*/
+                     CRYPTO_CMD_INSTR_DDATA1TODDATA0);/* DDATA0 = C initially */
+
+    t     = 0;
+    k     = 1;
+
+    /******************* Run main loop while 'C' is non-zero ********************/
+
+    /* while (C != 1024'd0)  */
+    while ( !crypto_ddata0_is_zero(crypto, &status_reg) )
+    {
+
+        lsb_C = (status_reg & _CRYPTO_DSTATUS_DDATA0LSBS_MASK) >> _CRYPTO_DSTATUS_DDATA0LSBS_SHIFT;
+        if ((lsb_C & 0x1) == 0)
+        {
+            CRYPTO_EXECUTE_3(crypto,
+                             CRYPTO_CMD_INSTR_SELDDATA1DDATA1,
+                             CRYPTO_CMD_INSTR_SHRA,
+                             CRYPTO_CMD_INSTR_DDATA0TODDATA1
+                             );
+            t = t-1;
+        }
+        else
+        {
+            if (t<0)
+            {
+                CRYPTO_EXECUTE_6(crypto,
+                                 CRYPTO_CMD_INSTR_DDATA2TODDATA0,
+                                 CRYPTO_CMD_INSTR_DDATA4TODDATA2,
+                                 CRYPTO_CMD_INSTR_DDATA0TODDATA4,
+                                 CRYPTO_CMD_INSTR_DDATA1TODDATA0,
+                                 CRYPTO_CMD_INSTR_DDATA3TODDATA1,
+                                 CRYPTO_CMD_INSTR_DDATA0TODDATA3);
+                CORE_ENTER_CRITICAL();
+                CRYPTO_DDATA0_260_BITS_READ(crypto, D);
+                CORE_EXIT_CRITICAL();
+                t = -t;
+            }
+
+            k = 1;
+
+            CRYPTO_EXECUTE_2(crypto,
+                             CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                             CRYPTO_CMD_INSTR_ADD);
+
+            rdata = CRYPTO_DData0_4LSBitsRead(crypto);
+
+            if((rdata & 0x3) != 0x0)
+              k = -1;
+            else
+              t = t-1;
+
+            /*  R1 = C >> 1  */
+            crypto->CMD = CRYPTO_CMD_INSTR_DDATA1TODDATA0; /* to get the lsb of C */
+
+            lsb_C = CRYPTO_DData0_4LSBitsRead(crypto);
+            CRYPTO_EXECUTE_4(crypto,
+                             CRYPTO_CMD_INSTR_SELDDATA1DDATA1,
+                             CRYPTO_CMD_INSTR_SHRA,
+                             CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                             CRYPTO_CMD_INSTR_DDATA3TODDATA0); /* to get the lsb of D(R3) */
+
+            /*  R3 = D >> 1  */
+            lsb_D = CRYPTO_DData0_4LSBitsRead(crypto);
+
+            CRYPTO_EXECUTE_2(crypto,
+                             CRYPTO_CMD_INSTR_SELDDATA3DDATA3,
+                             CRYPTO_CMD_INSTR_SHRA);
+
+            if(k == 1)
+            {
+                if (((lsb_C & 0x1)==0x1) && ((lsb_D & 0x1)==0x1))
+                {
+                    CRYPTO_EXECUTE_7(crypto,
+                                     /*  C = R1+R3+1  */
+                                     CRYPTO_CMD_INSTR_SELDDATA0DDATA1,
+                                     CRYPTO_CMD_INSTR_CSET,
+                                     CRYPTO_CMD_INSTR_ADDC,
+                                     CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                                     /*  U = mod(R2+R4,n)  */
+                                     CRYPTO_CMD_INSTR_SELDDATA2DDATA4,
+                                     CRYPTO_CMD_INSTR_MADD,
+                                     CRYPTO_CMD_INSTR_DDATA0TODDATA2
+                                     );
+                }
+                else
+                {
+                    CRYPTO_EXECUTE_6(crypto,
+                                     /*  C = R1+R3  */
+                                     CRYPTO_CMD_INSTR_SELDDATA0DDATA1,
+                                     CRYPTO_CMD_INSTR_ADD,
+                                     CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                                     /*  U = mod(R2+R4,n)  */
+                                     CRYPTO_CMD_INSTR_SELDDATA2DDATA4,
+                                     CRYPTO_CMD_INSTR_MADD,
+                                     CRYPTO_CMD_INSTR_DDATA0TODDATA2
+                                     );
+                }
+            }
+            else
+            {
+                if (k == -1)
+                {
+                    if (((lsb_C & 0x1)==0x0) && ((lsb_D & 0x1)==0x1))
+                    {
+                        CRYPTO_EXECUTE_8(crypto,
+                                         /*  C = R1-R3-1  */
+                                         CRYPTO_CMD_INSTR_DDATA0TODDATA3,
+                                         CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                                         CRYPTO_CMD_INSTR_CSET,
+                                         CRYPTO_CMD_INSTR_SUBC,
+                                         CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                                         /*  U = mod(R2-R4,p)  */
+                                         CRYPTO_CMD_INSTR_SELDDATA2DDATA4,
+                                         CRYPTO_CMD_INSTR_MSUB,
+                                         CRYPTO_CMD_INSTR_DDATA0TODDATA2
+                                         );
+                    }
+                    else
+                    {
+                        CRYPTO_EXECUTE_7(crypto,
+                                         /*  C = R1+R3  */
+                                         CRYPTO_CMD_INSTR_DDATA0TODDATA3,
+                                         CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                                         CRYPTO_CMD_INSTR_SUB,
+                                         CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                                         /*  U = mod(R2-R4,p)  */
+                                         CRYPTO_CMD_INSTR_SELDDATA2DDATA4,
+                                         CRYPTO_CMD_INSTR_MSUB,
+                                         CRYPTO_CMD_INSTR_DDATA0TODDATA2
+                                         );
+                    }
+
+                    CRYPTO_DDATA0_260_BITS_WRITE(crypto, D);
+                    crypto->CMD = CRYPTO_CMD_INSTR_DDATA0TODDATA3;
+
+                } /* if (k == -1) */
+            }
+        } /* else: !if((C[31:0] & 0x1) == 0x0) */
+
+        crypto->CMD = CRYPTO_CMD_INSTR_DDATA2TODDATA0;
+
+        lsb_U = CRYPTO_DData0_4LSBitsRead(crypto);
+
+        /* if ((U[31:0] & 0x1) == 0x1) */
+        if((lsb_U & 0x1) == 0x1)
+        {
+            CRYPTO_EXECUTE_3( crypto,
+                              CRYPTO_CMD_INSTR_SELDDATA2DDATA2,
+                              CRYPTO_CMD_INSTR_SHRA,
+                              CRYPTO_CMD_INSTR_DDATA0TODDATA2);
+
+            CORE_ENTER_CRITICAL();
+            CRYPTO_DDataWrite(&crypto->DDATA0, N);
+            CORE_EXIT_CRITICAL();
+
+            CRYPTO_EXECUTE_6( crypto,
+                              CRYPTO_CMD_INSTR_SELDDATA0DDATA0,
+                              CRYPTO_CMD_INSTR_SHR,
+                              CRYPTO_CMD_INSTR_SELDDATA0DDATA2,
+                              CRYPTO_CMD_INSTR_CSET,
+                              CRYPTO_CMD_INSTR_ADDC,
+                              CRYPTO_CMD_INSTR_DDATA0TODDATA2);
+        }
+        else
+        {
+            CRYPTO_EXECUTE_3(crypto,
+                             CRYPTO_CMD_INSTR_SELDDATA2DDATA2,
+                             CRYPTO_CMD_INSTR_SHRA,
+                             CRYPTO_CMD_INSTR_DDATA0TODDATA2);
+        }
+
+        /* DDATA0 = C */
+        crypto->CMD = CRYPTO_CMD_INSTR_DDATA1TODDATA0;
+
+    } /* End of main loop:  while (C != 0)  */
+
+    /* if (D == 1): */
+    /* Decrement D by 1 and test if zero. */
+    CRYPTO_EXECUTE_2(crypto,
+                     CRYPTO_CMD_INSTR_DDATA3TODDATA0,
+                     CRYPTO_CMD_INSTR_DEC);
+
+    if (crypto_ddata0_is_zero(crypto, &status_reg))
+    {
+        CORE_ENTER_CRITICAL();
+        CRYPTO_DDataRead(&crypto->DDATA4, R);
+        CORE_EXIT_CRITICAL();
+    }
+    else
+    {
+        CORE_ENTER_CRITICAL();
+        CRYPTO_DDataWrite(&crypto->DDATA0, N);
+        CORE_EXIT_CRITICAL();
+
+        CRYPTO_EXECUTE_2(crypto,
+                         CRYPTO_CMD_INSTR_SELDDATA0DDATA4,
+                         CRYPTO_CMD_INSTR_SUB
+                         );
+
+        CORE_ENTER_CRITICAL();
+        CRYPTO_DDataRead(&crypto->DDATA0, R);
+        CORE_EXIT_CRITICAL();
+    }
+    return;
+} /* crypto_mpi_div_mod  */
+#endif /* MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT || MBEDTLS_ECP_NORMALIZE_JAC_ALT */
+
+/***************************************************************************//**
+ * @brief
+ *   Enable CRYPTO by setting up control registers for given ecc curve.
+ ******************************************************************************/
+static int crypto_device_init( CRYPTO_TypeDef *device, const mbedtls_ecp_group *grp)
+{
+    int             ret = 0;
+
+    /* Setup CRYPTO registers for ECC operation */
+    device->CTRL     = 0;
+    device->SEQCTRL  = CRYPTO_SEQCTRL_BLOCKSIZE_32BYTES | 32;
+    device->SEQCTRLB = 0;
+
+    switch( grp->id )
+    {
+#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
+        case MBEDTLS_ECP_DP_SECP192R1:
+            CRYPTO_ModulusSet( device, cryptoModulusEccP192 );
+            CRYPTO_MulOperandWidthSet( device, cryptoMulOperandModulusBits );
+            CRYPTO_ResultWidthSet( device, cryptoResult256Bits );
+        break;
+#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
+        case MBEDTLS_ECP_DP_SECP224R1:
+            CRYPTO_ModulusSet( device, cryptoModulusEccP224 );
+            CRYPTO_MulOperandWidthSet( device, cryptoMulOperandModulusBits );
+            CRYPTO_ResultWidthSet( device, cryptoResult256Bits );
+        break;
+#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
+        case MBEDTLS_ECP_DP_SECP256R1:
+            CRYPTO_ModulusSet( device, cryptoModulusEccP256 );
+            CRYPTO_MulOperandWidthSet( device, cryptoMulOperandModulusBits );
+            CRYPTO_ResultWidthSet( device, cryptoResult260Bits );
+        break;
+#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */
+
+        default:
+            ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
+        break;
+    }
+
+    return( ret );
+}
+
+/***************************************************************************//**
+ * @brief
+ *   Write 256 bits of data to a DDATAX register in the CRYPTO module.
+ *
+ * @details
+ *   Write 256 bits of data into a DDATAX (Double Data) register in the crypto
+ *   module.
+ *
+ *  @param[in]  ddataReg   Data register identifier
+ *  @param[in]  val        Value of the data to write to the DDATA register.
+ ******************************************************************************/
+__STATIC_INLINE void ecp_crypto_ddata_write(CRYPTO_DDataReg_TypeDef  ddataReg,
+                                            const mbedtls_mpi*       mpi)
+{
+  uint32_t volatile* regPtr = (volatile uint32_t *) ddataReg;
+  uint32_t* pVal = mpi->p;
+  register uint32_t v0;
+  register uint32_t v1;
+  register uint32_t v2;
+  register uint32_t v3;
+  int      i;
+
+  if (mpi->n <4)
+  {
+    /* Non optimal write of data. */
+    for (i=0; i<(int)mpi->n; i++)
+      *regPtr = *pVal++;
+    for (; i<8; i++)
+      *regPtr = 0;
+  }
+  else
+  {
+    if (mpi->n < 8)
+    {
+      /* Optimal write of first 4 words. */
+      v0 = *pVal++;
+      v1 = *pVal++;
+      v2 = *pVal++;
+      v3 = *pVal++;
+      *regPtr = v0;
+      *regPtr = v1;
+      *regPtr = v2;
+      *regPtr = v3;
+
+      /* Non optimal write of remaining words */
+      for (i=4; i<(int)mpi->n; i++)
+        *regPtr = *pVal++;
+      for (; i<8; i++)
+        *regPtr = 0;
+    }
+    else
+    {
+      /* Optimal write of all data. */
+      v0 = *pVal++;
+      v1 = *pVal++;
+      v2 = *pVal++;
+      v3 = *pVal++;
+      *regPtr = v0;
+      *regPtr = v1;
+      *regPtr = v2;
+      *regPtr = v3;
+
+      v0 = *pVal++;
+      v1 = *pVal++;
+      v2 = *pVal++;
+      v3 = *pVal++;
+      *regPtr = v0;
+      *regPtr = v1;
+      *regPtr = v2;
+      *regPtr = v3;
+    }
+  }
+}
+
+/***************************************************************************//**
+ * @brief
+ *   Read 256 bits of data from a DDATAX register in the CRYPTO module.
+ *
+ * @details
+ *   Read 256 bits of data from a DDATAX (Double Data) register in the crypto
+ *   module.
+ *
+ *  @param[in]  ddataReg   Data register identifier
+ *  @param[out] val        Location where to store the value in memory.
+ ******************************************************************************/
+
+__STATIC_INLINE int ecp_crypto_ddata_read(CRYPTO_DDataReg_TypeDef  ddataReg,
+                                          mbedtls_mpi*             mpi)
+{
+  CRYPTO_DData_TypeDef  ddata;
+  uint32_t              val32;
+  int                   i;
+  int                   used;
+  int                   ret = 0;
+  CORE_DECLARE_IRQ_STATE;
+
+  if (mpi->n == 8)
+  {
+    CORE_ENTER_CRITICAL();
+    CRYPTO_DDataRead(ddataReg, mpi->p);
+    CORE_EXIT_CRITICAL();
+  }
+  else
+  {
+    if (mpi->n > 8)
+    {
+      CORE_ENTER_CRITICAL();
+      CRYPTO_DDataRead(ddataReg, mpi->p);
+      CORE_EXIT_CRITICAL();
+      memset(&mpi->p[8], 0, sizeof(uint32_t)*(mpi->n-8));
+    }
+    else
+    {
+      uint32_t volatile* regPtr = (volatile uint32_t*) ddataReg;
+      used = 0;
+      for (i=0; i<8; i++)
+      {
+        ddata[i] = val32 = *regPtr;
+        if (val32)
+          used = i+1;
+      }
+      if (used > (int)mpi->n)
+      {
+        SLCL_ECP_CHK( mbedtls_mpi_grow(mpi, used) );
+        memcpy(mpi->p, ddata, used*sizeof(uint32_t));
+        mpi->s = 1;
+      }
+      else
+      {
+        memcpy(mpi->p, ddata, mpi->n*sizeof(uint32_t));
+      }
+    }
+  }
+ cleanup:
+  return( ret );
+}
+
+/**
+ * \brief           Indicate if the Elliptic Curve Point module extension can
+ *                  handle the group.
+ *
+ * \param grp       The pointer to the elliptic curve group that will be the
+ *                  basis of the cryptographic computations.
+ *
+ * \return          Non-zero if successful.
+ */
+unsigned char mbedtls_internal_ecp_grp_capable( const mbedtls_ecp_group *grp )
+{
+    switch( grp->id )
+    {
+#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
+        case MBEDTLS_ECP_DP_SECP192R1:
+            return( true );
+#endif /* MBEDTLS_ECP_DP_SECP192R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
+        case MBEDTLS_ECP_DP_SECP224R1:
+            return( true );
+#endif /* MBEDTLS_ECP_DP_SECP224R1_ENABLED */
+
+#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
+        case MBEDTLS_ECP_DP_SECP256R1:
+            return( true );
+#endif /* MBEDTLS_ECP_DP_SECP256R1_ENABLED */
+
+        default:
+            return( false );
+    }
+}
+
+/**
+ * \brief           Initialise the Elliptic Curve Point module extension.
+ *
+ *                  If mbedtls_internal_ecp_grp_capable returns true for a
+ *                  group, this function has to be able to initialise the
+ *                  module for it.
+ *
+ *                  This module can be a driver to a crypto hardware
+ *                  accelerator, for which this could be an initialise function.
+ *
+ * \param grp       The pointer to the group the module needs to be
+ *                  initialised for.
+ *
+ * \return          0 if successful.
+ */
+int mbedtls_internal_ecp_init( const mbedtls_ecp_group *grp )
+{
+    /* Crypto operations are atomic, so no need to setup any context here */
+    (void) grp;
+    return 0;
+}
+
+/**
+ * \brief           Frees and deallocates the Elliptic Curve Point module
+ *                  extension.
+ *
+ * \param grp       The pointer to the group the module was initialised for.
+ */
+void mbedtls_internal_ecp_free( const mbedtls_ecp_group *grp )
+{
+    /* Crypto operations are atomic, so no need to free any context here */
+    (void) grp;
+}
+
+#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
+/**
+ * \brief           Randomize jacobian coordinates:
+ *                  (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l.
+ *
+ * \param grp       Pointer to the group representing the curve.
+ *
+ * \param pt        The point on the curve to be randomised, given with Jacobian
+ *                  coordinates.
+ *
+ * \param f_rng     A function pointer to the random number generator.
+ *
+ * \param p_rng     A pointer to the random number generator state.
+ *
+ * \return          0 if successful.
+ */
+int mbedtls_internal_ecp_randomize_jac( const mbedtls_ecp_group *grp,
+                                        mbedtls_ecp_point *pt,
+                                        int (*f_rng)(void *, unsigned char *, size_t),
+                                        void *p_rng )
+{
+    int ret;
+    ecc_bigint_t l;
+    CORE_DECLARE_IRQ_STATE;
+    CRYPTO_TypeDef *crypto;
+
+    /* Strategy:
+     *  1) Generate l such that 1 < l < p
+     *  2) Z = l (R1) * Z (R4)
+     *  3) ll (R1) = l (R4) * l
+     *  4) X = ll (R1) * X (R2)
+     *  5) lll (R1) = ll (R1) * l (R4)
+     *  6) Y = lll (R1) * Y (R3)
+     */
+
+    /* Acquire entropy before grabbing crypto, since the entropy function might use crypto */
+    /* Generate l such that 1 < l < p */
+    ret = f_rng(p_rng, (unsigned char *)l, sizeof(l));
+    if ( ret != 0 ) {
+        return( ret );
+    }
+
+    crypto = crypto_management_acquire();
+    crypto_device_init(crypto, grp);
+
+    CORE_ENTER_CRITICAL();
+    CRYPTO_DDataWrite(&crypto->DDATA1, l);
+    ecp_crypto_ddata_write(&crypto->DDATA2, &pt->X);
+    ecp_crypto_ddata_write(&crypto->DDATA3, &pt->Y);
+    ecp_crypto_ddata_write(&crypto->DDATA4, &pt->Z);
+    CORE_EXIT_CRITICAL();
+
+    /* Z = l * Z */
+    CRYPTO_EXECUTE_2 (  crypto,
+                        CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                        CRYPTO_CMD_INSTR_MMUL );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &pt->Z) );
+
+    /* X = l^2 * X */
+    CRYPTO_EXECUTE_6 (  crypto,
+                        CRYPTO_CMD_INSTR_DDATA1TODDATA4,
+                        CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                        CRYPTO_CMD_INSTR_MMUL,
+                        CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                        CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                        CRYPTO_CMD_INSTR_MMUL );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &pt->X) );
+
+    /* Y = l^3 * Y */
+    CRYPTO_EXECUTE_5 (  crypto,
+                        CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                        CRYPTO_CMD_INSTR_MMUL,
+                        CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                        CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                        CRYPTO_CMD_INSTR_MMUL );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    MBEDTLS_MPI_CHK( ecp_crypto_ddata_read(&crypto->DDATA0, &pt->Y) );
+
+cleanup:
+    crypto_management_release( crypto );
+    return( ret );
+}
+#endif
+
+#if defined(MBEDTLS_ECP_ADD_MIXED_ALT)
+/**
+ * \brief           Addition: R = P + Q, mixed affine-Jacobian coordinates.
+ *
+ *                  The coordinates of Q must be normalized (= affine),
+ *                  but those of P don't need to. R is not normalized.
+ *
+ *                  This function is used only as a subrutine of
+ *                  ecp_mul_comb().
+ *
+ *                  Special cases: (1) P or Q is zero, (2) R is zero,
+ *                      (3) P == Q.
+ *                  None of these cases can happen as intermediate step in
+ *                  ecp_mul_comb():
+ *                      - at each step, P, Q and R are multiples of the base
+ *                      point, the factor being less than its order, so none of
+ *                      them is zero;
+ *                      - Q is an odd multiple of the base point, P an even
+ *                      multiple, due to the choice of precomputed points in the
+ *                      modified comb method.
+ *                  So branches for these cases do not leak secret information.
+ *
+ *                  We accept Q->Z being unset (saving memory in tables) as
+ *                  meaning 1.
+ *
+ *                  Cost in field operations if done by [5] 3.22:
+ *                      1A := 8M + 3S
+ *
+ * \param grp       Pointer to the group representing the curve.
+ *
+ * \param R         Pointer to a point structure to hold the result.
+ *
+ * \param P         Pointer to the first summand, given with Jacobian
+ *                  coordinates
+ *
+ * \param Q         Pointer to the second summand, given with affine
+ *                  coordinates.
+ *
+ * \return          0 if successful.
+ */
+int mbedtls_internal_ecp_add_mixed( const mbedtls_ecp_group *grp,
+                                    mbedtls_ecp_point *R,
+                                    const mbedtls_ecp_point *P,
+                                    const mbedtls_ecp_point *Q )
+{
+    int             ret;
+    CORE_DECLARE_IRQ_STATE;
+    CRYPTO_TypeDef *crypto = crypto_management_acquire();
+
+    crypto_device_init(crypto, grp);
+
+    /*
+      STEP 1:
+
+      Goals:
+      A = Qx*Pz^2
+      B = Qy*Pz^3
+
+      Write Operations:
+
+      R0 = Pz
+      R0 = Qx
+      R0 = Qy
+
+      Instructions to be executed:
+
+      1. R0 = DMA = Pz
+      2. R1 = R0 = Pz
+      3. R2 = R0 = Pz
+      4. Select R1, R2
+      5. R0 = R1 * R2 = Pz^2
+      6. R1 = R0 = Pz^2
+
+      7.  R0 = DMA = Qx
+      8.  R3 = R0 = Qx
+      9.  Select R1, R3
+      10. R0 = R1 * R3 = Qx * Pz^2
+      11. R3 = R0 = Qx * Pz^2
+
+      12. Select R1, R2
+      13. R0 = R1 * R2 = Pz^3
+      14. R1 = R0 = Pz^3
+
+      15. R0 = DMA = Qy
+      16. R4 = R0 = Qx
+      17. Select R1, R4
+      18. R0 = R1 * R4 = Qy * Pz^3
+      19. Select R0, R1  (for MSUB in step 2)
+
+      Output State:
+      R0   = B
+      R1   = FREE
+      R2   = FREE
+      R3   = A
+      R4   = Pz
+
+      STEP 1:
+    */
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA0, &P->Z);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_5(crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA4,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA0, &Q->X);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_4 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA3,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA3);
+    CRYPTO_InstructionSequenceWait(crypto);
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA0, &Q->Y);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    /*
+      STEP 2:
+
+      Goals:
+      C  = A - Px
+      D  = B - Py
+      R->Z = Pz * C
+
+      Write Operations:
+
+      R1 = Py
+      R0 = Px (via DMA)
+
+      Input State:
+      R0   = B
+      R1   = Py
+      R2   = FREE
+      R3   = A
+      R4   = Pz
+
+      Instructions to be executed:
+
+      0. Select R0, R1
+      1. R0 = R0 - R1 = B - Py = D
+      2. R2 = R0 = D
+      3. R1 = R3 = A
+      4. R0 = DMA = Px
+      5. R3 = R0 = Px
+      6. Select R1, R3
+      7. R0 = R1 - R3 = A - Px = C
+      8. R1 = R0 = C
+      9. Select R1, R4
+      10. R0 = R1 * R4 = Pz * C = R->Z
+
+      Read Operations:
+
+      R->Z = R0 = Pz * C
+
+      Output State:
+      R0   = FREE
+      R1   = C
+      R2   = D
+      R3   = Px
+      R4   = FREE
+
+      STEP 2:
+    */
+
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA1, &P->Y);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA1,
+                      CRYPTO_CMD_INSTR_MSUB,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2); /* R2 = D */
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA0, &P->X);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_7 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA3TODDATA1,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA3,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                      CRYPTO_CMD_INSTR_MSUB,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,  /* R1 = C */
+
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z);
+
+    if (ret != 0) goto cleanup;
+
+    /*
+      STEP 3:
+
+      Goals:
+      X1C2  = Px * C^2
+      C3    = C^3
+      D2    = D^2
+
+      Input State:
+      R0   = FREE
+      R1   = C
+      R2   = D
+      R3   = Px
+      R4   = FREE
+
+      Instructions to be executed:
+
+      1. R4 = R1 = C
+      2. Select R1, R4
+      3. R0 = R1 * R4 = C^2
+      4. R1 = R0 = C^2
+      5. R0 = R1 * R4 = C^3
+      6. R4 = R0 = C^3
+      7. Select R1, R3
+      8. R0 = R1 * R3 = Px * C^2
+      9. R3 = R0 = Px * C^2
+      10. R1 = R2 = D
+      11. Select R1, R1
+      12. R0 = R1 * R1 = D^2
+      13. Select R0, R4
+      14. R0 = R0 - R4 = D2 - C3
+
+      Output state:
+
+      R0 = D2 - C3
+      R1 = FREE
+      R2 = D
+      R3 = X1C2 = Px * C^2
+      R4 = C3   = C^3
+
+      STEP 3:
+    */
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA1TODDATA4,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA4);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA3);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CRYPTO_EXECUTE_5 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA2TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA4,
+                      CRYPTO_CMD_INSTR_MSUB
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    /*
+      STEP 3:
+
+      Goals:
+      R->X   = D2 - (C3 + 2 * X1C2) = D2 - C3 - X1C2- X1C2
+      Y1C3 = Py * C3
+      R->Y = D * (X1C2 - R->X) - Y1C3
+
+      Write Operations:
+      R1 = Py
+
+      Input State:
+      R0 = D2 - C3
+      R1 = FREE
+      R2 = D
+      R3 = X1C2
+      R4 = C3
+
+      Instructions to be executed:
+
+      1.  Select R0, R3
+      2.  R0 = R0 - R3 = D2 - C3 - X1C2
+      3.  R0 = R0 - R3 = D2 - C3 - X1C2 - X1C2 = R->X
+      4.  DMA = R0 = R->X
+      5.  R1 = R0 = R->X
+
+      6.  Select R3, R1
+      7.  R0 = R3 - R1 = X1C2 - R->X
+      8.  R1 = R0 = X1C2 - R->X
+      9.  Select R1, R2
+      10. R0 = R1 * R2 = D *(X1C2 - R->X)
+      11. R2 = R0
+
+      12. R0 = DMA = Py
+      13. R1 = R0 = Py
+      14. Select R1, R4
+      15. R0 = R1 * R4 = Py * C3 = Y1C3
+      16. R4 = R0 = Y1C3
+
+      17. Select R2, R4
+      18. R0 = R2 - R4
+
+      Read Operations:
+
+      R->X = R2 = D2 - (C3 + 2 * X1C2)
+      R->Y = R0 = D * (X1C2 - R->X) - Y1C3
+
+      STEP 4:
+    */
+
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA3,
+                      CRYPTO_CMD_INSTR_MSUB,
+                      CRYPTO_CMD_INSTR_MSUB);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->X);
+    if ( ret != 0 ) goto cleanup;
+
+    CRYPTO_EXECUTE_7 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+
+                      CRYPTO_CMD_INSTR_SELDDATA3DDATA1,
+                      CRYPTO_CMD_INSTR_MSUB,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA0, &P->Y);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_6 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA4,
+
+                      CRYPTO_CMD_INSTR_SELDDATA2DDATA4,
+                      CRYPTO_CMD_INSTR_MSUB
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Y);
+    if ( ret != 0 ) goto cleanup;
+
+ cleanup:
+    crypto_management_release( crypto );
+    return ( ret );
+}
+#endif
+
+/**
+ * \brief           Point doubling R = 2 P, Jacobian coordinates.
+ *
+ *                  Cost:   1D := 3M + 4S    (A ==  0)
+ *                          4M + 4S          (A == -3)
+ *                          3M + 6S + 1a     otherwise
+ *                  when the implementation is based on the "dbl-1998-cmo-2"
+ *                  doubling formulas in [8] and standard optimizations are
+ *                  applied when curve parameter A is one of { 0, -3 }.
+ *
+ * \param grp       Pointer to the group representing the curve.
+ *
+ * \param R         Pointer to a point structure to hold the result.
+ *
+ * \param P         Pointer to the point that has to be doubled, given with
+ *                  Jacobian coordinates.
+ *
+ * \return          0 if successful.
+ */
+#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
+int mbedtls_internal_ecp_double_jac( const mbedtls_ecp_group *grp,
+                                     mbedtls_ecp_point *R,
+                                     const mbedtls_ecp_point *P )
+{
+    int             ret;
+    CORE_DECLARE_IRQ_STATE;
+    CRYPTO_TypeDef *crypto = crypto_management_acquire();
+
+    crypto_device_init(crypto, grp);
+
+    ecc_bigint_t _2YY;
+    /*
+      STEP 1:
+
+      Goals:
+      ZZ   = Z^2
+      R->Z = 2 * Y * Z
+      YY   = Y^2
+      4YY  = 4 * Y^2
+
+      Write Operations:
+
+      R2 = Y
+      R3 = Z
+
+      Instructions to be executed:
+
+      1.  R0 = DMA = Z
+      2.  R1 = R0 = Z
+      3.  R2 = R0 = Z
+      4.  Select R1, R2
+      5.  R0 = R1 * R2 = Z^2 = ZZ
+      6.  R3 = R0 = ZZ
+
+      7.  R0 = DMA = Y
+      8.  R2 = R0 = Y
+      9.  R0 = R1 * R2 = Y * Z
+      10. Select R0, R0
+      11. R0 = R0 + R0 = 2 * Y * Z = R->Z
+
+      12. DMA = R0 = R->Z
+
+      13. R1 = R2 = Y
+      14. Select R1, R2
+      15. R0 = R1 * R2 = Y^2 = YY
+      16.  Select R0, R0
+      17.  R0 = R0 + R0 = 2YY
+
+      Read Operations:
+
+      R->Z = R0 = 2 * Y * Z
+      2YY  = R0
+
+      Output State:
+      R0 = 2YY
+      R1 = FREE
+      R2 = FREE
+      R3 = ZZ
+      R4 = FREE
+
+      STEP 1:
+    */
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA0, &P->Z);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_5 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA3);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA0, &P->Y);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_4 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA0,
+                      CRYPTO_CMD_INSTR_MADD);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Z);
+    if ( ret != 0 ) goto cleanup;
+
+    CRYPTO_EXECUTE_5 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA2TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA0,
+                      CRYPTO_CMD_INSTR_MADD
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    CORE_ENTER_CRITICAL();
+    ecp_crypto_ddata_write(&crypto->DDATA4, &P->X);
+    CRYPTO_DDataRead(&crypto->DDATA0, _2YY);
+    CORE_EXIT_CRITICAL();
+
+    /*
+      STEP 2:
+
+      Goals:
+      A   = 4YY * X
+      C   = 3(X - ZZ)(X + ZZ)
+
+      Write Operations:
+
+      R4 = X
+
+      Input State:
+      R0 = 2YY
+      R1 = FREE
+      R2 = FREE
+      R3 = ZZ
+      R4 = X
+
+      Instructions to be executed:
+
+      1.  R0 = R0 + R0 = 4YY
+      2.  R1 = R0 = 4YY
+      3.  Select R1, R4
+      4.  R0 = R1 * R4 = 4YY * X = A
+      5.  R2 = R0 = A
+      6.  Select R4, R3
+      7.  R0 = R4 + R3 = X + ZZ
+      8.  R1 = R0 = X + ZZ
+      9.  R0 = R4 - R3 = X - ZZ
+      0.  R2 = R0 = X - ZZ
+      11. Select R1, R2
+      12. R0 = R1 * R2 = (X + ZZ)(X - ZZ)
+      13. R1 = R0 = (X + ZZ)(X - ZZ)
+      14. Select R0, R1
+      15. R0 = R0 + R1 = 2(X + ZZ)(X - ZZ)
+      16. R0 = R0 + R1 = 3(X + ZZ)(X - ZZ) = C
+      17. R1 = R0 = C
+
+      Output State:
+      R0 = FREE
+      R1 = C
+      R2 = A
+      R3 = FREE
+      R4 = FREE
+
+      STEP 2:
+    */
+    CRYPTO_EXECUTE_11(crypto,
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA0,
+                      CRYPTO_CMD_INSTR_MADD,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2,
+                      CRYPTO_CMD_INSTR_SELDDATA4DDATA3,
+                      CRYPTO_CMD_INSTR_MADD,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_MSUB,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA4);
+    CRYPTO_InstructionSequenceWait(crypto);
+    CRYPTO_EXECUTE_7 (crypto,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA1,
+                      CRYPTO_CMD_INSTR_MADD,
+                      CRYPTO_CMD_INSTR_MADD,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+    /*
+      STEP 3:
+
+      Goals:
+      R->X = C^2 - 2A
+      D = C(A - R->X)
+
+      Input State:
+      R0 = FREE
+      R1 = C
+      R2 = A
+      R3 = FREE
+      R4 = FREE
+
+      Instructions to be executed:
+
+      1.  R4 = R1 = C
+      2.  Select R1, R4
+      3.  R0 = R1 * R4 = C^2
+      4.  Select R0, R2
+      5.  R0 = R0 - R2 = C^2 - 2A = R->X
+      6.  R4 = R0 = R->X
+      7.  Select R3, R4
+      8.  R0 = R3 - R4 = A - R->X
+      9.  R2 = R0 = A - R->X
+      10  Select R1, R2
+      11. R0 = R1 * R2 = C(A - R->X) = D
+
+      Read Operations:
+
+      R->X = R4 = C^2 - 2A
+
+      Output State:
+      R0   = FREE
+      R1   = FREE
+      R2   = FREE
+      R3   = D
+      R4   = FREE
+
+      STEP 3:
+    */
+
+    CRYPTO_EXECUTE_8 (crypto,
+                      CRYPTO_CMD_INSTR_SELDDATA2DDATA2,
+                      CRYPTO_CMD_INSTR_MADD,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA4,
+
+                      CRYPTO_CMD_INSTR_DDATA1TODDATA3,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                      CRYPTO_CMD_INSTR_MMUL,
+
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA4,
+                      CRYPTO_CMD_INSTR_MSUB);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->X);
+    if ( ret != 0 ) goto cleanup;
+
+    CRYPTO_EXECUTE_7 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA4,
+
+                      CRYPTO_CMD_INSTR_SELDDATA2DDATA4,
+                      CRYPTO_CMD_INSTR_MSUB,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA3
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+
+    /*
+      STEP 4:
+
+      Goals:
+      B    = 8 * Y^4
+      R->Y = D - B
+
+      Write Operations:
+
+      R1 = YY
+
+      Input State:
+      R0   = FREE
+      R1   = YY
+      R2   = FREE
+      R3   = D
+      R4   = FREE
+
+      Instructions to be executed:
+
+      2. R0 = DMA0
+      3. R1 = R0 = Y^2
+      4. R2 = R0 = Y^2
+      5. Select R1, R2
+      6. R0 = R1 * R2 = Y^4
+      7. Select R0, R0
+      8. R0 = R0 + R0 = 2 * Y^4
+      9. R0 = R0 + R0 = 4 * Y^4
+      10. R0 = R0 + R0 = 8 * Y^4
+      11. R2 = R0
+      12. Select R3, R2
+      13. R0 = R3 - R2 = D - B = R->Y
+
+      Read Operations:
+
+      R->Y = R0 = D - B
+
+      STEP 4:
+    */
+    CORE_ENTER_CRITICAL();
+    CRYPTO_DDataWrite(&crypto->DDATA0, _2YY);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_9 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL,
+
+                      CRYPTO_CMD_INSTR_SELDDATA0DDATA0,
+                      CRYPTO_CMD_INSTR_MADD,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA2,
+
+                      CRYPTO_CMD_INSTR_SELDDATA3DDATA2,
+                      CRYPTO_CMD_INSTR_MSUB
+                      );
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    ret = ecp_crypto_ddata_read(&crypto->DDATA0, &R->Y);
+    if ( ret != 0 ) goto cleanup;
+
+ cleanup:
+    crypto_management_release( crypto );
+
+    return ( ret );
+}
+#endif
+
+/**
+ * \brief           Normalize jacobian coordinates of an array of (pointers to)
+ *                  points.
+ *
+ *                  Using Montgomery's trick to perform only one inversion mod P
+ *                  the cost is:
+ *                      1N(t) := 1I + (6t - 3)M + 1S
+ *                  (See for example Algorithm 10.3.4. in [9])
+ *
+ *                  This function is used only as a subrutine of
+ *                  ecp_mul_comb().
+ *
+ *                  Warning: fails (returning an error) if one of the points is
+ *                  zero!
+ *                  This should never happen, see choice of w in ecp_mul_comb().
+ *
+ * \param grp       Pointer to the group representing the curve.
+ *
+ * \param T         Array of pointers to the points to normalise.
+ *
+ * \param t_len     Number of elements in the array.
+ *
+ * \return          0 if successful,
+ *                      an error if one of the points is zero.
+ */
+#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
+int mbedtls_internal_ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
+                                             mbedtls_ecp_point *T[],
+                                             size_t t_len )
+{
+    int ret = 0;
+    size_t i;
+    ecc_bigint_t*   cc;
+    ecc_bigint_t    uu;
+    ecc_bigint_t    one;
+    ecc_bigint_t    modulus;
+    CORE_DECLARE_IRQ_STATE;
+
+    if( t_len < 2 )
+        return( mbedtls_internal_ecp_normalize_jac( grp, *T ) );
+
+    if( ( cc = mbedtls_calloc( t_len, sizeof( ecc_bigint_t ) ) ) == NULL )
+        return( MBEDTLS_ERR_ECP_ALLOC_FAILED );
+
+    /*
+     * c[i] = Z_0 * ... * Z_i
+     */
+    MPI_TO_BIGINT( cc[0], &T[0]->Z );
+
+    CRYPTO_TypeDef *crypto = crypto_management_acquire();
+    crypto_device_init(crypto, grp);
+
+    for( i = 1; i < t_len; i++ )
+    {
+        CORE_ENTER_CRITICAL();
+        ecp_crypto_ddata_write( &crypto->DDATA1, &T[i]->Z );
+        CRYPTO_DDataWrite( &crypto->DDATA2, cc[i-1] );
+        CORE_EXIT_CRITICAL();
+
+        CRYPTO_EXECUTE_2(crypto,
+                         CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                         CRYPTO_CMD_INSTR_MMUL);
+        CRYPTO_InstructionSequenceWait(crypto);
+
+        CORE_ENTER_CRITICAL();
+        CRYPTO_DDataRead( &crypto->DDATA0, cc[i] );
+        CORE_EXIT_CRITICAL();
+    }
+
+    memset(one, 0, sizeof(one));
+    one[0]=1;
+    MPI_TO_BIGINT( modulus, &grp->P );
+
+    /*
+     * u = 1 / (Z_0 * ... * Z_n) mod P
+     */
+    crypto_mpi_div_mod(crypto, one, cc[t_len-1], modulus, uu);
+
+    for( i = t_len - 1; ; i-- )
+    {
+        /*
+         * Zi = 1 / Z_i mod p
+         * u = 1 / (Z_0 * ... * Z_i) mod P
+         */
+        if( i == 0 )
+        {
+            /* Z_inv (DDATA2) = uu */
+            CORE_ENTER_CRITICAL();
+            CRYPTO_DDataWrite(&crypto->DDATA2, uu);
+            CORE_EXIT_CRITICAL();
+        }
+        else
+        {
+            /* Z_inv (DDATA1) = uu x cc[i-1] modulo p */
+            /* uu = uu x T[i]->Z modulo p */
+            CORE_ENTER_CRITICAL();
+            CRYPTO_DDataWrite(&crypto->DDATA1, uu);
+            CRYPTO_DDataWrite(&crypto->DDATA2, cc[i-1]);
+            ecp_crypto_ddata_write( &crypto->DDATA3, &T[i]->Z );
+            CORE_EXIT_CRITICAL();
+
+            CRYPTO_EXECUTE_3(crypto,
+                             CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                             CRYPTO_CMD_INSTR_MMUL,
+                             CRYPTO_CMD_INSTR_DDATA0TODDATA2); /* Z_inv (DDATA2) */
+            CRYPTO_InstructionSequenceWait(crypto);
+            CRYPTO_EXECUTE_2(crypto,
+                             CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                             CRYPTO_CMD_INSTR_MMUL);
+            CRYPTO_InstructionSequenceWait(crypto);
+
+            CORE_ENTER_CRITICAL();
+            CRYPTO_DDataRead(&crypto->DDATA0, uu);
+            CORE_EXIT_CRITICAL();
+        }
+
+        /*
+         * proceed as in normalize()
+         */
+        CORE_ENTER_CRITICAL();
+        ecp_crypto_ddata_write(&crypto->DDATA3, &T[i]->X);
+        ecp_crypto_ddata_write(&crypto->DDATA4, &T[i]->Y);
+        CORE_EXIT_CRITICAL();
+
+        /* Z_inv  already in DDATA2 */
+        CRYPTO_EXECUTE_3 (crypto,
+                          CRYPTO_CMD_INSTR_DDATA2TODDATA1,
+                          CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                          CRYPTO_CMD_INSTR_MMUL);
+        CRYPTO_InstructionSequenceWait(crypto);
+        CRYPTO_EXECUTE_3 (crypto,
+                          CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                          CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                          CRYPTO_CMD_INSTR_MMUL);
+        CRYPTO_InstructionSequenceWait(crypto);
+        CRYPTO_EXECUTE_3 (crypto,
+                          CRYPTO_CMD_INSTR_DDATA0TODDATA3,
+                          CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                          CRYPTO_CMD_INSTR_MMUL);
+        CRYPTO_InstructionSequenceWait(crypto);
+        CRYPTO_EXECUTE_3 (crypto,
+                          CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                          CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                          CRYPTO_CMD_INSTR_MMUL);
+        CRYPTO_InstructionSequenceWait(crypto);
+
+        ecp_crypto_ddata_read(&crypto->DDATA0, &T[i]->Y);
+        ecp_crypto_ddata_read(&crypto->DDATA3, &T[i]->X);
+
+        /*
+         * Post-precessing: reclaim some memory by shrinking coordinates
+         * - not storing Z (always 1)
+         * - shrinking other coordinates, but still keeping the same number of
+         *   limbs as P, as otherwise it will too likely be regrown too fast.
+         */
+        SLCL_ECP_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) );
+        SLCL_ECP_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) );
+        mbedtls_mpi_free( &T[i]->Z );
+
+        if( i == 0 )
+            break;
+    }
+
+ cleanup:
+    crypto_management_release( crypto );
+    mbedtls_free( cc );
+
+    return( ret );
+}
+#endif
+
+/**
+ * \brief           Normalize jacobian coordinates so that Z == 0 || Z == 1.
+ *
+ *                  Cost in field operations if done by [5] 3.2.1:
+ *                      1N := 1I + 3M + 1S
+ *
+ * \param grp       Pointer to the group representing the curve.
+ *
+ * \param pt        pointer to the point to be normalised. This is an
+ *                  input/output parameter.
+ *
+ * \return          0 if successful.
+ */
+#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
+int mbedtls_internal_ecp_normalize_jac( const mbedtls_ecp_group *grp,
+                                        mbedtls_ecp_point *pt )
+{
+    int             ret      = 0;
+    CORE_DECLARE_IRQ_STATE;
+    CRYPTO_TypeDef *crypto = crypto_management_acquire();
+
+    crypto_device_init(crypto, grp);
+
+    ecc_bigint_t    one;
+    ecc_bigint_t    Z;
+    ecc_bigint_t    modulus;
+    ecc_bigint_t    Z_inv;
+
+    memset(one, 0, sizeof(one));
+    one[0]=1;
+
+    MPI_TO_BIGINT( Z, &pt->Z );
+    MPI_TO_BIGINT( modulus, &grp->P );
+
+    crypto_mpi_div_mod(crypto, one, Z, modulus, Z_inv);
+
+    /*
+
+    Goals:
+    R->X = P->X * Z_inv ^2
+    R->Y = P->Y * Z_inv ^3
+
+    Write Operations:
+
+    R1 = Z_inv
+    R3 = P->X
+    R4 = P->Y
+
+    Instructions to be executed:
+
+    1.  R2 = R1 = Z_inv
+    2.  Select R1, R2
+    3.  R0 = R1 * R2 = Z_inv^2
+    4.  R1 = R0 = Z_inv^2
+    5.  Select R1, R3
+    6.  R0 = R1 * R3 = P->X * Z_inv^2 = R->X
+    7.  R3 = R0
+    8.  Select R1, R2
+    9.  R0 = R1 * R2 = Z_inv^3
+    10. R1 = R0 = Z_inv^3
+    11. Select R1, R4
+    12. R0 = R1 * R4 = P->Y * Z_inv^3 = R->Y
+
+    Read Operations:
+
+    R->Y = R0 = P->Y * P->Z_inv^3
+    R->X = R3 = P->X * P->Z_inv^2
+
+    */
+    CORE_ENTER_CRITICAL();
+    CRYPTO_DDataWrite(&crypto->DDATA1, Z_inv);
+    ecp_crypto_ddata_write(&crypto->DDATA3, &pt->X);
+    ecp_crypto_ddata_write(&crypto->DDATA4, &pt->Y);
+    CORE_EXIT_CRITICAL();
+
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA1TODDATA2,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL);
+    CRYPTO_InstructionSequenceWait(crypto);
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA3,
+                      CRYPTO_CMD_INSTR_MMUL);
+    CRYPTO_InstructionSequenceWait(crypto);
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA3,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA2,
+                      CRYPTO_CMD_INSTR_MMUL);
+    CRYPTO_InstructionSequenceWait(crypto);
+    CRYPTO_EXECUTE_3 (crypto,
+                      CRYPTO_CMD_INSTR_DDATA0TODDATA1,
+                      CRYPTO_CMD_INSTR_SELDDATA1DDATA4,
+                      CRYPTO_CMD_INSTR_MMUL);
+    CRYPTO_InstructionSequenceWait(crypto);
+
+    ecp_crypto_ddata_read(&crypto->DDATA0, &pt->Y);
+    ecp_crypto_ddata_read(&crypto->DDATA3, &pt->X);
+
+    crypto_management_release( crypto );
+
+    /*
+     * Z = 1
+     */
+    SLCL_ECP_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) );
+
+ cleanup:
+    return( ret );
+}
+#endif
+
+#endif /* #if defined( MBEDTLS_ECP_INTERNAL_ALT ) */
+
+#endif /* #if defined( MBEDTLS_ECP_C ) */
+
+#endif /* #if defined( CRYPTO_PRESENT ) */