mbed-os/features/mbedtls/targets/TARGET_Silicon_Labs/crypto_ecp.c

1726 lines
52 KiB
C

/*
* 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 ) */