xref: /optee_os/lib/libmbedtls/mbedtls/library/ecp.c (revision c3deb3d6f3b13d0e17fc9efe5880aec039e47594)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  Elliptic curves over GF(p): generic functions
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5b0563631STom 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  *
11b0563631STom 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
15b0563631STom Van Eyck  * - https://www.rfc-editor.org/rfc/rfc4492
163d3b0591SJens Wiklander  * RFC 7748 for the Curve448 and Curve25519 curve definitions
17b0563631STom Van Eyck  * - https://www.rfc-editor.org/rfc/rfc7748
18817466cbSJens Wiklander  *
19b0563631STom 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 
63b0563631STom 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  */
86b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C)
87b0563631STom Van Eyck static unsigned long add_count, dbl_count;
88b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */
89b0563631STom 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  */
mbedtls_ecp_set_max_ops(unsigned max_ops)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  */
mbedtls_ecp_restart_is_enabled(void)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  */
ecp_restart_rsm_init(mbedtls_ecp_restart_mul_ctx * ctx)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  */
ecp_restart_rsm_free(mbedtls_ecp_restart_mul_ctx * ctx)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  */
ecp_restart_ma_init(mbedtls_ecp_restart_muladd_ctx * ctx)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  */
ecp_restart_ma_free(mbedtls_ecp_restart_muladd_ctx * ctx)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  */
mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx * ctx)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  */
mbedtls_ecp_restart_free(mbedtls_ecp_restart_ctx * ctx)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  */
mbedtls_ecp_check_budget(const mbedtls_ecp_group * grp,mbedtls_ecp_restart_ctx * rs_ctx,unsigned ops)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 
316b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C)
mpi_init_many(mbedtls_mpi * arr,size_t size)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 
mpi_free_many(mbedtls_mpi * arr,size_t size)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 }
330b0563631STom 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  */
mbedtls_ecp_curve_list(void)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  */
mbedtls_ecp_grp_id_list(void)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  */
mbedtls_ecp_curve_info_from_grp_id(mbedtls_ecp_group_id grp_id)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  */
mbedtls_ecp_curve_info_from_tls_id(uint16_t tls_id)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  */
mbedtls_ecp_curve_info_from_name(const char * name)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  */
mbedtls_ecp_get_type(const mbedtls_ecp_group * grp)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  */
mbedtls_ecp_point_init(mbedtls_ecp_point * pt)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  */
mbedtls_ecp_group_init(mbedtls_ecp_group * grp)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  */
mbedtls_ecp_keypair_init(mbedtls_ecp_keypair * key)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  */
mbedtls_ecp_point_free(mbedtls_ecp_point * pt)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  */
ecp_group_is_static_comb_table(const mbedtls_ecp_group * grp)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  */
mbedtls_ecp_group_free(mbedtls_ecp_group * grp)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);
587b0563631STom Van Eyck 
588b0563631STom Van Eyck #if !defined(MBEDTLS_ECP_WITH_MPI_UINT)
589b0563631STom Van Eyck         mbedtls_mpi_free(&grp->N);
590b0563631STom Van Eyck         mbedtls_mpi_free(&grp->P);
591b0563631STom 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  */
mbedtls_ecp_keypair_free(mbedtls_ecp_keypair * key)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  */
mbedtls_ecp_copy(mbedtls_ecp_point * P,const mbedtls_ecp_point * Q)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  */
mbedtls_ecp_group_copy(mbedtls_ecp_group * dst,const mbedtls_ecp_group * src)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  */
mbedtls_ecp_set_zero(mbedtls_ecp_point * pt)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  */
mbedtls_ecp_is_zero(mbedtls_ecp_point * pt)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  */
mbedtls_ecp_point_cmp(const mbedtls_ecp_point * P,const mbedtls_ecp_point * Q)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  */
mbedtls_ecp_point_read_string(mbedtls_ecp_point * P,int radix,const char * x,const char * y)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  */
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)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  */
mbedtls_ecp_point_read_binary(const mbedtls_ecp_group * grp,mbedtls_ecp_point * pt,const unsigned char * buf,size_t ilen)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  */
mbedtls_ecp_tls_read_point(const mbedtls_ecp_group * grp,mbedtls_ecp_point * pt,const unsigned char ** buf,size_t buf_len)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  */
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)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  */
mbedtls_ecp_tls_read_group(mbedtls_ecp_group * grp,const unsigned char ** buf,size_t len)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  */
mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id * grp,const unsigned char ** buf,size_t len)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      */
953b0563631STom Van Eyck     tls_id = MBEDTLS_GET_UINT16_BE(*buf, 0);
954b0563631STom 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  */
mbedtls_ecp_tls_write_group(const mbedtls_ecp_group * grp,size_t * olen,unsigned char * buf,size_t blen)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  */
ecp_modp(mbedtls_mpi * N,const mbedtls_ecp_group * grp)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 
mbedtls_mpi_mul_mod(const mbedtls_ecp_group * grp,mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 
1081b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED
mbedtls_mpi_sub_mod(const mbedtls_ecp_group * grp,mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 
mbedtls_mpi_add_mod(const mbedtls_ecp_group * grp,mbedtls_mpi * X,const mbedtls_mpi * A,const mbedtls_mpi * B)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 
1115b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED
mbedtls_mpi_mul_int_mod(const mbedtls_ecp_group * grp,mbedtls_mpi * X,const mbedtls_mpi * A,mbedtls_mpi_uint c)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 
1129b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED
mbedtls_mpi_sub_int_mod(const mbedtls_ecp_group * grp,mbedtls_mpi * X,const mbedtls_mpi * A,mbedtls_mpi_uint c)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 
1146b0563631STom Van Eyck MBEDTLS_MAYBE_UNUSED
mbedtls_mpi_shift_l_mod(const mbedtls_ecp_group * grp,mbedtls_mpi * X,size_t count)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  */
ecp_sw_rhs(const mbedtls_ecp_group * grp,mbedtls_mpi * rhs,const mbedtls_mpi * X)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 */
1239b0563631STom 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  */
mbedtls_ecp_sw_derive_y(const mbedtls_ecp_group * grp,const mbedtls_mpi * X,mbedtls_mpi * Y,int parity_bit)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 }
1302b0563631STom Van Eyck #endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
130332b31808SJens Wiklander 
1304b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C)
1305b0563631STom 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  */
ecp_normalize_jac(const mbedtls_ecp_group * grp,mbedtls_ecp_point * pt)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  */
ecp_normalize_jac_many(const mbedtls_ecp_group * grp,mbedtls_ecp_point * T[],size_t T_size)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  */
ecp_safe_invert_jac(const mbedtls_ecp_group * grp,mbedtls_ecp_point * Q,unsigned char inv)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  */
ecp_double_jac(const mbedtls_ecp_group * grp,mbedtls_ecp_point * R,const mbedtls_ecp_point * P,mbedtls_mpi tmp[4])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 */
1510b0563631STom 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  */
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])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  */
ecp_randomize_jac(const mbedtls_ecp_group * grp,mbedtls_ecp_point * pt,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)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  */
ecp_comb_recode_core(unsigned char x[],size_t d,unsigned char w,const mbedtls_mpi * m)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  */
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)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  */
ecp_select_comb(const mbedtls_ecp_group * grp,mbedtls_ecp_point * R,const mbedtls_ecp_point T[],unsigned char T_size,unsigned char i)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  */
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)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  */
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)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  */
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)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  */
ecp_pick_window_size(const mbedtls_ecp_group * grp,unsigned char p_eq_g)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  */
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)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  */
ecp_normalize_mxz(const mbedtls_ecp_group * grp,mbedtls_ecp_point * P)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  */
ecp_randomize_mxz(const mbedtls_ecp_group * grp,mbedtls_ecp_point * P,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)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  */
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])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  */
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)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  */
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)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  */
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)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  */
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)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 }
2722b0563631STom 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  */
ecp_check_pubkey_sw(const mbedtls_ecp_group * grp,const mbedtls_ecp_point * pt)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 
2763b0563631STom 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  */
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)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  */
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)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  */
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)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 */
2915b0563631STom 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)
2919b0563631STom 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)   \
2921b0563631STom 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  */
ecp_check_bad_points_mx(const mbedtls_mpi * X,const mbedtls_mpi * P,const mbedtls_ecp_group_id grp_id)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  */
ecp_check_pubkey_mx(const mbedtls_ecp_group * grp,const mbedtls_ecp_point * pt)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  */
mbedtls_ecp_check_pubkey(const mbedtls_ecp_group * grp,const mbedtls_ecp_point * pt)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  */
mbedtls_ecp_check_privkey(const mbedtls_ecp_group * grp,const mbedtls_mpi * d)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 ||
3063*c3deb3d6SEtienne Carriere             mbedtls_mpi_bitlen(d) != grp->nbits + 1) {  /* 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
mbedtls_ecp_gen_privkey_mx(size_t high_bit,mbedtls_mpi * d,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)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)
mbedtls_ecp_gen_privkey_sw(const mbedtls_mpi * N,mbedtls_mpi * d,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)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  */
mbedtls_ecp_gen_privkey(const mbedtls_ecp_group * grp,mbedtls_mpi * d,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)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 
3161b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C)
31623d3b0591SJens Wiklander /*
31633d3b0591SJens Wiklander  * Generate a keypair with configurable base point
31643d3b0591SJens Wiklander  */
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)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  */
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)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  */
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)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 }
3203b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */
3204b0563631STom Van Eyck 
mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id,mbedtls_ecp_keypair * key,const mbedtls_ecp_point * Q)3205b0563631STom Van Eyck int mbedtls_ecp_set_public_key(mbedtls_ecp_group_id grp_id,
3206b0563631STom Van Eyck                                mbedtls_ecp_keypair *key,
3207b0563631STom Van Eyck                                const mbedtls_ecp_point *Q)
3208b0563631STom Van Eyck {
3209b0563631STom Van Eyck     int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
3210b0563631STom Van Eyck 
3211b0563631STom Van Eyck     if (key->grp.id == MBEDTLS_ECP_DP_NONE) {
3212b0563631STom Van Eyck         /* Group not set yet */
3213b0563631STom Van Eyck         if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0) {
3214b0563631STom Van Eyck             return ret;
3215b0563631STom Van Eyck         }
3216b0563631STom Van Eyck     } else if (key->grp.id != grp_id) {
3217b0563631STom Van Eyck         /* Group mismatch */
3218b0563631STom Van Eyck         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
3219b0563631STom Van Eyck     }
3220b0563631STom Van Eyck     return mbedtls_ecp_copy(&key->Q, Q);
3221b0563631STom Van Eyck }
3222b0563631STom 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  */
mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id,mbedtls_ecp_keypair * key,const unsigned char * buf,size_t buflen)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));
3290b0563631STom Van Eyck     }
3291b0563631STom Van Eyck #endif
329211fa71b9SJerome Forissier 
3293b0563631STom 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  */
3309b0563631STom Van Eyck #if !defined MBEDTLS_DEPRECATED_REMOVED
mbedtls_ecp_write_key(mbedtls_ecp_keypair * key,unsigned char * buf,size_t buflen)33107901324dSJerome Forissier int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
33117901324dSJerome Forissier                           unsigned char *buf, size_t buflen)
33127901324dSJerome Forissier {
3313b0563631STom 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 }
3340b0563631STom Van Eyck #endif /* MBEDTLS_DEPRECATED_REMOVED */
3341b0563631STom Van Eyck 
mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair * key,size_t * olen,unsigned char * buf,size_t buflen)3342b0563631STom Van Eyck int mbedtls_ecp_write_key_ext(const mbedtls_ecp_keypair *key,
3343b0563631STom Van Eyck                               size_t *olen, unsigned char *buf, size_t buflen)
3344b0563631STom Van Eyck {
3345b0563631STom Van Eyck     size_t len = (key->grp.nbits + 7) / 8;
3346b0563631STom Van Eyck     if (len > buflen) {
3347b0563631STom Van Eyck         /* For robustness, ensure *olen <= buflen even on error. */
3348b0563631STom Van Eyck         *olen = 0;
3349b0563631STom Van Eyck         return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
3350b0563631STom Van Eyck     }
3351b0563631STom Van Eyck     *olen = len;
3352b0563631STom Van Eyck 
3353b0563631STom Van Eyck     /* Private key not set */
3354b0563631STom Van Eyck     if (key->d.n == 0) {
3355b0563631STom Van Eyck         return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
3356b0563631STom Van Eyck     }
3357b0563631STom Van Eyck 
3358b0563631STom Van Eyck #if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
3359b0563631STom Van Eyck     if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
3360b0563631STom Van Eyck         return mbedtls_mpi_write_binary_le(&key->d, buf, len);
3361b0563631STom Van Eyck     }
3362b0563631STom Van Eyck #endif
3363b0563631STom Van Eyck 
3364b0563631STom Van Eyck #if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
3365b0563631STom Van Eyck     if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
3366b0563631STom Van Eyck         return mbedtls_mpi_write_binary(&key->d, buf, len);
3367b0563631STom Van Eyck     }
3368b0563631STom Van Eyck #endif
3369b0563631STom Van Eyck 
3370b0563631STom Van Eyck     /* Private key set but no recognized curve type? This shouldn't happen. */
3371b0563631STom Van Eyck     return MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
3372b0563631STom Van Eyck }
3373b0563631STom Van Eyck 
3374b0563631STom Van Eyck /*
3375b0563631STom Van Eyck  * Write a public key.
3376b0563631STom Van Eyck  */
mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair * key,int format,size_t * olen,unsigned char * buf,size_t buflen)3377b0563631STom Van Eyck int mbedtls_ecp_write_public_key(const mbedtls_ecp_keypair *key,
3378b0563631STom Van Eyck                                  int format, size_t *olen,
3379b0563631STom Van Eyck                                  unsigned char *buf, size_t buflen)
3380b0563631STom Van Eyck {
3381b0563631STom Van Eyck     return mbedtls_ecp_point_write_binary(&key->grp, &key->Q,
3382b0563631STom Van Eyck                                           format, olen, buf, buflen);
3383b0563631STom Van Eyck }
33847901324dSJerome Forissier 
33857901324dSJerome Forissier 
3386b0563631STom Van Eyck #if defined(MBEDTLS_ECP_C)
33877901324dSJerome Forissier /*
3388817466cbSJens Wiklander  * Check a public-private key pair
3389817466cbSJens Wiklander  */
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)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 
mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair * key,int (* f_rng)(void *,unsigned char *,size_t),void * p_rng)3428b0563631STom Van Eyck int mbedtls_ecp_keypair_calc_public(mbedtls_ecp_keypair *key,
3429b0563631STom Van Eyck                                     int (*f_rng)(void *, unsigned char *, size_t),
3430b0563631STom Van Eyck                                     void *p_rng)
3431b0563631STom Van Eyck {
3432b0563631STom Van Eyck     return mbedtls_ecp_mul(&key->grp, &key->Q, &key->d, &key->grp.G,
3433b0563631STom Van Eyck                            f_rng, p_rng);
3434b0563631STom Van Eyck }
3435b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */
3436b0563631STom Van Eyck 
mbedtls_ecp_keypair_get_group_id(const mbedtls_ecp_keypair * key)3437b0563631STom Van Eyck mbedtls_ecp_group_id mbedtls_ecp_keypair_get_group_id(
3438b0563631STom Van Eyck     const mbedtls_ecp_keypair *key)
3439b0563631STom Van Eyck {
3440b0563631STom Van Eyck     return key->grp.id;
3441b0563631STom Van Eyck }
3442b0563631STom Van Eyck 
344332b31808SJens Wiklander /*
344432b31808SJens Wiklander  * Export generic key-pair parameters.
344532b31808SJens Wiklander  */
mbedtls_ecp_export(const mbedtls_ecp_keypair * key,mbedtls_ecp_group * grp,mbedtls_mpi * d,mbedtls_ecp_point * Q)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 
3451b0563631STom Van Eyck     if (grp != NULL && (ret = mbedtls_ecp_group_copy(grp, &key->grp)) != 0) {
345232b31808SJens Wiklander         return ret;
345332b31808SJens Wiklander     }
345432b31808SJens Wiklander 
3455b0563631STom Van Eyck     if (d != NULL && (ret = mbedtls_mpi_copy(d, &key->d)) != 0) {
345632b31808SJens Wiklander         return ret;
345732b31808SJens Wiklander     }
345832b31808SJens Wiklander 
3459b0563631STom 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 
3468b0563631STom 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  */
self_test_rng(void * ctx,unsigned char * out,size_t len)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. */
self_test_adjust_exponent(const mbedtls_ecp_group * grp,mbedtls_mpi * m)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. */
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)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 }
3576b0563631STom Van Eyck #endif /* MBEDTLS_ECP_C */
35777901324dSJerome Forissier 
3578817466cbSJens Wiklander /*
3579817466cbSJens Wiklander  * Checkup routine
3580817466cbSJens Wiklander  */
mbedtls_ecp_self_test(int verbose)3581817466cbSJens Wiklander int mbedtls_ecp_self_test(int verbose)
3582817466cbSJens Wiklander {
3583b0563631STom 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;
3697b0563631STom Van Eyck #else /* MBEDTLS_ECP_C */
3698b0563631STom Van Eyck     (void) verbose;
3699b0563631STom Van Eyck     return 0;
3700b0563631STom 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 
3707b0563631STom Van Eyck #endif /* MBEDTLS_ECP_LIGHT */
3708