/* * Elliptic curves over GF(p): generic functions * * Copyright The Mbed TLS Contributors * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ /* * References: * * SEC1 https://www.secg.org/sec1-v2.pdf * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf * RFC 4492 for the related TLS structures and constants * - https://www.rfc-editor.org/rfc/rfc4492 * RFC 7748 for the Curve448 and Curve25519 curve definitions * - https://www.rfc-editor.org/rfc/rfc7748 * * [Curve25519] https://cr.yp.to/ecdh/curve25519-20060209.pdf * * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis * for elliptic curve cryptosystems. In : Cryptographic Hardware and * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302. * <http://link.springer.com/chapter/10.1007/3-540-48059-5_25> * * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to * render ECC resistant against Side Channel Attacks. IACR Cryptology * ePrint Archive, 2004, vol. 2004, p. 342. * <http://eprint.iacr.org/2004/342.pdf> */ #include "common.h" /** * \brief Function level alternative implementation. * * The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to * replace certain functions in this module. The alternative implementations are * typically hardware accelerators and need to activate the hardware before the * computation starts and deactivate it after it finishes. The * mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve * this purpose. * * To preserve the correct functionality the following conditions must hold: * * - The alternative implementation must be activated by * mbedtls_internal_ecp_init() before any of the replaceable functions is * called. * - mbedtls_internal_ecp_free() must \b only be called when the alternative * implementation is activated. * - mbedtls_internal_ecp_init() must \b not be called when the alternative * implementation is activated. * - Public functions must not return while the alternative implementation is * activated. * - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and * before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) ) * \endcode ensures that the alternative implementation supports the current * group. */ #if defined(MBEDTLS_ECP_INTERNAL_ALT) #endif #if defined(MBEDTLS_ECP_LIGHT) #include "mbedtls/ecp.h" #include "mbedtls/threading.h" #include "mbedtls/platform_util.h" #include "mbedtls/error.h" #include "bn_mul.h" #include "ecp_invasive.h" #include <string.h> #if !defined(MBEDTLS_ECP_ALT) #include "mbedtls/platform.h" #include "ecp_internal_alt.h" #if defined(MBEDTLS_SELF_TEST) /* * Counts of point addition and doubling, and field multiplications. * Used to test resistance of point multiplication to simple timing attacks. */ #if defined(MBEDTLS_ECP_C) static unsigned long add_count, dbl_count; #endif /* MBEDTLS_ECP_C */ static unsigned long mul_count; #endif #if defined(MBEDTLS_ECP_RESTARTABLE) /* * Maximum number of "basic operations" to be done in a row. * * Default value 0 means that ECC operations will not yield. * Note that regardless of the value of ecp_max_ops, always at * least one step is performed before yielding. * * Setting ecp_max_ops=1 can be suitable for testing purposes * as it will interrupt computation at all possible points. */ static unsigned ecp_max_ops = 0; /* * Set ecp_max_ops */ void mbedtls_ecp_set_max_ops(unsigned max_ops) { ecp_max_ops = max_ops; } /* * Check if restart is enabled */ int mbedtls_ecp_restart_is_enabled(void) { return ecp_max_ops != 0; } /* * Restart sub-context for ecp_mul_comb() */ struct mbedtls_ecp_restart_mul { mbedtls_ecp_point R; /* current intermediate result */ size_t i; /* current index in various loops, 0 outside */ mbedtls_ecp_point *T; /* table for precomputed points */ unsigned char T_size; /* number of points in table T */ enum { /* what were we doing last time we returned? */ ecp_rsm_init = 0, /* nothing so far, dummy initial state */ ecp_rsm_pre_dbl, /* precompute 2^n multiples */ ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */ ecp_rsm_pre_add, /* precompute remaining points by adding */ ecp_rsm_pre_norm_add, /* normalize all precomputed points */ ecp_rsm_comb_core, /* ecp_mul_comb_core() */ ecp_rsm_final_norm, /* do the final normalization */ } state; }; /* * Init restart_mul sub-context */ static void ecp_restart_rsm_init(mbedtls_ecp_restart_mul_ctx *ctx) { mbedtls_ecp_point_init(&ctx->R); ctx->i = 0; ctx->T = NULL; ctx->T_size = 0; ctx->state = ecp_rsm_init; } /* * Free the components of a restart_mul sub-context */ static void ecp_restart_rsm_free(mbedtls_ecp_restart_mul_ctx *ctx) { unsigned char i; if (ctx == NULL) { return; } mbedtls_ecp_point_free(&ctx->R); if (ctx->T != NULL) { for (i = 0; i < ctx->T_size; i++) { mbedtls_ecp_point_free(ctx->T + i); } mbedtls_free(ctx->T); } ecp_restart_rsm_init(ctx); } /* * Restart context for ecp_muladd() */ struct mbedtls_ecp_restart_muladd { mbedtls_ecp_point mP; /* mP value */ mbedtls_ecp_point R; /* R intermediate result */ enum { /* what should we do next? */ ecp_rsma_mul1 = 0, /* first multiplication */ ecp_rsma_mul2, /* second multiplication */ ecp_rsma_add, /* addition */ ecp_rsma_norm, /* normalization */ } state; }; /* * Init restart_muladd sub-context */ static void ecp_restart_ma_init(mbedtls_ecp_restart_muladd_ctx *ctx) { mbedtls_ecp_point_init(&ctx->mP); mbedtls_ecp_point_init(&ctx->R); ctx->state = ecp_rsma_mul1; } /* * Free the components of a restart_muladd sub-context */ static void ecp_restart_ma_free(mbedtls_ecp_restart_muladd_ctx *ctx) { if (ctx == NULL) { return; } mbedtls_ecp_point_free(&ctx->mP); mbedtls_ecp_point_free(&ctx->R); ecp_restart_ma_init(ctx); } /* * Initialize a restart context */ void mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx *ctx) { ctx->ops_done = 0; ctx->depth = 0; ctx->rsm = NULL; ctx->ma = NULL; } /* * Free the components of a restart context */ void mbedtls_ecp_restart_free(mbedtls_ecp_restart_ctx *ctx) { if (ctx == NULL) { return; } ecp_restart_rsm_free(ctx->rsm); mbedtls_free(ctx->rsm); ecp_restart_ma_free(ctx->ma); mbedtls_free(ctx->ma); mbedtls_ecp_restart_init(ctx); } /* * Check if we can do the next step */ int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp, mbedtls_ecp_restart_ctx *rs_ctx, unsigned ops) { if (rs_ctx != NULL && ecp_max_ops != 0) { /* scale depending on curve size: the chosen reference is 256-bit, * and multiplication is quadratic. Round to the closest integer. */ if (grp->pbits >= 512) { ops *= 4; } else if (grp->pbits >= 384) { ops *= 2; } /* Avoid infinite loops: always allow first step. * Because of that, however, it's not generally true * that ops_done <= ecp_max_ops, so the check * ops_done > ecp_max_ops below is mandatory. */ if ((rs_ctx->ops_done != 0) && (rs_ctx->ops_done > ecp_max_ops || ops > ecp_max_ops - rs_ctx->ops_done)) { return MBEDTLS_ERR_ECP_IN_PROGRESS; } /* update running count */ rs_ctx->ops_done += ops; } return 0; } /* Call this when entering a function that needs its own sub-context */ #define ECP_RS_ENTER … /* Call this when leaving a function that needs its own sub-context */ #define ECP_RS_LEAVE … #else /* MBEDTLS_ECP_RESTARTABLE */ #define ECP_RS_ENTER(sub) … #define ECP_RS_LEAVE(sub) … #endif /* MBEDTLS_ECP_RESTARTABLE */ #if defined(MBEDTLS_ECP_C) static void mpi_init_many(mbedtls_mpi *arr, size_t size) { … } static void mpi_free_many(mbedtls_mpi *arr, size_t size) { … } #endif /* MBEDTLS_ECP_C */ /* * List of supported curves: * - internal ID * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2, RFC 8446 sec. 4.2.7) * - size in bits * - readable name * * Curves are listed in order: largest curves first, and for a given size, * fastest curves first. * * Reminder: update profiles in x509_crt.c and ssl_tls.c when adding a new curve! */ static const mbedtls_ecp_curve_info ecp_supported_curves[] = …; #define ECP_NB_CURVES … static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES]; /* * List of supported curves and associated info */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list(void) { … } /* * List of supported curves, group ID only */ const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list(void) { … } /* * Get the curve info for the internal identifier */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id(mbedtls_ecp_group_id grp_id) { … } /* * Get the curve info from the TLS identifier */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id(uint16_t tls_id) { … } /* * Get the curve info from the name */ const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name(const char *name) { … } /* * Get the type of a curve */ mbedtls_ecp_curve_type mbedtls_ecp_get_type(const mbedtls_ecp_group *grp) { … } /* * Initialize (the components of) a point */ void mbedtls_ecp_point_init(mbedtls_ecp_point *pt) { … } /* * Initialize (the components of) a group */ void mbedtls_ecp_group_init(mbedtls_ecp_group *grp) { … } /* * Initialize (the components of) a key pair */ void mbedtls_ecp_keypair_init(mbedtls_ecp_keypair *key) { … } /* * Unallocate (the components of) a point */ void mbedtls_ecp_point_free(mbedtls_ecp_point *pt) { … } /* * Check that the comb table (grp->T) is static initialized. */ static int ecp_group_is_static_comb_table(const mbedtls_ecp_group *grp) { … } /* * Unallocate (the components of) a group */ void mbedtls_ecp_group_free(mbedtls_ecp_group *grp) { … } /* * Unallocate (the components of) a key pair */ void mbedtls_ecp_keypair_free(mbedtls_ecp_keypair *key) { … } /* * Copy the contents of a point */ int mbedtls_ecp_copy(mbedtls_ecp_point *P, const mbedtls_ecp_point *Q) { … } /* * Copy the contents of a group object */ int mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, const mbedtls_ecp_group *src) { … } /* * Set point to zero */ int mbedtls_ecp_set_zero(mbedtls_ecp_point *pt) { … } /* * Tell if a point is zero */ int mbedtls_ecp_is_zero(mbedtls_ecp_point *pt) { … } /* * Compare two points lazily */ int mbedtls_ecp_point_cmp(const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q) { … } /* * Import a non-zero point from ASCII strings */ int mbedtls_ecp_point_read_string(mbedtls_ecp_point *P, int radix, const char *x, const char *y) { … } /* * Export a point into unsigned binary data (SEC1 2.3.3 and RFC7748) */ int mbedtls_ecp_point_write_binary(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P, int format, size_t *olen, unsigned char *buf, size_t buflen) { … } #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, const mbedtls_mpi *X, mbedtls_mpi *Y, int parity_bit); #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ /* * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748) */ int mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, const unsigned char *buf, size_t ilen) { … } /* * Import a point from a TLS ECPoint record (RFC 4492) * struct { * opaque point <1..2^8-1>; * } ECPoint; */ int mbedtls_ecp_tls_read_point(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, const unsigned char **buf, size_t buf_len) { … } /* * Export a point as a TLS ECPoint record (RFC 4492) * struct { * opaque point <1..2^8-1>; * } ECPoint; */ int mbedtls_ecp_tls_write_point(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt, int format, size_t *olen, unsigned char *buf, size_t blen) { … } /* * Set a group from an ECParameters record (RFC 4492) */ int mbedtls_ecp_tls_read_group(mbedtls_ecp_group *grp, const unsigned char **buf, size_t len) { … } /* * Read a group id from an ECParameters record (RFC 4492) and convert it to * mbedtls_ecp_group_id. */ int mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp, const unsigned char **buf, size_t len) { … } /* * Write the ECParameters record corresponding to a group (RFC 4492) */ int mbedtls_ecp_tls_write_group(const mbedtls_ecp_group *grp, size_t *olen, unsigned char *buf, size_t blen) { … } /* * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi. * See the documentation of struct mbedtls_ecp_group. * * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf. */ static int ecp_modp(mbedtls_mpi *N, const mbedtls_ecp_group *grp) { … } /* * Fast mod-p functions expect their argument to be in the 0..p^2 range. * * In order to guarantee that, we need to ensure that operands of * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will * bring the result back to this range. * * The following macros are shortcuts for doing that. */ /* * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi */ #if defined(MBEDTLS_SELF_TEST) #define INC_MUL_COUNT … #else #define INC_MUL_COUNT #endif #define MOD_MUL(N) … static inline int mbedtls_mpi_mul_mod(const mbedtls_ecp_group *grp, mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) { … } /* * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi * N->s < 0 is a very fast test, which fails only if N is 0 */ #define MOD_SUB(N) … MBEDTLS_MAYBE_UNUSED static inline int mbedtls_mpi_sub_mod(const mbedtls_ecp_group *grp, mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) { … } /* * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int. * We known P, N and the result are positive, so sub_abs is correct, and * a bit faster. */ #define MOD_ADD(N) … static inline int mbedtls_mpi_add_mod(const mbedtls_ecp_group *grp, mbedtls_mpi *X, const mbedtls_mpi *A, const mbedtls_mpi *B) { … } MBEDTLS_MAYBE_UNUSED static inline int mbedtls_mpi_mul_int_mod(const mbedtls_ecp_group *grp, mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint c) { … } MBEDTLS_MAYBE_UNUSED static inline int mbedtls_mpi_sub_int_mod(const mbedtls_ecp_group *grp, mbedtls_mpi *X, const mbedtls_mpi *A, mbedtls_mpi_uint c) { … } #define MPI_ECP_SUB_INT(X, A, c) … MBEDTLS_MAYBE_UNUSED static inline int mbedtls_mpi_shift_l_mod(const mbedtls_ecp_group *grp, mbedtls_mpi *X, size_t count) { … } /* * Macro wrappers around ECP modular arithmetic * * Currently, these wrappers are defined via the bignum module. */ #define MPI_ECP_ADD(X, A, B) … #define MPI_ECP_SUB(X, A, B) … #define MPI_ECP_MUL(X, A, B) … #define MPI_ECP_SQR(X, A) … #define MPI_ECP_MUL_INT(X, A, c) … #define MPI_ECP_INV(dst, src) … #define MPI_ECP_MOV(X, A) … #define MPI_ECP_SHIFT_L(X, count) … #define MPI_ECP_LSET(X, c) … #define MPI_ECP_CMP_INT(X, c) … #define MPI_ECP_CMP(X, Y) … /* Needs f_rng, p_rng to be defined. */ #define MPI_ECP_RAND(X) … /* Conditional negation * Needs grp and a temporary MPI tmp to be defined. */ #define MPI_ECP_COND_NEG(X, cond) … #define MPI_ECP_NEG(X) … #define MPI_ECP_VALID(X) … #define MPI_ECP_COND_ASSIGN(X, Y, cond) … #define MPI_ECP_COND_SWAP(X, Y, cond) … #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) /* * Computes the right-hand side of the Short Weierstrass equation * RHS = X^3 + A X + B */ static int ecp_sw_rhs(const mbedtls_ecp_group *grp, mbedtls_mpi *rhs, const mbedtls_mpi *X) { … } /* * Derive Y from X and a parity bit */ static int mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group *grp, const mbedtls_mpi *X, mbedtls_mpi *Y, int parity_bit) { … } #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ #if defined(MBEDTLS_ECP_C) #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) /* * For curves in short Weierstrass form, we do all the internal operations in * Jacobian coordinates. * * For multiplication, we'll use a comb method with countermeasures against * SPA, hence timing attacks. */ /* * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1) * Cost: 1N := 1I + 3M + 1S */ static int ecp_normalize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt) { … } /* * Normalize jacobian coordinates of an array of (pointers to) points, * using Montgomery's trick to perform only one inversion mod P. * (See for example Cohen's "A Course in Computational Algebraic Number * Theory", Algorithm 10.3.4.) * * Warning: fails (returning an error) if one of the points is zero! * This should never happen, see choice of w in ecp_mul_comb(). * * Cost: 1N(t) := 1I + (6t - 3)M + 1S */ static int ecp_normalize_jac_many(const mbedtls_ecp_group *grp, mbedtls_ecp_point *T[], size_t T_size) { … } /* * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak. * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid */ static int ecp_safe_invert_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *Q, unsigned char inv) { … } /* * Point doubling R = 2 P, Jacobian coordinates * * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 . * * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring. * * Standard optimizations are applied when curve parameter A is one of { 0, -3 }. * * Cost: 1D := 3M + 4S (A == 0) * 4M + 4S (A == -3) * 3M + 6S + 1a otherwise */ static int ecp_double_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P, mbedtls_mpi tmp[4]) { … } /* * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22) * * The coordinates of Q must be normalized (= affine), * but those of P don't need to. R is not normalized. * * P,Q,R may alias, but only at the level of EC points: they must be either * equal as pointers, or disjoint (including the coordinate data buffers). * Fine-grained aliasing at the level of coordinates is not supported. * * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q. * None of these cases can happen as intermediate step in ecp_mul_comb(): * - at each step, P, Q and R are multiples of the base point, the factor * being less than its order, so none of them is zero; * - Q is an odd multiple of the base point, P an even multiple, * due to the choice of precomputed points in the modified comb method. * So branches for these cases do not leak secret information. * * Cost: 1A := 8M + 3S */ static int ecp_add_mixed(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, mbedtls_mpi tmp[4]) { … } /* * Randomize jacobian coordinates: * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l * This is sort of the reverse operation of ecp_normalize_jac(). * * This countermeasure was first suggested in [2]. */ static int ecp_randomize_jac(const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } /* * Check and define parameters used by the comb method (see below for details) */ #if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7 #error "MBEDTLS_ECP_WINDOW_SIZE out of bounds" #endif /* d = ceil( n / w ) */ #define COMB_MAX_D … /* number of precomputed points */ #define COMB_MAX_PRE … /* * Compute the representation of m that will be used with our comb method. * * The basic comb method is described in GECC 3.44 for example. We use a * modified version that provides resistance to SPA by avoiding zero * digits in the representation as in [3]. We modify the method further by * requiring that all K_i be odd, which has the small cost that our * representation uses one more K_i, due to carries, but saves on the size of * the precomputed table. * * Summary of the comb method and its modifications: * * - The goal is to compute m*P for some w*d-bit integer m. * * - The basic comb method splits m into the w-bit integers * x[0] .. x[d-1] where x[i] consists of the bits in m whose * index has residue i modulo d, and computes m * P as * S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where * S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P. * * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum by * .. + 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]] .., * thereby successively converting it into a form where all summands * are nonzero, at the cost of negative summands. This is the basic idea of [3]. * * - More generally, even if x[i+1] != 0, we can first transform the sum as * .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] .., * and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] & x[i+1]]. * Performing and iterating this procedure for those x[i] that are even * (keeping track of carry), we can transform the original sum into one of the form * S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]] * with all x'[i] odd. It is therefore only necessary to know S at odd indices, * which is why we are only computing half of it in the first place in * ecp_precompute_comb and accessing it with index abs(i) / 2 in ecp_select_comb. * * - For the sake of compactness, only the seven low-order bits of x[i] * are used to represent its absolute value (K_i in the paper), and the msb * of x[i] encodes the sign (s_i in the paper): it is set if and only if * if s_i == -1; * * Calling conventions: * - x is an array of size d + 1 * - w is the size, ie number of teeth, of the comb, and must be between * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE) * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d * (the result will be incorrect if these assumptions are not satisfied) */ static void ecp_comb_recode_core(unsigned char x[], size_t d, unsigned char w, const mbedtls_mpi *m) { … } /* * Precompute points for the adapted comb method * * Assumption: T must be able to hold 2^{w - 1} elements. * * Operation: If i = i_{w-1} ... i_1 is the binary representation of i, * sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P. * * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1) * * Note: Even comb values (those where P would be omitted from the * sum defining T[i] above) are not needed in our adaption * the comb method. See ecp_comb_recode_core(). * * This function currently works in four steps: * (1) [dbl] Computation of intermediate T[i] for 2-power values of i * (2) [norm_dbl] Normalization of coordinates of these T[i] * (3) [add] Computation of all T[i] * (4) [norm_add] Normalization of all T[i] * * Step 1 can be interrupted but not the others; together with the final * coordinate normalization they are the largest steps done at once, depending * on the window size. Here are operation counts for P-256: * * step (2) (3) (4) * w = 5 142 165 208 * w = 4 136 77 160 * w = 3 130 33 136 * w = 2 124 11 124 * * So if ECC operations are blocking for too long even with a low max_ops * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order * to minimize maximum blocking time. */ static int ecp_precompute_comb(const mbedtls_ecp_group *grp, mbedtls_ecp_point T[], const mbedtls_ecp_point *P, unsigned char w, size_t d, mbedtls_ecp_restart_ctx *rs_ctx) { … } /* * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ] * * See ecp_comb_recode_core() for background */ static int ecp_select_comb(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point T[], unsigned char T_size, unsigned char i) { … } /* * Core multiplication algorithm for the (modified) comb method. * This part is actually common with the basic comb method (GECC 3.44) * * Cost: d A + d D + 1 R */ static int ecp_mul_comb_core(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point T[], unsigned char T_size, const unsigned char x[], size_t d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, mbedtls_ecp_restart_ctx *rs_ctx) { … } /* * Recode the scalar to get constant-time comb multiplication * * As the actual scalar recoding needs an odd scalar as a starting point, * this wrapper ensures that by replacing m by N - m if necessary, and * informs the caller that the result of multiplication will be negated. * * This works because we only support large prime order for Short Weierstrass * curves, so N is always odd hence either m or N - m is. * * See ecp_comb_recode_core() for background. */ static int ecp_comb_recode_scalar(const mbedtls_ecp_group *grp, const mbedtls_mpi *m, unsigned char k[COMB_MAX_D + 1], size_t d, unsigned char w, unsigned char *parity_trick) { … } /* * Perform comb multiplication (for short Weierstrass curves) * once the auxiliary table has been pre-computed. * * Scalar recoding may use a parity trick that makes us compute -m * P, * if that is the case we'll need to recover m * P at the end. */ static int ecp_mul_comb_after_precomp(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *T, unsigned char T_size, unsigned char w, size_t d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, mbedtls_ecp_restart_ctx *rs_ctx) { … } /* * Pick window size based on curve size and whether we optimize for base point */ static unsigned char ecp_pick_window_size(const mbedtls_ecp_group *grp, unsigned char p_eq_g) { … } /* * Multiplication using the comb method - for curves in short Weierstrass form * * This function is mainly responsible for administrative work: * - managing the restart context if enabled * - managing the table of precomputed points (passed between the below two * functions): allocation, computation, ownership transfer, freeing. * * It delegates the actual arithmetic work to: * ecp_precompute_comb() and ecp_mul_comb_with_precomp() * * See comments on ecp_comb_recode_core() regarding the computation strategy. */ static int ecp_mul_comb(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, mbedtls_ecp_restart_ctx *rs_ctx) { … } #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) /* * For Montgomery curves, we do all the internal arithmetic in projective * coordinates. Import/export of points uses only the x coordinates, which is * internally represented as X / Z. * * For scalar multiplication, we'll use a Montgomery ladder. */ /* * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1 * Cost: 1M + 1I */ static int ecp_normalize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P) { … } /* * Randomize projective x/z coordinates: * (X, Z) -> (l X, l Z) for random l * This is sort of the reverse operation of ecp_normalize_mxz(). * * This countermeasure was first suggested in [2]. * Cost: 2M */ static int ecp_randomize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } /* * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q), * for Montgomery curves in x/z coordinates. * * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3 * with * d = X1 * P = (X2, Z2) * Q = (X3, Z3) * R = (X4, Z4) * S = (X5, Z5) * and eliminating temporary variables tO, ..., t4. * * Cost: 5M + 4S */ static int ecp_double_add_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, mbedtls_ecp_point *S, const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q, const mbedtls_mpi *d, mbedtls_mpi T[4]) { … } /* * Multiplication with Montgomery ladder in x/z coordinates, * for curves in Montgomery form */ static int ecp_mul_mxz(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ /* * Restartable multiplication R = m * P * * This internal function can be called without an RNG in case where we know * the inputs are not sensitive. */ static int ecp_mul_restartable_internal(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, mbedtls_ecp_restart_ctx *rs_ctx) { … } /* * Restartable multiplication R = m * P */ int mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, mbedtls_ecp_restart_ctx *rs_ctx) { … } /* * Multiplication R = m * P */ int mbedtls_ecp_mul(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } #endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) /* * Check that an affine point is valid as a public key, * short weierstrass curves (SEC1 3.2.3.1) */ static int ecp_check_pubkey_sw(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) { … } #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ #if defined(MBEDTLS_ECP_C) #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) /* * R = m * P with shortcuts for m == 0, m == 1 and m == -1 * NOT constant-time - ONLY for short Weierstrass! */ static int mbedtls_ecp_mul_shortcuts(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, mbedtls_ecp_restart_ctx *rs_ctx) { … } /* * Restartable linear combination * NOT constant-time */ int mbedtls_ecp_muladd_restartable( mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, const mbedtls_mpi *n, const mbedtls_ecp_point *Q, mbedtls_ecp_restart_ctx *rs_ctx) { … } /* * Linear combination * NOT constant-time */ int mbedtls_ecp_muladd(mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_mpi *m, const mbedtls_ecp_point *P, const mbedtls_mpi *n, const mbedtls_ecp_point *Q) { … } #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ #endif /* MBEDTLS_ECP_C */ #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) #define ECP_MPI_INIT(_p, _n) … #define ECP_MPI_INIT_ARRAY(x) … /* * Constants for the two points other than 0, 1, -1 (mod p) in * https://cr.yp.to/ecdh.html#validate * See ecp_check_pubkey_x25519(). */ static const mbedtls_mpi_uint x25519_bad_point_1[] = …; static const mbedtls_mpi_uint x25519_bad_point_2[] = …; static const mbedtls_mpi ecp_x25519_bad_point_1 = …; static const mbedtls_mpi ecp_x25519_bad_point_2 = …; #endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */ /* * Check that the input point is not one of the low-order points. * This is recommended by the "May the Fourth" paper: * https://eprint.iacr.org/2017/806.pdf * Those points are never sent by an honest peer. */ static int ecp_check_bad_points_mx(const mbedtls_mpi *X, const mbedtls_mpi *P, const mbedtls_ecp_group_id grp_id) { … } /* * Check validity of a public key for Montgomery curves with x-only schemes */ static int ecp_check_pubkey_mx(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) { … } #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ /* * Check that a point is valid as a public key */ int mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt) { … } /* * Check that an mbedtls_mpi is valid as a private key */ int mbedtls_ecp_check_privkey(const mbedtls_ecp_group *grp, const mbedtls_mpi *d) { … } #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) MBEDTLS_STATIC_TESTABLE int mbedtls_ecp_gen_privkey_mx(size_t high_bit, mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } #endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */ #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) static int mbedtls_ecp_gen_privkey_sw( const mbedtls_mpi *N, mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */ /* * Generate a private key */ int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp, mbedtls_mpi *d, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } #if defined(MBEDTLS_ECP_C) /* * Generate a keypair with configurable base point */ int mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp, const mbedtls_ecp_point *G, mbedtls_mpi *d, mbedtls_ecp_point *Q, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } /* * Generate key pair, wrapper for conventional base point */ int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } /* * Generate a keypair, prettier wrapper */ int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } #endif /* MBEDTLS_ECP_C */ int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, const mbedtls_ecp_point *Q) { … } #define ECP_CURVE25519_KEY_SIZE … #define ECP_CURVE448_KEY_SIZE … /* * Read a private key. */ int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key, const unsigned char *buf, size_t buflen) { … } /* * Write a private key. */ #if !defined MBEDTLS_DEPRECATED_REMOVED int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key, unsigned char *buf, size_t buflen) { int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED; #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) { if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) { if (buflen < ECP_CURVE25519_KEY_SIZE) { return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; } } else if (key->grp.id == MBEDTLS_ECP_DP_CURVE448) { if (buflen < ECP_CURVE448_KEY_SIZE) { return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL; } } MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&key->d, buf, buflen)); } #endif #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) { MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&key->d, buf, buflen)); } #endif cleanup: return ret; } #endif /* MBEDTLS_DEPRECATED_REMOVED */ int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key, size_t *olen, unsigned char *buf, size_t buflen) { … } /* * Write a public key. */ int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key, int format, size_t *olen, unsigned char *buf, size_t buflen) { … } #if defined(MBEDTLS_ECP_C) /* * Check a public-private key pair */ int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } int mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair *key, int (*f_rng)(void *, unsigned char *, size_t), void *p_rng) { … } #endif /* MBEDTLS_ECP_C */ mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id( const mbedtls_ecp_keypair *key) { … } /* * Export generic key-pair parameters. */ int mbedtls_ecp_export(const mbedtls_ecp_keypair *key, mbedtls_ecp_group *grp, mbedtls_mpi *d, mbedtls_ecp_point *Q) { … } #if defined(MBEDTLS_SELF_TEST) #if defined(MBEDTLS_ECP_C) /* * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!! * * This is the linear congruential generator from numerical recipes, * except we only use the low byte as the output. See * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use */ static int self_test_rng(void *ctx, unsigned char *out, size_t len) { … } /* Adjust the exponent to be a valid private point for the specified curve. * This is sometimes necessary because we use a single set of exponents * for all curves but the validity of values depends on the curve. */ static int self_test_adjust_exponent(const mbedtls_ecp_group *grp, mbedtls_mpi *m) { … } /* Calculate R = m.P for each m in exponents. Check that the number of * basic operations doesn't depend on the value of m. */ static int self_test_point(int verbose, mbedtls_ecp_group *grp, mbedtls_ecp_point *R, mbedtls_mpi *m, const mbedtls_ecp_point *P, const char *const *exponents, size_t n_exponents) { … } #endif /* MBEDTLS_ECP_C */ /* * Checkup routine */ int mbedtls_ecp_self_test(int verbose) { … } #endif /* MBEDTLS_SELF_TEST */ #endif /* !MBEDTLS_ECP_ALT */ #endif /* MBEDTLS_ECP_LIGHT */