1817466cbSJens Wiklander /* 2817466cbSJens Wiklander * Elliptic curves over GF(p): generic functions 3817466cbSJens Wiklander * 47901324dSJerome Forissier * Copyright The Mbed TLS Contributors 5*b0563631STom Van Eyck * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6817466cbSJens Wiklander */ 7817466cbSJens Wiklander 8817466cbSJens Wiklander /* 9817466cbSJens Wiklander * References: 10817466cbSJens Wiklander * 11*b0563631STom Van Eyck * SEC1 https://www.secg.org/sec1-v2.pdf 12817466cbSJens Wiklander * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone 13817466cbSJens Wiklander * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf 14817466cbSJens Wiklander * RFC 4492 for the related TLS structures and constants 15*b0563631STom Van Eyck * - https://www.rfc-editor.org/rfc/rfc4492 163d3b0591SJens Wiklander * RFC 7748 for the Curve448 and Curve25519 curve definitions 17*b0563631STom Van Eyck * - https://www.rfc-editor.org/rfc/rfc7748 18817466cbSJens Wiklander * 19*b0563631STom Van Eyck * [Curve25519] https://cr.yp.to/ecdh/curve25519-20060209.pdf 20817466cbSJens Wiklander * 21817466cbSJens Wiklander * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis 22817466cbSJens Wiklander * for elliptic curve cryptosystems. In : Cryptographic Hardware and 23817466cbSJens Wiklander * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. 24817466cbSJens Wiklander * <http://link.springer.com/chapter/10.1007/3-540-48059-5_25> 25817466cbSJens Wiklander * 26817466cbSJens Wiklander * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to 27817466cbSJens Wiklander * render ECC resistant against Side Channel Attacks. IACR Cryptology 28817466cbSJens Wiklander * ePrint Archive, 2004, vol. 2004, p. 342. 29817466cbSJens Wiklander * <http://eprint.iacr.org/2004/342.pdf> 30817466cbSJens Wiklander */ 31817466cbSJens Wiklander 327901324dSJerome Forissier #include "common.h" 33817466cbSJens Wiklander 343d3b0591SJens Wiklander /** 353d3b0591SJens Wiklander * \brief Function level alternative implementation. 363d3b0591SJens Wiklander * 373d3b0591SJens Wiklander * The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to 383d3b0591SJens Wiklander * replace certain functions in this module. The alternative implementations are 393d3b0591SJens Wiklander * typically hardware accelerators and need to activate the hardware before the 403d3b0591SJens Wiklander * computation starts and deactivate it after it finishes. The 413d3b0591SJens Wiklander * mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve 423d3b0591SJens Wiklander * this purpose. 433d3b0591SJens Wiklander * 443d3b0591SJens Wiklander * To preserve the correct functionality the following conditions must hold: 453d3b0591SJens Wiklander * 463d3b0591SJens Wiklander * - The alternative implementation must be activated by 473d3b0591SJens Wiklander * mbedtls_internal_ecp_init() before any of the replaceable functions is 483d3b0591SJens Wiklander * called. 493d3b0591SJens Wiklander * - mbedtls_internal_ecp_free() must \b only be called when the alternative 503d3b0591SJens Wiklander * implementation is activated. 513d3b0591SJens Wiklander * - mbedtls_internal_ecp_init() must \b not be called when the alternative 523d3b0591SJens Wiklander * implementation is activated. 533d3b0591SJens Wiklander * - Public functions must not return while the alternative implementation is 543d3b0591SJens Wiklander * activated. 553d3b0591SJens Wiklander * - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and 563d3b0591SJens Wiklander * before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) ) 573d3b0591SJens Wiklander * \endcode ensures that the alternative implementation supports the current 583d3b0591SJens Wiklander * group. 593d3b0591SJens Wiklander */ 603d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT) 613d3b0591SJens Wiklander #endif 623d3b0591SJens Wiklander 63*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_LIGHT) 64817466cbSJens Wiklander 65817466cbSJens Wiklander #include "mbedtls/ecp.h" 66817466cbSJens Wiklander #include "mbedtls/threading.h" 673d3b0591SJens Wiklander #include "mbedtls/platform_util.h" 6811fa71b9SJerome Forissier #include "mbedtls/error.h" 697901324dSJerome Forissier 7032b31808SJens Wiklander #include "bn_mul.h" 717901324dSJerome Forissier #include "ecp_invasive.h" 72817466cbSJens Wiklander 73817466cbSJens Wiklander #include <string.h> 74817466cbSJens Wiklander 75817466cbSJens Wiklander #if !defined(MBEDTLS_ECP_ALT) 76817466cbSJens Wiklander 77817466cbSJens Wiklander #include "mbedtls/platform.h" 78817466cbSJens Wiklander 7932b31808SJens Wiklander #include "ecp_internal_alt.h" 80817466cbSJens Wiklander 81817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 82817466cbSJens Wiklander /* 83817466cbSJens Wiklander * Counts of point addition and doubling, and field multiplications. 84817466cbSJens Wiklander * Used to test resistance of point multiplication to simple timing attacks. 85817466cbSJens Wiklander */ 86*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 87*b0563631STom Van Eyck static unsigned long add_count, dbl_count; 88*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 89*b0563631STom Van Eyck static unsigned long mul_count; 90817466cbSJens Wiklander #endif 91817466cbSJens Wiklander 923d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 933d3b0591SJens Wiklander /* 943d3b0591SJens Wiklander * Maximum number of "basic operations" to be done in a row. 953d3b0591SJens Wiklander * 963d3b0591SJens Wiklander * Default value 0 means that ECC operations will not yield. 973d3b0591SJens Wiklander * Note that regardless of the value of ecp_max_ops, always at 983d3b0591SJens Wiklander * least one step is performed before yielding. 993d3b0591SJens Wiklander * 1003d3b0591SJens Wiklander * Setting ecp_max_ops=1 can be suitable for testing purposes 1013d3b0591SJens Wiklander * as it will interrupt computation at all possible points. 1023d3b0591SJens Wiklander */ 1033d3b0591SJens Wiklander static unsigned ecp_max_ops = 0; 1043d3b0591SJens Wiklander 1053d3b0591SJens Wiklander /* 1063d3b0591SJens Wiklander * Set ecp_max_ops 1073d3b0591SJens Wiklander */ 1083d3b0591SJens Wiklander void mbedtls_ecp_set_max_ops(unsigned max_ops) 1093d3b0591SJens Wiklander { 1103d3b0591SJens Wiklander ecp_max_ops = max_ops; 1113d3b0591SJens Wiklander } 1123d3b0591SJens Wiklander 1133d3b0591SJens Wiklander /* 1143d3b0591SJens Wiklander * Check if restart is enabled 1153d3b0591SJens Wiklander */ 1163d3b0591SJens Wiklander int mbedtls_ecp_restart_is_enabled(void) 1173d3b0591SJens Wiklander { 11832b31808SJens Wiklander return ecp_max_ops != 0; 1193d3b0591SJens Wiklander } 1203d3b0591SJens Wiklander 1213d3b0591SJens Wiklander /* 1223d3b0591SJens Wiklander * Restart sub-context for ecp_mul_comb() 1233d3b0591SJens Wiklander */ 12432b31808SJens Wiklander struct mbedtls_ecp_restart_mul { 1253d3b0591SJens Wiklander mbedtls_ecp_point R; /* current intermediate result */ 1263d3b0591SJens Wiklander size_t i; /* current index in various loops, 0 outside */ 1273d3b0591SJens Wiklander mbedtls_ecp_point *T; /* table for precomputed points */ 1283d3b0591SJens Wiklander unsigned char T_size; /* number of points in table T */ 1293d3b0591SJens Wiklander enum { /* what were we doing last time we returned? */ 1303d3b0591SJens Wiklander ecp_rsm_init = 0, /* nothing so far, dummy initial state */ 1313d3b0591SJens Wiklander ecp_rsm_pre_dbl, /* precompute 2^n multiples */ 1323d3b0591SJens Wiklander ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */ 1333d3b0591SJens Wiklander ecp_rsm_pre_add, /* precompute remaining points by adding */ 1343d3b0591SJens Wiklander ecp_rsm_pre_norm_add, /* normalize all precomputed points */ 1353d3b0591SJens Wiklander ecp_rsm_comb_core, /* ecp_mul_comb_core() */ 1363d3b0591SJens Wiklander ecp_rsm_final_norm, /* do the final normalization */ 1373d3b0591SJens Wiklander } state; 1383d3b0591SJens Wiklander }; 1393d3b0591SJens Wiklander 1403d3b0591SJens Wiklander /* 1413d3b0591SJens Wiklander * Init restart_mul sub-context 1423d3b0591SJens Wiklander */ 1433d3b0591SJens Wiklander static void ecp_restart_rsm_init(mbedtls_ecp_restart_mul_ctx *ctx) 1443d3b0591SJens Wiklander { 1453d3b0591SJens Wiklander mbedtls_ecp_point_init(&ctx->R); 1463d3b0591SJens Wiklander ctx->i = 0; 1473d3b0591SJens Wiklander ctx->T = NULL; 1483d3b0591SJens Wiklander ctx->T_size = 0; 1493d3b0591SJens Wiklander ctx->state = ecp_rsm_init; 1503d3b0591SJens Wiklander } 1513d3b0591SJens Wiklander 1523d3b0591SJens Wiklander /* 1533d3b0591SJens Wiklander * Free the components of a restart_mul sub-context 1543d3b0591SJens Wiklander */ 1553d3b0591SJens Wiklander static void ecp_restart_rsm_free(mbedtls_ecp_restart_mul_ctx *ctx) 1563d3b0591SJens Wiklander { 1573d3b0591SJens Wiklander unsigned char i; 1583d3b0591SJens Wiklander 15932b31808SJens Wiklander if (ctx == NULL) { 1603d3b0591SJens Wiklander return; 16132b31808SJens Wiklander } 1623d3b0591SJens Wiklander 1633d3b0591SJens Wiklander mbedtls_ecp_point_free(&ctx->R); 1643d3b0591SJens Wiklander 16532b31808SJens Wiklander if (ctx->T != NULL) { 16632b31808SJens Wiklander for (i = 0; i < ctx->T_size; i++) { 1673d3b0591SJens Wiklander mbedtls_ecp_point_free(ctx->T + i); 16832b31808SJens Wiklander } 1693d3b0591SJens Wiklander mbedtls_free(ctx->T); 1703d3b0591SJens Wiklander } 1713d3b0591SJens Wiklander 1723d3b0591SJens Wiklander ecp_restart_rsm_init(ctx); 1733d3b0591SJens Wiklander } 1743d3b0591SJens Wiklander 1753d3b0591SJens Wiklander /* 1763d3b0591SJens Wiklander * Restart context for ecp_muladd() 1773d3b0591SJens Wiklander */ 17832b31808SJens Wiklander struct mbedtls_ecp_restart_muladd { 1793d3b0591SJens Wiklander mbedtls_ecp_point mP; /* mP value */ 1803d3b0591SJens Wiklander mbedtls_ecp_point R; /* R intermediate result */ 1813d3b0591SJens Wiklander enum { /* what should we do next? */ 1823d3b0591SJens Wiklander ecp_rsma_mul1 = 0, /* first multiplication */ 1833d3b0591SJens Wiklander ecp_rsma_mul2, /* second multiplication */ 1843d3b0591SJens Wiklander ecp_rsma_add, /* addition */ 1853d3b0591SJens Wiklander ecp_rsma_norm, /* normalization */ 1863d3b0591SJens Wiklander } state; 1873d3b0591SJens Wiklander }; 1883d3b0591SJens Wiklander 1893d3b0591SJens Wiklander /* 1903d3b0591SJens Wiklander * Init restart_muladd sub-context 1913d3b0591SJens Wiklander */ 1923d3b0591SJens Wiklander static void ecp_restart_ma_init(mbedtls_ecp_restart_muladd_ctx *ctx) 1933d3b0591SJens Wiklander { 1943d3b0591SJens Wiklander mbedtls_ecp_point_init(&ctx->mP); 1953d3b0591SJens Wiklander mbedtls_ecp_point_init(&ctx->R); 1963d3b0591SJens Wiklander ctx->state = ecp_rsma_mul1; 1973d3b0591SJens Wiklander } 1983d3b0591SJens Wiklander 1993d3b0591SJens Wiklander /* 2003d3b0591SJens Wiklander * Free the components of a restart_muladd sub-context 2013d3b0591SJens Wiklander */ 2023d3b0591SJens Wiklander static void ecp_restart_ma_free(mbedtls_ecp_restart_muladd_ctx *ctx) 2033d3b0591SJens Wiklander { 20432b31808SJens Wiklander if (ctx == NULL) { 2053d3b0591SJens Wiklander return; 20632b31808SJens Wiklander } 2073d3b0591SJens Wiklander 2083d3b0591SJens Wiklander mbedtls_ecp_point_free(&ctx->mP); 2093d3b0591SJens Wiklander mbedtls_ecp_point_free(&ctx->R); 2103d3b0591SJens Wiklander 2113d3b0591SJens Wiklander ecp_restart_ma_init(ctx); 2123d3b0591SJens Wiklander } 2133d3b0591SJens Wiklander 2143d3b0591SJens Wiklander /* 2153d3b0591SJens Wiklander * Initialize a restart context 2163d3b0591SJens Wiklander */ 2173d3b0591SJens Wiklander void mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx *ctx) 2183d3b0591SJens Wiklander { 2193d3b0591SJens Wiklander ctx->ops_done = 0; 2203d3b0591SJens Wiklander ctx->depth = 0; 2213d3b0591SJens Wiklander ctx->rsm = NULL; 2223d3b0591SJens Wiklander ctx->ma = NULL; 2233d3b0591SJens Wiklander } 2243d3b0591SJens Wiklander 2253d3b0591SJens Wiklander /* 2263d3b0591SJens Wiklander * Free the components of a restart context 2273d3b0591SJens Wiklander */ 2283d3b0591SJens Wiklander void mbedtls_ecp_restart_free(mbedtls_ecp_restart_ctx *ctx) 2293d3b0591SJens Wiklander { 23032b31808SJens Wiklander if (ctx == NULL) { 2313d3b0591SJens Wiklander return; 23232b31808SJens Wiklander } 2333d3b0591SJens Wiklander 2343d3b0591SJens Wiklander ecp_restart_rsm_free(ctx->rsm); 2353d3b0591SJens Wiklander mbedtls_free(ctx->rsm); 2363d3b0591SJens Wiklander 2373d3b0591SJens Wiklander ecp_restart_ma_free(ctx->ma); 2383d3b0591SJens Wiklander mbedtls_free(ctx->ma); 2393d3b0591SJens Wiklander 2403d3b0591SJens Wiklander mbedtls_ecp_restart_init(ctx); 2413d3b0591SJens Wiklander } 2423d3b0591SJens Wiklander 2433d3b0591SJens Wiklander /* 2443d3b0591SJens Wiklander * Check if we can do the next step 2453d3b0591SJens Wiklander */ 2463d3b0591SJens Wiklander int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp, 2473d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx, 2483d3b0591SJens Wiklander unsigned ops) 2493d3b0591SJens Wiklander { 25032b31808SJens Wiklander if (rs_ctx != NULL && ecp_max_ops != 0) { 2513d3b0591SJens Wiklander /* scale depending on curve size: the chosen reference is 256-bit, 2523d3b0591SJens Wiklander * and multiplication is quadratic. Round to the closest integer. */ 25332b31808SJens Wiklander if (grp->pbits >= 512) { 2543d3b0591SJens Wiklander ops *= 4; 25532b31808SJens Wiklander } else if (grp->pbits >= 384) { 2563d3b0591SJens Wiklander ops *= 2; 25732b31808SJens Wiklander } 2583d3b0591SJens Wiklander 2593d3b0591SJens Wiklander /* Avoid infinite loops: always allow first step. 2603d3b0591SJens Wiklander * Because of that, however, it's not generally true 2613d3b0591SJens Wiklander * that ops_done <= ecp_max_ops, so the check 2623d3b0591SJens Wiklander * ops_done > ecp_max_ops below is mandatory. */ 2633d3b0591SJens Wiklander if ((rs_ctx->ops_done != 0) && 2643d3b0591SJens Wiklander (rs_ctx->ops_done > ecp_max_ops || 26532b31808SJens Wiklander ops > ecp_max_ops - rs_ctx->ops_done)) { 26632b31808SJens Wiklander return MBEDTLS_ERR_ECP_IN_PROGRESS; 2673d3b0591SJens Wiklander } 2683d3b0591SJens Wiklander 2693d3b0591SJens Wiklander /* update running count */ 2703d3b0591SJens Wiklander rs_ctx->ops_done += ops; 2713d3b0591SJens Wiklander } 2723d3b0591SJens Wiklander 27332b31808SJens Wiklander return 0; 2743d3b0591SJens Wiklander } 2753d3b0591SJens Wiklander 2763d3b0591SJens Wiklander /* Call this when entering a function that needs its own sub-context */ 2773d3b0591SJens Wiklander #define ECP_RS_ENTER(SUB) do { \ 2783d3b0591SJens Wiklander /* reset ops count for this call if top-level */ \ 2793d3b0591SJens Wiklander if (rs_ctx != NULL && rs_ctx->depth++ == 0) \ 2803d3b0591SJens Wiklander rs_ctx->ops_done = 0; \ 2813d3b0591SJens Wiklander \ 2823d3b0591SJens Wiklander /* set up our own sub-context if needed */ \ 2833d3b0591SJens Wiklander if (mbedtls_ecp_restart_is_enabled() && \ 2843d3b0591SJens Wiklander rs_ctx != NULL && rs_ctx->SUB == NULL) \ 2853d3b0591SJens Wiklander { \ 2863d3b0591SJens Wiklander rs_ctx->SUB = mbedtls_calloc(1, sizeof(*rs_ctx->SUB)); \ 2873d3b0591SJens Wiklander if (rs_ctx->SUB == NULL) \ 28832b31808SJens Wiklander return MBEDTLS_ERR_ECP_ALLOC_FAILED; \ 2893d3b0591SJens Wiklander \ 2903d3b0591SJens Wiklander ecp_restart_## SUB ##_init(rs_ctx->SUB); \ 2913d3b0591SJens Wiklander } \ 2923d3b0591SJens Wiklander } while (0) 2933d3b0591SJens Wiklander 2943d3b0591SJens Wiklander /* Call this when leaving a function that needs its own sub-context */ 2953d3b0591SJens Wiklander #define ECP_RS_LEAVE(SUB) do { \ 2963d3b0591SJens Wiklander /* clear our sub-context when not in progress (done or error) */ \ 2973d3b0591SJens Wiklander if (rs_ctx != NULL && rs_ctx->SUB != NULL && \ 2983d3b0591SJens Wiklander ret != MBEDTLS_ERR_ECP_IN_PROGRESS) \ 2993d3b0591SJens Wiklander { \ 3003d3b0591SJens Wiklander ecp_restart_## SUB ##_free(rs_ctx->SUB); \ 3013d3b0591SJens Wiklander mbedtls_free(rs_ctx->SUB); \ 3023d3b0591SJens Wiklander rs_ctx->SUB = NULL; \ 3033d3b0591SJens Wiklander } \ 3043d3b0591SJens Wiklander \ 3053d3b0591SJens Wiklander if (rs_ctx != NULL) \ 3063d3b0591SJens Wiklander rs_ctx->depth--; \ 3073d3b0591SJens Wiklander } while (0) 3083d3b0591SJens Wiklander 3093d3b0591SJens Wiklander #else /* MBEDTLS_ECP_RESTARTABLE */ 3103d3b0591SJens Wiklander 3113d3b0591SJens Wiklander #define ECP_RS_ENTER(sub) (void) rs_ctx; 3123d3b0591SJens Wiklander #define ECP_RS_LEAVE(sub) (void) rs_ctx; 3133d3b0591SJens Wiklander 3143d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 3153d3b0591SJens Wiklander 316*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 31732b31808SJens Wiklander static void mpi_init_many(mbedtls_mpi *arr, size_t size) 31832b31808SJens Wiklander { 31932b31808SJens Wiklander while (size--) { 32032b31808SJens Wiklander mbedtls_mpi_init(arr++); 32132b31808SJens Wiklander } 32232b31808SJens Wiklander } 32332b31808SJens Wiklander 32432b31808SJens Wiklander static void mpi_free_many(mbedtls_mpi *arr, size_t size) 32532b31808SJens Wiklander { 32632b31808SJens Wiklander while (size--) { 32732b31808SJens Wiklander mbedtls_mpi_free(arr++); 32832b31808SJens Wiklander } 32932b31808SJens Wiklander } 330*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 33132b31808SJens Wiklander 332817466cbSJens Wiklander /* 333817466cbSJens Wiklander * List of supported curves: 334817466cbSJens Wiklander * - internal ID 33511fa71b9SJerome Forissier * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2, RFC 8446 sec. 4.2.7) 336817466cbSJens Wiklander * - size in bits 337817466cbSJens Wiklander * - readable name 338817466cbSJens Wiklander * 339817466cbSJens Wiklander * Curves are listed in order: largest curves first, and for a given size, 34032b31808SJens Wiklander * fastest curves first. 341817466cbSJens Wiklander * 34232b31808SJens Wiklander * Reminder: update profiles in x509_crt.c and ssl_tls.c when adding a new curve! 343817466cbSJens Wiklander */ 344817466cbSJens Wiklander static const mbedtls_ecp_curve_info ecp_supported_curves[] = 345817466cbSJens Wiklander { 346817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) 347817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" }, 348817466cbSJens Wiklander #endif 349817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED) 350817466cbSJens Wiklander { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" }, 351817466cbSJens Wiklander #endif 352817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) 353817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" }, 354817466cbSJens Wiklander #endif 355817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED) 356817466cbSJens Wiklander { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" }, 357817466cbSJens Wiklander #endif 358817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) 359817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" }, 360817466cbSJens Wiklander #endif 361817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED) 362817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" }, 363817466cbSJens Wiklander #endif 364817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED) 365817466cbSJens Wiklander { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" }, 366817466cbSJens Wiklander #endif 367817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) 368817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" }, 369817466cbSJens Wiklander #endif 370817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) 371817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" }, 372817466cbSJens Wiklander #endif 373817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) 374817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" }, 375817466cbSJens Wiklander #endif 376817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) 377817466cbSJens Wiklander { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" }, 378817466cbSJens Wiklander #endif 3797901324dSJerome Forissier #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 38011fa71b9SJerome Forissier { MBEDTLS_ECP_DP_CURVE25519, 29, 256, "x25519" }, 38111fa71b9SJerome Forissier #endif 3827901324dSJerome Forissier #if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) 3837901324dSJerome Forissier { MBEDTLS_ECP_DP_CURVE448, 30, 448, "x448" }, 3847901324dSJerome Forissier #endif 3859fc2442cSJerome Forissier #if defined(MBEDTLS_ECP_DP_SM2_ENABLED) 3869fc2442cSJerome Forissier /* https://tools.ietf.org/id/draft-yang-tls-tls13-sm-suites-05.html */ 3879fc2442cSJerome Forissier { MBEDTLS_ECP_DP_SM2, 41, 256, "sm2" }, 3889fc2442cSJerome Forissier #endif 389817466cbSJens Wiklander { MBEDTLS_ECP_DP_NONE, 0, 0, NULL }, 390817466cbSJens Wiklander }; 391817466cbSJens Wiklander 392817466cbSJens Wiklander #define ECP_NB_CURVES sizeof(ecp_supported_curves) / \ 393817466cbSJens Wiklander sizeof(ecp_supported_curves[0]) 394817466cbSJens Wiklander 395817466cbSJens Wiklander static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; 396817466cbSJens Wiklander 397817466cbSJens Wiklander /* 398817466cbSJens Wiklander * List of supported curves and associated info 399817466cbSJens Wiklander */ 400817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list(void) 401817466cbSJens Wiklander { 40232b31808SJens Wiklander return ecp_supported_curves; 403817466cbSJens Wiklander } 404817466cbSJens Wiklander 405817466cbSJens Wiklander /* 406817466cbSJens Wiklander * List of supported curves, group ID only 407817466cbSJens Wiklander */ 408817466cbSJens Wiklander const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list(void) 409817466cbSJens Wiklander { 410817466cbSJens Wiklander static int init_done = 0; 411817466cbSJens Wiklander 41232b31808SJens Wiklander if (!init_done) { 413817466cbSJens Wiklander size_t i = 0; 414817466cbSJens Wiklander const mbedtls_ecp_curve_info *curve_info; 415817466cbSJens Wiklander 416817466cbSJens Wiklander for (curve_info = mbedtls_ecp_curve_list(); 417817466cbSJens Wiklander curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 41832b31808SJens Wiklander curve_info++) { 419817466cbSJens Wiklander ecp_supported_grp_id[i++] = curve_info->grp_id; 420817466cbSJens Wiklander } 421817466cbSJens Wiklander ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE; 422817466cbSJens Wiklander 423817466cbSJens Wiklander init_done = 1; 424817466cbSJens Wiklander } 425817466cbSJens Wiklander 42632b31808SJens Wiklander return ecp_supported_grp_id; 427817466cbSJens Wiklander } 428817466cbSJens Wiklander 429817466cbSJens Wiklander /* 430817466cbSJens Wiklander * Get the curve info for the internal identifier 431817466cbSJens Wiklander */ 432817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id(mbedtls_ecp_group_id grp_id) 433817466cbSJens Wiklander { 434817466cbSJens Wiklander const mbedtls_ecp_curve_info *curve_info; 435817466cbSJens Wiklander 436817466cbSJens Wiklander for (curve_info = mbedtls_ecp_curve_list(); 437817466cbSJens Wiklander curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 43832b31808SJens Wiklander curve_info++) { 43932b31808SJens Wiklander if (curve_info->grp_id == grp_id) { 44032b31808SJens Wiklander return curve_info; 44132b31808SJens Wiklander } 442817466cbSJens Wiklander } 443817466cbSJens Wiklander 44432b31808SJens Wiklander return NULL; 445817466cbSJens Wiklander } 446817466cbSJens Wiklander 447817466cbSJens Wiklander /* 448817466cbSJens Wiklander * Get the curve info from the TLS identifier 449817466cbSJens Wiklander */ 450817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id(uint16_t tls_id) 451817466cbSJens Wiklander { 452817466cbSJens Wiklander const mbedtls_ecp_curve_info *curve_info; 453817466cbSJens Wiklander 454817466cbSJens Wiklander for (curve_info = mbedtls_ecp_curve_list(); 455817466cbSJens Wiklander curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 45632b31808SJens Wiklander curve_info++) { 45732b31808SJens Wiklander if (curve_info->tls_id == tls_id) { 45832b31808SJens Wiklander return curve_info; 45932b31808SJens Wiklander } 460817466cbSJens Wiklander } 461817466cbSJens Wiklander 46232b31808SJens Wiklander return NULL; 463817466cbSJens Wiklander } 464817466cbSJens Wiklander 465817466cbSJens Wiklander /* 466817466cbSJens Wiklander * Get the curve info from the name 467817466cbSJens Wiklander */ 468817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name(const char *name) 469817466cbSJens Wiklander { 470817466cbSJens Wiklander const mbedtls_ecp_curve_info *curve_info; 471817466cbSJens Wiklander 47232b31808SJens Wiklander if (name == NULL) { 47332b31808SJens Wiklander return NULL; 47432b31808SJens Wiklander } 4753d3b0591SJens Wiklander 476817466cbSJens Wiklander for (curve_info = mbedtls_ecp_curve_list(); 477817466cbSJens Wiklander curve_info->grp_id != MBEDTLS_ECP_DP_NONE; 47832b31808SJens Wiklander curve_info++) { 47932b31808SJens Wiklander if (strcmp(curve_info->name, name) == 0) { 48032b31808SJens Wiklander return curve_info; 48132b31808SJens Wiklander } 482817466cbSJens Wiklander } 483817466cbSJens Wiklander 48432b31808SJens Wiklander return NULL; 485817466cbSJens Wiklander } 486817466cbSJens Wiklander 487817466cbSJens Wiklander /* 488817466cbSJens Wiklander * Get the type of a curve 489817466cbSJens Wiklander */ 49011fa71b9SJerome Forissier mbedtls_ecp_curve_type mbedtls_ecp_get_type(const mbedtls_ecp_group *grp) 491817466cbSJens Wiklander { 49232b31808SJens Wiklander if (grp->G.X.p == NULL) { 49332b31808SJens Wiklander return MBEDTLS_ECP_TYPE_NONE; 49432b31808SJens Wiklander } 495817466cbSJens Wiklander 49632b31808SJens Wiklander if (grp->G.Y.p == NULL) { 49732b31808SJens Wiklander return MBEDTLS_ECP_TYPE_MONTGOMERY; 49832b31808SJens Wiklander } else { 49932b31808SJens Wiklander return MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS; 50032b31808SJens Wiklander } 501817466cbSJens Wiklander } 502817466cbSJens Wiklander 503817466cbSJens Wiklander /* 504817466cbSJens Wiklander * Initialize (the components of) a point 505817466cbSJens Wiklander */ 506817466cbSJens Wiklander void mbedtls_ecp_point_init(mbedtls_ecp_point *pt) 507817466cbSJens Wiklander { 508817466cbSJens Wiklander mbedtls_mpi_init(&pt->X); 509817466cbSJens Wiklander mbedtls_mpi_init(&pt->Y); 510817466cbSJens Wiklander mbedtls_mpi_init(&pt->Z); 511817466cbSJens Wiklander } 512817466cbSJens Wiklander 513817466cbSJens Wiklander /* 514817466cbSJens Wiklander * Initialize (the components of) a group 515817466cbSJens Wiklander */ 516817466cbSJens Wiklander void mbedtls_ecp_group_init(mbedtls_ecp_group *grp) 517817466cbSJens Wiklander { 5183d3b0591SJens Wiklander grp->id = MBEDTLS_ECP_DP_NONE; 5193d3b0591SJens Wiklander mbedtls_mpi_init(&grp->P); 5203d3b0591SJens Wiklander mbedtls_mpi_init(&grp->A); 5213d3b0591SJens Wiklander mbedtls_mpi_init(&grp->B); 5223d3b0591SJens Wiklander mbedtls_ecp_point_init(&grp->G); 5233d3b0591SJens Wiklander mbedtls_mpi_init(&grp->N); 5243d3b0591SJens Wiklander grp->pbits = 0; 5253d3b0591SJens Wiklander grp->nbits = 0; 5263d3b0591SJens Wiklander grp->h = 0; 5273d3b0591SJens Wiklander grp->modp = NULL; 5283d3b0591SJens Wiklander grp->t_pre = NULL; 5293d3b0591SJens Wiklander grp->t_post = NULL; 5303d3b0591SJens Wiklander grp->t_data = NULL; 5313d3b0591SJens Wiklander grp->T = NULL; 5323d3b0591SJens Wiklander grp->T_size = 0; 533817466cbSJens Wiklander } 534817466cbSJens Wiklander 535817466cbSJens Wiklander /* 536817466cbSJens Wiklander * Initialize (the components of) a key pair 537817466cbSJens Wiklander */ 538817466cbSJens Wiklander void mbedtls_ecp_keypair_init(mbedtls_ecp_keypair *key) 539817466cbSJens Wiklander { 540817466cbSJens Wiklander mbedtls_ecp_group_init(&key->grp); 541817466cbSJens Wiklander mbedtls_mpi_init(&key->d); 542817466cbSJens Wiklander mbedtls_ecp_point_init(&key->Q); 543817466cbSJens Wiklander } 544817466cbSJens Wiklander 545817466cbSJens Wiklander /* 546817466cbSJens Wiklander * Unallocate (the components of) a point 547817466cbSJens Wiklander */ 548817466cbSJens Wiklander void mbedtls_ecp_point_free(mbedtls_ecp_point *pt) 549817466cbSJens Wiklander { 55032b31808SJens Wiklander if (pt == NULL) { 551817466cbSJens Wiklander return; 55232b31808SJens Wiklander } 553817466cbSJens Wiklander 554817466cbSJens Wiklander mbedtls_mpi_free(&(pt->X)); 555817466cbSJens Wiklander mbedtls_mpi_free(&(pt->Y)); 556817466cbSJens Wiklander mbedtls_mpi_free(&(pt->Z)); 557817466cbSJens Wiklander } 558817466cbSJens Wiklander 559817466cbSJens Wiklander /* 56032b31808SJens Wiklander * Check that the comb table (grp->T) is static initialized. 56132b31808SJens Wiklander */ 56232b31808SJens Wiklander static int ecp_group_is_static_comb_table(const mbedtls_ecp_group *grp) 56332b31808SJens Wiklander { 56432b31808SJens Wiklander #if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 56532b31808SJens Wiklander return grp->T != NULL && grp->T_size == 0; 56632b31808SJens Wiklander #else 56732b31808SJens Wiklander (void) grp; 56832b31808SJens Wiklander return 0; 56932b31808SJens Wiklander #endif 57032b31808SJens Wiklander } 57132b31808SJens Wiklander 57232b31808SJens Wiklander /* 573817466cbSJens Wiklander * Unallocate (the components of) a group 574817466cbSJens Wiklander */ 575817466cbSJens Wiklander void mbedtls_ecp_group_free(mbedtls_ecp_group *grp) 576817466cbSJens Wiklander { 577817466cbSJens Wiklander size_t i; 578817466cbSJens Wiklander 57932b31808SJens Wiklander if (grp == NULL) { 580817466cbSJens Wiklander return; 58132b31808SJens Wiklander } 582817466cbSJens Wiklander 58332b31808SJens Wiklander if (grp->h != 1) { 584817466cbSJens Wiklander mbedtls_mpi_free(&grp->A); 585817466cbSJens Wiklander mbedtls_mpi_free(&grp->B); 586817466cbSJens Wiklander mbedtls_ecp_point_free(&grp->G); 587*b0563631STom Van Eyck 588*b0563631STom Van Eyck #if !defined(MBEDTLS_ECP_WITH_MPI_UINT) 589*b0563631STom Van Eyck mbedtls_mpi_free(&grp->N); 590*b0563631STom Van Eyck mbedtls_mpi_free(&grp->P); 591*b0563631STom Van Eyck #endif 592817466cbSJens Wiklander } 593817466cbSJens Wiklander 59432b31808SJens Wiklander if (!ecp_group_is_static_comb_table(grp) && grp->T != NULL) { 59532b31808SJens Wiklander for (i = 0; i < grp->T_size; i++) { 596817466cbSJens Wiklander mbedtls_ecp_point_free(&grp->T[i]); 59732b31808SJens Wiklander } 598817466cbSJens Wiklander mbedtls_free(grp->T); 599817466cbSJens Wiklander } 600817466cbSJens Wiklander 6013d3b0591SJens Wiklander mbedtls_platform_zeroize(grp, sizeof(mbedtls_ecp_group)); 602817466cbSJens Wiklander } 603817466cbSJens Wiklander 604817466cbSJens Wiklander /* 605817466cbSJens Wiklander * Unallocate (the components of) a key pair 606817466cbSJens Wiklander */ 607817466cbSJens Wiklander void mbedtls_ecp_keypair_free(mbedtls_ecp_keypair *key) 608817466cbSJens Wiklander { 60932b31808SJens Wiklander if (key == NULL) { 610817466cbSJens Wiklander return; 61132b31808SJens Wiklander } 612817466cbSJens Wiklander 613817466cbSJens Wiklander mbedtls_ecp_group_free(&key->grp); 614817466cbSJens Wiklander mbedtls_mpi_free(&key->d); 615817466cbSJens Wiklander mbedtls_ecp_point_free(&key->Q); 616817466cbSJens Wiklander } 617817466cbSJens Wiklander 618817466cbSJens Wiklander /* 619817466cbSJens Wiklander * Copy the contents of a point 620817466cbSJens Wiklander */ 621817466cbSJens Wiklander int mbedtls_ecp_copy(mbedtls_ecp_point *P, const mbedtls_ecp_point *Q) 622817466cbSJens Wiklander { 62311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 624817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->X, &Q->X)); 625817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Y, &Q->Y)); 626817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Z, &Q->Z)); 627817466cbSJens Wiklander 628817466cbSJens Wiklander cleanup: 62932b31808SJens Wiklander return ret; 630817466cbSJens Wiklander } 631817466cbSJens Wiklander 632817466cbSJens Wiklander /* 633817466cbSJens Wiklander * Copy the contents of a group object 634817466cbSJens Wiklander */ 635817466cbSJens Wiklander int mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, const mbedtls_ecp_group *src) 636817466cbSJens Wiklander { 63732b31808SJens Wiklander return mbedtls_ecp_group_load(dst, src->id); 638817466cbSJens Wiklander } 639817466cbSJens Wiklander 640817466cbSJens Wiklander /* 641817466cbSJens Wiklander * Set point to zero 642817466cbSJens Wiklander */ 643817466cbSJens Wiklander int mbedtls_ecp_set_zero(mbedtls_ecp_point *pt) 644817466cbSJens Wiklander { 64511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 646817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->X, 1)); 647817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Y, 1)); 648817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 0)); 649817466cbSJens Wiklander 650817466cbSJens Wiklander cleanup: 65132b31808SJens Wiklander return ret; 652817466cbSJens Wiklander } 653817466cbSJens Wiklander 654817466cbSJens Wiklander /* 655817466cbSJens Wiklander * Tell if a point is zero 656817466cbSJens Wiklander */ 657817466cbSJens Wiklander int mbedtls_ecp_is_zero(mbedtls_ecp_point *pt) 658817466cbSJens Wiklander { 65932b31808SJens Wiklander return mbedtls_mpi_cmp_int(&pt->Z, 0) == 0; 660817466cbSJens Wiklander } 661817466cbSJens Wiklander 662817466cbSJens Wiklander /* 6633d3b0591SJens Wiklander * Compare two points lazily 664817466cbSJens Wiklander */ 665817466cbSJens Wiklander int mbedtls_ecp_point_cmp(const mbedtls_ecp_point *P, 666817466cbSJens Wiklander const mbedtls_ecp_point *Q) 667817466cbSJens Wiklander { 668817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&P->X, &Q->X) == 0 && 669817466cbSJens Wiklander mbedtls_mpi_cmp_mpi(&P->Y, &Q->Y) == 0 && 67032b31808SJens Wiklander mbedtls_mpi_cmp_mpi(&P->Z, &Q->Z) == 0) { 67132b31808SJens Wiklander return 0; 672817466cbSJens Wiklander } 673817466cbSJens Wiklander 67432b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 675817466cbSJens Wiklander } 676817466cbSJens Wiklander 677817466cbSJens Wiklander /* 678817466cbSJens Wiklander * Import a non-zero point from ASCII strings 679817466cbSJens Wiklander */ 680817466cbSJens Wiklander int mbedtls_ecp_point_read_string(mbedtls_ecp_point *P, int radix, 681817466cbSJens Wiklander const char *x, const char *y) 682817466cbSJens Wiklander { 68311fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 684817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->X, radix, x)); 685817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->Y, radix, y)); 686817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->Z, 1)); 687817466cbSJens Wiklander 688817466cbSJens Wiklander cleanup: 68932b31808SJens Wiklander return ret; 690817466cbSJens Wiklander } 691817466cbSJens Wiklander 692817466cbSJens Wiklander /* 69311fa71b9SJerome Forissier * Export a point into unsigned binary data (SEC1 2.3.3 and RFC7748) 694817466cbSJens Wiklander */ 6953d3b0591SJens Wiklander int mbedtls_ecp_point_write_binary(const mbedtls_ecp_group *grp, 6963d3b0591SJens Wiklander const mbedtls_ecp_point *P, 697817466cbSJens Wiklander int format, size_t *olen, 698817466cbSJens Wiklander unsigned char *buf, size_t buflen) 699817466cbSJens Wiklander { 70011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 701817466cbSJens Wiklander size_t plen; 70232b31808SJens Wiklander if (format != MBEDTLS_ECP_PF_UNCOMPRESSED && 70332b31808SJens Wiklander format != MBEDTLS_ECP_PF_COMPRESSED) { 70432b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 70532b31808SJens Wiklander } 706817466cbSJens Wiklander 70711fa71b9SJerome Forissier plen = mbedtls_mpi_size(&grp->P); 70811fa71b9SJerome Forissier 7097901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 7107901324dSJerome Forissier (void) format; /* Montgomery curves always use the same point format */ 71132b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 71211fa71b9SJerome Forissier *olen = plen; 71332b31808SJens Wiklander if (buflen < *olen) { 71432b31808SJens Wiklander return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 71532b31808SJens Wiklander } 71611fa71b9SJerome Forissier 71711fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&P->X, buf, plen)); 71811fa71b9SJerome Forissier } 71911fa71b9SJerome Forissier #endif 7207901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 72132b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 722817466cbSJens Wiklander /* 723817466cbSJens Wiklander * Common case: P == 0 724817466cbSJens Wiklander */ 72532b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0) { 72632b31808SJens Wiklander if (buflen < 1) { 72732b31808SJens Wiklander return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 72832b31808SJens Wiklander } 729817466cbSJens Wiklander 730817466cbSJens Wiklander buf[0] = 0x00; 731817466cbSJens Wiklander *olen = 1; 732817466cbSJens Wiklander 73332b31808SJens Wiklander return 0; 734817466cbSJens Wiklander } 735817466cbSJens Wiklander 73632b31808SJens Wiklander if (format == MBEDTLS_ECP_PF_UNCOMPRESSED) { 737817466cbSJens Wiklander *olen = 2 * plen + 1; 738817466cbSJens Wiklander 73932b31808SJens Wiklander if (buflen < *olen) { 74032b31808SJens Wiklander return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 74132b31808SJens Wiklander } 742817466cbSJens Wiklander 743817466cbSJens Wiklander buf[0] = 0x04; 744817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen)); 745817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->Y, buf + 1 + plen, plen)); 74632b31808SJens Wiklander } else if (format == MBEDTLS_ECP_PF_COMPRESSED) { 747817466cbSJens Wiklander *olen = plen + 1; 748817466cbSJens Wiklander 74932b31808SJens Wiklander if (buflen < *olen) { 75032b31808SJens Wiklander return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 75132b31808SJens Wiklander } 752817466cbSJens Wiklander 753817466cbSJens Wiklander buf[0] = 0x02 + mbedtls_mpi_get_bit(&P->Y, 0); 754817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen)); 755817466cbSJens Wiklander } 75611fa71b9SJerome Forissier } 75711fa71b9SJerome Forissier #endif 758817466cbSJens Wiklander 759817466cbSJens Wiklander cleanup: 76032b31808SJens Wiklander return ret; 761817466cbSJens Wiklander } 762817466cbSJens Wiklander 76332b31808SJens Wiklander #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 76432b31808SJens Wiklander static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, 76532b31808SJens Wiklander const mbedtls_mpi *X, 76632b31808SJens Wiklander mbedtls_mpi *Y, 76732b31808SJens Wiklander int parity_bit); 76832b31808SJens Wiklander #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 76932b31808SJens Wiklander 770817466cbSJens Wiklander /* 77111fa71b9SJerome Forissier * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748) 772817466cbSJens Wiklander */ 7733d3b0591SJens Wiklander int mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp, 7743d3b0591SJens Wiklander mbedtls_ecp_point *pt, 775817466cbSJens Wiklander const unsigned char *buf, size_t ilen) 776817466cbSJens Wiklander { 77711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 778817466cbSJens Wiklander size_t plen; 77932b31808SJens Wiklander if (ilen < 1) { 78032b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 78132b31808SJens Wiklander } 782817466cbSJens Wiklander 78311fa71b9SJerome Forissier plen = mbedtls_mpi_size(&grp->P); 78411fa71b9SJerome Forissier 7857901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 78632b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 78732b31808SJens Wiklander if (plen != ilen) { 78832b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 78932b31808SJens Wiklander } 79011fa71b9SJerome Forissier 79111fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&pt->X, buf, plen)); 79211fa71b9SJerome Forissier mbedtls_mpi_free(&pt->Y); 79311fa71b9SJerome Forissier 79432b31808SJens Wiklander if (grp->id == MBEDTLS_ECP_DP_CURVE25519) { 79511fa71b9SJerome Forissier /* Set most significant bit to 0 as prescribed in RFC7748 §5 */ 79611fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&pt->X, plen * 8 - 1, 0)); 79732b31808SJens Wiklander } 79811fa71b9SJerome Forissier 79911fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); 80011fa71b9SJerome Forissier } 80111fa71b9SJerome Forissier #endif 8027901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 80332b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 80432b31808SJens Wiklander if (buf[0] == 0x00) { 80532b31808SJens Wiklander if (ilen == 1) { 80632b31808SJens Wiklander return mbedtls_ecp_set_zero(pt); 80732b31808SJens Wiklander } else { 80832b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 80932b31808SJens Wiklander } 810817466cbSJens Wiklander } 811817466cbSJens Wiklander 81232b31808SJens Wiklander if (ilen < 1 + plen) { 81332b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 81432b31808SJens Wiklander } 815817466cbSJens Wiklander 816817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, buf + 1, plen)); 817817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1)); 81832b31808SJens Wiklander 81932b31808SJens Wiklander if (buf[0] == 0x04) { 82032b31808SJens Wiklander /* format == MBEDTLS_ECP_PF_UNCOMPRESSED */ 82132b31808SJens Wiklander if (ilen != 1 + plen * 2) { 82232b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 82332b31808SJens Wiklander } 82432b31808SJens Wiklander return mbedtls_mpi_read_binary(&pt->Y, buf + 1 + plen, plen); 82532b31808SJens Wiklander } else if (buf[0] == 0x02 || buf[0] == 0x03) { 82632b31808SJens Wiklander /* format == MBEDTLS_ECP_PF_COMPRESSED */ 82732b31808SJens Wiklander if (ilen != 1 + plen) { 82832b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 82932b31808SJens Wiklander } 83032b31808SJens Wiklander return mbedtls_ecp_sw_derive_y(grp, &pt->X, &pt->Y, 83132b31808SJens Wiklander (buf[0] & 1)); 83232b31808SJens Wiklander } else { 83332b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 83432b31808SJens Wiklander } 83511fa71b9SJerome Forissier } 83611fa71b9SJerome Forissier #endif 837817466cbSJens Wiklander 838817466cbSJens Wiklander cleanup: 83932b31808SJens Wiklander return ret; 840817466cbSJens Wiklander } 841817466cbSJens Wiklander 842817466cbSJens Wiklander /* 843817466cbSJens Wiklander * Import a point from a TLS ECPoint record (RFC 4492) 844817466cbSJens Wiklander * struct { 845817466cbSJens Wiklander * opaque point <1..2^8-1>; 846817466cbSJens Wiklander * } ECPoint; 847817466cbSJens Wiklander */ 8483d3b0591SJens Wiklander int mbedtls_ecp_tls_read_point(const mbedtls_ecp_group *grp, 8493d3b0591SJens Wiklander mbedtls_ecp_point *pt, 850817466cbSJens Wiklander const unsigned char **buf, size_t buf_len) 851817466cbSJens Wiklander { 852817466cbSJens Wiklander unsigned char data_len; 853817466cbSJens Wiklander const unsigned char *buf_start; 854817466cbSJens Wiklander /* 855817466cbSJens Wiklander * We must have at least two bytes (1 for length, at least one for data) 856817466cbSJens Wiklander */ 85732b31808SJens Wiklander if (buf_len < 2) { 85832b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 85932b31808SJens Wiklander } 860817466cbSJens Wiklander 861817466cbSJens Wiklander data_len = *(*buf)++; 86232b31808SJens Wiklander if (data_len < 1 || data_len > buf_len - 1) { 86332b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 86432b31808SJens Wiklander } 865817466cbSJens Wiklander 866817466cbSJens Wiklander /* 867817466cbSJens Wiklander * Save buffer start for read_binary and update buf 868817466cbSJens Wiklander */ 869817466cbSJens Wiklander buf_start = *buf; 870817466cbSJens Wiklander *buf += data_len; 871817466cbSJens Wiklander 87232b31808SJens Wiklander return mbedtls_ecp_point_read_binary(grp, pt, buf_start, data_len); 873817466cbSJens Wiklander } 874817466cbSJens Wiklander 875817466cbSJens Wiklander /* 876817466cbSJens Wiklander * Export a point as a TLS ECPoint record (RFC 4492) 877817466cbSJens Wiklander * struct { 878817466cbSJens Wiklander * opaque point <1..2^8-1>; 879817466cbSJens Wiklander * } ECPoint; 880817466cbSJens Wiklander */ 881817466cbSJens Wiklander int mbedtls_ecp_tls_write_point(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, 882817466cbSJens Wiklander int format, size_t *olen, 883817466cbSJens Wiklander unsigned char *buf, size_t blen) 884817466cbSJens Wiklander { 88511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 88632b31808SJens Wiklander if (format != MBEDTLS_ECP_PF_UNCOMPRESSED && 88732b31808SJens Wiklander format != MBEDTLS_ECP_PF_COMPRESSED) { 88832b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 88932b31808SJens Wiklander } 890817466cbSJens Wiklander 891817466cbSJens Wiklander /* 892817466cbSJens Wiklander * buffer length must be at least one, for our length byte 893817466cbSJens Wiklander */ 89432b31808SJens Wiklander if (blen < 1) { 89532b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 89632b31808SJens Wiklander } 897817466cbSJens Wiklander 898817466cbSJens Wiklander if ((ret = mbedtls_ecp_point_write_binary(grp, pt, format, 89932b31808SJens Wiklander olen, buf + 1, blen - 1)) != 0) { 90032b31808SJens Wiklander return ret; 90132b31808SJens Wiklander } 902817466cbSJens Wiklander 903817466cbSJens Wiklander /* 904817466cbSJens Wiklander * write length to the first byte and update total length 905817466cbSJens Wiklander */ 906817466cbSJens Wiklander buf[0] = (unsigned char) *olen; 907817466cbSJens Wiklander ++*olen; 908817466cbSJens Wiklander 90932b31808SJens Wiklander return 0; 910817466cbSJens Wiklander } 911817466cbSJens Wiklander 912817466cbSJens Wiklander /* 913817466cbSJens Wiklander * Set a group from an ECParameters record (RFC 4492) 914817466cbSJens Wiklander */ 9153d3b0591SJens Wiklander int mbedtls_ecp_tls_read_group(mbedtls_ecp_group *grp, 9163d3b0591SJens Wiklander const unsigned char **buf, size_t len) 9173d3b0591SJens Wiklander { 91811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 9193d3b0591SJens Wiklander mbedtls_ecp_group_id grp_id; 92032b31808SJens Wiklander if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, len)) != 0) { 92132b31808SJens Wiklander return ret; 92232b31808SJens Wiklander } 9233d3b0591SJens Wiklander 92432b31808SJens Wiklander return mbedtls_ecp_group_load(grp, grp_id); 9253d3b0591SJens Wiklander } 9263d3b0591SJens Wiklander 9273d3b0591SJens Wiklander /* 9283d3b0591SJens Wiklander * Read a group id from an ECParameters record (RFC 4492) and convert it to 9293d3b0591SJens Wiklander * mbedtls_ecp_group_id. 9303d3b0591SJens Wiklander */ 9313d3b0591SJens Wiklander int mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp, 9323d3b0591SJens Wiklander const unsigned char **buf, size_t len) 933817466cbSJens Wiklander { 934817466cbSJens Wiklander uint16_t tls_id; 935817466cbSJens Wiklander const mbedtls_ecp_curve_info *curve_info; 936817466cbSJens Wiklander /* 937817466cbSJens Wiklander * We expect at least three bytes (see below) 938817466cbSJens Wiklander */ 93932b31808SJens Wiklander if (len < 3) { 94032b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 94132b31808SJens Wiklander } 942817466cbSJens Wiklander 943817466cbSJens Wiklander /* 944817466cbSJens Wiklander * First byte is curve_type; only named_curve is handled 945817466cbSJens Wiklander */ 94632b31808SJens Wiklander if (*(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE) { 94732b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 94832b31808SJens Wiklander } 949817466cbSJens Wiklander 950817466cbSJens Wiklander /* 951817466cbSJens Wiklander * Next two bytes are the namedcurve value 952817466cbSJens Wiklander */ 953*b0563631STom Van Eyck tls_id = MBEDTLS_GET_UINT16_BE(*buf, 0); 954*b0563631STom Van Eyck *buf += 2; 955817466cbSJens Wiklander 95632b31808SJens Wiklander if ((curve_info = mbedtls_ecp_curve_info_from_tls_id(tls_id)) == NULL) { 95732b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 95832b31808SJens Wiklander } 959817466cbSJens Wiklander 9603d3b0591SJens Wiklander *grp = curve_info->grp_id; 9613d3b0591SJens Wiklander 96232b31808SJens Wiklander return 0; 963817466cbSJens Wiklander } 964817466cbSJens Wiklander 965817466cbSJens Wiklander /* 966817466cbSJens Wiklander * Write the ECParameters record corresponding to a group (RFC 4492) 967817466cbSJens Wiklander */ 968817466cbSJens Wiklander int mbedtls_ecp_tls_write_group(const mbedtls_ecp_group *grp, size_t *olen, 969817466cbSJens Wiklander unsigned char *buf, size_t blen) 970817466cbSJens Wiklander { 971817466cbSJens Wiklander const mbedtls_ecp_curve_info *curve_info; 97232b31808SJens Wiklander if ((curve_info = mbedtls_ecp_curve_info_from_grp_id(grp->id)) == NULL) { 97332b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 97432b31808SJens Wiklander } 975817466cbSJens Wiklander 976817466cbSJens Wiklander /* 977817466cbSJens Wiklander * We are going to write 3 bytes (see below) 978817466cbSJens Wiklander */ 979817466cbSJens Wiklander *olen = 3; 98032b31808SJens Wiklander if (blen < *olen) { 98132b31808SJens Wiklander return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 98232b31808SJens Wiklander } 983817466cbSJens Wiklander 984817466cbSJens Wiklander /* 985817466cbSJens Wiklander * First byte is curve_type, always named_curve 986817466cbSJens Wiklander */ 987817466cbSJens Wiklander *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE; 988817466cbSJens Wiklander 989817466cbSJens Wiklander /* 990817466cbSJens Wiklander * Next two bytes are the namedcurve value 991817466cbSJens Wiklander */ 992039e02dfSJerome Forissier MBEDTLS_PUT_UINT16_BE(curve_info->tls_id, buf, 0); 993817466cbSJens Wiklander 99432b31808SJens Wiklander return 0; 995817466cbSJens Wiklander } 996817466cbSJens Wiklander 997817466cbSJens Wiklander /* 998817466cbSJens Wiklander * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. 999817466cbSJens Wiklander * See the documentation of struct mbedtls_ecp_group. 1000817466cbSJens Wiklander * 1001817466cbSJens Wiklander * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. 1002817466cbSJens Wiklander */ 1003817466cbSJens Wiklander static int ecp_modp(mbedtls_mpi *N, const mbedtls_ecp_group *grp) 1004817466cbSJens Wiklander { 100511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1006817466cbSJens Wiklander 100732b31808SJens Wiklander if (grp->modp == NULL) { 100832b31808SJens Wiklander return mbedtls_mpi_mod_mpi(N, N, &grp->P); 100932b31808SJens Wiklander } 1010817466cbSJens Wiklander 1011817466cbSJens Wiklander /* N->s < 0 is a much faster test, which fails only if N is 0 */ 1012817466cbSJens Wiklander if ((N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) || 101332b31808SJens Wiklander mbedtls_mpi_bitlen(N) > 2 * grp->pbits) { 101432b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 1015817466cbSJens Wiklander } 1016817466cbSJens Wiklander 1017817466cbSJens Wiklander MBEDTLS_MPI_CHK(grp->modp(N)); 1018817466cbSJens Wiklander 1019817466cbSJens Wiklander /* N->s < 0 is a much faster test, which fails only if N is 0 */ 102032b31808SJens Wiklander while (N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) { 1021817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &grp->P)); 102232b31808SJens Wiklander } 1023817466cbSJens Wiklander 102432b31808SJens Wiklander while (mbedtls_mpi_cmp_mpi(N, &grp->P) >= 0) { 1025817466cbSJens Wiklander /* we known P, N and the result are positive */ 1026817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(N, N, &grp->P)); 102732b31808SJens Wiklander } 1028817466cbSJens Wiklander 1029817466cbSJens Wiklander cleanup: 103032b31808SJens Wiklander return ret; 1031817466cbSJens Wiklander } 1032817466cbSJens Wiklander 1033817466cbSJens Wiklander /* 1034817466cbSJens Wiklander * Fast mod-p functions expect their argument to be in the 0..p^2 range. 1035817466cbSJens Wiklander * 1036817466cbSJens Wiklander * In order to guarantee that, we need to ensure that operands of 1037817466cbSJens Wiklander * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will 1038817466cbSJens Wiklander * bring the result back to this range. 1039817466cbSJens Wiklander * 1040817466cbSJens Wiklander * The following macros are shortcuts for doing that. 1041817466cbSJens Wiklander */ 1042817466cbSJens Wiklander 1043817466cbSJens Wiklander /* 1044817466cbSJens Wiklander * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi 1045817466cbSJens Wiklander */ 1046817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 1047817466cbSJens Wiklander #define INC_MUL_COUNT mul_count++; 1048817466cbSJens Wiklander #else 1049817466cbSJens Wiklander #define INC_MUL_COUNT 1050817466cbSJens Wiklander #endif 1051817466cbSJens Wiklander 10525b25c76aSJerome Forissier #define MOD_MUL(N) \ 10535b25c76aSJerome Forissier do \ 10545b25c76aSJerome Forissier { \ 10555b25c76aSJerome Forissier MBEDTLS_MPI_CHK(ecp_modp(&(N), grp)); \ 10565b25c76aSJerome Forissier INC_MUL_COUNT \ 10575b25c76aSJerome Forissier } while (0) 1058817466cbSJens Wiklander 105911fa71b9SJerome Forissier static inline int mbedtls_mpi_mul_mod(const mbedtls_ecp_group *grp, 106011fa71b9SJerome Forissier mbedtls_mpi *X, 106111fa71b9SJerome Forissier const mbedtls_mpi *A, 106211fa71b9SJerome Forissier const mbedtls_mpi *B) 106311fa71b9SJerome Forissier { 106411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 106511fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(X, A, B)); 106611fa71b9SJerome Forissier MOD_MUL(*X); 106711fa71b9SJerome Forissier cleanup: 106832b31808SJens Wiklander return ret; 106911fa71b9SJerome Forissier } 107011fa71b9SJerome Forissier 1071817466cbSJens Wiklander /* 1072817466cbSJens Wiklander * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi 1073817466cbSJens Wiklander * N->s < 0 is a very fast test, which fails only if N is 0 1074817466cbSJens Wiklander */ 1075817466cbSJens Wiklander #define MOD_SUB(N) \ 107632b31808SJens Wiklander do { \ 107732b31808SJens Wiklander while ((N)->s < 0 && mbedtls_mpi_cmp_int((N), 0) != 0) \ 107832b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi((N), (N), &grp->P)); \ 107932b31808SJens Wiklander } while (0) 1080817466cbSJens Wiklander 1081*b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED 108211fa71b9SJerome Forissier static inline int mbedtls_mpi_sub_mod(const mbedtls_ecp_group *grp, 108311fa71b9SJerome Forissier mbedtls_mpi *X, 108411fa71b9SJerome Forissier const mbedtls_mpi *A, 108511fa71b9SJerome Forissier const mbedtls_mpi *B) 108611fa71b9SJerome Forissier { 108711fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 108811fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, A, B)); 108932b31808SJens Wiklander MOD_SUB(X); 109011fa71b9SJerome Forissier cleanup: 109132b31808SJens Wiklander return ret; 109211fa71b9SJerome Forissier } 109311fa71b9SJerome Forissier 1094817466cbSJens Wiklander /* 1095817466cbSJens Wiklander * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. 1096817466cbSJens Wiklander * We known P, N and the result are positive, so sub_abs is correct, and 1097817466cbSJens Wiklander * a bit faster. 1098817466cbSJens Wiklander */ 1099817466cbSJens Wiklander #define MOD_ADD(N) \ 110032b31808SJens Wiklander while (mbedtls_mpi_cmp_mpi((N), &grp->P) >= 0) \ 110132b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs((N), (N), &grp->P)) 1102817466cbSJens Wiklander 110311fa71b9SJerome Forissier static inline int mbedtls_mpi_add_mod(const mbedtls_ecp_group *grp, 110411fa71b9SJerome Forissier mbedtls_mpi *X, 110511fa71b9SJerome Forissier const mbedtls_mpi *A, 110611fa71b9SJerome Forissier const mbedtls_mpi *B) 110711fa71b9SJerome Forissier { 110811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 110911fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, A, B)); 111032b31808SJens Wiklander MOD_ADD(X); 111111fa71b9SJerome Forissier cleanup: 111232b31808SJens Wiklander return ret; 111311fa71b9SJerome Forissier } 111411fa71b9SJerome Forissier 1115*b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED 111632b31808SJens Wiklander static inline int mbedtls_mpi_mul_int_mod(const mbedtls_ecp_group *grp, 111732b31808SJens Wiklander mbedtls_mpi *X, 111832b31808SJens Wiklander const mbedtls_mpi *A, 111932b31808SJens Wiklander mbedtls_mpi_uint c) 112032b31808SJens Wiklander { 112132b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 112232b31808SJens Wiklander 112332b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(X, A, c)); 112432b31808SJens Wiklander MOD_ADD(X); 112532b31808SJens Wiklander cleanup: 112632b31808SJens Wiklander return ret; 112732b31808SJens Wiklander } 112832b31808SJens Wiklander 1129*b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED 113032b31808SJens Wiklander static inline int mbedtls_mpi_sub_int_mod(const mbedtls_ecp_group *grp, 113132b31808SJens Wiklander mbedtls_mpi *X, 113232b31808SJens Wiklander const mbedtls_mpi *A, 113332b31808SJens Wiklander mbedtls_mpi_uint c) 113432b31808SJens Wiklander { 113532b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 113632b31808SJens Wiklander 113732b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(X, A, c)); 113832b31808SJens Wiklander MOD_SUB(X); 113932b31808SJens Wiklander cleanup: 114032b31808SJens Wiklander return ret; 114132b31808SJens Wiklander } 114232b31808SJens Wiklander 114332b31808SJens Wiklander #define MPI_ECP_SUB_INT(X, A, c) \ 114432b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int_mod(grp, X, A, c)) 114532b31808SJens Wiklander 1146*b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED 114711fa71b9SJerome Forissier static inline int mbedtls_mpi_shift_l_mod(const mbedtls_ecp_group *grp, 114811fa71b9SJerome Forissier mbedtls_mpi *X, 114911fa71b9SJerome Forissier size_t count) 115011fa71b9SJerome Forissier { 115111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 115211fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(X, count)); 115332b31808SJens Wiklander MOD_ADD(X); 115411fa71b9SJerome Forissier cleanup: 115532b31808SJens Wiklander return ret; 115611fa71b9SJerome Forissier } 115732b31808SJens Wiklander 115832b31808SJens Wiklander /* 115932b31808SJens Wiklander * Macro wrappers around ECP modular arithmetic 116032b31808SJens Wiklander * 116132b31808SJens Wiklander * Currently, these wrappers are defined via the bignum module. 116232b31808SJens Wiklander */ 116332b31808SJens Wiklander 116432b31808SJens Wiklander #define MPI_ECP_ADD(X, A, B) \ 116532b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, X, A, B)) 116632b31808SJens Wiklander 116732b31808SJens Wiklander #define MPI_ECP_SUB(X, A, B) \ 116832b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, X, A, B)) 116932b31808SJens Wiklander 117032b31808SJens Wiklander #define MPI_ECP_MUL(X, A, B) \ 117132b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, B)) 117232b31808SJens Wiklander 117332b31808SJens Wiklander #define MPI_ECP_SQR(X, A) \ 117432b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, X, A, A)) 117532b31808SJens Wiklander 117632b31808SJens Wiklander #define MPI_ECP_MUL_INT(X, A, c) \ 117732b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int_mod(grp, X, A, c)) 117832b31808SJens Wiklander 117932b31808SJens Wiklander #define MPI_ECP_INV(dst, src) \ 118032b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod((dst), (src), &grp->P)) 118132b31808SJens Wiklander 118232b31808SJens Wiklander #define MPI_ECP_MOV(X, A) \ 118332b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(X, A)) 118432b31808SJens Wiklander 118532b31808SJens Wiklander #define MPI_ECP_SHIFT_L(X, count) \ 118632b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, X, count)) 118732b31808SJens Wiklander 118832b31808SJens Wiklander #define MPI_ECP_LSET(X, c) \ 118932b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(X, c)) 119032b31808SJens Wiklander 119132b31808SJens Wiklander #define MPI_ECP_CMP_INT(X, c) \ 119232b31808SJens Wiklander mbedtls_mpi_cmp_int(X, c) 119332b31808SJens Wiklander 119432b31808SJens Wiklander #define MPI_ECP_CMP(X, Y) \ 119532b31808SJens Wiklander mbedtls_mpi_cmp_mpi(X, Y) 119632b31808SJens Wiklander 119732b31808SJens Wiklander /* Needs f_rng, p_rng to be defined. */ 119832b31808SJens Wiklander #define MPI_ECP_RAND(X) \ 119932b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_random((X), 2, &grp->P, f_rng, p_rng)) 120032b31808SJens Wiklander 120132b31808SJens Wiklander /* Conditional negation 120232b31808SJens Wiklander * Needs grp and a temporary MPI tmp to be defined. */ 120332b31808SJens Wiklander #define MPI_ECP_COND_NEG(X, cond) \ 120432b31808SJens Wiklander do \ 120532b31808SJens Wiklander { \ 120632b31808SJens Wiklander unsigned char nonzero = mbedtls_mpi_cmp_int((X), 0) != 0; \ 120732b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&tmp, &grp->P, (X))); \ 120832b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), &tmp, \ 120932b31808SJens Wiklander nonzero & cond)); \ 121032b31808SJens Wiklander } while (0) 121132b31808SJens Wiklander 121232b31808SJens Wiklander #define MPI_ECP_NEG(X) MPI_ECP_COND_NEG((X), 1) 121332b31808SJens Wiklander 121432b31808SJens Wiklander #define MPI_ECP_VALID(X) \ 121532b31808SJens Wiklander ((X)->p != NULL) 121632b31808SJens Wiklander 121732b31808SJens Wiklander #define MPI_ECP_COND_ASSIGN(X, Y, cond) \ 121832b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign((X), (Y), (cond))) 121932b31808SJens Wiklander 122032b31808SJens Wiklander #define MPI_ECP_COND_SWAP(X, Y, cond) \ 122132b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap((X), (Y), (cond))) 122211fa71b9SJerome Forissier 12237901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 122432b31808SJens Wiklander 122532b31808SJens Wiklander /* 122632b31808SJens Wiklander * Computes the right-hand side of the Short Weierstrass equation 122732b31808SJens Wiklander * RHS = X^3 + A X + B 122832b31808SJens Wiklander */ 122932b31808SJens Wiklander static int ecp_sw_rhs(const mbedtls_ecp_group *grp, 123032b31808SJens Wiklander mbedtls_mpi *rhs, 123132b31808SJens Wiklander const mbedtls_mpi *X) 123232b31808SJens Wiklander { 123332b31808SJens Wiklander int ret; 123432b31808SJens Wiklander 123532b31808SJens Wiklander /* Compute X^3 + A X + B as X (X^2 + A) + B */ 123632b31808SJens Wiklander MPI_ECP_SQR(rhs, X); 123732b31808SJens Wiklander 123832b31808SJens Wiklander /* Special case for A = -3 */ 1239*b0563631STom Van Eyck if (mbedtls_ecp_group_a_is_minus_3(grp)) { 124032b31808SJens Wiklander MPI_ECP_SUB_INT(rhs, rhs, 3); 124132b31808SJens Wiklander } else { 124232b31808SJens Wiklander MPI_ECP_ADD(rhs, rhs, &grp->A); 124332b31808SJens Wiklander } 124432b31808SJens Wiklander 124532b31808SJens Wiklander MPI_ECP_MUL(rhs, rhs, X); 124632b31808SJens Wiklander MPI_ECP_ADD(rhs, rhs, &grp->B); 124732b31808SJens Wiklander 124832b31808SJens Wiklander cleanup: 124932b31808SJens Wiklander return ret; 125032b31808SJens Wiklander } 125132b31808SJens Wiklander 125232b31808SJens Wiklander /* 125332b31808SJens Wiklander * Derive Y from X and a parity bit 125432b31808SJens Wiklander */ 125532b31808SJens Wiklander static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, 125632b31808SJens Wiklander const mbedtls_mpi *X, 125732b31808SJens Wiklander mbedtls_mpi *Y, 125832b31808SJens Wiklander int parity_bit) 125932b31808SJens Wiklander { 126032b31808SJens Wiklander /* w = y^2 = x^3 + ax + b 126132b31808SJens Wiklander * y = sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) 126232b31808SJens Wiklander * 126332b31808SJens Wiklander * Note: this method for extracting square root does not validate that w 126432b31808SJens Wiklander * was indeed a square so this function will return garbage in Y if X 126532b31808SJens Wiklander * does not correspond to a point on the curve. 126632b31808SJens Wiklander */ 126732b31808SJens Wiklander 126832b31808SJens Wiklander /* Check prerequisite p = 3 mod 4 */ 126932b31808SJens Wiklander if (mbedtls_mpi_get_bit(&grp->P, 0) != 1 || 127032b31808SJens Wiklander mbedtls_mpi_get_bit(&grp->P, 1) != 1) { 127132b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 127232b31808SJens Wiklander } 127332b31808SJens Wiklander 127432b31808SJens Wiklander int ret; 127532b31808SJens Wiklander mbedtls_mpi exp; 127632b31808SJens Wiklander mbedtls_mpi_init(&exp); 127732b31808SJens Wiklander 127832b31808SJens Wiklander /* use Y to store intermediate result, actually w above */ 127932b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, Y, X)); 128032b31808SJens Wiklander 128132b31808SJens Wiklander /* w = y^2 */ /* Y contains y^2 intermediate result */ 128232b31808SJens Wiklander /* exp = ((p+1)/4) */ 128332b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&exp, &grp->P, 1)); 128432b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 2)); 128532b31808SJens Wiklander /* sqrt(w) = w^((p+1)/4) mod p (for prime p where p = 3 mod 4) */ 128632b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(Y, Y /*y^2*/, &exp, &grp->P, NULL)); 128732b31808SJens Wiklander 128832b31808SJens Wiklander /* check parity bit match or else invert Y */ 128932b31808SJens Wiklander /* This quick inversion implementation is valid because Y != 0 for all 129032b31808SJens Wiklander * Short Weierstrass curves supported by mbedtls, as each supported curve 129132b31808SJens Wiklander * has an order that is a large prime, so each supported curve does not 129232b31808SJens Wiklander * have any point of order 2, and a point with Y == 0 would be of order 2 */ 129332b31808SJens Wiklander if (mbedtls_mpi_get_bit(Y, 0) != parity_bit) { 129432b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(Y, &grp->P, Y)); 129532b31808SJens Wiklander } 129632b31808SJens Wiklander 129732b31808SJens Wiklander cleanup: 129832b31808SJens Wiklander 129932b31808SJens Wiklander mbedtls_mpi_free(&exp); 130032b31808SJens Wiklander return ret; 130132b31808SJens Wiklander } 1302*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 130332b31808SJens Wiklander 1304*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 1305*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 1306817466cbSJens Wiklander /* 1307817466cbSJens Wiklander * For curves in short Weierstrass form, we do all the internal operations in 1308817466cbSJens Wiklander * Jacobian coordinates. 1309817466cbSJens Wiklander * 1310039e02dfSJerome Forissier * For multiplication, we'll use a comb method with countermeasures against 1311817466cbSJens Wiklander * SPA, hence timing attacks. 1312817466cbSJens Wiklander */ 1313817466cbSJens Wiklander 1314817466cbSJens Wiklander /* 1315817466cbSJens Wiklander * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) 1316817466cbSJens Wiklander * Cost: 1N := 1I + 3M + 1S 1317817466cbSJens Wiklander */ 1318817466cbSJens Wiklander static int ecp_normalize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt) 1319817466cbSJens Wiklander { 132032b31808SJens Wiklander if (MPI_ECP_CMP_INT(&pt->Z, 0) == 0) { 132132b31808SJens Wiklander return 0; 132232b31808SJens Wiklander } 1323817466cbSJens Wiklander 1324817466cbSJens Wiklander #if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) 132532b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 132632b31808SJens Wiklander return mbedtls_internal_ecp_normalize_jac(grp, pt); 132732b31808SJens Wiklander } 1328817466cbSJens Wiklander #endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */ 13293d3b0591SJens Wiklander 13307901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) 133132b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 13327901324dSJerome Forissier #else 13337901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 133432b31808SJens Wiklander mbedtls_mpi T; 133532b31808SJens Wiklander mbedtls_mpi_init(&T); 1336817466cbSJens Wiklander 133732b31808SJens Wiklander MPI_ECP_INV(&T, &pt->Z); /* T <- 1 / Z */ 133832b31808SJens Wiklander MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y' <- Y*T = Y / Z */ 133932b31808SJens Wiklander MPI_ECP_SQR(&T, &T); /* T <- T^2 = 1 / Z^2 */ 134032b31808SJens Wiklander MPI_ECP_MUL(&pt->X, &pt->X, &T); /* X <- X * T = X / Z^2 */ 134132b31808SJens Wiklander MPI_ECP_MUL(&pt->Y, &pt->Y, &T); /* Y'' <- Y' * T = Y / Z^3 */ 1342817466cbSJens Wiklander 134332b31808SJens Wiklander MPI_ECP_LSET(&pt->Z, 1); 1344817466cbSJens Wiklander 1345817466cbSJens Wiklander cleanup: 1346817466cbSJens Wiklander 134732b31808SJens Wiklander mbedtls_mpi_free(&T); 1348817466cbSJens Wiklander 134932b31808SJens Wiklander return ret; 13507901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) */ 1351817466cbSJens Wiklander } 1352817466cbSJens Wiklander 1353817466cbSJens Wiklander /* 1354817466cbSJens Wiklander * Normalize jacobian coordinates of an array of (pointers to) points, 1355817466cbSJens Wiklander * using Montgomery's trick to perform only one inversion mod P. 1356817466cbSJens Wiklander * (See for example Cohen's "A Course in Computational Algebraic Number 1357817466cbSJens Wiklander * Theory", Algorithm 10.3.4.) 1358817466cbSJens Wiklander * 1359817466cbSJens Wiklander * Warning: fails (returning an error) if one of the points is zero! 1360817466cbSJens Wiklander * This should never happen, see choice of w in ecp_mul_comb(). 1361817466cbSJens Wiklander * 1362817466cbSJens Wiklander * Cost: 1N(t) := 1I + (6t - 3)M + 1S 1363817466cbSJens Wiklander */ 1364817466cbSJens Wiklander static int ecp_normalize_jac_many(const mbedtls_ecp_group *grp, 13653d3b0591SJens Wiklander mbedtls_ecp_point *T[], size_t T_size) 1366817466cbSJens Wiklander { 136732b31808SJens Wiklander if (T_size < 2) { 136832b31808SJens Wiklander return ecp_normalize_jac(grp, *T); 136932b31808SJens Wiklander } 1370817466cbSJens Wiklander 1371817466cbSJens Wiklander #if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) 137232b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 137332b31808SJens Wiklander return mbedtls_internal_ecp_normalize_jac_many(grp, T, T_size); 137432b31808SJens Wiklander } 1375817466cbSJens Wiklander #endif 1376817466cbSJens Wiklander 13777901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) 137832b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 13797901324dSJerome Forissier #else 13807901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 13817901324dSJerome Forissier size_t i; 138232b31808SJens Wiklander mbedtls_mpi *c, t; 13837901324dSJerome Forissier 138432b31808SJens Wiklander if ((c = mbedtls_calloc(T_size, sizeof(mbedtls_mpi))) == NULL) { 138532b31808SJens Wiklander return MBEDTLS_ERR_ECP_ALLOC_FAILED; 138632b31808SJens Wiklander } 1387817466cbSJens Wiklander 138832b31808SJens Wiklander mbedtls_mpi_init(&t); 13893d3b0591SJens Wiklander 139032b31808SJens Wiklander mpi_init_many(c, T_size); 1391817466cbSJens Wiklander /* 139232b31808SJens Wiklander * c[i] = Z_0 * ... * Z_i, i = 0,..,n := T_size-1 1393817466cbSJens Wiklander */ 139432b31808SJens Wiklander MPI_ECP_MOV(&c[0], &T[0]->Z); 139532b31808SJens Wiklander for (i = 1; i < T_size; i++) { 139632b31808SJens Wiklander MPI_ECP_MUL(&c[i], &c[i-1], &T[i]->Z); 1397817466cbSJens Wiklander } 1398817466cbSJens Wiklander 1399817466cbSJens Wiklander /* 140032b31808SJens Wiklander * c[n] = 1 / (Z_0 * ... * Z_n) mod P 1401817466cbSJens Wiklander */ 140232b31808SJens Wiklander MPI_ECP_INV(&c[T_size-1], &c[T_size-1]); 1403817466cbSJens Wiklander 140432b31808SJens Wiklander for (i = T_size - 1;; i--) { 140532b31808SJens Wiklander /* At the start of iteration i (note that i decrements), we have 140632b31808SJens Wiklander * - c[j] = Z_0 * .... * Z_j for j < i, 140732b31808SJens Wiklander * - c[j] = 1 / (Z_0 * .... * Z_j) for j == i, 140832b31808SJens Wiklander * 140932b31808SJens Wiklander * This is maintained via 141032b31808SJens Wiklander * - c[i-1] <- c[i] * Z_i 141132b31808SJens Wiklander * 141232b31808SJens Wiklander * We also derive 1/Z_i = c[i] * c[i-1] for i>0 and use that 141332b31808SJens Wiklander * to do the actual normalization. For i==0, we already have 141432b31808SJens Wiklander * c[0] = 1 / Z_0. 1415817466cbSJens Wiklander */ 141632b31808SJens Wiklander 141732b31808SJens Wiklander if (i > 0) { 141832b31808SJens Wiklander /* Compute 1/Z_i and establish invariant for the next iteration. */ 141932b31808SJens Wiklander MPI_ECP_MUL(&t, &c[i], &c[i-1]); 142032b31808SJens Wiklander MPI_ECP_MUL(&c[i-1], &c[i], &T[i]->Z); 142132b31808SJens Wiklander } else { 142232b31808SJens Wiklander MPI_ECP_MOV(&t, &c[0]); 1423817466cbSJens Wiklander } 1424817466cbSJens Wiklander 142532b31808SJens Wiklander /* Now t holds 1 / Z_i; normalize as in ecp_normalize_jac() */ 142632b31808SJens Wiklander MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t); 142732b31808SJens Wiklander MPI_ECP_SQR(&t, &t); 142832b31808SJens Wiklander MPI_ECP_MUL(&T[i]->X, &T[i]->X, &t); 142932b31808SJens Wiklander MPI_ECP_MUL(&T[i]->Y, &T[i]->Y, &t); 1430817466cbSJens Wiklander 1431817466cbSJens Wiklander /* 1432817466cbSJens Wiklander * Post-precessing: reclaim some memory by shrinking coordinates 1433817466cbSJens Wiklander * - not storing Z (always 1) 1434817466cbSJens Wiklander * - shrinking other coordinates, but still keeping the same number of 1435817466cbSJens Wiklander * limbs as P, as otherwise it will too likely be regrown too fast. 1436817466cbSJens Wiklander */ 1437817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->X, grp->P.n)); 1438817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->Y, grp->P.n)); 1439817466cbSJens Wiklander 144032b31808SJens Wiklander MPI_ECP_LSET(&T[i]->Z, 1); 144132b31808SJens Wiklander 144232b31808SJens Wiklander if (i == 0) { 1443817466cbSJens Wiklander break; 1444817466cbSJens Wiklander } 144532b31808SJens Wiklander } 1446817466cbSJens Wiklander 1447817466cbSJens Wiklander cleanup: 1448817466cbSJens Wiklander 144932b31808SJens Wiklander mbedtls_mpi_free(&t); 145032b31808SJens Wiklander mpi_free_many(c, T_size); 1451817466cbSJens Wiklander mbedtls_free(c); 1452817466cbSJens Wiklander 145332b31808SJens Wiklander return ret; 14547901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) */ 1455817466cbSJens Wiklander } 1456817466cbSJens Wiklander 1457817466cbSJens Wiklander /* 1458817466cbSJens Wiklander * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. 1459817466cbSJens Wiklander * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid 1460817466cbSJens Wiklander */ 1461817466cbSJens Wiklander static int ecp_safe_invert_jac(const mbedtls_ecp_group *grp, 1462817466cbSJens Wiklander mbedtls_ecp_point *Q, 1463817466cbSJens Wiklander unsigned char inv) 1464817466cbSJens Wiklander { 146511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 146632b31808SJens Wiklander mbedtls_mpi tmp; 146732b31808SJens Wiklander mbedtls_mpi_init(&tmp); 1468817466cbSJens Wiklander 146932b31808SJens Wiklander MPI_ECP_COND_NEG(&Q->Y, inv); 1470817466cbSJens Wiklander 1471817466cbSJens Wiklander cleanup: 147232b31808SJens Wiklander mbedtls_mpi_free(&tmp); 147332b31808SJens Wiklander return ret; 1474817466cbSJens Wiklander } 1475817466cbSJens Wiklander 1476817466cbSJens Wiklander /* 1477817466cbSJens Wiklander * Point doubling R = 2 P, Jacobian coordinates 1478817466cbSJens Wiklander * 1479817466cbSJens Wiklander * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . 1480817466cbSJens Wiklander * 1481817466cbSJens Wiklander * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR 1482817466cbSJens Wiklander * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. 1483817466cbSJens Wiklander * 1484817466cbSJens Wiklander * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. 1485817466cbSJens Wiklander * 1486817466cbSJens Wiklander * Cost: 1D := 3M + 4S (A == 0) 1487817466cbSJens Wiklander * 4M + 4S (A == -3) 1488817466cbSJens Wiklander * 3M + 6S + 1a otherwise 1489817466cbSJens Wiklander */ 1490817466cbSJens Wiklander static int ecp_double_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 149132b31808SJens Wiklander const mbedtls_ecp_point *P, 149232b31808SJens Wiklander mbedtls_mpi tmp[4]) 1493817466cbSJens Wiklander { 1494817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 1495817466cbSJens Wiklander dbl_count++; 1496817466cbSJens Wiklander #endif 1497817466cbSJens Wiklander 1498817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) 149932b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 150032b31808SJens Wiklander return mbedtls_internal_ecp_double_jac(grp, R, P); 150132b31808SJens Wiklander } 1502817466cbSJens Wiklander #endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */ 1503817466cbSJens Wiklander 15047901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) 150532b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 15067901324dSJerome Forissier #else 15077901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 1508817466cbSJens Wiklander 1509817466cbSJens Wiklander /* Special case for A = -3 */ 1510*b0563631STom Van Eyck if (mbedtls_ecp_group_a_is_minus_3(grp)) { 151132b31808SJens Wiklander /* tmp[0] <- M = 3(X + Z^2)(X - Z^2) */ 151232b31808SJens Wiklander MPI_ECP_SQR(&tmp[1], &P->Z); 151332b31808SJens Wiklander MPI_ECP_ADD(&tmp[2], &P->X, &tmp[1]); 151432b31808SJens Wiklander MPI_ECP_SUB(&tmp[3], &P->X, &tmp[1]); 151532b31808SJens Wiklander MPI_ECP_MUL(&tmp[1], &tmp[2], &tmp[3]); 151632b31808SJens Wiklander MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3); 151732b31808SJens Wiklander } else { 151832b31808SJens Wiklander /* tmp[0] <- M = 3.X^2 + A.Z^4 */ 151932b31808SJens Wiklander MPI_ECP_SQR(&tmp[1], &P->X); 152032b31808SJens Wiklander MPI_ECP_MUL_INT(&tmp[0], &tmp[1], 3); 1521817466cbSJens Wiklander 1522817466cbSJens Wiklander /* Optimize away for "koblitz" curves with A = 0 */ 152332b31808SJens Wiklander if (MPI_ECP_CMP_INT(&grp->A, 0) != 0) { 1524817466cbSJens Wiklander /* M += A.Z^4 */ 152532b31808SJens Wiklander MPI_ECP_SQR(&tmp[1], &P->Z); 152632b31808SJens Wiklander MPI_ECP_SQR(&tmp[2], &tmp[1]); 152732b31808SJens Wiklander MPI_ECP_MUL(&tmp[1], &tmp[2], &grp->A); 152832b31808SJens Wiklander MPI_ECP_ADD(&tmp[0], &tmp[0], &tmp[1]); 1529817466cbSJens Wiklander } 1530817466cbSJens Wiklander } 1531817466cbSJens Wiklander 153232b31808SJens Wiklander /* tmp[1] <- S = 4.X.Y^2 */ 153332b31808SJens Wiklander MPI_ECP_SQR(&tmp[2], &P->Y); 153432b31808SJens Wiklander MPI_ECP_SHIFT_L(&tmp[2], 1); 153532b31808SJens Wiklander MPI_ECP_MUL(&tmp[1], &P->X, &tmp[2]); 153632b31808SJens Wiklander MPI_ECP_SHIFT_L(&tmp[1], 1); 1537817466cbSJens Wiklander 153832b31808SJens Wiklander /* tmp[3] <- U = 8.Y^4 */ 153932b31808SJens Wiklander MPI_ECP_SQR(&tmp[3], &tmp[2]); 154032b31808SJens Wiklander MPI_ECP_SHIFT_L(&tmp[3], 1); 1541817466cbSJens Wiklander 154232b31808SJens Wiklander /* tmp[2] <- T = M^2 - 2.S */ 154332b31808SJens Wiklander MPI_ECP_SQR(&tmp[2], &tmp[0]); 154432b31808SJens Wiklander MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]); 154532b31808SJens Wiklander MPI_ECP_SUB(&tmp[2], &tmp[2], &tmp[1]); 1546817466cbSJens Wiklander 154732b31808SJens Wiklander /* tmp[1] <- S = M(S - T) - U */ 154832b31808SJens Wiklander MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[2]); 154932b31808SJens Wiklander MPI_ECP_MUL(&tmp[1], &tmp[1], &tmp[0]); 155032b31808SJens Wiklander MPI_ECP_SUB(&tmp[1], &tmp[1], &tmp[3]); 1551817466cbSJens Wiklander 155232b31808SJens Wiklander /* tmp[3] <- U = 2.Y.Z */ 155332b31808SJens Wiklander MPI_ECP_MUL(&tmp[3], &P->Y, &P->Z); 155432b31808SJens Wiklander MPI_ECP_SHIFT_L(&tmp[3], 1); 1555817466cbSJens Wiklander 155632b31808SJens Wiklander /* Store results */ 155732b31808SJens Wiklander MPI_ECP_MOV(&R->X, &tmp[2]); 155832b31808SJens Wiklander MPI_ECP_MOV(&R->Y, &tmp[1]); 155932b31808SJens Wiklander MPI_ECP_MOV(&R->Z, &tmp[3]); 1560817466cbSJens Wiklander 1561817466cbSJens Wiklander cleanup: 1562817466cbSJens Wiklander 156332b31808SJens Wiklander return ret; 15647901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) */ 1565817466cbSJens Wiklander } 1566817466cbSJens Wiklander 1567817466cbSJens Wiklander /* 1568817466cbSJens Wiklander * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) 1569817466cbSJens Wiklander * 1570817466cbSJens Wiklander * The coordinates of Q must be normalized (= affine), 1571817466cbSJens Wiklander * but those of P don't need to. R is not normalized. 1572817466cbSJens Wiklander * 157332b31808SJens Wiklander * P,Q,R may alias, but only at the level of EC points: they must be either 157432b31808SJens Wiklander * equal as pointers, or disjoint (including the coordinate data buffers). 157532b31808SJens Wiklander * Fine-grained aliasing at the level of coordinates is not supported. 157632b31808SJens Wiklander * 1577817466cbSJens Wiklander * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. 1578817466cbSJens Wiklander * None of these cases can happen as intermediate step in ecp_mul_comb(): 1579817466cbSJens Wiklander * - at each step, P, Q and R are multiples of the base point, the factor 1580817466cbSJens Wiklander * being less than its order, so none of them is zero; 1581817466cbSJens Wiklander * - Q is an odd multiple of the base point, P an even multiple, 1582817466cbSJens Wiklander * due to the choice of precomputed points in the modified comb method. 1583817466cbSJens Wiklander * So branches for these cases do not leak secret information. 1584817466cbSJens Wiklander * 1585817466cbSJens Wiklander * Cost: 1A := 8M + 3S 1586817466cbSJens Wiklander */ 1587817466cbSJens Wiklander static int ecp_add_mixed(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 158832b31808SJens Wiklander const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, 158932b31808SJens Wiklander mbedtls_mpi tmp[4]) 1590817466cbSJens Wiklander { 1591817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 1592817466cbSJens Wiklander add_count++; 1593817466cbSJens Wiklander #endif 1594817466cbSJens Wiklander 1595817466cbSJens Wiklander #if defined(MBEDTLS_ECP_ADD_MIXED_ALT) 159632b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 159732b31808SJens Wiklander return mbedtls_internal_ecp_add_mixed(grp, R, P, Q); 159832b31808SJens Wiklander } 1599817466cbSJens Wiklander #endif /* MBEDTLS_ECP_ADD_MIXED_ALT */ 1600817466cbSJens Wiklander 16017901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_ADD_MIXED_ALT) 160232b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 16037901324dSJerome Forissier #else 16047901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 160532b31808SJens Wiklander 160632b31808SJens Wiklander /* NOTE: Aliasing between input and output is allowed, so one has to make 160732b31808SJens Wiklander * sure that at the point X,Y,Z are written, {P,Q}->{X,Y,Z} are no 160832b31808SJens Wiklander * longer read from. */ 160932b31808SJens Wiklander mbedtls_mpi * const X = &R->X; 161032b31808SJens Wiklander mbedtls_mpi * const Y = &R->Y; 161132b31808SJens Wiklander mbedtls_mpi * const Z = &R->Z; 161232b31808SJens Wiklander 161332b31808SJens Wiklander if (!MPI_ECP_VALID(&Q->Z)) { 161432b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 161532b31808SJens Wiklander } 16167901324dSJerome Forissier 1617817466cbSJens Wiklander /* 1618817466cbSJens Wiklander * Trivial cases: P == 0 or Q == 0 (case 1) 1619817466cbSJens Wiklander */ 162032b31808SJens Wiklander if (MPI_ECP_CMP_INT(&P->Z, 0) == 0) { 162132b31808SJens Wiklander return mbedtls_ecp_copy(R, Q); 162232b31808SJens Wiklander } 1623817466cbSJens Wiklander 162432b31808SJens Wiklander if (MPI_ECP_CMP_INT(&Q->Z, 0) == 0) { 162532b31808SJens Wiklander return mbedtls_ecp_copy(R, P); 162632b31808SJens Wiklander } 1627817466cbSJens Wiklander 1628817466cbSJens Wiklander /* 1629817466cbSJens Wiklander * Make sure Q coordinates are normalized 1630817466cbSJens Wiklander */ 163132b31808SJens Wiklander if (MPI_ECP_CMP_INT(&Q->Z, 1) != 0) { 163232b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 163332b31808SJens Wiklander } 1634817466cbSJens Wiklander 163532b31808SJens Wiklander MPI_ECP_SQR(&tmp[0], &P->Z); 163632b31808SJens Wiklander MPI_ECP_MUL(&tmp[1], &tmp[0], &P->Z); 163732b31808SJens Wiklander MPI_ECP_MUL(&tmp[0], &tmp[0], &Q->X); 163832b31808SJens Wiklander MPI_ECP_MUL(&tmp[1], &tmp[1], &Q->Y); 163932b31808SJens Wiklander MPI_ECP_SUB(&tmp[0], &tmp[0], &P->X); 164032b31808SJens Wiklander MPI_ECP_SUB(&tmp[1], &tmp[1], &P->Y); 1641817466cbSJens Wiklander 1642817466cbSJens Wiklander /* Special cases (2) and (3) */ 164332b31808SJens Wiklander if (MPI_ECP_CMP_INT(&tmp[0], 0) == 0) { 164432b31808SJens Wiklander if (MPI_ECP_CMP_INT(&tmp[1], 0) == 0) { 164532b31808SJens Wiklander ret = ecp_double_jac(grp, R, P, tmp); 1646817466cbSJens Wiklander goto cleanup; 164732b31808SJens Wiklander } else { 1648817466cbSJens Wiklander ret = mbedtls_ecp_set_zero(R); 1649817466cbSJens Wiklander goto cleanup; 1650817466cbSJens Wiklander } 1651817466cbSJens Wiklander } 1652817466cbSJens Wiklander 165332b31808SJens Wiklander /* {P,Q}->Z no longer used, so OK to write to Z even if there's aliasing. */ 165432b31808SJens Wiklander MPI_ECP_MUL(Z, &P->Z, &tmp[0]); 165532b31808SJens Wiklander MPI_ECP_SQR(&tmp[2], &tmp[0]); 165632b31808SJens Wiklander MPI_ECP_MUL(&tmp[3], &tmp[2], &tmp[0]); 165732b31808SJens Wiklander MPI_ECP_MUL(&tmp[2], &tmp[2], &P->X); 1658817466cbSJens Wiklander 165932b31808SJens Wiklander MPI_ECP_MOV(&tmp[0], &tmp[2]); 166032b31808SJens Wiklander MPI_ECP_SHIFT_L(&tmp[0], 1); 166132b31808SJens Wiklander 166232b31808SJens Wiklander /* {P,Q}->X no longer used, so OK to write to X even if there's aliasing. */ 166332b31808SJens Wiklander MPI_ECP_SQR(X, &tmp[1]); 166432b31808SJens Wiklander MPI_ECP_SUB(X, X, &tmp[0]); 166532b31808SJens Wiklander MPI_ECP_SUB(X, X, &tmp[3]); 166632b31808SJens Wiklander MPI_ECP_SUB(&tmp[2], &tmp[2], X); 166732b31808SJens Wiklander MPI_ECP_MUL(&tmp[2], &tmp[2], &tmp[1]); 166832b31808SJens Wiklander MPI_ECP_MUL(&tmp[3], &tmp[3], &P->Y); 166932b31808SJens Wiklander /* {P,Q}->Y no longer used, so OK to write to Y even if there's aliasing. */ 167032b31808SJens Wiklander MPI_ECP_SUB(Y, &tmp[2], &tmp[3]); 1671817466cbSJens Wiklander 1672817466cbSJens Wiklander cleanup: 1673817466cbSJens Wiklander 167432b31808SJens Wiklander return ret; 16757901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_ADD_MIXED_ALT) */ 1676817466cbSJens Wiklander } 1677817466cbSJens Wiklander 1678817466cbSJens Wiklander /* 1679817466cbSJens Wiklander * Randomize jacobian coordinates: 1680817466cbSJens Wiklander * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l 1681817466cbSJens Wiklander * This is sort of the reverse operation of ecp_normalize_jac(). 1682817466cbSJens Wiklander * 1683817466cbSJens Wiklander * This countermeasure was first suggested in [2]. 1684817466cbSJens Wiklander */ 1685817466cbSJens Wiklander static int ecp_randomize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, 1686817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 1687817466cbSJens Wiklander { 1688817466cbSJens Wiklander #if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) 168932b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 169032b31808SJens Wiklander return mbedtls_internal_ecp_randomize_jac(grp, pt, f_rng, p_rng); 169132b31808SJens Wiklander } 1692817466cbSJens Wiklander #endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */ 1693817466cbSJens Wiklander 16947901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) 169532b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 16967901324dSJerome Forissier #else 16977901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 169832b31808SJens Wiklander mbedtls_mpi l; 16997901324dSJerome Forissier 170032b31808SJens Wiklander mbedtls_mpi_init(&l); 1701817466cbSJens Wiklander 1702817466cbSJens Wiklander /* Generate l such that 1 < l < p */ 170332b31808SJens Wiklander MPI_ECP_RAND(&l); 1704817466cbSJens Wiklander 170532b31808SJens Wiklander /* Z' = l * Z */ 170632b31808SJens Wiklander MPI_ECP_MUL(&pt->Z, &pt->Z, &l); 1707817466cbSJens Wiklander 170832b31808SJens Wiklander /* Y' = l * Y */ 170932b31808SJens Wiklander MPI_ECP_MUL(&pt->Y, &pt->Y, &l); 1710817466cbSJens Wiklander 171132b31808SJens Wiklander /* X' = l^2 * X */ 171232b31808SJens Wiklander MPI_ECP_SQR(&l, &l); 171332b31808SJens Wiklander MPI_ECP_MUL(&pt->X, &pt->X, &l); 171432b31808SJens Wiklander 171532b31808SJens Wiklander /* Y'' = l^2 * Y' = l^3 * Y */ 171632b31808SJens Wiklander MPI_ECP_MUL(&pt->Y, &pt->Y, &l); 1717817466cbSJens Wiklander 1718817466cbSJens Wiklander cleanup: 171932b31808SJens Wiklander mbedtls_mpi_free(&l); 1720817466cbSJens Wiklander 172132b31808SJens Wiklander if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { 17227901324dSJerome Forissier ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 172332b31808SJens Wiklander } 172432b31808SJens Wiklander return ret; 17257901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) */ 1726817466cbSJens Wiklander } 1727817466cbSJens Wiklander 1728817466cbSJens Wiklander /* 1729817466cbSJens Wiklander * Check and define parameters used by the comb method (see below for details) 1730817466cbSJens Wiklander */ 1731817466cbSJens Wiklander #if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 1732817466cbSJens Wiklander #error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" 1733817466cbSJens Wiklander #endif 1734817466cbSJens Wiklander 1735817466cbSJens Wiklander /* d = ceil( n / w ) */ 1736817466cbSJens Wiklander #define COMB_MAX_D (MBEDTLS_ECP_MAX_BITS + 1) / 2 1737817466cbSJens Wiklander 1738817466cbSJens Wiklander /* number of precomputed points */ 1739817466cbSJens Wiklander #define COMB_MAX_PRE (1 << (MBEDTLS_ECP_WINDOW_SIZE - 1)) 1740817466cbSJens Wiklander 1741817466cbSJens Wiklander /* 1742817466cbSJens Wiklander * Compute the representation of m that will be used with our comb method. 1743817466cbSJens Wiklander * 1744817466cbSJens Wiklander * The basic comb method is described in GECC 3.44 for example. We use a 1745817466cbSJens Wiklander * modified version that provides resistance to SPA by avoiding zero 1746817466cbSJens Wiklander * digits in the representation as in [3]. We modify the method further by 1747817466cbSJens Wiklander * requiring that all K_i be odd, which has the small cost that our 17483d3b0591SJens Wiklander * representation uses one more K_i, due to carries, but saves on the size of 17493d3b0591SJens Wiklander * the precomputed table. 1750817466cbSJens Wiklander * 17513d3b0591SJens Wiklander * Summary of the comb method and its modifications: 17523d3b0591SJens Wiklander * 17533d3b0591SJens Wiklander * - The goal is to compute m*P for some w*d-bit integer m. 17543d3b0591SJens Wiklander * 17553d3b0591SJens Wiklander * - The basic comb method splits m into the w-bit integers 17563d3b0591SJens Wiklander * x[0] .. x[d-1] where x[i] consists of the bits in m whose 17573d3b0591SJens Wiklander * index has residue i modulo d, and computes m * P as 17583d3b0591SJens Wiklander * S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where 17593d3b0591SJens Wiklander * S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P. 17603d3b0591SJens Wiklander * 17613d3b0591SJens Wiklander * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by 17623d3b0591SJens Wiklander * .. + 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]] .., 17633d3b0591SJens Wiklander * thereby successively converting it into a form where all summands 17643d3b0591SJens Wiklander * are nonzero, at the cost of negative summands. This is the basic idea of [3]. 17653d3b0591SJens Wiklander * 17663d3b0591SJens Wiklander * - More generally, even if x[i+1] != 0, we can first transform the sum as 17673d3b0591SJens Wiklander * .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] .., 17683d3b0591SJens Wiklander * and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]]. 17693d3b0591SJens Wiklander * Performing and iterating this procedure for those x[i] that are even 17703d3b0591SJens Wiklander * (keeping track of carry), we can transform the original sum into one of the form 17713d3b0591SJens Wiklander * S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]] 17723d3b0591SJens Wiklander * with all x'[i] odd. It is therefore only necessary to know S at odd indices, 17733d3b0591SJens Wiklander * which is why we are only computing half of it in the first place in 17743d3b0591SJens Wiklander * ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb. 17753d3b0591SJens Wiklander * 17763d3b0591SJens Wiklander * - For the sake of compactness, only the seven low-order bits of x[i] 17773d3b0591SJens Wiklander * are used to represent its absolute value (K_i in the paper), and the msb 17783d3b0591SJens Wiklander * of x[i] encodes the sign (s_i in the paper): it is set if and only if 17793d3b0591SJens Wiklander * if s_i == -1; 1780817466cbSJens Wiklander * 1781817466cbSJens Wiklander * Calling conventions: 1782817466cbSJens Wiklander * - x is an array of size d + 1 1783817466cbSJens Wiklander * - w is the size, ie number of teeth, of the comb, and must be between 1784817466cbSJens Wiklander * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) 1785817466cbSJens Wiklander * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d 1786817466cbSJens Wiklander * (the result will be incorrect if these assumptions are not satisfied) 1787817466cbSJens Wiklander */ 17883d3b0591SJens Wiklander static void ecp_comb_recode_core(unsigned char x[], size_t d, 1789817466cbSJens Wiklander unsigned char w, const mbedtls_mpi *m) 1790817466cbSJens Wiklander { 1791817466cbSJens Wiklander size_t i, j; 1792817466cbSJens Wiklander unsigned char c, cc, adjust; 1793817466cbSJens Wiklander 1794817466cbSJens Wiklander memset(x, 0, d+1); 1795817466cbSJens Wiklander 1796817466cbSJens Wiklander /* First get the classical comb values (except for x_d = 0) */ 179732b31808SJens Wiklander for (i = 0; i < d; i++) { 179832b31808SJens Wiklander for (j = 0; j < w; j++) { 1799817466cbSJens Wiklander x[i] |= mbedtls_mpi_get_bit(m, i + d * j) << j; 180032b31808SJens Wiklander } 180132b31808SJens Wiklander } 1802817466cbSJens Wiklander 1803817466cbSJens Wiklander /* Now make sure x_1 .. x_d are odd */ 1804817466cbSJens Wiklander c = 0; 180532b31808SJens Wiklander for (i = 1; i <= d; i++) { 1806817466cbSJens Wiklander /* Add carry and update it */ 1807817466cbSJens Wiklander cc = x[i] & c; 1808817466cbSJens Wiklander x[i] = x[i] ^ c; 1809817466cbSJens Wiklander c = cc; 1810817466cbSJens Wiklander 1811817466cbSJens Wiklander /* Adjust if needed, avoiding branches */ 1812817466cbSJens Wiklander adjust = 1 - (x[i] & 0x01); 1813817466cbSJens Wiklander c |= x[i] & (x[i-1] * adjust); 1814817466cbSJens Wiklander x[i] = x[i] ^ (x[i-1] * adjust); 1815817466cbSJens Wiklander x[i-1] |= adjust << 7; 1816817466cbSJens Wiklander } 1817817466cbSJens Wiklander } 1818817466cbSJens Wiklander 1819817466cbSJens Wiklander /* 18203d3b0591SJens Wiklander * Precompute points for the adapted comb method 1821817466cbSJens Wiklander * 18223d3b0591SJens Wiklander * Assumption: T must be able to hold 2^{w - 1} elements. 1823817466cbSJens Wiklander * 18243d3b0591SJens Wiklander * Operation: If i = i_{w-1} ... i_1 is the binary representation of i, 18253d3b0591SJens Wiklander * sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P. 1826817466cbSJens Wiklander * 1827817466cbSJens Wiklander * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) 18283d3b0591SJens Wiklander * 18293d3b0591SJens Wiklander * Note: Even comb values (those where P would be omitted from the 18303d3b0591SJens Wiklander * sum defining T[i] above) are not needed in our adaption 18313d3b0591SJens Wiklander * the comb method. See ecp_comb_recode_core(). 18323d3b0591SJens Wiklander * 18333d3b0591SJens Wiklander * This function currently works in four steps: 18343d3b0591SJens Wiklander * (1) [dbl] Computation of intermediate T[i] for 2-power values of i 18353d3b0591SJens Wiklander * (2) [norm_dbl] Normalization of coordinates of these T[i] 18363d3b0591SJens Wiklander * (3) [add] Computation of all T[i] 18373d3b0591SJens Wiklander * (4) [norm_add] Normalization of all T[i] 18383d3b0591SJens Wiklander * 18393d3b0591SJens Wiklander * Step 1 can be interrupted but not the others; together with the final 18403d3b0591SJens Wiklander * coordinate normalization they are the largest steps done at once, depending 18413d3b0591SJens Wiklander * on the window size. Here are operation counts for P-256: 18423d3b0591SJens Wiklander * 18433d3b0591SJens Wiklander * step (2) (3) (4) 18443d3b0591SJens Wiklander * w = 5 142 165 208 18453d3b0591SJens Wiklander * w = 4 136 77 160 18463d3b0591SJens Wiklander * w = 3 130 33 136 18473d3b0591SJens Wiklander * w = 2 124 11 124 18483d3b0591SJens Wiklander * 18493d3b0591SJens Wiklander * So if ECC operations are blocking for too long even with a low max_ops 18503d3b0591SJens Wiklander * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order 18513d3b0591SJens Wiklander * to minimize maximum blocking time. 1852817466cbSJens Wiklander */ 1853817466cbSJens Wiklander static int ecp_precompute_comb(const mbedtls_ecp_group *grp, 1854817466cbSJens Wiklander mbedtls_ecp_point T[], const mbedtls_ecp_point *P, 18553d3b0591SJens Wiklander unsigned char w, size_t d, 18563d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 1857817466cbSJens Wiklander { 185811fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 18593d3b0591SJens Wiklander unsigned char i; 18603d3b0591SJens Wiklander size_t j = 0; 18613d3b0591SJens Wiklander const unsigned char T_size = 1U << (w - 1); 186232b31808SJens Wiklander mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1] = { NULL }; 186332b31808SJens Wiklander 186432b31808SJens Wiklander mbedtls_mpi tmp[4]; 186532b31808SJens Wiklander 186632b31808SJens Wiklander mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 1867817466cbSJens Wiklander 18683d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 186932b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 187032b31808SJens Wiklander if (rs_ctx->rsm->state == ecp_rsm_pre_dbl) { 18713d3b0591SJens Wiklander goto dbl; 187232b31808SJens Wiklander } 187332b31808SJens Wiklander if (rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl) { 18743d3b0591SJens Wiklander goto norm_dbl; 187532b31808SJens Wiklander } 187632b31808SJens Wiklander if (rs_ctx->rsm->state == ecp_rsm_pre_add) { 18773d3b0591SJens Wiklander goto add; 187832b31808SJens Wiklander } 187932b31808SJens Wiklander if (rs_ctx->rsm->state == ecp_rsm_pre_norm_add) { 18803d3b0591SJens Wiklander goto norm_add; 18813d3b0591SJens Wiklander } 188232b31808SJens Wiklander } 18833d3b0591SJens Wiklander #else 18843d3b0591SJens Wiklander (void) rs_ctx; 18853d3b0591SJens Wiklander #endif 18863d3b0591SJens Wiklander 18873d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 188832b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 18893d3b0591SJens Wiklander rs_ctx->rsm->state = ecp_rsm_pre_dbl; 18903d3b0591SJens Wiklander 18913d3b0591SJens Wiklander /* initial state for the loop */ 18923d3b0591SJens Wiklander rs_ctx->rsm->i = 0; 18933d3b0591SJens Wiklander } 18943d3b0591SJens Wiklander 18953d3b0591SJens Wiklander dbl: 18963d3b0591SJens Wiklander #endif 1897817466cbSJens Wiklander /* 1898817466cbSJens Wiklander * Set T[0] = P and 1899817466cbSJens Wiklander * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value) 1900817466cbSJens Wiklander */ 1901817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&T[0], P)); 1902817466cbSJens Wiklander 19033d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 190432b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0) { 19053d3b0591SJens Wiklander j = rs_ctx->rsm->i; 190632b31808SJens Wiklander } else 19073d3b0591SJens Wiklander #endif 19083d3b0591SJens Wiklander j = 0; 1909817466cbSJens Wiklander 191032b31808SJens Wiklander for (; j < d * (w - 1); j++) { 19113d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL); 19123d3b0591SJens Wiklander 19133d3b0591SJens Wiklander i = 1U << (j / d); 19143d3b0591SJens Wiklander cur = T + i; 19153d3b0591SJens Wiklander 191632b31808SJens Wiklander if (j % d == 0) { 19173d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_copy(cur, T + (i >> 1))); 191832b31808SJens Wiklander } 19193d3b0591SJens Wiklander 192032b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_double_jac(grp, cur, cur, tmp)); 1921817466cbSJens Wiklander } 1922817466cbSJens Wiklander 19233d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 192432b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 19253d3b0591SJens Wiklander rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl; 192632b31808SJens Wiklander } 1927817466cbSJens Wiklander 19283d3b0591SJens Wiklander norm_dbl: 19293d3b0591SJens Wiklander #endif 19303d3b0591SJens Wiklander /* 193132b31808SJens Wiklander * Normalize current elements in T to allow them to be used in 193232b31808SJens Wiklander * ecp_add_mixed() below, which requires one normalized input. 193332b31808SJens Wiklander * 193432b31808SJens Wiklander * As T has holes, use an auxiliary array of pointers to elements in T. 193532b31808SJens Wiklander * 19363d3b0591SJens Wiklander */ 19373d3b0591SJens Wiklander j = 0; 193832b31808SJens Wiklander for (i = 1; i < T_size; i <<= 1) { 19393d3b0591SJens Wiklander TT[j++] = T + i; 194032b31808SJens Wiklander } 19413d3b0591SJens Wiklander 19423d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2); 19433d3b0591SJens Wiklander 19443d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j)); 19453d3b0591SJens Wiklander 19463d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 194732b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 19483d3b0591SJens Wiklander rs_ctx->rsm->state = ecp_rsm_pre_add; 194932b31808SJens Wiklander } 19503d3b0591SJens Wiklander 19513d3b0591SJens Wiklander add: 19523d3b0591SJens Wiklander #endif 1953817466cbSJens Wiklander /* 1954817466cbSJens Wiklander * Compute the remaining ones using the minimal number of additions 1955817466cbSJens Wiklander * Be careful to update T[2^l] only after using it! 1956817466cbSJens Wiklander */ 19573d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET((T_size - 1) * MBEDTLS_ECP_OPS_ADD); 19583d3b0591SJens Wiklander 195932b31808SJens Wiklander for (i = 1; i < T_size; i <<= 1) { 1960817466cbSJens Wiklander j = i; 196132b31808SJens Wiklander while (j--) { 196232b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_add_mixed(grp, &T[i + j], &T[j], &T[i], tmp)); 196332b31808SJens Wiklander } 1964817466cbSJens Wiklander } 1965817466cbSJens Wiklander 19663d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 196732b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 19683d3b0591SJens Wiklander rs_ctx->rsm->state = ecp_rsm_pre_norm_add; 196932b31808SJens Wiklander } 19703d3b0591SJens Wiklander 19713d3b0591SJens Wiklander norm_add: 19723d3b0591SJens Wiklander #endif 19733d3b0591SJens Wiklander /* 19743d3b0591SJens Wiklander * Normalize final elements in T. Even though there are no holes now, we 19753d3b0591SJens Wiklander * still need the auxiliary array for homogeneity with the previous 19763d3b0591SJens Wiklander * call. Also, skip T[0] which is already normalised, being a copy of P. 19773d3b0591SJens Wiklander */ 197832b31808SJens Wiklander for (j = 0; j + 1 < T_size; j++) { 19793d3b0591SJens Wiklander TT[j] = T + j + 1; 198032b31808SJens Wiklander } 19813d3b0591SJens Wiklander 19823d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2); 19833d3b0591SJens Wiklander 19843d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j)); 1985817466cbSJens Wiklander 198632b31808SJens Wiklander /* Free Z coordinate (=1 after normalization) to save RAM. 198732b31808SJens Wiklander * This makes T[i] invalid as mbedtls_ecp_points, but this is OK 198832b31808SJens Wiklander * since from this point onwards, they are only accessed indirectly 198932b31808SJens Wiklander * via the getter function ecp_select_comb() which does set the 199032b31808SJens Wiklander * target's Z coordinate to 1. */ 199132b31808SJens Wiklander for (i = 0; i < T_size; i++) { 199232b31808SJens Wiklander mbedtls_mpi_free(&T[i].Z); 199332b31808SJens Wiklander } 199432b31808SJens Wiklander 1995817466cbSJens Wiklander cleanup: 199632b31808SJens Wiklander 199732b31808SJens Wiklander mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 199832b31808SJens Wiklander 19993d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 20003d3b0591SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL && 200132b31808SJens Wiklander ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 200232b31808SJens Wiklander if (rs_ctx->rsm->state == ecp_rsm_pre_dbl) { 20033d3b0591SJens Wiklander rs_ctx->rsm->i = j; 20043d3b0591SJens Wiklander } 200532b31808SJens Wiklander } 20063d3b0591SJens Wiklander #endif 2007817466cbSJens Wiklander 200832b31808SJens Wiklander return ret; 2009817466cbSJens Wiklander } 2010817466cbSJens Wiklander 2011817466cbSJens Wiklander /* 2012817466cbSJens Wiklander * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] 20133d3b0591SJens Wiklander * 20143d3b0591SJens Wiklander * See ecp_comb_recode_core() for background 2015817466cbSJens Wiklander */ 2016817466cbSJens Wiklander static int ecp_select_comb(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 20173d3b0591SJens Wiklander const mbedtls_ecp_point T[], unsigned char T_size, 2018817466cbSJens Wiklander unsigned char i) 2019817466cbSJens Wiklander { 202011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2021817466cbSJens Wiklander unsigned char ii, j; 2022817466cbSJens Wiklander 2023817466cbSJens Wiklander /* Ignore the "sign" bit and scale down */ 2024817466cbSJens Wiklander ii = (i & 0x7Fu) >> 1; 2025817466cbSJens Wiklander 2026817466cbSJens Wiklander /* Read the whole table to thwart cache-based timing attacks */ 202732b31808SJens Wiklander for (j = 0; j < T_size; j++) { 202832b31808SJens Wiklander MPI_ECP_COND_ASSIGN(&R->X, &T[j].X, j == ii); 202932b31808SJens Wiklander MPI_ECP_COND_ASSIGN(&R->Y, &T[j].Y, j == ii); 2030817466cbSJens Wiklander } 2031817466cbSJens Wiklander 2032817466cbSJens Wiklander /* Safely invert result if i is "negative" */ 2033817466cbSJens Wiklander MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, R, i >> 7)); 2034817466cbSJens Wiklander 203532b31808SJens Wiklander MPI_ECP_LSET(&R->Z, 1); 203632b31808SJens Wiklander 2037817466cbSJens Wiklander cleanup: 203832b31808SJens Wiklander return ret; 2039817466cbSJens Wiklander } 2040817466cbSJens Wiklander 2041817466cbSJens Wiklander /* 2042817466cbSJens Wiklander * Core multiplication algorithm for the (modified) comb method. 2043817466cbSJens Wiklander * This part is actually common with the basic comb method (GECC 3.44) 2044817466cbSJens Wiklander * 2045817466cbSJens Wiklander * Cost: d A + d D + 1 R 2046817466cbSJens Wiklander */ 2047817466cbSJens Wiklander static int ecp_mul_comb_core(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 20483d3b0591SJens Wiklander const mbedtls_ecp_point T[], unsigned char T_size, 2049817466cbSJens Wiklander const unsigned char x[], size_t d, 2050817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 20513d3b0591SJens Wiklander void *p_rng, 20523d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 2053817466cbSJens Wiklander { 205411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2055817466cbSJens Wiklander mbedtls_ecp_point Txi; 205632b31808SJens Wiklander mbedtls_mpi tmp[4]; 2057817466cbSJens Wiklander size_t i; 2058817466cbSJens Wiklander 2059817466cbSJens Wiklander mbedtls_ecp_point_init(&Txi); 206032b31808SJens Wiklander mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2061817466cbSJens Wiklander 20623d3b0591SJens Wiklander #if !defined(MBEDTLS_ECP_RESTARTABLE) 20633d3b0591SJens Wiklander (void) rs_ctx; 20643d3b0591SJens Wiklander #endif 20653d3b0591SJens Wiklander 20663d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 20673d3b0591SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL && 206832b31808SJens Wiklander rs_ctx->rsm->state != ecp_rsm_comb_core) { 20693d3b0591SJens Wiklander rs_ctx->rsm->i = 0; 20703d3b0591SJens Wiklander rs_ctx->rsm->state = ecp_rsm_comb_core; 20713d3b0591SJens Wiklander } 20723d3b0591SJens Wiklander 20733d3b0591SJens Wiklander /* new 'if' instead of nested for the sake of the 'else' branch */ 207432b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0) { 20753d3b0591SJens Wiklander /* restore current index (R already pointing to rs_ctx->rsm->R) */ 20763d3b0591SJens Wiklander i = rs_ctx->rsm->i; 207732b31808SJens Wiklander } else 20783d3b0591SJens Wiklander #endif 20793d3b0591SJens Wiklander { 2080817466cbSJens Wiklander /* Start with a non-zero point and randomize its coordinates */ 2081817466cbSJens Wiklander i = d; 20823d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_select_comb(grp, R, T, T_size, x[i])); 208332b31808SJens Wiklander if (f_rng != 0) { 2084817466cbSJens Wiklander MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, R, f_rng, p_rng)); 20853d3b0591SJens Wiklander } 208632b31808SJens Wiklander } 2087817466cbSJens Wiklander 208832b31808SJens Wiklander while (i != 0) { 20893d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD); 20903d3b0591SJens Wiklander --i; 20913d3b0591SJens Wiklander 209232b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_double_jac(grp, R, R, tmp)); 20933d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_select_comb(grp, &Txi, T, T_size, x[i])); 209432b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_add_mixed(grp, R, R, &Txi, tmp)); 2095817466cbSJens Wiklander } 2096817466cbSJens Wiklander 2097817466cbSJens Wiklander cleanup: 2098817466cbSJens Wiklander 2099817466cbSJens Wiklander mbedtls_ecp_point_free(&Txi); 210032b31808SJens Wiklander mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 2101817466cbSJens Wiklander 21023d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 21033d3b0591SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL && 210432b31808SJens Wiklander ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 21053d3b0591SJens Wiklander rs_ctx->rsm->i = i; 21063d3b0591SJens Wiklander /* no need to save R, already pointing to rs_ctx->rsm->R */ 21073d3b0591SJens Wiklander } 21083d3b0591SJens Wiklander #endif 21093d3b0591SJens Wiklander 211032b31808SJens Wiklander return ret; 2111817466cbSJens Wiklander } 2112817466cbSJens Wiklander 2113817466cbSJens Wiklander /* 21143d3b0591SJens Wiklander * Recode the scalar to get constant-time comb multiplication 21153d3b0591SJens Wiklander * 21163d3b0591SJens Wiklander * As the actual scalar recoding needs an odd scalar as a starting point, 21173d3b0591SJens Wiklander * this wrapper ensures that by replacing m by N - m if necessary, and 21183d3b0591SJens Wiklander * informs the caller that the result of multiplication will be negated. 21193d3b0591SJens Wiklander * 21203d3b0591SJens Wiklander * This works because we only support large prime order for Short Weierstrass 21213d3b0591SJens Wiklander * curves, so N is always odd hence either m or N - m is. 21223d3b0591SJens Wiklander * 21233d3b0591SJens Wiklander * See ecp_comb_recode_core() for background. 2124817466cbSJens Wiklander */ 21253d3b0591SJens Wiklander static int ecp_comb_recode_scalar(const mbedtls_ecp_group *grp, 21263d3b0591SJens Wiklander const mbedtls_mpi *m, 21273d3b0591SJens Wiklander unsigned char k[COMB_MAX_D + 1], 21283d3b0591SJens Wiklander size_t d, 21293d3b0591SJens Wiklander unsigned char w, 21303d3b0591SJens Wiklander unsigned char *parity_trick) 2131817466cbSJens Wiklander { 213211fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2133817466cbSJens Wiklander mbedtls_mpi M, mm; 2134817466cbSJens Wiklander 2135817466cbSJens Wiklander mbedtls_mpi_init(&M); 2136817466cbSJens Wiklander mbedtls_mpi_init(&mm); 2137817466cbSJens Wiklander 21383d3b0591SJens Wiklander /* N is always odd (see above), just make extra sure */ 213932b31808SJens Wiklander if (mbedtls_mpi_get_bit(&grp->N, 0) != 1) { 214032b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 214132b31808SJens Wiklander } 2142817466cbSJens Wiklander 21433d3b0591SJens Wiklander /* do we need the parity trick? */ 21443d3b0591SJens Wiklander *parity_trick = (mbedtls_mpi_get_bit(m, 0) == 0); 21453d3b0591SJens Wiklander 21463d3b0591SJens Wiklander /* execute parity fix in constant time */ 21473d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&M, m)); 21483d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&mm, &grp->N, m)); 21493d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&M, &mm, *parity_trick)); 21503d3b0591SJens Wiklander 21513d3b0591SJens Wiklander /* actual scalar recoding */ 21523d3b0591SJens Wiklander ecp_comb_recode_core(k, d, w, &M); 21533d3b0591SJens Wiklander 21543d3b0591SJens Wiklander cleanup: 21553d3b0591SJens Wiklander mbedtls_mpi_free(&mm); 21563d3b0591SJens Wiklander mbedtls_mpi_free(&M); 21573d3b0591SJens Wiklander 215832b31808SJens Wiklander return ret; 21593d3b0591SJens Wiklander } 21603d3b0591SJens Wiklander 21613d3b0591SJens Wiklander /* 21623d3b0591SJens Wiklander * Perform comb multiplication (for short Weierstrass curves) 21633d3b0591SJens Wiklander * once the auxiliary table has been pre-computed. 21643d3b0591SJens Wiklander * 21653d3b0591SJens Wiklander * Scalar recoding may use a parity trick that makes us compute -m * P, 21663d3b0591SJens Wiklander * if that is the case we'll need to recover m * P at the end. 21673d3b0591SJens Wiklander */ 21683d3b0591SJens Wiklander static int ecp_mul_comb_after_precomp(const mbedtls_ecp_group *grp, 21693d3b0591SJens Wiklander mbedtls_ecp_point *R, 21703d3b0591SJens Wiklander const mbedtls_mpi *m, 21713d3b0591SJens Wiklander const mbedtls_ecp_point *T, 21723d3b0591SJens Wiklander unsigned char T_size, 21733d3b0591SJens Wiklander unsigned char w, 21743d3b0591SJens Wiklander size_t d, 21753d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 21763d3b0591SJens Wiklander void *p_rng, 21773d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 21783d3b0591SJens Wiklander { 217911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 21803d3b0591SJens Wiklander unsigned char parity_trick; 21813d3b0591SJens Wiklander unsigned char k[COMB_MAX_D + 1]; 21823d3b0591SJens Wiklander mbedtls_ecp_point *RR = R; 21833d3b0591SJens Wiklander 21843d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 218532b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 21863d3b0591SJens Wiklander RR = &rs_ctx->rsm->R; 21873d3b0591SJens Wiklander 218832b31808SJens Wiklander if (rs_ctx->rsm->state == ecp_rsm_final_norm) { 21893d3b0591SJens Wiklander goto final_norm; 21903d3b0591SJens Wiklander } 219132b31808SJens Wiklander } 21923d3b0591SJens Wiklander #endif 21933d3b0591SJens Wiklander 21943d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_comb_recode_scalar(grp, m, k, d, w, 21953d3b0591SJens Wiklander &parity_trick)); 21963d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_mul_comb_core(grp, RR, T, T_size, k, d, 21973d3b0591SJens Wiklander f_rng, p_rng, rs_ctx)); 21983d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, RR, parity_trick)); 21993d3b0591SJens Wiklander 22003d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 220132b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 22023d3b0591SJens Wiklander rs_ctx->rsm->state = ecp_rsm_final_norm; 220332b31808SJens Wiklander } 22043d3b0591SJens Wiklander 22053d3b0591SJens Wiklander final_norm: 22067901324dSJerome Forissier MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV); 22073d3b0591SJens Wiklander #endif 220811fa71b9SJerome Forissier /* 220911fa71b9SJerome Forissier * Knowledge of the jacobian coordinates may leak the last few bits of the 221011fa71b9SJerome Forissier * scalar [1], and since our MPI implementation isn't constant-flow, 221111fa71b9SJerome Forissier * inversion (used for coordinate normalization) may leak the full value 221211fa71b9SJerome Forissier * of its input via side-channels [2]. 221311fa71b9SJerome Forissier * 221411fa71b9SJerome Forissier * [1] https://eprint.iacr.org/2003/191 221511fa71b9SJerome Forissier * [2] https://eprint.iacr.org/2020/055 221611fa71b9SJerome Forissier * 221711fa71b9SJerome Forissier * Avoid the leak by randomizing coordinates before we normalize them. 221811fa71b9SJerome Forissier */ 221932b31808SJens Wiklander if (f_rng != 0) { 222011fa71b9SJerome Forissier MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, RR, f_rng, p_rng)); 222132b31808SJens Wiklander } 222211fa71b9SJerome Forissier 22233d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, RR)); 22243d3b0591SJens Wiklander 22253d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 222632b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL) { 22273d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, RR)); 222832b31808SJens Wiklander } 22293d3b0591SJens Wiklander #endif 22303d3b0591SJens Wiklander 22313d3b0591SJens Wiklander cleanup: 223232b31808SJens Wiklander return ret; 22333d3b0591SJens Wiklander } 22343d3b0591SJens Wiklander 22353d3b0591SJens Wiklander /* 22363d3b0591SJens Wiklander * Pick window size based on curve size and whether we optimize for base point 22373d3b0591SJens Wiklander */ 22383d3b0591SJens Wiklander static unsigned char ecp_pick_window_size(const mbedtls_ecp_group *grp, 22393d3b0591SJens Wiklander unsigned char p_eq_g) 22403d3b0591SJens Wiklander { 22413d3b0591SJens Wiklander unsigned char w; 22423d3b0591SJens Wiklander 2243817466cbSJens Wiklander /* 2244817466cbSJens Wiklander * Minimize the number of multiplications, that is minimize 2245817466cbSJens Wiklander * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w ) 2246817466cbSJens Wiklander * (see costs of the various parts, with 1S = 1M) 2247817466cbSJens Wiklander */ 2248817466cbSJens Wiklander w = grp->nbits >= 384 ? 5 : 4; 2249817466cbSJens Wiklander 2250817466cbSJens Wiklander /* 2251817466cbSJens Wiklander * If P == G, pre-compute a bit more, since this may be re-used later. 2252817466cbSJens Wiklander * Just adding one avoids upping the cost of the first mul too much, 2253817466cbSJens Wiklander * and the memory cost too. 2254817466cbSJens Wiklander */ 225532b31808SJens Wiklander if (p_eq_g) { 2256817466cbSJens Wiklander w++; 225732b31808SJens Wiklander } 2258817466cbSJens Wiklander 2259817466cbSJens Wiklander /* 226032b31808SJens Wiklander * If static comb table may not be used (!p_eq_g) or static comb table does 226132b31808SJens Wiklander * not exists, make sure w is within bounds. 2262817466cbSJens Wiklander * (The last test is useful only for very small curves in the test suite.) 226332b31808SJens Wiklander * 226432b31808SJens Wiklander * The user reduces MBEDTLS_ECP_WINDOW_SIZE does not changes the size of 226532b31808SJens Wiklander * static comb table, because the size of static comb table is fixed when 226632b31808SJens Wiklander * it is generated. 2267817466cbSJens Wiklander */ 226811fa71b9SJerome Forissier #if (MBEDTLS_ECP_WINDOW_SIZE < 6) 226932b31808SJens Wiklander if ((!p_eq_g || !ecp_group_is_static_comb_table(grp)) && w > MBEDTLS_ECP_WINDOW_SIZE) { 2270817466cbSJens Wiklander w = MBEDTLS_ECP_WINDOW_SIZE; 227132b31808SJens Wiklander } 227211fa71b9SJerome Forissier #endif 227332b31808SJens Wiklander if (w >= grp->nbits) { 2274817466cbSJens Wiklander w = 2; 227532b31808SJens Wiklander } 2276817466cbSJens Wiklander 227732b31808SJens Wiklander return w; 22783d3b0591SJens Wiklander } 2279817466cbSJens Wiklander 2280817466cbSJens Wiklander /* 22813d3b0591SJens Wiklander * Multiplication using the comb method - for curves in short Weierstrass form 22823d3b0591SJens Wiklander * 22833d3b0591SJens Wiklander * This function is mainly responsible for administrative work: 22843d3b0591SJens Wiklander * - managing the restart context if enabled 22853d3b0591SJens Wiklander * - managing the table of precomputed points (passed between the below two 2286039e02dfSJerome Forissier * functions): allocation, computation, ownership transfer, freeing. 22873d3b0591SJens Wiklander * 22883d3b0591SJens Wiklander * It delegates the actual arithmetic work to: 22893d3b0591SJens Wiklander * ecp_precompute_comb() and ecp_mul_comb_with_precomp() 22903d3b0591SJens Wiklander * 22913d3b0591SJens Wiklander * See comments on ecp_comb_recode_core() regarding the computation strategy. 2292817466cbSJens Wiklander */ 22933d3b0591SJens Wiklander static int ecp_mul_comb(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 22943d3b0591SJens Wiklander const mbedtls_mpi *m, const mbedtls_ecp_point *P, 22953d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 22963d3b0591SJens Wiklander void *p_rng, 22973d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 2298817466cbSJens Wiklander { 229911fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 23003d3b0591SJens Wiklander unsigned char w, p_eq_g, i; 23013d3b0591SJens Wiklander size_t d; 23027901324dSJerome Forissier unsigned char T_size = 0, T_ok = 0; 23037901324dSJerome Forissier mbedtls_ecp_point *T = NULL; 23043d3b0591SJens Wiklander 23053d3b0591SJens Wiklander ECP_RS_ENTER(rsm); 23063d3b0591SJens Wiklander 23073d3b0591SJens Wiklander /* Is P the base point ? */ 23083d3b0591SJens Wiklander #if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1 230932b31808SJens Wiklander p_eq_g = (MPI_ECP_CMP(&P->Y, &grp->G.Y) == 0 && 231032b31808SJens Wiklander MPI_ECP_CMP(&P->X, &grp->G.X) == 0); 23113d3b0591SJens Wiklander #else 23123d3b0591SJens Wiklander p_eq_g = 0; 23133d3b0591SJens Wiklander #endif 23143d3b0591SJens Wiklander 23153d3b0591SJens Wiklander /* Pick window size and deduce related sizes */ 23163d3b0591SJens Wiklander w = ecp_pick_window_size(grp, p_eq_g); 23173d3b0591SJens Wiklander T_size = 1U << (w - 1); 23183d3b0591SJens Wiklander d = (grp->nbits + w - 1) / w; 23193d3b0591SJens Wiklander 23203d3b0591SJens Wiklander /* Pre-computed table: do we have it already for the base point? */ 232132b31808SJens Wiklander if (p_eq_g && grp->T != NULL) { 23223d3b0591SJens Wiklander /* second pointer to the same table, will be deleted on exit */ 23233d3b0591SJens Wiklander T = grp->T; 23243d3b0591SJens Wiklander T_ok = 1; 232532b31808SJens Wiklander } else 23263d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 23273d3b0591SJens Wiklander /* Pre-computed table: do we have one in progress? complete? */ 232832b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL) { 23293d3b0591SJens Wiklander /* transfer ownership of T from rsm to local function */ 23303d3b0591SJens Wiklander T = rs_ctx->rsm->T; 23313d3b0591SJens Wiklander rs_ctx->rsm->T = NULL; 23323d3b0591SJens Wiklander rs_ctx->rsm->T_size = 0; 23333d3b0591SJens Wiklander 23343d3b0591SJens Wiklander /* This effectively jumps to the call to mul_comb_after_precomp() */ 23353d3b0591SJens Wiklander T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core; 233632b31808SJens Wiklander } else 23373d3b0591SJens Wiklander #endif 23383d3b0591SJens Wiklander /* Allocate table if we didn't have any */ 23393d3b0591SJens Wiklander { 23403d3b0591SJens Wiklander T = mbedtls_calloc(T_size, sizeof(mbedtls_ecp_point)); 234132b31808SJens Wiklander if (T == NULL) { 2342817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_ALLOC_FAILED; 2343817466cbSJens Wiklander goto cleanup; 2344817466cbSJens Wiklander } 2345817466cbSJens Wiklander 234632b31808SJens Wiklander for (i = 0; i < T_size; i++) { 23473d3b0591SJens Wiklander mbedtls_ecp_point_init(&T[i]); 234832b31808SJens Wiklander } 23493d3b0591SJens Wiklander 23503d3b0591SJens Wiklander T_ok = 0; 23513d3b0591SJens Wiklander } 23523d3b0591SJens Wiklander 23533d3b0591SJens Wiklander /* Compute table (or finish computing it) if not done already */ 235432b31808SJens Wiklander if (!T_ok) { 23553d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_precompute_comb(grp, T, P, w, d, rs_ctx)); 2356817466cbSJens Wiklander 235732b31808SJens Wiklander if (p_eq_g) { 23583d3b0591SJens Wiklander /* almost transfer ownership of T to the group, but keep a copy of 23593d3b0591SJens Wiklander * the pointer to use for calling the next function more easily */ 2360817466cbSJens Wiklander grp->T = T; 23613d3b0591SJens Wiklander grp->T_size = T_size; 2362817466cbSJens Wiklander } 2363817466cbSJens Wiklander } 2364817466cbSJens Wiklander 23653d3b0591SJens Wiklander /* Actual comb multiplication using precomputed points */ 23663d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_mul_comb_after_precomp(grp, R, m, 23673d3b0591SJens Wiklander T, T_size, w, d, 23683d3b0591SJens Wiklander f_rng, p_rng, rs_ctx)); 2369817466cbSJens Wiklander 2370817466cbSJens Wiklander cleanup: 2371817466cbSJens Wiklander 23723d3b0591SJens Wiklander /* does T belong to the group? */ 237332b31808SJens Wiklander if (T == grp->T) { 23743d3b0591SJens Wiklander T = NULL; 237532b31808SJens Wiklander } 23763d3b0591SJens Wiklander 23773d3b0591SJens Wiklander /* does T belong to the restart context? */ 23783d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 237932b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->rsm != NULL && ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL) { 23803d3b0591SJens Wiklander /* transfer ownership of T from local function to rsm */ 23813d3b0591SJens Wiklander rs_ctx->rsm->T_size = T_size; 23823d3b0591SJens Wiklander rs_ctx->rsm->T = T; 23833d3b0591SJens Wiklander T = NULL; 23843d3b0591SJens Wiklander } 23853d3b0591SJens Wiklander #endif 23863d3b0591SJens Wiklander 23873d3b0591SJens Wiklander /* did T belong to us? then let's destroy it! */ 238832b31808SJens Wiklander if (T != NULL) { 238932b31808SJens Wiklander for (i = 0; i < T_size; i++) { 2390817466cbSJens Wiklander mbedtls_ecp_point_free(&T[i]); 239132b31808SJens Wiklander } 2392817466cbSJens Wiklander mbedtls_free(T); 2393817466cbSJens Wiklander } 2394817466cbSJens Wiklander 23953d3b0591SJens Wiklander /* prevent caller from using invalid value */ 239632b31808SJens Wiklander int should_free_R = (ret != 0); 239732b31808SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 239832b31808SJens Wiklander /* don't free R while in progress in case R == P */ 239932b31808SJens Wiklander if (ret == MBEDTLS_ERR_ECP_IN_PROGRESS) { 240032b31808SJens Wiklander should_free_R = 0; 240132b31808SJens Wiklander } 240232b31808SJens Wiklander #endif 240332b31808SJens Wiklander if (should_free_R) { 2404817466cbSJens Wiklander mbedtls_ecp_point_free(R); 240532b31808SJens Wiklander } 2406817466cbSJens Wiklander 24073d3b0591SJens Wiklander ECP_RS_LEAVE(rsm); 24083d3b0591SJens Wiklander 240932b31808SJens Wiklander return ret; 2410817466cbSJens Wiklander } 2411817466cbSJens Wiklander 24127901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 2413817466cbSJens Wiklander 24147901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 2415817466cbSJens Wiklander /* 2416817466cbSJens Wiklander * For Montgomery curves, we do all the internal arithmetic in projective 2417817466cbSJens Wiklander * coordinates. Import/export of points uses only the x coordinates, which is 2418039e02dfSJerome Forissier * internally represented as X / Z. 2419817466cbSJens Wiklander * 2420817466cbSJens Wiklander * For scalar multiplication, we'll use a Montgomery ladder. 2421817466cbSJens Wiklander */ 2422817466cbSJens Wiklander 2423817466cbSJens Wiklander /* 2424817466cbSJens Wiklander * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 2425817466cbSJens Wiklander * Cost: 1M + 1I 2426817466cbSJens Wiklander */ 2427817466cbSJens Wiklander static int ecp_normalize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P) 2428817466cbSJens Wiklander { 2429817466cbSJens Wiklander #if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) 243032b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 243132b31808SJens Wiklander return mbedtls_internal_ecp_normalize_mxz(grp, P); 243232b31808SJens Wiklander } 2433817466cbSJens Wiklander #endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */ 2434817466cbSJens Wiklander 24357901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) 243632b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 24377901324dSJerome Forissier #else 24387901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 243932b31808SJens Wiklander MPI_ECP_INV(&P->Z, &P->Z); 244032b31808SJens Wiklander MPI_ECP_MUL(&P->X, &P->X, &P->Z); 244132b31808SJens Wiklander MPI_ECP_LSET(&P->Z, 1); 2442817466cbSJens Wiklander 2443817466cbSJens Wiklander cleanup: 244432b31808SJens Wiklander return ret; 24457901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) */ 2446817466cbSJens Wiklander } 2447817466cbSJens Wiklander 2448817466cbSJens Wiklander /* 2449817466cbSJens Wiklander * Randomize projective x/z coordinates: 2450817466cbSJens Wiklander * (X, Z) -> (l X, l Z) for random l 2451817466cbSJens Wiklander * This is sort of the reverse operation of ecp_normalize_mxz(). 2452817466cbSJens Wiklander * 2453817466cbSJens Wiklander * This countermeasure was first suggested in [2]. 2454817466cbSJens Wiklander * Cost: 2M 2455817466cbSJens Wiklander */ 2456817466cbSJens Wiklander static int ecp_randomize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, 2457817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 2458817466cbSJens Wiklander { 2459817466cbSJens Wiklander #if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) 246032b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 246132b31808SJens Wiklander return mbedtls_internal_ecp_randomize_mxz(grp, P, f_rng, p_rng); 246232b31808SJens Wiklander } 2463817466cbSJens Wiklander #endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */ 2464817466cbSJens Wiklander 24657901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) 246632b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 24677901324dSJerome Forissier #else 24687901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 24697901324dSJerome Forissier mbedtls_mpi l; 2470817466cbSJens Wiklander mbedtls_mpi_init(&l); 2471817466cbSJens Wiklander 2472817466cbSJens Wiklander /* Generate l such that 1 < l < p */ 247332b31808SJens Wiklander MPI_ECP_RAND(&l); 2474817466cbSJens Wiklander 247532b31808SJens Wiklander MPI_ECP_MUL(&P->X, &P->X, &l); 247632b31808SJens Wiklander MPI_ECP_MUL(&P->Z, &P->Z, &l); 2477817466cbSJens Wiklander 2478817466cbSJens Wiklander cleanup: 2479817466cbSJens Wiklander mbedtls_mpi_free(&l); 2480817466cbSJens Wiklander 248132b31808SJens Wiklander if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE) { 24827901324dSJerome Forissier ret = MBEDTLS_ERR_ECP_RANDOM_FAILED; 248332b31808SJens Wiklander } 248432b31808SJens Wiklander return ret; 24857901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) */ 2486817466cbSJens Wiklander } 2487817466cbSJens Wiklander 2488817466cbSJens Wiklander /* 2489817466cbSJens Wiklander * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), 2490817466cbSJens Wiklander * for Montgomery curves in x/z coordinates. 2491817466cbSJens Wiklander * 2492817466cbSJens Wiklander * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 2493817466cbSJens Wiklander * with 2494817466cbSJens Wiklander * d = X1 2495817466cbSJens Wiklander * P = (X2, Z2) 2496817466cbSJens Wiklander * Q = (X3, Z3) 2497817466cbSJens Wiklander * R = (X4, Z4) 2498817466cbSJens Wiklander * S = (X5, Z5) 2499817466cbSJens Wiklander * and eliminating temporary variables tO, ..., t4. 2500817466cbSJens Wiklander * 2501817466cbSJens Wiklander * Cost: 5M + 4S 2502817466cbSJens Wiklander */ 2503817466cbSJens Wiklander static int ecp_double_add_mxz(const mbedtls_ecp_group *grp, 2504817466cbSJens Wiklander mbedtls_ecp_point *R, mbedtls_ecp_point *S, 2505817466cbSJens Wiklander const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, 250632b31808SJens Wiklander const mbedtls_mpi *d, 250732b31808SJens Wiklander mbedtls_mpi T[4]) 2508817466cbSJens Wiklander { 2509817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) 251032b31808SJens Wiklander if (mbedtls_internal_ecp_grp_capable(grp)) { 251132b31808SJens Wiklander return mbedtls_internal_ecp_double_add_mxz(grp, R, S, P, Q, d); 251232b31808SJens Wiklander } 2513817466cbSJens Wiklander #endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */ 2514817466cbSJens Wiklander 25157901324dSJerome Forissier #if defined(MBEDTLS_ECP_NO_FALLBACK) && defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) 251632b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 25177901324dSJerome Forissier #else 25187901324dSJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 25197901324dSJerome Forissier 252032b31808SJens Wiklander MPI_ECP_ADD(&T[0], &P->X, &P->Z); /* Pp := PX + PZ */ 252132b31808SJens Wiklander MPI_ECP_SUB(&T[1], &P->X, &P->Z); /* Pm := PX - PZ */ 252232b31808SJens Wiklander MPI_ECP_ADD(&T[2], &Q->X, &Q->Z); /* Qp := QX + XZ */ 252332b31808SJens Wiklander MPI_ECP_SUB(&T[3], &Q->X, &Q->Z); /* Qm := QX - QZ */ 252432b31808SJens Wiklander MPI_ECP_MUL(&T[3], &T[3], &T[0]); /* Qm * Pp */ 252532b31808SJens Wiklander MPI_ECP_MUL(&T[2], &T[2], &T[1]); /* Qp * Pm */ 252632b31808SJens Wiklander MPI_ECP_SQR(&T[0], &T[0]); /* Pp^2 */ 252732b31808SJens Wiklander MPI_ECP_SQR(&T[1], &T[1]); /* Pm^2 */ 252832b31808SJens Wiklander MPI_ECP_MUL(&R->X, &T[0], &T[1]); /* Pp^2 * Pm^2 */ 252932b31808SJens Wiklander MPI_ECP_SUB(&T[0], &T[0], &T[1]); /* Pp^2 - Pm^2 */ 253032b31808SJens Wiklander MPI_ECP_MUL(&R->Z, &grp->A, &T[0]); /* A * (Pp^2 - Pm^2) */ 253132b31808SJens Wiklander MPI_ECP_ADD(&R->Z, &T[1], &R->Z); /* [ A * (Pp^2-Pm^2) ] + Pm^2 */ 253232b31808SJens Wiklander MPI_ECP_ADD(&S->X, &T[3], &T[2]); /* Qm*Pp + Qp*Pm */ 253332b31808SJens Wiklander MPI_ECP_SQR(&S->X, &S->X); /* (Qm*Pp + Qp*Pm)^2 */ 253432b31808SJens Wiklander MPI_ECP_SUB(&S->Z, &T[3], &T[2]); /* Qm*Pp - Qp*Pm */ 253532b31808SJens Wiklander MPI_ECP_SQR(&S->Z, &S->Z); /* (Qm*Pp - Qp*Pm)^2 */ 253632b31808SJens Wiklander MPI_ECP_MUL(&S->Z, d, &S->Z); /* d * ( Qm*Pp - Qp*Pm )^2 */ 253732b31808SJens Wiklander MPI_ECP_MUL(&R->Z, &T[0], &R->Z); /* [A*(Pp^2-Pm^2)+Pm^2]*(Pp^2-Pm^2) */ 2538817466cbSJens Wiklander 2539817466cbSJens Wiklander cleanup: 2540817466cbSJens Wiklander 254132b31808SJens Wiklander return ret; 25427901324dSJerome Forissier #endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || !defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) */ 2543817466cbSJens Wiklander } 2544817466cbSJens Wiklander 2545817466cbSJens Wiklander /* 2546817466cbSJens Wiklander * Multiplication with Montgomery ladder in x/z coordinates, 2547817466cbSJens Wiklander * for curves in Montgomery form 2548817466cbSJens Wiklander */ 2549817466cbSJens Wiklander static int ecp_mul_mxz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2550817466cbSJens Wiklander const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2551817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 2552817466cbSJens Wiklander void *p_rng) 2553817466cbSJens Wiklander { 255411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2555817466cbSJens Wiklander size_t i; 2556817466cbSJens Wiklander unsigned char b; 2557817466cbSJens Wiklander mbedtls_ecp_point RP; 2558817466cbSJens Wiklander mbedtls_mpi PX; 255932b31808SJens Wiklander mbedtls_mpi tmp[4]; 2560817466cbSJens Wiklander mbedtls_ecp_point_init(&RP); mbedtls_mpi_init(&PX); 2561817466cbSJens Wiklander 256232b31808SJens Wiklander mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 256332b31808SJens Wiklander 256432b31808SJens Wiklander if (f_rng == NULL) { 256532b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 25667901324dSJerome Forissier } 25677901324dSJerome Forissier 2568817466cbSJens Wiklander /* Save PX and read from P before writing to R, in case P == R */ 256932b31808SJens Wiklander MPI_ECP_MOV(&PX, &P->X); 2570817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&RP, P)); 2571817466cbSJens Wiklander 2572817466cbSJens Wiklander /* Set R to zero in modified x/z coordinates */ 257332b31808SJens Wiklander MPI_ECP_LSET(&R->X, 1); 257432b31808SJens Wiklander MPI_ECP_LSET(&R->Z, 0); 2575817466cbSJens Wiklander mbedtls_mpi_free(&R->Y); 2576817466cbSJens Wiklander 2577039e02dfSJerome Forissier /* RP.X might be slightly larger than P, so reduce it */ 257832b31808SJens Wiklander MOD_ADD(&RP.X); 2579817466cbSJens Wiklander 2580817466cbSJens Wiklander /* Randomize coordinates of the starting point */ 2581817466cbSJens Wiklander MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, &RP, f_rng, p_rng)); 2582817466cbSJens Wiklander 2583817466cbSJens Wiklander /* Loop invariant: R = result so far, RP = R + P */ 258432b31808SJens Wiklander i = grp->nbits + 1; /* one past the (zero-based) required msb for private keys */ 258532b31808SJens Wiklander while (i-- > 0) { 2586817466cbSJens Wiklander b = mbedtls_mpi_get_bit(m, i); 2587817466cbSJens Wiklander /* 2588817466cbSJens Wiklander * if (b) R = 2R + P else R = 2R, 2589817466cbSJens Wiklander * which is: 2590817466cbSJens Wiklander * if (b) double_add( RP, R, RP, R ) 2591817466cbSJens Wiklander * else double_add( R, RP, R, RP ) 2592817466cbSJens Wiklander * but using safe conditional swaps to avoid leaks 2593817466cbSJens Wiklander */ 259432b31808SJens Wiklander MPI_ECP_COND_SWAP(&R->X, &RP.X, b); 259532b31808SJens Wiklander MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b); 259632b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_double_add_mxz(grp, R, &RP, R, &RP, &PX, tmp)); 259732b31808SJens Wiklander MPI_ECP_COND_SWAP(&R->X, &RP.X, b); 259832b31808SJens Wiklander MPI_ECP_COND_SWAP(&R->Z, &RP.Z, b); 2599817466cbSJens Wiklander } 2600817466cbSJens Wiklander 260111fa71b9SJerome Forissier /* 260211fa71b9SJerome Forissier * Knowledge of the projective coordinates may leak the last few bits of the 260311fa71b9SJerome Forissier * scalar [1], and since our MPI implementation isn't constant-flow, 260411fa71b9SJerome Forissier * inversion (used for coordinate normalization) may leak the full value 260511fa71b9SJerome Forissier * of its input via side-channels [2]. 260611fa71b9SJerome Forissier * 260711fa71b9SJerome Forissier * [1] https://eprint.iacr.org/2003/191 260811fa71b9SJerome Forissier * [2] https://eprint.iacr.org/2020/055 260911fa71b9SJerome Forissier * 261011fa71b9SJerome Forissier * Avoid the leak by randomizing coordinates before we normalize them. 261111fa71b9SJerome Forissier */ 261211fa71b9SJerome Forissier MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, R, f_rng, p_rng)); 2613817466cbSJens Wiklander MBEDTLS_MPI_CHK(ecp_normalize_mxz(grp, R)); 2614817466cbSJens Wiklander 2615817466cbSJens Wiklander cleanup: 2616817466cbSJens Wiklander mbedtls_ecp_point_free(&RP); mbedtls_mpi_free(&PX); 2617817466cbSJens Wiklander 261832b31808SJens Wiklander mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 261932b31808SJens Wiklander return ret; 2620817466cbSJens Wiklander } 2621817466cbSJens Wiklander 26227901324dSJerome Forissier #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 2623817466cbSJens Wiklander 2624817466cbSJens Wiklander /* 26253d3b0591SJens Wiklander * Restartable multiplication R = m * P 262632b31808SJens Wiklander * 262732b31808SJens Wiklander * This internal function can be called without an RNG in case where we know 262832b31808SJens Wiklander * the inputs are not sensitive. 26293d3b0591SJens Wiklander */ 263032b31808SJens Wiklander static int ecp_mul_restartable_internal(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 26313d3b0591SJens Wiklander const mbedtls_mpi *m, const mbedtls_ecp_point *P, 26323d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 26333d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 26343d3b0591SJens Wiklander { 26353d3b0591SJens Wiklander int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 26363d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT) 26373d3b0591SJens Wiklander char is_grp_capable = 0; 26383d3b0591SJens Wiklander #endif 26393d3b0591SJens Wiklander 26403d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 26413d3b0591SJens Wiklander /* reset ops count for this call if top-level */ 264232b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->depth++ == 0) { 26433d3b0591SJens Wiklander rs_ctx->ops_done = 0; 264432b31808SJens Wiklander } 26457901324dSJerome Forissier #else 26467901324dSJerome Forissier (void) rs_ctx; 26473d3b0591SJens Wiklander #endif 26483d3b0591SJens Wiklander 26493d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT) 265032b31808SJens Wiklander if ((is_grp_capable = mbedtls_internal_ecp_grp_capable(grp))) { 26513d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_internal_ecp_init(grp)); 265232b31808SJens Wiklander } 26533d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */ 26543d3b0591SJens Wiklander 265532b31808SJens Wiklander int restarting = 0; 26563d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 265732b31808SJens Wiklander restarting = (rs_ctx != NULL && rs_ctx->rsm != NULL); 26583d3b0591SJens Wiklander #endif 265932b31808SJens Wiklander /* skip argument check when restarting */ 266032b31808SJens Wiklander if (!restarting) { 26613d3b0591SJens Wiklander /* check_privkey is free */ 26623d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_CHK); 26633d3b0591SJens Wiklander 26643d3b0591SJens Wiklander /* Common sanity checks */ 26653d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(grp, m)); 26663d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 26673d3b0591SJens Wiklander } 26683d3b0591SJens Wiklander 26693d3b0591SJens Wiklander ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 26707901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 267132b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 26723d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_mul_mxz(grp, R, m, P, f_rng, p_rng)); 267332b31808SJens Wiklander } 26743d3b0591SJens Wiklander #endif 26757901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 267632b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 26773d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_mul_comb(grp, R, m, P, f_rng, p_rng, rs_ctx)); 267832b31808SJens Wiklander } 26793d3b0591SJens Wiklander #endif 26803d3b0591SJens Wiklander 26813d3b0591SJens Wiklander cleanup: 26823d3b0591SJens Wiklander 26833d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT) 268432b31808SJens Wiklander if (is_grp_capable) { 26853d3b0591SJens Wiklander mbedtls_internal_ecp_free(grp); 268632b31808SJens Wiklander } 26873d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */ 26883d3b0591SJens Wiklander 26893d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 269032b31808SJens Wiklander if (rs_ctx != NULL) { 26913d3b0591SJens Wiklander rs_ctx->depth--; 269232b31808SJens Wiklander } 26933d3b0591SJens Wiklander #endif 26943d3b0591SJens Wiklander 269532b31808SJens Wiklander return ret; 269632b31808SJens Wiklander } 269732b31808SJens Wiklander 269832b31808SJens Wiklander /* 269932b31808SJens Wiklander * Restartable multiplication R = m * P 270032b31808SJens Wiklander */ 270132b31808SJens Wiklander int mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 270232b31808SJens Wiklander const mbedtls_mpi *m, const mbedtls_ecp_point *P, 270332b31808SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, 270432b31808SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 270532b31808SJens Wiklander { 270632b31808SJens Wiklander if (f_rng == NULL) { 270732b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 270832b31808SJens Wiklander } 270932b31808SJens Wiklander 271032b31808SJens Wiklander return ecp_mul_restartable_internal(grp, R, m, P, f_rng, p_rng, rs_ctx); 27113d3b0591SJens Wiklander } 27123d3b0591SJens Wiklander 27133d3b0591SJens Wiklander /* 2714817466cbSJens Wiklander * Multiplication R = m * P 2715817466cbSJens Wiklander */ 2716817466cbSJens Wiklander int mbedtls_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2717817466cbSJens Wiklander const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2718817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 2719817466cbSJens Wiklander { 272032b31808SJens Wiklander return mbedtls_ecp_mul_restartable(grp, R, m, P, f_rng, p_rng, NULL); 2721817466cbSJens Wiklander } 2722*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 2723817466cbSJens Wiklander 27247901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 2725817466cbSJens Wiklander /* 2726817466cbSJens Wiklander * Check that an affine point is valid as a public key, 2727817466cbSJens Wiklander * short weierstrass curves (SEC1 3.2.3.1) 2728817466cbSJens Wiklander */ 2729817466cbSJens Wiklander static int ecp_check_pubkey_sw(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) 2730817466cbSJens Wiklander { 273111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 2732817466cbSJens Wiklander mbedtls_mpi YY, RHS; 2733817466cbSJens Wiklander 2734817466cbSJens Wiklander /* pt coordinates must be normalized for our checks */ 2735817466cbSJens Wiklander if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0 || 2736817466cbSJens Wiklander mbedtls_mpi_cmp_int(&pt->Y, 0) < 0 || 2737817466cbSJens Wiklander mbedtls_mpi_cmp_mpi(&pt->X, &grp->P) >= 0 || 273832b31808SJens Wiklander mbedtls_mpi_cmp_mpi(&pt->Y, &grp->P) >= 0) { 273932b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 274032b31808SJens Wiklander } 2741817466cbSJens Wiklander 2742817466cbSJens Wiklander mbedtls_mpi_init(&YY); mbedtls_mpi_init(&RHS); 2743817466cbSJens Wiklander 2744817466cbSJens Wiklander /* 2745817466cbSJens Wiklander * YY = Y^2 274632b31808SJens Wiklander * RHS = X^3 + A X + B 2747817466cbSJens Wiklander */ 274832b31808SJens Wiklander MPI_ECP_SQR(&YY, &pt->Y); 274932b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_sw_rhs(grp, &RHS, &pt->X)); 2750817466cbSJens Wiklander 275132b31808SJens Wiklander if (MPI_ECP_CMP(&YY, &RHS) != 0) { 2752817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_INVALID_KEY; 275332b31808SJens Wiklander } 2754817466cbSJens Wiklander 2755817466cbSJens Wiklander cleanup: 2756817466cbSJens Wiklander 2757817466cbSJens Wiklander mbedtls_mpi_free(&YY); mbedtls_mpi_free(&RHS); 2758817466cbSJens Wiklander 275932b31808SJens Wiklander return ret; 2760817466cbSJens Wiklander } 27617901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 2762817466cbSJens Wiklander 2763*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 27647901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 2765817466cbSJens Wiklander /* 27667901324dSJerome Forissier * R = m * P with shortcuts for m == 0, m == 1 and m == -1 2767817466cbSJens Wiklander * NOT constant-time - ONLY for short Weierstrass! 2768817466cbSJens Wiklander */ 2769817466cbSJens Wiklander static int mbedtls_ecp_mul_shortcuts(mbedtls_ecp_group *grp, 2770817466cbSJens Wiklander mbedtls_ecp_point *R, 2771817466cbSJens Wiklander const mbedtls_mpi *m, 27723d3b0591SJens Wiklander const mbedtls_ecp_point *P, 27733d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 2774817466cbSJens Wiklander { 277511fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 277632b31808SJens Wiklander mbedtls_mpi tmp; 277732b31808SJens Wiklander mbedtls_mpi_init(&tmp); 2778817466cbSJens Wiklander 277932b31808SJens Wiklander if (mbedtls_mpi_cmp_int(m, 0) == 0) { 278032b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 27817901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R)); 278232b31808SJens Wiklander } else if (mbedtls_mpi_cmp_int(m, 1) == 0) { 278332b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 2784817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); 278532b31808SJens Wiklander } else if (mbedtls_mpi_cmp_int(m, -1) == 0) { 278632b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P)); 2787817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P)); 278832b31808SJens Wiklander MPI_ECP_NEG(&R->Y); 278932b31808SJens Wiklander } else { 279032b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_mul_restartable_internal(grp, R, m, P, 27913d3b0591SJens Wiklander NULL, NULL, rs_ctx)); 2792817466cbSJens Wiklander } 2793817466cbSJens Wiklander 2794817466cbSJens Wiklander cleanup: 279532b31808SJens Wiklander mbedtls_mpi_free(&tmp); 279632b31808SJens Wiklander 279732b31808SJens Wiklander return ret; 2798817466cbSJens Wiklander } 2799817466cbSJens Wiklander 2800817466cbSJens Wiklander /* 28013d3b0591SJens Wiklander * Restartable linear combination 28023d3b0591SJens Wiklander * NOT constant-time 28033d3b0591SJens Wiklander */ 28043d3b0591SJens Wiklander int mbedtls_ecp_muladd_restartable( 28053d3b0591SJens Wiklander mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 28063d3b0591SJens Wiklander const mbedtls_mpi *m, const mbedtls_ecp_point *P, 28073d3b0591SJens Wiklander const mbedtls_mpi *n, const mbedtls_ecp_point *Q, 28083d3b0591SJens Wiklander mbedtls_ecp_restart_ctx *rs_ctx) 28093d3b0591SJens Wiklander { 281011fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 28113d3b0591SJens Wiklander mbedtls_ecp_point mP; 28123d3b0591SJens Wiklander mbedtls_ecp_point *pmP = &mP; 28133d3b0591SJens Wiklander mbedtls_ecp_point *pR = R; 281432b31808SJens Wiklander mbedtls_mpi tmp[4]; 28153d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT) 28163d3b0591SJens Wiklander char is_grp_capable = 0; 28173d3b0591SJens Wiklander #endif 281832b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 281932b31808SJens Wiklander return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 282032b31808SJens Wiklander } 28213d3b0591SJens Wiklander 28223d3b0591SJens Wiklander mbedtls_ecp_point_init(&mP); 282332b31808SJens Wiklander mpi_init_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 28243d3b0591SJens Wiklander 28253d3b0591SJens Wiklander ECP_RS_ENTER(ma); 28263d3b0591SJens Wiklander 28273d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 282832b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->ma != NULL) { 28293d3b0591SJens Wiklander /* redirect intermediate results to restart context */ 28303d3b0591SJens Wiklander pmP = &rs_ctx->ma->mP; 28313d3b0591SJens Wiklander pR = &rs_ctx->ma->R; 28323d3b0591SJens Wiklander 28333d3b0591SJens Wiklander /* jump to next operation */ 283432b31808SJens Wiklander if (rs_ctx->ma->state == ecp_rsma_mul2) { 28353d3b0591SJens Wiklander goto mul2; 283632b31808SJens Wiklander } 283732b31808SJens Wiklander if (rs_ctx->ma->state == ecp_rsma_add) { 28383d3b0591SJens Wiklander goto add; 283932b31808SJens Wiklander } 284032b31808SJens Wiklander if (rs_ctx->ma->state == ecp_rsma_norm) { 28413d3b0591SJens Wiklander goto norm; 28423d3b0591SJens Wiklander } 284332b31808SJens Wiklander } 28443d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_RESTARTABLE */ 28453d3b0591SJens Wiklander 28463d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pmP, m, P, rs_ctx)); 28473d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 284832b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->ma != NULL) { 28493d3b0591SJens Wiklander rs_ctx->ma->state = ecp_rsma_mul2; 285032b31808SJens Wiklander } 28513d3b0591SJens Wiklander 28523d3b0591SJens Wiklander mul2: 28533d3b0591SJens Wiklander #endif 28543d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pR, n, Q, rs_ctx)); 28553d3b0591SJens Wiklander 28563d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT) 285732b31808SJens Wiklander if ((is_grp_capable = mbedtls_internal_ecp_grp_capable(grp))) { 28583d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_internal_ecp_init(grp)); 285932b31808SJens Wiklander } 28603d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */ 28613d3b0591SJens Wiklander 28623d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 286332b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->ma != NULL) { 28643d3b0591SJens Wiklander rs_ctx->ma->state = ecp_rsma_add; 286532b31808SJens Wiklander } 28663d3b0591SJens Wiklander 28673d3b0591SJens Wiklander add: 28683d3b0591SJens Wiklander #endif 28693d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_ADD); 287032b31808SJens Wiklander MBEDTLS_MPI_CHK(ecp_add_mixed(grp, pR, pmP, pR, tmp)); 28713d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 287232b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->ma != NULL) { 28733d3b0591SJens Wiklander rs_ctx->ma->state = ecp_rsma_norm; 287432b31808SJens Wiklander } 28753d3b0591SJens Wiklander 28763d3b0591SJens Wiklander norm: 28773d3b0591SJens Wiklander #endif 28783d3b0591SJens Wiklander MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV); 28793d3b0591SJens Wiklander MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, pR)); 28803d3b0591SJens Wiklander 28813d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_RESTARTABLE) 288232b31808SJens Wiklander if (rs_ctx != NULL && rs_ctx->ma != NULL) { 28833d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, pR)); 288432b31808SJens Wiklander } 28853d3b0591SJens Wiklander #endif 28863d3b0591SJens Wiklander 28873d3b0591SJens Wiklander cleanup: 288832b31808SJens Wiklander 288932b31808SJens Wiklander mpi_free_many(tmp, sizeof(tmp) / sizeof(mbedtls_mpi)); 289032b31808SJens Wiklander 28913d3b0591SJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT) 289232b31808SJens Wiklander if (is_grp_capable) { 28933d3b0591SJens Wiklander mbedtls_internal_ecp_free(grp); 289432b31808SJens Wiklander } 28953d3b0591SJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */ 28963d3b0591SJens Wiklander 28973d3b0591SJens Wiklander mbedtls_ecp_point_free(&mP); 28983d3b0591SJens Wiklander 28993d3b0591SJens Wiklander ECP_RS_LEAVE(ma); 29003d3b0591SJens Wiklander 290132b31808SJens Wiklander return ret; 29023d3b0591SJens Wiklander } 29033d3b0591SJens Wiklander 29043d3b0591SJens Wiklander /* 2905817466cbSJens Wiklander * Linear combination 2906817466cbSJens Wiklander * NOT constant-time 2907817466cbSJens Wiklander */ 2908817466cbSJens Wiklander int mbedtls_ecp_muladd(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, 2909817466cbSJens Wiklander const mbedtls_mpi *m, const mbedtls_ecp_point *P, 2910817466cbSJens Wiklander const mbedtls_mpi *n, const mbedtls_ecp_point *Q) 2911817466cbSJens Wiklander { 291232b31808SJens Wiklander return mbedtls_ecp_muladd_restartable(grp, R, m, P, n, Q, NULL); 2913817466cbSJens Wiklander } 29147901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 2915*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 2916817466cbSJens Wiklander 29177901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 29187901324dSJerome Forissier #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 2919*b0563631STom Van Eyck #define ECP_MPI_INIT(_p, _n) { .p = (mbedtls_mpi_uint *) (_p), .s = 1, .n = (_n), .use_mempool = 0 } 29207901324dSJerome Forissier #define ECP_MPI_INIT_ARRAY(x) \ 2921*b0563631STom Van Eyck ECP_MPI_INIT(x, sizeof(x) / sizeof(mbedtls_mpi_uint)) 29227901324dSJerome Forissier /* 29237901324dSJerome Forissier * Constants for the two points other than 0, 1, -1 (mod p) in 29247901324dSJerome Forissier * https://cr.yp.to/ecdh.html#validate 29257901324dSJerome Forissier * See ecp_check_pubkey_x25519(). 29267901324dSJerome Forissier */ 29277901324dSJerome Forissier static const mbedtls_mpi_uint x25519_bad_point_1[] = { 29287901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae), 29297901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a), 29307901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd), 29317901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00), 29327901324dSJerome Forissier }; 29337901324dSJerome Forissier static const mbedtls_mpi_uint x25519_bad_point_2[] = { 29347901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24), 29357901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b), 29367901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86), 29377901324dSJerome Forissier MBEDTLS_BYTES_TO_T_UINT_8(0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57), 29387901324dSJerome Forissier }; 29397901324dSJerome Forissier static const mbedtls_mpi ecp_x25519_bad_point_1 = ECP_MPI_INIT_ARRAY( 29407901324dSJerome Forissier x25519_bad_point_1); 29417901324dSJerome Forissier static const mbedtls_mpi ecp_x25519_bad_point_2 = ECP_MPI_INIT_ARRAY( 29427901324dSJerome Forissier x25519_bad_point_2); 29437901324dSJerome Forissier #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ 29447901324dSJerome Forissier 29457901324dSJerome Forissier /* 29467901324dSJerome Forissier * Check that the input point is not one of the low-order points. 29477901324dSJerome Forissier * This is recommended by the "May the Fourth" paper: 29487901324dSJerome Forissier * https://eprint.iacr.org/2017/806.pdf 29497901324dSJerome Forissier * Those points are never sent by an honest peer. 29507901324dSJerome Forissier */ 29517901324dSJerome Forissier static int ecp_check_bad_points_mx(const mbedtls_mpi *X, const mbedtls_mpi *P, 29527901324dSJerome Forissier const mbedtls_ecp_group_id grp_id) 29537901324dSJerome Forissier { 29547901324dSJerome Forissier int ret; 29557901324dSJerome Forissier mbedtls_mpi XmP; 29567901324dSJerome Forissier 29577901324dSJerome Forissier mbedtls_mpi_init(&XmP); 29587901324dSJerome Forissier 29597901324dSJerome Forissier /* Reduce X mod P so that we only need to check values less than P. 29607901324dSJerome Forissier * We know X < 2^256 so we can proceed by subtraction. */ 29617901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&XmP, X)); 296232b31808SJens Wiklander while (mbedtls_mpi_cmp_mpi(&XmP, P) >= 0) { 29637901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&XmP, &XmP, P)); 296432b31808SJens Wiklander } 29657901324dSJerome Forissier 29667901324dSJerome Forissier /* Check against the known bad values that are less than P. For Curve448 29677901324dSJerome Forissier * these are 0, 1 and -1. For Curve25519 we check the values less than P 29687901324dSJerome Forissier * from the following list: https://cr.yp.to/ecdh.html#validate */ 296932b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&XmP, 1) <= 0) { /* takes care of 0 and 1 */ 29707901324dSJerome Forissier ret = MBEDTLS_ERR_ECP_INVALID_KEY; 29717901324dSJerome Forissier goto cleanup; 29727901324dSJerome Forissier } 29737901324dSJerome Forissier 29747901324dSJerome Forissier #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 297532b31808SJens Wiklander if (grp_id == MBEDTLS_ECP_DP_CURVE25519) { 297632b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_1) == 0) { 29777901324dSJerome Forissier ret = MBEDTLS_ERR_ECP_INVALID_KEY; 29787901324dSJerome Forissier goto cleanup; 29797901324dSJerome Forissier } 29807901324dSJerome Forissier 298132b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_2) == 0) { 29827901324dSJerome Forissier ret = MBEDTLS_ERR_ECP_INVALID_KEY; 29837901324dSJerome Forissier goto cleanup; 29847901324dSJerome Forissier } 29857901324dSJerome Forissier } 29867901324dSJerome Forissier #else 29877901324dSJerome Forissier (void) grp_id; 29887901324dSJerome Forissier #endif 29897901324dSJerome Forissier 29907901324dSJerome Forissier /* Final check: check if XmP + 1 is P (final because it changes XmP!) */ 29917901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&XmP, &XmP, 1)); 299232b31808SJens Wiklander if (mbedtls_mpi_cmp_mpi(&XmP, P) == 0) { 29937901324dSJerome Forissier ret = MBEDTLS_ERR_ECP_INVALID_KEY; 29947901324dSJerome Forissier goto cleanup; 29957901324dSJerome Forissier } 29967901324dSJerome Forissier 29977901324dSJerome Forissier ret = 0; 29987901324dSJerome Forissier 29997901324dSJerome Forissier cleanup: 30007901324dSJerome Forissier mbedtls_mpi_free(&XmP); 30017901324dSJerome Forissier 300232b31808SJens Wiklander return ret; 30037901324dSJerome Forissier } 30047901324dSJerome Forissier 3005817466cbSJens Wiklander /* 3006817466cbSJens Wiklander * Check validity of a public key for Montgomery curves with x-only schemes 3007817466cbSJens Wiklander */ 3008817466cbSJens Wiklander static int ecp_check_pubkey_mx(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) 3009817466cbSJens Wiklander { 3010817466cbSJens Wiklander /* [Curve25519 p. 5] Just check X is the correct number of bytes */ 30113d3b0591SJens Wiklander /* Allow any public value, if it's too big then we'll just reduce it mod p 30123d3b0591SJens Wiklander * (RFC 7748 sec. 5 para. 3). */ 301332b31808SJens Wiklander if (mbedtls_mpi_size(&pt->X) > (grp->nbits + 7) / 8) { 301432b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 301532b31808SJens Wiklander } 3016817466cbSJens Wiklander 30177901324dSJerome Forissier /* Implicit in all standards (as they don't consider negative numbers): 30187901324dSJerome Forissier * X must be non-negative. This is normally ensured by the way it's 30197901324dSJerome Forissier * encoded for transmission, but let's be extra sure. */ 302032b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0) { 302132b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 302232b31808SJens Wiklander } 30237901324dSJerome Forissier 302432b31808SJens Wiklander return ecp_check_bad_points_mx(&pt->X, &grp->P, grp->id); 3025817466cbSJens Wiklander } 30267901324dSJerome Forissier #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3027817466cbSJens Wiklander 3028817466cbSJens Wiklander /* 3029817466cbSJens Wiklander * Check that a point is valid as a public key 3030817466cbSJens Wiklander */ 30313d3b0591SJens Wiklander int mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp, 30323d3b0591SJens Wiklander const mbedtls_ecp_point *pt) 3033817466cbSJens Wiklander { 3034817466cbSJens Wiklander /* Must use affine coordinates */ 303532b31808SJens Wiklander if (mbedtls_mpi_cmp_int(&pt->Z, 1) != 0) { 303632b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 303732b31808SJens Wiklander } 3038817466cbSJens Wiklander 30397901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 304032b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 304132b31808SJens Wiklander return ecp_check_pubkey_mx(grp, pt); 304232b31808SJens Wiklander } 3043817466cbSJens Wiklander #endif 30447901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 304532b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 304632b31808SJens Wiklander return ecp_check_pubkey_sw(grp, pt); 304732b31808SJens Wiklander } 3048817466cbSJens Wiklander #endif 304932b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3050817466cbSJens Wiklander } 3051817466cbSJens Wiklander 3052817466cbSJens Wiklander /* 3053817466cbSJens Wiklander * Check that an mbedtls_mpi is valid as a private key 3054817466cbSJens Wiklander */ 30553d3b0591SJens Wiklander int mbedtls_ecp_check_privkey(const mbedtls_ecp_group *grp, 30563d3b0591SJens Wiklander const mbedtls_mpi *d) 3057817466cbSJens Wiklander { 30587901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 305932b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 30603d3b0591SJens Wiklander /* see RFC 7748 sec. 5 para. 5 */ 3061817466cbSJens Wiklander if (mbedtls_mpi_get_bit(d, 0) != 0 || 3062817466cbSJens Wiklander mbedtls_mpi_get_bit(d, 1) != 0 || 306332b31808SJens Wiklander mbedtls_mpi_bitlen(d) - 1 != grp->nbits) { /* mbedtls_mpi_bitlen is one-based! */ 306432b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 306532b31808SJens Wiklander } 30663d3b0591SJens Wiklander 30673d3b0591SJens Wiklander /* see [Curve25519] page 5 */ 306832b31808SJens Wiklander if (grp->nbits == 254 && mbedtls_mpi_get_bit(d, 2) != 0) { 306932b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 307032b31808SJens Wiklander } 30713d3b0591SJens Wiklander 307232b31808SJens Wiklander return 0; 3073817466cbSJens Wiklander } 30747901324dSJerome Forissier #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 30757901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 307632b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3077817466cbSJens Wiklander /* see SEC1 3.2 */ 3078817466cbSJens Wiklander if (mbedtls_mpi_cmp_int(d, 1) < 0 || 307932b31808SJens Wiklander mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0) { 308032b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 308132b31808SJens Wiklander } else { 308232b31808SJens Wiklander return 0; 308332b31808SJens Wiklander } 3084817466cbSJens Wiklander } 30857901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 3086817466cbSJens Wiklander 308732b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3088817466cbSJens Wiklander } 3089817466cbSJens Wiklander 30907901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 30917901324dSJerome Forissier MBEDTLS_STATIC_TESTABLE 30927901324dSJerome Forissier int mbedtls_ecp_gen_privkey_mx(size_t high_bit, 30937901324dSJerome Forissier mbedtls_mpi *d, 30947901324dSJerome Forissier int (*f_rng)(void *, unsigned char *, size_t), 30957901324dSJerome Forissier void *p_rng) 30967901324dSJerome Forissier { 30977901324dSJerome Forissier int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 30987901324dSJerome Forissier size_t n_random_bytes = high_bit / 8 + 1; 30997901324dSJerome Forissier 31007901324dSJerome Forissier /* [Curve25519] page 5 */ 31017901324dSJerome Forissier /* Generate a (high_bit+1)-bit random number by generating just enough 31027901324dSJerome Forissier * random bytes, then shifting out extra bits from the top (necessary 31037901324dSJerome Forissier * when (high_bit+1) is not a multiple of 8). */ 31047901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(d, n_random_bytes, 31057901324dSJerome Forissier f_rng, p_rng)); 31067901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(d, 8 * n_random_bytes - high_bit - 1)); 31077901324dSJerome Forissier 31087901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, high_bit, 1)); 31097901324dSJerome Forissier 31107901324dSJerome Forissier /* Make sure the last two bits are unset for Curve448, three bits for 31117901324dSJerome Forissier Curve25519 */ 31127901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 0, 0)); 31137901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 1, 0)); 311432b31808SJens Wiklander if (high_bit == 254) { 31157901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 2, 0)); 31167901324dSJerome Forissier } 31177901324dSJerome Forissier 31187901324dSJerome Forissier cleanup: 311932b31808SJens Wiklander return ret; 31207901324dSJerome Forissier } 31217901324dSJerome Forissier #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 31227901324dSJerome Forissier 31237901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 31247901324dSJerome Forissier static int mbedtls_ecp_gen_privkey_sw( 31257901324dSJerome Forissier const mbedtls_mpi *N, mbedtls_mpi *d, 31267901324dSJerome Forissier int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 31277901324dSJerome Forissier { 31287901324dSJerome Forissier int ret = mbedtls_mpi_random(d, 1, N, f_rng, p_rng); 312932b31808SJens Wiklander switch (ret) { 31307901324dSJerome Forissier case MBEDTLS_ERR_MPI_NOT_ACCEPTABLE: 313132b31808SJens Wiklander return MBEDTLS_ERR_ECP_RANDOM_FAILED; 31327901324dSJerome Forissier default: 313332b31808SJens Wiklander return ret; 31347901324dSJerome Forissier } 31357901324dSJerome Forissier } 31367901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 31377901324dSJerome Forissier 3138817466cbSJens Wiklander /* 31393d3b0591SJens Wiklander * Generate a private key 3140817466cbSJens Wiklander */ 31413d3b0591SJens Wiklander int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp, 31423d3b0591SJens Wiklander mbedtls_mpi *d, 3143817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 3144817466cbSJens Wiklander void *p_rng) 3145817466cbSJens Wiklander { 31467901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 314732b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 314832b31808SJens Wiklander return mbedtls_ecp_gen_privkey_mx(grp->nbits, d, f_rng, p_rng); 314932b31808SJens Wiklander } 31507901324dSJerome Forissier #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3151817466cbSJens Wiklander 31527901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 315332b31808SJens Wiklander if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 315432b31808SJens Wiklander return mbedtls_ecp_gen_privkey_sw(&grp->N, d, f_rng, p_rng); 315532b31808SJens Wiklander } 31567901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 3157817466cbSJens Wiklander 315832b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 31593d3b0591SJens Wiklander } 3160817466cbSJens Wiklander 3161*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 31623d3b0591SJens Wiklander /* 31633d3b0591SJens Wiklander * Generate a keypair with configurable base point 31643d3b0591SJens Wiklander */ 31653d3b0591SJens Wiklander int mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp, 31663d3b0591SJens Wiklander const mbedtls_ecp_point *G, 31673d3b0591SJens Wiklander mbedtls_mpi *d, mbedtls_ecp_point *Q, 31683d3b0591SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 31693d3b0591SJens Wiklander void *p_rng) 31703d3b0591SJens Wiklander { 317111fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 31723d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, d, f_rng, p_rng)); 31733d3b0591SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, Q, d, G, f_rng, p_rng)); 31743d3b0591SJens Wiklander 31753d3b0591SJens Wiklander cleanup: 317632b31808SJens Wiklander return ret; 3177817466cbSJens Wiklander } 3178817466cbSJens Wiklander 3179817466cbSJens Wiklander /* 3180817466cbSJens Wiklander * Generate key pair, wrapper for conventional base point 3181817466cbSJens Wiklander */ 3182817466cbSJens Wiklander int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp, 3183817466cbSJens Wiklander mbedtls_mpi *d, mbedtls_ecp_point *Q, 3184817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), 3185817466cbSJens Wiklander void *p_rng) 3186817466cbSJens Wiklander { 318732b31808SJens Wiklander return mbedtls_ecp_gen_keypair_base(grp, &grp->G, d, Q, f_rng, p_rng); 3188817466cbSJens Wiklander } 3189817466cbSJens Wiklander 3190817466cbSJens Wiklander /* 3191817466cbSJens Wiklander * Generate a keypair, prettier wrapper 3192817466cbSJens Wiklander */ 3193817466cbSJens Wiklander int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, 3194817466cbSJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 3195817466cbSJens Wiklander { 319611fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 319732b31808SJens Wiklander if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { 319832b31808SJens Wiklander return ret; 319932b31808SJens Wiklander } 3200817466cbSJens Wiklander 320132b31808SJens Wiklander return mbedtls_ecp_gen_keypair(&key->grp, &key->d, &key->Q, f_rng, p_rng); 3202817466cbSJens Wiklander } 3203*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 3204*b0563631STom Van Eyck 3205*b0563631STom Van Eyck int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id, 3206*b0563631STom Van Eyck mbedtls_ecp_keypair *key, 3207*b0563631STom Van Eyck const mbedtls_ecp_point *Q) 3208*b0563631STom Van Eyck { 3209*b0563631STom Van Eyck int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3210*b0563631STom Van Eyck 3211*b0563631STom Van Eyck if (key->grp.id == MBEDTLS_ECP_DP_NONE) { 3212*b0563631STom Van Eyck /* Group not set yet */ 3213*b0563631STom Van Eyck if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { 3214*b0563631STom Van Eyck return ret; 3215*b0563631STom Van Eyck } 3216*b0563631STom Van Eyck } else if (key->grp.id != grp_id) { 3217*b0563631STom Van Eyck /* Group mismatch */ 3218*b0563631STom Van Eyck return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3219*b0563631STom Van Eyck } 3220*b0563631STom Van Eyck return mbedtls_ecp_copy(&key->Q, Q); 3221*b0563631STom Van Eyck } 3222*b0563631STom Van Eyck 3223817466cbSJens Wiklander 322411fa71b9SJerome Forissier #define ECP_CURVE25519_KEY_SIZE 32 322532b31808SJens Wiklander #define ECP_CURVE448_KEY_SIZE 56 322611fa71b9SJerome Forissier /* 322711fa71b9SJerome Forissier * Read a private key. 322811fa71b9SJerome Forissier */ 322911fa71b9SJerome Forissier int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, 323011fa71b9SJerome Forissier const unsigned char *buf, size_t buflen) 323111fa71b9SJerome Forissier { 323211fa71b9SJerome Forissier int ret = 0; 323311fa71b9SJerome Forissier 323432b31808SJens Wiklander if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) { 323532b31808SJens Wiklander return ret; 323632b31808SJens Wiklander } 323711fa71b9SJerome Forissier 323811fa71b9SJerome Forissier ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE; 323911fa71b9SJerome Forissier 32407901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 324132b31808SJens Wiklander if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 324211fa71b9SJerome Forissier /* 324332b31808SJens Wiklander * Mask the key as mandated by RFC7748 for Curve25519 and Curve448. 324411fa71b9SJerome Forissier */ 324532b31808SJens Wiklander if (grp_id == MBEDTLS_ECP_DP_CURVE25519) { 324632b31808SJens Wiklander if (buflen != ECP_CURVE25519_KEY_SIZE) { 324711fa71b9SJerome Forissier return MBEDTLS_ERR_ECP_INVALID_KEY; 324832b31808SJens Wiklander } 324911fa71b9SJerome Forissier 325011fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen)); 325111fa71b9SJerome Forissier 325211fa71b9SJerome Forissier /* Set the three least significant bits to 0 */ 325311fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0)); 325411fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0)); 325511fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 2, 0)); 325611fa71b9SJerome Forissier 325711fa71b9SJerome Forissier /* Set the most significant bit to 0 */ 325811fa71b9SJerome Forissier MBEDTLS_MPI_CHK( 325911fa71b9SJerome Forissier mbedtls_mpi_set_bit(&key->d, 326011fa71b9SJerome Forissier ECP_CURVE25519_KEY_SIZE * 8 - 1, 0) 326111fa71b9SJerome Forissier ); 326211fa71b9SJerome Forissier 326311fa71b9SJerome Forissier /* Set the second most significant bit to 1 */ 326411fa71b9SJerome Forissier MBEDTLS_MPI_CHK( 326511fa71b9SJerome Forissier mbedtls_mpi_set_bit(&key->d, 326611fa71b9SJerome Forissier ECP_CURVE25519_KEY_SIZE * 8 - 2, 1) 326711fa71b9SJerome Forissier ); 326832b31808SJens Wiklander } else if (grp_id == MBEDTLS_ECP_DP_CURVE448) { 326932b31808SJens Wiklander if (buflen != ECP_CURVE448_KEY_SIZE) { 327032b31808SJens Wiklander return MBEDTLS_ERR_ECP_INVALID_KEY; 327111fa71b9SJerome Forissier } 327232b31808SJens Wiklander 327332b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen)); 327432b31808SJens Wiklander 327532b31808SJens Wiklander /* Set the two least significant bits to 0 */ 327632b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0)); 327732b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0)); 327832b31808SJens Wiklander 327932b31808SJens Wiklander /* Set the most significant bit to 1 */ 328032b31808SJens Wiklander MBEDTLS_MPI_CHK( 328132b31808SJens Wiklander mbedtls_mpi_set_bit(&key->d, 328232b31808SJens Wiklander ECP_CURVE448_KEY_SIZE * 8 - 1, 1) 328332b31808SJens Wiklander ); 328432b31808SJens Wiklander } 328511fa71b9SJerome Forissier } 328611fa71b9SJerome Forissier #endif 32877901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 328832b31808SJens Wiklander if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 328911fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&key->d, buf, buflen)); 3290*b0563631STom Van Eyck } 3291*b0563631STom Van Eyck #endif 329211fa71b9SJerome Forissier 3293*b0563631STom Van Eyck if (ret == 0) { 329411fa71b9SJerome Forissier MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(&key->grp, &key->d)); 329511fa71b9SJerome Forissier } 329611fa71b9SJerome Forissier 329711fa71b9SJerome Forissier cleanup: 329811fa71b9SJerome Forissier 329932b31808SJens Wiklander if (ret != 0) { 330011fa71b9SJerome Forissier mbedtls_mpi_free(&key->d); 330132b31808SJens Wiklander } 330211fa71b9SJerome Forissier 330332b31808SJens Wiklander return ret; 330411fa71b9SJerome Forissier } 330511fa71b9SJerome Forissier 3306817466cbSJens Wiklander /* 33077901324dSJerome Forissier * Write a private key. 33087901324dSJerome Forissier */ 3309*b0563631STom Van Eyck #if !defined MBEDTLS_DEPRECATED_REMOVED 33107901324dSJerome Forissier int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, 33117901324dSJerome Forissier unsigned char *buf, size_t buflen) 33127901324dSJerome Forissier { 3313*b0563631STom Van Eyck int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 33147901324dSJerome Forissier 33157901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 331632b31808SJens Wiklander if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 331732b31808SJens Wiklander if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) { 331832b31808SJens Wiklander if (buflen < ECP_CURVE25519_KEY_SIZE) { 33197901324dSJerome Forissier return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 332032b31808SJens Wiklander } 33217901324dSJerome Forissier 332232b31808SJens Wiklander } else if (key->grp.id == MBEDTLS_ECP_DP_CURVE448) { 332332b31808SJens Wiklander if (buflen < ECP_CURVE448_KEY_SIZE) { 332432b31808SJens Wiklander return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 332532b31808SJens Wiklander } 332632b31808SJens Wiklander } 33277901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&key->d, buf, buflen)); 33287901324dSJerome Forissier } 33297901324dSJerome Forissier #endif 33307901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 333132b31808SJens Wiklander if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 33327901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&key->d, buf, buflen)); 33337901324dSJerome Forissier } 33347901324dSJerome Forissier 33357901324dSJerome Forissier #endif 33367901324dSJerome Forissier cleanup: 33377901324dSJerome Forissier 333832b31808SJens Wiklander return ret; 33397901324dSJerome Forissier } 3340*b0563631STom Van Eyck #endif /* MBEDTLS_DEPRECATED_REMOVED */ 3341*b0563631STom Van Eyck 3342*b0563631STom Van Eyck int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key, 3343*b0563631STom Van Eyck size_t *olen, unsigned char *buf, size_t buflen) 3344*b0563631STom Van Eyck { 3345*b0563631STom Van Eyck size_t len = (key->grp.nbits + 7) / 8; 3346*b0563631STom Van Eyck if (len > buflen) { 3347*b0563631STom Van Eyck /* For robustness, ensure *olen <= buflen even on error. */ 3348*b0563631STom Van Eyck *olen = 0; 3349*b0563631STom Van Eyck return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; 3350*b0563631STom Van Eyck } 3351*b0563631STom Van Eyck *olen = len; 3352*b0563631STom Van Eyck 3353*b0563631STom Van Eyck /* Private key not set */ 3354*b0563631STom Van Eyck if (key->d.n == 0) { 3355*b0563631STom Van Eyck return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3356*b0563631STom Van Eyck } 3357*b0563631STom Van Eyck 3358*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 3359*b0563631STom Van Eyck if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { 3360*b0563631STom Van Eyck return mbedtls_mpi_write_binary_le(&key->d, buf, len); 3361*b0563631STom Van Eyck } 3362*b0563631STom Van Eyck #endif 3363*b0563631STom Van Eyck 3364*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3365*b0563631STom Van Eyck if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { 3366*b0563631STom Van Eyck return mbedtls_mpi_write_binary(&key->d, buf, len); 3367*b0563631STom Van Eyck } 3368*b0563631STom Van Eyck #endif 3369*b0563631STom Van Eyck 3370*b0563631STom Van Eyck /* Private key set but no recognized curve type? This shouldn't happen. */ 3371*b0563631STom Van Eyck return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3372*b0563631STom Van Eyck } 3373*b0563631STom Van Eyck 3374*b0563631STom Van Eyck /* 3375*b0563631STom Van Eyck * Write a public key. 3376*b0563631STom Van Eyck */ 3377*b0563631STom Van Eyck int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key, 3378*b0563631STom Van Eyck int format, size_t *olen, 3379*b0563631STom Van Eyck unsigned char *buf, size_t buflen) 3380*b0563631STom Van Eyck { 3381*b0563631STom Van Eyck return mbedtls_ecp_point_write_binary(&key->grp, &key->Q, 3382*b0563631STom Van Eyck format, olen, buf, buflen); 3383*b0563631STom Van Eyck } 33847901324dSJerome Forissier 33857901324dSJerome Forissier 3386*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 33877901324dSJerome Forissier /* 3388817466cbSJens Wiklander * Check a public-private key pair 3389817466cbSJens Wiklander */ 339032b31808SJens Wiklander int mbedtls_ecp_check_pub_priv( 339132b31808SJens Wiklander const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv, 339232b31808SJens Wiklander int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) 3393817466cbSJens Wiklander { 339411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3395817466cbSJens Wiklander mbedtls_ecp_point Q; 3396817466cbSJens Wiklander mbedtls_ecp_group grp; 3397817466cbSJens Wiklander if (pub->grp.id == MBEDTLS_ECP_DP_NONE || 3398817466cbSJens Wiklander pub->grp.id != prv->grp.id || 3399817466cbSJens Wiklander mbedtls_mpi_cmp_mpi(&pub->Q.X, &prv->Q.X) || 3400817466cbSJens Wiklander mbedtls_mpi_cmp_mpi(&pub->Q.Y, &prv->Q.Y) || 340132b31808SJens Wiklander mbedtls_mpi_cmp_mpi(&pub->Q.Z, &prv->Q.Z)) { 340232b31808SJens Wiklander return MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3403817466cbSJens Wiklander } 3404817466cbSJens Wiklander 3405817466cbSJens Wiklander mbedtls_ecp_point_init(&Q); 3406817466cbSJens Wiklander mbedtls_ecp_group_init(&grp); 3407817466cbSJens Wiklander 3408817466cbSJens Wiklander /* mbedtls_ecp_mul() needs a non-const group... */ 3409817466cbSJens Wiklander mbedtls_ecp_group_copy(&grp, &prv->grp); 3410817466cbSJens Wiklander 3411817466cbSJens Wiklander /* Also checks d is valid */ 341232b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &Q, &prv->d, &prv->grp.G, f_rng, p_rng)); 3413817466cbSJens Wiklander 3414817466cbSJens Wiklander if (mbedtls_mpi_cmp_mpi(&Q.X, &prv->Q.X) || 3415817466cbSJens Wiklander mbedtls_mpi_cmp_mpi(&Q.Y, &prv->Q.Y) || 341632b31808SJens Wiklander mbedtls_mpi_cmp_mpi(&Q.Z, &prv->Q.Z)) { 3417817466cbSJens Wiklander ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA; 3418817466cbSJens Wiklander goto cleanup; 3419817466cbSJens Wiklander } 3420817466cbSJens Wiklander 3421817466cbSJens Wiklander cleanup: 3422817466cbSJens Wiklander mbedtls_ecp_point_free(&Q); 3423817466cbSJens Wiklander mbedtls_ecp_group_free(&grp); 3424817466cbSJens Wiklander 342532b31808SJens Wiklander return ret; 342632b31808SJens Wiklander } 342732b31808SJens Wiklander 3428*b0563631STom Van Eyck int mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair *key, 3429*b0563631STom Van Eyck int (*f_rng)(void *, unsigned char *, size_t), 3430*b0563631STom Van Eyck void *p_rng) 3431*b0563631STom Van Eyck { 3432*b0563631STom Van Eyck return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G, 3433*b0563631STom Van Eyck f_rng, p_rng); 3434*b0563631STom Van Eyck } 3435*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 3436*b0563631STom Van Eyck 3437*b0563631STom Van Eyck mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id( 3438*b0563631STom Van Eyck const mbedtls_ecp_keypair *key) 3439*b0563631STom Van Eyck { 3440*b0563631STom Van Eyck return key->grp.id; 3441*b0563631STom Van Eyck } 3442*b0563631STom Van Eyck 344332b31808SJens Wiklander /* 344432b31808SJens Wiklander * Export generic key-pair parameters. 344532b31808SJens Wiklander */ 344632b31808SJens Wiklander int mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp, 344732b31808SJens Wiklander mbedtls_mpi *d, mbedtls_ecp_point *Q) 344832b31808SJens Wiklander { 344932b31808SJens Wiklander int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 345032b31808SJens Wiklander 3451*b0563631STom Van Eyck if (grp != NULL && (ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) { 345232b31808SJens Wiklander return ret; 345332b31808SJens Wiklander } 345432b31808SJens Wiklander 3455*b0563631STom Van Eyck if (d != NULL && (ret = mbedtls_mpi_copy(d, &key->d)) != 0) { 345632b31808SJens Wiklander return ret; 345732b31808SJens Wiklander } 345832b31808SJens Wiklander 3459*b0563631STom Van Eyck if (Q != NULL && (ret = mbedtls_ecp_copy(Q, &key->Q)) != 0) { 346032b31808SJens Wiklander return ret; 346132b31808SJens Wiklander } 346232b31808SJens Wiklander 346332b31808SJens Wiklander return 0; 3464817466cbSJens Wiklander } 3465817466cbSJens Wiklander 3466817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST) 3467817466cbSJens Wiklander 3468*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 346932b31808SJens Wiklander /* 347032b31808SJens Wiklander * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!! 347132b31808SJens Wiklander * 347232b31808SJens Wiklander * This is the linear congruential generator from numerical recipes, 347332b31808SJens Wiklander * except we only use the low byte as the output. See 347432b31808SJens Wiklander * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use 347532b31808SJens Wiklander */ 347632b31808SJens Wiklander static int self_test_rng(void *ctx, unsigned char *out, size_t len) 347732b31808SJens Wiklander { 347832b31808SJens Wiklander static uint32_t state = 42; 347932b31808SJens Wiklander 348032b31808SJens Wiklander (void) ctx; 348132b31808SJens Wiklander 348232b31808SJens Wiklander for (size_t i = 0; i < len; i++) { 348332b31808SJens Wiklander state = state * 1664525u + 1013904223u; 348432b31808SJens Wiklander out[i] = (unsigned char) state; 348532b31808SJens Wiklander } 348632b31808SJens Wiklander 348732b31808SJens Wiklander return 0; 348832b31808SJens Wiklander } 348932b31808SJens Wiklander 34907901324dSJerome Forissier /* Adjust the exponent to be a valid private point for the specified curve. 34917901324dSJerome Forissier * This is sometimes necessary because we use a single set of exponents 34927901324dSJerome Forissier * for all curves but the validity of values depends on the curve. */ 34937901324dSJerome Forissier static int self_test_adjust_exponent(const mbedtls_ecp_group *grp, 34947901324dSJerome Forissier mbedtls_mpi *m) 34957901324dSJerome Forissier { 34967901324dSJerome Forissier int ret = 0; 349732b31808SJens Wiklander switch (grp->id) { 34987901324dSJerome Forissier /* If Curve25519 is available, then that's what we use for the 34997901324dSJerome Forissier * Montgomery test, so we don't need the adjustment code. */ 35007901324dSJerome Forissier #if !defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 35017901324dSJerome Forissier #if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) 35027901324dSJerome Forissier case MBEDTLS_ECP_DP_CURVE448: 35037901324dSJerome Forissier /* Move highest bit from 254 to N-1. Setting bit N-1 is 35047901324dSJerome Forissier * necessary to enforce the highest-bit-set constraint. */ 35057901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, 254, 0)); 35067901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, grp->nbits, 1)); 35077901324dSJerome Forissier /* Copy second-highest bit from 253 to N-2. This is not 35087901324dSJerome Forissier * necessary but improves the test variety a bit. */ 35097901324dSJerome Forissier MBEDTLS_MPI_CHK( 35107901324dSJerome Forissier mbedtls_mpi_set_bit(m, grp->nbits - 1, 35117901324dSJerome Forissier mbedtls_mpi_get_bit(m, 253))); 35127901324dSJerome Forissier break; 35137901324dSJerome Forissier #endif 35147901324dSJerome Forissier #endif /* ! defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) */ 35157901324dSJerome Forissier default: 35167901324dSJerome Forissier /* Non-Montgomery curves and Curve25519 need no adjustment. */ 35177901324dSJerome Forissier (void) grp; 35187901324dSJerome Forissier (void) m; 35197901324dSJerome Forissier goto cleanup; 35207901324dSJerome Forissier } 35217901324dSJerome Forissier cleanup: 352232b31808SJens Wiklander return ret; 35237901324dSJerome Forissier } 35247901324dSJerome Forissier 35257901324dSJerome Forissier /* Calculate R = m.P for each m in exponents. Check that the number of 35267901324dSJerome Forissier * basic operations doesn't depend on the value of m. */ 35277901324dSJerome Forissier static int self_test_point(int verbose, 35287901324dSJerome Forissier mbedtls_ecp_group *grp, 35297901324dSJerome Forissier mbedtls_ecp_point *R, 35307901324dSJerome Forissier mbedtls_mpi *m, 35317901324dSJerome Forissier const mbedtls_ecp_point *P, 35327901324dSJerome Forissier const char *const *exponents, 35337901324dSJerome Forissier size_t n_exponents) 35347901324dSJerome Forissier { 35357901324dSJerome Forissier int ret = 0; 35367901324dSJerome Forissier size_t i = 0; 35377901324dSJerome Forissier unsigned long add_c_prev, dbl_c_prev, mul_c_prev; 35387901324dSJerome Forissier add_count = 0; 35397901324dSJerome Forissier dbl_count = 0; 35407901324dSJerome Forissier mul_count = 0; 35417901324dSJerome Forissier 35427901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[0])); 35437901324dSJerome Forissier MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m)); 354432b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL)); 35457901324dSJerome Forissier 354632b31808SJens Wiklander for (i = 1; i < n_exponents; i++) { 35477901324dSJerome Forissier add_c_prev = add_count; 35487901324dSJerome Forissier dbl_c_prev = dbl_count; 35497901324dSJerome Forissier mul_c_prev = mul_count; 35507901324dSJerome Forissier add_count = 0; 35517901324dSJerome Forissier dbl_count = 0; 35527901324dSJerome Forissier mul_count = 0; 35537901324dSJerome Forissier 35547901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[i])); 35557901324dSJerome Forissier MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m)); 355632b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL)); 35577901324dSJerome Forissier 35587901324dSJerome Forissier if (add_count != add_c_prev || 35597901324dSJerome Forissier dbl_count != dbl_c_prev || 356032b31808SJens Wiklander mul_count != mul_c_prev) { 35617901324dSJerome Forissier ret = 1; 35627901324dSJerome Forissier break; 35637901324dSJerome Forissier } 35647901324dSJerome Forissier } 35657901324dSJerome Forissier 35667901324dSJerome Forissier cleanup: 356732b31808SJens Wiklander if (verbose != 0) { 356832b31808SJens Wiklander if (ret != 0) { 35697901324dSJerome Forissier mbedtls_printf("failed (%u)\n", (unsigned int) i); 357032b31808SJens Wiklander } else { 35717901324dSJerome Forissier mbedtls_printf("passed\n"); 35727901324dSJerome Forissier } 357332b31808SJens Wiklander } 357432b31808SJens Wiklander return ret; 35757901324dSJerome Forissier } 3576*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 35777901324dSJerome Forissier 3578817466cbSJens Wiklander /* 3579817466cbSJens Wiklander * Checkup routine 3580817466cbSJens Wiklander */ 3581817466cbSJens Wiklander int mbedtls_ecp_self_test(int verbose) 3582817466cbSJens Wiklander { 3583*b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C) 358411fa71b9SJerome Forissier int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; 3585817466cbSJens Wiklander mbedtls_ecp_group grp; 3586817466cbSJens Wiklander mbedtls_ecp_point R, P; 3587817466cbSJens Wiklander mbedtls_mpi m; 35887901324dSJerome Forissier 35897901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 35907901324dSJerome Forissier /* Exponents especially adapted for secp192k1, which has the lowest 35917901324dSJerome Forissier * order n of all supported curves (secp192r1 is in a slightly larger 35927901324dSJerome Forissier * field but the order of its base point is slightly smaller). */ 35937901324dSJerome Forissier const char *sw_exponents[] = 3594817466cbSJens Wiklander { 3595817466cbSJens Wiklander "000000000000000000000000000000000000000000000001", /* one */ 35967901324dSJerome Forissier "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8C", /* n - 1 */ 3597817466cbSJens Wiklander "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */ 3598817466cbSJens Wiklander "400000000000000000000000000000000000000000000000", /* one and zeros */ 3599817466cbSJens Wiklander "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */ 3600817466cbSJens Wiklander "555555555555555555555555555555555555555555555555", /* 101010... */ 3601817466cbSJens Wiklander }; 36027901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 36037901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 36047901324dSJerome Forissier const char *m_exponents[] = 36057901324dSJerome Forissier { 36067901324dSJerome Forissier /* Valid private values for Curve25519. In a build with Curve448 36077901324dSJerome Forissier * but not Curve25519, they will be adjusted in 36087901324dSJerome Forissier * self_test_adjust_exponent(). */ 36097901324dSJerome Forissier "4000000000000000000000000000000000000000000000000000000000000000", 36107901324dSJerome Forissier "5C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C30", 36117901324dSJerome Forissier "5715ECCE24583F7A7023C24164390586842E816D7280A49EF6DF4EAE6B280BF8", 36127901324dSJerome Forissier "41A2B017516F6D254E1F002BCCBADD54BE30F8CEC737A0E912B4963B6BA74460", 36137901324dSJerome Forissier "5555555555555555555555555555555555555555555555555555555555555550", 36147901324dSJerome Forissier "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8", 36157901324dSJerome Forissier }; 36167901324dSJerome Forissier #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3617817466cbSJens Wiklander 3618817466cbSJens Wiklander mbedtls_ecp_group_init(&grp); 3619817466cbSJens Wiklander mbedtls_ecp_point_init(&R); 3620817466cbSJens Wiklander mbedtls_ecp_point_init(&P); 3621817466cbSJens Wiklander mbedtls_mpi_init(&m); 3622817466cbSJens Wiklander 36237901324dSJerome Forissier #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) 3624817466cbSJens Wiklander /* Use secp192r1 if available, or any available curve */ 3625817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) 3626817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP192R1)); 3627817466cbSJens Wiklander #else 3628817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, mbedtls_ecp_curve_list()->grp_id)); 3629817466cbSJens Wiklander #endif 3630817466cbSJens Wiklander 363132b31808SJens Wiklander if (verbose != 0) { 36327901324dSJerome Forissier mbedtls_printf(" ECP SW test #1 (constant op_count, base point G): "); 363332b31808SJens Wiklander } 3634817466cbSJens Wiklander /* Do a dummy multiplication first to trigger precomputation */ 3635817466cbSJens Wiklander MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&m, 2)); 363632b31808SJens Wiklander MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &P, &m, &grp.G, self_test_rng, NULL)); 36377901324dSJerome Forissier ret = self_test_point(verbose, 36387901324dSJerome Forissier &grp, &R, &m, &grp.G, 36397901324dSJerome Forissier sw_exponents, 36407901324dSJerome Forissier sizeof(sw_exponents) / sizeof(sw_exponents[0])); 364132b31808SJens Wiklander if (ret != 0) { 3642817466cbSJens Wiklander goto cleanup; 364332b31808SJens Wiklander } 3644817466cbSJens Wiklander 364532b31808SJens Wiklander if (verbose != 0) { 36467901324dSJerome Forissier mbedtls_printf(" ECP SW test #2 (constant op_count, other point): "); 364732b31808SJens Wiklander } 3648817466cbSJens Wiklander /* We computed P = 2G last time, use it */ 36497901324dSJerome Forissier ret = self_test_point(verbose, 36507901324dSJerome Forissier &grp, &R, &m, &P, 36517901324dSJerome Forissier sw_exponents, 36527901324dSJerome Forissier sizeof(sw_exponents) / sizeof(sw_exponents[0])); 365332b31808SJens Wiklander if (ret != 0) { 3654817466cbSJens Wiklander goto cleanup; 365532b31808SJens Wiklander } 3656817466cbSJens Wiklander 36577901324dSJerome Forissier mbedtls_ecp_group_free(&grp); 36587901324dSJerome Forissier mbedtls_ecp_point_free(&R); 36597901324dSJerome Forissier #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ 36607901324dSJerome Forissier 36617901324dSJerome Forissier #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) 366232b31808SJens Wiklander if (verbose != 0) { 36637901324dSJerome Forissier mbedtls_printf(" ECP Montgomery test (constant op_count): "); 366432b31808SJens Wiklander } 36657901324dSJerome Forissier #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) 36667901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE25519)); 36677901324dSJerome Forissier #elif defined(MBEDTLS_ECP_DP_CURVE448_ENABLED) 36687901324dSJerome Forissier MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE448)); 36697901324dSJerome Forissier #else 36707901324dSJerome Forissier #error "MBEDTLS_ECP_MONTGOMERY_ENABLED is defined, but no curve is supported for self-test" 36717901324dSJerome Forissier #endif 36727901324dSJerome Forissier ret = self_test_point(verbose, 36737901324dSJerome Forissier &grp, &R, &m, &grp.G, 36747901324dSJerome Forissier m_exponents, 36757901324dSJerome Forissier sizeof(m_exponents) / sizeof(m_exponents[0])); 367632b31808SJens Wiklander if (ret != 0) { 36777901324dSJerome Forissier goto cleanup; 367832b31808SJens Wiklander } 36797901324dSJerome Forissier #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ 3680817466cbSJens Wiklander 3681817466cbSJens Wiklander cleanup: 3682817466cbSJens Wiklander 368332b31808SJens Wiklander if (ret < 0 && verbose != 0) { 36847901324dSJerome Forissier mbedtls_printf("Unexpected error, return code = %08X\n", (unsigned int) ret); 368532b31808SJens Wiklander } 3686817466cbSJens Wiklander 3687817466cbSJens Wiklander mbedtls_ecp_group_free(&grp); 3688817466cbSJens Wiklander mbedtls_ecp_point_free(&R); 3689817466cbSJens Wiklander mbedtls_ecp_point_free(&P); 3690817466cbSJens Wiklander mbedtls_mpi_free(&m); 3691817466cbSJens Wiklander 369232b31808SJens Wiklander if (verbose != 0) { 3693817466cbSJens Wiklander mbedtls_printf("\n"); 369432b31808SJens Wiklander } 3695817466cbSJens Wiklander 369632b31808SJens Wiklander return ret; 3697*b0563631STom Van Eyck #else /* MBEDTLS_ECP_C */ 3698*b0563631STom Van Eyck (void) verbose; 3699*b0563631STom Van Eyck return 0; 3700*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */ 3701817466cbSJens Wiklander } 3702817466cbSJens Wiklander 3703817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */ 3704817466cbSJens Wiklander 3705817466cbSJens Wiklander #endif /* !MBEDTLS_ECP_ALT */ 3706817466cbSJens Wiklander 3707*b0563631STom Van Eyck #endif /* MBEDTLS_ECP_LIGHT */ 3708