Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Diff: mbed-os/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_ecp.c
- 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 ) */