blob: 44e7ccacd4699d66805764008c4d0ba0a225a105 [file] [log] [blame]
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01001/*
Manuel Pégourié-Gonnard32b04c12013-12-02 15:49:09 +01002 * Elliptic curves over GF(p): generic functions
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01003 *
Bence Szépkúti1e148272020-08-07 13:07:28 +02004 * Copyright The Mbed TLS Contributors
Manuel Pégourié-Gonnard37ff1402015-09-04 14:21:07 +02005 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License"); you may
8 * not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010018 */
19
20/*
21 * References:
22 *
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010023 * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +010024 * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +010025 * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf
Manuel Pégourié-Gonnard1a967282013-02-09 17:03:58 +010026 * RFC 4492 for the related TLS structures and constants
Nicholas Wilson08f3ef12015-11-10 13:10:01 +000027 * RFC 7748 for the Curve448 and Curve25519 curve definitions
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +020028 *
Manuel Pégourié-Gonnard07894332015-06-23 00:18:41 +020029 * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf
Manuel Pégourié-Gonnardfe0af402013-12-04 18:14:55 +010030 *
Manuel Pégourié-Gonnard998930a2015-04-03 13:48:06 +020031 * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +020032 * for elliptic curve cryptosystems. In : Cryptographic Hardware and
33 * Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302.
34 * <http://link.springer.com/chapter/10.1007/3-540-48059-5_25>
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +010035 *
Manuel Pégourié-Gonnard998930a2015-04-03 13:48:06 +020036 * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +010037 * render ECC resistant against Side Channel Attacks. IACR Cryptology
38 * ePrint Archive, 2004, vol. 2004, p. 342.
39 * <http://eprint.iacr.org/2004/342.pdf>
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010040 */
41
Gilles Peskinedb09ef62020-06-03 01:43:33 +020042#include "common.h"
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010043
Andrzej Kurekc470b6b2019-01-31 08:20:20 -050044/**
45 * \brief Function level alternative implementation.
46 *
47 * The MBEDTLS_ECP_INTERNAL_ALT macro enables alternative implementations to
48 * replace certain functions in this module. The alternative implementations are
49 * typically hardware accelerators and need to activate the hardware before the
50 * computation starts and deactivate it after it finishes. The
51 * mbedtls_internal_ecp_init() and mbedtls_internal_ecp_free() functions serve
52 * this purpose.
53 *
54 * To preserve the correct functionality the following conditions must hold:
55 *
56 * - The alternative implementation must be activated by
57 * mbedtls_internal_ecp_init() before any of the replaceable functions is
58 * called.
59 * - mbedtls_internal_ecp_free() must \b only be called when the alternative
60 * implementation is activated.
61 * - mbedtls_internal_ecp_init() must \b not be called when the alternative
62 * implementation is activated.
63 * - Public functions must not return while the alternative implementation is
64 * activated.
65 * - Replaceable functions are guarded by \c MBEDTLS_ECP_XXX_ALT macros and
66 * before calling them an \code if( mbedtls_internal_ecp_grp_capable( grp ) )
67 * \endcode ensures that the alternative implementation supports the current
68 * group.
69 */
70#if defined(MBEDTLS_ECP_INTERNAL_ALT)
71#endif
72
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020073#if defined(MBEDTLS_ECP_C)
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010074
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020075# include "mbedtls/ecp.h"
76# include "mbedtls/threading.h"
77# include "mbedtls/platform_util.h"
78# include "mbedtls/error.h"
Paul Bakker6e339b52013-07-03 13:37:05 +020079
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020080# include "bn_mul.h"
81# include "ecp_invasive.h"
Gilles Peskine80ba8502021-04-03 20:36:37 +020082
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020083# include <string.h>
Rich Evans00ab4702015-02-06 13:43:58 +000084
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020085# if !defined(MBEDTLS_ECP_ALT)
Janos Follathb0697532016-08-18 12:38:46 +010086
Andrzej Kurekc470b6b2019-01-31 08:20:20 -050087/* Parameter validation macros based on platform_util.h */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020088# define ECP_VALIDATE_RET(cond) \
89 MBEDTLS_INTERNAL_VALIDATE_RET(cond, MBEDTLS_ERR_ECP_BAD_INPUT_DATA)
90# define ECP_VALIDATE(cond) MBEDTLS_INTERNAL_VALIDATE(cond)
Andrzej Kurekc470b6b2019-01-31 08:20:20 -050091
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +020092# if defined(MBEDTLS_PLATFORM_C)
93# include "mbedtls/platform.h"
94# else
95# include <stdlib.h>
96# include <stdio.h>
97# define mbedtls_printf printf
98# define mbedtls_calloc calloc
99# define mbedtls_free free
100# endif
Paul Bakker6e339b52013-07-03 13:37:05 +0200101
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200102# include "ecp_internal_alt.h"
Janos Follathb0697532016-08-18 12:38:46 +0100103
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200104# if (defined(__ARMCC_VERSION) || defined(_MSC_VER)) && \
105 !defined(inline) && !defined(__cplusplus)
106# define inline __inline
107# endif
Paul Bakker6a6087e2013-10-28 18:53:08 +0100108
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200109# if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +0100110/*
Manuel Pégourié-Gonnard91814812013-11-21 20:23:55 +0100111 * Counts of point addition and doubling, and field multiplications.
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +0200112 * Used to test resistance of point multiplication to simple timing attacks.
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +0100113 */
Manuel Pégourié-Gonnard43863ee2013-12-01 16:51:27 +0100114static unsigned long add_count, dbl_count, mul_count;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200115# endif
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +0100116
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200117# if defined(MBEDTLS_ECP_RESTARTABLE)
Manuel Pégourié-Gonnard054433c2017-03-22 11:18:33 +0100118/*
119 * Maximum number of "basic operations" to be done in a row.
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +0200120 *
121 * Default value 0 means that ECC operations will not yield.
122 * Note that regardless of the value of ecp_max_ops, always at
123 * least one step is performed before yielding.
124 *
125 * Setting ecp_max_ops=1 can be suitable for testing purposes
126 * as it will interrupt computation at all possible points.
Manuel Pégourié-Gonnard054433c2017-03-22 11:18:33 +0100127 */
128static unsigned ecp_max_ops = 0;
129
130/*
131 * Set ecp_max_ops
132 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200133void mbedtls_ecp_set_max_ops(unsigned max_ops)
Manuel Pégourié-Gonnard054433c2017-03-22 11:18:33 +0100134{
135 ecp_max_ops = max_ops;
136}
Manuel Pégourié-Gonnard510d5ca2017-03-08 11:41:47 +0100137
138/*
Manuel Pégourié-Gonnarda0c5bcc2017-04-21 11:33:57 +0200139 * Check if restart is enabled
140 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200141int mbedtls_ecp_restart_is_enabled(void)
Manuel Pégourié-Gonnarda0c5bcc2017-04-21 11:33:57 +0200142{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200143 return ecp_max_ops != 0;
Manuel Pégourié-Gonnarda0c5bcc2017-04-21 11:33:57 +0200144}
145
146/*
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200147 * Restart sub-context for ecp_mul_comb()
Manuel Pégourié-Gonnard510d5ca2017-03-08 11:41:47 +0100148 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200149struct mbedtls_ecp_restart_mul {
150 mbedtls_ecp_point R; /* current intermediate result */
151 size_t i; /* current index in various loops, 0 outside */
152 mbedtls_ecp_point *T; /* table for precomputed points */
153 unsigned char T_size; /* number of points in table T */
154 enum
155 { /* what were we doing last time we returned? */
156 ecp_rsm_init = 0, /* nothing so far, dummy initial state */
157 ecp_rsm_pre_dbl, /* precompute 2^n multiples */
158 ecp_rsm_pre_norm_dbl, /* normalize precomputed 2^n multiples */
159 ecp_rsm_pre_add, /* precompute remaining points by adding */
160 ecp_rsm_pre_norm_add, /* normalize all precomputed points */
161 ecp_rsm_comb_core, /* ecp_mul_comb_core() */
162 ecp_rsm_final_norm, /* do the final normalization */
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100163 } state;
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +0100164};
Manuel Pégourié-Gonnard510d5ca2017-03-08 11:41:47 +0100165
166/*
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200167 * Init restart_mul sub-context
Manuel Pégourié-Gonnard510d5ca2017-03-08 11:41:47 +0100168 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200169static void ecp_restart_rsm_init(mbedtls_ecp_restart_mul_ctx *ctx)
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +0100170{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200171 mbedtls_ecp_point_init(&ctx->R);
Manuel Pégourié-Gonnard5bd38b12017-08-23 16:55:59 +0200172 ctx->i = 0;
173 ctx->T = NULL;
174 ctx->T_size = 0;
175 ctx->state = ecp_rsm_init;
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +0100176}
177
178/*
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200179 * Free the components of a restart_mul sub-context
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +0100180 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200181static void ecp_restart_rsm_free(mbedtls_ecp_restart_mul_ctx *ctx)
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +0100182{
Manuel Pégourié-Gonnardc9c0aa62017-03-16 14:53:26 +0100183 unsigned char i;
184
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200185 if (ctx == NULL)
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +0100186 return;
Manuel Pégourié-Gonnard78d564a2017-03-14 11:48:38 +0100187
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200188 mbedtls_ecp_point_free(&ctx->R);
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100189
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200190 if (ctx->T != NULL) {
191 for (i = 0; i < ctx->T_size; i++)
192 mbedtls_ecp_point_free(ctx->T + i);
193 mbedtls_free(ctx->T);
Manuel Pégourié-Gonnardc9c0aa62017-03-16 14:53:26 +0100194 }
195
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200196 ecp_restart_rsm_init(ctx);
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +0100197}
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100198
199/*
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200200 * Restart context for ecp_muladd()
201 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200202struct mbedtls_ecp_restart_muladd {
203 mbedtls_ecp_point mP; /* mP value */
204 mbedtls_ecp_point R; /* R intermediate result */
205 enum
206 { /* what should we do next? */
207 ecp_rsma_mul1 = 0, /* first multiplication */
208 ecp_rsma_mul2, /* second multiplication */
209 ecp_rsma_add, /* addition */
210 ecp_rsma_norm, /* normalization */
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +0200211 } state;
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200212};
213
214/*
215 * Init restart_muladd sub-context
216 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200217static void ecp_restart_ma_init(mbedtls_ecp_restart_muladd_ctx *ctx)
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200218{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200219 mbedtls_ecp_point_init(&ctx->mP);
220 mbedtls_ecp_point_init(&ctx->R);
Manuel Pégourié-Gonnard5bd38b12017-08-23 16:55:59 +0200221 ctx->state = ecp_rsma_mul1;
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200222}
223
224/*
225 * Free the components of a restart_muladd sub-context
226 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200227static void ecp_restart_ma_free(mbedtls_ecp_restart_muladd_ctx *ctx)
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200228{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200229 if (ctx == NULL)
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200230 return;
231
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200232 mbedtls_ecp_point_free(&ctx->mP);
233 mbedtls_ecp_point_free(&ctx->R);
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +0200234
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200235 ecp_restart_ma_init(ctx);
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +0200236}
237
238/*
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +0200239 * Initialize a restart context
240 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200241void mbedtls_ecp_restart_init(mbedtls_ecp_restart_ctx *ctx)
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +0200242{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200243 ECP_VALIDATE(ctx != NULL);
Manuel Pégourié-Gonnard5bd38b12017-08-23 16:55:59 +0200244 ctx->ops_done = 0;
245 ctx->depth = 0;
246 ctx->rsm = NULL;
247 ctx->ma = NULL;
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +0200248}
249
250/*
251 * Free the components of a restart context
252 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200253void mbedtls_ecp_restart_free(mbedtls_ecp_restart_ctx *ctx)
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +0200254{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200255 if (ctx == NULL)
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +0200256 return;
257
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200258 ecp_restart_rsm_free(ctx->rsm);
259 mbedtls_free(ctx->rsm);
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +0200260
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200261 ecp_restart_ma_free(ctx->ma);
262 mbedtls_free(ctx->ma);
Manuel Pégourié-Gonnard5bd38b12017-08-23 16:55:59 +0200263
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200264 mbedtls_ecp_restart_init(ctx);
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +0200265}
266
267/*
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100268 * Check if we can do the next step
269 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200270int mbedtls_ecp_check_budget(const mbedtls_ecp_group *grp,
271 mbedtls_ecp_restart_ctx *rs_ctx,
272 unsigned ops)
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100273{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200274 ECP_VALIDATE_RET(grp != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500275
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200276 if (rs_ctx != NULL && ecp_max_ops != 0) {
Manuel Pégourié-Gonnarde6854492017-03-20 14:35:19 +0100277 /* scale depending on curve size: the chosen reference is 256-bit,
278 * and multiplication is quadratic. Round to the closest integer. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200279 if (grp->pbits >= 512)
Manuel Pégourié-Gonnarde6854492017-03-20 14:35:19 +0100280 ops *= 4;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200281 else if (grp->pbits >= 384)
Manuel Pégourié-Gonnarde6854492017-03-20 14:35:19 +0100282 ops *= 2;
283
Hanno Beckerb10c6602018-10-26 13:50:13 +0100284 /* Avoid infinite loops: always allow first step.
285 * Because of that, however, it's not generally true
286 * that ops_done <= ecp_max_ops, so the check
287 * ops_done > ecp_max_ops below is mandatory. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200288 if ((rs_ctx->ops_done != 0) && (rs_ctx->ops_done > ecp_max_ops ||
289 ops > ecp_max_ops - rs_ctx->ops_done)) {
290 return MBEDTLS_ERR_ECP_IN_PROGRESS;
Hanno Beckerb10c6602018-10-26 13:50:13 +0100291 }
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100292
Manuel Pégourié-Gonnarde6854492017-03-20 14:35:19 +0100293 /* update running count */
Manuel Pégourié-Gonnard646393b2017-04-20 10:03:45 +0200294 rs_ctx->ops_done += ops;
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100295 }
296
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200297 return 0;
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +0100298}
299
Manuel Pégourié-Gonnarddb4a8eb2017-08-23 18:18:22 +0200300/* Call this when entering a function that needs its own sub-context */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200301# define ECP_RS_ENTER(SUB) \
302 do { \
303 /* reset ops count for this call if top-level */ \
304 if (rs_ctx != NULL && rs_ctx->depth++ == 0) \
305 rs_ctx->ops_done = 0; \
306 \
307 /* set up our own sub-context if needed */ \
308 if (mbedtls_ecp_restart_is_enabled() && rs_ctx != NULL && \
309 rs_ctx->SUB == NULL) { \
310 rs_ctx->SUB = mbedtls_calloc(1, sizeof(*rs_ctx->SUB)); \
311 if (rs_ctx->SUB == NULL) \
312 return MBEDTLS_ERR_ECP_ALLOC_FAILED; \
313 \
314 ecp_restart_##SUB##_init(rs_ctx->SUB); \
315 } \
316 } while (0)
Manuel Pégourié-Gonnarddb4a8eb2017-08-23 18:18:22 +0200317
318/* Call this when leaving a function that needs its own sub-context */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200319# define ECP_RS_LEAVE(SUB) \
320 do { \
321 /* clear our sub-context when not in progress (done or \
322 * error) */ \
323 if (rs_ctx != NULL && rs_ctx->SUB != NULL && \
324 ret != MBEDTLS_ERR_ECP_IN_PROGRESS) { \
325 ecp_restart_##SUB##_free(rs_ctx->SUB); \
326 mbedtls_free(rs_ctx->SUB); \
327 rs_ctx->SUB = NULL; \
328 } \
329 \
330 if (rs_ctx != NULL) \
331 rs_ctx->depth--; \
332 } while (0)
Manuel Pégourié-Gonnarddb4a8eb2017-08-23 18:18:22 +0200333
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200334# else /* MBEDTLS_ECP_RESTARTABLE */
Manuel Pégourié-Gonnarddb4a8eb2017-08-23 18:18:22 +0200335
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200336# define ECP_RS_ENTER(sub) (void)rs_ctx;
337# define ECP_RS_LEAVE(sub) (void)rs_ctx;
Manuel Pégourié-Gonnarddb4a8eb2017-08-23 18:18:22 +0200338
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200339# endif /* MBEDTLS_ECP_RESTARTABLE */
Manuel Pégourié-Gonnard054433c2017-03-22 11:18:33 +0100340
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +0100341/*
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +0200342 * List of supported curves:
343 * - internal ID
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200344 * - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2, RFC 8446
345 * sec. 4.2.7)
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +0200346 * - size in bits
Manuel Pégourié-Gonnard8195c1a2013-10-07 19:40:41 +0200347 * - readable name
Gergely Budaie40c4692014-01-22 11:22:20 +0100348 *
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100349 * Curves are listed in order: largest curves first, and for a given size,
Gilles Peskineae270bf2021-06-02 00:05:29 +0200350 * fastest curves first.
Manuel Pégourié-Gonnard88db5da2015-06-15 14:34:59 +0200351 *
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200352 * Reminder: update profiles in x509_crt.c and ssl_tls.c when adding a new
353 * curve!
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +0200354 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200355static const mbedtls_ecp_curve_info ecp_supported_curves[] = {
356# if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
357 { MBEDTLS_ECP_DP_SECP521R1, 25, 521, "secp521r1" },
358# endif
359# if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)
360 { MBEDTLS_ECP_DP_BP512R1, 28, 512, "brainpoolP512r1" },
361# endif
362# if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
363 { MBEDTLS_ECP_DP_SECP384R1, 24, 384, "secp384r1" },
364# endif
365# if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)
366 { MBEDTLS_ECP_DP_BP384R1, 27, 384, "brainpoolP384r1" },
367# endif
368# if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
369 { MBEDTLS_ECP_DP_SECP256R1, 23, 256, "secp256r1" },
370# endif
371# if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
372 { MBEDTLS_ECP_DP_SECP256K1, 22, 256, "secp256k1" },
373# endif
374# if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)
375 { MBEDTLS_ECP_DP_BP256R1, 26, 256, "brainpoolP256r1" },
376# endif
377# if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
378 { MBEDTLS_ECP_DP_SECP224R1, 21, 224, "secp224r1" },
379# endif
380# if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED)
381 { MBEDTLS_ECP_DP_SECP224K1, 20, 224, "secp224k1" },
382# endif
383# if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
384 { MBEDTLS_ECP_DP_SECP192R1, 19, 192, "secp192r1" },
385# endif
386# if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
387 { MBEDTLS_ECP_DP_SECP192K1, 18, 192, "secp192k1" },
388# endif
389# if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
390 { MBEDTLS_ECP_DP_CURVE25519, 29, 256, "x25519" },
391# endif
392# if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
393 { MBEDTLS_ECP_DP_CURVE448, 30, 448, "x448" },
394# endif
395 { MBEDTLS_ECP_DP_NONE, 0, 0, NULL },
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +0200396};
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100397
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200398# define ECP_NB_CURVES \
399 sizeof(ecp_supported_curves) / sizeof(ecp_supported_curves[0])
Manuel Pégourié-Gonnardba782bb2014-07-08 13:31:34 +0200400
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200401static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES];
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +0200402
403/*
Manuel Pégourié-Gonnardda179e42013-09-18 15:31:24 +0200404 * List of supported curves and associated info
405 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200406const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list(void)
Manuel Pégourié-Gonnardda179e42013-09-18 15:31:24 +0200407{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200408 return ecp_supported_curves;
Manuel Pégourié-Gonnardda179e42013-09-18 15:31:24 +0200409}
410
411/*
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100412 * List of supported curves, group ID only
413 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200414const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list(void)
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100415{
416 static int init_done = 0;
417
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200418 if (!init_done) {
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100419 size_t i = 0;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200420 const mbedtls_ecp_curve_info *curve_info;
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100421
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200422 for (curve_info = mbedtls_ecp_curve_list();
423 curve_info->grp_id != MBEDTLS_ECP_DP_NONE; curve_info++) {
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100424 ecp_supported_grp_id[i++] = curve_info->grp_id;
425 }
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200426 ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE;
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100427
428 init_done = 1;
429 }
430
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200431 return ecp_supported_grp_id;
Manuel Pégourié-Gonnardac719412014-02-04 14:48:50 +0100432}
433
434/*
435 * Get the curve info for the internal identifier
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200436 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200437const mbedtls_ecp_curve_info *
438mbedtls_ecp_curve_info_from_grp_id(mbedtls_ecp_group_id grp_id)
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200439{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200440 const mbedtls_ecp_curve_info *curve_info;
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200441
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200442 for (curve_info = mbedtls_ecp_curve_list();
443 curve_info->grp_id != MBEDTLS_ECP_DP_NONE; curve_info++) {
444 if (curve_info->grp_id == grp_id)
445 return curve_info;
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200446 }
447
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200448 return NULL;
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200449}
450
451/*
452 * Get the curve info from the TLS identifier
453 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200454const mbedtls_ecp_curve_info *
455mbedtls_ecp_curve_info_from_tls_id(uint16_t tls_id)
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200456{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200457 const mbedtls_ecp_curve_info *curve_info;
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200458
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200459 for (curve_info = mbedtls_ecp_curve_list();
460 curve_info->grp_id != MBEDTLS_ECP_DP_NONE; curve_info++) {
461 if (curve_info->tls_id == tls_id)
462 return curve_info;
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200463 }
464
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200465 return NULL;
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200466}
467
468/*
Manuel Pégourié-Gonnard0267e3d2013-11-30 15:10:14 +0100469 * Get the curve info from the name
470 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200471const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name(const char *name)
Manuel Pégourié-Gonnard0267e3d2013-11-30 15:10:14 +0100472{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200473 const mbedtls_ecp_curve_info *curve_info;
Manuel Pégourié-Gonnard0267e3d2013-11-30 15:10:14 +0100474
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200475 if (name == NULL)
476 return NULL;
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500477
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200478 for (curve_info = mbedtls_ecp_curve_list();
479 curve_info->grp_id != MBEDTLS_ECP_DP_NONE; curve_info++) {
480 if (strcmp(curve_info->name, name) == 0)
481 return curve_info;
Manuel Pégourié-Gonnard0267e3d2013-11-30 15:10:14 +0100482 }
483
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200484 return NULL;
Manuel Pégourié-Gonnard0267e3d2013-11-30 15:10:14 +0100485}
486
487/*
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +0100488 * Get the type of a curve
Manuel Pégourié-Gonnard312d2e82013-12-04 11:08:01 +0100489 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200490mbedtls_ecp_curve_type mbedtls_ecp_get_type(const mbedtls_ecp_group *grp)
Manuel Pégourié-Gonnard312d2e82013-12-04 11:08:01 +0100491{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200492 if (grp->G.X.p == NULL)
493 return MBEDTLS_ECP_TYPE_NONE;
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +0100494
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200495 if (grp->G.Y.p == NULL)
496 return MBEDTLS_ECP_TYPE_MONTGOMERY;
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +0100497 else
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200498 return MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS;
Manuel Pégourié-Gonnard312d2e82013-12-04 11:08:01 +0100499}
500
501/*
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100502 * Initialize (the components of) a point
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100503 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200504void mbedtls_ecp_point_init(mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100505{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200506 ECP_VALIDATE(pt != NULL);
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100507
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200508 mbedtls_mpi_init(&pt->X);
509 mbedtls_mpi_init(&pt->Y);
510 mbedtls_mpi_init(&pt->Z);
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100511}
512
513/*
514 * Initialize (the components of) a group
515 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200516void mbedtls_ecp_group_init(mbedtls_ecp_group *grp)
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100517{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200518 ECP_VALIDATE(grp != NULL);
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100519
Manuel Pégourié-Gonnard95e2eca2018-06-20 10:29:47 +0200520 grp->id = MBEDTLS_ECP_DP_NONE;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200521 mbedtls_mpi_init(&grp->P);
522 mbedtls_mpi_init(&grp->A);
523 mbedtls_mpi_init(&grp->B);
524 mbedtls_ecp_point_init(&grp->G);
525 mbedtls_mpi_init(&grp->N);
Manuel Pégourié-Gonnard5bd38b12017-08-23 16:55:59 +0200526 grp->pbits = 0;
527 grp->nbits = 0;
528 grp->h = 0;
529 grp->modp = NULL;
530 grp->t_pre = NULL;
531 grp->t_post = NULL;
532 grp->t_data = NULL;
533 grp->T = NULL;
534 grp->T_size = 0;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100535}
536
537/*
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200538 * Initialize (the components of) a key pair
539 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200540void mbedtls_ecp_keypair_init(mbedtls_ecp_keypair *key)
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200541{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200542 ECP_VALIDATE(key != NULL);
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200543
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200544 mbedtls_ecp_group_init(&key->grp);
545 mbedtls_mpi_init(&key->d);
546 mbedtls_ecp_point_init(&key->Q);
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200547}
548
549/*
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100550 * Unallocate (the components of) a point
551 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200552void mbedtls_ecp_point_free(mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100553{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200554 if (pt == NULL)
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100555 return;
556
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200557 mbedtls_mpi_free(&(pt->X));
558 mbedtls_mpi_free(&(pt->Y));
559 mbedtls_mpi_free(&(pt->Z));
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100560}
561
562/*
kXuanba9cb762021-04-08 14:32:06 +0800563 * Check that the comb table (grp->T) is static initialized.
564 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200565static int ecp_group_is_static_comb_table(const mbedtls_ecp_group *grp)
566{
567# if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
kXuanba9cb762021-04-08 14:32:06 +0800568 return grp->T != NULL && grp->T_size == 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200569# else
570 (void)grp;
kXuanba9cb762021-04-08 14:32:06 +0800571 return 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200572# endif
kXuanba9cb762021-04-08 14:32:06 +0800573}
574
575/*
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100576 * Unallocate (the components of) a group
577 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200578void mbedtls_ecp_group_free(mbedtls_ecp_group *grp)
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100579{
Manuel Pégourié-Gonnard161ef962013-09-17 19:13:10 +0200580 size_t i;
581
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200582 if (grp == NULL)
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100583 return;
584
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200585 if (grp->h != 1) {
586 mbedtls_mpi_free(&grp->P);
587 mbedtls_mpi_free(&grp->A);
588 mbedtls_mpi_free(&grp->B);
589 mbedtls_ecp_point_free(&grp->G);
590 mbedtls_mpi_free(&grp->N);
Manuel Pégourié-Gonnard1f82b042013-12-06 12:51:50 +0100591 }
Manuel Pégourié-Gonnardc9727702013-09-16 18:56:28 +0200592
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200593 if (!ecp_group_is_static_comb_table(grp) && grp->T != NULL) {
594 for (i = 0; i < grp->T_size; i++)
595 mbedtls_ecp_point_free(&grp->T[i]);
596 mbedtls_free(grp->T);
Manuel Pégourié-Gonnard161ef962013-09-17 19:13:10 +0200597 }
598
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200599 mbedtls_platform_zeroize(grp, sizeof(mbedtls_ecp_group));
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +0100600}
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100601
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100602/*
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200603 * Unallocate (the components of) a key pair
604 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200605void mbedtls_ecp_keypair_free(mbedtls_ecp_keypair *key)
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200606{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200607 if (key == NULL)
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200608 return;
609
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200610 mbedtls_ecp_group_free(&key->grp);
611 mbedtls_mpi_free(&key->d);
612 mbedtls_ecp_point_free(&key->Q);
Manuel Pégourié-Gonnardb8c6e0e2013-07-01 13:40:52 +0200613}
614
615/*
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200616 * Copy the contents of a point
617 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200618int mbedtls_ecp_copy(mbedtls_ecp_point *P, const mbedtls_ecp_point *Q)
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200619{
Janos Follath24eed8d2019-11-22 13:21:35 +0000620 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200621 ECP_VALIDATE_RET(P != NULL);
622 ECP_VALIDATE_RET(Q != NULL);
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200623
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200624 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->X, &Q->X));
625 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Y, &Q->Y));
626 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&P->Z, &Q->Z));
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200627
628cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200629 return ret;
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200630}
631
632/*
633 * Copy the contents of a group object
634 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200635int mbedtls_ecp_group_copy(mbedtls_ecp_group *dst, const mbedtls_ecp_group *src)
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200636{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200637 ECP_VALIDATE_RET(dst != NULL);
638 ECP_VALIDATE_RET(src != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500639
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200640 return mbedtls_ecp_group_load(dst, src->id);
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +0200641}
642
643/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100644 * Set point to zero
645 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200646int mbedtls_ecp_set_zero(mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100647{
Janos Follath24eed8d2019-11-22 13:21:35 +0000648 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200649 ECP_VALIDATE_RET(pt != NULL);
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100650
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200651 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->X, 1));
652 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Y, 1));
653 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 0));
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100654
655cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200656 return ret;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100657}
658
659/*
Manuel Pégourié-Gonnard6545ca72013-01-26 16:05:22 +0100660 * Tell if a point is zero
661 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200662int mbedtls_ecp_is_zero(mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnard6545ca72013-01-26 16:05:22 +0100663{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200664 ECP_VALIDATE_RET(pt != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500665
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200666 return mbedtls_mpi_cmp_int(&pt->Z, 0) == 0;
Manuel Pégourié-Gonnard6545ca72013-01-26 16:05:22 +0100667}
668
669/*
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500670 * Compare two points lazily
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200671 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200672int mbedtls_ecp_point_cmp(const mbedtls_ecp_point *P,
673 const mbedtls_ecp_point *Q)
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200674{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200675 ECP_VALIDATE_RET(P != NULL);
676 ECP_VALIDATE_RET(Q != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500677
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200678 if (mbedtls_mpi_cmp_mpi(&P->X, &Q->X) == 0 &&
679 mbedtls_mpi_cmp_mpi(&P->Y, &Q->Y) == 0 &&
680 mbedtls_mpi_cmp_mpi(&P->Z, &Q->Z) == 0) {
681 return 0;
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200682 }
683
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200684 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard6029a852015-08-11 15:44:41 +0200685}
686
687/*
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100688 * Import a non-zero point from ASCII strings
689 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200690int mbedtls_ecp_point_read_string(mbedtls_ecp_point *P,
691 int radix,
692 const char *x,
693 const char *y)
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100694{
Janos Follath24eed8d2019-11-22 13:21:35 +0000695 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200696 ECP_VALIDATE_RET(P != NULL);
697 ECP_VALIDATE_RET(x != NULL);
698 ECP_VALIDATE_RET(y != NULL);
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100699
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200700 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->X, radix, x));
701 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(&P->Y, radix, y));
702 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->Z, 1));
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100703
704cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200705 return ret;
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100706}
707
708/*
Janos Follath7caf8e42019-02-20 12:00:22 +0000709 * Export a point into unsigned binary data (SEC1 2.3.3 and RFC7748)
Manuel Pégourié-Gonnarde19feb52012-11-24 14:10:14 +0100710 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200711int mbedtls_ecp_point_write_binary(const mbedtls_ecp_group *grp,
712 const mbedtls_ecp_point *P,
713 int format,
714 size_t *olen,
715 unsigned char *buf,
716 size_t buflen)
Manuel Pégourié-Gonnarde19feb52012-11-24 14:10:14 +0100717{
Janos Follath28eb06d2019-02-26 10:53:34 +0000718 int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
Manuel Pégourié-Gonnarde19feb52012-11-24 14:10:14 +0100719 size_t plen;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200720 ECP_VALIDATE_RET(grp != NULL);
721 ECP_VALIDATE_RET(P != NULL);
722 ECP_VALIDATE_RET(olen != NULL);
723 ECP_VALIDATE_RET(buf != NULL);
724 ECP_VALIDATE_RET(format == MBEDTLS_ECP_PF_UNCOMPRESSED ||
725 format == MBEDTLS_ECP_PF_COMPRESSED);
Manuel Pégourié-Gonnard37d218a2012-11-24 15:19:55 +0100726
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200727 plen = mbedtls_mpi_size(&grp->P);
Manuel Pégourié-Gonnarde19feb52012-11-24 14:10:14 +0100728
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200729# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
730 (void)format; /* Montgomery curves always use the same point format */
731 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
Janos Follath7caf8e42019-02-20 12:00:22 +0000732 *olen = plen;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200733 if (buflen < *olen)
734 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
Manuel Pégourié-Gonnard37d218a2012-11-24 15:19:55 +0100735
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200736 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&P->X, buf, plen));
Manuel Pégourié-Gonnard37d218a2012-11-24 15:19:55 +0100737 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200738# endif
739# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
740 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
Janos Follath7caf8e42019-02-20 12:00:22 +0000741 /*
742 * Common case: P == 0
743 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200744 if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0) {
745 if (buflen < 1)
746 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
Manuel Pégourié-Gonnard37d218a2012-11-24 15:19:55 +0100747
Janos Follath7caf8e42019-02-20 12:00:22 +0000748 buf[0] = 0x00;
749 *olen = 1;
Manuel Pégourié-Gonnard37d218a2012-11-24 15:19:55 +0100750
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200751 return 0;
Janos Follath7caf8e42019-02-20 12:00:22 +0000752 }
753
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200754 if (format == MBEDTLS_ECP_PF_UNCOMPRESSED) {
Janos Follath7caf8e42019-02-20 12:00:22 +0000755 *olen = 2 * plen + 1;
756
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200757 if (buflen < *olen)
758 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
Janos Follath7caf8e42019-02-20 12:00:22 +0000759
760 buf[0] = 0x04;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200761 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen));
762 MBEDTLS_MPI_CHK(
763 mbedtls_mpi_write_binary(&P->Y, buf + 1 + plen, plen));
764 } else if (format == MBEDTLS_ECP_PF_COMPRESSED) {
Janos Follath7caf8e42019-02-20 12:00:22 +0000765 *olen = plen + 1;
766
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200767 if (buflen < *olen)
768 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
Janos Follath7caf8e42019-02-20 12:00:22 +0000769
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200770 buf[0] = 0x02 + mbedtls_mpi_get_bit(&P->Y, 0);
771 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&P->X, buf + 1, plen));
Janos Follath7caf8e42019-02-20 12:00:22 +0000772 }
Manuel Pégourié-Gonnard37d218a2012-11-24 15:19:55 +0100773 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200774# endif
Manuel Pégourié-Gonnarde19feb52012-11-24 14:10:14 +0100775
776cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200777 return ret;
Manuel Pégourié-Gonnarde19feb52012-11-24 14:10:14 +0100778}
779
780/*
Janos Follath59b813c2019-02-13 10:44:06 +0000781 * Import a point from unsigned binary data (SEC1 2.3.4 and RFC7748)
Manuel Pégourié-Gonnard5e402d82012-11-24 16:19:42 +0100782 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200783int mbedtls_ecp_point_read_binary(const mbedtls_ecp_group *grp,
784 mbedtls_ecp_point *pt,
785 const unsigned char *buf,
786 size_t ilen)
Manuel Pégourié-Gonnard5246ee52014-03-19 16:18:38 +0100787{
Janos Follath28eb06d2019-02-26 10:53:34 +0000788 int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
Manuel Pégourié-Gonnard5e402d82012-11-24 16:19:42 +0100789 size_t plen;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200790 ECP_VALIDATE_RET(grp != NULL);
791 ECP_VALIDATE_RET(pt != NULL);
792 ECP_VALIDATE_RET(buf != NULL);
Manuel Pégourié-Gonnard5e402d82012-11-24 16:19:42 +0100793
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200794 if (ilen < 1)
795 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard67dbe1e2014-07-08 13:09:24 +0200796
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200797 plen = mbedtls_mpi_size(&grp->P);
Manuel Pégourié-Gonnard5e402d82012-11-24 16:19:42 +0100798
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200799# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
800 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
801 if (plen != ilen)
802 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard5246ee52014-03-19 16:18:38 +0100803
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200804 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&pt->X, buf, plen));
805 mbedtls_mpi_free(&pt->Y);
Manuel Pégourié-Gonnard5e402d82012-11-24 16:19:42 +0100806
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200807 if (grp->id == MBEDTLS_ECP_DP_CURVE25519)
Janos Follathffbd7e82019-02-25 11:35:20 +0000808 /* Set most significant bit to 0 as prescribed in RFC7748 §5 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200809 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&pt->X, plen * 8 - 1, 0));
Janos Follath28eb06d2019-02-26 10:53:34 +0000810
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200811 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1));
Janos Follath59b813c2019-02-13 10:44:06 +0000812 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200813# endif
814# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
815 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
816 if (buf[0] == 0x00) {
817 if (ilen == 1)
818 return mbedtls_ecp_set_zero(pt);
Janos Follath59b813c2019-02-13 10:44:06 +0000819 else
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200820 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Janos Follath59b813c2019-02-13 10:44:06 +0000821 }
822
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200823 if (buf[0] != 0x04)
824 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
Janos Follath59b813c2019-02-13 10:44:06 +0000825
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200826 if (ilen != 2 * plen + 1)
827 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Janos Follath59b813c2019-02-13 10:44:06 +0000828
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200829 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, buf + 1, plen));
830 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->Y, buf + 1 + plen, plen));
831 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1));
Janos Follath59b813c2019-02-13 10:44:06 +0000832 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200833# endif
Manuel Pégourié-Gonnard5e402d82012-11-24 16:19:42 +0100834
835cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200836 return ret;
Manuel Pégourié-Gonnard5e402d82012-11-24 16:19:42 +0100837}
838
839/*
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100840 * Import a point from a TLS ECPoint record (RFC 4492)
841 * struct {
842 * opaque point <1..2^8-1>;
843 * } ECPoint;
844 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200845int mbedtls_ecp_tls_read_point(const mbedtls_ecp_group *grp,
846 mbedtls_ecp_point *pt,
847 const unsigned char **buf,
848 size_t buf_len)
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100849{
850 unsigned char data_len;
Manuel Pégourié-Gonnard98f51812013-02-10 13:38:29 +0100851 const unsigned char *buf_start;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200852 ECP_VALIDATE_RET(grp != NULL);
853 ECP_VALIDATE_RET(pt != NULL);
854 ECP_VALIDATE_RET(buf != NULL);
855 ECP_VALIDATE_RET(*buf != NULL);
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100856
857 /*
Manuel Pégourié-Gonnard67dbe1e2014-07-08 13:09:24 +0200858 * We must have at least two bytes (1 for length, at least one for data)
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100859 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200860 if (buf_len < 2)
861 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100862
Manuel Pégourié-Gonnard98f51812013-02-10 13:38:29 +0100863 data_len = *(*buf)++;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200864 if (data_len < 1 || data_len > buf_len - 1)
865 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100866
Manuel Pégourié-Gonnard98f51812013-02-10 13:38:29 +0100867 /*
868 * Save buffer start for read_binary and update buf
869 */
870 buf_start = *buf;
871 *buf += data_len;
872
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200873 return mbedtls_ecp_point_read_binary(grp, pt, buf_start, data_len);
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100874}
875
876/*
877 * Export a point as a TLS ECPoint record (RFC 4492)
878 * struct {
879 * opaque point <1..2^8-1>;
880 * } ECPoint;
881 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200882int mbedtls_ecp_tls_write_point(const mbedtls_ecp_group *grp,
883 const mbedtls_ecp_point *pt,
884 int format,
885 size_t *olen,
886 unsigned char *buf,
887 size_t blen)
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100888{
Janos Follath24eed8d2019-11-22 13:21:35 +0000889 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200890 ECP_VALIDATE_RET(grp != NULL);
891 ECP_VALIDATE_RET(pt != NULL);
892 ECP_VALIDATE_RET(olen != NULL);
893 ECP_VALIDATE_RET(buf != NULL);
894 ECP_VALIDATE_RET(format == MBEDTLS_ECP_PF_UNCOMPRESSED ||
895 format == MBEDTLS_ECP_PF_COMPRESSED);
Manuel Pégourié-Gonnard420f1eb2013-02-10 12:22:46 +0100896
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100897 /*
Manuel Pégourié-Gonnard420f1eb2013-02-10 12:22:46 +0100898 * buffer length must be at least one, for our length byte
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100899 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200900 if (blen < 1)
901 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100902
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200903 if ((ret = mbedtls_ecp_point_write_binary(grp, pt, format, olen, buf + 1,
904 blen - 1)) != 0)
905 return ret;
Manuel Pégourié-Gonnard420f1eb2013-02-10 12:22:46 +0100906
907 /*
908 * write length to the first byte and update total length
909 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200910 buf[0] = (unsigned char)*olen;
Manuel Pégourié-Gonnard420f1eb2013-02-10 12:22:46 +0100911 ++*olen;
912
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200913 return 0;
Manuel Pégourié-Gonnard00794052013-02-09 19:00:07 +0100914}
915
916/*
Manuel Pégourié-Gonnard1a967282013-02-09 17:03:58 +0100917 * Set a group from an ECParameters record (RFC 4492)
918 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200919int mbedtls_ecp_tls_read_group(mbedtls_ecp_group *grp,
920 const unsigned char **buf,
921 size_t len)
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500922{
Janos Follath24eed8d2019-11-22 13:21:35 +0000923 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500924 mbedtls_ecp_group_id grp_id;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200925 ECP_VALIDATE_RET(grp != NULL);
926 ECP_VALIDATE_RET(buf != NULL);
927 ECP_VALIDATE_RET(*buf != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500928
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200929 if ((ret = mbedtls_ecp_tls_read_group_id(&grp_id, buf, len)) != 0)
930 return ret;
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500931
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200932 return mbedtls_ecp_group_load(grp, grp_id);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500933}
934
935/*
936 * Read a group id from an ECParameters record (RFC 4492) and convert it to
937 * mbedtls_ecp_group_id.
938 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200939int mbedtls_ecp_tls_read_group_id(mbedtls_ecp_group_id *grp,
940 const unsigned char **buf,
941 size_t len)
Manuel Pégourié-Gonnard1a967282013-02-09 17:03:58 +0100942{
Manuel Pégourié-Gonnardf24b4a72013-09-23 18:14:50 +0200943 uint16_t tls_id;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200944 const mbedtls_ecp_curve_info *curve_info;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200945 ECP_VALIDATE_RET(grp != NULL);
946 ECP_VALIDATE_RET(buf != NULL);
947 ECP_VALIDATE_RET(*buf != NULL);
Manuel Pégourié-Gonnard1a967282013-02-09 17:03:58 +0100948
949 /*
950 * We expect at least three bytes (see below)
951 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200952 if (len < 3)
953 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard1a967282013-02-09 17:03:58 +0100954
955 /*
956 * First byte is curve_type; only named_curve is handled
957 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200958 if (*(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE)
959 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard1a967282013-02-09 17:03:58 +0100960
961 /*
Manuel Pégourié-Gonnardb3258872013-02-10 12:06:19 +0100962 * Next two bytes are the namedcurve value
Manuel Pégourié-Gonnard1a967282013-02-09 17:03:58 +0100963 */
Manuel Pégourié-Gonnardf24b4a72013-09-23 18:14:50 +0200964 tls_id = *(*buf)++;
965 tls_id <<= 8;
966 tls_id |= *(*buf)++;
967
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200968 if ((curve_info = mbedtls_ecp_curve_info_from_tls_id(tls_id)) == NULL)
969 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
Manuel Pégourié-Gonnardf24b4a72013-09-23 18:14:50 +0200970
Andrzej Kurekc470b6b2019-01-31 08:20:20 -0500971 *grp = curve_info->grp_id;
972
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200973 return 0;
Manuel Pégourié-Gonnardb3258872013-02-10 12:06:19 +0100974}
975
976/*
977 * Write the ECParameters record corresponding to a group (RFC 4492)
978 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200979int mbedtls_ecp_tls_write_group(const mbedtls_ecp_group *grp,
980 size_t *olen,
981 unsigned char *buf,
982 size_t blen)
Manuel Pégourié-Gonnardb3258872013-02-10 12:06:19 +0100983{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200984 const mbedtls_ecp_curve_info *curve_info;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200985 ECP_VALIDATE_RET(grp != NULL);
986 ECP_VALIDATE_RET(buf != NULL);
987 ECP_VALIDATE_RET(olen != NULL);
Manuel Pégourié-Gonnardf24b4a72013-09-23 18:14:50 +0200988
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200989 if ((curve_info = mbedtls_ecp_curve_info_from_grp_id(grp->id)) == NULL)
990 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard70380392013-09-16 16:19:53 +0200991
Manuel Pégourié-Gonnardb3258872013-02-10 12:06:19 +0100992 /*
993 * We are going to write 3 bytes (see below)
994 */
995 *olen = 3;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +0200996 if (blen < *olen)
997 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
Manuel Pégourié-Gonnardb3258872013-02-10 12:06:19 +0100998
999 /*
1000 * First byte is curve_type, always named_curve
1001 */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001002 *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE;
Manuel Pégourié-Gonnardb3258872013-02-10 12:06:19 +01001003
1004 /*
1005 * Next two bytes are the namedcurve value
1006 */
Manuel Pégourié-Gonnardf24b4a72013-09-23 18:14:50 +02001007 buf[0] = curve_info->tls_id >> 8;
1008 buf[1] = curve_info->tls_id & 0xFF;
Manuel Pégourié-Gonnardb3258872013-02-10 12:06:19 +01001009
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001010 return 0;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +01001011}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +01001012
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +02001013/*
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001014 * Wrapper around fast quasi-modp functions, with fall-back to
1015 * mbedtls_mpi_mod_mpi. See the documentation of struct mbedtls_ecp_group.
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +02001016 *
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001017 * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to
1018 * perf.
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +02001019 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001020static int ecp_modp(mbedtls_mpi *N, const mbedtls_ecp_group *grp)
Manuel Pégourié-Gonnard70380392013-09-16 16:19:53 +02001021{
Janos Follath24eed8d2019-11-22 13:21:35 +00001022 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +02001023
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001024 if (grp->modp == NULL)
1025 return mbedtls_mpi_mod_mpi(N, N, &grp->P);
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +02001026
1027 /* N->s < 0 is a much faster test, which fails only if N is 0 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001028 if ((N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0) ||
1029 mbedtls_mpi_bitlen(N) > 2 * grp->pbits) {
1030 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard70380392013-09-16 16:19:53 +02001031 }
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +02001032
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001033 MBEDTLS_MPI_CHK(grp->modp(N));
Manuel Pégourié-Gonnard70380392013-09-16 16:19:53 +02001034
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +02001035 /* N->s < 0 is a much faster test, which fails only if N is 0 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001036 while (N->s < 0 && mbedtls_mpi_cmp_int(N, 0) != 0)
1037 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(N, N, &grp->P));
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +02001038
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001039 while (mbedtls_mpi_cmp_mpi(N, &grp->P) >= 0)
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +02001040 /* we known P, N and the result are positive */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001041 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(N, N, &grp->P));
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +02001042
Manuel Pégourié-Gonnardcae6f3e2013-10-23 20:19:57 +02001043cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001044 return ret;
Manuel Pégourié-Gonnard70380392013-09-16 16:19:53 +02001045}
Manuel Pégourié-Gonnard568c9cf2013-09-16 17:30:04 +02001046
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +01001047/*
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +01001048 * Fast mod-p functions expect their argument to be in the 0..p^2 range.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +01001049 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +01001050 * In order to guarantee that, we need to ensure that operands of
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001051 * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +01001052 * bring the result back to this range.
1053 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +01001054 * The following macros are shortcuts for doing that.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +01001055 */
1056
1057/*
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001058 * Reduce a mbedtls_mpi mod p in-place, general case, to use after
1059 * mbedtls_mpi_mul_mpi
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001060 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001061# if defined(MBEDTLS_SELF_TEST)
1062# define INC_MUL_COUNT mul_count++;
1063# else
1064# define INC_MUL_COUNT
1065# endif
Manuel Pégourié-Gonnard91814812013-11-21 20:23:55 +01001066
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001067# define MOD_MUL(N) \
1068 do { \
1069 MBEDTLS_MPI_CHK(ecp_modp(&(N), grp)); \
1070 INC_MUL_COUNT \
1071 } while (0)
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001072
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001073static inline int mbedtls_mpi_mul_mod(const mbedtls_ecp_group *grp,
1074 mbedtls_mpi *X,
1075 const mbedtls_mpi *A,
1076 const mbedtls_mpi *B)
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001077{
Janos Follath24eed8d2019-11-22 13:21:35 +00001078 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001079 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(X, A, B));
1080 MOD_MUL(*X);
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001081cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001082 return ret;
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001083}
1084
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001085/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001086 * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi
Manuel Pégourié-Gonnardc9e387c2013-10-17 17:15:35 +02001087 * N->s < 0 is a very fast test, which fails only if N is 0
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001088 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001089# define MOD_SUB(N) \
1090 while ((N).s < 0 && mbedtls_mpi_cmp_int(&(N), 0) != 0) \
1091 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&(N), &(N), &grp->P))
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001092
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001093# if (defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) && \
1094 !(defined(MBEDTLS_ECP_NO_FALLBACK) && \
1095 defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && \
1096 defined(MBEDTLS_ECP_ADD_MIXED_ALT))) || \
1097 (defined(MBEDTLS_ECP_MONTGOMERY_ENABLED) && \
1098 !(defined(MBEDTLS_ECP_NO_FALLBACK) && \
1099 defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)))
1100static inline int mbedtls_mpi_sub_mod(const mbedtls_ecp_group *grp,
1101 mbedtls_mpi *X,
1102 const mbedtls_mpi *A,
1103 const mbedtls_mpi *B)
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001104{
Janos Follath24eed8d2019-11-22 13:21:35 +00001105 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001106 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(X, A, B));
1107 MOD_SUB(*X);
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001108cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001109 return ret;
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001110}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001111# endif /* All functions referencing mbedtls_mpi_sub_mod() are \
1112 alt-implemented without fallback */
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001113
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001114/*
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001115 * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and
1116 * mbedtls_mpi_mul_int. We known P, N and the result are positive, so sub_abs is
1117 * correct, and a bit faster.
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001118 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001119# define MOD_ADD(N) \
1120 while (mbedtls_mpi_cmp_mpi(&(N), &grp->P) >= 0) \
1121 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_abs(&(N), &(N), &grp->P))
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001122
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001123static inline int mbedtls_mpi_add_mod(const mbedtls_ecp_group *grp,
1124 mbedtls_mpi *X,
1125 const mbedtls_mpi *A,
1126 const mbedtls_mpi *B)
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001127{
Janos Follath24eed8d2019-11-22 13:21:35 +00001128 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001129 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(X, A, B));
1130 MOD_ADD(*X);
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001131cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001132 return ret;
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001133}
1134
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001135# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED) && \
1136 !(defined(MBEDTLS_ECP_NO_FALLBACK) && \
1137 defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) && \
1138 defined(MBEDTLS_ECP_ADD_MIXED_ALT))
1139static inline int mbedtls_mpi_shift_l_mod(const mbedtls_ecp_group *grp,
1140 mbedtls_mpi *X,
1141 size_t count)
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001142{
Janos Follath24eed8d2019-11-22 13:21:35 +00001143 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001144 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(X, count));
1145 MOD_ADD(*X);
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001146cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001147 return ret;
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001148}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001149# endif /* All functions referencing mbedtls_mpi_shift_l_mod() are \
1150 alt-implemented without fallback */
Gilles Peskine3b3b34f2019-07-18 21:08:27 +02001151
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001152# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +01001153/*
1154 * For curves in short Weierstrass form, we do all the internal operations in
1155 * Jacobian coordinates.
1156 *
1157 * For multiplication, we'll use a comb method with coutermeasueres against
1158 * SPA, hence timing attacks.
1159 */
1160
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +01001161/*
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +01001162 * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1)
Manuel Pégourié-Gonnard04a02252013-11-20 22:57:38 +01001163 * Cost: 1N := 1I + 3M + 1S
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001164 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001165static int ecp_normalize_jac(const mbedtls_ecp_group *grp,
1166 mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001167{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001168 if (mbedtls_mpi_cmp_int(&pt->Z, 0) == 0)
1169 return 0;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001170
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001171# if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
1172 if (mbedtls_internal_ecp_grp_capable(grp))
1173 return mbedtls_internal_ecp_normalize_jac(grp, pt);
1174# endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */
Manuel Pégourié-Gonnardebac5d32017-08-23 16:23:36 +02001175
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001176# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
1177 defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
1178 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
1179# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01001180 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1181 mbedtls_mpi Zi, ZZi;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001182 mbedtls_mpi_init(&Zi);
1183 mbedtls_mpi_init(&ZZi);
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001184
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +01001185 /*
1186 * X = X / Z^2 mod p
1187 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001188 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&Zi, &pt->Z, &grp->P));
1189 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ZZi, &Zi, &Zi));
1190 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->X, &pt->X, &ZZi));
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001191
1192 /*
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +01001193 * Y = Y / Z^3 mod p
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001194 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001195 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Y, &pt->Y, &ZZi));
1196 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Y, &pt->Y, &Zi));
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001197
1198 /*
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +01001199 * Z = 1
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001200 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001201 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&pt->Z, 1));
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001202
1203cleanup:
1204
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001205 mbedtls_mpi_free(&Zi);
1206 mbedtls_mpi_free(&ZZi);
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001207
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001208 return ret;
1209# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
1210 !defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT) */
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +01001211}
1212
1213/*
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001214 * Normalize jacobian coordinates of an array of (pointers to) points,
Manuel Pégourié-Gonnard3680c822012-11-21 18:49:45 +01001215 * using Montgomery's trick to perform only one inversion mod P.
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001216 * (See for example Cohen's "A Course in Computational Algebraic Number
1217 * Theory", Algorithm 10.3.4.)
1218 *
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001219 * Warning: fails (returning an error) if one of the points is zero!
Manuel Pégourié-Gonnard7a949d32013-12-05 10:26:01 +01001220 * This should never happen, see choice of w in ecp_mul_comb().
Manuel Pégourié-Gonnard04a02252013-11-20 22:57:38 +01001221 *
1222 * Cost: 1N(t) := 1I + (6t - 3)M + 1S
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001223 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001224static int ecp_normalize_jac_many(const mbedtls_ecp_group *grp,
1225 mbedtls_ecp_point *T[],
1226 size_t T_size)
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001227{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001228 if (T_size < 2)
1229 return ecp_normalize_jac(grp, *T);
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001230
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001231# if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
1232 if (mbedtls_internal_ecp_grp_capable(grp))
1233 return mbedtls_internal_ecp_normalize_jac_many(grp, T, T_size);
1234# endif
Janos Follathb0697532016-08-18 12:38:46 +01001235
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001236# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
1237 defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
1238 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
1239# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01001240 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1241 size_t i;
1242 mbedtls_mpi *c, u, Zi, ZZi;
1243
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001244 if ((c = mbedtls_calloc(T_size, sizeof(mbedtls_mpi))) == NULL)
1245 return MBEDTLS_ERR_ECP_ALLOC_FAILED;
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001246
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001247 for (i = 0; i < T_size; i++)
1248 mbedtls_mpi_init(&c[i]);
Manuel Pégourié-Gonnard5bd38b12017-08-23 16:55:59 +02001249
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001250 mbedtls_mpi_init(&u);
1251 mbedtls_mpi_init(&Zi);
1252 mbedtls_mpi_init(&ZZi);
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001253
1254 /*
1255 * c[i] = Z_0 * ... * Z_i
1256 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001257 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&c[0], &T[0]->Z));
1258 for (i = 1; i < T_size; i++) {
1259 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &c[i], &c[i - 1], &T[i]->Z));
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001260 }
1261
1262 /*
1263 * u = 1 / (Z_0 * ... * Z_n) mod P
1264 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001265 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&u, &c[T_size - 1], &grp->P));
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001266
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001267 for (i = T_size - 1;; i--) {
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001268 /*
1269 * Zi = 1 / Z_i mod p
1270 * u = 1 / (Z_0 * ... * Z_i) mod P
1271 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001272 if (i == 0) {
1273 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&Zi, &u));
1274 } else {
1275 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &Zi, &u, &c[i - 1]));
1276 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &u, &u, &T[i]->Z));
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001277 }
1278
1279 /*
1280 * proceed as in normalize()
1281 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001282 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ZZi, &Zi, &Zi));
1283 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T[i]->X, &T[i]->X, &ZZi));
1284 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T[i]->Y, &T[i]->Y, &ZZi));
1285 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T[i]->Y, &T[i]->Y, &Zi));
Manuel Pégourié-Gonnard1f789b82013-12-30 17:31:56 +01001286
1287 /*
1288 * Post-precessing: reclaim some memory by shrinking coordinates
1289 * - not storing Z (always 1)
1290 * - shrinking other coordinates, but still keeping the same number of
1291 * limbs as P, as otherwise it will too likely be regrown too fast.
1292 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001293 MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->X, grp->P.n));
1294 MBEDTLS_MPI_CHK(mbedtls_mpi_shrink(&T[i]->Y, grp->P.n));
1295 mbedtls_mpi_free(&T[i]->Z);
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001296
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001297 if (i == 0)
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001298 break;
1299 }
1300
1301cleanup:
1302
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001303 mbedtls_mpi_free(&u);
1304 mbedtls_mpi_free(&Zi);
1305 mbedtls_mpi_free(&ZZi);
1306 for (i = 0; i < T_size; i++)
1307 mbedtls_mpi_free(&c[i]);
1308 mbedtls_free(c);
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001309
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001310 return ret;
1311# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
1312 !defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT) */
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001313}
1314
Manuel Pégourié-Gonnardcdd44322012-11-21 16:00:55 +01001315/*
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001316 * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak.
1317 * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid
1318 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001319static int ecp_safe_invert_jac(const mbedtls_ecp_group *grp,
1320 mbedtls_ecp_point *Q,
1321 unsigned char inv)
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001322{
Janos Follath24eed8d2019-11-22 13:21:35 +00001323 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001324 unsigned char nonzero;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001325 mbedtls_mpi mQY;
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001326
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001327 mbedtls_mpi_init(&mQY);
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001328
1329 /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001330 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&mQY, &grp->P, &Q->Y));
1331 nonzero = mbedtls_mpi_cmp_int(&Q->Y, 0) != 0;
1332 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&Q->Y, &mQY, inv & nonzero));
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001333
1334cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001335 mbedtls_mpi_free(&mQY);
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001336
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001337 return ret;
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001338}
1339
1340/*
Manuel Pégourié-Gonnard0cd6f982013-10-10 15:55:39 +02001341 * Point doubling R = 2 P, Jacobian coordinates
Manuel Pégourié-Gonnard0ace4b32013-10-10 12:44:27 +02001342 *
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001343 * Based on
1344 * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2
1345 * .
Manuel Pégourié-Gonnard04a02252013-11-20 22:57:38 +01001346 *
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001347 * We follow the variable naming fairly closely. The formula variations that
1348 * trade a MUL for a SQR (plus a few ADDs) aren't useful as our bignum
1349 * implementation doesn't distinguish squaring.
Peter Dettmance661b22015-02-07 14:43:51 +07001350 *
1351 * Standard optimizations are applied when curve parameter A is one of { 0, -3 }.
1352 *
1353 * Cost: 1D := 3M + 4S (A == 0)
1354 * 4M + 4S (A == -3)
1355 * 3M + 6S + 1a otherwise
Manuel Pégourié-Gonnard1c4aa242013-10-09 16:09:46 +02001356 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001357static int ecp_double_jac(const mbedtls_ecp_group *grp,
1358 mbedtls_ecp_point *R,
1359 const mbedtls_ecp_point *P)
Manuel Pégourié-Gonnard1c4aa242013-10-09 16:09:46 +02001360{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001361# if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnard0cd6f982013-10-10 15:55:39 +02001362 dbl_count++;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001363# endif
Manuel Pégourié-Gonnard0cd6f982013-10-10 15:55:39 +02001364
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001365# if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
1366 if (mbedtls_internal_ecp_grp_capable(grp))
1367 return mbedtls_internal_ecp_double_jac(grp, R, P);
1368# endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */
Janos Follathb0697532016-08-18 12:38:46 +01001369
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001370# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
1371 defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
1372 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
1373# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01001374 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1375 mbedtls_mpi M, S, T, U;
1376
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001377 mbedtls_mpi_init(&M);
1378 mbedtls_mpi_init(&S);
1379 mbedtls_mpi_init(&T);
1380 mbedtls_mpi_init(&U);
Manuel Pégourié-Gonnard73cc01d2013-12-06 12:41:30 +01001381
1382 /* Special case for A = -3 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001383 if (grp->A.p == NULL) {
Peter Dettmance661b22015-02-07 14:43:51 +07001384 /* M = 3(X + Z^2)(X - Z^2) */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001385 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->Z, &P->Z));
1386 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &T, &P->X, &S));
1387 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &U, &P->X, &S));
1388 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &T, &U));
1389 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&M, &S, 3));
1390 MOD_ADD(M);
1391 } else {
Peter Dettmance661b22015-02-07 14:43:51 +07001392 /* M = 3.X^2 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001393 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->X, &P->X));
1394 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_int(&M, &S, 3));
1395 MOD_ADD(M);
Peter Dettmance661b22015-02-07 14:43:51 +07001396
1397 /* Optimize away for "koblitz" curves with A = 0 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001398 if (mbedtls_mpi_cmp_int(&grp->A, 0) != 0) {
Peter Dettmance661b22015-02-07 14:43:51 +07001399 /* M += A.Z^4 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001400 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->Z, &P->Z));
1401 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T, &S, &S));
1402 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &T, &grp->A));
1403 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &M, &M, &S));
Peter Dettmance661b22015-02-07 14:43:51 +07001404 }
Peter Vaskovica676acf2014-08-06 00:48:39 +02001405 }
Manuel Pégourié-Gonnard73cc01d2013-12-06 12:41:30 +01001406
Peter Dettmance661b22015-02-07 14:43:51 +07001407 /* S = 4.X.Y^2 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001408 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T, &P->Y, &P->Y));
1409 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &T, 1));
1410 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &P->X, &T));
1411 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &S, 1));
Manuel Pégourié-Gonnard1c4aa242013-10-09 16:09:46 +02001412
Peter Dettmance661b22015-02-07 14:43:51 +07001413 /* U = 8.Y^4 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001414 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &U, &T, &T));
1415 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &U, 1));
Peter Dettmance661b22015-02-07 14:43:51 +07001416
1417 /* T = M^2 - 2.S */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001418 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T, &M, &M));
1419 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T, &T, &S));
1420 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T, &T, &S));
Peter Dettmance661b22015-02-07 14:43:51 +07001421
1422 /* S = M(S - T) - U */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001423 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &S, &S, &T));
1424 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S, &S, &M));
1425 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &S, &S, &U));
Peter Dettmance661b22015-02-07 14:43:51 +07001426
1427 /* U = 2.Y.Z */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001428 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &U, &P->Y, &P->Z));
1429 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &U, 1));
Peter Dettmance661b22015-02-07 14:43:51 +07001430
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001431 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->X, &T));
1432 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Y, &S));
1433 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Z, &U));
Manuel Pégourié-Gonnard1c4aa242013-10-09 16:09:46 +02001434
1435cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001436 mbedtls_mpi_free(&M);
1437 mbedtls_mpi_free(&S);
1438 mbedtls_mpi_free(&T);
1439 mbedtls_mpi_free(&U);
Manuel Pégourié-Gonnard1c4aa242013-10-09 16:09:46 +02001440
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001441 return ret;
1442# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
1443 !defined(MBEDTLS_ECP_DOUBLE_JAC_ALT) */
Manuel Pégourié-Gonnard1c4aa242013-10-09 16:09:46 +02001444}
1445
1446/*
Manuel Pégourié-Gonnard469a2092013-11-21 18:20:43 +01001447 * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +01001448 *
1449 * The coordinates of Q must be normalized (= affine),
1450 * but those of P don't need to. R is not normalized.
1451 *
Manuel Pégourié-Gonnardaade42f2013-11-21 19:19:54 +01001452 * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q.
Manuel Pégourié-Gonnard7a949d32013-12-05 10:26:01 +01001453 * None of these cases can happen as intermediate step in ecp_mul_comb():
Manuel Pégourié-Gonnardaade42f2013-11-21 19:19:54 +01001454 * - at each step, P, Q and R are multiples of the base point, the factor
1455 * being less than its order, so none of them is zero;
1456 * - Q is an odd multiple of the base point, P an even multiple,
1457 * due to the choice of precomputed points in the modified comb method.
1458 * So branches for these cases do not leak secret information.
1459 *
Manuel Pégourié-Gonnard72c172a2013-12-30 16:04:55 +01001460 * We accept Q->Z being unset (saving memory in tables) as meaning 1.
1461 *
Manuel Pégourié-Gonnard04a02252013-11-20 22:57:38 +01001462 * Cost: 1A := 8M + 3S
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001463 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001464static int ecp_add_mixed(const mbedtls_ecp_group *grp,
1465 mbedtls_ecp_point *R,
1466 const mbedtls_ecp_point *P,
1467 const mbedtls_ecp_point *Q)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001468{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001469# if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01001470 add_count++;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001471# endif
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01001472
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001473# if defined(MBEDTLS_ECP_ADD_MIXED_ALT)
1474 if (mbedtls_internal_ecp_grp_capable(grp))
1475 return mbedtls_internal_ecp_add_mixed(grp, R, P, Q);
1476# endif /* MBEDTLS_ECP_ADD_MIXED_ALT */
Janos Follathb0697532016-08-18 12:38:46 +01001477
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001478# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
1479 defined(MBEDTLS_ECP_ADD_MIXED_ALT)
1480 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
1481# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01001482 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1483 mbedtls_mpi T1, T2, T3, T4, X, Y, Z;
1484
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001485 /*
Manuel Pégourié-Gonnardaade42f2013-11-21 19:19:54 +01001486 * Trivial cases: P == 0 or Q == 0 (case 1)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001487 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001488 if (mbedtls_mpi_cmp_int(&P->Z, 0) == 0)
1489 return mbedtls_ecp_copy(R, Q);
Manuel Pégourié-Gonnard469a2092013-11-21 18:20:43 +01001490
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001491 if (Q->Z.p != NULL && mbedtls_mpi_cmp_int(&Q->Z, 0) == 0)
1492 return mbedtls_ecp_copy(R, P);
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +01001493
1494 /*
1495 * Make sure Q coordinates are normalized
1496 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001497 if (Q->Z.p != NULL && mbedtls_mpi_cmp_int(&Q->Z, 1) != 0)
1498 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001499
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001500 mbedtls_mpi_init(&T1);
1501 mbedtls_mpi_init(&T2);
1502 mbedtls_mpi_init(&T3);
1503 mbedtls_mpi_init(&T4);
1504 mbedtls_mpi_init(&X);
1505 mbedtls_mpi_init(&Y);
1506 mbedtls_mpi_init(&Z);
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +01001507
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001508 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T1, &P->Z, &P->Z));
1509 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T2, &T1, &P->Z));
1510 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T1, &T1, &Q->X));
1511 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T2, &T2, &Q->Y));
1512 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T1, &T1, &P->X));
1513 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T2, &T2, &P->Y));
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001514
Manuel Pégourié-Gonnardaade42f2013-11-21 19:19:54 +01001515 /* Special cases (2) and (3) */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001516 if (mbedtls_mpi_cmp_int(&T1, 0) == 0) {
1517 if (mbedtls_mpi_cmp_int(&T2, 0) == 0) {
1518 ret = ecp_double_jac(grp, R, P);
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +01001519 goto cleanup;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001520 } else {
1521 ret = mbedtls_ecp_set_zero(R);
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +01001522 goto cleanup;
1523 }
1524 }
1525
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001526 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &Z, &P->Z, &T1));
1527 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T3, &T1, &T1));
1528 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T4, &T3, &T1));
1529 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T3, &T3, &P->X));
1530 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&T1, &T3));
1531 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l_mod(grp, &T1, 1));
1532 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &X, &T2, &T2));
1533 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &X, &X, &T1));
1534 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &X, &X, &T4));
1535 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &T3, &T3, &X));
1536 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T3, &T3, &T2));
1537 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &T4, &T4, &P->Y));
1538 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &Y, &T3, &T4));
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +01001539
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001540 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->X, &X));
1541 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Y, &Y));
1542 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&R->Z, &Z));
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001543
1544cleanup:
1545
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001546 mbedtls_mpi_free(&T1);
1547 mbedtls_mpi_free(&T2);
1548 mbedtls_mpi_free(&T3);
1549 mbedtls_mpi_free(&T4);
1550 mbedtls_mpi_free(&X);
1551 mbedtls_mpi_free(&Y);
1552 mbedtls_mpi_free(&Z);
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001553
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001554 return ret;
1555# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
1556 !defined(MBEDTLS_ECP_ADD_MIXED_ALT) */
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +01001557}
1558
1559/*
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001560 * Randomize jacobian coordinates:
1561 * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l
Manuel Pégourié-Gonnard3c0b4ea2013-12-02 19:44:41 +01001562 * This is sort of the reverse operation of ecp_normalize_jac().
Manuel Pégourié-Gonnard44aab792013-11-21 10:53:59 +01001563 *
1564 * This countermeasure was first suggested in [2].
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001565 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001566static int ecp_randomize_jac(const mbedtls_ecp_group *grp,
1567 mbedtls_ecp_point *pt,
1568 int (*f_rng)(void *, unsigned char *, size_t),
1569 void *p_rng)
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001570{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001571# if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
1572 if (mbedtls_internal_ecp_grp_capable(grp))
1573 return mbedtls_internal_ecp_randomize_jac(grp, pt, f_rng, p_rng);
1574# endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */
Janos Follathb0697532016-08-18 12:38:46 +01001575
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001576# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
1577 defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
1578 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
1579# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01001580 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
1581 mbedtls_mpi l, ll;
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01001582
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001583 mbedtls_mpi_init(&l);
1584 mbedtls_mpi_init(&ll);
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001585
1586 /* Generate l such that 1 < l < p */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001587 MBEDTLS_MPI_CHK(mbedtls_mpi_random(&l, 2, &grp->P, f_rng, p_rng));
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001588
1589 /* Z = l * Z */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001590 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Z, &pt->Z, &l));
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001591
1592 /* X = l^2 * X */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001593 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ll, &l, &l));
1594 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->X, &pt->X, &ll));
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001595
1596 /* Y = l^3 * Y */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001597 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &ll, &ll, &l));
1598 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &pt->Y, &pt->Y, &ll));
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001599
1600cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001601 mbedtls_mpi_free(&l);
1602 mbedtls_mpi_free(&ll);
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001603
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001604 if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE)
Gilles Peskine59215172021-03-29 22:28:50 +02001605 ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001606 return ret;
1607# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
1608 !defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT) */
Manuel Pégourié-Gonnard07de4b12013-09-02 16:26:04 +02001609}
1610
1611/*
Manuel Pégourié-Gonnardc30200e2013-11-20 18:39:55 +01001612 * Check and define parameters used by the comb method (see below for details)
1613 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001614# if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7
1615# error "MBEDTLS_ECP_WINDOW_SIZE out of bounds"
1616# endif
Manuel Pégourié-Gonnardc30200e2013-11-20 18:39:55 +01001617
1618/* d = ceil( n / w ) */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001619# define COMB_MAX_D (MBEDTLS_ECP_MAX_BITS + 1) / 2
Manuel Pégourié-Gonnardc30200e2013-11-20 18:39:55 +01001620
1621/* number of precomputed points */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001622# define COMB_MAX_PRE (1 << (MBEDTLS_ECP_WINDOW_SIZE - 1))
Manuel Pégourié-Gonnardc30200e2013-11-20 18:39:55 +01001623
1624/*
1625 * Compute the representation of m that will be used with our comb method.
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001626 *
1627 * The basic comb method is described in GECC 3.44 for example. We use a
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001628 * modified version that provides resistance to SPA by avoiding zero
1629 * digits in the representation as in [3]. We modify the method further by
1630 * requiring that all K_i be odd, which has the small cost that our
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001631 * representation uses one more K_i, due to carries, but saves on the size of
1632 * the precomputed table.
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001633 *
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001634 * Summary of the comb method and its modifications:
1635 *
1636 * - The goal is to compute m*P for some w*d-bit integer m.
1637 *
1638 * - The basic comb method splits m into the w-bit integers
1639 * x[0] .. x[d-1] where x[i] consists of the bits in m whose
1640 * index has residue i modulo d, and computes m * P as
1641 * S[x[0]] + 2 * S[x[1]] + .. + 2^(d-1) S[x[d-1]], where
1642 * S[i_{w-1} .. i_0] := i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + i_0 P.
1643 *
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001644 * - If it happens that, say, x[i+1]=0 (=> S[x[i+1]]=0), one can replace the sum
1645 * by
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001646 * .. + 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]] ..,
1647 * thereby successively converting it into a form where all summands
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001648 * are nonzero, at the cost of negative summands. This is the basic idea of
1649 * [3].
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001650 *
1651 * - More generally, even if x[i+1] != 0, we can first transform the sum as
1652 * .. - 2^i S[x[i]] + 2^{i+1} ( S[x[i]] + S[x[i+1]] ) + 2^{i+2} S[x[i+2]] ..,
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001653 * and then replace S[x[i]] + S[x[i+1]] = S[x[i] ^ x[i+1]] + 2 S[x[i] &
1654 * x[i+1]]. Performing and iterating this procedure for those x[i] that are even
1655 * (keeping track of carry), we can transform the original sum into one of the
1656 * form
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001657 * S[x'[0]] +- 2 S[x'[1]] +- .. +- 2^{d-1} S[x'[d-1]] + 2^d S[x'[d]]
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001658 * with all x'[i] odd. It is therefore only necessary to know S at odd
1659 * indices, which is why we are only computing half of it in the first place in
1660 * ecp_precompute_comb and accessing it with index abs(i) / 2 in
1661 * ecp_select_comb.
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001662 *
1663 * - For the sake of compactness, only the seven low-order bits of x[i]
1664 * are used to represent its absolute value (K_i in the paper), and the msb
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001665 * of x[i] encodes the sign (s_i in the paper): it is set if and only if
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001666 * if s_i == -1;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001667 *
1668 * Calling conventions:
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001669 * - x is an array of size d + 1
Manuel Pégourié-Gonnardc30200e2013-11-20 18:39:55 +01001670 * - w is the size, ie number of teeth, of the comb, and must be between
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001671 * 2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE)
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001672 * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d
1673 * (the result will be incorrect if these assumptions are not satisfied)
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001674 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001675static void ecp_comb_recode_core(unsigned char x[],
1676 size_t d,
1677 unsigned char w,
1678 const mbedtls_mpi *m)
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001679{
1680 size_t i, j;
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001681 unsigned char c, cc, adjust;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001682
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001683 memset(x, 0, d + 1);
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001684
Manuel Pégourié-Gonnardedc1a1f2013-11-21 09:50:00 +01001685 /* First get the classical comb values (except for x_d = 0) */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001686 for (i = 0; i < d; i++)
1687 for (j = 0; j < w; j++)
1688 x[i] |= mbedtls_mpi_get_bit(m, i + d * j) << j;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001689
Manuel Pégourié-Gonnardedc1a1f2013-11-21 09:50:00 +01001690 /* Now make sure x_1 .. x_d are odd */
1691 c = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001692 for (i = 1; i <= d; i++) {
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001693 /* Add carry and update it */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001694 cc = x[i] & c;
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001695 x[i] = x[i] ^ c;
1696 c = cc;
1697
Manuel Pégourié-Gonnardedc1a1f2013-11-21 09:50:00 +01001698 /* Adjust if needed, avoiding branches */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001699 adjust = 1 - (x[i] & 0x01);
1700 c |= x[i] & (x[i - 1] * adjust);
1701 x[i] = x[i] ^ (x[i - 1] * adjust);
1702 x[i - 1] |= adjust << 7;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001703 }
1704}
1705
1706/*
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001707 * Precompute points for the adapted comb method
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001708 *
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001709 * Assumption: T must be able to hold 2^{w - 1} elements.
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001710 *
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001711 * Operation: If i = i_{w-1} ... i_1 is the binary representation of i,
1712 * sets T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P.
Manuel Pégourié-Gonnard04a02252013-11-20 22:57:38 +01001713 *
1714 * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1)
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001715 *
1716 * Note: Even comb values (those where P would be omitted from the
1717 * sum defining T[i] above) are not needed in our adaption
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001718 * the comb method. See ecp_comb_recode_core().
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001719 *
1720 * This function currently works in four steps:
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001721 * (1) [dbl] Computation of intermediate T[i] for 2-power values of i
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001722 * (2) [norm_dbl] Normalization of coordinates of these T[i]
1723 * (3) [add] Computation of all T[i]
1724 * (4) [norm_add] Normalization of all T[i]
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001725 *
1726 * Step 1 can be interrupted but not the others; together with the final
1727 * coordinate normalization they are the largest steps done at once, depending
1728 * on the window size. Here are operation counts for P-256:
1729 *
1730 * step (2) (3) (4)
1731 * w = 5 142 165 208
1732 * w = 4 136 77 160
1733 * w = 3 130 33 136
1734 * w = 2 124 11 124
1735 *
1736 * So if ECC operations are blocking for too long even with a low max_ops
1737 * value, it's useful to set MBEDTLS_ECP_WINDOW_SIZE to a lower value in order
1738 * to minimize maximum blocking time.
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001739 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001740static int ecp_precompute_comb(const mbedtls_ecp_group *grp,
1741 mbedtls_ecp_point T[],
1742 const mbedtls_ecp_point *P,
1743 unsigned char w,
1744 size_t d,
1745 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001746{
Janos Follath24eed8d2019-11-22 13:21:35 +00001747 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardfc3e0be2017-03-20 09:29:31 +01001748 unsigned char i;
Manuel Pégourié-Gonnard213541a2017-03-20 12:50:41 +01001749 size_t j = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001750 const unsigned char T_size = 1U << (w - 1);
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001751 mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1];
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001752
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001753# if defined(MBEDTLS_ECP_RESTARTABLE)
1754 if (rs_ctx != NULL && rs_ctx->rsm != NULL) {
1755 if (rs_ctx->rsm->state == ecp_rsm_pre_dbl)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001756 goto dbl;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001757 if (rs_ctx->rsm->state == ecp_rsm_pre_norm_dbl)
Manuel Pégourié-Gonnarde2d7cb32017-03-20 10:24:17 +01001758 goto norm_dbl;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001759 if (rs_ctx->rsm->state == ecp_rsm_pre_add)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001760 goto add;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001761 if (rs_ctx->rsm->state == ecp_rsm_pre_norm_add)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001762 goto norm_add;
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01001763 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001764# else
1765 (void)rs_ctx;
1766# endif
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01001767
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001768# if defined(MBEDTLS_ECP_RESTARTABLE)
1769 if (rs_ctx != NULL && rs_ctx->rsm != NULL) {
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001770 rs_ctx->rsm->state = ecp_rsm_pre_dbl;
1771
1772 /* initial state for the loop */
1773 rs_ctx->rsm->i = 0;
1774 }
1775
1776dbl:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001777# endif
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001778 /*
1779 * Set T[0] = P and
1780 * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value)
1781 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001782 MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&T[0], P));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001783
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001784# if defined(MBEDTLS_ECP_RESTARTABLE)
1785 if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0)
Manuel Pégourié-Gonnard3cade222017-04-20 09:31:00 +02001786 j = rs_ctx->rsm->i;
Manuel Pégourié-Gonnard213541a2017-03-20 12:50:41 +01001787 else
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001788# endif
Manuel Pégourié-Gonnard213541a2017-03-20 12:50:41 +01001789 j = 0;
1790
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001791 for (; j < d * (w - 1); j++) {
1792 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL);
Manuel Pégourié-Gonnard213541a2017-03-20 12:50:41 +01001793
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001794 i = 1U << (j / d);
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001795 cur = T + i;
Manuel Pégourié-Gonnardae557072017-03-20 12:21:24 +01001796
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001797 if (j % d == 0)
1798 MBEDTLS_MPI_CHK(mbedtls_ecp_copy(cur, T + (i >> 1)));
Manuel Pégourié-Gonnardae557072017-03-20 12:21:24 +01001799
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001800 MBEDTLS_MPI_CHK(ecp_double_jac(grp, cur, cur));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001801 }
1802
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001803# if defined(MBEDTLS_ECP_RESTARTABLE)
1804 if (rs_ctx != NULL && rs_ctx->rsm != NULL)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001805 rs_ctx->rsm->state = ecp_rsm_pre_norm_dbl;
1806
Manuel Pégourié-Gonnarde2d7cb32017-03-20 10:24:17 +01001807norm_dbl:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001808# endif
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001809 /*
1810 * Normalize current elements in T. As T has holes,
1811 * use an auxiliary array of pointers to elements in T.
1812 */
Manuel Pégourié-Gonnardfc3e0be2017-03-20 09:29:31 +01001813 j = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001814 for (i = 1; i < T_size; i <<= 1)
Manuel Pégourié-Gonnardfc3e0be2017-03-20 09:29:31 +01001815 TT[j++] = T + i;
1816
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001817 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2);
Manuel Pégourié-Gonnarde2d7cb32017-03-20 10:24:17 +01001818
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001819 MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001820
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001821# if defined(MBEDTLS_ECP_RESTARTABLE)
1822 if (rs_ctx != NULL && rs_ctx->rsm != NULL)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001823 rs_ctx->rsm->state = ecp_rsm_pre_add;
1824
Manuel Pégourié-Gonnarde2d7cb32017-03-20 10:24:17 +01001825add:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001826# endif
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001827 /*
1828 * Compute the remaining ones using the minimal number of additions
1829 * Be careful to update T[2^l] only after using it!
1830 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001831 MBEDTLS_ECP_BUDGET((T_size - 1) * MBEDTLS_ECP_OPS_ADD);
Manuel Pégourié-Gonnarde2d7cb32017-03-20 10:24:17 +01001832
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001833 for (i = 1; i < T_size; i <<= 1) {
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001834 j = i;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001835 while (j--)
1836 MBEDTLS_MPI_CHK(ecp_add_mixed(grp, &T[i + j], &T[j], &T[i]));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001837 }
1838
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001839# if defined(MBEDTLS_ECP_RESTARTABLE)
1840 if (rs_ctx != NULL && rs_ctx->rsm != NULL)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001841 rs_ctx->rsm->state = ecp_rsm_pre_norm_add;
1842
Manuel Pégourié-Gonnarde2d7cb32017-03-20 10:24:17 +01001843norm_add:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001844# endif
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001845 /*
Manuel Pégourié-Gonnarda966fde2018-10-23 10:41:11 +02001846 * Normalize final elements in T. Even though there are no holes now, we
1847 * still need the auxiliary array for homogeneity with the previous
1848 * call. Also, skip T[0] which is already normalised, being a copy of P.
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02001849 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001850 for (j = 0; j + 1 < T_size; j++)
Manuel Pégourié-Gonnardfc3e0be2017-03-20 09:29:31 +01001851 TT[j] = T + j + 1;
1852
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001853 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV + 6 * j - 2);
Manuel Pégourié-Gonnarde2d7cb32017-03-20 10:24:17 +01001854
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001855 MBEDTLS_MPI_CHK(ecp_normalize_jac_many(grp, TT, j));
Manuel Pégourié-Gonnarde2820122013-11-21 10:08:50 +01001856
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001857cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001858# if defined(MBEDTLS_ECP_RESTARTABLE)
1859 if (rs_ctx != NULL && rs_ctx->rsm != NULL &&
1860 ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
1861 if (rs_ctx->rsm->state == ecp_rsm_pre_dbl)
Manuel Pégourié-Gonnard3cade222017-04-20 09:31:00 +02001862 rs_ctx->rsm->i = j;
Manuel Pégourié-Gonnard213541a2017-03-20 12:50:41 +01001863 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001864# endif
Janos Follathb0697532016-08-18 12:38:46 +01001865
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001866 return ret;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001867}
1868
1869/*
Manuel Pégourié-Gonnard101a39f2013-11-20 14:47:19 +01001870 * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ]
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001871 *
1872 * See ecp_comb_recode_core() for background
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001873 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001874static int ecp_select_comb(const mbedtls_ecp_group *grp,
1875 mbedtls_ecp_point *R,
1876 const mbedtls_ecp_point T[],
1877 unsigned char T_size,
1878 unsigned char i)
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001879{
Janos Follath24eed8d2019-11-22 13:21:35 +00001880 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardd7283502013-11-21 20:00:38 +01001881 unsigned char ii, j;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001882
Manuel Pégourié-Gonnardd7283502013-11-21 20:00:38 +01001883 /* Ignore the "sign" bit and scale down */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001884 ii = (i & 0x7Fu) >> 1;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001885
Manuel Pégourié-Gonnardd7283502013-11-21 20:00:38 +01001886 /* Read the whole table to thwart cache-based timing attacks */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001887 for (j = 0; j < T_size; j++) {
1888 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&R->X, &T[j].X, j == ii));
1889 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&R->Y, &T[j].Y, j == ii));
Manuel Pégourié-Gonnardd7283502013-11-21 20:00:38 +01001890 }
1891
Manuel Pégourié-Gonnard01fca5e2013-11-21 17:47:12 +01001892 /* Safely invert result if i is "negative" */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001893 MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, R, i >> 7));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001894
1895cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001896 return ret;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001897}
1898
1899/*
1900 * Core multiplication algorithm for the (modified) comb method.
1901 * This part is actually common with the basic comb method (GECC 3.44)
Manuel Pégourié-Gonnard04a02252013-11-20 22:57:38 +01001902 *
1903 * Cost: d A + d D + 1 R
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001904 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001905static int ecp_mul_comb_core(const mbedtls_ecp_group *grp,
1906 mbedtls_ecp_point *R,
1907 const mbedtls_ecp_point T[],
1908 unsigned char T_size,
1909 const unsigned char x[],
1910 size_t d,
1911 int (*f_rng)(void *, unsigned char *, size_t),
1912 void *p_rng,
1913 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001914{
Janos Follath24eed8d2019-11-22 13:21:35 +00001915 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02001916 mbedtls_ecp_point Txi;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001917 size_t i;
1918
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001919 mbedtls_ecp_point_init(&Txi);
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001920
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001921# if !defined(MBEDTLS_ECP_RESTARTABLE)
1922 (void)rs_ctx;
1923# endif
Manuel Pégourié-Gonnard3cade222017-04-20 09:31:00 +02001924
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001925# if defined(MBEDTLS_ECP_RESTARTABLE)
1926 if (rs_ctx != NULL && rs_ctx->rsm != NULL &&
1927 rs_ctx->rsm->state != ecp_rsm_comb_core) {
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001928 rs_ctx->rsm->i = 0;
1929 rs_ctx->rsm->state = ecp_rsm_comb_core;
1930 }
1931
1932 /* new 'if' instead of nested for the sake of the 'else' branch */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001933 if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->i != 0) {
Manuel Pégourié-Gonnard3cade222017-04-20 09:31:00 +02001934 /* restore current index (R already pointing to rs_ctx->rsm->R) */
1935 i = rs_ctx->rsm->i;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001936 } else
1937# endif
Manuel Pégourié-Gonnardc5d844b2017-03-15 13:06:28 +01001938 {
1939 /* Start with a non-zero point and randomize its coordinates */
1940 i = d;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001941 MBEDTLS_MPI_CHK(ecp_select_comb(grp, R, T, T_size, x[i]));
1942 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 1));
1943 if (f_rng != 0)
1944 MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, R, f_rng, p_rng));
Manuel Pégourié-Gonnardc5d844b2017-03-15 13:06:28 +01001945 }
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001946
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001947 while (i != 0) {
1948 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_DBL + MBEDTLS_ECP_OPS_ADD);
Manuel Pégourié-Gonnard90f31b72018-10-16 10:45:24 +02001949 --i;
1950
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001951 MBEDTLS_MPI_CHK(ecp_double_jac(grp, R, R));
1952 MBEDTLS_MPI_CHK(ecp_select_comb(grp, &Txi, T, T_size, x[i]));
1953 MBEDTLS_MPI_CHK(ecp_add_mixed(grp, R, R, &Txi));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001954 }
1955
1956cleanup:
Janos Follathb0697532016-08-18 12:38:46 +01001957
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001958 mbedtls_ecp_point_free(&Txi);
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001959
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001960# if defined(MBEDTLS_ECP_RESTARTABLE)
1961 if (rs_ctx != NULL && rs_ctx->rsm != NULL &&
1962 ret == MBEDTLS_ERR_ECP_IN_PROGRESS) {
Manuel Pégourié-Gonnard90f31b72018-10-16 10:45:24 +02001963 rs_ctx->rsm->i = i;
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02001964 /* no need to save R, already pointing to rs_ctx->rsm->R */
Manuel Pégourié-Gonnardc5d844b2017-03-15 13:06:28 +01001965 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001966# endif
Manuel Pégourié-Gonnardc5d844b2017-03-15 13:06:28 +01001967
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001968 return ret;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01001969}
1970
1971/*
Manuel Pégourié-Gonnard62738e92017-03-14 10:00:21 +01001972 * Recode the scalar to get constant-time comb multiplication
1973 *
1974 * As the actual scalar recoding needs an odd scalar as a starting point,
1975 * this wrapper ensures that by replacing m by N - m if necessary, and
1976 * informs the caller that the result of multiplication will be negated.
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001977 *
Manuel Pégourié-Gonnardfd87e352017-08-24 14:21:05 +02001978 * This works because we only support large prime order for Short Weierstrass
1979 * curves, so N is always odd hence either m or N - m is.
1980 *
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02001981 * See ecp_comb_recode_core() for background.
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01001982 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001983static int ecp_comb_recode_scalar(const mbedtls_ecp_group *grp,
1984 const mbedtls_mpi *m,
1985 unsigned char k[COMB_MAX_D + 1],
1986 size_t d,
1987 unsigned char w,
1988 unsigned char *parity_trick)
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01001989{
Janos Follath24eed8d2019-11-22 13:21:35 +00001990 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard62738e92017-03-14 10:00:21 +01001991 mbedtls_mpi M, mm;
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01001992
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001993 mbedtls_mpi_init(&M);
1994 mbedtls_mpi_init(&mm);
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01001995
Manuel Pégourié-Gonnardfd87e352017-08-24 14:21:05 +02001996 /* N is always odd (see above), just make extra sure */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02001997 if (mbedtls_mpi_get_bit(&grp->N, 0) != 1)
1998 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01001999
Manuel Pégourié-Gonnard62738e92017-03-14 10:00:21 +01002000 /* do we need the parity trick? */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002001 *parity_trick = (mbedtls_mpi_get_bit(m, 0) == 0);
Manuel Pégourié-Gonnard62738e92017-03-14 10:00:21 +01002002
2003 /* execute parity fix in constant time */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002004 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&M, m));
2005 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&mm, &grp->N, m));
2006 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_assign(&M, &mm, *parity_trick));
Manuel Pégourié-Gonnard62738e92017-03-14 10:00:21 +01002007
2008 /* actual scalar recoding */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002009 ecp_comb_recode_core(k, d, w, &M);
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01002010
2011cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002012 mbedtls_mpi_free(&mm);
2013 mbedtls_mpi_free(&M);
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01002014
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002015 return ret;
Manuel Pégourié-Gonnardec5606a2017-03-09 12:46:45 +01002016}
2017
2018/*
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002019 * Perform comb multiplication (for short Weierstrass curves)
2020 * once the auxiliary table has been pre-computed.
Manuel Pégourié-Gonnard62738e92017-03-14 10:00:21 +01002021 *
2022 * Scalar recoding may use a parity trick that makes us compute -m * P,
2023 * if that is the case we'll need to recover m * P at the end.
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002024 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002025static int
2026ecp_mul_comb_after_precomp(const mbedtls_ecp_group *grp,
2027 mbedtls_ecp_point *R,
2028 const mbedtls_mpi *m,
2029 const mbedtls_ecp_point *T,
2030 unsigned char T_size,
2031 unsigned char w,
2032 size_t d,
2033 int (*f_rng)(void *, unsigned char *, size_t),
2034 void *p_rng,
2035 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002036{
Janos Follath24eed8d2019-11-22 13:21:35 +00002037 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard62738e92017-03-14 10:00:21 +01002038 unsigned char parity_trick;
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002039 unsigned char k[COMB_MAX_D + 1];
Manuel Pégourié-Gonnard8962ddb2017-03-14 12:11:21 +01002040 mbedtls_ecp_point *RR = R;
2041
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002042# if defined(MBEDTLS_ECP_RESTARTABLE)
2043 if (rs_ctx != NULL && rs_ctx->rsm != NULL) {
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02002044 RR = &rs_ctx->rsm->R;
2045
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002046 if (rs_ctx->rsm->state == ecp_rsm_final_norm)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02002047 goto final_norm;
2048 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002049# endif
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002050
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002051 MBEDTLS_MPI_CHK(ecp_comb_recode_scalar(grp, m, k, d, w, &parity_trick));
2052 MBEDTLS_MPI_CHK(
2053 ecp_mul_comb_core(grp, RR, T, T_size, k, d, f_rng, p_rng, rs_ctx));
2054 MBEDTLS_MPI_CHK(ecp_safe_invert_jac(grp, RR, parity_trick));
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02002055
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002056# if defined(MBEDTLS_ECP_RESTARTABLE)
2057 if (rs_ctx != NULL && rs_ctx->rsm != NULL)
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02002058 rs_ctx->rsm->state = ecp_rsm_final_norm;
Manuel Pégourié-Gonnard3cade222017-04-20 09:31:00 +02002059
Manuel Pégourié-Gonnard4ed1dab2017-08-24 11:02:04 +02002060final_norm:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002061 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV);
2062# endif
Manuel Pégourié-Gonnarda4aa89b2020-03-25 12:41:29 +01002063 /*
2064 * Knowledge of the jacobian coordinates may leak the last few bits of the
2065 * scalar [1], and since our MPI implementation isn't constant-flow,
2066 * inversion (used for coordinate normalization) may leak the full value
2067 * of its input via side-channels [2].
2068 *
2069 * [1] https://eprint.iacr.org/2003/191
2070 * [2] https://eprint.iacr.org/2020/055
2071 *
2072 * Avoid the leak by randomizing coordinates before we normalize them.
2073 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002074 if (f_rng != 0)
2075 MBEDTLS_MPI_CHK(ecp_randomize_jac(grp, RR, f_rng, p_rng));
Manuel Pégourié-Gonnarda4aa89b2020-03-25 12:41:29 +01002076
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002077 MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, RR));
Manuel Pégourié-Gonnard8962ddb2017-03-14 12:11:21 +01002078
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002079# if defined(MBEDTLS_ECP_RESTARTABLE)
2080 if (rs_ctx != NULL && rs_ctx->rsm != NULL)
2081 MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, RR));
2082# endif
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002083
2084cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002085 return ret;
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002086}
2087
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002088/*
Manuel Pégourié-Gonnard4b2336d2017-03-09 13:23:50 +01002089 * Pick window size based on curve size and whether we optimize for base point
2090 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002091static unsigned char ecp_pick_window_size(const mbedtls_ecp_group *grp,
2092 unsigned char p_eq_g)
Manuel Pégourié-Gonnard4b2336d2017-03-09 13:23:50 +01002093{
2094 unsigned char w;
2095
2096 /*
2097 * Minimize the number of multiplications, that is minimize
2098 * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w )
2099 * (see costs of the various parts, with 1S = 1M)
2100 */
2101 w = grp->nbits >= 384 ? 5 : 4;
2102
2103 /*
2104 * If P == G, pre-compute a bit more, since this may be re-used later.
2105 * Just adding one avoids upping the cost of the first mul too much,
2106 * and the memory cost too.
2107 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002108 if (p_eq_g)
Manuel Pégourié-Gonnard4b2336d2017-03-09 13:23:50 +01002109 w++;
2110
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002111 /*
2112 * If static comb table may not be used (!p_eq_g) or static comb table
2113 * does not exists, make sure w is within bounds. (The last test is
2114 * useful only for very small curves in the test suite.)
2115 *
2116 * The user reduces MBEDTLS_ECP_WINDOW_SIZE does not changes the size of
2117 * static comb table, because the size of static comb table is fixed
2118 * when it is generated.
2119 */
2120# if (MBEDTLS_ECP_WINDOW_SIZE < 6)
2121 if ((!p_eq_g || !ecp_group_is_static_comb_table(grp)) &&
2122 w > MBEDTLS_ECP_WINDOW_SIZE)
Manuel Pégourié-Gonnard4b2336d2017-03-09 13:23:50 +01002123 w = MBEDTLS_ECP_WINDOW_SIZE;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002124# endif
2125 if (w >= grp->nbits)
Manuel Pégourié-Gonnard4b2336d2017-03-09 13:23:50 +01002126 w = 2;
2127
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002128 return w;
Manuel Pégourié-Gonnard4b2336d2017-03-09 13:23:50 +01002129}
2130
2131/*
Manuel Pégourié-Gonnard07bf6f52017-03-16 17:21:38 +01002132 * Multiplication using the comb method - for curves in short Weierstrass form
2133 *
2134 * This function is mainly responsible for administrative work:
2135 * - managing the restart context if enabled
Manuel Pégourié-Gonnard11556e22017-08-24 13:41:19 +02002136 * - managing the table of precomputed points (passed between the below two
Manuel Pégourié-Gonnard07bf6f52017-03-16 17:21:38 +01002137 * functions): allocation, computation, ownership tranfer, freeing.
2138 *
2139 * It delegates the actual arithmetic work to:
2140 * ecp_precompute_comb() and ecp_mul_comb_with_precomp()
2141 *
2142 * See comments on ecp_comb_recode_core() regarding the computation strategy.
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002143 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002144static int ecp_mul_comb(mbedtls_ecp_group *grp,
2145 mbedtls_ecp_point *R,
2146 const mbedtls_mpi *m,
2147 const mbedtls_ecp_point *P,
2148 int (*f_rng)(void *, unsigned char *, size_t),
2149 void *p_rng,
2150 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002151{
Janos Follath24eed8d2019-11-22 13:21:35 +00002152 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard11556e22017-08-24 13:41:19 +02002153 unsigned char w, p_eq_g, i;
Manuel Pégourié-Gonnardd7283502013-11-21 20:00:38 +01002154 size_t d;
Manuel Pégourié-Gonnardf2a9fcf2020-06-03 12:11:56 +02002155 unsigned char T_size = 0, T_ok = 0;
2156 mbedtls_ecp_point *T = NULL;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002157
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002158 ECP_RS_ENTER(rsm);
Manuel Pégourié-Gonnard510d5ca2017-03-08 11:41:47 +01002159
Manuel Pégourié-Gonnard22be6352017-03-09 13:02:35 +01002160 /* Is P the base point ? */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002161# if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
2162 p_eq_g = (mbedtls_mpi_cmp_mpi(&P->Y, &grp->G.Y) == 0 &&
2163 mbedtls_mpi_cmp_mpi(&P->X, &grp->G.X) == 0);
2164# else
Manuel Pégourié-Gonnard196d1332017-08-28 13:14:27 +02002165 p_eq_g = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002166# endif
Manuel Pégourié-Gonnard22be6352017-03-09 13:02:35 +01002167
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002168 /* Pick window size and deduce related sizes */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002169 w = ecp_pick_window_size(grp, p_eq_g);
2170 T_size = 1U << (w - 1);
2171 d = (grp->nbits + w - 1) / w;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002172
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01002173 /* Pre-computed table: do we have it already for the base point? */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002174 if (p_eq_g && grp->T != NULL) {
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02002175 /* second pointer to the same table, will be deleted on exit */
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01002176 T = grp->T;
2177 T_ok = 1;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002178 } else
2179# if defined(MBEDTLS_ECP_RESTARTABLE)
2180 /* Pre-computed table: do we have one in progress? complete? */
2181 if (rs_ctx != NULL && rs_ctx->rsm != NULL && rs_ctx->rsm->T != NULL) {
Manuel Pégourié-Gonnard45fd0162017-03-22 08:24:42 +01002182 /* transfer ownership of T from rsm to local function */
Manuel Pégourié-Gonnard3cade222017-04-20 09:31:00 +02002183 T = rs_ctx->rsm->T;
2184 rs_ctx->rsm->T = NULL;
2185 rs_ctx->rsm->T_size = 0;
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01002186
Manuel Pégourié-Gonnardb25cb602018-10-16 11:48:09 +02002187 /* This effectively jumps to the call to mul_comb_after_precomp() */
Manuel Pégourié-Gonnard11556e22017-08-24 13:41:19 +02002188 T_ok = rs_ctx->rsm->state >= ecp_rsm_comb_core;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002189 } else
2190# endif
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01002191 /* Allocate table if we didn't have any */
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002192 {
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002193 T = mbedtls_calloc(T_size, sizeof(mbedtls_ecp_point));
2194 if (T == NULL) {
Manuel Pégourié-Gonnard6a8ca332015-05-28 09:33:39 +02002195 ret = MBEDTLS_ERR_ECP_ALLOC_FAILED;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002196 goto cleanup;
2197 }
Manuel Pégourié-Gonnard5bd38b12017-08-23 16:55:59 +02002198
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002199 for (i = 0; i < T_size; i++)
2200 mbedtls_ecp_point_init(&T[i]);
Manuel Pégourié-Gonnard11556e22017-08-24 13:41:19 +02002201
2202 T_ok = 0;
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01002203 }
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002204
Manuel Pégourié-Gonnard085b1df2017-03-16 16:56:04 +01002205 /* Compute table (or finish computing it) if not done already */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002206 if (!T_ok) {
2207 MBEDTLS_MPI_CHK(ecp_precompute_comb(grp, T, P, w, d, rs_ctx));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002208
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002209 if (p_eq_g) {
Manuel Pégourié-Gonnard7037e222017-08-23 14:30:36 +02002210 /* almost transfer ownership of T to the group, but keep a copy of
Manuel Pégourié-Gonnardee68cff2018-10-15 15:27:49 +02002211 * the pointer to use for calling the next function more easily */
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002212 grp->T = T;
Manuel Pégourié-Gonnard92cceb22017-08-23 16:27:29 +02002213 grp->T_size = T_size;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002214 }
2215 }
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002216
Manuel Pégourié-Gonnard391f4412017-03-13 12:26:21 +01002217 /* Actual comb multiplication using precomputed points */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002218 MBEDTLS_MPI_CHK(ecp_mul_comb_after_precomp(grp, R, m, T, T_size, w, d,
2219 f_rng, p_rng, rs_ctx));
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002220
2221cleanup:
2222
Manuel Pégourié-Gonnard07bf6f52017-03-16 17:21:38 +01002223 /* does T belong to the group? */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002224 if (T == grp->T)
Manuel Pégourié-Gonnard07bf6f52017-03-16 17:21:38 +01002225 T = NULL;
2226
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002227 /* does T belong to the restart context? */
2228# if defined(MBEDTLS_ECP_RESTARTABLE)
2229 if (rs_ctx != NULL && rs_ctx->rsm != NULL &&
2230 ret == MBEDTLS_ERR_ECP_IN_PROGRESS && T != NULL) {
Manuel Pégourié-Gonnard45fd0162017-03-22 08:24:42 +01002231 /* transfer ownership of T from local function to rsm */
Manuel Pégourié-Gonnard92cceb22017-08-23 16:27:29 +02002232 rs_ctx->rsm->T_size = T_size;
Manuel Pégourié-Gonnard3cade222017-04-20 09:31:00 +02002233 rs_ctx->rsm->T = T;
Manuel Pégourié-Gonnardc9c0aa62017-03-16 14:53:26 +01002234 T = NULL;
2235 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002236# endif
Manuel Pégourié-Gonnardc9c0aa62017-03-16 14:53:26 +01002237
Manuel Pégourié-Gonnard07bf6f52017-03-16 17:21:38 +01002238 /* did T belong to us? then let's destroy it! */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002239 if (T != NULL) {
2240 for (i = 0; i < T_size; i++)
2241 mbedtls_ecp_point_free(&T[i]);
2242 mbedtls_free(T);
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002243 }
2244
Manuel Pégourié-Gonnard2fad7ae2017-03-14 13:13:13 +01002245 /* don't free R while in progress in case R == P */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002246# if defined(MBEDTLS_ECP_RESTARTABLE)
2247 if (ret != MBEDTLS_ERR_ECP_IN_PROGRESS)
2248# endif
2249 /* prevent caller from using invalid value */
2250 if (ret != 0)
2251 mbedtls_ecp_point_free(R);
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002252
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002253 ECP_RS_LEAVE(rsm);
Manuel Pégourié-Gonnard77af79a2017-03-14 10:58:00 +01002254
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002255 return ret;
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002256}
2257
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002258# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +01002259
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002260# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +01002261/*
2262 * For Montgomery curves, we do all the internal arithmetic in projective
2263 * coordinates. Import/export of points uses only the x coordinates, which is
2264 * internaly represented as X / Z.
2265 *
2266 * For scalar multiplication, we'll use a Montgomery ladder.
2267 */
2268
Manuel Pégourié-Gonnardd1c1ba92013-11-16 15:50:12 +01002269/*
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002270 * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1
2271 * Cost: 1M + 1I
2272 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002273static int ecp_normalize_mxz(const mbedtls_ecp_group *grp, mbedtls_ecp_point *P)
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002274{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002275# if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT)
2276 if (mbedtls_internal_ecp_grp_capable(grp))
2277 return mbedtls_internal_ecp_normalize_mxz(grp, P);
2278# endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */
Janos Follathb0697532016-08-18 12:38:46 +01002279
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002280# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
2281 defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT)
2282 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
2283# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01002284 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002285 MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&P->Z, &P->Z, &grp->P));
2286 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &P->X, &P->X, &P->Z));
2287 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&P->Z, 1));
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002288
2289cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002290 return ret;
2291# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
2292 !defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT) */
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002293}
2294
2295/*
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002296 * Randomize projective x/z coordinates:
2297 * (X, Z) -> (l X, l Z) for random l
2298 * This is sort of the reverse operation of ecp_normalize_mxz().
2299 *
2300 * This countermeasure was first suggested in [2].
2301 * Cost: 2M
2302 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002303static int ecp_randomize_mxz(const mbedtls_ecp_group *grp,
2304 mbedtls_ecp_point *P,
2305 int (*f_rng)(void *, unsigned char *, size_t),
2306 void *p_rng)
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002307{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002308# if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT)
2309 if (mbedtls_internal_ecp_grp_capable(grp))
2310 return mbedtls_internal_ecp_randomize_mxz(grp, P, f_rng, p_rng);
2311# endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */
Janos Follathb0697532016-08-18 12:38:46 +01002312
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002313# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
2314 defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT)
2315 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
2316# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01002317 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2318 mbedtls_mpi l;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002319 mbedtls_mpi_init(&l);
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002320
2321 /* Generate l such that 1 < l < p */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002322 MBEDTLS_MPI_CHK(mbedtls_mpi_random(&l, 2, &grp->P, f_rng, p_rng));
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002323
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002324 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &P->X, &P->X, &l));
2325 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &P->Z, &P->Z, &l));
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002326
2327cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002328 mbedtls_mpi_free(&l);
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002329
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002330 if (ret == MBEDTLS_ERR_MPI_NOT_ACCEPTABLE)
Gilles Peskine59215172021-03-29 22:28:50 +02002331 ret = MBEDTLS_ERR_ECP_RANDOM_FAILED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002332 return ret;
2333# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
2334 !defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT) */
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002335}
2336
2337/*
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002338 * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q),
2339 * for Montgomery curves in x/z coordinates.
2340 *
2341 * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3
2342 * with
2343 * d = X1
2344 * P = (X2, Z2)
2345 * Q = (X3, Z3)
2346 * R = (X4, Z4)
2347 * S = (X5, Z5)
2348 * and eliminating temporary variables tO, ..., t4.
2349 *
2350 * Cost: 5M + 4S
2351 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002352static int ecp_double_add_mxz(const mbedtls_ecp_group *grp,
2353 mbedtls_ecp_point *R,
2354 mbedtls_ecp_point *S,
2355 const mbedtls_ecp_point *P,
2356 const mbedtls_ecp_point *Q,
2357 const mbedtls_mpi *d)
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002358{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002359# if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
2360 if (mbedtls_internal_ecp_grp_capable(grp))
2361 return mbedtls_internal_ecp_double_add_mxz(grp, R, S, P, Q, d);
2362# endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */
Janos Follathb0697532016-08-18 12:38:46 +01002363
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002364# if defined(MBEDTLS_ECP_NO_FALLBACK) && \
2365 defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
2366 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
2367# else
Steven Cooreman7eb2aa02021-01-22 09:43:59 +01002368 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
2369 mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB;
2370
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002371 mbedtls_mpi_init(&A);
2372 mbedtls_mpi_init(&AA);
2373 mbedtls_mpi_init(&B);
2374 mbedtls_mpi_init(&BB);
2375 mbedtls_mpi_init(&E);
2376 mbedtls_mpi_init(&C);
2377 mbedtls_mpi_init(&D);
2378 mbedtls_mpi_init(&DA);
2379 mbedtls_mpi_init(&CB);
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002380
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002381 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &A, &P->X, &P->Z));
2382 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &AA, &A, &A));
2383 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &B, &P->X, &P->Z));
2384 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &BB, &B, &B));
2385 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &E, &AA, &BB));
2386 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &C, &Q->X, &Q->Z));
2387 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &D, &Q->X, &Q->Z));
2388 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &DA, &D, &A));
2389 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &CB, &C, &B));
2390 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &S->X, &DA, &CB));
2391 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S->X, &S->X, &S->X));
2392 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mod(grp, &S->Z, &DA, &CB));
2393 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S->Z, &S->Z, &S->Z));
2394 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &S->Z, d, &S->Z));
2395 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &R->X, &AA, &BB));
2396 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &R->Z, &grp->A, &E));
2397 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &R->Z, &BB, &R->Z));
2398 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &R->Z, &E, &R->Z));
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002399
2400cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002401 mbedtls_mpi_free(&A);
2402 mbedtls_mpi_free(&AA);
2403 mbedtls_mpi_free(&B);
2404 mbedtls_mpi_free(&BB);
2405 mbedtls_mpi_free(&E);
2406 mbedtls_mpi_free(&C);
2407 mbedtls_mpi_free(&D);
2408 mbedtls_mpi_free(&DA);
2409 mbedtls_mpi_free(&CB);
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002410
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002411 return ret;
2412# endif /* !defined(MBEDTLS_ECP_NO_FALLBACK) || \
2413 !defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT) */
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002414}
2415
2416/*
Manuel Pégourié-Gonnarda0179b82013-12-04 11:49:20 +01002417 * Multiplication with Montgomery ladder in x/z coordinates,
2418 * for curves in Montgomery form
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002419 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002420static int ecp_mul_mxz(mbedtls_ecp_group *grp,
2421 mbedtls_ecp_point *R,
2422 const mbedtls_mpi *m,
2423 const mbedtls_ecp_point *P,
2424 int (*f_rng)(void *, unsigned char *, size_t),
2425 void *p_rng)
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002426{
Janos Follath24eed8d2019-11-22 13:21:35 +00002427 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002428 size_t i;
Manuel Pégourié-Gonnardb6f45a62013-12-04 21:54:36 +01002429 unsigned char b;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002430 mbedtls_ecp_point RP;
2431 mbedtls_mpi PX;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002432 mbedtls_ecp_point_init(&RP);
2433 mbedtls_mpi_init(&PX);
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002434
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002435 if (f_rng == NULL)
2436 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard02b57052021-06-15 11:29:26 +02002437
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002438 /* Save PX and read from P before writing to R, in case P == R */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002439 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&PX, &P->X));
2440 MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&RP, P));
Manuel Pégourié-Gonnard357ff652013-12-04 18:39:17 +01002441
2442 /* Set R to zero in modified x/z coordinates */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002443 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->X, 1));
2444 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&R->Z, 0));
2445 mbedtls_mpi_free(&R->Y);
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002446
Manuel Pégourié-Gonnard93f41db2013-12-05 10:48:42 +01002447 /* RP.X might be sligtly larger than P, so reduce it */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002448 MOD_ADD(RP.X);
Manuel Pégourié-Gonnard93f41db2013-12-05 10:48:42 +01002449
Manuel Pégourié-Gonnard3afa07f2013-12-03 13:28:21 +01002450 /* Randomize coordinates of the starting point */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002451 MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, &RP, f_rng, p_rng));
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002452
Manuel Pégourié-Gonnardb6f45a62013-12-04 21:54:36 +01002453 /* Loop invariant: R = result so far, RP = R + P */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002454 i = mbedtls_mpi_bitlen(m); /* one past the (zero-based) most significant bit
2455 */
2456 while (i-- > 0) {
2457 b = mbedtls_mpi_get_bit(m, i);
Manuel Pégourié-Gonnardb6f45a62013-12-04 21:54:36 +01002458 /*
2459 * if (b) R = 2R + P else R = 2R,
2460 * which is:
2461 * if (b) double_add( RP, R, RP, R )
2462 * else double_add( R, RP, R, RP )
2463 * but using safe conditional swaps to avoid leaks
2464 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002465 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->X, &RP.X, b));
2466 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->Z, &RP.Z, b));
2467 MBEDTLS_MPI_CHK(ecp_double_add_mxz(grp, R, &RP, R, &RP, &PX));
2468 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->X, &RP.X, b));
2469 MBEDTLS_MPI_CHK(mbedtls_mpi_safe_cond_swap(&R->Z, &RP.Z, b));
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002470 }
2471
Manuel Pégourié-Gonnarda4aa89b2020-03-25 12:41:29 +01002472 /*
2473 * Knowledge of the projective coordinates may leak the last few bits of the
2474 * scalar [1], and since our MPI implementation isn't constant-flow,
2475 * inversion (used for coordinate normalization) may leak the full value
2476 * of its input via side-channels [2].
2477 *
2478 * [1] https://eprint.iacr.org/2003/191
2479 * [2] https://eprint.iacr.org/2020/055
2480 *
2481 * Avoid the leak by randomizing coordinates before we normalize them.
2482 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002483 MBEDTLS_MPI_CHK(ecp_randomize_mxz(grp, R, f_rng, p_rng));
2484 MBEDTLS_MPI_CHK(ecp_normalize_mxz(grp, R));
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002485
2486cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002487 mbedtls_ecp_point_free(&RP);
2488 mbedtls_mpi_free(&PX);
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002489
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002490 return ret;
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002491}
2492
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002493# endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
Manuel Pégourié-Gonnard7c94d8b2013-12-04 23:15:46 +01002494
Manuel Pégourié-Gonnardd9ea82e72013-12-03 12:02:28 +01002495/*
Manuel Pégourié-Gonnard884569c2017-04-20 10:10:59 +02002496 * Restartable multiplication R = m * P
Manuel Pégourié-Gonnard75525ae2021-06-15 11:29:26 +02002497 *
2498 * This internal function can be called without an RNG in case where we know
2499 * the inputs are not sensitive.
Manuel Pégourié-Gonnarda0179b82013-12-04 11:49:20 +01002500 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002501static int
2502ecp_mul_restartable_internal(mbedtls_ecp_group *grp,
2503 mbedtls_ecp_point *R,
2504 const mbedtls_mpi *m,
2505 const mbedtls_ecp_point *P,
2506 int (*f_rng)(void *, unsigned char *, size_t),
2507 void *p_rng,
2508 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnarda0179b82013-12-04 11:49:20 +01002509{
Janos Follathb0697532016-08-18 12:38:46 +01002510 int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002511# if defined(MBEDTLS_ECP_INTERNAL_ALT)
Janos Follathc44ab972016-11-18 16:38:23 +00002512 char is_grp_capable = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002513# endif
Manuel Pégourié-Gonnardaa3ed6f2021-06-15 11:29:26 +02002514
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002515# if defined(MBEDTLS_ECP_RESTARTABLE)
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002516 /* reset ops count for this call if top-level */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002517 if (rs_ctx != NULL && rs_ctx->depth++ == 0)
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002518 rs_ctx->ops_done = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002519# else
2520 (void)rs_ctx;
2521# endif
Manuel Pégourié-Gonnarda0179b82013-12-04 11:49:20 +01002522
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002523# if defined(MBEDTLS_ECP_INTERNAL_ALT)
2524 if ((is_grp_capable = mbedtls_internal_ecp_grp_capable(grp)))
2525 MBEDTLS_MPI_CHK(mbedtls_internal_ecp_init(grp));
2526# endif /* MBEDTLS_ECP_INTERNAL_ALT */
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002527
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002528# if defined(MBEDTLS_ECP_RESTARTABLE)
Manuel Pégourié-Gonnarda08cd1a2017-04-20 11:29:43 +02002529 /* skip argument check when restarting */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002530 if (rs_ctx == NULL || rs_ctx->rsm == NULL)
2531# endif
Manuel Pégourié-Gonnarda08cd1a2017-04-20 11:29:43 +02002532 {
Manuel Pégourié-Gonnard5314f232017-04-21 12:36:59 +02002533 /* check_privkey is free */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002534 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_CHK);
Manuel Pégourié-Gonnard5314f232017-04-21 12:36:59 +02002535
Manuel Pégourié-Gonnarda08cd1a2017-04-20 11:29:43 +02002536 /* Common sanity checks */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002537 MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(grp, m));
2538 MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, P));
Manuel Pégourié-Gonnarda08cd1a2017-04-20 11:29:43 +02002539 }
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002540
2541 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002542# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
2543 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY)
2544 MBEDTLS_MPI_CHK(ecp_mul_mxz(grp, R, m, P, f_rng, p_rng));
2545# endif
2546# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
2547 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS)
2548 MBEDTLS_MPI_CHK(ecp_mul_comb(grp, R, m, P, f_rng, p_rng, rs_ctx));
2549# endif
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002550
Janos Follath6c8ccd52016-11-29 15:37:09 +00002551cleanup:
Janos Follathb0697532016-08-18 12:38:46 +01002552
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002553# if defined(MBEDTLS_ECP_INTERNAL_ALT)
2554 if (is_grp_capable)
2555 mbedtls_internal_ecp_free(grp);
2556# endif /* MBEDTLS_ECP_INTERNAL_ALT */
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002557
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002558# if defined(MBEDTLS_ECP_RESTARTABLE)
2559 if (rs_ctx != NULL)
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002560 rs_ctx->depth--;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002561# endif
Manuel Pégourié-Gonnard3a256122017-04-20 11:20:26 +02002562
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002563 return ret;
Manuel Pégourié-Gonnarda0179b82013-12-04 11:49:20 +01002564}
2565
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +02002566/*
Manuel Pégourié-Gonnard75525ae2021-06-15 11:29:26 +02002567 * Restartable multiplication R = m * P
2568 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002569int mbedtls_ecp_mul_restartable(mbedtls_ecp_group *grp,
2570 mbedtls_ecp_point *R,
2571 const mbedtls_mpi *m,
2572 const mbedtls_ecp_point *P,
2573 int (*f_rng)(void *, unsigned char *, size_t),
2574 void *p_rng,
2575 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnard75525ae2021-06-15 11:29:26 +02002576{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002577 ECP_VALIDATE_RET(grp != NULL);
2578 ECP_VALIDATE_RET(R != NULL);
2579 ECP_VALIDATE_RET(m != NULL);
2580 ECP_VALIDATE_RET(P != NULL);
Manuel Pégourié-Gonnard75525ae2021-06-15 11:29:26 +02002581
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002582 if (f_rng == NULL)
2583 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard75525ae2021-06-15 11:29:26 +02002584
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002585 return ecp_mul_restartable_internal(grp, R, m, P, f_rng, p_rng, rs_ctx);
Manuel Pégourié-Gonnard75525ae2021-06-15 11:29:26 +02002586}
2587
2588/*
Manuel Pégourié-Gonnard884569c2017-04-20 10:10:59 +02002589 * Multiplication R = m * P
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +02002590 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002591int mbedtls_ecp_mul(mbedtls_ecp_group *grp,
2592 mbedtls_ecp_point *R,
2593 const mbedtls_mpi *m,
2594 const mbedtls_ecp_point *P,
2595 int (*f_rng)(void *, unsigned char *, size_t),
2596 void *p_rng)
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +02002597{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002598 ECP_VALIDATE_RET(grp != NULL);
2599 ECP_VALIDATE_RET(R != NULL);
2600 ECP_VALIDATE_RET(m != NULL);
2601 ECP_VALIDATE_RET(P != NULL);
2602 return mbedtls_ecp_mul_restartable(grp, R, m, P, f_rng, p_rng, NULL);
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +02002603}
Manuel Pégourié-Gonnardb739a712017-04-19 10:11:56 +02002604
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002605# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
Manuel Pégourié-Gonnarda0179b82013-12-04 11:49:20 +01002606/*
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002607 * Check that an affine point is valid as a public key,
2608 * short weierstrass curves (SEC1 3.2.3.1)
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002609 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002610static int ecp_check_pubkey_sw(const mbedtls_ecp_group *grp,
2611 const mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002612{
Janos Follath24eed8d2019-11-22 13:21:35 +00002613 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002614 mbedtls_mpi YY, RHS;
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002615
Manuel Pégourié-Gonnard312d2e82013-12-04 11:08:01 +01002616 /* pt coordinates must be normalized for our checks */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002617 if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0 ||
2618 mbedtls_mpi_cmp_int(&pt->Y, 0) < 0 ||
2619 mbedtls_mpi_cmp_mpi(&pt->X, &grp->P) >= 0 ||
2620 mbedtls_mpi_cmp_mpi(&pt->Y, &grp->P) >= 0)
2621 return MBEDTLS_ERR_ECP_INVALID_KEY;
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002622
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002623 mbedtls_mpi_init(&YY);
2624 mbedtls_mpi_init(&RHS);
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002625
2626 /*
2627 * YY = Y^2
Manuel Pégourié-Gonnardcd7458a2013-10-08 13:11:30 +02002628 * RHS = X (X^2 + A) + B = X^3 + A X + B
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002629 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002630 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &YY, &pt->Y, &pt->Y));
2631 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &RHS, &pt->X, &pt->X));
Manuel Pégourié-Gonnard73cc01d2013-12-06 12:41:30 +01002632
2633 /* Special case for A = -3 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002634 if (grp->A.p == NULL) {
2635 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&RHS, &RHS, 3));
2636 MOD_SUB(RHS);
2637 } else {
2638 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &RHS, &RHS, &grp->A));
Manuel Pégourié-Gonnard73cc01d2013-12-06 12:41:30 +01002639 }
2640
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002641 MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mod(grp, &RHS, &RHS, &pt->X));
2642 MBEDTLS_MPI_CHK(mbedtls_mpi_add_mod(grp, &RHS, &RHS, &grp->B));
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002643
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002644 if (mbedtls_mpi_cmp_mpi(&YY, &RHS) != 0)
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002645 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002646
2647cleanup:
2648
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002649 mbedtls_mpi_free(&YY);
2650 mbedtls_mpi_free(&RHS);
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002651
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002652 return ret;
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002653}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002654# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002655
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002656# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002657/*
TRodziewicz9edff742021-03-04 17:59:39 +01002658 * R = m * P with shortcuts for m == 0, m == 1 and m == -1
Manuel Pégourié-Gonnardde9f9532015-10-23 15:50:37 +02002659 * NOT constant-time - ONLY for short Weierstrass!
2660 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002661static int mbedtls_ecp_mul_shortcuts(mbedtls_ecp_group *grp,
2662 mbedtls_ecp_point *R,
2663 const mbedtls_mpi *m,
2664 const mbedtls_ecp_point *P,
2665 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnardde9f9532015-10-23 15:50:37 +02002666{
Janos Follath24eed8d2019-11-22 13:21:35 +00002667 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnardde9f9532015-10-23 15:50:37 +02002668
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002669 if (mbedtls_mpi_cmp_int(m, 0) == 0) {
2670 MBEDTLS_MPI_CHK(mbedtls_ecp_set_zero(R));
2671 } else if (mbedtls_mpi_cmp_int(m, 1) == 0) {
2672 MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P));
2673 } else if (mbedtls_mpi_cmp_int(m, -1) == 0) {
2674 MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P));
2675 if (mbedtls_mpi_cmp_int(&R->Y, 0) != 0)
2676 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&R->Y, &grp->P, &R->Y));
2677 } else {
2678 MBEDTLS_MPI_CHK(
2679 ecp_mul_restartable_internal(grp, R, m, P, NULL, NULL, rs_ctx));
Manuel Pégourié-Gonnardde9f9532015-10-23 15:50:37 +02002680 }
2681
2682cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002683 return ret;
Manuel Pégourié-Gonnardde9f9532015-10-23 15:50:37 +02002684}
2685
2686/*
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +02002687 * Restartable linear combination
Manuel Pégourié-Gonnardde9f9532015-10-23 15:50:37 +02002688 * NOT constant-time
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002689 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002690int mbedtls_ecp_muladd_restartable(mbedtls_ecp_group *grp,
2691 mbedtls_ecp_point *R,
2692 const mbedtls_mpi *m,
2693 const mbedtls_ecp_point *P,
2694 const mbedtls_mpi *n,
2695 const mbedtls_ecp_point *Q,
2696 mbedtls_ecp_restart_ctx *rs_ctx)
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002697{
Janos Follath24eed8d2019-11-22 13:21:35 +00002698 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002699 mbedtls_ecp_point mP;
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002700 mbedtls_ecp_point *pmP = &mP;
2701 mbedtls_ecp_point *pR = R;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002702# if defined(MBEDTLS_ECP_INTERNAL_ALT)
Janos Follathc44ab972016-11-18 16:38:23 +00002703 char is_grp_capable = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002704# endif
2705 ECP_VALIDATE_RET(grp != NULL);
2706 ECP_VALIDATE_RET(R != NULL);
2707 ECP_VALIDATE_RET(m != NULL);
2708 ECP_VALIDATE_RET(P != NULL);
2709 ECP_VALIDATE_RET(n != NULL);
2710 ECP_VALIDATE_RET(Q != NULL);
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002711
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002712 if (mbedtls_ecp_get_type(grp) != MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS)
2713 return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002714
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002715 mbedtls_ecp_point_init(&mP);
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002716
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002717 ECP_RS_ENTER(ma);
Manuel Pégourié-Gonnarddb4a8eb2017-08-23 18:18:22 +02002718
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002719# if defined(MBEDTLS_ECP_RESTARTABLE)
2720 if (rs_ctx != NULL && rs_ctx->ma != NULL) {
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002721 /* redirect intermediate results to restart context */
2722 pmP = &rs_ctx->ma->mP;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002723 pR = &rs_ctx->ma->R;
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002724
2725 /* jump to next operation */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002726 if (rs_ctx->ma->state == ecp_rsma_mul2)
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002727 goto mul2;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002728 if (rs_ctx->ma->state == ecp_rsma_add)
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002729 goto add;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002730 if (rs_ctx->ma->state == ecp_rsma_norm)
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002731 goto norm;
2732 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002733# endif /* MBEDTLS_ECP_RESTARTABLE */
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +02002734
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002735 MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pmP, m, P, rs_ctx));
2736# if defined(MBEDTLS_ECP_RESTARTABLE)
2737 if (rs_ctx != NULL && rs_ctx->ma != NULL)
Manuel Pégourié-Gonnardc9efa002017-08-24 10:25:06 +02002738 rs_ctx->ma->state = ecp_rsma_mul2;
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002739
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002740mul2:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002741# endif
2742 MBEDTLS_MPI_CHK(mbedtls_ecp_mul_shortcuts(grp, pR, n, Q, rs_ctx));
Andrzej Kurekc470b6b2019-01-31 08:20:20 -05002743
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002744# if defined(MBEDTLS_ECP_INTERNAL_ALT)
2745 if ((is_grp_capable = mbedtls_internal_ecp_grp_capable(grp)))
2746 MBEDTLS_MPI_CHK(mbedtls_internal_ecp_init(grp));
2747# endif /* MBEDTLS_ECP_INTERNAL_ALT */
Andrzej Kurekc470b6b2019-01-31 08:20:20 -05002748
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002749# if defined(MBEDTLS_ECP_RESTARTABLE)
2750 if (rs_ctx != NULL && rs_ctx->ma != NULL)
Manuel Pégourié-Gonnardc9efa002017-08-24 10:25:06 +02002751 rs_ctx->ma->state = ecp_rsma_add;
Manuel Pégourié-Gonnard1a7c5ef2015-08-13 10:19:09 +02002752
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002753add:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002754# endif
2755 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_ADD);
2756 MBEDTLS_MPI_CHK(ecp_add_mixed(grp, pR, pmP, pR));
2757# if defined(MBEDTLS_ECP_RESTARTABLE)
2758 if (rs_ctx != NULL && rs_ctx->ma != NULL)
Manuel Pégourié-Gonnardc9efa002017-08-24 10:25:06 +02002759 rs_ctx->ma->state = ecp_rsma_norm;
Janos Follath430d3372016-11-03 14:25:37 +00002760
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002761norm:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002762# endif
2763 MBEDTLS_ECP_BUDGET(MBEDTLS_ECP_OPS_INV);
2764 MBEDTLS_MPI_CHK(ecp_normalize_jac(grp, pR));
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002765
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002766# if defined(MBEDTLS_ECP_RESTARTABLE)
2767 if (rs_ctx != NULL && rs_ctx->ma != NULL)
2768 MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, pR));
2769# endif
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002770
2771cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002772# if defined(MBEDTLS_ECP_INTERNAL_ALT)
2773 if (is_grp_capable)
2774 mbedtls_internal_ecp_free(grp);
2775# endif /* MBEDTLS_ECP_INTERNAL_ALT */
Manuel Pégourié-Gonnard1631d632017-04-20 14:48:56 +02002776
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002777 mbedtls_ecp_point_free(&mP);
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002778
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002779 ECP_RS_LEAVE(ma);
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +02002780
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002781 return ret;
Manuel Pégourié-Gonnard56cc88a2015-05-11 18:40:45 +02002782}
2783
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +02002784/*
2785 * Linear combination
2786 * NOT constant-time
2787 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002788int mbedtls_ecp_muladd(mbedtls_ecp_group *grp,
2789 mbedtls_ecp_point *R,
2790 const mbedtls_mpi *m,
2791 const mbedtls_ecp_point *P,
2792 const mbedtls_mpi *n,
2793 const mbedtls_ecp_point *Q)
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +02002794{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002795 ECP_VALIDATE_RET(grp != NULL);
2796 ECP_VALIDATE_RET(R != NULL);
2797 ECP_VALIDATE_RET(m != NULL);
2798 ECP_VALIDATE_RET(P != NULL);
2799 ECP_VALIDATE_RET(n != NULL);
2800 ECP_VALIDATE_RET(Q != NULL);
2801 return mbedtls_ecp_muladd_restartable(grp, R, m, P, n, Q, NULL);
Manuel Pégourié-Gonnard54dd6522017-04-20 13:36:18 +02002802}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002803# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002804
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002805# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
2806# if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
2807# define ECP_MPI_INIT(s, n, p) \
2808 { \
2809 s, (n), (mbedtls_mpi_uint *)(p) \
2810 }
2811# define ECP_MPI_INIT_ARRAY(x) \
2812 ECP_MPI_INIT(1, sizeof(x) / sizeof(mbedtls_mpi_uint), x)
Manuel Pégourié-Gonnard06215ea2021-06-23 12:53:18 +02002813/*
2814 * Constants for the two points other than 0, 1, -1 (mod p) in
2815 * https://cr.yp.to/ecdh.html#validate
2816 * See ecp_check_pubkey_x25519().
2817 */
2818static const mbedtls_mpi_uint x25519_bad_point_1[] = {
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002819 MBEDTLS_BYTES_TO_T_UINT_8(0xe0, 0xeb, 0x7a, 0x7c, 0x3b, 0x41, 0xb8, 0xae),
2820 MBEDTLS_BYTES_TO_T_UINT_8(0x16, 0x56, 0xe3, 0xfa, 0xf1, 0x9f, 0xc4, 0x6a),
2821 MBEDTLS_BYTES_TO_T_UINT_8(0xda, 0x09, 0x8d, 0xeb, 0x9c, 0x32, 0xb1, 0xfd),
2822 MBEDTLS_BYTES_TO_T_UINT_8(0x86, 0x62, 0x05, 0x16, 0x5f, 0x49, 0xb8, 0x00),
Manuel Pégourié-Gonnard06215ea2021-06-23 12:53:18 +02002823};
2824static const mbedtls_mpi_uint x25519_bad_point_2[] = {
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002825 MBEDTLS_BYTES_TO_T_UINT_8(0x5f, 0x9c, 0x95, 0xbc, 0xa3, 0x50, 0x8c, 0x24),
2826 MBEDTLS_BYTES_TO_T_UINT_8(0xb1, 0xd0, 0xb1, 0x55, 0x9c, 0x83, 0xef, 0x5b),
2827 MBEDTLS_BYTES_TO_T_UINT_8(0x04, 0x44, 0x5c, 0xc4, 0x58, 0x1c, 0x8e, 0x86),
2828 MBEDTLS_BYTES_TO_T_UINT_8(0xd8, 0x22, 0x4e, 0xdd, 0xd0, 0x9f, 0x11, 0x57),
Manuel Pégourié-Gonnard06215ea2021-06-23 12:53:18 +02002829};
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002830static const mbedtls_mpi ecp_x25519_bad_point_1 =
2831 ECP_MPI_INIT_ARRAY(x25519_bad_point_1);
2832static const mbedtls_mpi ecp_x25519_bad_point_2 =
2833 ECP_MPI_INIT_ARRAY(x25519_bad_point_2);
2834# endif /* MBEDTLS_ECP_DP_CURVE25519_ENABLED */
Manuel Pégourié-Gonnard2389a602021-06-23 12:25:48 +02002835
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002836/*
2837 * Check that the input point is not one of the low-order points.
2838 * This is recommended by the "May the Fourth" paper:
2839 * https://eprint.iacr.org/2017/806.pdf
2840 * Those points are never sent by an honest peer.
2841 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002842static int ecp_check_bad_points_mx(const mbedtls_mpi *X,
2843 const mbedtls_mpi *P,
2844 const mbedtls_ecp_group_id grp_id)
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002845{
2846 int ret;
Manuel Pégourié-Gonnard2389a602021-06-23 12:25:48 +02002847 mbedtls_mpi XmP;
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002848
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002849 mbedtls_mpi_init(&XmP);
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002850
2851 /* Reduce X mod P so that we only need to check values less than P.
2852 * We know X < 2^256 so we can proceed by subtraction. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002853 MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&XmP, X));
2854 while (mbedtls_mpi_cmp_mpi(&XmP, P) >= 0)
2855 MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&XmP, &XmP, P));
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002856
Janos Follath865a75e2021-06-24 15:34:59 +01002857 /* Check against the known bad values that are less than P. For Curve448
2858 * these are 0, 1 and -1. For Curve25519 we check the values less than P
2859 * from the following list: https://cr.yp.to/ecdh.html#validate */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002860 if (mbedtls_mpi_cmp_int(&XmP, 1) <= 0) /* takes care of 0 and 1 */
Janos Follath8081ced2021-06-24 14:24:13 +01002861 {
2862 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
2863 goto cleanup;
2864 }
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002865
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002866# if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
2867 if (grp_id == MBEDTLS_ECP_DP_CURVE25519) {
2868 if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_1) == 0) {
Janos Follath865a75e2021-06-24 15:34:59 +01002869 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
2870 goto cleanup;
2871 }
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002872
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002873 if (mbedtls_mpi_cmp_mpi(&XmP, &ecp_x25519_bad_point_2) == 0) {
Janos Follath865a75e2021-06-24 15:34:59 +01002874 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
2875 goto cleanup;
2876 }
Janos Follath8081ced2021-06-24 14:24:13 +01002877 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002878# else
2879 (void)grp_id;
2880# endif
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002881
Manuel Pégourié-Gonnard2389a602021-06-23 12:25:48 +02002882 /* Final check: check if XmP + 1 is P (final because it changes XmP!) */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002883 MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&XmP, &XmP, 1));
2884 if (mbedtls_mpi_cmp_mpi(&XmP, P) == 0) {
Janos Follath8081ced2021-06-24 14:24:13 +01002885 ret = MBEDTLS_ERR_ECP_INVALID_KEY;
2886 goto cleanup;
2887 }
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002888
2889 ret = 0;
2890
2891cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002892 mbedtls_mpi_free(&XmP);
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002893
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002894 return ret;
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002895}
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002896
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002897/*
2898 * Check validity of a public key for Montgomery curves with x-only schemes
2899 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002900static int ecp_check_pubkey_mx(const mbedtls_ecp_group *grp,
2901 const mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002902{
Manuel Pégourié-Gonnard07894332015-06-23 00:18:41 +02002903 /* [Curve25519 p. 5] Just check X is the correct number of bytes */
Nicholas Wilson08f3ef12015-11-10 13:10:01 +00002904 /* Allow any public value, if it's too big then we'll just reduce it mod p
2905 * (RFC 7748 sec. 5 para. 3). */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002906 if (mbedtls_mpi_size(&pt->X) > (grp->nbits + 7) / 8)
2907 return MBEDTLS_ERR_ECP_INVALID_KEY;
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002908
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002909 /* Implicit in all standards (as they don't consider negative numbers):
2910 * X must be non-negative. This is normally ensured by the way it's
2911 * encoded for transmission, but let's be extra sure. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002912 if (mbedtls_mpi_cmp_int(&pt->X, 0) < 0)
2913 return MBEDTLS_ERR_ECP_INVALID_KEY;
Manuel Pégourié-Gonnardf29857c2021-06-23 10:14:58 +02002914
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002915 return ecp_check_bad_points_mx(&pt->X, &grp->P, grp->id);
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002916}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002917# endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002918
2919/*
2920 * Check that a point is valid as a public key
2921 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002922int mbedtls_ecp_check_pubkey(const mbedtls_ecp_group *grp,
2923 const mbedtls_ecp_point *pt)
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002924{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002925 ECP_VALIDATE_RET(grp != NULL);
2926 ECP_VALIDATE_RET(pt != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -05002927
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002928 /* Must use affine coordinates */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002929 if (mbedtls_mpi_cmp_int(&pt->Z, 1) != 0)
2930 return MBEDTLS_ERR_ECP_INVALID_KEY;
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002931
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002932# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
2933 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY)
2934 return ecp_check_pubkey_mx(grp, pt);
2935# endif
2936# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
2937 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS)
2938 return ecp_check_pubkey_sw(grp, pt);
2939# endif
2940 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002941}
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002942
2943/*
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02002944 * Check that an mbedtls_mpi is valid as a private key
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002945 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002946int mbedtls_ecp_check_privkey(const mbedtls_ecp_group *grp,
2947 const mbedtls_mpi *d)
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002948{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002949 ECP_VALIDATE_RET(grp != NULL);
2950 ECP_VALIDATE_RET(d != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -05002951
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002952# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
2953 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
Nicholas Wilson08f3ef12015-11-10 13:10:01 +00002954 /* see RFC 7748 sec. 5 para. 5 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002955 if (mbedtls_mpi_get_bit(d, 0) != 0 || mbedtls_mpi_get_bit(d, 1) != 0 ||
2956 mbedtls_mpi_bitlen(d) - 1 != grp->nbits) /* mbedtls_mpi_bitlen is
2957 one-based! */
2958 return MBEDTLS_ERR_ECP_INVALID_KEY;
Nicholas Wilson08f3ef12015-11-10 13:10:01 +00002959
2960 /* see [Curve25519] page 5 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002961 if (grp->nbits == 254 && mbedtls_mpi_get_bit(d, 2) != 0)
2962 return MBEDTLS_ERR_ECP_INVALID_KEY;
Nicholas Wilson08f3ef12015-11-10 13:10:01 +00002963
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002964 return 0;
Manuel Pégourié-Gonnard312d2e82013-12-04 11:08:01 +01002965 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002966# endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
2967# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
2968 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
Manuel Pégourié-Gonnard312d2e82013-12-04 11:08:01 +01002969 /* see SEC1 3.2 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002970 if (mbedtls_mpi_cmp_int(d, 1) < 0 ||
2971 mbedtls_mpi_cmp_mpi(d, &grp->N) >= 0)
2972 return MBEDTLS_ERR_ECP_INVALID_KEY;
Manuel Pégourié-Gonnardd9622732013-12-05 10:06:06 +01002973 else
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002974 return 0;
Manuel Pégourié-Gonnard312d2e82013-12-04 11:08:01 +01002975 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002976# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002977
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002978 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02002979}
2980
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002981# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
Gilles Peskine72fcc982021-03-23 22:31:31 +01002982MBEDTLS_STATIC_TESTABLE
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002983int mbedtls_ecp_gen_privkey_mx(size_t high_bit,
2984 mbedtls_mpi *d,
2985 int (*f_rng)(void *, unsigned char *, size_t),
2986 void *p_rng)
Gilles Peskine72fcc982021-03-23 22:31:31 +01002987{
2988 int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Gilles Peskine61f1f5f2021-03-24 12:46:46 +01002989 size_t n_random_bytes = high_bit / 8 + 1;
Gilles Peskine72fcc982021-03-23 22:31:31 +01002990
2991 /* [Curve25519] page 5 */
Gilles Peskine61f1f5f2021-03-24 12:46:46 +01002992 /* Generate a (high_bit+1)-bit random number by generating just enough
2993 * random bytes, then shifting out extra bits from the top (necessary
2994 * when (high_bit+1) is not a multiple of 8). */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002995 MBEDTLS_MPI_CHK(mbedtls_mpi_fill_random(d, n_random_bytes, f_rng, p_rng));
2996 MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(d, 8 * n_random_bytes - high_bit - 1));
Gilles Peskine72fcc982021-03-23 22:31:31 +01002997
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02002998 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, high_bit, 1));
Gilles Peskine72fcc982021-03-23 22:31:31 +01002999
3000 /* Make sure the last two bits are unset for Curve448, three bits for
3001 Curve25519 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003002 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 0, 0));
3003 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 1, 0));
3004 if (high_bit == 254) {
3005 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(d, 2, 0));
Gilles Peskine72fcc982021-03-23 22:31:31 +01003006 }
3007
3008cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003009 return ret;
Gilles Peskine72fcc982021-03-23 22:31:31 +01003010}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003011# endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
Gilles Peskine72fcc982021-03-23 22:31:31 +01003012
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003013# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
3014static int
3015mbedtls_ecp_gen_privkey_sw(const mbedtls_mpi *N,
3016 mbedtls_mpi *d,
3017 int (*f_rng)(void *, unsigned char *, size_t),
3018 void *p_rng)
Gilles Peskine60d8b982021-03-29 22:28:21 +02003019{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003020 int ret = mbedtls_mpi_random(d, 1, N, f_rng, p_rng);
3021 switch (ret) {
Gilles Peskine60d8b982021-03-29 22:28:21 +02003022 case MBEDTLS_ERR_MPI_NOT_ACCEPTABLE:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003023 return MBEDTLS_ERR_ECP_RANDOM_FAILED;
Gilles Peskine60d8b982021-03-29 22:28:21 +02003024 default:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003025 return ret;
Gilles Peskine60d8b982021-03-29 22:28:21 +02003026 }
3027}
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003028# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
Gilles Peskine60d8b982021-03-29 22:28:21 +02003029
Manuel Pégourié-Gonnardc8dc2952013-07-01 14:06:13 +02003030/*
Manuel Pégourié-Gonnarda7937f92017-04-20 15:37:46 +02003031 * Generate a private key
Manuel Pégourié-Gonnard45a035a2013-01-26 14:42:45 +01003032 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003033int mbedtls_ecp_gen_privkey(const mbedtls_ecp_group *grp,
3034 mbedtls_mpi *d,
3035 int (*f_rng)(void *, unsigned char *, size_t),
3036 void *p_rng)
Manuel Pégourié-Gonnard45a035a2013-01-26 14:42:45 +01003037{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003038 ECP_VALIDATE_RET(grp != NULL);
3039 ECP_VALIDATE_RET(d != NULL);
3040 ECP_VALIDATE_RET(f_rng != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -05003041
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003042# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
3043 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_MONTGOMERY)
3044 return mbedtls_ecp_gen_privkey_mx(grp->nbits, d, f_rng, p_rng);
3045# endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
Manuel Pégourié-Gonnarda7937f92017-04-20 15:37:46 +02003046
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003047# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
3048 if (mbedtls_ecp_get_type(grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS)
3049 return mbedtls_ecp_gen_privkey_sw(&grp->N, d, f_rng, p_rng);
3050# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
Manuel Pégourié-Gonnard45a035a2013-01-26 14:42:45 +01003051
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003052 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnarda7937f92017-04-20 15:37:46 +02003053}
Manuel Pégourié-Gonnardc9573992014-01-03 12:54:00 +01003054
Manuel Pégourié-Gonnarda7937f92017-04-20 15:37:46 +02003055/*
3056 * Generate a keypair with configurable base point
3057 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003058int mbedtls_ecp_gen_keypair_base(mbedtls_ecp_group *grp,
3059 const mbedtls_ecp_point *G,
3060 mbedtls_mpi *d,
3061 mbedtls_ecp_point *Q,
3062 int (*f_rng)(void *, unsigned char *, size_t),
3063 void *p_rng)
Manuel Pégourié-Gonnarda7937f92017-04-20 15:37:46 +02003064{
Janos Follath24eed8d2019-11-22 13:21:35 +00003065 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003066 ECP_VALIDATE_RET(grp != NULL);
3067 ECP_VALIDATE_RET(d != NULL);
3068 ECP_VALIDATE_RET(G != NULL);
3069 ECP_VALIDATE_RET(Q != NULL);
3070 ECP_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnarda7937f92017-04-20 15:37:46 +02003071
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003072 MBEDTLS_MPI_CHK(mbedtls_ecp_gen_privkey(grp, d, f_rng, p_rng));
3073 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, Q, d, G, f_rng, p_rng));
Manuel Pégourié-Gonnarda7937f92017-04-20 15:37:46 +02003074
3075cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003076 return ret;
Manuel Pégourié-Gonnardd9a3f472015-08-11 14:31:03 +02003077}
3078
3079/*
3080 * Generate key pair, wrapper for conventional base point
3081 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003082int mbedtls_ecp_gen_keypair(mbedtls_ecp_group *grp,
3083 mbedtls_mpi *d,
3084 mbedtls_ecp_point *Q,
3085 int (*f_rng)(void *, unsigned char *, size_t),
3086 void *p_rng)
Manuel Pégourié-Gonnardd9a3f472015-08-11 14:31:03 +02003087{
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003088 ECP_VALIDATE_RET(grp != NULL);
3089 ECP_VALIDATE_RET(d != NULL);
3090 ECP_VALIDATE_RET(Q != NULL);
3091 ECP_VALIDATE_RET(f_rng != NULL);
Andrzej Kurekc470b6b2019-01-31 08:20:20 -05003092
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003093 return mbedtls_ecp_gen_keypair_base(grp, &grp->G, d, Q, f_rng, p_rng);
Manuel Pégourié-Gonnard45a035a2013-01-26 14:42:45 +01003094}
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +01003095
Manuel Pégourié-Gonnard104ee1d2013-11-30 14:13:16 +01003096/*
3097 * Generate a keypair, prettier wrapper
3098 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003099int mbedtls_ecp_gen_key(mbedtls_ecp_group_id grp_id,
3100 mbedtls_ecp_keypair *key,
3101 int (*f_rng)(void *, unsigned char *, size_t),
3102 void *p_rng)
Manuel Pégourié-Gonnard104ee1d2013-11-30 14:13:16 +01003103{
Janos Follath24eed8d2019-11-22 13:21:35 +00003104 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003105 ECP_VALIDATE_RET(key != NULL);
3106 ECP_VALIDATE_RET(f_rng != NULL);
Manuel Pégourié-Gonnard104ee1d2013-11-30 14:13:16 +01003107
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003108 if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0)
3109 return ret;
Manuel Pégourié-Gonnard104ee1d2013-11-30 14:13:16 +01003110
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003111 return mbedtls_ecp_gen_keypair(&key->grp, &key->d, &key->Q, f_rng, p_rng);
Manuel Pégourié-Gonnard104ee1d2013-11-30 14:13:16 +01003112}
3113
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003114# define ECP_CURVE25519_KEY_SIZE 32
3115# define ECP_CURVE448_KEY_SIZE 56
Janos Follath171a7ef2019-02-15 16:17:45 +00003116/*
3117 * Read a private key.
3118 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003119int mbedtls_ecp_read_key(mbedtls_ecp_group_id grp_id,
3120 mbedtls_ecp_keypair *key,
3121 const unsigned char *buf,
3122 size_t buflen)
Janos Follath171a7ef2019-02-15 16:17:45 +00003123{
3124 int ret = 0;
3125
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003126 ECP_VALIDATE_RET(key != NULL);
3127 ECP_VALIDATE_RET(buf != NULL);
Janos Follath28eb06d2019-02-26 10:53:34 +00003128
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003129 if ((ret = mbedtls_ecp_group_load(&key->grp, grp_id)) != 0)
3130 return ret;
Janos Follath171a7ef2019-02-15 16:17:45 +00003131
Janos Follath28eb06d2019-02-26 10:53:34 +00003132 ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
3133
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003134# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
3135 if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
Janos Follath28eb06d2019-02-26 10:53:34 +00003136 /*
Archana1d2e2bb2021-06-07 06:13:16 +05303137 * Mask the key as mandated by RFC7748 for Curve25519 and Curve448.
Janos Follath28eb06d2019-02-26 10:53:34 +00003138 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003139 if (grp_id == MBEDTLS_ECP_DP_CURVE25519) {
3140 if (buflen != ECP_CURVE25519_KEY_SIZE)
3141 return MBEDTLS_ERR_ECP_INVALID_KEY;
Janos Follath171a7ef2019-02-15 16:17:45 +00003142
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003143 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen));
Janos Follath171a7ef2019-02-15 16:17:45 +00003144
Janos Follath28eb06d2019-02-26 10:53:34 +00003145 /* Set the three least significant bits to 0 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003146 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0));
3147 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0));
3148 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 2, 0));
Janos Follath171a7ef2019-02-15 16:17:45 +00003149
Janos Follath28eb06d2019-02-26 10:53:34 +00003150 /* Set the most significant bit to 0 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003151 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(
3152 &key->d, ECP_CURVE25519_KEY_SIZE * 8 - 1, 0));
Janos Follath171a7ef2019-02-15 16:17:45 +00003153
Janos Follath28eb06d2019-02-26 10:53:34 +00003154 /* Set the second most significant bit to 1 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003155 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(
3156 &key->d, ECP_CURVE25519_KEY_SIZE * 8 - 2, 1));
3157 } else if (grp_id == MBEDTLS_ECP_DP_CURVE448) {
3158 if (buflen != ECP_CURVE448_KEY_SIZE)
3159 return MBEDTLS_ERR_ECP_INVALID_KEY;
Archana1d2e2bb2021-06-07 06:13:16 +05303160
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003161 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&key->d, buf, buflen));
Archana1d2e2bb2021-06-07 06:13:16 +05303162
3163 /* Set the two least significant bits to 0 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003164 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 0, 0));
3165 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(&key->d, 1, 0));
Archana1d2e2bb2021-06-07 06:13:16 +05303166
3167 /* Set the most significant bit to 1 */
3168 MBEDTLS_MPI_CHK(
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003169 mbedtls_mpi_set_bit(&key->d, ECP_CURVE448_KEY_SIZE * 8 - 1, 1));
Archana1d2e2bb2021-06-07 06:13:16 +05303170 }
Janos Follath171a7ef2019-02-15 16:17:45 +00003171 }
3172
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003173# endif
3174# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
3175 if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
3176 MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&key->d, buf, buflen));
Janos Follath171a7ef2019-02-15 16:17:45 +00003177
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003178 MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(&key->grp, &key->d));
Janos Follath171a7ef2019-02-15 16:17:45 +00003179 }
3180
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003181# endif
Janos Follath171a7ef2019-02-15 16:17:45 +00003182cleanup:
3183
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003184 if (ret != 0)
3185 mbedtls_mpi_free(&key->d);
Janos Follath171a7ef2019-02-15 16:17:45 +00003186
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003187 return ret;
Janos Follath171a7ef2019-02-15 16:17:45 +00003188}
3189
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003190/*
Steven Cooremande8593f2020-06-09 19:55:26 +02003191 * Write a private key.
3192 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003193int mbedtls_ecp_write_key(mbedtls_ecp_keypair *key,
3194 unsigned char *buf,
3195 size_t buflen)
Steven Cooremande8593f2020-06-09 19:55:26 +02003196{
Steven Cooreman0024df62020-07-13 10:59:40 +02003197 int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
Steven Cooremande8593f2020-06-09 19:55:26 +02003198
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003199 ECP_VALIDATE_RET(key != NULL);
3200 ECP_VALIDATE_RET(buf != NULL);
Steven Cooremande8593f2020-06-09 19:55:26 +02003201
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003202# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
3203 if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_MONTGOMERY) {
3204 if (key->grp.id == MBEDTLS_ECP_DP_CURVE25519) {
3205 if (buflen < ECP_CURVE25519_KEY_SIZE)
3206 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
Steven Cooremande8593f2020-06-09 19:55:26 +02003207
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003208 } else if (key->grp.id == MBEDTLS_ECP_DP_CURVE448) {
3209 if (buflen < ECP_CURVE448_KEY_SIZE)
3210 return MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL;
Steven Cooremande8593f2020-06-09 19:55:26 +02003211 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003212 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&key->d, buf, buflen));
Steven Cooremande8593f2020-06-09 19:55:26 +02003213 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003214# endif
3215# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
3216 if (mbedtls_ecp_get_type(&key->grp) == MBEDTLS_ECP_TYPE_SHORT_WEIERSTRASS) {
3217 MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary(&key->d, buf, buflen));
Steven Cooremande8593f2020-06-09 19:55:26 +02003218 }
3219
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003220# endif
Steven Cooremande8593f2020-06-09 19:55:26 +02003221cleanup:
3222
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003223 return ret;
Steven Cooremande8593f2020-06-09 19:55:26 +02003224}
3225
Steven Cooremande8593f2020-06-09 19:55:26 +02003226/*
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003227 * Check a public-private key pair
3228 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003229int mbedtls_ecp_check_pub_priv(const mbedtls_ecp_keypair *pub,
3230 const mbedtls_ecp_keypair *prv,
3231 int (*f_rng)(void *, unsigned char *, size_t),
3232 void *p_rng)
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003233{
Janos Follath24eed8d2019-11-22 13:21:35 +00003234 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02003235 mbedtls_ecp_point Q;
3236 mbedtls_ecp_group grp;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003237 ECP_VALIDATE_RET(pub != NULL);
3238 ECP_VALIDATE_RET(prv != NULL);
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003239
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003240 if (pub->grp.id == MBEDTLS_ECP_DP_NONE || pub->grp.id != prv->grp.id ||
3241 mbedtls_mpi_cmp_mpi(&pub->Q.X, &prv->Q.X) ||
3242 mbedtls_mpi_cmp_mpi(&pub->Q.Y, &prv->Q.Y) ||
3243 mbedtls_mpi_cmp_mpi(&pub->Q.Z, &prv->Q.Z)) {
3244 return MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003245 }
3246
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003247 mbedtls_ecp_point_init(&Q);
3248 mbedtls_ecp_group_init(&grp);
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003249
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02003250 /* mbedtls_ecp_mul() needs a non-const group... */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003251 mbedtls_ecp_group_copy(&grp, &prv->grp);
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003252
3253 /* Also checks d is valid */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003254 MBEDTLS_MPI_CHK(
3255 mbedtls_ecp_mul(&grp, &Q, &prv->d, &prv->grp.G, f_rng, p_rng));
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003256
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003257 if (mbedtls_mpi_cmp_mpi(&Q.X, &prv->Q.X) ||
3258 mbedtls_mpi_cmp_mpi(&Q.Y, &prv->Q.Y) ||
3259 mbedtls_mpi_cmp_mpi(&Q.Z, &prv->Q.Z)) {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02003260 ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003261 goto cleanup;
3262 }
3263
3264cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003265 mbedtls_ecp_point_free(&Q);
3266 mbedtls_ecp_group_free(&grp);
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003267
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003268 return ret;
Manuel Pégourié-Gonnard30668d62014-11-06 15:25:32 +01003269}
3270
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003271# if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01003272
Manuel Pégourié-Gonnardaa3ed6f2021-06-15 11:29:26 +02003273/*
3274 * PRNG for test - !!!INSECURE NEVER USE IN PRODUCTION!!!
3275 *
3276 * This is the linear congruential generator from numerical recipes,
3277 * except we only use the low byte as the output. See
3278 * https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use
3279 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003280static int self_test_rng(void *ctx, unsigned char *out, size_t len)
Manuel Pégourié-Gonnardaa3ed6f2021-06-15 11:29:26 +02003281{
3282 static uint32_t state = 42;
3283
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003284 (void)ctx;
Manuel Pégourié-Gonnardaa3ed6f2021-06-15 11:29:26 +02003285
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003286 for (size_t i = 0; i < len; i++) {
Manuel Pégourié-Gonnardaa3ed6f2021-06-15 11:29:26 +02003287 state = state * 1664525u + 1013904223u;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003288 out[i] = (unsigned char)state;
Manuel Pégourié-Gonnardaa3ed6f2021-06-15 11:29:26 +02003289 }
3290
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003291 return 0;
Manuel Pégourié-Gonnardaa3ed6f2021-06-15 11:29:26 +02003292}
3293
Gilles Peskine6d9c8d72020-07-22 01:26:25 +02003294/* Adjust the exponent to be a valid private point for the specified curve.
3295 * This is sometimes necessary because we use a single set of exponents
3296 * for all curves but the validity of values depends on the curve. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003297static int self_test_adjust_exponent(const mbedtls_ecp_group *grp,
3298 mbedtls_mpi *m)
Gilles Peskinea088c812018-09-17 18:31:15 +02003299{
3300 int ret = 0;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003301 switch (grp->id) {
Gilles Peskinea088c812018-09-17 18:31:15 +02003302 /* If Curve25519 is available, then that's what we use for the
3303 * Montgomery test, so we don't need the adjustment code. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003304# if !defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
3305# if defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
Gilles Peskinea088c812018-09-17 18:31:15 +02003306 case MBEDTLS_ECP_DP_CURVE448:
3307 /* Move highest bit from 254 to N-1. Setting bit N-1 is
3308 * necessary to enforce the highest-bit-set constraint. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003309 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, 254, 0));
3310 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, grp->nbits, 1));
Gilles Peskinea088c812018-09-17 18:31:15 +02003311 /* Copy second-highest bit from 253 to N-2. This is not
3312 * necessary but improves the test variety a bit. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003313 MBEDTLS_MPI_CHK(mbedtls_mpi_set_bit(m, grp->nbits - 1,
3314 mbedtls_mpi_get_bit(m, 253)));
Gilles Peskinea088c812018-09-17 18:31:15 +02003315 break;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003316# endif
3317# endif /* ! defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED) */
Gilles Peskinea088c812018-09-17 18:31:15 +02003318 default:
3319 /* Non-Montgomery curves and Curve25519 need no adjustment. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003320 (void)grp;
3321 (void)m;
Gilles Peskinea088c812018-09-17 18:31:15 +02003322 goto cleanup;
3323 }
3324cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003325 return ret;
Gilles Peskinea088c812018-09-17 18:31:15 +02003326}
3327
Gilles Peskine6d9c8d72020-07-22 01:26:25 +02003328/* Calculate R = m.P for each m in exponents. Check that the number of
3329 * basic operations doesn't depend on the value of m. */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003330static int self_test_point(int verbose,
3331 mbedtls_ecp_group *grp,
3332 mbedtls_ecp_point *R,
3333 mbedtls_mpi *m,
3334 const mbedtls_ecp_point *P,
3335 const char *const *exponents,
3336 size_t n_exponents)
Gilles Peskinec95696f2018-09-17 15:59:01 +02003337{
3338 int ret = 0;
Gilles Peskine24666792018-09-17 18:29:49 +02003339 size_t i = 0;
Gilles Peskinec95696f2018-09-17 15:59:01 +02003340 unsigned long add_c_prev, dbl_c_prev, mul_c_prev;
3341 add_count = 0;
3342 dbl_count = 0;
3343 mul_count = 0;
Gilles Peskinea088c812018-09-17 18:31:15 +02003344
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003345 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[0]));
3346 MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m));
3347 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL));
Gilles Peskinec95696f2018-09-17 15:59:01 +02003348
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003349 for (i = 1; i < n_exponents; i++) {
Gilles Peskinec95696f2018-09-17 15:59:01 +02003350 add_c_prev = add_count;
3351 dbl_c_prev = dbl_count;
3352 mul_c_prev = mul_count;
3353 add_count = 0;
3354 dbl_count = 0;
3355 mul_count = 0;
3356
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003357 MBEDTLS_MPI_CHK(mbedtls_mpi_read_string(m, 16, exponents[i]));
3358 MBEDTLS_MPI_CHK(self_test_adjust_exponent(grp, m));
3359 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(grp, R, m, P, self_test_rng, NULL));
Gilles Peskinec95696f2018-09-17 15:59:01 +02003360
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003361 if (add_count != add_c_prev || dbl_count != dbl_c_prev ||
3362 mul_count != mul_c_prev) {
Gilles Peskinec95696f2018-09-17 15:59:01 +02003363 ret = 1;
3364 break;
3365 }
3366 }
3367
3368cleanup:
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003369 if (verbose != 0) {
3370 if (ret != 0)
3371 mbedtls_printf("failed (%u)\n", (unsigned int)i);
Gilles Peskinec95696f2018-09-17 15:59:01 +02003372 else
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003373 mbedtls_printf("passed\n");
Gilles Peskinec95696f2018-09-17 15:59:01 +02003374 }
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003375 return ret;
Gilles Peskinec95696f2018-09-17 15:59:01 +02003376}
3377
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +01003378/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01003379 * Checkup routine
3380 */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003381int mbedtls_ecp_self_test(int verbose)
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01003382{
Janos Follath24eed8d2019-11-22 13:21:35 +00003383 int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02003384 mbedtls_ecp_group grp;
3385 mbedtls_ecp_point R, P;
3386 mbedtls_mpi m;
Gilles Peskine24666792018-09-17 18:29:49 +02003387
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003388# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
Gilles Peskined9767a52018-09-14 19:29:47 +02003389 /* Exponents especially adapted for secp192k1, which has the lowest
3390 * order n of all supported curves (secp192r1 is in a slightly larger
3391 * field but the order of its base point is slightly smaller). */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003392 const char *sw_exponents[] = {
Manuel Pégourié-Gonnardb63f9e92012-11-21 13:00:58 +01003393 "000000000000000000000000000000000000000000000001", /* one */
Gilles Peskined9767a52018-09-14 19:29:47 +02003394 "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8C", /* n - 1 */
Manuel Pégourié-Gonnardb63f9e92012-11-21 13:00:58 +01003395 "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */
Manuel Pégourié-Gonnardff27b7c2013-11-21 09:28:03 +01003396 "400000000000000000000000000000000000000000000000", /* one and zeros */
3397 "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */
3398 "555555555555555555555555555555555555555555555555", /* 101010... */
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003399 };
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003400# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
3401# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
3402 const char *m_exponents[] = {
Gilles Peskine6d9c8d72020-07-22 01:26:25 +02003403 /* Valid private values for Curve25519. In a build with Curve448
3404 * but not Curve25519, they will be adjusted in
3405 * self_test_adjust_exponent(). */
Gilles Peskine24666792018-09-17 18:29:49 +02003406 "4000000000000000000000000000000000000000000000000000000000000000",
3407 "5C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C3C30",
3408 "5715ECCE24583F7A7023C24164390586842E816D7280A49EF6DF4EAE6B280BF8",
3409 "41A2B017516F6D254E1F002BCCBADD54BE30F8CEC737A0E912B4963B6BA74460",
3410 "5555555555555555555555555555555555555555555555555555555555555550",
3411 "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8",
3412 };
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003413# endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003414
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003415 mbedtls_ecp_group_init(&grp);
3416 mbedtls_ecp_point_init(&R);
3417 mbedtls_ecp_point_init(&P);
3418 mbedtls_mpi_init(&m);
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003419
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003420# if defined(MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED)
Manuel Pégourié-Gonnardb8012fc2013-10-10 15:40:49 +02003421 /* Use secp192r1 if available, or any available curve */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003422# if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
3423 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_SECP192R1));
3424# else
3425 MBEDTLS_MPI_CHK(
3426 mbedtls_ecp_group_load(&grp, mbedtls_ecp_curve_list()->grp_id));
3427# endif
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003428
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003429 if (verbose != 0)
3430 mbedtls_printf(" ECP SW test #1 (constant op_count, base point G): ");
Manuel Pégourié-Gonnard161ef962013-09-17 19:13:10 +02003431 /* Do a dummy multiplication first to trigger precomputation */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003432 MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&m, 2));
3433 MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&grp, &P, &m, &grp.G, self_test_rng, NULL));
3434 ret = self_test_point(verbose, &grp, &R, &m, &grp.G, sw_exponents,
3435 sizeof(sw_exponents) / sizeof(sw_exponents[0]));
3436 if (ret != 0)
Gilles Peskinec95696f2018-09-17 15:59:01 +02003437 goto cleanup;
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003438
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003439 if (verbose != 0)
3440 mbedtls_printf(" ECP SW test #2 (constant op_count, other point): ");
Manuel Pégourié-Gonnard161ef962013-09-17 19:13:10 +02003441 /* We computed P = 2G last time, use it */
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003442 ret = self_test_point(verbose, &grp, &R, &m, &P, sw_exponents,
3443 sizeof(sw_exponents) / sizeof(sw_exponents[0]));
3444 if (ret != 0)
Gilles Peskine24666792018-09-17 18:29:49 +02003445 goto cleanup;
3446
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003447 mbedtls_ecp_group_free(&grp);
3448 mbedtls_ecp_point_free(&R);
3449# endif /* MBEDTLS_ECP_SHORT_WEIERSTRASS_ENABLED */
Gilles Peskine24666792018-09-17 18:29:49 +02003450
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003451# if defined(MBEDTLS_ECP_MONTGOMERY_ENABLED)
3452 if (verbose != 0)
3453 mbedtls_printf(" ECP Montgomery test (constant op_count): ");
3454# if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
3455 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE25519));
3456# elif defined(MBEDTLS_ECP_DP_CURVE448_ENABLED)
3457 MBEDTLS_MPI_CHK(mbedtls_ecp_group_load(&grp, MBEDTLS_ECP_DP_CURVE448));
3458# else
3459# error \
3460 "MBEDTLS_ECP_MONTGOMERY_ENABLED is defined, but no curve is supported for self-test"
3461# endif
3462 ret = self_test_point(verbose, &grp, &R, &m, &grp.G, m_exponents,
3463 sizeof(m_exponents) / sizeof(m_exponents[0]));
3464 if (ret != 0)
Gilles Peskine24666792018-09-17 18:29:49 +02003465 goto cleanup;
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003466# endif /* MBEDTLS_ECP_MONTGOMERY_ENABLED */
Manuel Pégourié-Gonnard161ef962013-09-17 19:13:10 +02003467
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003468cleanup:
3469
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003470 if (ret < 0 && verbose != 0)
3471 mbedtls_printf("Unexpected error, return code = %08X\n",
3472 (unsigned int)ret);
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003473
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003474 mbedtls_ecp_group_free(&grp);
3475 mbedtls_ecp_point_free(&R);
3476 mbedtls_ecp_point_free(&P);
3477 mbedtls_mpi_free(&m);
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003478
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003479 if (verbose != 0)
3480 mbedtls_printf("\n");
Manuel Pégourié-Gonnardb4a310b2012-11-13 20:57:00 +01003481
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003482 return ret;
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01003483}
3484
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003485# endif /* MBEDTLS_SELF_TEST */
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01003486
Mateusz Starzykc0eabdc2021-08-03 14:09:02 +02003487# endif /* !MBEDTLS_ECP_ALT */
Janos Follathb0697532016-08-18 12:38:46 +01003488
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +02003489#endif /* MBEDTLS_ECP_C */