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