/* * 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. * * * [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. * */ #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 #include /** 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 ) */