1a8e1175bSopenharmony_ci/* 2a8e1175bSopenharmony_ci * Elliptic curves over GF(p): generic functions 3a8e1175bSopenharmony_ci * 4a8e1175bSopenharmony_ci * Copyright The Mbed TLS Contributors 5a8e1175bSopenharmony_ci * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6a8e1175bSopenharmony_ci */ 7a8e1175bSopenharmony_ci 8a8e1175bSopenharmony_ci/* 9a8e1175bSopenharmony_ci * References: 10a8e1175bSopenharmony_ci * 11a8e1175bSopenharmony_ci * SEC1 https://www.secg.org/sec1-v2.pdf 12a8e1175bSopenharmony_ci * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone 13a8e1175bSopenharmony_ci * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf 14a8e1175bSopenharmony_ci * RFC 4492 for the related TLS structures and constants 15a8e1175bSopenharmony_ci * - https://www.rfc-editor.org/rfc/rfc4492 16a8e1175bSopenharmony_ci * RFC 7748 for the Curve448 and Curve25519 curve definitions 17a8e1175bSopenharmony_ci * - https://www.rfc-editor.org/rfc/rfc7748 18a8e1175bSopenharmony_ci * 19a8e1175bSopenharmony_ci * [Curve25519] https://cr.yp.to/ecdh/curve25519-20060209.pdf 20a8e1175bSopenharmony_ci * 21a8e1175bSopenharmony_ci * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis 22a8e1175bSopenharmony_ci * for elliptic curve cryptosystems. In : Cryptographic Hardware and 23a8e1175bSopenharmony_ci * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. 24a8e1175bSopenharmony_ci * <http://link.springer.com/chapter/10.1007/3-540-48059-5_25> 25a8e1175bSopenharmony_ci * 26a8e1175bSopenharmony_ci * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to 27a8e1175bSopenharmony_ci * render ECC resistant against Side Channel Attacks. IACR Cryptology 28a8e1175bSopenharmony_ci * ePrint Archive, 2004, vol. 2004, p. 342. 29a8e1175bSopenharmony_ci * <http://eprint.iacr.org/2004/342.pdf> 30a8e1175bSopenharmony_ci */ 31a8e1175bSopenharmony_ci 32a8e1175bSopenharmony_ci#include "common.h" 33a8e1175bSopenharmony_ci 34a8e1175bSopenharmony_ci/** 35a8e1175bSopenharmony_ci * \brief Function level alternative implementation. 36a8e1175bSopenharmony_ci * 37a8e1175bSopenharmony_ci * The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to 38a8e1175bSopenharmony_ci * replace certain functions in this module. The alternative implementations are 39a8e1175bSopenharmony_ci * typically hardware accelerators and need to activate the hardware before the 40a8e1175bSopenharmony_ci * computation starts and deactivate it after it finishes. The 41a8e1175bSopenharmony_ci * mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve 42a8e1175bSopenharmony_ci * this purpose. 43a8e1175bSopenharmony_ci * 44a8e1175bSopenharmony_ci * To preserve the correct functionality the following conditions must hold: 45a8e1175bSopenharmony_ci * 46a8e1175bSopenharmony_ci * - The alternative implementation must be activated by 47a8e1175bSopenharmony_ci * mbedtls_internal_ecp_init() before any of the replaceable functions is 48a8e1175bSopenharmony_ci * called. 49a8e1175bSopenharmony_ci * - mbedtls_internal_ecp_free() must \b only be called when the alternative 50a8e1175bSopenharmony_ci * implementation is activated. 51a8e1175bSopenharmony_ci * - mbedtls_internal_ecp_init() must \b not be called when the alternative 52a8e1175bSopenharmony_ci * implementation is activated. 53a8e1175bSopenharmony_ci * - Public functions must not return while the alternative implementation is 54a8e1175bSopenharmony_ci * activated. 55a8e1175bSopenharmony_ci * - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and 56a8e1175bSopenharmony_ci * before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) ) 57a8e1175bSopenharmony_ci * \endcode ensures that the alternative implementation supports the current 58a8e1175bSopenharmony_ci * group. 59a8e1175bSopenharmony_ci */ 60a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_INTERNAL_ALT) 61a8e1175bSopenharmony_ci#endif 62a8e1175bSopenharmony_ci 63a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_LIGHT) 64a8e1175bSopenharmony_ci 65a8e1175bSopenharmony_ci#include "mbedtls/ecp.h" 66a8e1175bSopenharmony_ci#include "mbedtls/threading.h" 67a8e1175bSopenharmony_ci#include "mbedtls/platform_util.h" 68a8e1175bSopenharmony_ci#include "mbedtls/error.h" 69a8e1175bSopenharmony_ci 70a8e1175bSopenharmony_ci#include "bn_mul.h" 71a8e1175bSopenharmony_ci#include "ecp_invasive.h" 72a8e1175bSopenharmony_ci 73a8e1175bSopenharmony_ci#include <string.h> 74a8e1175bSopenharmony_ci 75a8e1175bSopenharmony_ci#if !defined(MBEDTLS_ECP_ALT) 76a8e1175bSopenharmony_ci 77a8e1175bSopenharmony_ci#include "mbedtls/platform.h" 78a8e1175bSopenharmony_ci 79a8e1175bSopenharmony_ci#include "ecp_internal_alt.h" 80a8e1175bSopenharmony_ci 81a8e1175bSopenharmony_ci#if defined(MBEDTLS_SELF_TEST) 82a8e1175bSopenharmony_ci/* 83a8e1175bSopenharmony_ci * Counts of point addition and doubling, and field multiplications. 84a8e1175bSopenharmony_ci * Used to test resistance of point multiplication to simple timing attacks. 85a8e1175bSopenharmony_ci */ 86a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 87a8e1175bSopenharmony_cistatic unsigned long add_count, dbl_count; 88a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 89a8e1175bSopenharmony_cistatic unsigned long mul_count; 90a8e1175bSopenharmony_ci#endif 91a8e1175bSopenharmony_ci 92a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 93a8e1175bSopenharmony_ci/* 94a8e1175bSopenharmony_ci * Maximum number of "basic operations" to be done in a row. 95a8e1175bSopenharmony_ci * 96a8e1175bSopenharmony_ci * Default value 0 means that ECC operations will not yield. 97a8e1175bSopenharmony_ci * Note that regardless of the value of ecp_max_ops, always at 98a8e1175bSopenharmony_ci * least one step is performed before yielding. 99a8e1175bSopenharmony_ci * 100a8e1175bSopenharmony_ci * Setting ecp_max_ops=1 can be suitable for testing purposes 101a8e1175bSopenharmony_ci * as it will interrupt computation at all possible points. 102a8e1175bSopenharmony_ci */ 103a8e1175bSopenharmony_cistatic unsigned ecp_max_ops = 0; 104a8e1175bSopenharmony_ci 105a8e1175bSopenharmony_ci/* 106a8e1175bSopenharmony_ci * Set ecp_max_ops 107a8e1175bSopenharmony_ci */ 108a8e1175bSopenharmony_civoid mbedtls_ecp_set_max_ops(unsigned max_ops) 109a8e1175bSopenharmony_ci{ 110a8e1175bSopenharmony_ci ecp_max_ops = max_ops; 111a8e1175bSopenharmony_ci} 112a8e1175bSopenharmony_ci 113a8e1175bSopenharmony_ci/* 114a8e1175bSopenharmony_ci * Check if restart is enabled 115a8e1175bSopenharmony_ci */ 116a8e1175bSopenharmony_ciint mbedtls_ecp_restart_is_enabled(void) 117a8e1175bSopenharmony_ci{ 118a8e1175bSopenharmony_ci return ecp_max_ops != 0; 119a8e1175bSopenharmony_ci} 120a8e1175bSopenharmony_ci 121a8e1175bSopenharmony_ci/* 122a8e1175bSopenharmony_ci * Restart sub-context for ecp_mul_comb() 123a8e1175bSopenharmony_ci */ 124a8e1175bSopenharmony_cistruct mbedtls_ecp_restart_mul { 125a8e1175bSopenharmony_ci mbedtls_ecp_point R; /* current intermediate result */ 126a8e1175bSopenharmony_ci size_t i; /* current index in various loops, 0 outside */ 127a8e1175bSopenharmony_ci mbedtls_ecp_point *T; /* table for precomputed points */ 128a8e1175bSopenharmony_ci unsigned char T_size; /* number of points in table T */ 129a8e1175bSopenharmony_ci enum { /* what were we doing last time we returned? */ 130a8e1175bSopenharmony_ci ecp_rsm_init = 0, /* nothing so far, dummy initial state */ 131a8e1175bSopenharmony_ci ecp_rsm_pre_dbl, /* precompute 2^n multiples */ 132a8e1175bSopenharmony_ci ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */ 133a8e1175bSopenharmony_ci ecp_rsm_pre_add, /* precompute remaining points by adding */ 134a8e1175bSopenharmony_ci ecp_rsm_pre_norm_add, /* normalize all precomputed points */ 135a8e1175bSopenharmony_ci ecp_rsm_comb_core, /* ecp_mul_comb_core() */ 136a8e1175bSopenharmony_ci ecp_rsm_final_norm, /* do the final normalization */ 137a8e1175bSopenharmony_ci } state; 138a8e1175bSopenharmony_ci}; 139a8e1175bSopenharmony_ci 140a8e1175bSopenharmony_ci/* 141a8e1175bSopenharmony_ci * Init restart_mul sub-context 142a8e1175bSopenharmony_ci */ 143a8e1175bSopenharmony_cistatic void ecp_restart_rsm_init(mbedtls_ecp_restart_mul_ctx *ctx) 144a8e1175bSopenharmony_ci{ 145a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&ctx->R); 146a8e1175bSopenharmony_ci ctx->i = 0; 147a8e1175bSopenharmony_ci ctx->T = NULL; 148a8e1175bSopenharmony_ci ctx->T_size = 0; 149a8e1175bSopenharmony_ci ctx->state = ecp_rsm_init; 150a8e1175bSopenharmony_ci} 151a8e1175bSopenharmony_ci 152a8e1175bSopenharmony_ci/* 153a8e1175bSopenharmony_ci * Free the components of a restart_mul sub-context 154a8e1175bSopenharmony_ci */ 155a8e1175bSopenharmony_cistatic void ecp_restart_rsm_free(mbedtls_ecp_restart_mul_ctx *ctx) 156a8e1175bSopenharmony_ci{ 157a8e1175bSopenharmony_ci unsigned char i; 158a8e1175bSopenharmony_ci 159a8e1175bSopenharmony_ci if (ctx == NULL) { 160a8e1175bSopenharmony_ci return; 161a8e1175bSopenharmony_ci } 162a8e1175bSopenharmony_ci 163a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&ctx->R); 164a8e1175bSopenharmony_ci 165a8e1175bSopenharmony_ci if (ctx->T != NULL) { 166a8e1175bSopenharmony_ci for (i = 0; i < ctx->T_size; i++) { 167a8e1175bSopenharmony_ci mbedtls_ecp_point_free(ctx->T + i); 168a8e1175bSopenharmony_ci } 169a8e1175bSopenharmony_ci mbedtls_free(ctx->T); 170a8e1175bSopenharmony_ci } 171a8e1175bSopenharmony_ci 172a8e1175bSopenharmony_ci ecp_restart_rsm_init(ctx); 173a8e1175bSopenharmony_ci} 174a8e1175bSopenharmony_ci 175a8e1175bSopenharmony_ci/* 176a8e1175bSopenharmony_ci * Restart context for ecp_muladd() 177a8e1175bSopenharmony_ci */ 178a8e1175bSopenharmony_cistruct mbedtls_ecp_restart_muladd { 179a8e1175bSopenharmony_ci mbedtls_ecp_point mP; /* mP value */ 180a8e1175bSopenharmony_ci mbedtls_ecp_point R; /* R intermediate result */ 181a8e1175bSopenharmony_ci enum { /* what should we do next? */ 182a8e1175bSopenharmony_ci ecp_rsma_mul1 = 0, /* first multiplication */ 183a8e1175bSopenharmony_ci ecp_rsma_mul2, /* second multiplication */ 184a8e1175bSopenharmony_ci ecp_rsma_add, /* addition */ 185a8e1175bSopenharmony_ci ecp_rsma_norm, /* normalization */ 186a8e1175bSopenharmony_ci } state; 187a8e1175bSopenharmony_ci}; 188a8e1175bSopenharmony_ci 189a8e1175bSopenharmony_ci/* 190a8e1175bSopenharmony_ci * Init restart_muladd sub-context 191a8e1175bSopenharmony_ci */ 192a8e1175bSopenharmony_cistatic void ecp_restart_ma_init(mbedtls_ecp_restart_muladd_ctx *ctx) 193a8e1175bSopenharmony_ci{ 194a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&ctx->mP); 195a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&ctx->R); 196a8e1175bSopenharmony_ci ctx->state = ecp_rsma_mul1; 197a8e1175bSopenharmony_ci} 198a8e1175bSopenharmony_ci 199a8e1175bSopenharmony_ci/* 200a8e1175bSopenharmony_ci * Free the components of a restart_muladd sub-context 201a8e1175bSopenharmony_ci */ 202a8e1175bSopenharmony_cistatic void ecp_restart_ma_free(mbedtls_ecp_restart_muladd_ctx *ctx) 203a8e1175bSopenharmony_ci{ 204a8e1175bSopenharmony_ci if (ctx == NULL) { 205a8e1175bSopenharmony_ci return; 206a8e1175bSopenharmony_ci } 207a8e1175bSopenharmony_ci 208a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&ctx->mP); 209a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&ctx->R); 210a8e1175bSopenharmony_ci 211a8e1175bSopenharmony_ci ecp_restart_ma_init(ctx); 212a8e1175bSopenharmony_ci} 213a8e1175bSopenharmony_ci 214a8e1175bSopenharmony_ci/* 215a8e1175bSopenharmony_ci * Initialize a restart context 216a8e1175bSopenharmony_ci */ 217a8e1175bSopenharmony_civoid mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx *ctx) 218a8e1175bSopenharmony_ci{ 219a8e1175bSopenharmony_ci ctx->ops_done = 0; 220a8e1175bSopenharmony_ci ctx->depth = 0; 221a8e1175bSopenharmony_ci ctx->rsm = NULL; 222a8e1175bSopenharmony_ci ctx->ma = NULL; 223a8e1175bSopenharmony_ci} 224a8e1175bSopenharmony_ci 225a8e1175bSopenharmony_ci/* 226a8e1175bSopenharmony_ci * Free the components of a restart context 227a8e1175bSopenharmony_ci */ 228a8e1175bSopenharmony_civoid mbedtls_ecp_restart_free(mbedtls_ecp_restart_ctx *ctx) 229a8e1175bSopenharmony_ci{ 230a8e1175bSopenharmony_ci if (ctx == NULL) { 231a8e1175bSopenharmony_ci return; 232a8e1175bSopenharmony_ci } 233a8e1175bSopenharmony_ci 234a8e1175bSopenharmony_ci ecp_restart_rsm_free(ctx->rsm); 235a8e1175bSopenharmony_ci mbedtls_free(ctx->rsm); 236a8e1175bSopenharmony_ci 237a8e1175bSopenharmony_ci ecp_restart_ma_free(ctx->ma); 238a8e1175bSopenharmony_ci mbedtls_free(ctx->ma); 239a8e1175bSopenharmony_ci 240a8e1175bSopenharmony_ci mbedtls_ecp_restart_init(ctx); 241a8e1175bSopenharmony_ci} 242a8e1175bSopenharmony_ci 243a8e1175bSopenharmony_ci/* 244a8e1175bSopenharmony_ci * Check if we can do the next step 245a8e1175bSopenharmony_ci */ 246a8e1175bSopenharmony_ciint mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp, 247a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx, 248a8e1175bSopenharmony_ci unsigned ops) 249a8e1175bSopenharmony_ci{ 250a8e1175bSopenharmony_ci if (rs_ctx != NULL && ecp_max_ops != 0) { 251a8e1175bSopenharmony_ci /* scale depending on curve size: the chosen reference is 256-bit, 252a8e1175bSopenharmony_ci * and multiplication is quadratic. Round to the closest integer. */ 253a8e1175bSopenharmony_ci if (grp->pbits >= 512) { 254a8e1175bSopenharmony_ci ops *= 4; 255a8e1175bSopenharmony_ci } else if (grp->pbits >= 384) { 256a8e1175bSopenharmony_ci ops *= 2; 257a8e1175bSopenharmony_ci } 258a8e1175bSopenharmony_ci 259a8e1175bSopenharmony_ci /* Avoid infinite loops: always allow first step. 260a8e1175bSopenharmony_ci * Because of that, however, it's not generally true 261a8e1175bSopenharmony_ci * that ops_done <= ecp_max_ops, so the check 262a8e1175bSopenharmony_ci * ops_done > ecp_max_ops below is mandatory. */ 263a8e1175bSopenharmony_ci if ((rs_ctx->ops_done != 0) && 264a8e1175bSopenharmony_ci (rs_ctx->ops_done > ecp_max_ops || 265a8e1175bSopenharmony_ci ops > ecp_max_ops - rs_ctx->ops_done)) { 266a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_IN_PROGRESS; 267a8e1175bSopenharmony_ci } 268a8e1175bSopenharmony_ci 269a8e1175bSopenharmony_ci /* update running count */ 270a8e1175bSopenharmony_ci rs_ctx->ops_done += ops; 271a8e1175bSopenharmony_ci } 272a8e1175bSopenharmony_ci 273a8e1175bSopenharmony_ci return 0; 274a8e1175bSopenharmony_ci} 275a8e1175bSopenharmony_ci 276a8e1175bSopenharmony_ci/* Call this when entering a function that needs its own sub-context */ 277a8e1175bSopenharmony_ci#define ECP_RS_ENTER(SUB) do { \ 278a8e1175bSopenharmony_ci /* reset ops count for this call if top-level */ \ 279a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->depth++ == 0) \ 280a8e1175bSopenharmony_ci rs_ctx->ops_done = 0; \ 281a8e1175bSopenharmony_ci \ 282a8e1175bSopenharmony_ci /* set up our own sub-context if needed */ \ 283a8e1175bSopenharmony_ci if (mbedtls_ecp_restart_is_enabled() && \ 284a8e1175bSopenharmony_ci rs_ctx != NULL && rs_ctx->SUB == NULL) \ 285a8e1175bSopenharmony_ci { \ 286a8e1175bSopenharmony_ci rs_ctx->SUB = mbedtls_calloc(1, sizeof(*rs_ctx->SUB)); \ 287a8e1175bSopenharmony_ci if (rs_ctx->SUB == NULL) \ 288a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_ALLOC_FAILED; \ 289a8e1175bSopenharmony_ci \ 290a8e1175bSopenharmony_ci ecp_restart_## SUB ##_init(rs_ctx->SUB); \ 291a8e1175bSopenharmony_ci } \ 292a8e1175bSopenharmony_ci} while (0) 293a8e1175bSopenharmony_ci 294a8e1175bSopenharmony_ci/* Call this when leaving a function that needs its own sub-context */ 295a8e1175bSopenharmony_ci#define ECP_RS_LEAVE(SUB) do { \ 296a8e1175bSopenharmony_ci /* clear our sub-context when not in progress (done or error) */ \ 297a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->SUB != NULL && \ 298a8e1175bSopenharmony_ci ret != MBEDTLS_ERR_ECP_IN_PROGRESS) \ 299a8e1175bSopenharmony_ci { \ 300a8e1175bSopenharmony_ci ecp_restart_## SUB ##_free(rs_ctx->SUB); \ 301a8e1175bSopenharmony_ci mbedtls_free(rs_ctx->SUB); \ 302a8e1175bSopenharmony_ci rs_ctx->SUB = NULL; \ 303a8e1175bSopenharmony_ci } \ 304a8e1175bSopenharmony_ci \ 305a8e1175bSopenharmony_ci if (rs_ctx != NULL) \ 306a8e1175bSopenharmony_ci rs_ctx->depth--; \ 307a8e1175bSopenharmony_ci} while (0) 308a8e1175bSopenharmony_ci 309a8e1175bSopenharmony_ci#else /* MBEDTLS_ECP_RESTARTABLE */ 310a8e1175bSopenharmony_ci 311a8e1175bSopenharmony_ci#define ECP_RS_ENTER(sub) (void) rs_ctx; 312a8e1175bSopenharmony_ci#define ECP_RS_LEAVE(sub) (void) rs_ctx; 313a8e1175bSopenharmony_ci 314a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_RESTARTABLE */ 315a8e1175bSopenharmony_ci 316a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 317a8e1175bSopenharmony_cistatic void mpi_init_many(mbedtls_mpi *arr, size_t size) 318a8e1175bSopenharmony_ci{ 319a8e1175bSopenharmony_ci while (size--) { 320a8e1175bSopenharmony_ci mbedtls_mpi_init(arr++); 321a8e1175bSopenharmony_ci } 322a8e1175bSopenharmony_ci} 323a8e1175bSopenharmony_ci 324a8e1175bSopenharmony_cistatic void mpi_free_many(mbedtls_mpi *arr, size_t size) 325a8e1175bSopenharmony_ci{ 326a8e1175bSopenharmony_ci while (size--) { 327a8e1175bSopenharmony_ci mbedtls_mpi_free(arr++); 328a8e1175bSopenharmony_ci } 329a8e1175bSopenharmony_ci} 330a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 331a8e1175bSopenharmony_ci 332a8e1175bSopenharmony_ci/* 333a8e1175bSopenharmony_ci * List of supported curves: 334a8e1175bSopenharmony_ci * - internal ID 335a8e1175bSopenharmony_ci * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2, RFC 8446 sec. 4.2.7) 336a8e1175bSopenharmony_ci * - size in bits 337a8e1175bSopenharmony_ci * - readable name 338a8e1175bSopenharmony_ci * 339a8e1175bSopenharmony_ci * Curves are listed in order: largest curves first, and for a given size, 340a8e1175bSopenharmony_ci * fastest curves first. 341a8e1175bSopenharmony_ci * 342a8e1175bSopenharmony_ci * Reminder: update profiles in x509_crt.c and ssl_tls.c when adding a new curve! 343a8e1175bSopenharmony_ci */ 344a8e1175bSopenharmony_cistatic const mbedtls_ecp_curve_info ecp_supported_curves[] = 345a8e1175bSopenharmony_ci{ 346a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) 347a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, 348a8e1175bSopenharmony_ci#endif 349a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) 350a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, 351a8e1175bSopenharmony_ci#endif 352a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) 353a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, 354a8e1175bSopenharmony_ci#endif 355a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) 356a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, 357a8e1175bSopenharmony_ci#endif 358a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) 359a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, 360a8e1175bSopenharmony_ci#endif 361a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) 362a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, 363a8e1175bSopenharmony_ci#endif 364a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) 365a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, 366a8e1175bSopenharmony_ci#endif 367a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) 368a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, 369a8e1175bSopenharmony_ci#endif 370a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) 371a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, 372a8e1175bSopenharmony_ci#endif 373a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) 374a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, 375a8e1175bSopenharmony_ci#endif 376a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) 377a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, 378a8e1175bSopenharmony_ci#endif 379a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 380a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_CURVE25519, 29, 256, "x25519" }, 381a8e1175bSopenharmony_ci#endif 382a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) 383a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_CURVE448, 30, 448, "x448" }, 384a8e1175bSopenharmony_ci#endif 385a8e1175bSopenharmony_ci { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, 386a8e1175bSopenharmony_ci}; 387a8e1175bSopenharmony_ci 388a8e1175bSopenharmony_ci#define ECP_NB_CURVES sizeof(ecp_supported_curves) / \ 389a8e1175bSopenharmony_ci sizeof(ecp_supported_curves[0]) 390a8e1175bSopenharmony_ci 391a8e1175bSopenharmony_cistatic mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; 392a8e1175bSopenharmony_ci 393a8e1175bSopenharmony_ci/* 394a8e1175bSopenharmony_ci * List of supported curves and associated info 395a8e1175bSopenharmony_ci */ 396a8e1175bSopenharmony_ciconst mbedtls_ecp_curve_info *mbedtls_ecp_curve_list(void) 397a8e1175bSopenharmony_ci{ 398a8e1175bSopenharmony_ci return ecp_supported_curves; 399a8e1175bSopenharmony_ci} 400a8e1175bSopenharmony_ci 401a8e1175bSopenharmony_ci/* 402a8e1175bSopenharmony_ci * List of supported curves, group ID only 403a8e1175bSopenharmony_ci */ 404a8e1175bSopenharmony_ciconst mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list(void) 405a8e1175bSopenharmony_ci{ 406a8e1175bSopenharmony_ci static int init_done = 0; 407a8e1175bSopenharmony_ci 408a8e1175bSopenharmony_ci if (!init_done) { 409a8e1175bSopenharmony_ci size_t i = 0; 410a8e1175bSopenharmony_ci const mbedtls_ecp_curve_info *curve_info; 411a8e1175bSopenharmony_ci 412a8e1175bSopenharmony_ci for (curve_info = mbedtls_ecp_curve_list(); 413a8e1175bSopenharmony_ci curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 414a8e1175bSopenharmony_ci curve_info++) { 415a8e1175bSopenharmony_ci ecp_supported_grp_id[i++] = curve_info->grp_id; 416a8e1175bSopenharmony_ci } 417a8e1175bSopenharmony_ci ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE; 418a8e1175bSopenharmony_ci 419a8e1175bSopenharmony_ci init_done = 1; 420a8e1175bSopenharmony_ci } 421a8e1175bSopenharmony_ci 422a8e1175bSopenharmony_ci return ecp_supported_grp_id; 423a8e1175bSopenharmony_ci} 424a8e1175bSopenharmony_ci 425a8e1175bSopenharmony_ci/* 426a8e1175bSopenharmony_ci * Get the curve info for the internal identifier 427a8e1175bSopenharmony_ci */ 428a8e1175bSopenharmony_ciconst mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id(mbedtls_ecp_group_id grp_id) 429a8e1175bSopenharmony_ci{ 430a8e1175bSopenharmony_ci const mbedtls_ecp_curve_info *curve_info; 431a8e1175bSopenharmony_ci 432a8e1175bSopenharmony_ci for (curve_info = mbedtls_ecp_curve_list(); 433a8e1175bSopenharmony_ci curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 434a8e1175bSopenharmony_ci curve_info++) { 435a8e1175bSopenharmony_ci if (curve_info->grp_id == grp_id) { 436a8e1175bSopenharmony_ci return curve_info; 437a8e1175bSopenharmony_ci } 438a8e1175bSopenharmony_ci } 439a8e1175bSopenharmony_ci 440a8e1175bSopenharmony_ci return NULL; 441a8e1175bSopenharmony_ci} 442a8e1175bSopenharmony_ci 443a8e1175bSopenharmony_ci/* 444a8e1175bSopenharmony_ci * Get the curve info from the TLS identifier 445a8e1175bSopenharmony_ci */ 446a8e1175bSopenharmony_ciconst mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id(uint16_t tls_id) 447a8e1175bSopenharmony_ci{ 448a8e1175bSopenharmony_ci const mbedtls_ecp_curve_info *curve_info; 449a8e1175bSopenharmony_ci 450a8e1175bSopenharmony_ci for (curve_info = mbedtls_ecp_curve_list(); 451a8e1175bSopenharmony_ci curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 452a8e1175bSopenharmony_ci curve_info++) { 453a8e1175bSopenharmony_ci if (curve_info->tls_id == tls_id) { 454a8e1175bSopenharmony_ci return curve_info; 455a8e1175bSopenharmony_ci } 456a8e1175bSopenharmony_ci } 457a8e1175bSopenharmony_ci 458a8e1175bSopenharmony_ci return NULL; 459a8e1175bSopenharmony_ci} 460a8e1175bSopenharmony_ci 461a8e1175bSopenharmony_ci/* 462a8e1175bSopenharmony_ci * Get the curve info from the name 463a8e1175bSopenharmony_ci */ 464a8e1175bSopenharmony_ciconst mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name(const char *name) 465a8e1175bSopenharmony_ci{ 466a8e1175bSopenharmony_ci const mbedtls_ecp_curve_info *curve_info; 467a8e1175bSopenharmony_ci 468a8e1175bSopenharmony_ci if (name == NULL) { 469a8e1175bSopenharmony_ci return NULL; 470a8e1175bSopenharmony_ci } 471a8e1175bSopenharmony_ci 472a8e1175bSopenharmony_ci for (curve_info = mbedtls_ecp_curve_list(); 473a8e1175bSopenharmony_ci curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 474a8e1175bSopenharmony_ci curve_info++) { 475a8e1175bSopenharmony_ci if (strcmp(curve_info->name, name) == 0) { 476a8e1175bSopenharmony_ci return curve_info; 477a8e1175bSopenharmony_ci } 478a8e1175bSopenharmony_ci } 479a8e1175bSopenharmony_ci 480a8e1175bSopenharmony_ci return NULL; 481a8e1175bSopenharmony_ci} 482a8e1175bSopenharmony_ci 483a8e1175bSopenharmony_ci/* 484a8e1175bSopenharmony_ci * Get the type of a curve 485a8e1175bSopenharmony_ci */ 486a8e1175bSopenharmony_cimbedtls_ecp_curve_type mbedtls_ecp_get_type(const mbedtls_ecp_group *grp) 487a8e1175bSopenharmony_ci{ 488a8e1175bSopenharmony_ci if (grp->G.X.p == NULL) { 489a8e1175bSopenharmony_ci return MBEDTLS_ECP_TYPE_NONE; 490a8e1175bSopenharmony_ci } 491a8e1175bSopenharmony_ci 492a8e1175bSopenharmony_ci if (grp->G.Y.p == NULL) { 493a8e1175bSopenharmony_ci return MBEDTLS_ECP_TYPE_MONTGOMERY; 494a8e1175bSopenharmony_ci } else { 495a8e1175bSopenharmony_ci return MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS; 496a8e1175bSopenharmony_ci } 497a8e1175bSopenharmony_ci} 498a8e1175bSopenharmony_ci 499a8e1175bSopenharmony_ci/* 500a8e1175bSopenharmony_ci * Initialize (the components of) a point 501a8e1175bSopenharmony_ci */ 502a8e1175bSopenharmony_civoid mbedtls_ecp_point_init(mbedtls_ecp_point *pt) 503a8e1175bSopenharmony_ci{ 504a8e1175bSopenharmony_ci mbedtls_mpi_init(&pt->X); 505a8e1175bSopenharmony_ci mbedtls_mpi_init(&pt->Y); 506a8e1175bSopenharmony_ci mbedtls_mpi_init(&pt->Z); 507a8e1175bSopenharmony_ci} 508a8e1175bSopenharmony_ci 509a8e1175bSopenharmony_ci/* 510a8e1175bSopenharmony_ci * Initialize (the components of) a group 511a8e1175bSopenharmony_ci */ 512a8e1175bSopenharmony_civoid mbedtls_ecp_group_init(mbedtls_ecp_group *grp) 513a8e1175bSopenharmony_ci{ 514a8e1175bSopenharmony_ci grp->id = MBEDTLS_ECP_DP_NONE; 515a8e1175bSopenharmony_ci mbedtls_mpi_init(&grp->P); 516a8e1175bSopenharmony_ci mbedtls_mpi_init(&grp->A); 517a8e1175bSopenharmony_ci mbedtls_mpi_init(&grp->B); 518a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&grp->G); 519a8e1175bSopenharmony_ci mbedtls_mpi_init(&grp->N); 520a8e1175bSopenharmony_ci grp->pbits = 0; 521a8e1175bSopenharmony_ci grp->nbits = 0; 522a8e1175bSopenharmony_ci grp->h = 0; 523a8e1175bSopenharmony_ci grp->modp = NULL; 524a8e1175bSopenharmony_ci grp->t_pre = NULL; 525a8e1175bSopenharmony_ci grp->t_post = NULL; 526a8e1175bSopenharmony_ci grp->t_data = NULL; 527a8e1175bSopenharmony_ci grp->T = NULL; 528a8e1175bSopenharmony_ci grp->T_size = 0; 529a8e1175bSopenharmony_ci} 530a8e1175bSopenharmony_ci 531a8e1175bSopenharmony_ci/* 532a8e1175bSopenharmony_ci * Initialize (the components of) a key pair 533a8e1175bSopenharmony_ci */ 534a8e1175bSopenharmony_civoid mbedtls_ecp_keypair_init(mbedtls_ecp_keypair *key) 535a8e1175bSopenharmony_ci{ 536a8e1175bSopenharmony_ci mbedtls_ecp_group_init(&key->grp); 537a8e1175bSopenharmony_ci mbedtls_mpi_init(&key->d); 538a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&key->Q); 539a8e1175bSopenharmony_ci} 540a8e1175bSopenharmony_ci 541a8e1175bSopenharmony_ci/* 542a8e1175bSopenharmony_ci * Unallocate (the components of) a point 543a8e1175bSopenharmony_ci */ 544a8e1175bSopenharmony_civoid mbedtls_ecp_point_free(mbedtls_ecp_point *pt) 545a8e1175bSopenharmony_ci{ 546a8e1175bSopenharmony_ci if (pt == NULL) { 547a8e1175bSopenharmony_ci return; 548a8e1175bSopenharmony_ci } 549a8e1175bSopenharmony_ci 550a8e1175bSopenharmony_ci mbedtls_mpi_free(&(pt->X)); 551a8e1175bSopenharmony_ci mbedtls_mpi_free(&(pt->Y)); 552a8e1175bSopenharmony_ci mbedtls_mpi_free(&(pt->Z)); 553a8e1175bSopenharmony_ci} 554a8e1175bSopenharmony_ci 555a8e1175bSopenharmony_ci/* 556a8e1175bSopenharmony_ci * Check that the comb table (grp->T) is static initialized. 557a8e1175bSopenharmony_ci */ 558a8e1175bSopenharmony_cistatic int ecp_group_is_static_comb_table(const mbedtls_ecp_group *grp) 559a8e1175bSopenharmony_ci{ 560a8e1175bSopenharmony_ci#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 561a8e1175bSopenharmony_ci return grp->T != NULL && grp->T_size == 0; 562a8e1175bSopenharmony_ci#else 563a8e1175bSopenharmony_ci (void) grp; 564a8e1175bSopenharmony_ci return 0; 565a8e1175bSopenharmony_ci#endif 566a8e1175bSopenharmony_ci} 567a8e1175bSopenharmony_ci 568a8e1175bSopenharmony_ci/* 569a8e1175bSopenharmony_ci * Unallocate (the components of) a group 570a8e1175bSopenharmony_ci */ 571a8e1175bSopenharmony_civoid mbedtls_ecp_group_free(mbedtls_ecp_group *grp) 572a8e1175bSopenharmony_ci{ 573a8e1175bSopenharmony_ci size_t i; 574a8e1175bSopenharmony_ci 575a8e1175bSopenharmony_ci if (grp == NULL) { 576a8e1175bSopenharmony_ci return; 577a8e1175bSopenharmony_ci } 578a8e1175bSopenharmony_ci 579a8e1175bSopenharmony_ci if (grp->h != 1) { 580a8e1175bSopenharmony_ci mbedtls_mpi_free(&grp->A); 581a8e1175bSopenharmony_ci mbedtls_mpi_free(&grp->B); 582a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&grp->G); 583a8e1175bSopenharmony_ci 584a8e1175bSopenharmony_ci#if !defined(MBEDTLS_ECP_WITH_MPI_UINT) 585a8e1175bSopenharmony_ci mbedtls_mpi_free(&grp->N); 586a8e1175bSopenharmony_ci mbedtls_mpi_free(&grp->P); 587a8e1175bSopenharmony_ci#endif 588a8e1175bSopenharmony_ci } 589a8e1175bSopenharmony_ci 590a8e1175bSopenharmony_ci if (!ecp_group_is_static_comb_table(grp) && grp->T != NULL) { 591a8e1175bSopenharmony_ci for (i = 0; i < grp->T_size; i++) { 592a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&grp->T[i]); 593a8e1175bSopenharmony_ci } 594a8e1175bSopenharmony_ci mbedtls_free(grp->T); 595a8e1175bSopenharmony_ci } 596a8e1175bSopenharmony_ci 597a8e1175bSopenharmony_ci mbedtls_platform_zeroize(grp, sizeof(mbedtls_ecp_group)); 598a8e1175bSopenharmony_ci} 599a8e1175bSopenharmony_ci 600a8e1175bSopenharmony_ci/* 601a8e1175bSopenharmony_ci * Unallocate (the components of) a key pair 602a8e1175bSopenharmony_ci */ 603a8e1175bSopenharmony_civoid mbedtls_ecp_keypair_free(mbedtls_ecp_keypair *key) 604a8e1175bSopenharmony_ci{ 605a8e1175bSopenharmony_ci if (key == NULL) { 606a8e1175bSopenharmony_ci return; 607a8e1175bSopenharmony_ci } 608a8e1175bSopenharmony_ci 609a8e1175bSopenharmony_ci mbedtls_ecp_group_free(&key->grp); 610a8e1175bSopenharmony_ci mbedtls_mpi_free(&key->d); 611a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&key->Q); 612a8e1175bSopenharmony_ci} 613a8e1175bSopenharmony_ci 614a8e1175bSopenharmony_ci/* 615a8e1175bSopenharmony_ci * Copy the contents of a point 616a8e1175bSopenharmony_ci */ 617a8e1175bSopenharmony_ciint mbedtls_ecp_copy(mbedtls_ecp_point *P, const mbedtls_ecp_point *Q) 618a8e1175bSopenharmony_ci{ 619a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 620a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->X, &Q->X)); 621a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Y, &Q->Y)); 622a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Z, &Q->Z)); 623a8e1175bSopenharmony_ci 624a8e1175bSopenharmony_cicleanup: 625a8e1175bSopenharmony_ci return ret; 626a8e1175bSopenharmony_ci} 627a8e1175bSopenharmony_ci 628a8e1175bSopenharmony_ci/* 629a8e1175bSopenharmony_ci * Copy the contents of a group object 630a8e1175bSopenharmony_ci */ 631a8e1175bSopenharmony_ciint mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, const mbedtls_ecp_group *src) 632a8e1175bSopenharmony_ci{ 633a8e1175bSopenharmony_ci return mbedtls_ecp_group_load(dst, src->id); 634a8e1175bSopenharmony_ci} 635a8e1175bSopenharmony_ci 636a8e1175bSopenharmony_ci/* 637a8e1175bSopenharmony_ci * Set point to zero 638a8e1175bSopenharmony_ci */ 639a8e1175bSopenharmony_ciint mbedtls_ecp_set_zero(mbedtls_ecp_point *pt) 640a8e1175bSopenharmony_ci{ 641a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 642a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->X, 1)); 643a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Y, 1)); 644a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 0)); 645a8e1175bSopenharmony_ci 646a8e1175bSopenharmony_cicleanup: 647a8e1175bSopenharmony_ci return ret; 648a8e1175bSopenharmony_ci} 649a8e1175bSopenharmony_ci 650a8e1175bSopenharmony_ci/* 651a8e1175bSopenharmony_ci * Tell if a point is zero 652a8e1175bSopenharmony_ci */ 653a8e1175bSopenharmony_ciint mbedtls_ecp_is_zero(mbedtls_ecp_point *pt) 654a8e1175bSopenharmony_ci{ 655a8e1175bSopenharmony_ci return mbedtls_mpi_cmp_int(&pt->Z, 0) == 0; 656a8e1175bSopenharmony_ci} 657a8e1175bSopenharmony_ci 658a8e1175bSopenharmony_ci/* 659a8e1175bSopenharmony_ci * Compare two points lazily 660a8e1175bSopenharmony_ci */ 661a8e1175bSopenharmony_ciint mbedtls_ecp_point_cmp(const mbedtls_ecp_point *P, 662a8e1175bSopenharmony_ci const mbedtls_ecp_point *Q) 663a8e1175bSopenharmony_ci{ 664a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_mpi(&P->X, &Q->X) == 0 && 665a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&P->Y, &Q->Y) == 0 && 666a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&P->Z, &Q->Z) == 0) { 667a8e1175bSopenharmony_ci return 0; 668a8e1175bSopenharmony_ci } 669a8e1175bSopenharmony_ci 670a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 671a8e1175bSopenharmony_ci} 672a8e1175bSopenharmony_ci 673a8e1175bSopenharmony_ci/* 674a8e1175bSopenharmony_ci * Import a non-zero point from ASCII strings 675a8e1175bSopenharmony_ci */ 676a8e1175bSopenharmony_ciint mbedtls_ecp_point_read_string(mbedtls_ecp_point *P, int radix, 677a8e1175bSopenharmony_ci const char *x, const char *y) 678a8e1175bSopenharmony_ci{ 679a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 680a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->X, radix, x)); 681a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->Y, radix, y)); 682a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->Z, 1)); 683a8e1175bSopenharmony_ci 684a8e1175bSopenharmony_cicleanup: 685a8e1175bSopenharmony_ci return ret; 686a8e1175bSopenharmony_ci} 687a8e1175bSopenharmony_ci 688a8e1175bSopenharmony_ci/* 689a8e1175bSopenharmony_ci * Export a point into unsigned binary data (SEC1 2.3.3 and RFC7748) 690a8e1175bSopenharmony_ci */ 691a8e1175bSopenharmony_ciint mbedtls_ecp_point_write_binary(const mbedtls_ecp_group *grp, 692a8e1175bSopenharmony_ci const mbedtls_ecp_point *P, 693a8e1175bSopenharmony_ci int format, size_t *olen, 694a8e1175bSopenharmony_ci unsigned char *buf, size_t buflen) 695a8e1175bSopenharmony_ci{ 696a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 697a8e1175bSopenharmony_ci size_t plen; 698a8e1175bSopenharmony_ci if (format != MBEDTLS_ECP_PF_UNCOMPRESSED && 699a8e1175bSopenharmony_ci format != MBEDTLS_ECP_PF_COMPRESSED) { 700a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 701a8e1175bSopenharmony_ci } 702a8e1175bSopenharmony_ci 703a8e1175bSopenharmony_ci plen = mbedtls_mpi_size(&grp->P); 704a8e1175bSopenharmony_ci 705a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 706a8e1175bSopenharmony_ci (void) format; /* Montgomery curves always use the same point format */ 707a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 708a8e1175bSopenharmony_ci *olen = plen; 709a8e1175bSopenharmony_ci if (buflen < *olen) { 710a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 711a8e1175bSopenharmony_ci } 712a8e1175bSopenharmony_ci 713a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&P->X, buf, plen)); 714a8e1175bSopenharmony_ci } 715a8e1175bSopenharmony_ci#endif 716a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 717a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 718a8e1175bSopenharmony_ci /* 719a8e1175bSopenharmony_ci * Common case: P == 0 720a8e1175bSopenharmony_ci */ 721a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0) { 722a8e1175bSopenharmony_ci if (buflen < 1) { 723a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 724a8e1175bSopenharmony_ci } 725a8e1175bSopenharmony_ci 726a8e1175bSopenharmony_ci buf[0] = 0x00; 727a8e1175bSopenharmony_ci *olen = 1; 728a8e1175bSopenharmony_ci 729a8e1175bSopenharmony_ci return 0; 730a8e1175bSopenharmony_ci } 731a8e1175bSopenharmony_ci 732a8e1175bSopenharmony_ci if (format == MBEDTLS_ECP_PF_UNCOMPRESSED) { 733a8e1175bSopenharmony_ci *olen = 2 * plen + 1; 734a8e1175bSopenharmony_ci 735a8e1175bSopenharmony_ci if (buflen < *olen) { 736a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 737a8e1175bSopenharmony_ci } 738a8e1175bSopenharmony_ci 739a8e1175bSopenharmony_ci buf[0] = 0x04; 740a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen)); 741a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->Y, buf + 1 + plen, plen)); 742a8e1175bSopenharmony_ci } else if (format == MBEDTLS_ECP_PF_COMPRESSED) { 743a8e1175bSopenharmony_ci *olen = plen + 1; 744a8e1175bSopenharmony_ci 745a8e1175bSopenharmony_ci if (buflen < *olen) { 746a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 747a8e1175bSopenharmony_ci } 748a8e1175bSopenharmony_ci 749a8e1175bSopenharmony_ci buf[0] = 0x02 + mbedtls_mpi_get_bit(&P->Y, 0); 750a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen)); 751a8e1175bSopenharmony_ci } 752a8e1175bSopenharmony_ci } 753a8e1175bSopenharmony_ci#endif 754a8e1175bSopenharmony_ci 755a8e1175bSopenharmony_cicleanup: 756a8e1175bSopenharmony_ci return ret; 757a8e1175bSopenharmony_ci} 758a8e1175bSopenharmony_ci 759a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 760a8e1175bSopenharmony_cistatic int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, 761a8e1175bSopenharmony_ci const mbedtls_mpi *X, 762a8e1175bSopenharmony_ci mbedtls_mpi *Y, 763a8e1175bSopenharmony_ci int parity_bit); 764a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 765a8e1175bSopenharmony_ci 766a8e1175bSopenharmony_ci/* 767a8e1175bSopenharmony_ci * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748) 768a8e1175bSopenharmony_ci */ 769a8e1175bSopenharmony_ciint mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp, 770a8e1175bSopenharmony_ci mbedtls_ecp_point *pt, 771a8e1175bSopenharmony_ci const unsigned char *buf, size_t ilen) 772a8e1175bSopenharmony_ci{ 773a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 774a8e1175bSopenharmony_ci size_t plen; 775a8e1175bSopenharmony_ci if (ilen < 1) { 776a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 777a8e1175bSopenharmony_ci } 778a8e1175bSopenharmony_ci 779a8e1175bSopenharmony_ci plen = mbedtls_mpi_size(&grp->P); 780a8e1175bSopenharmony_ci 781a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 782a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 783a8e1175bSopenharmony_ci if (plen != ilen) { 784a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 785a8e1175bSopenharmony_ci } 786a8e1175bSopenharmony_ci 787a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&pt->X, buf, plen)); 788a8e1175bSopenharmony_ci mbedtls_mpi_free(&pt->Y); 789a8e1175bSopenharmony_ci 790a8e1175bSopenharmony_ci if (grp->id == MBEDTLS_ECP_DP_CURVE25519) { 791a8e1175bSopenharmony_ci /* Set most significant bit to 0 as prescribed in RFC7748 §5 */ 792a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&pt->X, plen * 8 - 1, 0)); 793a8e1175bSopenharmony_ci } 794a8e1175bSopenharmony_ci 795a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); 796a8e1175bSopenharmony_ci } 797a8e1175bSopenharmony_ci#endif 798a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 799a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 800a8e1175bSopenharmony_ci if (buf[0] == 0x00) { 801a8e1175bSopenharmony_ci if (ilen == 1) { 802a8e1175bSopenharmony_ci return mbedtls_ecp_set_zero(pt); 803a8e1175bSopenharmony_ci } else { 804a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 805a8e1175bSopenharmony_ci } 806a8e1175bSopenharmony_ci } 807a8e1175bSopenharmony_ci 808a8e1175bSopenharmony_ci if (ilen < 1 + plen) { 809a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 810a8e1175bSopenharmony_ci } 811a8e1175bSopenharmony_ci 812a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, buf + 1, plen)); 813a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); 814a8e1175bSopenharmony_ci 815a8e1175bSopenharmony_ci if (buf[0] == 0x04) { 816a8e1175bSopenharmony_ci /* format == MBEDTLS_ECP_PF_UNCOMPRESSED */ 817a8e1175bSopenharmony_ci if (ilen != 1 + plen * 2) { 818a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 819a8e1175bSopenharmony_ci } 820a8e1175bSopenharmony_ci return mbedtls_mpi_read_binary(&pt->Y, buf + 1 + plen, plen); 821a8e1175bSopenharmony_ci } else if (buf[0] == 0x02 || buf[0] == 0x03) { 822a8e1175bSopenharmony_ci /* format == MBEDTLS_ECP_PF_COMPRESSED */ 823a8e1175bSopenharmony_ci if (ilen != 1 + plen) { 824a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 825a8e1175bSopenharmony_ci } 826a8e1175bSopenharmony_ci return mbedtls_ecp_sw_derive_y(grp, &pt->X, &pt->Y, 827a8e1175bSopenharmony_ci (buf[0] & 1)); 828a8e1175bSopenharmony_ci } else { 829a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 830a8e1175bSopenharmony_ci } 831a8e1175bSopenharmony_ci } 832a8e1175bSopenharmony_ci#endif 833a8e1175bSopenharmony_ci 834a8e1175bSopenharmony_cicleanup: 835a8e1175bSopenharmony_ci return ret; 836a8e1175bSopenharmony_ci} 837a8e1175bSopenharmony_ci 838a8e1175bSopenharmony_ci/* 839a8e1175bSopenharmony_ci * Import a point from a TLS ECPoint record (RFC 4492) 840a8e1175bSopenharmony_ci * struct { 841a8e1175bSopenharmony_ci * opaque point <1..2^8-1>; 842a8e1175bSopenharmony_ci * } ECPoint; 843a8e1175bSopenharmony_ci */ 844a8e1175bSopenharmony_ciint mbedtls_ecp_tls_read_point(const mbedtls_ecp_group *grp, 845a8e1175bSopenharmony_ci mbedtls_ecp_point *pt, 846a8e1175bSopenharmony_ci const unsigned char **buf, size_t buf_len) 847a8e1175bSopenharmony_ci{ 848a8e1175bSopenharmony_ci unsigned char data_len; 849a8e1175bSopenharmony_ci const unsigned char *buf_start; 850a8e1175bSopenharmony_ci /* 851a8e1175bSopenharmony_ci * We must have at least two bytes (1 for length, at least one for data) 852a8e1175bSopenharmony_ci */ 853a8e1175bSopenharmony_ci if (buf_len < 2) { 854a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 855a8e1175bSopenharmony_ci } 856a8e1175bSopenharmony_ci 857a8e1175bSopenharmony_ci data_len = *(*buf)++; 858a8e1175bSopenharmony_ci if (data_len < 1 || data_len > buf_len - 1) { 859a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 860a8e1175bSopenharmony_ci } 861a8e1175bSopenharmony_ci 862a8e1175bSopenharmony_ci /* 863a8e1175bSopenharmony_ci * Save buffer start for read_binary and update buf 864a8e1175bSopenharmony_ci */ 865a8e1175bSopenharmony_ci buf_start = *buf; 866a8e1175bSopenharmony_ci *buf += data_len; 867a8e1175bSopenharmony_ci 868a8e1175bSopenharmony_ci return mbedtls_ecp_point_read_binary(grp, pt, buf_start, data_len); 869a8e1175bSopenharmony_ci} 870a8e1175bSopenharmony_ci 871a8e1175bSopenharmony_ci/* 872a8e1175bSopenharmony_ci * Export a point as a TLS ECPoint record (RFC 4492) 873a8e1175bSopenharmony_ci * struct { 874a8e1175bSopenharmony_ci * opaque point <1..2^8-1>; 875a8e1175bSopenharmony_ci * } ECPoint; 876a8e1175bSopenharmony_ci */ 877a8e1175bSopenharmony_ciint mbedtls_ecp_tls_write_point(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, 878a8e1175bSopenharmony_ci int format, size_t *olen, 879a8e1175bSopenharmony_ci unsigned char *buf, size_t blen) 880a8e1175bSopenharmony_ci{ 881a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 882a8e1175bSopenharmony_ci if (format != MBEDTLS_ECP_PF_UNCOMPRESSED && 883a8e1175bSopenharmony_ci format != MBEDTLS_ECP_PF_COMPRESSED) { 884a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 885a8e1175bSopenharmony_ci } 886a8e1175bSopenharmony_ci 887a8e1175bSopenharmony_ci /* 888a8e1175bSopenharmony_ci * buffer length must be at least one, for our length byte 889a8e1175bSopenharmony_ci */ 890a8e1175bSopenharmony_ci if (blen < 1) { 891a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 892a8e1175bSopenharmony_ci } 893a8e1175bSopenharmony_ci 894a8e1175bSopenharmony_ci if ((ret = mbedtls_ecp_point_write_binary(grp, pt, format, 895a8e1175bSopenharmony_ci olen, buf + 1, blen - 1)) != 0) { 896a8e1175bSopenharmony_ci return ret; 897a8e1175bSopenharmony_ci } 898a8e1175bSopenharmony_ci 899a8e1175bSopenharmony_ci /* 900a8e1175bSopenharmony_ci * write length to the first byte and update total length 901a8e1175bSopenharmony_ci */ 902a8e1175bSopenharmony_ci buf[0] = (unsigned char) *olen; 903a8e1175bSopenharmony_ci ++*olen; 904a8e1175bSopenharmony_ci 905a8e1175bSopenharmony_ci return 0; 906a8e1175bSopenharmony_ci} 907a8e1175bSopenharmony_ci 908a8e1175bSopenharmony_ci/* 909a8e1175bSopenharmony_ci * Set a group from an ECParameters record (RFC 4492) 910a8e1175bSopenharmony_ci */ 911a8e1175bSopenharmony_ciint mbedtls_ecp_tls_read_group(mbedtls_ecp_group *grp, 912a8e1175bSopenharmony_ci const unsigned char **buf, size_t len) 913a8e1175bSopenharmony_ci{ 914a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 915a8e1175bSopenharmony_ci mbedtls_ecp_group_id grp_id; 916a8e1175bSopenharmony_ci if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, len)) != 0) { 917a8e1175bSopenharmony_ci return ret; 918a8e1175bSopenharmony_ci } 919a8e1175bSopenharmony_ci 920a8e1175bSopenharmony_ci return mbedtls_ecp_group_load(grp, grp_id); 921a8e1175bSopenharmony_ci} 922a8e1175bSopenharmony_ci 923a8e1175bSopenharmony_ci/* 924a8e1175bSopenharmony_ci * Read a group id from an ECParameters record (RFC 4492) and convert it to 925a8e1175bSopenharmony_ci * mbedtls_ecp_group_id. 926a8e1175bSopenharmony_ci */ 927a8e1175bSopenharmony_ciint mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp, 928a8e1175bSopenharmony_ci const unsigned char **buf, size_t len) 929a8e1175bSopenharmony_ci{ 930a8e1175bSopenharmony_ci uint16_t tls_id; 931a8e1175bSopenharmony_ci const mbedtls_ecp_curve_info *curve_info; 932a8e1175bSopenharmony_ci /* 933a8e1175bSopenharmony_ci * We expect at least three bytes (see below) 934a8e1175bSopenharmony_ci */ 935a8e1175bSopenharmony_ci if (len < 3) { 936a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 937a8e1175bSopenharmony_ci } 938a8e1175bSopenharmony_ci 939a8e1175bSopenharmony_ci /* 940a8e1175bSopenharmony_ci * First byte is curve_type; only named_curve is handled 941a8e1175bSopenharmony_ci */ 942a8e1175bSopenharmony_ci if (*(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE) { 943a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 944a8e1175bSopenharmony_ci } 945a8e1175bSopenharmony_ci 946a8e1175bSopenharmony_ci /* 947a8e1175bSopenharmony_ci * Next two bytes are the namedcurve value 948a8e1175bSopenharmony_ci */ 949a8e1175bSopenharmony_ci tls_id = MBEDTLS_GET_UINT16_BE(*buf, 0); 950a8e1175bSopenharmony_ci *buf += 2; 951a8e1175bSopenharmony_ci 952a8e1175bSopenharmony_ci if ((curve_info = mbedtls_ecp_curve_info_from_tls_id(tls_id)) == NULL) { 953a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 954a8e1175bSopenharmony_ci } 955a8e1175bSopenharmony_ci 956a8e1175bSopenharmony_ci *grp = curve_info->grp_id; 957a8e1175bSopenharmony_ci 958a8e1175bSopenharmony_ci return 0; 959a8e1175bSopenharmony_ci} 960a8e1175bSopenharmony_ci 961a8e1175bSopenharmony_ci/* 962a8e1175bSopenharmony_ci * Write the ECParameters record corresponding to a group (RFC 4492) 963a8e1175bSopenharmony_ci */ 964a8e1175bSopenharmony_ciint mbedtls_ecp_tls_write_group(const mbedtls_ecp_group *grp, size_t *olen, 965a8e1175bSopenharmony_ci unsigned char *buf, size_t blen) 966a8e1175bSopenharmony_ci{ 967a8e1175bSopenharmony_ci const mbedtls_ecp_curve_info *curve_info; 968a8e1175bSopenharmony_ci if ((curve_info = mbedtls_ecp_curve_info_from_grp_id(grp->id)) == NULL) { 969a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 970a8e1175bSopenharmony_ci } 971a8e1175bSopenharmony_ci 972a8e1175bSopenharmony_ci /* 973a8e1175bSopenharmony_ci * We are going to write 3 bytes (see below) 974a8e1175bSopenharmony_ci */ 975a8e1175bSopenharmony_ci *olen = 3; 976a8e1175bSopenharmony_ci if (blen < *olen) { 977a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 978a8e1175bSopenharmony_ci } 979a8e1175bSopenharmony_ci 980a8e1175bSopenharmony_ci /* 981a8e1175bSopenharmony_ci * First byte is curve_type, always named_curve 982a8e1175bSopenharmony_ci */ 983a8e1175bSopenharmony_ci *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; 984a8e1175bSopenharmony_ci 985a8e1175bSopenharmony_ci /* 986a8e1175bSopenharmony_ci * Next two bytes are the namedcurve value 987a8e1175bSopenharmony_ci */ 988a8e1175bSopenharmony_ci MBEDTLS_PUT_UINT16_BE(curve_info->tls_id, buf, 0); 989a8e1175bSopenharmony_ci 990a8e1175bSopenharmony_ci return 0; 991a8e1175bSopenharmony_ci} 992a8e1175bSopenharmony_ci 993a8e1175bSopenharmony_ci/* 994a8e1175bSopenharmony_ci * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. 995a8e1175bSopenharmony_ci * See the documentation of struct mbedtls_ecp_group. 996a8e1175bSopenharmony_ci * 997a8e1175bSopenharmony_ci * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. 998a8e1175bSopenharmony_ci */ 999a8e1175bSopenharmony_cistatic int ecp_modp(mbedtls_mpi *N, const mbedtls_ecp_group *grp) 1000a8e1175bSopenharmony_ci{ 1001a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1002a8e1175bSopenharmony_ci 1003a8e1175bSopenharmony_ci if (grp->modp == NULL) { 1004a8e1175bSopenharmony_ci return mbedtls_mpi_mod_mpi(N, N, &grp->P); 1005a8e1175bSopenharmony_ci } 1006a8e1175bSopenharmony_ci 1007a8e1175bSopenharmony_ci /* N->s < 0 is a much faster test, which fails only if N is 0 */ 1008a8e1175bSopenharmony_ci if ((N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) || 1009a8e1175bSopenharmony_ci mbedtls_mpi_bitlen(N) > 2 * grp->pbits) { 1010a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 1011a8e1175bSopenharmony_ci } 1012a8e1175bSopenharmony_ci 1013a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(grp->modp(N)); 1014a8e1175bSopenharmony_ci 1015a8e1175bSopenharmony_ci /* N->s < 0 is a much faster test, which fails only if N is 0 */ 1016a8e1175bSopenharmony_ci while (N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) { 1017a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &grp->P)); 1018a8e1175bSopenharmony_ci } 1019a8e1175bSopenharmony_ci 1020a8e1175bSopenharmony_ci while (mbedtls_mpi_cmp_mpi(N, &grp->P) >= 0) { 1021a8e1175bSopenharmony_ci /* we known P, N and the result are positive */ 1022a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(N, N, &grp->P)); 1023a8e1175bSopenharmony_ci } 1024a8e1175bSopenharmony_ci 1025a8e1175bSopenharmony_cicleanup: 1026a8e1175bSopenharmony_ci return ret; 1027a8e1175bSopenharmony_ci} 1028a8e1175bSopenharmony_ci 1029a8e1175bSopenharmony_ci/* 1030a8e1175bSopenharmony_ci * Fast mod-p functions expect their argument to be in the 0..p^2 range. 1031a8e1175bSopenharmony_ci * 1032a8e1175bSopenharmony_ci * In order to guarantee that, we need to ensure that operands of 1033a8e1175bSopenharmony_ci * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will 1034a8e1175bSopenharmony_ci * bring the result back to this range. 1035a8e1175bSopenharmony_ci * 1036a8e1175bSopenharmony_ci * The following macros are shortcuts for doing that. 1037a8e1175bSopenharmony_ci */ 1038a8e1175bSopenharmony_ci 1039a8e1175bSopenharmony_ci/* 1040a8e1175bSopenharmony_ci * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi 1041a8e1175bSopenharmony_ci */ 1042a8e1175bSopenharmony_ci#if defined(MBEDTLS_SELF_TEST) 1043a8e1175bSopenharmony_ci#define INC_MUL_COUNT mul_count++; 1044a8e1175bSopenharmony_ci#else 1045a8e1175bSopenharmony_ci#define INC_MUL_COUNT 1046a8e1175bSopenharmony_ci#endif 1047a8e1175bSopenharmony_ci 1048a8e1175bSopenharmony_ci#define MOD_MUL(N) \ 1049a8e1175bSopenharmony_ci do \ 1050a8e1175bSopenharmony_ci { \ 1051a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_modp(&(N), grp)); \ 1052a8e1175bSopenharmony_ci INC_MUL_COUNT \ 1053a8e1175bSopenharmony_ci } while (0) 1054a8e1175bSopenharmony_ci 1055a8e1175bSopenharmony_cistatic inline int mbedtls_mpi_mul_mod(const mbedtls_ecp_group *grp, 1056a8e1175bSopenharmony_ci mbedtls_mpi *X, 1057a8e1175bSopenharmony_ci const mbedtls_mpi *A, 1058a8e1175bSopenharmony_ci const mbedtls_mpi *B) 1059a8e1175bSopenharmony_ci{ 1060a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1061a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(X, A, B)); 1062a8e1175bSopenharmony_ci MOD_MUL(*X); 1063a8e1175bSopenharmony_cicleanup: 1064a8e1175bSopenharmony_ci return ret; 1065a8e1175bSopenharmony_ci} 1066a8e1175bSopenharmony_ci 1067a8e1175bSopenharmony_ci/* 1068a8e1175bSopenharmony_ci * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi 1069a8e1175bSopenharmony_ci * N->s < 0 is a very fast test, which fails only if N is 0 1070a8e1175bSopenharmony_ci */ 1071a8e1175bSopenharmony_ci#define MOD_SUB(N) \ 1072a8e1175bSopenharmony_ci do { \ 1073a8e1175bSopenharmony_ci while ((N)->s < 0 && mbedtls_mpi_cmp_int((N), 0) != 0) \ 1074a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi((N), (N), &grp->P)); \ 1075a8e1175bSopenharmony_ci } while (0) 1076a8e1175bSopenharmony_ci 1077a8e1175bSopenharmony_ciMBEDTLS_MAYBE_UNUSED 1078a8e1175bSopenharmony_cistatic inline int mbedtls_mpi_sub_mod(const mbedtls_ecp_group *grp, 1079a8e1175bSopenharmony_ci mbedtls_mpi *X, 1080a8e1175bSopenharmony_ci const mbedtls_mpi *A, 1081a8e1175bSopenharmony_ci const mbedtls_mpi *B) 1082a8e1175bSopenharmony_ci{ 1083a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1084a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, A, B)); 1085a8e1175bSopenharmony_ci MOD_SUB(X); 1086a8e1175bSopenharmony_cicleanup: 1087a8e1175bSopenharmony_ci return ret; 1088a8e1175bSopenharmony_ci} 1089a8e1175bSopenharmony_ci 1090a8e1175bSopenharmony_ci/* 1091a8e1175bSopenharmony_ci * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. 1092a8e1175bSopenharmony_ci * We known P, N and the result are positive, so sub_abs is correct, and 1093a8e1175bSopenharmony_ci * a bit faster. 1094a8e1175bSopenharmony_ci */ 1095a8e1175bSopenharmony_ci#define MOD_ADD(N) \ 1096a8e1175bSopenharmony_ci while (mbedtls_mpi_cmp_mpi((N), &grp->P) >= 0) \ 1097a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs((N), (N), &grp->P)) 1098a8e1175bSopenharmony_ci 1099a8e1175bSopenharmony_cistatic inline int mbedtls_mpi_add_mod(const mbedtls_ecp_group *grp, 1100a8e1175bSopenharmony_ci mbedtls_mpi *X, 1101a8e1175bSopenharmony_ci const mbedtls_mpi *A, 1102a8e1175bSopenharmony_ci const mbedtls_mpi *B) 1103a8e1175bSopenharmony_ci{ 1104a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1105a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, A, B)); 1106a8e1175bSopenharmony_ci MOD_ADD(X); 1107a8e1175bSopenharmony_cicleanup: 1108a8e1175bSopenharmony_ci return ret; 1109a8e1175bSopenharmony_ci} 1110a8e1175bSopenharmony_ci 1111a8e1175bSopenharmony_ciMBEDTLS_MAYBE_UNUSED 1112a8e1175bSopenharmony_cistatic inline int mbedtls_mpi_mul_int_mod(const mbedtls_ecp_group *grp, 1113a8e1175bSopenharmony_ci mbedtls_mpi *X, 1114a8e1175bSopenharmony_ci const mbedtls_mpi *A, 1115a8e1175bSopenharmony_ci mbedtls_mpi_uint c) 1116a8e1175bSopenharmony_ci{ 1117a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1118a8e1175bSopenharmony_ci 1119a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(X, A, c)); 1120a8e1175bSopenharmony_ci MOD_ADD(X); 1121a8e1175bSopenharmony_cicleanup: 1122a8e1175bSopenharmony_ci return ret; 1123a8e1175bSopenharmony_ci} 1124a8e1175bSopenharmony_ci 1125a8e1175bSopenharmony_ciMBEDTLS_MAYBE_UNUSED 1126a8e1175bSopenharmony_cistatic inline int mbedtls_mpi_sub_int_mod(const mbedtls_ecp_group *grp, 1127a8e1175bSopenharmony_ci mbedtls_mpi *X, 1128a8e1175bSopenharmony_ci const mbedtls_mpi *A, 1129a8e1175bSopenharmony_ci mbedtls_mpi_uint c) 1130a8e1175bSopenharmony_ci{ 1131a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1132a8e1175bSopenharmony_ci 1133a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(X, A, c)); 1134a8e1175bSopenharmony_ci MOD_SUB(X); 1135a8e1175bSopenharmony_cicleanup: 1136a8e1175bSopenharmony_ci return ret; 1137a8e1175bSopenharmony_ci} 1138a8e1175bSopenharmony_ci 1139a8e1175bSopenharmony_ci#define MPI_ECP_SUB_INT(X, A, c) \ 1140a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int_mod(grp, X, A, c)) 1141a8e1175bSopenharmony_ci 1142a8e1175bSopenharmony_ciMBEDTLS_MAYBE_UNUSED 1143a8e1175bSopenharmony_cistatic inline int mbedtls_mpi_shift_l_mod(const mbedtls_ecp_group *grp, 1144a8e1175bSopenharmony_ci mbedtls_mpi *X, 1145a8e1175bSopenharmony_ci size_t count) 1146a8e1175bSopenharmony_ci{ 1147a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1148a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(X, count)); 1149a8e1175bSopenharmony_ci MOD_ADD(X); 1150a8e1175bSopenharmony_cicleanup: 1151a8e1175bSopenharmony_ci return ret; 1152a8e1175bSopenharmony_ci} 1153a8e1175bSopenharmony_ci 1154a8e1175bSopenharmony_ci/* 1155a8e1175bSopenharmony_ci * Macro wrappers around ECP modular arithmetic 1156a8e1175bSopenharmony_ci * 1157a8e1175bSopenharmony_ci * Currently, these wrappers are defined via the bignum module. 1158a8e1175bSopenharmony_ci */ 1159a8e1175bSopenharmony_ci 1160a8e1175bSopenharmony_ci#define MPI_ECP_ADD(X, A, B) \ 1161a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, X, A, B)) 1162a8e1175bSopenharmony_ci 1163a8e1175bSopenharmony_ci#define MPI_ECP_SUB(X, A, B) \ 1164a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, X, A, B)) 1165a8e1175bSopenharmony_ci 1166a8e1175bSopenharmony_ci#define MPI_ECP_MUL(X, A, B) \ 1167a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, B)) 1168a8e1175bSopenharmony_ci 1169a8e1175bSopenharmony_ci#define MPI_ECP_SQR(X, A) \ 1170a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, A)) 1171a8e1175bSopenharmony_ci 1172a8e1175bSopenharmony_ci#define MPI_ECP_MUL_INT(X, A, c) \ 1173a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int_mod(grp, X, A, c)) 1174a8e1175bSopenharmony_ci 1175a8e1175bSopenharmony_ci#define MPI_ECP_INV(dst, src) \ 1176a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod((dst), (src), &grp->P)) 1177a8e1175bSopenharmony_ci 1178a8e1175bSopenharmony_ci#define MPI_ECP_MOV(X, A) \ 1179a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)) 1180a8e1175bSopenharmony_ci 1181a8e1175bSopenharmony_ci#define MPI_ECP_SHIFT_L(X, count) \ 1182a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, X, count)) 1183a8e1175bSopenharmony_ci 1184a8e1175bSopenharmony_ci#define MPI_ECP_LSET(X, c) \ 1185a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, c)) 1186a8e1175bSopenharmony_ci 1187a8e1175bSopenharmony_ci#define MPI_ECP_CMP_INT(X, c) \ 1188a8e1175bSopenharmony_ci mbedtls_mpi_cmp_int(X, c) 1189a8e1175bSopenharmony_ci 1190a8e1175bSopenharmony_ci#define MPI_ECP_CMP(X, Y) \ 1191a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(X, Y) 1192a8e1175bSopenharmony_ci 1193a8e1175bSopenharmony_ci/* Needs f_rng, p_rng to be defined. */ 1194a8e1175bSopenharmony_ci#define MPI_ECP_RAND(X) \ 1195a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_random((X), 2, &grp->P, f_rng, p_rng)) 1196a8e1175bSopenharmony_ci 1197a8e1175bSopenharmony_ci/* Conditional negation 1198a8e1175bSopenharmony_ci * Needs grp and a temporary MPI tmp to be defined. */ 1199a8e1175bSopenharmony_ci#define MPI_ECP_COND_NEG(X, cond) \ 1200a8e1175bSopenharmony_ci do \ 1201a8e1175bSopenharmony_ci { \ 1202a8e1175bSopenharmony_ci unsigned char nonzero = mbedtls_mpi_cmp_int((X), 0) != 0; \ 1203a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&tmp, &grp->P, (X))); \ 1204a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), &tmp, \ 1205a8e1175bSopenharmony_ci nonzero & cond)); \ 1206a8e1175bSopenharmony_ci } while (0) 1207a8e1175bSopenharmony_ci 1208a8e1175bSopenharmony_ci#define MPI_ECP_NEG(X) MPI_ECP_COND_NEG((X), 1) 1209a8e1175bSopenharmony_ci 1210a8e1175bSopenharmony_ci#define MPI_ECP_VALID(X) \ 1211a8e1175bSopenharmony_ci ((X)->p != NULL) 1212a8e1175bSopenharmony_ci 1213a8e1175bSopenharmony_ci#define MPI_ECP_COND_ASSIGN(X, Y, cond) \ 1214a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), (Y), (cond))) 1215a8e1175bSopenharmony_ci 1216a8e1175bSopenharmony_ci#define MPI_ECP_COND_SWAP(X, Y, cond) \ 1217a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap((X), (Y), (cond))) 1218a8e1175bSopenharmony_ci 1219a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 1220a8e1175bSopenharmony_ci 1221a8e1175bSopenharmony_ci/* 1222a8e1175bSopenharmony_ci * Computes the right-hand side of the Short Weierstrass equation 1223a8e1175bSopenharmony_ci * RHS = X^3 + A X + B 1224a8e1175bSopenharmony_ci */ 1225a8e1175bSopenharmony_cistatic int ecp_sw_rhs(const mbedtls_ecp_group *grp, 1226a8e1175bSopenharmony_ci mbedtls_mpi *rhs, 1227a8e1175bSopenharmony_ci const mbedtls_mpi *X) 1228a8e1175bSopenharmony_ci{ 1229a8e1175bSopenharmony_ci int ret; 1230a8e1175bSopenharmony_ci 1231a8e1175bSopenharmony_ci /* Compute X^3 + A X + B as X (X^2 + A) + B */ 1232a8e1175bSopenharmony_ci MPI_ECP_SQR(rhs, X); 1233a8e1175bSopenharmony_ci 1234a8e1175bSopenharmony_ci /* Special case for A = -3 */ 1235a8e1175bSopenharmony_ci if (mbedtls_ecp_group_a_is_minus_3(grp)) { 1236a8e1175bSopenharmony_ci MPI_ECP_SUB_INT(rhs, rhs, 3); 1237a8e1175bSopenharmony_ci } else { 1238a8e1175bSopenharmony_ci MPI_ECP_ADD(rhs, rhs, &grp->A); 1239a8e1175bSopenharmony_ci } 1240a8e1175bSopenharmony_ci 1241a8e1175bSopenharmony_ci MPI_ECP_MUL(rhs, rhs, X); 1242a8e1175bSopenharmony_ci MPI_ECP_ADD(rhs, rhs, &grp->B); 1243a8e1175bSopenharmony_ci 1244a8e1175bSopenharmony_cicleanup: 1245a8e1175bSopenharmony_ci return ret; 1246a8e1175bSopenharmony_ci} 1247a8e1175bSopenharmony_ci 1248a8e1175bSopenharmony_ci/* 1249a8e1175bSopenharmony_ci * Derive Y from X and a parity bit 1250a8e1175bSopenharmony_ci */ 1251a8e1175bSopenharmony_cistatic int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, 1252a8e1175bSopenharmony_ci const mbedtls_mpi *X, 1253a8e1175bSopenharmony_ci mbedtls_mpi *Y, 1254a8e1175bSopenharmony_ci int parity_bit) 1255a8e1175bSopenharmony_ci{ 1256a8e1175bSopenharmony_ci /* w = y^2 = x^3 + ax + b 1257a8e1175bSopenharmony_ci * y = sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) 1258a8e1175bSopenharmony_ci * 1259a8e1175bSopenharmony_ci * Note: this method for extracting square root does not validate that w 1260a8e1175bSopenharmony_ci * was indeed a square so this function will return garbage in Y if X 1261a8e1175bSopenharmony_ci * does not correspond to a point on the curve. 1262a8e1175bSopenharmony_ci */ 1263a8e1175bSopenharmony_ci 1264a8e1175bSopenharmony_ci /* Check prerequisite p = 3 mod 4 */ 1265a8e1175bSopenharmony_ci if (mbedtls_mpi_get_bit(&grp->P, 0) != 1 || 1266a8e1175bSopenharmony_ci mbedtls_mpi_get_bit(&grp->P, 1) != 1) { 1267a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 1268a8e1175bSopenharmony_ci } 1269a8e1175bSopenharmony_ci 1270a8e1175bSopenharmony_ci int ret; 1271a8e1175bSopenharmony_ci mbedtls_mpi exp; 1272a8e1175bSopenharmony_ci mbedtls_mpi_init(&exp); 1273a8e1175bSopenharmony_ci 1274a8e1175bSopenharmony_ci /* use Y to store intermediate result, actually w above */ 1275a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, Y, X)); 1276a8e1175bSopenharmony_ci 1277a8e1175bSopenharmony_ci /* w = y^2 */ /* Y contains y^2 intermediate result */ 1278a8e1175bSopenharmony_ci /* exp = ((p+1)/4) */ 1279a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&exp, &grp->P, 1)); 1280a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 2)); 1281a8e1175bSopenharmony_ci /* sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) */ 1282a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(Y, Y /*y^2*/, &exp, &grp->P, NULL)); 1283a8e1175bSopenharmony_ci 1284a8e1175bSopenharmony_ci /* check parity bit match or else invert Y */ 1285a8e1175bSopenharmony_ci /* This quick inversion implementation is valid because Y != 0 for all 1286a8e1175bSopenharmony_ci * Short Weierstrass curves supported by mbedtls, as each supported curve 1287a8e1175bSopenharmony_ci * has an order that is a large prime, so each supported curve does not 1288a8e1175bSopenharmony_ci * have any point of order 2, and a point with Y == 0 would be of order 2 */ 1289a8e1175bSopenharmony_ci if (mbedtls_mpi_get_bit(Y, 0) != parity_bit) { 1290a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(Y, &grp->P, Y)); 1291a8e1175bSopenharmony_ci } 1292a8e1175bSopenharmony_ci 1293a8e1175bSopenharmony_cicleanup: 1294a8e1175bSopenharmony_ci 1295a8e1175bSopenharmony_ci mbedtls_mpi_free(&exp); 1296a8e1175bSopenharmony_ci return ret; 1297a8e1175bSopenharmony_ci} 1298a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 1299a8e1175bSopenharmony_ci 1300a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 1301a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 1302a8e1175bSopenharmony_ci/* 1303a8e1175bSopenharmony_ci * For curves in short Weierstrass form, we do all the internal operations in 1304a8e1175bSopenharmony_ci * Jacobian coordinates. 1305a8e1175bSopenharmony_ci * 1306a8e1175bSopenharmony_ci * For multiplication, we'll use a comb method with countermeasures against 1307a8e1175bSopenharmony_ci * SPA, hence timing attacks. 1308a8e1175bSopenharmony_ci */ 1309a8e1175bSopenharmony_ci 1310a8e1175bSopenharmony_ci/* 1311a8e1175bSopenharmony_ci * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) 1312a8e1175bSopenharmony_ci * Cost: 1N := 1I + 3M + 1S 1313a8e1175bSopenharmony_ci */ 1314a8e1175bSopenharmony_cistatic int ecp_normalize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt) 1315a8e1175bSopenharmony_ci{ 1316a8e1175bSopenharmony_ci if (MPI_ECP_CMP_INT(&pt->Z, 0) == 0) { 1317a8e1175bSopenharmony_ci return 0; 1318a8e1175bSopenharmony_ci } 1319a8e1175bSopenharmony_ci 1320a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) 1321a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 1322a8e1175bSopenharmony_ci return mbedtls_internal_ecp_normalize_jac(grp, pt); 1323a8e1175bSopenharmony_ci } 1324a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */ 1325a8e1175bSopenharmony_ci 1326a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) 1327a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 1328a8e1175bSopenharmony_ci#else 1329a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1330a8e1175bSopenharmony_ci mbedtls_mpi T; 1331a8e1175bSopenharmony_ci mbedtls_mpi_init(&T); 1332a8e1175bSopenharmony_ci 1333a8e1175bSopenharmony_ci MPI_ECP_INV(&T, &pt->Z); /* T <- 1 / Z */ 1334a8e1175bSopenharmony_ci MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y' <- Y*T = Y / Z */ 1335a8e1175bSopenharmony_ci MPI_ECP_SQR(&T, &T); /* T <- T^2 = 1 / Z^2 */ 1336a8e1175bSopenharmony_ci MPI_ECP_MUL(&pt->X, &pt->X, &T); /* X <- X * T = X / Z^2 */ 1337a8e1175bSopenharmony_ci MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y'' <- Y' * T = Y / Z^3 */ 1338a8e1175bSopenharmony_ci 1339a8e1175bSopenharmony_ci MPI_ECP_LSET(&pt->Z, 1); 1340a8e1175bSopenharmony_ci 1341a8e1175bSopenharmony_cicleanup: 1342a8e1175bSopenharmony_ci 1343a8e1175bSopenharmony_ci mbedtls_mpi_free(&T); 1344a8e1175bSopenharmony_ci 1345a8e1175bSopenharmony_ci return ret; 1346a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) */ 1347a8e1175bSopenharmony_ci} 1348a8e1175bSopenharmony_ci 1349a8e1175bSopenharmony_ci/* 1350a8e1175bSopenharmony_ci * Normalize jacobian coordinates of an array of (pointers to) points, 1351a8e1175bSopenharmony_ci * using Montgomery's trick to perform only one inversion mod P. 1352a8e1175bSopenharmony_ci * (See for example Cohen's "A Course in Computational Algebraic Number 1353a8e1175bSopenharmony_ci * Theory", Algorithm 10.3.4.) 1354a8e1175bSopenharmony_ci * 1355a8e1175bSopenharmony_ci * Warning: fails (returning an error) if one of the points is zero! 1356a8e1175bSopenharmony_ci * This should never happen, see choice of w in ecp_mul_comb(). 1357a8e1175bSopenharmony_ci * 1358a8e1175bSopenharmony_ci * Cost: 1N(t) := 1I + (6t - 3)M + 1S 1359a8e1175bSopenharmony_ci */ 1360a8e1175bSopenharmony_cistatic int ecp_normalize_jac_many(const mbedtls_ecp_group *grp, 1361a8e1175bSopenharmony_ci mbedtls_ecp_point *T[], size_t T_size) 1362a8e1175bSopenharmony_ci{ 1363a8e1175bSopenharmony_ci if (T_size < 2) { 1364a8e1175bSopenharmony_ci return ecp_normalize_jac(grp, *T); 1365a8e1175bSopenharmony_ci } 1366a8e1175bSopenharmony_ci 1367a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) 1368a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 1369a8e1175bSopenharmony_ci return mbedtls_internal_ecp_normalize_jac_many(grp, T, T_size); 1370a8e1175bSopenharmony_ci } 1371a8e1175bSopenharmony_ci#endif 1372a8e1175bSopenharmony_ci 1373a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) 1374a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 1375a8e1175bSopenharmony_ci#else 1376a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1377a8e1175bSopenharmony_ci size_t i; 1378a8e1175bSopenharmony_ci mbedtls_mpi *c, t; 1379a8e1175bSopenharmony_ci 1380a8e1175bSopenharmony_ci if ((c = mbedtls_calloc(T_size, sizeof(mbedtls_mpi))) == NULL) { 1381a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_ALLOC_FAILED; 1382a8e1175bSopenharmony_ci } 1383a8e1175bSopenharmony_ci 1384a8e1175bSopenharmony_ci mbedtls_mpi_init(&t); 1385a8e1175bSopenharmony_ci 1386a8e1175bSopenharmony_ci mpi_init_many(c, T_size); 1387a8e1175bSopenharmony_ci /* 1388a8e1175bSopenharmony_ci * c[i] = Z_0 * ... * Z_i, i = 0,..,n := T_size-1 1389a8e1175bSopenharmony_ci */ 1390a8e1175bSopenharmony_ci MPI_ECP_MOV(&c[0], &T[0]->Z); 1391a8e1175bSopenharmony_ci for (i = 1; i < T_size; i++) { 1392a8e1175bSopenharmony_ci MPI_ECP_MUL(&c[i], &c[i-1], &T[i]->Z); 1393a8e1175bSopenharmony_ci } 1394a8e1175bSopenharmony_ci 1395a8e1175bSopenharmony_ci /* 1396a8e1175bSopenharmony_ci * c[n] = 1 / (Z_0 * ... * Z_n) mod P 1397a8e1175bSopenharmony_ci */ 1398a8e1175bSopenharmony_ci MPI_ECP_INV(&c[T_size-1], &c[T_size-1]); 1399a8e1175bSopenharmony_ci 1400a8e1175bSopenharmony_ci for (i = T_size - 1;; i--) { 1401a8e1175bSopenharmony_ci /* At the start of iteration i (note that i decrements), we have 1402a8e1175bSopenharmony_ci * - c[j] = Z_0 * .... * Z_j for j < i, 1403a8e1175bSopenharmony_ci * - c[j] = 1 / (Z_0 * .... * Z_j) for j == i, 1404a8e1175bSopenharmony_ci * 1405a8e1175bSopenharmony_ci * This is maintained via 1406a8e1175bSopenharmony_ci * - c[i-1] <- c[i] * Z_i 1407a8e1175bSopenharmony_ci * 1408a8e1175bSopenharmony_ci * We also derive 1/Z_i = c[i] * c[i-1] for i>0 and use that 1409a8e1175bSopenharmony_ci * to do the actual normalization. For i==0, we already have 1410a8e1175bSopenharmony_ci * c[0] = 1 / Z_0. 1411a8e1175bSopenharmony_ci */ 1412a8e1175bSopenharmony_ci 1413a8e1175bSopenharmony_ci if (i > 0) { 1414a8e1175bSopenharmony_ci /* Compute 1/Z_i and establish invariant for the next iteration. */ 1415a8e1175bSopenharmony_ci MPI_ECP_MUL(&t, &c[i], &c[i-1]); 1416a8e1175bSopenharmony_ci MPI_ECP_MUL(&c[i-1], &c[i], &T[i]->Z); 1417a8e1175bSopenharmony_ci } else { 1418a8e1175bSopenharmony_ci MPI_ECP_MOV(&t, &c[0]); 1419a8e1175bSopenharmony_ci } 1420a8e1175bSopenharmony_ci 1421a8e1175bSopenharmony_ci /* Now t holds 1 / Z_i; normalize as in ecp_normalize_jac() */ 1422a8e1175bSopenharmony_ci MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t); 1423a8e1175bSopenharmony_ci MPI_ECP_SQR(&t, &t); 1424a8e1175bSopenharmony_ci MPI_ECP_MUL(&T[i]->X, &T[i]->X, &t); 1425a8e1175bSopenharmony_ci MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t); 1426a8e1175bSopenharmony_ci 1427a8e1175bSopenharmony_ci /* 1428a8e1175bSopenharmony_ci * Post-precessing: reclaim some memory by shrinking coordinates 1429a8e1175bSopenharmony_ci * - not storing Z (always 1) 1430a8e1175bSopenharmony_ci * - shrinking other coordinates, but still keeping the same number of 1431a8e1175bSopenharmony_ci * limbs as P, as otherwise it will too likely be regrown too fast. 1432a8e1175bSopenharmony_ci */ 1433a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->X, grp->P.n)); 1434a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->Y, grp->P.n)); 1435a8e1175bSopenharmony_ci 1436a8e1175bSopenharmony_ci MPI_ECP_LSET(&T[i]->Z, 1); 1437a8e1175bSopenharmony_ci 1438a8e1175bSopenharmony_ci if (i == 0) { 1439a8e1175bSopenharmony_ci break; 1440a8e1175bSopenharmony_ci } 1441a8e1175bSopenharmony_ci } 1442a8e1175bSopenharmony_ci 1443a8e1175bSopenharmony_cicleanup: 1444a8e1175bSopenharmony_ci 1445a8e1175bSopenharmony_ci mbedtls_mpi_free(&t); 1446a8e1175bSopenharmony_ci mpi_free_many(c, T_size); 1447a8e1175bSopenharmony_ci mbedtls_free(c); 1448a8e1175bSopenharmony_ci 1449a8e1175bSopenharmony_ci return ret; 1450a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) */ 1451a8e1175bSopenharmony_ci} 1452a8e1175bSopenharmony_ci 1453a8e1175bSopenharmony_ci/* 1454a8e1175bSopenharmony_ci * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. 1455a8e1175bSopenharmony_ci * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid 1456a8e1175bSopenharmony_ci */ 1457a8e1175bSopenharmony_cistatic int ecp_safe_invert_jac(const mbedtls_ecp_group *grp, 1458a8e1175bSopenharmony_ci mbedtls_ecp_point *Q, 1459a8e1175bSopenharmony_ci unsigned char inv) 1460a8e1175bSopenharmony_ci{ 1461a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1462a8e1175bSopenharmony_ci mbedtls_mpi tmp; 1463a8e1175bSopenharmony_ci mbedtls_mpi_init(&tmp); 1464a8e1175bSopenharmony_ci 1465a8e1175bSopenharmony_ci MPI_ECP_COND_NEG(&Q->Y, inv); 1466a8e1175bSopenharmony_ci 1467a8e1175bSopenharmony_cicleanup: 1468a8e1175bSopenharmony_ci mbedtls_mpi_free(&tmp); 1469a8e1175bSopenharmony_ci return ret; 1470a8e1175bSopenharmony_ci} 1471a8e1175bSopenharmony_ci 1472a8e1175bSopenharmony_ci/* 1473a8e1175bSopenharmony_ci * Point doubling R = 2 P, Jacobian coordinates 1474a8e1175bSopenharmony_ci * 1475a8e1175bSopenharmony_ci * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . 1476a8e1175bSopenharmony_ci * 1477a8e1175bSopenharmony_ci * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR 1478a8e1175bSopenharmony_ci * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. 1479a8e1175bSopenharmony_ci * 1480a8e1175bSopenharmony_ci * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. 1481a8e1175bSopenharmony_ci * 1482a8e1175bSopenharmony_ci * Cost: 1D := 3M + 4S (A == 0) 1483a8e1175bSopenharmony_ci * 4M + 4S (A == -3) 1484a8e1175bSopenharmony_ci * 3M + 6S + 1a otherwise 1485a8e1175bSopenharmony_ci */ 1486a8e1175bSopenharmony_cistatic int ecp_double_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 1487a8e1175bSopenharmony_ci const mbedtls_ecp_point *P, 1488a8e1175bSopenharmony_ci mbedtls_mpi tmp[4]) 1489a8e1175bSopenharmony_ci{ 1490a8e1175bSopenharmony_ci#if defined(MBEDTLS_SELF_TEST) 1491a8e1175bSopenharmony_ci dbl_count++; 1492a8e1175bSopenharmony_ci#endif 1493a8e1175bSopenharmony_ci 1494a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) 1495a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 1496a8e1175bSopenharmony_ci return mbedtls_internal_ecp_double_jac(grp, R, P); 1497a8e1175bSopenharmony_ci } 1498a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */ 1499a8e1175bSopenharmony_ci 1500a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) 1501a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 1502a8e1175bSopenharmony_ci#else 1503a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1504a8e1175bSopenharmony_ci 1505a8e1175bSopenharmony_ci /* Special case for A = -3 */ 1506a8e1175bSopenharmony_ci if (mbedtls_ecp_group_a_is_minus_3(grp)) { 1507a8e1175bSopenharmony_ci /* tmp[0] <- M = 3(X + Z^2)(X - Z^2) */ 1508a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[1], &P->Z); 1509a8e1175bSopenharmony_ci MPI_ECP_ADD(&tmp[2], &P->X, &tmp[1]); 1510a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[3], &P->X, &tmp[1]); 1511a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[1], &tmp[2], &tmp[3]); 1512a8e1175bSopenharmony_ci MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3); 1513a8e1175bSopenharmony_ci } else { 1514a8e1175bSopenharmony_ci /* tmp[0] <- M = 3.X^2 + A.Z^4 */ 1515a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[1], &P->X); 1516a8e1175bSopenharmony_ci MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3); 1517a8e1175bSopenharmony_ci 1518a8e1175bSopenharmony_ci /* Optimize away for "koblitz" curves with A = 0 */ 1519a8e1175bSopenharmony_ci if (MPI_ECP_CMP_INT(&grp->A, 0) != 0) { 1520a8e1175bSopenharmony_ci /* M += A.Z^4 */ 1521a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[1], &P->Z); 1522a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[2], &tmp[1]); 1523a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[1], &tmp[2], &grp->A); 1524a8e1175bSopenharmony_ci MPI_ECP_ADD(&tmp[0], &tmp[0], &tmp[1]); 1525a8e1175bSopenharmony_ci } 1526a8e1175bSopenharmony_ci } 1527a8e1175bSopenharmony_ci 1528a8e1175bSopenharmony_ci /* tmp[1] <- S = 4.X.Y^2 */ 1529a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[2], &P->Y); 1530a8e1175bSopenharmony_ci MPI_ECP_SHIFT_L(&tmp[2], 1); 1531a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[1], &P->X, &tmp[2]); 1532a8e1175bSopenharmony_ci MPI_ECP_SHIFT_L(&tmp[1], 1); 1533a8e1175bSopenharmony_ci 1534a8e1175bSopenharmony_ci /* tmp[3] <- U = 8.Y^4 */ 1535a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[3], &tmp[2]); 1536a8e1175bSopenharmony_ci MPI_ECP_SHIFT_L(&tmp[3], 1); 1537a8e1175bSopenharmony_ci 1538a8e1175bSopenharmony_ci /* tmp[2] <- T = M^2 - 2.S */ 1539a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[2], &tmp[0]); 1540a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]); 1541a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]); 1542a8e1175bSopenharmony_ci 1543a8e1175bSopenharmony_ci /* tmp[1] <- S = M(S - T) - U */ 1544a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[2]); 1545a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[1], &tmp[1], &tmp[0]); 1546a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[3]); 1547a8e1175bSopenharmony_ci 1548a8e1175bSopenharmony_ci /* tmp[3] <- U = 2.Y.Z */ 1549a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[3], &P->Y, &P->Z); 1550a8e1175bSopenharmony_ci MPI_ECP_SHIFT_L(&tmp[3], 1); 1551a8e1175bSopenharmony_ci 1552a8e1175bSopenharmony_ci /* Store results */ 1553a8e1175bSopenharmony_ci MPI_ECP_MOV(&R->X, &tmp[2]); 1554a8e1175bSopenharmony_ci MPI_ECP_MOV(&R->Y, &tmp[1]); 1555a8e1175bSopenharmony_ci MPI_ECP_MOV(&R->Z, &tmp[3]); 1556a8e1175bSopenharmony_ci 1557a8e1175bSopenharmony_cicleanup: 1558a8e1175bSopenharmony_ci 1559a8e1175bSopenharmony_ci return ret; 1560a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) */ 1561a8e1175bSopenharmony_ci} 1562a8e1175bSopenharmony_ci 1563a8e1175bSopenharmony_ci/* 1564a8e1175bSopenharmony_ci * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) 1565a8e1175bSopenharmony_ci * 1566a8e1175bSopenharmony_ci * The coordinates of Q must be normalized (= affine), 1567a8e1175bSopenharmony_ci * but those of P don't need to. R is not normalized. 1568a8e1175bSopenharmony_ci * 1569a8e1175bSopenharmony_ci * P,Q,R may alias, but only at the level of EC points: they must be either 1570a8e1175bSopenharmony_ci * equal as pointers, or disjoint (including the coordinate data buffers). 1571a8e1175bSopenharmony_ci * Fine-grained aliasing at the level of coordinates is not supported. 1572a8e1175bSopenharmony_ci * 1573a8e1175bSopenharmony_ci * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. 1574a8e1175bSopenharmony_ci * None of these cases can happen as intermediate step in ecp_mul_comb(): 1575a8e1175bSopenharmony_ci * - at each step, P, Q and R are multiples of the base point, the factor 1576a8e1175bSopenharmony_ci * being less than its order, so none of them is zero; 1577a8e1175bSopenharmony_ci * - Q is an odd multiple of the base point, P an even multiple, 1578a8e1175bSopenharmony_ci * due to the choice of precomputed points in the modified comb method. 1579a8e1175bSopenharmony_ci * So branches for these cases do not leak secret information. 1580a8e1175bSopenharmony_ci * 1581a8e1175bSopenharmony_ci * Cost: 1A := 8M + 3S 1582a8e1175bSopenharmony_ci */ 1583a8e1175bSopenharmony_cistatic int ecp_add_mixed(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 1584a8e1175bSopenharmony_ci const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, 1585a8e1175bSopenharmony_ci mbedtls_mpi tmp[4]) 1586a8e1175bSopenharmony_ci{ 1587a8e1175bSopenharmony_ci#if defined(MBEDTLS_SELF_TEST) 1588a8e1175bSopenharmony_ci add_count++; 1589a8e1175bSopenharmony_ci#endif 1590a8e1175bSopenharmony_ci 1591a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_ADD_MIXED_ALT) 1592a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 1593a8e1175bSopenharmony_ci return mbedtls_internal_ecp_add_mixed(grp, R, P, Q); 1594a8e1175bSopenharmony_ci } 1595a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_ADD_MIXED_ALT */ 1596a8e1175bSopenharmony_ci 1597a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_ADD_MIXED_ALT) 1598a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 1599a8e1175bSopenharmony_ci#else 1600a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1601a8e1175bSopenharmony_ci 1602a8e1175bSopenharmony_ci /* NOTE: Aliasing between input and output is allowed, so one has to make 1603a8e1175bSopenharmony_ci * sure that at the point X,Y,Z are written, {P,Q}->{X,Y,Z} are no 1604a8e1175bSopenharmony_ci * longer read from. */ 1605a8e1175bSopenharmony_ci mbedtls_mpi * const X = &R->X; 1606a8e1175bSopenharmony_ci mbedtls_mpi * const Y = &R->Y; 1607a8e1175bSopenharmony_ci mbedtls_mpi * const Z = &R->Z; 1608a8e1175bSopenharmony_ci 1609a8e1175bSopenharmony_ci if (!MPI_ECP_VALID(&Q->Z)) { 1610a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 1611a8e1175bSopenharmony_ci } 1612a8e1175bSopenharmony_ci 1613a8e1175bSopenharmony_ci /* 1614a8e1175bSopenharmony_ci * Trivial cases: P == 0 or Q == 0 (case 1) 1615a8e1175bSopenharmony_ci */ 1616a8e1175bSopenharmony_ci if (MPI_ECP_CMP_INT(&P->Z, 0) == 0) { 1617a8e1175bSopenharmony_ci return mbedtls_ecp_copy(R, Q); 1618a8e1175bSopenharmony_ci } 1619a8e1175bSopenharmony_ci 1620a8e1175bSopenharmony_ci if (MPI_ECP_CMP_INT(&Q->Z, 0) == 0) { 1621a8e1175bSopenharmony_ci return mbedtls_ecp_copy(R, P); 1622a8e1175bSopenharmony_ci } 1623a8e1175bSopenharmony_ci 1624a8e1175bSopenharmony_ci /* 1625a8e1175bSopenharmony_ci * Make sure Q coordinates are normalized 1626a8e1175bSopenharmony_ci */ 1627a8e1175bSopenharmony_ci if (MPI_ECP_CMP_INT(&Q->Z, 1) != 0) { 1628a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 1629a8e1175bSopenharmony_ci } 1630a8e1175bSopenharmony_ci 1631a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[0], &P->Z); 1632a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[1], &tmp[0], &P->Z); 1633a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[0], &tmp[0], &Q->X); 1634a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[1], &tmp[1], &Q->Y); 1635a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[0], &tmp[0], &P->X); 1636a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[1], &tmp[1], &P->Y); 1637a8e1175bSopenharmony_ci 1638a8e1175bSopenharmony_ci /* Special cases (2) and (3) */ 1639a8e1175bSopenharmony_ci if (MPI_ECP_CMP_INT(&tmp[0], 0) == 0) { 1640a8e1175bSopenharmony_ci if (MPI_ECP_CMP_INT(&tmp[1], 0) == 0) { 1641a8e1175bSopenharmony_ci ret = ecp_double_jac(grp, R, P, tmp); 1642a8e1175bSopenharmony_ci goto cleanup; 1643a8e1175bSopenharmony_ci } else { 1644a8e1175bSopenharmony_ci ret = mbedtls_ecp_set_zero(R); 1645a8e1175bSopenharmony_ci goto cleanup; 1646a8e1175bSopenharmony_ci } 1647a8e1175bSopenharmony_ci } 1648a8e1175bSopenharmony_ci 1649a8e1175bSopenharmony_ci /* {P,Q}->Z no longer used, so OK to write to Z even if there's aliasing. */ 1650a8e1175bSopenharmony_ci MPI_ECP_MUL(Z, &P->Z, &tmp[0]); 1651a8e1175bSopenharmony_ci MPI_ECP_SQR(&tmp[2], &tmp[0]); 1652a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[3], &tmp[2], &tmp[0]); 1653a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[2], &tmp[2], &P->X); 1654a8e1175bSopenharmony_ci 1655a8e1175bSopenharmony_ci MPI_ECP_MOV(&tmp[0], &tmp[2]); 1656a8e1175bSopenharmony_ci MPI_ECP_SHIFT_L(&tmp[0], 1); 1657a8e1175bSopenharmony_ci 1658a8e1175bSopenharmony_ci /* {P,Q}->X no longer used, so OK to write to X even if there's aliasing. */ 1659a8e1175bSopenharmony_ci MPI_ECP_SQR(X, &tmp[1]); 1660a8e1175bSopenharmony_ci MPI_ECP_SUB(X, X, &tmp[0]); 1661a8e1175bSopenharmony_ci MPI_ECP_SUB(X, X, &tmp[3]); 1662a8e1175bSopenharmony_ci MPI_ECP_SUB(&tmp[2], &tmp[2], X); 1663a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[2], &tmp[2], &tmp[1]); 1664a8e1175bSopenharmony_ci MPI_ECP_MUL(&tmp[3], &tmp[3], &P->Y); 1665a8e1175bSopenharmony_ci /* {P,Q}->Y no longer used, so OK to write to Y even if there's aliasing. */ 1666a8e1175bSopenharmony_ci MPI_ECP_SUB(Y, &tmp[2], &tmp[3]); 1667a8e1175bSopenharmony_ci 1668a8e1175bSopenharmony_cicleanup: 1669a8e1175bSopenharmony_ci 1670a8e1175bSopenharmony_ci return ret; 1671a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_ADD_MIXED_ALT) */ 1672a8e1175bSopenharmony_ci} 1673a8e1175bSopenharmony_ci 1674a8e1175bSopenharmony_ci/* 1675a8e1175bSopenharmony_ci * Randomize jacobian coordinates: 1676a8e1175bSopenharmony_ci * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l 1677a8e1175bSopenharmony_ci * This is sort of the reverse operation of ecp_normalize_jac(). 1678a8e1175bSopenharmony_ci * 1679a8e1175bSopenharmony_ci * This countermeasure was first suggested in [2]. 1680a8e1175bSopenharmony_ci */ 1681a8e1175bSopenharmony_cistatic int ecp_randomize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, 1682a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 1683a8e1175bSopenharmony_ci{ 1684a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) 1685a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 1686a8e1175bSopenharmony_ci return mbedtls_internal_ecp_randomize_jac(grp, pt, f_rng, p_rng); 1687a8e1175bSopenharmony_ci } 1688a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */ 1689a8e1175bSopenharmony_ci 1690a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) 1691a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 1692a8e1175bSopenharmony_ci#else 1693a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1694a8e1175bSopenharmony_ci mbedtls_mpi l; 1695a8e1175bSopenharmony_ci 1696a8e1175bSopenharmony_ci mbedtls_mpi_init(&l); 1697a8e1175bSopenharmony_ci 1698a8e1175bSopenharmony_ci /* Generate l such that 1 < l < p */ 1699a8e1175bSopenharmony_ci MPI_ECP_RAND(&l); 1700a8e1175bSopenharmony_ci 1701a8e1175bSopenharmony_ci /* Z' = l * Z */ 1702a8e1175bSopenharmony_ci MPI_ECP_MUL(&pt->Z, &pt->Z, &l); 1703a8e1175bSopenharmony_ci 1704a8e1175bSopenharmony_ci /* Y' = l * Y */ 1705a8e1175bSopenharmony_ci MPI_ECP_MUL(&pt->Y, &pt->Y, &l); 1706a8e1175bSopenharmony_ci 1707a8e1175bSopenharmony_ci /* X' = l^2 * X */ 1708a8e1175bSopenharmony_ci MPI_ECP_SQR(&l, &l); 1709a8e1175bSopenharmony_ci MPI_ECP_MUL(&pt->X, &pt->X, &l); 1710a8e1175bSopenharmony_ci 1711a8e1175bSopenharmony_ci /* Y'' = l^2 * Y' = l^3 * Y */ 1712a8e1175bSopenharmony_ci MPI_ECP_MUL(&pt->Y, &pt->Y, &l); 1713a8e1175bSopenharmony_ci 1714a8e1175bSopenharmony_cicleanup: 1715a8e1175bSopenharmony_ci mbedtls_mpi_free(&l); 1716a8e1175bSopenharmony_ci 1717a8e1175bSopenharmony_ci if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { 1718a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 1719a8e1175bSopenharmony_ci } 1720a8e1175bSopenharmony_ci return ret; 1721a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) */ 1722a8e1175bSopenharmony_ci} 1723a8e1175bSopenharmony_ci 1724a8e1175bSopenharmony_ci/* 1725a8e1175bSopenharmony_ci * Check and define parameters used by the comb method (see below for details) 1726a8e1175bSopenharmony_ci */ 1727a8e1175bSopenharmony_ci#if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 1728a8e1175bSopenharmony_ci#error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" 1729a8e1175bSopenharmony_ci#endif 1730a8e1175bSopenharmony_ci 1731a8e1175bSopenharmony_ci/* d = ceil( n / w ) */ 1732a8e1175bSopenharmony_ci#define COMB_MAX_D (MBEDTLS_ECP_MAX_BITS + 1) / 2 1733a8e1175bSopenharmony_ci 1734a8e1175bSopenharmony_ci/* number of precomputed points */ 1735a8e1175bSopenharmony_ci#define COMB_MAX_PRE (1 << (MBEDTLS_ECP_WINDOW_SIZE - 1)) 1736a8e1175bSopenharmony_ci 1737a8e1175bSopenharmony_ci/* 1738a8e1175bSopenharmony_ci * Compute the representation of m that will be used with our comb method. 1739a8e1175bSopenharmony_ci * 1740a8e1175bSopenharmony_ci * The basic comb method is described in GECC 3.44 for example. We use a 1741a8e1175bSopenharmony_ci * modified version that provides resistance to SPA by avoiding zero 1742a8e1175bSopenharmony_ci * digits in the representation as in [3]. We modify the method further by 1743a8e1175bSopenharmony_ci * requiring that all K_i be odd, which has the small cost that our 1744a8e1175bSopenharmony_ci * representation uses one more K_i, due to carries, but saves on the size of 1745a8e1175bSopenharmony_ci * the precomputed table. 1746a8e1175bSopenharmony_ci * 1747a8e1175bSopenharmony_ci * Summary of the comb method and its modifications: 1748a8e1175bSopenharmony_ci * 1749a8e1175bSopenharmony_ci * - The goal is to compute m*P for some w*d-bit integer m. 1750a8e1175bSopenharmony_ci * 1751a8e1175bSopenharmony_ci * - The basic comb method splits m into the w-bit integers 1752a8e1175bSopenharmony_ci * x[0] .. x[d-1] where x[i] consists of the bits in m whose 1753a8e1175bSopenharmony_ci * index has residue i modulo d, and computes m * P as 1754a8e1175bSopenharmony_ci * S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where 1755a8e1175bSopenharmony_ci * S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P. 1756a8e1175bSopenharmony_ci * 1757a8e1175bSopenharmony_ci * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by 1758a8e1175bSopenharmony_ci * .. + 2^{i-1} S[x[i-1]] - 2^i S[x[i]] + 2^{i+1} S[x[i]] + 2^{i+2} S[x[i+2]] .., 1759a8e1175bSopenharmony_ci * thereby successively converting it into a form where all summands 1760a8e1175bSopenharmony_ci * are nonzero, at the cost of negative summands. This is the basic idea of [3]. 1761a8e1175bSopenharmony_ci * 1762a8e1175bSopenharmony_ci * - More generally, even if x[i+1] != 0, we can first transform the sum as 1763a8e1175bSopenharmony_ci * .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] .., 1764a8e1175bSopenharmony_ci * and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]]. 1765a8e1175bSopenharmony_ci * Performing and iterating this procedure for those x[i] that are even 1766a8e1175bSopenharmony_ci * (keeping track of carry), we can transform the original sum into one of the form 1767a8e1175bSopenharmony_ci * S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]] 1768a8e1175bSopenharmony_ci * with all x'[i] odd. It is therefore only necessary to know S at odd indices, 1769a8e1175bSopenharmony_ci * which is why we are only computing half of it in the first place in 1770a8e1175bSopenharmony_ci * ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb. 1771a8e1175bSopenharmony_ci * 1772a8e1175bSopenharmony_ci * - For the sake of compactness, only the seven low-order bits of x[i] 1773a8e1175bSopenharmony_ci * are used to represent its absolute value (K_i in the paper), and the msb 1774a8e1175bSopenharmony_ci * of x[i] encodes the sign (s_i in the paper): it is set if and only if 1775a8e1175bSopenharmony_ci * if s_i == -1; 1776a8e1175bSopenharmony_ci * 1777a8e1175bSopenharmony_ci * Calling conventions: 1778a8e1175bSopenharmony_ci * - x is an array of size d + 1 1779a8e1175bSopenharmony_ci * - w is the size, ie number of teeth, of the comb, and must be between 1780a8e1175bSopenharmony_ci * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) 1781a8e1175bSopenharmony_ci * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d 1782a8e1175bSopenharmony_ci * (the result will be incorrect if these assumptions are not satisfied) 1783a8e1175bSopenharmony_ci */ 1784a8e1175bSopenharmony_cistatic void ecp_comb_recode_core(unsigned char x[], size_t d, 1785a8e1175bSopenharmony_ci unsigned char w, const mbedtls_mpi *m) 1786a8e1175bSopenharmony_ci{ 1787a8e1175bSopenharmony_ci size_t i, j; 1788a8e1175bSopenharmony_ci unsigned char c, cc, adjust; 1789a8e1175bSopenharmony_ci 1790a8e1175bSopenharmony_ci memset(x, 0, d+1); 1791a8e1175bSopenharmony_ci 1792a8e1175bSopenharmony_ci /* First get the classical comb values (except for x_d = 0) */ 1793a8e1175bSopenharmony_ci for (i = 0; i < d; i++) { 1794a8e1175bSopenharmony_ci for (j = 0; j < w; j++) { 1795a8e1175bSopenharmony_ci x[i] |= mbedtls_mpi_get_bit(m, i + d * j) << j; 1796a8e1175bSopenharmony_ci } 1797a8e1175bSopenharmony_ci } 1798a8e1175bSopenharmony_ci 1799a8e1175bSopenharmony_ci /* Now make sure x_1 .. x_d are odd */ 1800a8e1175bSopenharmony_ci c = 0; 1801a8e1175bSopenharmony_ci for (i = 1; i <= d; i++) { 1802a8e1175bSopenharmony_ci /* Add carry and update it */ 1803a8e1175bSopenharmony_ci cc = x[i] & c; 1804a8e1175bSopenharmony_ci x[i] = x[i] ^ c; 1805a8e1175bSopenharmony_ci c = cc; 1806a8e1175bSopenharmony_ci 1807a8e1175bSopenharmony_ci /* Adjust if needed, avoiding branches */ 1808a8e1175bSopenharmony_ci adjust = 1 - (x[i] & 0x01); 1809a8e1175bSopenharmony_ci c |= x[i] & (x[i-1] * adjust); 1810a8e1175bSopenharmony_ci x[i] = x[i] ^ (x[i-1] * adjust); 1811a8e1175bSopenharmony_ci x[i-1] |= adjust << 7; 1812a8e1175bSopenharmony_ci } 1813a8e1175bSopenharmony_ci} 1814a8e1175bSopenharmony_ci 1815a8e1175bSopenharmony_ci/* 1816a8e1175bSopenharmony_ci * Precompute points for the adapted comb method 1817a8e1175bSopenharmony_ci * 1818a8e1175bSopenharmony_ci * Assumption: T must be able to hold 2^{w - 1} elements. 1819a8e1175bSopenharmony_ci * 1820a8e1175bSopenharmony_ci * Operation: If i = i_{w-1} ... i_1 is the binary representation of i, 1821a8e1175bSopenharmony_ci * sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P. 1822a8e1175bSopenharmony_ci * 1823a8e1175bSopenharmony_ci * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) 1824a8e1175bSopenharmony_ci * 1825a8e1175bSopenharmony_ci * Note: Even comb values (those where P would be omitted from the 1826a8e1175bSopenharmony_ci * sum defining T[i] above) are not needed in our adaption 1827a8e1175bSopenharmony_ci * the comb method. See ecp_comb_recode_core(). 1828a8e1175bSopenharmony_ci * 1829a8e1175bSopenharmony_ci * This function currently works in four steps: 1830a8e1175bSopenharmony_ci * (1) [dbl] Computation of intermediate T[i] for 2-power values of i 1831a8e1175bSopenharmony_ci * (2) [norm_dbl] Normalization of coordinates of these T[i] 1832a8e1175bSopenharmony_ci * (3) [add] Computation of all T[i] 1833a8e1175bSopenharmony_ci * (4) [norm_add] Normalization of all T[i] 1834a8e1175bSopenharmony_ci * 1835a8e1175bSopenharmony_ci * Step 1 can be interrupted but not the others; together with the final 1836a8e1175bSopenharmony_ci * coordinate normalization they are the largest steps done at once, depending 1837a8e1175bSopenharmony_ci * on the window size. Here are operation counts for P-256: 1838a8e1175bSopenharmony_ci * 1839a8e1175bSopenharmony_ci * step (2) (3) (4) 1840a8e1175bSopenharmony_ci * w = 5 142 165 208 1841a8e1175bSopenharmony_ci * w = 4 136 77 160 1842a8e1175bSopenharmony_ci * w = 3 130 33 136 1843a8e1175bSopenharmony_ci * w = 2 124 11 124 1844a8e1175bSopenharmony_ci * 1845a8e1175bSopenharmony_ci * So if ECC operations are blocking for too long even with a low max_ops 1846a8e1175bSopenharmony_ci * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order 1847a8e1175bSopenharmony_ci * to minimize maximum blocking time. 1848a8e1175bSopenharmony_ci */ 1849a8e1175bSopenharmony_cistatic int ecp_precompute_comb(const mbedtls_ecp_group *grp, 1850a8e1175bSopenharmony_ci mbedtls_ecp_point T[], const mbedtls_ecp_point *P, 1851a8e1175bSopenharmony_ci unsigned char w, size_t d, 1852a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 1853a8e1175bSopenharmony_ci{ 1854a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1855a8e1175bSopenharmony_ci unsigned char i; 1856a8e1175bSopenharmony_ci size_t j = 0; 1857a8e1175bSopenharmony_ci const unsigned char T_size = 1U << (w - 1); 1858a8e1175bSopenharmony_ci mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1] = { NULL }; 1859a8e1175bSopenharmony_ci 1860a8e1175bSopenharmony_ci mbedtls_mpi tmp[4]; 1861a8e1175bSopenharmony_ci 1862a8e1175bSopenharmony_ci mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 1863a8e1175bSopenharmony_ci 1864a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 1865a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 1866a8e1175bSopenharmony_ci if (rs_ctx->rsm->state == ecp_rsm_pre_dbl) { 1867a8e1175bSopenharmony_ci goto dbl; 1868a8e1175bSopenharmony_ci } 1869a8e1175bSopenharmony_ci if (rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl) { 1870a8e1175bSopenharmony_ci goto norm_dbl; 1871a8e1175bSopenharmony_ci } 1872a8e1175bSopenharmony_ci if (rs_ctx->rsm->state == ecp_rsm_pre_add) { 1873a8e1175bSopenharmony_ci goto add; 1874a8e1175bSopenharmony_ci } 1875a8e1175bSopenharmony_ci if (rs_ctx->rsm->state == ecp_rsm_pre_norm_add) { 1876a8e1175bSopenharmony_ci goto norm_add; 1877a8e1175bSopenharmony_ci } 1878a8e1175bSopenharmony_ci } 1879a8e1175bSopenharmony_ci#else 1880a8e1175bSopenharmony_ci (void) rs_ctx; 1881a8e1175bSopenharmony_ci#endif 1882a8e1175bSopenharmony_ci 1883a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 1884a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 1885a8e1175bSopenharmony_ci rs_ctx->rsm->state = ecp_rsm_pre_dbl; 1886a8e1175bSopenharmony_ci 1887a8e1175bSopenharmony_ci /* initial state for the loop */ 1888a8e1175bSopenharmony_ci rs_ctx->rsm->i = 0; 1889a8e1175bSopenharmony_ci } 1890a8e1175bSopenharmony_ci 1891a8e1175bSopenharmony_cidbl: 1892a8e1175bSopenharmony_ci#endif 1893a8e1175bSopenharmony_ci /* 1894a8e1175bSopenharmony_ci * Set T[0] = P and 1895a8e1175bSopenharmony_ci * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) 1896a8e1175bSopenharmony_ci */ 1897a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&T[0], P)); 1898a8e1175bSopenharmony_ci 1899a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 1900a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0) { 1901a8e1175bSopenharmony_ci j = rs_ctx->rsm->i; 1902a8e1175bSopenharmony_ci } else 1903a8e1175bSopenharmony_ci#endif 1904a8e1175bSopenharmony_ci j = 0; 1905a8e1175bSopenharmony_ci 1906a8e1175bSopenharmony_ci for (; j < d * (w - 1); j++) { 1907a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL); 1908a8e1175bSopenharmony_ci 1909a8e1175bSopenharmony_ci i = 1U << (j / d); 1910a8e1175bSopenharmony_ci cur = T + i; 1911a8e1175bSopenharmony_ci 1912a8e1175bSopenharmony_ci if (j % d == 0) { 1913a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_copy(cur, T + (i >> 1))); 1914a8e1175bSopenharmony_ci } 1915a8e1175bSopenharmony_ci 1916a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_double_jac(grp, cur, cur, tmp)); 1917a8e1175bSopenharmony_ci } 1918a8e1175bSopenharmony_ci 1919a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 1920a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 1921a8e1175bSopenharmony_ci rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl; 1922a8e1175bSopenharmony_ci } 1923a8e1175bSopenharmony_ci 1924a8e1175bSopenharmony_cinorm_dbl: 1925a8e1175bSopenharmony_ci#endif 1926a8e1175bSopenharmony_ci /* 1927a8e1175bSopenharmony_ci * Normalize current elements in T to allow them to be used in 1928a8e1175bSopenharmony_ci * ecp_add_mixed() below, which requires one normalized input. 1929a8e1175bSopenharmony_ci * 1930a8e1175bSopenharmony_ci * As T has holes, use an auxiliary array of pointers to elements in T. 1931a8e1175bSopenharmony_ci * 1932a8e1175bSopenharmony_ci */ 1933a8e1175bSopenharmony_ci j = 0; 1934a8e1175bSopenharmony_ci for (i = 1; i < T_size; i <<= 1) { 1935a8e1175bSopenharmony_ci TT[j++] = T + i; 1936a8e1175bSopenharmony_ci } 1937a8e1175bSopenharmony_ci 1938a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2); 1939a8e1175bSopenharmony_ci 1940a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j)); 1941a8e1175bSopenharmony_ci 1942a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 1943a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 1944a8e1175bSopenharmony_ci rs_ctx->rsm->state = ecp_rsm_pre_add; 1945a8e1175bSopenharmony_ci } 1946a8e1175bSopenharmony_ci 1947a8e1175bSopenharmony_ciadd: 1948a8e1175bSopenharmony_ci#endif 1949a8e1175bSopenharmony_ci /* 1950a8e1175bSopenharmony_ci * Compute the remaining ones using the minimal number of additions 1951a8e1175bSopenharmony_ci * Be careful to update T[2^l] only after using it! 1952a8e1175bSopenharmony_ci */ 1953a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET((T_size - 1) * MBEDTLS_ECP_OPS_ADD); 1954a8e1175bSopenharmony_ci 1955a8e1175bSopenharmony_ci for (i = 1; i < T_size; i <<= 1) { 1956a8e1175bSopenharmony_ci j = i; 1957a8e1175bSopenharmony_ci while (j--) { 1958a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_add_mixed(grp, &T[i + j], &T[j], &T[i], tmp)); 1959a8e1175bSopenharmony_ci } 1960a8e1175bSopenharmony_ci } 1961a8e1175bSopenharmony_ci 1962a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 1963a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 1964a8e1175bSopenharmony_ci rs_ctx->rsm->state = ecp_rsm_pre_norm_add; 1965a8e1175bSopenharmony_ci } 1966a8e1175bSopenharmony_ci 1967a8e1175bSopenharmony_cinorm_add: 1968a8e1175bSopenharmony_ci#endif 1969a8e1175bSopenharmony_ci /* 1970a8e1175bSopenharmony_ci * Normalize final elements in T. Even though there are no holes now, we 1971a8e1175bSopenharmony_ci * still need the auxiliary array for homogeneity with the previous 1972a8e1175bSopenharmony_ci * call. Also, skip T[0] which is already normalised, being a copy of P. 1973a8e1175bSopenharmony_ci */ 1974a8e1175bSopenharmony_ci for (j = 0; j + 1 < T_size; j++) { 1975a8e1175bSopenharmony_ci TT[j] = T + j + 1; 1976a8e1175bSopenharmony_ci } 1977a8e1175bSopenharmony_ci 1978a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2); 1979a8e1175bSopenharmony_ci 1980a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j)); 1981a8e1175bSopenharmony_ci 1982a8e1175bSopenharmony_ci /* Free Z coordinate (=1 after normalization) to save RAM. 1983a8e1175bSopenharmony_ci * This makes T[i] invalid as mbedtls_ecp_points, but this is OK 1984a8e1175bSopenharmony_ci * since from this point onwards, they are only accessed indirectly 1985a8e1175bSopenharmony_ci * via the getter function ecp_select_comb() which does set the 1986a8e1175bSopenharmony_ci * target's Z coordinate to 1. */ 1987a8e1175bSopenharmony_ci for (i = 0; i < T_size; i++) { 1988a8e1175bSopenharmony_ci mbedtls_mpi_free(&T[i].Z); 1989a8e1175bSopenharmony_ci } 1990a8e1175bSopenharmony_ci 1991a8e1175bSopenharmony_cicleanup: 1992a8e1175bSopenharmony_ci 1993a8e1175bSopenharmony_ci mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 1994a8e1175bSopenharmony_ci 1995a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 1996a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL && 1997a8e1175bSopenharmony_ci ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 1998a8e1175bSopenharmony_ci if (rs_ctx->rsm->state == ecp_rsm_pre_dbl) { 1999a8e1175bSopenharmony_ci rs_ctx->rsm->i = j; 2000a8e1175bSopenharmony_ci } 2001a8e1175bSopenharmony_ci } 2002a8e1175bSopenharmony_ci#endif 2003a8e1175bSopenharmony_ci 2004a8e1175bSopenharmony_ci return ret; 2005a8e1175bSopenharmony_ci} 2006a8e1175bSopenharmony_ci 2007a8e1175bSopenharmony_ci/* 2008a8e1175bSopenharmony_ci * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] 2009a8e1175bSopenharmony_ci * 2010a8e1175bSopenharmony_ci * See ecp_comb_recode_core() for background 2011a8e1175bSopenharmony_ci */ 2012a8e1175bSopenharmony_cistatic int ecp_select_comb(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2013a8e1175bSopenharmony_ci const mbedtls_ecp_point T[], unsigned char T_size, 2014a8e1175bSopenharmony_ci unsigned char i) 2015a8e1175bSopenharmony_ci{ 2016a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2017a8e1175bSopenharmony_ci unsigned char ii, j; 2018a8e1175bSopenharmony_ci 2019a8e1175bSopenharmony_ci /* Ignore the "sign" bit and scale down */ 2020a8e1175bSopenharmony_ci ii = (i & 0x7Fu) >> 1; 2021a8e1175bSopenharmony_ci 2022a8e1175bSopenharmony_ci /* Read the whole table to thwart cache-based timing attacks */ 2023a8e1175bSopenharmony_ci for (j = 0; j < T_size; j++) { 2024a8e1175bSopenharmony_ci MPI_ECP_COND_ASSIGN(&R->X, &T[j].X, j == ii); 2025a8e1175bSopenharmony_ci MPI_ECP_COND_ASSIGN(&R->Y, &T[j].Y, j == ii); 2026a8e1175bSopenharmony_ci } 2027a8e1175bSopenharmony_ci 2028a8e1175bSopenharmony_ci /* Safely invert result if i is "negative" */ 2029a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, R, i >> 7)); 2030a8e1175bSopenharmony_ci 2031a8e1175bSopenharmony_ci MPI_ECP_LSET(&R->Z, 1); 2032a8e1175bSopenharmony_ci 2033a8e1175bSopenharmony_cicleanup: 2034a8e1175bSopenharmony_ci return ret; 2035a8e1175bSopenharmony_ci} 2036a8e1175bSopenharmony_ci 2037a8e1175bSopenharmony_ci/* 2038a8e1175bSopenharmony_ci * Core multiplication algorithm for the (modified) comb method. 2039a8e1175bSopenharmony_ci * This part is actually common with the basic comb method (GECC 3.44) 2040a8e1175bSopenharmony_ci * 2041a8e1175bSopenharmony_ci * Cost: d A + d D + 1 R 2042a8e1175bSopenharmony_ci */ 2043a8e1175bSopenharmony_cistatic int ecp_mul_comb_core(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2044a8e1175bSopenharmony_ci const mbedtls_ecp_point T[], unsigned char T_size, 2045a8e1175bSopenharmony_ci const unsigned char x[], size_t d, 2046a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 2047a8e1175bSopenharmony_ci void *p_rng, 2048a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 2049a8e1175bSopenharmony_ci{ 2050a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2051a8e1175bSopenharmony_ci mbedtls_ecp_point Txi; 2052a8e1175bSopenharmony_ci mbedtls_mpi tmp[4]; 2053a8e1175bSopenharmony_ci size_t i; 2054a8e1175bSopenharmony_ci 2055a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&Txi); 2056a8e1175bSopenharmony_ci mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2057a8e1175bSopenharmony_ci 2058a8e1175bSopenharmony_ci#if !defined(MBEDTLS_ECP_RESTARTABLE) 2059a8e1175bSopenharmony_ci (void) rs_ctx; 2060a8e1175bSopenharmony_ci#endif 2061a8e1175bSopenharmony_ci 2062a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2063a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL && 2064a8e1175bSopenharmony_ci rs_ctx->rsm->state != ecp_rsm_comb_core) { 2065a8e1175bSopenharmony_ci rs_ctx->rsm->i = 0; 2066a8e1175bSopenharmony_ci rs_ctx->rsm->state = ecp_rsm_comb_core; 2067a8e1175bSopenharmony_ci } 2068a8e1175bSopenharmony_ci 2069a8e1175bSopenharmony_ci /* new 'if' instead of nested for the sake of the 'else' branch */ 2070a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0) { 2071a8e1175bSopenharmony_ci /* restore current index (R already pointing to rs_ctx->rsm->R) */ 2072a8e1175bSopenharmony_ci i = rs_ctx->rsm->i; 2073a8e1175bSopenharmony_ci } else 2074a8e1175bSopenharmony_ci#endif 2075a8e1175bSopenharmony_ci { 2076a8e1175bSopenharmony_ci /* Start with a non-zero point and randomize its coordinates */ 2077a8e1175bSopenharmony_ci i = d; 2078a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_select_comb(grp, R, T, T_size, x[i])); 2079a8e1175bSopenharmony_ci if (f_rng != 0) { 2080a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, R, f_rng, p_rng)); 2081a8e1175bSopenharmony_ci } 2082a8e1175bSopenharmony_ci } 2083a8e1175bSopenharmony_ci 2084a8e1175bSopenharmony_ci while (i != 0) { 2085a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD); 2086a8e1175bSopenharmony_ci --i; 2087a8e1175bSopenharmony_ci 2088a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_double_jac(grp, R, R, tmp)); 2089a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_select_comb(grp, &Txi, T, T_size, x[i])); 2090a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_add_mixed(grp, R, R, &Txi, tmp)); 2091a8e1175bSopenharmony_ci } 2092a8e1175bSopenharmony_ci 2093a8e1175bSopenharmony_cicleanup: 2094a8e1175bSopenharmony_ci 2095a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&Txi); 2096a8e1175bSopenharmony_ci mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2097a8e1175bSopenharmony_ci 2098a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2099a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL && 2100a8e1175bSopenharmony_ci ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 2101a8e1175bSopenharmony_ci rs_ctx->rsm->i = i; 2102a8e1175bSopenharmony_ci /* no need to save R, already pointing to rs_ctx->rsm->R */ 2103a8e1175bSopenharmony_ci } 2104a8e1175bSopenharmony_ci#endif 2105a8e1175bSopenharmony_ci 2106a8e1175bSopenharmony_ci return ret; 2107a8e1175bSopenharmony_ci} 2108a8e1175bSopenharmony_ci 2109a8e1175bSopenharmony_ci/* 2110a8e1175bSopenharmony_ci * Recode the scalar to get constant-time comb multiplication 2111a8e1175bSopenharmony_ci * 2112a8e1175bSopenharmony_ci * As the actual scalar recoding needs an odd scalar as a starting point, 2113a8e1175bSopenharmony_ci * this wrapper ensures that by replacing m by N - m if necessary, and 2114a8e1175bSopenharmony_ci * informs the caller that the result of multiplication will be negated. 2115a8e1175bSopenharmony_ci * 2116a8e1175bSopenharmony_ci * This works because we only support large prime order for Short Weierstrass 2117a8e1175bSopenharmony_ci * curves, so N is always odd hence either m or N - m is. 2118a8e1175bSopenharmony_ci * 2119a8e1175bSopenharmony_ci * See ecp_comb_recode_core() for background. 2120a8e1175bSopenharmony_ci */ 2121a8e1175bSopenharmony_cistatic int ecp_comb_recode_scalar(const mbedtls_ecp_group *grp, 2122a8e1175bSopenharmony_ci const mbedtls_mpi *m, 2123a8e1175bSopenharmony_ci unsigned char k[COMB_MAX_D + 1], 2124a8e1175bSopenharmony_ci size_t d, 2125a8e1175bSopenharmony_ci unsigned char w, 2126a8e1175bSopenharmony_ci unsigned char *parity_trick) 2127a8e1175bSopenharmony_ci{ 2128a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2129a8e1175bSopenharmony_ci mbedtls_mpi M, mm; 2130a8e1175bSopenharmony_ci 2131a8e1175bSopenharmony_ci mbedtls_mpi_init(&M); 2132a8e1175bSopenharmony_ci mbedtls_mpi_init(&mm); 2133a8e1175bSopenharmony_ci 2134a8e1175bSopenharmony_ci /* N is always odd (see above), just make extra sure */ 2135a8e1175bSopenharmony_ci if (mbedtls_mpi_get_bit(&grp->N, 0) != 1) { 2136a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 2137a8e1175bSopenharmony_ci } 2138a8e1175bSopenharmony_ci 2139a8e1175bSopenharmony_ci /* do we need the parity trick? */ 2140a8e1175bSopenharmony_ci *parity_trick = (mbedtls_mpi_get_bit(m, 0) == 0); 2141a8e1175bSopenharmony_ci 2142a8e1175bSopenharmony_ci /* execute parity fix in constant time */ 2143a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&M, m)); 2144a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&mm, &grp->N, m)); 2145a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&M, &mm, *parity_trick)); 2146a8e1175bSopenharmony_ci 2147a8e1175bSopenharmony_ci /* actual scalar recoding */ 2148a8e1175bSopenharmony_ci ecp_comb_recode_core(k, d, w, &M); 2149a8e1175bSopenharmony_ci 2150a8e1175bSopenharmony_cicleanup: 2151a8e1175bSopenharmony_ci mbedtls_mpi_free(&mm); 2152a8e1175bSopenharmony_ci mbedtls_mpi_free(&M); 2153a8e1175bSopenharmony_ci 2154a8e1175bSopenharmony_ci return ret; 2155a8e1175bSopenharmony_ci} 2156a8e1175bSopenharmony_ci 2157a8e1175bSopenharmony_ci/* 2158a8e1175bSopenharmony_ci * Perform comb multiplication (for short Weierstrass curves) 2159a8e1175bSopenharmony_ci * once the auxiliary table has been pre-computed. 2160a8e1175bSopenharmony_ci * 2161a8e1175bSopenharmony_ci * Scalar recoding may use a parity trick that makes us compute -m * P, 2162a8e1175bSopenharmony_ci * if that is the case we'll need to recover m * P at the end. 2163a8e1175bSopenharmony_ci */ 2164a8e1175bSopenharmony_cistatic int ecp_mul_comb_after_precomp(const mbedtls_ecp_group *grp, 2165a8e1175bSopenharmony_ci mbedtls_ecp_point *R, 2166a8e1175bSopenharmony_ci const mbedtls_mpi *m, 2167a8e1175bSopenharmony_ci const mbedtls_ecp_point *T, 2168a8e1175bSopenharmony_ci unsigned char T_size, 2169a8e1175bSopenharmony_ci unsigned char w, 2170a8e1175bSopenharmony_ci size_t d, 2171a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 2172a8e1175bSopenharmony_ci void *p_rng, 2173a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 2174a8e1175bSopenharmony_ci{ 2175a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2176a8e1175bSopenharmony_ci unsigned char parity_trick; 2177a8e1175bSopenharmony_ci unsigned char k[COMB_MAX_D + 1]; 2178a8e1175bSopenharmony_ci mbedtls_ecp_point *RR = R; 2179a8e1175bSopenharmony_ci 2180a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2181a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 2182a8e1175bSopenharmony_ci RR = &rs_ctx->rsm->R; 2183a8e1175bSopenharmony_ci 2184a8e1175bSopenharmony_ci if (rs_ctx->rsm->state == ecp_rsm_final_norm) { 2185a8e1175bSopenharmony_ci goto final_norm; 2186a8e1175bSopenharmony_ci } 2187a8e1175bSopenharmony_ci } 2188a8e1175bSopenharmony_ci#endif 2189a8e1175bSopenharmony_ci 2190a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_comb_recode_scalar(grp, m, k, d, w, 2191a8e1175bSopenharmony_ci &parity_trick)); 2192a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_mul_comb_core(grp, RR, T, T_size, k, d, 2193a8e1175bSopenharmony_ci f_rng, p_rng, rs_ctx)); 2194a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, RR, parity_trick)); 2195a8e1175bSopenharmony_ci 2196a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2197a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 2198a8e1175bSopenharmony_ci rs_ctx->rsm->state = ecp_rsm_final_norm; 2199a8e1175bSopenharmony_ci } 2200a8e1175bSopenharmony_ci 2201a8e1175bSopenharmony_cifinal_norm: 2202a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV); 2203a8e1175bSopenharmony_ci#endif 2204a8e1175bSopenharmony_ci /* 2205a8e1175bSopenharmony_ci * Knowledge of the jacobian coordinates may leak the last few bits of the 2206a8e1175bSopenharmony_ci * scalar [1], and since our MPI implementation isn't constant-flow, 2207a8e1175bSopenharmony_ci * inversion (used for coordinate normalization) may leak the full value 2208a8e1175bSopenharmony_ci * of its input via side-channels [2]. 2209a8e1175bSopenharmony_ci * 2210a8e1175bSopenharmony_ci * [1] https://eprint.iacr.org/2003/191 2211a8e1175bSopenharmony_ci * [2] https://eprint.iacr.org/2020/055 2212a8e1175bSopenharmony_ci * 2213a8e1175bSopenharmony_ci * Avoid the leak by randomizing coordinates before we normalize them. 2214a8e1175bSopenharmony_ci */ 2215a8e1175bSopenharmony_ci if (f_rng != 0) { 2216a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, RR, f_rng, p_rng)); 2217a8e1175bSopenharmony_ci } 2218a8e1175bSopenharmony_ci 2219a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, RR)); 2220a8e1175bSopenharmony_ci 2221a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2222a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 2223a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, RR)); 2224a8e1175bSopenharmony_ci } 2225a8e1175bSopenharmony_ci#endif 2226a8e1175bSopenharmony_ci 2227a8e1175bSopenharmony_cicleanup: 2228a8e1175bSopenharmony_ci return ret; 2229a8e1175bSopenharmony_ci} 2230a8e1175bSopenharmony_ci 2231a8e1175bSopenharmony_ci/* 2232a8e1175bSopenharmony_ci * Pick window size based on curve size and whether we optimize for base point 2233a8e1175bSopenharmony_ci */ 2234a8e1175bSopenharmony_cistatic unsigned char ecp_pick_window_size(const mbedtls_ecp_group *grp, 2235a8e1175bSopenharmony_ci unsigned char p_eq_g) 2236a8e1175bSopenharmony_ci{ 2237a8e1175bSopenharmony_ci unsigned char w; 2238a8e1175bSopenharmony_ci 2239a8e1175bSopenharmony_ci /* 2240a8e1175bSopenharmony_ci * Minimize the number of multiplications, that is minimize 2241a8e1175bSopenharmony_ci * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) 2242a8e1175bSopenharmony_ci * (see costs of the various parts, with 1S = 1M) 2243a8e1175bSopenharmony_ci */ 2244a8e1175bSopenharmony_ci w = grp->nbits >= 384 ? 5 : 4; 2245a8e1175bSopenharmony_ci 2246a8e1175bSopenharmony_ci /* 2247a8e1175bSopenharmony_ci * If P == G, pre-compute a bit more, since this may be re-used later. 2248a8e1175bSopenharmony_ci * Just adding one avoids upping the cost of the first mul too much, 2249a8e1175bSopenharmony_ci * and the memory cost too. 2250a8e1175bSopenharmony_ci */ 2251a8e1175bSopenharmony_ci if (p_eq_g) { 2252a8e1175bSopenharmony_ci w++; 2253a8e1175bSopenharmony_ci } 2254a8e1175bSopenharmony_ci 2255a8e1175bSopenharmony_ci /* 2256a8e1175bSopenharmony_ci * If static comb table may not be used (!p_eq_g) or static comb table does 2257a8e1175bSopenharmony_ci * not exists, make sure w is within bounds. 2258a8e1175bSopenharmony_ci * (The last test is useful only for very small curves in the test suite.) 2259a8e1175bSopenharmony_ci * 2260a8e1175bSopenharmony_ci * The user reduces MBEDTLS_ECP_WINDOW_SIZE does not changes the size of 2261a8e1175bSopenharmony_ci * static comb table, because the size of static comb table is fixed when 2262a8e1175bSopenharmony_ci * it is generated. 2263a8e1175bSopenharmony_ci */ 2264a8e1175bSopenharmony_ci#if (MBEDTLS_ECP_WINDOW_SIZE < 6) 2265a8e1175bSopenharmony_ci if ((!p_eq_g || !ecp_group_is_static_comb_table(grp)) && w > MBEDTLS_ECP_WINDOW_SIZE) { 2266a8e1175bSopenharmony_ci w = MBEDTLS_ECP_WINDOW_SIZE; 2267a8e1175bSopenharmony_ci } 2268a8e1175bSopenharmony_ci#endif 2269a8e1175bSopenharmony_ci if (w >= grp->nbits) { 2270a8e1175bSopenharmony_ci w = 2; 2271a8e1175bSopenharmony_ci } 2272a8e1175bSopenharmony_ci 2273a8e1175bSopenharmony_ci return w; 2274a8e1175bSopenharmony_ci} 2275a8e1175bSopenharmony_ci 2276a8e1175bSopenharmony_ci/* 2277a8e1175bSopenharmony_ci * Multiplication using the comb method - for curves in short Weierstrass form 2278a8e1175bSopenharmony_ci * 2279a8e1175bSopenharmony_ci * This function is mainly responsible for administrative work: 2280a8e1175bSopenharmony_ci * - managing the restart context if enabled 2281a8e1175bSopenharmony_ci * - managing the table of precomputed points (passed between the below two 2282a8e1175bSopenharmony_ci * functions): allocation, computation, ownership transfer, freeing. 2283a8e1175bSopenharmony_ci * 2284a8e1175bSopenharmony_ci * It delegates the actual arithmetic work to: 2285a8e1175bSopenharmony_ci * ecp_precompute_comb() and ecp_mul_comb_with_precomp() 2286a8e1175bSopenharmony_ci * 2287a8e1175bSopenharmony_ci * See comments on ecp_comb_recode_core() regarding the computation strategy. 2288a8e1175bSopenharmony_ci */ 2289a8e1175bSopenharmony_cistatic int ecp_mul_comb(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2290a8e1175bSopenharmony_ci const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2291a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 2292a8e1175bSopenharmony_ci void *p_rng, 2293a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 2294a8e1175bSopenharmony_ci{ 2295a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2296a8e1175bSopenharmony_ci unsigned char w, p_eq_g, i; 2297a8e1175bSopenharmony_ci size_t d; 2298a8e1175bSopenharmony_ci unsigned char T_size = 0, T_ok = 0; 2299a8e1175bSopenharmony_ci mbedtls_ecp_point *T = NULL; 2300a8e1175bSopenharmony_ci 2301a8e1175bSopenharmony_ci ECP_RS_ENTER(rsm); 2302a8e1175bSopenharmony_ci 2303a8e1175bSopenharmony_ci /* Is P the base point ? */ 2304a8e1175bSopenharmony_ci#if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 2305a8e1175bSopenharmony_ci p_eq_g = (MPI_ECP_CMP(&P->Y, &grp->G.Y) == 0 && 2306a8e1175bSopenharmony_ci MPI_ECP_CMP(&P->X, &grp->G.X) == 0); 2307a8e1175bSopenharmony_ci#else 2308a8e1175bSopenharmony_ci p_eq_g = 0; 2309a8e1175bSopenharmony_ci#endif 2310a8e1175bSopenharmony_ci 2311a8e1175bSopenharmony_ci /* Pick window size and deduce related sizes */ 2312a8e1175bSopenharmony_ci w = ecp_pick_window_size(grp, p_eq_g); 2313a8e1175bSopenharmony_ci T_size = 1U << (w - 1); 2314a8e1175bSopenharmony_ci d = (grp->nbits + w - 1) / w; 2315a8e1175bSopenharmony_ci 2316a8e1175bSopenharmony_ci /* Pre-computed table: do we have it already for the base point? */ 2317a8e1175bSopenharmony_ci if (p_eq_g && grp->T != NULL) { 2318a8e1175bSopenharmony_ci /* second pointer to the same table, will be deleted on exit */ 2319a8e1175bSopenharmony_ci T = grp->T; 2320a8e1175bSopenharmony_ci T_ok = 1; 2321a8e1175bSopenharmony_ci } else 2322a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2323a8e1175bSopenharmony_ci /* Pre-computed table: do we have one in progress? complete? */ 2324a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL) { 2325a8e1175bSopenharmony_ci /* transfer ownership of T from rsm to local function */ 2326a8e1175bSopenharmony_ci T = rs_ctx->rsm->T; 2327a8e1175bSopenharmony_ci rs_ctx->rsm->T = NULL; 2328a8e1175bSopenharmony_ci rs_ctx->rsm->T_size = 0; 2329a8e1175bSopenharmony_ci 2330a8e1175bSopenharmony_ci /* This effectively jumps to the call to mul_comb_after_precomp() */ 2331a8e1175bSopenharmony_ci T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core; 2332a8e1175bSopenharmony_ci } else 2333a8e1175bSopenharmony_ci#endif 2334a8e1175bSopenharmony_ci /* Allocate table if we didn't have any */ 2335a8e1175bSopenharmony_ci { 2336a8e1175bSopenharmony_ci T = mbedtls_calloc(T_size, sizeof(mbedtls_ecp_point)); 2337a8e1175bSopenharmony_ci if (T == NULL) { 2338a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; 2339a8e1175bSopenharmony_ci goto cleanup; 2340a8e1175bSopenharmony_ci } 2341a8e1175bSopenharmony_ci 2342a8e1175bSopenharmony_ci for (i = 0; i < T_size; i++) { 2343a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&T[i]); 2344a8e1175bSopenharmony_ci } 2345a8e1175bSopenharmony_ci 2346a8e1175bSopenharmony_ci T_ok = 0; 2347a8e1175bSopenharmony_ci } 2348a8e1175bSopenharmony_ci 2349a8e1175bSopenharmony_ci /* Compute table (or finish computing it) if not done already */ 2350a8e1175bSopenharmony_ci if (!T_ok) { 2351a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_precompute_comb(grp, T, P, w, d, rs_ctx)); 2352a8e1175bSopenharmony_ci 2353a8e1175bSopenharmony_ci if (p_eq_g) { 2354a8e1175bSopenharmony_ci /* almost transfer ownership of T to the group, but keep a copy of 2355a8e1175bSopenharmony_ci * the pointer to use for calling the next function more easily */ 2356a8e1175bSopenharmony_ci grp->T = T; 2357a8e1175bSopenharmony_ci grp->T_size = T_size; 2358a8e1175bSopenharmony_ci } 2359a8e1175bSopenharmony_ci } 2360a8e1175bSopenharmony_ci 2361a8e1175bSopenharmony_ci /* Actual comb multiplication using precomputed points */ 2362a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_mul_comb_after_precomp(grp, R, m, 2363a8e1175bSopenharmony_ci T, T_size, w, d, 2364a8e1175bSopenharmony_ci f_rng, p_rng, rs_ctx)); 2365a8e1175bSopenharmony_ci 2366a8e1175bSopenharmony_cicleanup: 2367a8e1175bSopenharmony_ci 2368a8e1175bSopenharmony_ci /* does T belong to the group? */ 2369a8e1175bSopenharmony_ci if (T == grp->T) { 2370a8e1175bSopenharmony_ci T = NULL; 2371a8e1175bSopenharmony_ci } 2372a8e1175bSopenharmony_ci 2373a8e1175bSopenharmony_ci /* does T belong to the restart context? */ 2374a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2375a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->rsm != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL) { 2376a8e1175bSopenharmony_ci /* transfer ownership of T from local function to rsm */ 2377a8e1175bSopenharmony_ci rs_ctx->rsm->T_size = T_size; 2378a8e1175bSopenharmony_ci rs_ctx->rsm->T = T; 2379a8e1175bSopenharmony_ci T = NULL; 2380a8e1175bSopenharmony_ci } 2381a8e1175bSopenharmony_ci#endif 2382a8e1175bSopenharmony_ci 2383a8e1175bSopenharmony_ci /* did T belong to us? then let's destroy it! */ 2384a8e1175bSopenharmony_ci if (T != NULL) { 2385a8e1175bSopenharmony_ci for (i = 0; i < T_size; i++) { 2386a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&T[i]); 2387a8e1175bSopenharmony_ci } 2388a8e1175bSopenharmony_ci mbedtls_free(T); 2389a8e1175bSopenharmony_ci } 2390a8e1175bSopenharmony_ci 2391a8e1175bSopenharmony_ci /* prevent caller from using invalid value */ 2392a8e1175bSopenharmony_ci int should_free_R = (ret != 0); 2393a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2394a8e1175bSopenharmony_ci /* don't free R while in progress in case R == P */ 2395a8e1175bSopenharmony_ci if (ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 2396a8e1175bSopenharmony_ci should_free_R = 0; 2397a8e1175bSopenharmony_ci } 2398a8e1175bSopenharmony_ci#endif 2399a8e1175bSopenharmony_ci if (should_free_R) { 2400a8e1175bSopenharmony_ci mbedtls_ecp_point_free(R); 2401a8e1175bSopenharmony_ci } 2402a8e1175bSopenharmony_ci 2403a8e1175bSopenharmony_ci ECP_RS_LEAVE(rsm); 2404a8e1175bSopenharmony_ci 2405a8e1175bSopenharmony_ci return ret; 2406a8e1175bSopenharmony_ci} 2407a8e1175bSopenharmony_ci 2408a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 2409a8e1175bSopenharmony_ci 2410a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 2411a8e1175bSopenharmony_ci/* 2412a8e1175bSopenharmony_ci * For Montgomery curves, we do all the internal arithmetic in projective 2413a8e1175bSopenharmony_ci * coordinates. Import/export of points uses only the x coordinates, which is 2414a8e1175bSopenharmony_ci * internally represented as X / Z. 2415a8e1175bSopenharmony_ci * 2416a8e1175bSopenharmony_ci * For scalar multiplication, we'll use a Montgomery ladder. 2417a8e1175bSopenharmony_ci */ 2418a8e1175bSopenharmony_ci 2419a8e1175bSopenharmony_ci/* 2420a8e1175bSopenharmony_ci * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 2421a8e1175bSopenharmony_ci * Cost: 1M + 1I 2422a8e1175bSopenharmony_ci */ 2423a8e1175bSopenharmony_cistatic int ecp_normalize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P) 2424a8e1175bSopenharmony_ci{ 2425a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) 2426a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 2427a8e1175bSopenharmony_ci return mbedtls_internal_ecp_normalize_mxz(grp, P); 2428a8e1175bSopenharmony_ci } 2429a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */ 2430a8e1175bSopenharmony_ci 2431a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) 2432a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 2433a8e1175bSopenharmony_ci#else 2434a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2435a8e1175bSopenharmony_ci MPI_ECP_INV(&P->Z, &P->Z); 2436a8e1175bSopenharmony_ci MPI_ECP_MUL(&P->X, &P->X, &P->Z); 2437a8e1175bSopenharmony_ci MPI_ECP_LSET(&P->Z, 1); 2438a8e1175bSopenharmony_ci 2439a8e1175bSopenharmony_cicleanup: 2440a8e1175bSopenharmony_ci return ret; 2441a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) */ 2442a8e1175bSopenharmony_ci} 2443a8e1175bSopenharmony_ci 2444a8e1175bSopenharmony_ci/* 2445a8e1175bSopenharmony_ci * Randomize projective x/z coordinates: 2446a8e1175bSopenharmony_ci * (X, Z) -> (l X, l Z) for random l 2447a8e1175bSopenharmony_ci * This is sort of the reverse operation of ecp_normalize_mxz(). 2448a8e1175bSopenharmony_ci * 2449a8e1175bSopenharmony_ci * This countermeasure was first suggested in [2]. 2450a8e1175bSopenharmony_ci * Cost: 2M 2451a8e1175bSopenharmony_ci */ 2452a8e1175bSopenharmony_cistatic int ecp_randomize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, 2453a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 2454a8e1175bSopenharmony_ci{ 2455a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) 2456a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 2457a8e1175bSopenharmony_ci return mbedtls_internal_ecp_randomize_mxz(grp, P, f_rng, p_rng); 2458a8e1175bSopenharmony_ci } 2459a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */ 2460a8e1175bSopenharmony_ci 2461a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) 2462a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 2463a8e1175bSopenharmony_ci#else 2464a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2465a8e1175bSopenharmony_ci mbedtls_mpi l; 2466a8e1175bSopenharmony_ci mbedtls_mpi_init(&l); 2467a8e1175bSopenharmony_ci 2468a8e1175bSopenharmony_ci /* Generate l such that 1 < l < p */ 2469a8e1175bSopenharmony_ci MPI_ECP_RAND(&l); 2470a8e1175bSopenharmony_ci 2471a8e1175bSopenharmony_ci MPI_ECP_MUL(&P->X, &P->X, &l); 2472a8e1175bSopenharmony_ci MPI_ECP_MUL(&P->Z, &P->Z, &l); 2473a8e1175bSopenharmony_ci 2474a8e1175bSopenharmony_cicleanup: 2475a8e1175bSopenharmony_ci mbedtls_mpi_free(&l); 2476a8e1175bSopenharmony_ci 2477a8e1175bSopenharmony_ci if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { 2478a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 2479a8e1175bSopenharmony_ci } 2480a8e1175bSopenharmony_ci return ret; 2481a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) */ 2482a8e1175bSopenharmony_ci} 2483a8e1175bSopenharmony_ci 2484a8e1175bSopenharmony_ci/* 2485a8e1175bSopenharmony_ci * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), 2486a8e1175bSopenharmony_ci * for Montgomery curves in x/z coordinates. 2487a8e1175bSopenharmony_ci * 2488a8e1175bSopenharmony_ci * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 2489a8e1175bSopenharmony_ci * with 2490a8e1175bSopenharmony_ci * d = X1 2491a8e1175bSopenharmony_ci * P = (X2, Z2) 2492a8e1175bSopenharmony_ci * Q = (X3, Z3) 2493a8e1175bSopenharmony_ci * R = (X4, Z4) 2494a8e1175bSopenharmony_ci * S = (X5, Z5) 2495a8e1175bSopenharmony_ci * and eliminating temporary variables tO, ..., t4. 2496a8e1175bSopenharmony_ci * 2497a8e1175bSopenharmony_ci * Cost: 5M + 4S 2498a8e1175bSopenharmony_ci */ 2499a8e1175bSopenharmony_cistatic int ecp_double_add_mxz(const mbedtls_ecp_group *grp, 2500a8e1175bSopenharmony_ci mbedtls_ecp_point *R, mbedtls_ecp_point *S, 2501a8e1175bSopenharmony_ci const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, 2502a8e1175bSopenharmony_ci const mbedtls_mpi *d, 2503a8e1175bSopenharmony_ci mbedtls_mpi T[4]) 2504a8e1175bSopenharmony_ci{ 2505a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) 2506a8e1175bSopenharmony_ci if (mbedtls_internal_ecp_grp_capable(grp)) { 2507a8e1175bSopenharmony_ci return mbedtls_internal_ecp_double_add_mxz(grp, R, S, P, Q, d); 2508a8e1175bSopenharmony_ci } 2509a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */ 2510a8e1175bSopenharmony_ci 2511a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) 2512a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 2513a8e1175bSopenharmony_ci#else 2514a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2515a8e1175bSopenharmony_ci 2516a8e1175bSopenharmony_ci MPI_ECP_ADD(&T[0], &P->X, &P->Z); /* Pp := PX + PZ */ 2517a8e1175bSopenharmony_ci MPI_ECP_SUB(&T[1], &P->X, &P->Z); /* Pm := PX - PZ */ 2518a8e1175bSopenharmony_ci MPI_ECP_ADD(&T[2], &Q->X, &Q->Z); /* Qp := QX + XZ */ 2519a8e1175bSopenharmony_ci MPI_ECP_SUB(&T[3], &Q->X, &Q->Z); /* Qm := QX - QZ */ 2520a8e1175bSopenharmony_ci MPI_ECP_MUL(&T[3], &T[3], &T[0]); /* Qm * Pp */ 2521a8e1175bSopenharmony_ci MPI_ECP_MUL(&T[2], &T[2], &T[1]); /* Qp * Pm */ 2522a8e1175bSopenharmony_ci MPI_ECP_SQR(&T[0], &T[0]); /* Pp^2 */ 2523a8e1175bSopenharmony_ci MPI_ECP_SQR(&T[1], &T[1]); /* Pm^2 */ 2524a8e1175bSopenharmony_ci MPI_ECP_MUL(&R->X, &T[0], &T[1]); /* Pp^2 * Pm^2 */ 2525a8e1175bSopenharmony_ci MPI_ECP_SUB(&T[0], &T[0], &T[1]); /* Pp^2 - Pm^2 */ 2526a8e1175bSopenharmony_ci MPI_ECP_MUL(&R->Z, &grp->A, &T[0]); /* A * (Pp^2 - Pm^2) */ 2527a8e1175bSopenharmony_ci MPI_ECP_ADD(&R->Z, &T[1], &R->Z); /* [ A * (Pp^2-Pm^2) ] + Pm^2 */ 2528a8e1175bSopenharmony_ci MPI_ECP_ADD(&S->X, &T[3], &T[2]); /* Qm*Pp + Qp*Pm */ 2529a8e1175bSopenharmony_ci MPI_ECP_SQR(&S->X, &S->X); /* (Qm*Pp + Qp*Pm)^2 */ 2530a8e1175bSopenharmony_ci MPI_ECP_SUB(&S->Z, &T[3], &T[2]); /* Qm*Pp - Qp*Pm */ 2531a8e1175bSopenharmony_ci MPI_ECP_SQR(&S->Z, &S->Z); /* (Qm*Pp - Qp*Pm)^2 */ 2532a8e1175bSopenharmony_ci MPI_ECP_MUL(&S->Z, d, &S->Z); /* d * ( Qm*Pp - Qp*Pm )^2 */ 2533a8e1175bSopenharmony_ci MPI_ECP_MUL(&R->Z, &T[0], &R->Z); /* [A*(Pp^2-Pm^2)+Pm^2]*(Pp^2-Pm^2) */ 2534a8e1175bSopenharmony_ci 2535a8e1175bSopenharmony_cicleanup: 2536a8e1175bSopenharmony_ci 2537a8e1175bSopenharmony_ci return ret; 2538a8e1175bSopenharmony_ci#endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) */ 2539a8e1175bSopenharmony_ci} 2540a8e1175bSopenharmony_ci 2541a8e1175bSopenharmony_ci/* 2542a8e1175bSopenharmony_ci * Multiplication with Montgomery ladder in x/z coordinates, 2543a8e1175bSopenharmony_ci * for curves in Montgomery form 2544a8e1175bSopenharmony_ci */ 2545a8e1175bSopenharmony_cistatic int ecp_mul_mxz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2546a8e1175bSopenharmony_ci const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2547a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 2548a8e1175bSopenharmony_ci void *p_rng) 2549a8e1175bSopenharmony_ci{ 2550a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2551a8e1175bSopenharmony_ci size_t i; 2552a8e1175bSopenharmony_ci unsigned char b; 2553a8e1175bSopenharmony_ci mbedtls_ecp_point RP; 2554a8e1175bSopenharmony_ci mbedtls_mpi PX; 2555a8e1175bSopenharmony_ci mbedtls_mpi tmp[4]; 2556a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&RP); mbedtls_mpi_init(&PX); 2557a8e1175bSopenharmony_ci 2558a8e1175bSopenharmony_ci mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2559a8e1175bSopenharmony_ci 2560a8e1175bSopenharmony_ci if (f_rng == NULL) { 2561a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 2562a8e1175bSopenharmony_ci } 2563a8e1175bSopenharmony_ci 2564a8e1175bSopenharmony_ci /* Save PX and read from P before writing to R, in case P == R */ 2565a8e1175bSopenharmony_ci MPI_ECP_MOV(&PX, &P->X); 2566a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&RP, P)); 2567a8e1175bSopenharmony_ci 2568a8e1175bSopenharmony_ci /* Set R to zero in modified x/z coordinates */ 2569a8e1175bSopenharmony_ci MPI_ECP_LSET(&R->X, 1); 2570a8e1175bSopenharmony_ci MPI_ECP_LSET(&R->Z, 0); 2571a8e1175bSopenharmony_ci mbedtls_mpi_free(&R->Y); 2572a8e1175bSopenharmony_ci 2573a8e1175bSopenharmony_ci /* RP.X might be slightly larger than P, so reduce it */ 2574a8e1175bSopenharmony_ci MOD_ADD(&RP.X); 2575a8e1175bSopenharmony_ci 2576a8e1175bSopenharmony_ci /* Randomize coordinates of the starting point */ 2577a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, &RP, f_rng, p_rng)); 2578a8e1175bSopenharmony_ci 2579a8e1175bSopenharmony_ci /* Loop invariant: R = result so far, RP = R + P */ 2580a8e1175bSopenharmony_ci i = grp->nbits + 1; /* one past the (zero-based) required msb for private keys */ 2581a8e1175bSopenharmony_ci while (i-- > 0) { 2582a8e1175bSopenharmony_ci b = mbedtls_mpi_get_bit(m, i); 2583a8e1175bSopenharmony_ci /* 2584a8e1175bSopenharmony_ci * if (b) R = 2R + P else R = 2R, 2585a8e1175bSopenharmony_ci * which is: 2586a8e1175bSopenharmony_ci * if (b) double_add( RP, R, RP, R ) 2587a8e1175bSopenharmony_ci * else double_add( R, RP, R, RP ) 2588a8e1175bSopenharmony_ci * but using safe conditional swaps to avoid leaks 2589a8e1175bSopenharmony_ci */ 2590a8e1175bSopenharmony_ci MPI_ECP_COND_SWAP(&R->X, &RP.X, b); 2591a8e1175bSopenharmony_ci MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b); 2592a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_double_add_mxz(grp, R, &RP, R, &RP, &PX, tmp)); 2593a8e1175bSopenharmony_ci MPI_ECP_COND_SWAP(&R->X, &RP.X, b); 2594a8e1175bSopenharmony_ci MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b); 2595a8e1175bSopenharmony_ci } 2596a8e1175bSopenharmony_ci 2597a8e1175bSopenharmony_ci /* 2598a8e1175bSopenharmony_ci * Knowledge of the projective coordinates may leak the last few bits of the 2599a8e1175bSopenharmony_ci * scalar [1], and since our MPI implementation isn't constant-flow, 2600a8e1175bSopenharmony_ci * inversion (used for coordinate normalization) may leak the full value 2601a8e1175bSopenharmony_ci * of its input via side-channels [2]. 2602a8e1175bSopenharmony_ci * 2603a8e1175bSopenharmony_ci * [1] https://eprint.iacr.org/2003/191 2604a8e1175bSopenharmony_ci * [2] https://eprint.iacr.org/2020/055 2605a8e1175bSopenharmony_ci * 2606a8e1175bSopenharmony_ci * Avoid the leak by randomizing coordinates before we normalize them. 2607a8e1175bSopenharmony_ci */ 2608a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, R, f_rng, p_rng)); 2609a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_normalize_mxz(grp, R)); 2610a8e1175bSopenharmony_ci 2611a8e1175bSopenharmony_cicleanup: 2612a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&RP); mbedtls_mpi_free(&PX); 2613a8e1175bSopenharmony_ci 2614a8e1175bSopenharmony_ci mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2615a8e1175bSopenharmony_ci return ret; 2616a8e1175bSopenharmony_ci} 2617a8e1175bSopenharmony_ci 2618a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 2619a8e1175bSopenharmony_ci 2620a8e1175bSopenharmony_ci/* 2621a8e1175bSopenharmony_ci * Restartable multiplication R = m * P 2622a8e1175bSopenharmony_ci * 2623a8e1175bSopenharmony_ci * This internal function can be called without an RNG in case where we know 2624a8e1175bSopenharmony_ci * the inputs are not sensitive. 2625a8e1175bSopenharmony_ci */ 2626a8e1175bSopenharmony_cistatic int ecp_mul_restartable_internal(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2627a8e1175bSopenharmony_ci const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2628a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 2629a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 2630a8e1175bSopenharmony_ci{ 2631a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 2632a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_INTERNAL_ALT) 2633a8e1175bSopenharmony_ci char is_grp_capable = 0; 2634a8e1175bSopenharmony_ci#endif 2635a8e1175bSopenharmony_ci 2636a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2637a8e1175bSopenharmony_ci /* reset ops count for this call if top-level */ 2638a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->depth++ == 0) { 2639a8e1175bSopenharmony_ci rs_ctx->ops_done = 0; 2640a8e1175bSopenharmony_ci } 2641a8e1175bSopenharmony_ci#else 2642a8e1175bSopenharmony_ci (void) rs_ctx; 2643a8e1175bSopenharmony_ci#endif 2644a8e1175bSopenharmony_ci 2645a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_INTERNAL_ALT) 2646a8e1175bSopenharmony_ci if ((is_grp_capable = mbedtls_internal_ecp_grp_capable(grp))) { 2647a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_internal_ecp_init(grp)); 2648a8e1175bSopenharmony_ci } 2649a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_INTERNAL_ALT */ 2650a8e1175bSopenharmony_ci 2651a8e1175bSopenharmony_ci int restarting = 0; 2652a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2653a8e1175bSopenharmony_ci restarting = (rs_ctx != NULL && rs_ctx->rsm != NULL); 2654a8e1175bSopenharmony_ci#endif 2655a8e1175bSopenharmony_ci /* skip argument check when restarting */ 2656a8e1175bSopenharmony_ci if (!restarting) { 2657a8e1175bSopenharmony_ci /* check_privkey is free */ 2658a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_CHK); 2659a8e1175bSopenharmony_ci 2660a8e1175bSopenharmony_ci /* Common sanity checks */ 2661a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(grp, m)); 2662a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 2663a8e1175bSopenharmony_ci } 2664a8e1175bSopenharmony_ci 2665a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 2666a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 2667a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 2668a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_mul_mxz(grp, R, m, P, f_rng, p_rng)); 2669a8e1175bSopenharmony_ci } 2670a8e1175bSopenharmony_ci#endif 2671a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 2672a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 2673a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_mul_comb(grp, R, m, P, f_rng, p_rng, rs_ctx)); 2674a8e1175bSopenharmony_ci } 2675a8e1175bSopenharmony_ci#endif 2676a8e1175bSopenharmony_ci 2677a8e1175bSopenharmony_cicleanup: 2678a8e1175bSopenharmony_ci 2679a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_INTERNAL_ALT) 2680a8e1175bSopenharmony_ci if (is_grp_capable) { 2681a8e1175bSopenharmony_ci mbedtls_internal_ecp_free(grp); 2682a8e1175bSopenharmony_ci } 2683a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_INTERNAL_ALT */ 2684a8e1175bSopenharmony_ci 2685a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2686a8e1175bSopenharmony_ci if (rs_ctx != NULL) { 2687a8e1175bSopenharmony_ci rs_ctx->depth--; 2688a8e1175bSopenharmony_ci } 2689a8e1175bSopenharmony_ci#endif 2690a8e1175bSopenharmony_ci 2691a8e1175bSopenharmony_ci return ret; 2692a8e1175bSopenharmony_ci} 2693a8e1175bSopenharmony_ci 2694a8e1175bSopenharmony_ci/* 2695a8e1175bSopenharmony_ci * Restartable multiplication R = m * P 2696a8e1175bSopenharmony_ci */ 2697a8e1175bSopenharmony_ciint mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2698a8e1175bSopenharmony_ci const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2699a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 2700a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 2701a8e1175bSopenharmony_ci{ 2702a8e1175bSopenharmony_ci if (f_rng == NULL) { 2703a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 2704a8e1175bSopenharmony_ci } 2705a8e1175bSopenharmony_ci 2706a8e1175bSopenharmony_ci return ecp_mul_restartable_internal(grp, R, m, P, f_rng, p_rng, rs_ctx); 2707a8e1175bSopenharmony_ci} 2708a8e1175bSopenharmony_ci 2709a8e1175bSopenharmony_ci/* 2710a8e1175bSopenharmony_ci * Multiplication R = m * P 2711a8e1175bSopenharmony_ci */ 2712a8e1175bSopenharmony_ciint mbedtls_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2713a8e1175bSopenharmony_ci const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2714a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 2715a8e1175bSopenharmony_ci{ 2716a8e1175bSopenharmony_ci return mbedtls_ecp_mul_restartable(grp, R, m, P, f_rng, p_rng, NULL); 2717a8e1175bSopenharmony_ci} 2718a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 2719a8e1175bSopenharmony_ci 2720a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 2721a8e1175bSopenharmony_ci/* 2722a8e1175bSopenharmony_ci * Check that an affine point is valid as a public key, 2723a8e1175bSopenharmony_ci * short weierstrass curves (SEC1 3.2.3.1) 2724a8e1175bSopenharmony_ci */ 2725a8e1175bSopenharmony_cistatic int ecp_check_pubkey_sw(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) 2726a8e1175bSopenharmony_ci{ 2727a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2728a8e1175bSopenharmony_ci mbedtls_mpi YY, RHS; 2729a8e1175bSopenharmony_ci 2730a8e1175bSopenharmony_ci /* pt coordinates must be normalized for our checks */ 2731a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0 || 2732a8e1175bSopenharmony_ci mbedtls_mpi_cmp_int(&pt->Y, 0) < 0 || 2733a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&pt->X, &grp->P) >= 0 || 2734a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&pt->Y, &grp->P) >= 0) { 2735a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 2736a8e1175bSopenharmony_ci } 2737a8e1175bSopenharmony_ci 2738a8e1175bSopenharmony_ci mbedtls_mpi_init(&YY); mbedtls_mpi_init(&RHS); 2739a8e1175bSopenharmony_ci 2740a8e1175bSopenharmony_ci /* 2741a8e1175bSopenharmony_ci * YY = Y^2 2742a8e1175bSopenharmony_ci * RHS = X^3 + A X + B 2743a8e1175bSopenharmony_ci */ 2744a8e1175bSopenharmony_ci MPI_ECP_SQR(&YY, &pt->Y); 2745a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, &RHS, &pt->X)); 2746a8e1175bSopenharmony_ci 2747a8e1175bSopenharmony_ci if (MPI_ECP_CMP(&YY, &RHS) != 0) { 2748a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_INVALID_KEY; 2749a8e1175bSopenharmony_ci } 2750a8e1175bSopenharmony_ci 2751a8e1175bSopenharmony_cicleanup: 2752a8e1175bSopenharmony_ci 2753a8e1175bSopenharmony_ci mbedtls_mpi_free(&YY); mbedtls_mpi_free(&RHS); 2754a8e1175bSopenharmony_ci 2755a8e1175bSopenharmony_ci return ret; 2756a8e1175bSopenharmony_ci} 2757a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 2758a8e1175bSopenharmony_ci 2759a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 2760a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 2761a8e1175bSopenharmony_ci/* 2762a8e1175bSopenharmony_ci * R = m * P with shortcuts for m == 0, m == 1 and m == -1 2763a8e1175bSopenharmony_ci * NOT constant-time - ONLY for short Weierstrass! 2764a8e1175bSopenharmony_ci */ 2765a8e1175bSopenharmony_cistatic int mbedtls_ecp_mul_shortcuts(mbedtls_ecp_group *grp, 2766a8e1175bSopenharmony_ci mbedtls_ecp_point *R, 2767a8e1175bSopenharmony_ci const mbedtls_mpi *m, 2768a8e1175bSopenharmony_ci const mbedtls_ecp_point *P, 2769a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 2770a8e1175bSopenharmony_ci{ 2771a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2772a8e1175bSopenharmony_ci mbedtls_mpi tmp; 2773a8e1175bSopenharmony_ci mbedtls_mpi_init(&tmp); 2774a8e1175bSopenharmony_ci 2775a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_int(m, 0) == 0) { 2776a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 2777a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R)); 2778a8e1175bSopenharmony_ci } else if (mbedtls_mpi_cmp_int(m, 1) == 0) { 2779a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 2780a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); 2781a8e1175bSopenharmony_ci } else if (mbedtls_mpi_cmp_int(m, -1) == 0) { 2782a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 2783a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); 2784a8e1175bSopenharmony_ci MPI_ECP_NEG(&R->Y); 2785a8e1175bSopenharmony_ci } else { 2786a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_mul_restartable_internal(grp, R, m, P, 2787a8e1175bSopenharmony_ci NULL, NULL, rs_ctx)); 2788a8e1175bSopenharmony_ci } 2789a8e1175bSopenharmony_ci 2790a8e1175bSopenharmony_cicleanup: 2791a8e1175bSopenharmony_ci mbedtls_mpi_free(&tmp); 2792a8e1175bSopenharmony_ci 2793a8e1175bSopenharmony_ci return ret; 2794a8e1175bSopenharmony_ci} 2795a8e1175bSopenharmony_ci 2796a8e1175bSopenharmony_ci/* 2797a8e1175bSopenharmony_ci * Restartable linear combination 2798a8e1175bSopenharmony_ci * NOT constant-time 2799a8e1175bSopenharmony_ci */ 2800a8e1175bSopenharmony_ciint mbedtls_ecp_muladd_restartable( 2801a8e1175bSopenharmony_ci mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2802a8e1175bSopenharmony_ci const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2803a8e1175bSopenharmony_ci const mbedtls_mpi *n, const mbedtls_ecp_point *Q, 2804a8e1175bSopenharmony_ci mbedtls_ecp_restart_ctx *rs_ctx) 2805a8e1175bSopenharmony_ci{ 2806a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2807a8e1175bSopenharmony_ci mbedtls_ecp_point mP; 2808a8e1175bSopenharmony_ci mbedtls_ecp_point *pmP = &mP; 2809a8e1175bSopenharmony_ci mbedtls_ecp_point *pR = R; 2810a8e1175bSopenharmony_ci mbedtls_mpi tmp[4]; 2811a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_INTERNAL_ALT) 2812a8e1175bSopenharmony_ci char is_grp_capable = 0; 2813a8e1175bSopenharmony_ci#endif 2814a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 2815a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 2816a8e1175bSopenharmony_ci } 2817a8e1175bSopenharmony_ci 2818a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&mP); 2819a8e1175bSopenharmony_ci mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2820a8e1175bSopenharmony_ci 2821a8e1175bSopenharmony_ci ECP_RS_ENTER(ma); 2822a8e1175bSopenharmony_ci 2823a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2824a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->ma != NULL) { 2825a8e1175bSopenharmony_ci /* redirect intermediate results to restart context */ 2826a8e1175bSopenharmony_ci pmP = &rs_ctx->ma->mP; 2827a8e1175bSopenharmony_ci pR = &rs_ctx->ma->R; 2828a8e1175bSopenharmony_ci 2829a8e1175bSopenharmony_ci /* jump to next operation */ 2830a8e1175bSopenharmony_ci if (rs_ctx->ma->state == ecp_rsma_mul2) { 2831a8e1175bSopenharmony_ci goto mul2; 2832a8e1175bSopenharmony_ci } 2833a8e1175bSopenharmony_ci if (rs_ctx->ma->state == ecp_rsma_add) { 2834a8e1175bSopenharmony_ci goto add; 2835a8e1175bSopenharmony_ci } 2836a8e1175bSopenharmony_ci if (rs_ctx->ma->state == ecp_rsma_norm) { 2837a8e1175bSopenharmony_ci goto norm; 2838a8e1175bSopenharmony_ci } 2839a8e1175bSopenharmony_ci } 2840a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_RESTARTABLE */ 2841a8e1175bSopenharmony_ci 2842a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pmP, m, P, rs_ctx)); 2843a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2844a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->ma != NULL) { 2845a8e1175bSopenharmony_ci rs_ctx->ma->state = ecp_rsma_mul2; 2846a8e1175bSopenharmony_ci } 2847a8e1175bSopenharmony_ci 2848a8e1175bSopenharmony_cimul2: 2849a8e1175bSopenharmony_ci#endif 2850a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pR, n, Q, rs_ctx)); 2851a8e1175bSopenharmony_ci 2852a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_INTERNAL_ALT) 2853a8e1175bSopenharmony_ci if ((is_grp_capable = mbedtls_internal_ecp_grp_capable(grp))) { 2854a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_internal_ecp_init(grp)); 2855a8e1175bSopenharmony_ci } 2856a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_INTERNAL_ALT */ 2857a8e1175bSopenharmony_ci 2858a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2859a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->ma != NULL) { 2860a8e1175bSopenharmony_ci rs_ctx->ma->state = ecp_rsma_add; 2861a8e1175bSopenharmony_ci } 2862a8e1175bSopenharmony_ci 2863a8e1175bSopenharmony_ciadd: 2864a8e1175bSopenharmony_ci#endif 2865a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_ADD); 2866a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_add_mixed(grp, pR, pmP, pR, tmp)); 2867a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2868a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->ma != NULL) { 2869a8e1175bSopenharmony_ci rs_ctx->ma->state = ecp_rsma_norm; 2870a8e1175bSopenharmony_ci } 2871a8e1175bSopenharmony_ci 2872a8e1175bSopenharmony_cinorm: 2873a8e1175bSopenharmony_ci#endif 2874a8e1175bSopenharmony_ci MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV); 2875a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, pR)); 2876a8e1175bSopenharmony_ci 2877a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_RESTARTABLE) 2878a8e1175bSopenharmony_ci if (rs_ctx != NULL && rs_ctx->ma != NULL) { 2879a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, pR)); 2880a8e1175bSopenharmony_ci } 2881a8e1175bSopenharmony_ci#endif 2882a8e1175bSopenharmony_ci 2883a8e1175bSopenharmony_cicleanup: 2884a8e1175bSopenharmony_ci 2885a8e1175bSopenharmony_ci mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2886a8e1175bSopenharmony_ci 2887a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_INTERNAL_ALT) 2888a8e1175bSopenharmony_ci if (is_grp_capable) { 2889a8e1175bSopenharmony_ci mbedtls_internal_ecp_free(grp); 2890a8e1175bSopenharmony_ci } 2891a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_INTERNAL_ALT */ 2892a8e1175bSopenharmony_ci 2893a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&mP); 2894a8e1175bSopenharmony_ci 2895a8e1175bSopenharmony_ci ECP_RS_LEAVE(ma); 2896a8e1175bSopenharmony_ci 2897a8e1175bSopenharmony_ci return ret; 2898a8e1175bSopenharmony_ci} 2899a8e1175bSopenharmony_ci 2900a8e1175bSopenharmony_ci/* 2901a8e1175bSopenharmony_ci * Linear combination 2902a8e1175bSopenharmony_ci * NOT constant-time 2903a8e1175bSopenharmony_ci */ 2904a8e1175bSopenharmony_ciint mbedtls_ecp_muladd(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2905a8e1175bSopenharmony_ci const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2906a8e1175bSopenharmony_ci const mbedtls_mpi *n, const mbedtls_ecp_point *Q) 2907a8e1175bSopenharmony_ci{ 2908a8e1175bSopenharmony_ci return mbedtls_ecp_muladd_restartable(grp, R, m, P, n, Q, NULL); 2909a8e1175bSopenharmony_ci} 2910a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 2911a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 2912a8e1175bSopenharmony_ci 2913a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 2914a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 2915a8e1175bSopenharmony_ci#define ECP_MPI_INIT(_p, _n) { .p = (mbedtls_mpi_uint *) (_p), .s = 1, .n = (_n) } 2916a8e1175bSopenharmony_ci#define ECP_MPI_INIT_ARRAY(x) \ 2917a8e1175bSopenharmony_ci ECP_MPI_INIT(x, sizeof(x) / sizeof(mbedtls_mpi_uint)) 2918a8e1175bSopenharmony_ci/* 2919a8e1175bSopenharmony_ci * Constants for the two points other than 0, 1, -1 (mod p) in 2920a8e1175bSopenharmony_ci * https://cr.yp.to/ecdh.html#validate 2921a8e1175bSopenharmony_ci * See ecp_check_pubkey_x25519(). 2922a8e1175bSopenharmony_ci */ 2923a8e1175bSopenharmony_cistatic const mbedtls_mpi_uint x25519_bad_point_1[] = { 2924a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae), 2925a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a), 2926a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd), 2927a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00), 2928a8e1175bSopenharmony_ci}; 2929a8e1175bSopenharmony_cistatic const mbedtls_mpi_uint x25519_bad_point_2[] = { 2930a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24), 2931a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b), 2932a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86), 2933a8e1175bSopenharmony_ci MBEDTLS_BYTES_TO_T_UINT_8(0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57), 2934a8e1175bSopenharmony_ci}; 2935a8e1175bSopenharmony_cistatic const mbedtls_mpi ecp_x25519_bad_point_1 = ECP_MPI_INIT_ARRAY( 2936a8e1175bSopenharmony_ci x25519_bad_point_1); 2937a8e1175bSopenharmony_cistatic const mbedtls_mpi ecp_x25519_bad_point_2 = ECP_MPI_INIT_ARRAY( 2938a8e1175bSopenharmony_ci x25519_bad_point_2); 2939a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ 2940a8e1175bSopenharmony_ci 2941a8e1175bSopenharmony_ci/* 2942a8e1175bSopenharmony_ci * Check that the input point is not one of the low-order points. 2943a8e1175bSopenharmony_ci * This is recommended by the "May the Fourth" paper: 2944a8e1175bSopenharmony_ci * https://eprint.iacr.org/2017/806.pdf 2945a8e1175bSopenharmony_ci * Those points are never sent by an honest peer. 2946a8e1175bSopenharmony_ci */ 2947a8e1175bSopenharmony_cistatic int ecp_check_bad_points_mx(const mbedtls_mpi *X, const mbedtls_mpi *P, 2948a8e1175bSopenharmony_ci const mbedtls_ecp_group_id grp_id) 2949a8e1175bSopenharmony_ci{ 2950a8e1175bSopenharmony_ci int ret; 2951a8e1175bSopenharmony_ci mbedtls_mpi XmP; 2952a8e1175bSopenharmony_ci 2953a8e1175bSopenharmony_ci mbedtls_mpi_init(&XmP); 2954a8e1175bSopenharmony_ci 2955a8e1175bSopenharmony_ci /* Reduce X mod P so that we only need to check values less than P. 2956a8e1175bSopenharmony_ci * We know X < 2^256 so we can proceed by subtraction. */ 2957a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&XmP, X)); 2958a8e1175bSopenharmony_ci while (mbedtls_mpi_cmp_mpi(&XmP, P) >= 0) { 2959a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&XmP, &XmP, P)); 2960a8e1175bSopenharmony_ci } 2961a8e1175bSopenharmony_ci 2962a8e1175bSopenharmony_ci /* Check against the known bad values that are less than P. For Curve448 2963a8e1175bSopenharmony_ci * these are 0, 1 and -1. For Curve25519 we check the values less than P 2964a8e1175bSopenharmony_ci * from the following list: https://cr.yp.to/ecdh.html#validate */ 2965a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_int(&XmP, 1) <= 0) { /* takes care of 0 and 1 */ 2966a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_INVALID_KEY; 2967a8e1175bSopenharmony_ci goto cleanup; 2968a8e1175bSopenharmony_ci } 2969a8e1175bSopenharmony_ci 2970a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 2971a8e1175bSopenharmony_ci if (grp_id == MBEDTLS_ECP_DP_CURVE25519) { 2972a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_1) == 0) { 2973a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_INVALID_KEY; 2974a8e1175bSopenharmony_ci goto cleanup; 2975a8e1175bSopenharmony_ci } 2976a8e1175bSopenharmony_ci 2977a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_2) == 0) { 2978a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_INVALID_KEY; 2979a8e1175bSopenharmony_ci goto cleanup; 2980a8e1175bSopenharmony_ci } 2981a8e1175bSopenharmony_ci } 2982a8e1175bSopenharmony_ci#else 2983a8e1175bSopenharmony_ci (void) grp_id; 2984a8e1175bSopenharmony_ci#endif 2985a8e1175bSopenharmony_ci 2986a8e1175bSopenharmony_ci /* Final check: check if XmP + 1 is P (final because it changes XmP!) */ 2987a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&XmP, &XmP, 1)); 2988a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_mpi(&XmP, P) == 0) { 2989a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_INVALID_KEY; 2990a8e1175bSopenharmony_ci goto cleanup; 2991a8e1175bSopenharmony_ci } 2992a8e1175bSopenharmony_ci 2993a8e1175bSopenharmony_ci ret = 0; 2994a8e1175bSopenharmony_ci 2995a8e1175bSopenharmony_cicleanup: 2996a8e1175bSopenharmony_ci mbedtls_mpi_free(&XmP); 2997a8e1175bSopenharmony_ci 2998a8e1175bSopenharmony_ci return ret; 2999a8e1175bSopenharmony_ci} 3000a8e1175bSopenharmony_ci 3001a8e1175bSopenharmony_ci/* 3002a8e1175bSopenharmony_ci * Check validity of a public key for Montgomery curves with x-only schemes 3003a8e1175bSopenharmony_ci */ 3004a8e1175bSopenharmony_cistatic int ecp_check_pubkey_mx(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) 3005a8e1175bSopenharmony_ci{ 3006a8e1175bSopenharmony_ci /* [Curve25519 p. 5] Just check X is the correct number of bytes */ 3007a8e1175bSopenharmony_ci /* Allow any public value, if it's too big then we'll just reduce it mod p 3008a8e1175bSopenharmony_ci * (RFC 7748 sec. 5 para. 3). */ 3009a8e1175bSopenharmony_ci if (mbedtls_mpi_size(&pt->X) > (grp->nbits + 7) / 8) { 3010a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3011a8e1175bSopenharmony_ci } 3012a8e1175bSopenharmony_ci 3013a8e1175bSopenharmony_ci /* Implicit in all standards (as they don't consider negative numbers): 3014a8e1175bSopenharmony_ci * X must be non-negative. This is normally ensured by the way it's 3015a8e1175bSopenharmony_ci * encoded for transmission, but let's be extra sure. */ 3016a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0) { 3017a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3018a8e1175bSopenharmony_ci } 3019a8e1175bSopenharmony_ci 3020a8e1175bSopenharmony_ci return ecp_check_bad_points_mx(&pt->X, &grp->P, grp->id); 3021a8e1175bSopenharmony_ci} 3022a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3023a8e1175bSopenharmony_ci 3024a8e1175bSopenharmony_ci/* 3025a8e1175bSopenharmony_ci * Check that a point is valid as a public key 3026a8e1175bSopenharmony_ci */ 3027a8e1175bSopenharmony_ciint mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp, 3028a8e1175bSopenharmony_ci const mbedtls_ecp_point *pt) 3029a8e1175bSopenharmony_ci{ 3030a8e1175bSopenharmony_ci /* Must use affine coordinates */ 3031a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_int(&pt->Z, 1) != 0) { 3032a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3033a8e1175bSopenharmony_ci } 3034a8e1175bSopenharmony_ci 3035a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3036a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 3037a8e1175bSopenharmony_ci return ecp_check_pubkey_mx(grp, pt); 3038a8e1175bSopenharmony_ci } 3039a8e1175bSopenharmony_ci#endif 3040a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3041a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3042a8e1175bSopenharmony_ci return ecp_check_pubkey_sw(grp, pt); 3043a8e1175bSopenharmony_ci } 3044a8e1175bSopenharmony_ci#endif 3045a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3046a8e1175bSopenharmony_ci} 3047a8e1175bSopenharmony_ci 3048a8e1175bSopenharmony_ci/* 3049a8e1175bSopenharmony_ci * Check that an mbedtls_mpi is valid as a private key 3050a8e1175bSopenharmony_ci */ 3051a8e1175bSopenharmony_ciint mbedtls_ecp_check_privkey(const mbedtls_ecp_group *grp, 3052a8e1175bSopenharmony_ci const mbedtls_mpi *d) 3053a8e1175bSopenharmony_ci{ 3054a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3055a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 3056a8e1175bSopenharmony_ci /* see RFC 7748 sec. 5 para. 5 */ 3057a8e1175bSopenharmony_ci if (mbedtls_mpi_get_bit(d, 0) != 0 || 3058a8e1175bSopenharmony_ci mbedtls_mpi_get_bit(d, 1) != 0 || 3059a8e1175bSopenharmony_ci mbedtls_mpi_bitlen(d) - 1 != grp->nbits) { /* mbedtls_mpi_bitlen is one-based! */ 3060a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3061a8e1175bSopenharmony_ci } 3062a8e1175bSopenharmony_ci 3063a8e1175bSopenharmony_ci /* see [Curve25519] page 5 */ 3064a8e1175bSopenharmony_ci if (grp->nbits == 254 && mbedtls_mpi_get_bit(d, 2) != 0) { 3065a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3066a8e1175bSopenharmony_ci } 3067a8e1175bSopenharmony_ci 3068a8e1175bSopenharmony_ci return 0; 3069a8e1175bSopenharmony_ci } 3070a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3071a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3072a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3073a8e1175bSopenharmony_ci /* see SEC1 3.2 */ 3074a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_int(d, 1) < 0 || 3075a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0) { 3076a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3077a8e1175bSopenharmony_ci } else { 3078a8e1175bSopenharmony_ci return 0; 3079a8e1175bSopenharmony_ci } 3080a8e1175bSopenharmony_ci } 3081a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 3082a8e1175bSopenharmony_ci 3083a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3084a8e1175bSopenharmony_ci} 3085a8e1175bSopenharmony_ci 3086a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3087a8e1175bSopenharmony_ciMBEDTLS_STATIC_TESTABLE 3088a8e1175bSopenharmony_ciint mbedtls_ecp_gen_privkey_mx(size_t high_bit, 3089a8e1175bSopenharmony_ci mbedtls_mpi *d, 3090a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 3091a8e1175bSopenharmony_ci void *p_rng) 3092a8e1175bSopenharmony_ci{ 3093a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3094a8e1175bSopenharmony_ci size_t n_random_bytes = high_bit / 8 + 1; 3095a8e1175bSopenharmony_ci 3096a8e1175bSopenharmony_ci /* [Curve25519] page 5 */ 3097a8e1175bSopenharmony_ci /* Generate a (high_bit+1)-bit random number by generating just enough 3098a8e1175bSopenharmony_ci * random bytes, then shifting out extra bits from the top (necessary 3099a8e1175bSopenharmony_ci * when (high_bit+1) is not a multiple of 8). */ 3100a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(d, n_random_bytes, 3101a8e1175bSopenharmony_ci f_rng, p_rng)); 3102a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(d, 8 * n_random_bytes - high_bit - 1)); 3103a8e1175bSopenharmony_ci 3104a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, high_bit, 1)); 3105a8e1175bSopenharmony_ci 3106a8e1175bSopenharmony_ci /* Make sure the last two bits are unset for Curve448, three bits for 3107a8e1175bSopenharmony_ci Curve25519 */ 3108a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 0, 0)); 3109a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 1, 0)); 3110a8e1175bSopenharmony_ci if (high_bit == 254) { 3111a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 2, 0)); 3112a8e1175bSopenharmony_ci } 3113a8e1175bSopenharmony_ci 3114a8e1175bSopenharmony_cicleanup: 3115a8e1175bSopenharmony_ci return ret; 3116a8e1175bSopenharmony_ci} 3117a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3118a8e1175bSopenharmony_ci 3119a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3120a8e1175bSopenharmony_cistatic int mbedtls_ecp_gen_privkey_sw( 3121a8e1175bSopenharmony_ci const mbedtls_mpi *N, mbedtls_mpi *d, 3122a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 3123a8e1175bSopenharmony_ci{ 3124a8e1175bSopenharmony_ci int ret = mbedtls_mpi_random(d, 1, N, f_rng, p_rng); 3125a8e1175bSopenharmony_ci switch (ret) { 3126a8e1175bSopenharmony_ci case MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: 3127a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_RANDOM_FAILED; 3128a8e1175bSopenharmony_ci default: 3129a8e1175bSopenharmony_ci return ret; 3130a8e1175bSopenharmony_ci } 3131a8e1175bSopenharmony_ci} 3132a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 3133a8e1175bSopenharmony_ci 3134a8e1175bSopenharmony_ci/* 3135a8e1175bSopenharmony_ci * Generate a private key 3136a8e1175bSopenharmony_ci */ 3137a8e1175bSopenharmony_ciint mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp, 3138a8e1175bSopenharmony_ci mbedtls_mpi *d, 3139a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 3140a8e1175bSopenharmony_ci void *p_rng) 3141a8e1175bSopenharmony_ci{ 3142a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3143a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 3144a8e1175bSopenharmony_ci return mbedtls_ecp_gen_privkey_mx(grp->nbits, d, f_rng, p_rng); 3145a8e1175bSopenharmony_ci } 3146a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3147a8e1175bSopenharmony_ci 3148a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3149a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3150a8e1175bSopenharmony_ci return mbedtls_ecp_gen_privkey_sw(&grp->N, d, f_rng, p_rng); 3151a8e1175bSopenharmony_ci } 3152a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 3153a8e1175bSopenharmony_ci 3154a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3155a8e1175bSopenharmony_ci} 3156a8e1175bSopenharmony_ci 3157a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 3158a8e1175bSopenharmony_ci/* 3159a8e1175bSopenharmony_ci * Generate a keypair with configurable base point 3160a8e1175bSopenharmony_ci */ 3161a8e1175bSopenharmony_ciint mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp, 3162a8e1175bSopenharmony_ci const mbedtls_ecp_point *G, 3163a8e1175bSopenharmony_ci mbedtls_mpi *d, mbedtls_ecp_point *Q, 3164a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 3165a8e1175bSopenharmony_ci void *p_rng) 3166a8e1175bSopenharmony_ci{ 3167a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3168a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, d, f_rng, p_rng)); 3169a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, Q, d, G, f_rng, p_rng)); 3170a8e1175bSopenharmony_ci 3171a8e1175bSopenharmony_cicleanup: 3172a8e1175bSopenharmony_ci return ret; 3173a8e1175bSopenharmony_ci} 3174a8e1175bSopenharmony_ci 3175a8e1175bSopenharmony_ci/* 3176a8e1175bSopenharmony_ci * Generate key pair, wrapper for conventional base point 3177a8e1175bSopenharmony_ci */ 3178a8e1175bSopenharmony_ciint mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp, 3179a8e1175bSopenharmony_ci mbedtls_mpi *d, mbedtls_ecp_point *Q, 3180a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 3181a8e1175bSopenharmony_ci void *p_rng) 3182a8e1175bSopenharmony_ci{ 3183a8e1175bSopenharmony_ci return mbedtls_ecp_gen_keypair_base(grp, &grp->G, d, Q, f_rng, p_rng); 3184a8e1175bSopenharmony_ci} 3185a8e1175bSopenharmony_ci 3186a8e1175bSopenharmony_ci/* 3187a8e1175bSopenharmony_ci * Generate a keypair, prettier wrapper 3188a8e1175bSopenharmony_ci */ 3189a8e1175bSopenharmony_ciint mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, 3190a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 3191a8e1175bSopenharmony_ci{ 3192a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3193a8e1175bSopenharmony_ci if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { 3194a8e1175bSopenharmony_ci return ret; 3195a8e1175bSopenharmony_ci } 3196a8e1175bSopenharmony_ci 3197a8e1175bSopenharmony_ci return mbedtls_ecp_gen_keypair(&key->grp, &key->d, &key->Q, f_rng, p_rng); 3198a8e1175bSopenharmony_ci} 3199a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 3200a8e1175bSopenharmony_ci 3201a8e1175bSopenharmony_ciint mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id, 3202a8e1175bSopenharmony_ci mbedtls_ecp_keypair *key, 3203a8e1175bSopenharmony_ci const mbedtls_ecp_point *Q) 3204a8e1175bSopenharmony_ci{ 3205a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3206a8e1175bSopenharmony_ci 3207a8e1175bSopenharmony_ci if (key->grp.id == MBEDTLS_ECP_DP_NONE) { 3208a8e1175bSopenharmony_ci /* Group not set yet */ 3209a8e1175bSopenharmony_ci if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { 3210a8e1175bSopenharmony_ci return ret; 3211a8e1175bSopenharmony_ci } 3212a8e1175bSopenharmony_ci } else if (key->grp.id != grp_id) { 3213a8e1175bSopenharmony_ci /* Group mismatch */ 3214a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3215a8e1175bSopenharmony_ci } 3216a8e1175bSopenharmony_ci return mbedtls_ecp_copy(&key->Q, Q); 3217a8e1175bSopenharmony_ci} 3218a8e1175bSopenharmony_ci 3219a8e1175bSopenharmony_ci 3220a8e1175bSopenharmony_ci#define ECP_CURVE25519_KEY_SIZE 32 3221a8e1175bSopenharmony_ci#define ECP_CURVE448_KEY_SIZE 56 3222a8e1175bSopenharmony_ci/* 3223a8e1175bSopenharmony_ci * Read a private key. 3224a8e1175bSopenharmony_ci */ 3225a8e1175bSopenharmony_ciint mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, 3226a8e1175bSopenharmony_ci const unsigned char *buf, size_t buflen) 3227a8e1175bSopenharmony_ci{ 3228a8e1175bSopenharmony_ci int ret = 0; 3229a8e1175bSopenharmony_ci 3230a8e1175bSopenharmony_ci if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { 3231a8e1175bSopenharmony_ci return ret; 3232a8e1175bSopenharmony_ci } 3233a8e1175bSopenharmony_ci 3234a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 3235a8e1175bSopenharmony_ci 3236a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3237a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 3238a8e1175bSopenharmony_ci /* 3239a8e1175bSopenharmony_ci * Mask the key as mandated by RFC7748 for Curve25519 and Curve448. 3240a8e1175bSopenharmony_ci */ 3241a8e1175bSopenharmony_ci if (grp_id == MBEDTLS_ECP_DP_CURVE25519) { 3242a8e1175bSopenharmony_ci if (buflen != ECP_CURVE25519_KEY_SIZE) { 3243a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3244a8e1175bSopenharmony_ci } 3245a8e1175bSopenharmony_ci 3246a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen)); 3247a8e1175bSopenharmony_ci 3248a8e1175bSopenharmony_ci /* Set the three least significant bits to 0 */ 3249a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0)); 3250a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0)); 3251a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 2, 0)); 3252a8e1175bSopenharmony_ci 3253a8e1175bSopenharmony_ci /* Set the most significant bit to 0 */ 3254a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK( 3255a8e1175bSopenharmony_ci mbedtls_mpi_set_bit(&key->d, 3256a8e1175bSopenharmony_ci ECP_CURVE25519_KEY_SIZE * 8 - 1, 0) 3257a8e1175bSopenharmony_ci ); 3258a8e1175bSopenharmony_ci 3259a8e1175bSopenharmony_ci /* Set the second most significant bit to 1 */ 3260a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK( 3261a8e1175bSopenharmony_ci mbedtls_mpi_set_bit(&key->d, 3262a8e1175bSopenharmony_ci ECP_CURVE25519_KEY_SIZE * 8 - 2, 1) 3263a8e1175bSopenharmony_ci ); 3264a8e1175bSopenharmony_ci } else if (grp_id == MBEDTLS_ECP_DP_CURVE448) { 3265a8e1175bSopenharmony_ci if (buflen != ECP_CURVE448_KEY_SIZE) { 3266a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_INVALID_KEY; 3267a8e1175bSopenharmony_ci } 3268a8e1175bSopenharmony_ci 3269a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen)); 3270a8e1175bSopenharmony_ci 3271a8e1175bSopenharmony_ci /* Set the two least significant bits to 0 */ 3272a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0)); 3273a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0)); 3274a8e1175bSopenharmony_ci 3275a8e1175bSopenharmony_ci /* Set the most significant bit to 1 */ 3276a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK( 3277a8e1175bSopenharmony_ci mbedtls_mpi_set_bit(&key->d, 3278a8e1175bSopenharmony_ci ECP_CURVE448_KEY_SIZE * 8 - 1, 1) 3279a8e1175bSopenharmony_ci ); 3280a8e1175bSopenharmony_ci } 3281a8e1175bSopenharmony_ci } 3282a8e1175bSopenharmony_ci#endif 3283a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3284a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3285a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&key->d, buf, buflen)); 3286a8e1175bSopenharmony_ci } 3287a8e1175bSopenharmony_ci#endif 3288a8e1175bSopenharmony_ci 3289a8e1175bSopenharmony_ci if (ret == 0) { 3290a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(&key->grp, &key->d)); 3291a8e1175bSopenharmony_ci } 3292a8e1175bSopenharmony_ci 3293a8e1175bSopenharmony_cicleanup: 3294a8e1175bSopenharmony_ci 3295a8e1175bSopenharmony_ci if (ret != 0) { 3296a8e1175bSopenharmony_ci mbedtls_mpi_free(&key->d); 3297a8e1175bSopenharmony_ci } 3298a8e1175bSopenharmony_ci 3299a8e1175bSopenharmony_ci return ret; 3300a8e1175bSopenharmony_ci} 3301a8e1175bSopenharmony_ci 3302a8e1175bSopenharmony_ci/* 3303a8e1175bSopenharmony_ci * Write a private key. 3304a8e1175bSopenharmony_ci */ 3305a8e1175bSopenharmony_ci#if !defined MBEDTLS_DEPRECATED_REMOVED 3306a8e1175bSopenharmony_ciint mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, 3307a8e1175bSopenharmony_ci unsigned char *buf, size_t buflen) 3308a8e1175bSopenharmony_ci{ 3309a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3310a8e1175bSopenharmony_ci 3311a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3312a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 3313a8e1175bSopenharmony_ci if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) { 3314a8e1175bSopenharmony_ci if (buflen < ECP_CURVE25519_KEY_SIZE) { 3315a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 3316a8e1175bSopenharmony_ci } 3317a8e1175bSopenharmony_ci 3318a8e1175bSopenharmony_ci } else if (key->grp.id == MBEDTLS_ECP_DP_CURVE448) { 3319a8e1175bSopenharmony_ci if (buflen < ECP_CURVE448_KEY_SIZE) { 3320a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 3321a8e1175bSopenharmony_ci } 3322a8e1175bSopenharmony_ci } 3323a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&key->d, buf, buflen)); 3324a8e1175bSopenharmony_ci } 3325a8e1175bSopenharmony_ci#endif 3326a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3327a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3328a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&key->d, buf, buflen)); 3329a8e1175bSopenharmony_ci } 3330a8e1175bSopenharmony_ci 3331a8e1175bSopenharmony_ci#endif 3332a8e1175bSopenharmony_cicleanup: 3333a8e1175bSopenharmony_ci 3334a8e1175bSopenharmony_ci return ret; 3335a8e1175bSopenharmony_ci} 3336a8e1175bSopenharmony_ci#endif /* MBEDTLS_DEPRECATED_REMOVED */ 3337a8e1175bSopenharmony_ci 3338a8e1175bSopenharmony_ciint mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key, 3339a8e1175bSopenharmony_ci size_t *olen, unsigned char *buf, size_t buflen) 3340a8e1175bSopenharmony_ci{ 3341a8e1175bSopenharmony_ci size_t len = (key->grp.nbits + 7) / 8; 3342a8e1175bSopenharmony_ci if (len > buflen) { 3343a8e1175bSopenharmony_ci /* For robustness, ensure *olen <= buflen even on error. */ 3344a8e1175bSopenharmony_ci *olen = 0; 3345a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 3346a8e1175bSopenharmony_ci } 3347a8e1175bSopenharmony_ci *olen = len; 3348a8e1175bSopenharmony_ci 3349a8e1175bSopenharmony_ci /* Private key not set */ 3350a8e1175bSopenharmony_ci if (key->d.n == 0) { 3351a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3352a8e1175bSopenharmony_ci } 3353a8e1175bSopenharmony_ci 3354a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3355a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 3356a8e1175bSopenharmony_ci return mbedtls_mpi_write_binary_le(&key->d, buf, len); 3357a8e1175bSopenharmony_ci } 3358a8e1175bSopenharmony_ci#endif 3359a8e1175bSopenharmony_ci 3360a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3361a8e1175bSopenharmony_ci if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3362a8e1175bSopenharmony_ci return mbedtls_mpi_write_binary(&key->d, buf, len); 3363a8e1175bSopenharmony_ci } 3364a8e1175bSopenharmony_ci#endif 3365a8e1175bSopenharmony_ci 3366a8e1175bSopenharmony_ci /* Private key set but no recognized curve type? This shouldn't happen. */ 3367a8e1175bSopenharmony_ci return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3368a8e1175bSopenharmony_ci} 3369a8e1175bSopenharmony_ci 3370a8e1175bSopenharmony_ci/* 3371a8e1175bSopenharmony_ci * Write a public key. 3372a8e1175bSopenharmony_ci */ 3373a8e1175bSopenharmony_ciint mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key, 3374a8e1175bSopenharmony_ci int format, size_t *olen, 3375a8e1175bSopenharmony_ci unsigned char *buf, size_t buflen) 3376a8e1175bSopenharmony_ci{ 3377a8e1175bSopenharmony_ci return mbedtls_ecp_point_write_binary(&key->grp, &key->Q, 3378a8e1175bSopenharmony_ci format, olen, buf, buflen); 3379a8e1175bSopenharmony_ci} 3380a8e1175bSopenharmony_ci 3381a8e1175bSopenharmony_ci 3382a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 3383a8e1175bSopenharmony_ci/* 3384a8e1175bSopenharmony_ci * Check a public-private key pair 3385a8e1175bSopenharmony_ci */ 3386a8e1175bSopenharmony_ciint mbedtls_ecp_check_pub_priv( 3387a8e1175bSopenharmony_ci const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv, 3388a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 3389a8e1175bSopenharmony_ci{ 3390a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3391a8e1175bSopenharmony_ci mbedtls_ecp_point Q; 3392a8e1175bSopenharmony_ci mbedtls_ecp_group grp; 3393a8e1175bSopenharmony_ci if (pub->grp.id == MBEDTLS_ECP_DP_NONE || 3394a8e1175bSopenharmony_ci pub->grp.id != prv->grp.id || 3395a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&pub->Q.X, &prv->Q.X) || 3396a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&pub->Q.Y, &prv->Q.Y) || 3397a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&pub->Q.Z, &prv->Q.Z)) { 3398a8e1175bSopenharmony_ci return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3399a8e1175bSopenharmony_ci } 3400a8e1175bSopenharmony_ci 3401a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&Q); 3402a8e1175bSopenharmony_ci mbedtls_ecp_group_init(&grp); 3403a8e1175bSopenharmony_ci 3404a8e1175bSopenharmony_ci /* mbedtls_ecp_mul() needs a non-const group... */ 3405a8e1175bSopenharmony_ci mbedtls_ecp_group_copy(&grp, &prv->grp); 3406a8e1175bSopenharmony_ci 3407a8e1175bSopenharmony_ci /* Also checks d is valid */ 3408a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &Q, &prv->d, &prv->grp.G, f_rng, p_rng)); 3409a8e1175bSopenharmony_ci 3410a8e1175bSopenharmony_ci if (mbedtls_mpi_cmp_mpi(&Q.X, &prv->Q.X) || 3411a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&Q.Y, &prv->Q.Y) || 3412a8e1175bSopenharmony_ci mbedtls_mpi_cmp_mpi(&Q.Z, &prv->Q.Z)) { 3413a8e1175bSopenharmony_ci ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3414a8e1175bSopenharmony_ci goto cleanup; 3415a8e1175bSopenharmony_ci } 3416a8e1175bSopenharmony_ci 3417a8e1175bSopenharmony_cicleanup: 3418a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&Q); 3419a8e1175bSopenharmony_ci mbedtls_ecp_group_free(&grp); 3420a8e1175bSopenharmony_ci 3421a8e1175bSopenharmony_ci return ret; 3422a8e1175bSopenharmony_ci} 3423a8e1175bSopenharmony_ci 3424a8e1175bSopenharmony_ciint mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair *key, 3425a8e1175bSopenharmony_ci int (*f_rng)(void *, unsigned char *, size_t), 3426a8e1175bSopenharmony_ci void *p_rng) 3427a8e1175bSopenharmony_ci{ 3428a8e1175bSopenharmony_ci return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, 3429a8e1175bSopenharmony_ci f_rng, p_rng); 3430a8e1175bSopenharmony_ci} 3431a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 3432a8e1175bSopenharmony_ci 3433a8e1175bSopenharmony_cimbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id( 3434a8e1175bSopenharmony_ci const mbedtls_ecp_keypair *key) 3435a8e1175bSopenharmony_ci{ 3436a8e1175bSopenharmony_ci return key->grp.id; 3437a8e1175bSopenharmony_ci} 3438a8e1175bSopenharmony_ci 3439a8e1175bSopenharmony_ci/* 3440a8e1175bSopenharmony_ci * Export generic key-pair parameters. 3441a8e1175bSopenharmony_ci */ 3442a8e1175bSopenharmony_ciint mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp, 3443a8e1175bSopenharmony_ci mbedtls_mpi *d, mbedtls_ecp_point *Q) 3444a8e1175bSopenharmony_ci{ 3445a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3446a8e1175bSopenharmony_ci 3447a8e1175bSopenharmony_ci if (grp != NULL && (ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) { 3448a8e1175bSopenharmony_ci return ret; 3449a8e1175bSopenharmony_ci } 3450a8e1175bSopenharmony_ci 3451a8e1175bSopenharmony_ci if (d != NULL && (ret = mbedtls_mpi_copy(d, &key->d)) != 0) { 3452a8e1175bSopenharmony_ci return ret; 3453a8e1175bSopenharmony_ci } 3454a8e1175bSopenharmony_ci 3455a8e1175bSopenharmony_ci if (Q != NULL && (ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) { 3456a8e1175bSopenharmony_ci return ret; 3457a8e1175bSopenharmony_ci } 3458a8e1175bSopenharmony_ci 3459a8e1175bSopenharmony_ci return 0; 3460a8e1175bSopenharmony_ci} 3461a8e1175bSopenharmony_ci 3462a8e1175bSopenharmony_ci#if defined(MBEDTLS_SELF_TEST) 3463a8e1175bSopenharmony_ci 3464a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 3465a8e1175bSopenharmony_ci/* 3466a8e1175bSopenharmony_ci * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!! 3467a8e1175bSopenharmony_ci * 3468a8e1175bSopenharmony_ci * This is the linear congruential generator from numerical recipes, 3469a8e1175bSopenharmony_ci * except we only use the low byte as the output. See 3470a8e1175bSopenharmony_ci * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use 3471a8e1175bSopenharmony_ci */ 3472a8e1175bSopenharmony_cistatic int self_test_rng(void *ctx, unsigned char *out, size_t len) 3473a8e1175bSopenharmony_ci{ 3474a8e1175bSopenharmony_ci static uint32_t state = 42; 3475a8e1175bSopenharmony_ci 3476a8e1175bSopenharmony_ci (void) ctx; 3477a8e1175bSopenharmony_ci 3478a8e1175bSopenharmony_ci for (size_t i = 0; i < len; i++) { 3479a8e1175bSopenharmony_ci state = state * 1664525u + 1013904223u; 3480a8e1175bSopenharmony_ci out[i] = (unsigned char) state; 3481a8e1175bSopenharmony_ci } 3482a8e1175bSopenharmony_ci 3483a8e1175bSopenharmony_ci return 0; 3484a8e1175bSopenharmony_ci} 3485a8e1175bSopenharmony_ci 3486a8e1175bSopenharmony_ci/* Adjust the exponent to be a valid private point for the specified curve. 3487a8e1175bSopenharmony_ci * This is sometimes necessary because we use a single set of exponents 3488a8e1175bSopenharmony_ci * for all curves but the validity of values depends on the curve. */ 3489a8e1175bSopenharmony_cistatic int self_test_adjust_exponent(const mbedtls_ecp_group *grp, 3490a8e1175bSopenharmony_ci mbedtls_mpi *m) 3491a8e1175bSopenharmony_ci{ 3492a8e1175bSopenharmony_ci int ret = 0; 3493a8e1175bSopenharmony_ci switch (grp->id) { 3494a8e1175bSopenharmony_ci /* If Curve25519 is available, then that's what we use for the 3495a8e1175bSopenharmony_ci * Montgomery test, so we don't need the adjustment code. */ 3496a8e1175bSopenharmony_ci#if !defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 3497a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) 3498a8e1175bSopenharmony_ci case MBEDTLS_ECP_DP_CURVE448: 3499a8e1175bSopenharmony_ci /* Move highest bit from 254 to N-1. Setting bit N-1 is 3500a8e1175bSopenharmony_ci * necessary to enforce the highest-bit-set constraint. */ 3501a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, 254, 0)); 3502a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, grp->nbits, 1)); 3503a8e1175bSopenharmony_ci /* Copy second-highest bit from 253 to N-2. This is not 3504a8e1175bSopenharmony_ci * necessary but improves the test variety a bit. */ 3505a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK( 3506a8e1175bSopenharmony_ci mbedtls_mpi_set_bit(m, grp->nbits - 1, 3507a8e1175bSopenharmony_ci mbedtls_mpi_get_bit(m, 253))); 3508a8e1175bSopenharmony_ci break; 3509a8e1175bSopenharmony_ci#endif 3510a8e1175bSopenharmony_ci#endif /* ! defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) */ 3511a8e1175bSopenharmony_ci default: 3512a8e1175bSopenharmony_ci /* Non-Montgomery curves and Curve25519 need no adjustment. */ 3513a8e1175bSopenharmony_ci (void) grp; 3514a8e1175bSopenharmony_ci (void) m; 3515a8e1175bSopenharmony_ci goto cleanup; 3516a8e1175bSopenharmony_ci } 3517a8e1175bSopenharmony_cicleanup: 3518a8e1175bSopenharmony_ci return ret; 3519a8e1175bSopenharmony_ci} 3520a8e1175bSopenharmony_ci 3521a8e1175bSopenharmony_ci/* Calculate R = m.P for each m in exponents. Check that the number of 3522a8e1175bSopenharmony_ci * basic operations doesn't depend on the value of m. */ 3523a8e1175bSopenharmony_cistatic int self_test_point(int verbose, 3524a8e1175bSopenharmony_ci mbedtls_ecp_group *grp, 3525a8e1175bSopenharmony_ci mbedtls_ecp_point *R, 3526a8e1175bSopenharmony_ci mbedtls_mpi *m, 3527a8e1175bSopenharmony_ci const mbedtls_ecp_point *P, 3528a8e1175bSopenharmony_ci const char *const *exponents, 3529a8e1175bSopenharmony_ci size_t n_exponents) 3530a8e1175bSopenharmony_ci{ 3531a8e1175bSopenharmony_ci int ret = 0; 3532a8e1175bSopenharmony_ci size_t i = 0; 3533a8e1175bSopenharmony_ci unsigned long add_c_prev, dbl_c_prev, mul_c_prev; 3534a8e1175bSopenharmony_ci add_count = 0; 3535a8e1175bSopenharmony_ci dbl_count = 0; 3536a8e1175bSopenharmony_ci mul_count = 0; 3537a8e1175bSopenharmony_ci 3538a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[0])); 3539a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m)); 3540a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL)); 3541a8e1175bSopenharmony_ci 3542a8e1175bSopenharmony_ci for (i = 1; i < n_exponents; i++) { 3543a8e1175bSopenharmony_ci add_c_prev = add_count; 3544a8e1175bSopenharmony_ci dbl_c_prev = dbl_count; 3545a8e1175bSopenharmony_ci mul_c_prev = mul_count; 3546a8e1175bSopenharmony_ci add_count = 0; 3547a8e1175bSopenharmony_ci dbl_count = 0; 3548a8e1175bSopenharmony_ci mul_count = 0; 3549a8e1175bSopenharmony_ci 3550a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[i])); 3551a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m)); 3552a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL)); 3553a8e1175bSopenharmony_ci 3554a8e1175bSopenharmony_ci if (add_count != add_c_prev || 3555a8e1175bSopenharmony_ci dbl_count != dbl_c_prev || 3556a8e1175bSopenharmony_ci mul_count != mul_c_prev) { 3557a8e1175bSopenharmony_ci ret = 1; 3558a8e1175bSopenharmony_ci break; 3559a8e1175bSopenharmony_ci } 3560a8e1175bSopenharmony_ci } 3561a8e1175bSopenharmony_ci 3562a8e1175bSopenharmony_cicleanup: 3563a8e1175bSopenharmony_ci if (verbose != 0) { 3564a8e1175bSopenharmony_ci if (ret != 0) { 3565a8e1175bSopenharmony_ci mbedtls_printf("failed (%u)\n", (unsigned int) i); 3566a8e1175bSopenharmony_ci } else { 3567a8e1175bSopenharmony_ci mbedtls_printf("passed\n"); 3568a8e1175bSopenharmony_ci } 3569a8e1175bSopenharmony_ci } 3570a8e1175bSopenharmony_ci return ret; 3571a8e1175bSopenharmony_ci} 3572a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 3573a8e1175bSopenharmony_ci 3574a8e1175bSopenharmony_ci/* 3575a8e1175bSopenharmony_ci * Checkup routine 3576a8e1175bSopenharmony_ci */ 3577a8e1175bSopenharmony_ciint mbedtls_ecp_self_test(int verbose) 3578a8e1175bSopenharmony_ci{ 3579a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_C) 3580a8e1175bSopenharmony_ci int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3581a8e1175bSopenharmony_ci mbedtls_ecp_group grp; 3582a8e1175bSopenharmony_ci mbedtls_ecp_point R, P; 3583a8e1175bSopenharmony_ci mbedtls_mpi m; 3584a8e1175bSopenharmony_ci 3585a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3586a8e1175bSopenharmony_ci /* Exponents especially adapted for secp192k1, which has the lowest 3587a8e1175bSopenharmony_ci * order n of all supported curves (secp192r1 is in a slightly larger 3588a8e1175bSopenharmony_ci * field but the order of its base point is slightly smaller). */ 3589a8e1175bSopenharmony_ci const char *sw_exponents[] = 3590a8e1175bSopenharmony_ci { 3591a8e1175bSopenharmony_ci "000000000000000000000000000000000000000000000001", /* one */ 3592a8e1175bSopenharmony_ci "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8C", /* n - 1 */ 3593a8e1175bSopenharmony_ci "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */ 3594a8e1175bSopenharmony_ci "400000000000000000000000000000000000000000000000", /* one and zeros */ 3595a8e1175bSopenharmony_ci "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */ 3596a8e1175bSopenharmony_ci "555555555555555555555555555555555555555555555555", /* 101010... */ 3597a8e1175bSopenharmony_ci }; 3598a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 3599a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3600a8e1175bSopenharmony_ci const char *m_exponents[] = 3601a8e1175bSopenharmony_ci { 3602a8e1175bSopenharmony_ci /* Valid private values for Curve25519. In a build with Curve448 3603a8e1175bSopenharmony_ci * but not Curve25519, they will be adjusted in 3604a8e1175bSopenharmony_ci * self_test_adjust_exponent(). */ 3605a8e1175bSopenharmony_ci "4000000000000000000000000000000000000000000000000000000000000000", 3606a8e1175bSopenharmony_ci "5C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C30", 3607a8e1175bSopenharmony_ci "5715ECCE24583F7A7023C24164390586842E816D7280A49EF6DF4EAE6B280BF8", 3608a8e1175bSopenharmony_ci "41A2B017516F6D254E1F002BCCBADD54BE30F8CEC737A0E912B4963B6BA74460", 3609a8e1175bSopenharmony_ci "5555555555555555555555555555555555555555555555555555555555555550", 3610a8e1175bSopenharmony_ci "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8", 3611a8e1175bSopenharmony_ci }; 3612a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3613a8e1175bSopenharmony_ci 3614a8e1175bSopenharmony_ci mbedtls_ecp_group_init(&grp); 3615a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&R); 3616a8e1175bSopenharmony_ci mbedtls_ecp_point_init(&P); 3617a8e1175bSopenharmony_ci mbedtls_mpi_init(&m); 3618a8e1175bSopenharmony_ci 3619a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3620a8e1175bSopenharmony_ci /* Use secp192r1 if available, or any available curve */ 3621a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) 3622a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP192R1)); 3623a8e1175bSopenharmony_ci#else 3624a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, mbedtls_ecp_curve_list()->grp_id)); 3625a8e1175bSopenharmony_ci#endif 3626a8e1175bSopenharmony_ci 3627a8e1175bSopenharmony_ci if (verbose != 0) { 3628a8e1175bSopenharmony_ci mbedtls_printf(" ECP SW test #1 (constant op_count, base point G): "); 3629a8e1175bSopenharmony_ci } 3630a8e1175bSopenharmony_ci /* Do a dummy multiplication first to trigger precomputation */ 3631a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&m, 2)); 3632a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &P, &m, &grp.G, self_test_rng, NULL)); 3633a8e1175bSopenharmony_ci ret = self_test_point(verbose, 3634a8e1175bSopenharmony_ci &grp, &R, &m, &grp.G, 3635a8e1175bSopenharmony_ci sw_exponents, 3636a8e1175bSopenharmony_ci sizeof(sw_exponents) / sizeof(sw_exponents[0])); 3637a8e1175bSopenharmony_ci if (ret != 0) { 3638a8e1175bSopenharmony_ci goto cleanup; 3639a8e1175bSopenharmony_ci } 3640a8e1175bSopenharmony_ci 3641a8e1175bSopenharmony_ci if (verbose != 0) { 3642a8e1175bSopenharmony_ci mbedtls_printf(" ECP SW test #2 (constant op_count, other point): "); 3643a8e1175bSopenharmony_ci } 3644a8e1175bSopenharmony_ci /* We computed P = 2G last time, use it */ 3645a8e1175bSopenharmony_ci ret = self_test_point(verbose, 3646a8e1175bSopenharmony_ci &grp, &R, &m, &P, 3647a8e1175bSopenharmony_ci sw_exponents, 3648a8e1175bSopenharmony_ci sizeof(sw_exponents) / sizeof(sw_exponents[0])); 3649a8e1175bSopenharmony_ci if (ret != 0) { 3650a8e1175bSopenharmony_ci goto cleanup; 3651a8e1175bSopenharmony_ci } 3652a8e1175bSopenharmony_ci 3653a8e1175bSopenharmony_ci mbedtls_ecp_group_free(&grp); 3654a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&R); 3655a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 3656a8e1175bSopenharmony_ci 3657a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3658a8e1175bSopenharmony_ci if (verbose != 0) { 3659a8e1175bSopenharmony_ci mbedtls_printf(" ECP Montgomery test (constant op_count): "); 3660a8e1175bSopenharmony_ci } 3661a8e1175bSopenharmony_ci#if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 3662a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE25519)); 3663a8e1175bSopenharmony_ci#elif defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) 3664a8e1175bSopenharmony_ci MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE448)); 3665a8e1175bSopenharmony_ci#else 3666a8e1175bSopenharmony_ci#error "MBEDTLS_ECP_MONTGOMERY_ENABLED is defined, but no curve is supported for self-test" 3667a8e1175bSopenharmony_ci#endif 3668a8e1175bSopenharmony_ci ret = self_test_point(verbose, 3669a8e1175bSopenharmony_ci &grp, &R, &m, &grp.G, 3670a8e1175bSopenharmony_ci m_exponents, 3671a8e1175bSopenharmony_ci sizeof(m_exponents) / sizeof(m_exponents[0])); 3672a8e1175bSopenharmony_ci if (ret != 0) { 3673a8e1175bSopenharmony_ci goto cleanup; 3674a8e1175bSopenharmony_ci } 3675a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3676a8e1175bSopenharmony_ci 3677a8e1175bSopenharmony_cicleanup: 3678a8e1175bSopenharmony_ci 3679a8e1175bSopenharmony_ci if (ret < 0 && verbose != 0) { 3680a8e1175bSopenharmony_ci mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret); 3681a8e1175bSopenharmony_ci } 3682a8e1175bSopenharmony_ci 3683a8e1175bSopenharmony_ci mbedtls_ecp_group_free(&grp); 3684a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&R); 3685a8e1175bSopenharmony_ci mbedtls_ecp_point_free(&P); 3686a8e1175bSopenharmony_ci mbedtls_mpi_free(&m); 3687a8e1175bSopenharmony_ci 3688a8e1175bSopenharmony_ci if (verbose != 0) { 3689a8e1175bSopenharmony_ci mbedtls_printf("\n"); 3690a8e1175bSopenharmony_ci } 3691a8e1175bSopenharmony_ci 3692a8e1175bSopenharmony_ci return ret; 3693a8e1175bSopenharmony_ci#else /* MBEDTLS_ECP_C */ 3694a8e1175bSopenharmony_ci (void) verbose; 3695a8e1175bSopenharmony_ci return 0; 3696a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_C */ 3697a8e1175bSopenharmony_ci} 3698a8e1175bSopenharmony_ci 3699a8e1175bSopenharmony_ci#endif /* MBEDTLS_SELF_TEST */ 3700a8e1175bSopenharmony_ci 3701a8e1175bSopenharmony_ci#endif /* !MBEDTLS_ECP_ALT */ 3702a8e1175bSopenharmony_ci 3703a8e1175bSopenharmony_ci#endif /* MBEDTLS_ECP_LIGHT */ 3704