xref: /optee_os/lib/libmbedtls/mbedtls/library/ecp.c (revision c6672fdcd95b9a895eb5b4191f8ba3483a34a442)
1*c6672fdcSEdison Ai // SPDX-License-Identifier: Apache-2.0
2817466cbSJens Wiklander /*
3817466cbSJens Wiklander  *  Elliptic curves over GF(p): generic functions
4817466cbSJens Wiklander  *
5817466cbSJens Wiklander  *  Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
6817466cbSJens Wiklander  *
7817466cbSJens Wiklander  *  Licensed under the Apache License, Version 2.0 (the "License"); you may
8817466cbSJens Wiklander  *  not use this file except in compliance with the License.
9817466cbSJens Wiklander  *  You may obtain a copy of the License at
10817466cbSJens Wiklander  *
11817466cbSJens Wiklander  *  http://www.apache.org/licenses/LICENSE-2.0
12817466cbSJens Wiklander  *
13817466cbSJens Wiklander  *  Unless required by applicable law or agreed to in writing, software
14817466cbSJens Wiklander  *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15817466cbSJens Wiklander  *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16817466cbSJens Wiklander  *  See the License for the specific language governing permissions and
17817466cbSJens Wiklander  *  limitations under the License.
18817466cbSJens Wiklander  *
19817466cbSJens Wiklander  *  This file is part of mbed TLS (https://tls.mbed.org)
20817466cbSJens Wiklander  */
21817466cbSJens Wiklander 
22817466cbSJens Wiklander /*
23817466cbSJens Wiklander  * References:
24817466cbSJens Wiklander  *
25817466cbSJens Wiklander  * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
26817466cbSJens Wiklander  * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone
27817466cbSJens Wiklander  * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf
28817466cbSJens Wiklander  * RFC 4492 for the related TLS structures and constants
29817466cbSJens Wiklander  *
30817466cbSJens Wiklander  * [Curve25519] http://cr.yp.to/ecdh/curve25519-20060209.pdf
31817466cbSJens Wiklander  *
32817466cbSJens Wiklander  * [2] CORON, Jean-S'ebastien. Resistance against differential power analysis
33817466cbSJens Wiklander  *     for elliptic curve cryptosystems. In : Cryptographic Hardware and
34817466cbSJens Wiklander  *     Embedded Systems. Springer Berlin Heidelberg, 1999. p. 292-302.
35817466cbSJens Wiklander  *     <http://link.springer.com/chapter/10.1007/3-540-48059-5_25>
36817466cbSJens Wiklander  *
37817466cbSJens Wiklander  * [3] HEDABOU, Mustapha, PINEL, Pierre, et B'EN'ETEAU, Lucien. A comb method to
38817466cbSJens Wiklander  *     render ECC resistant against Side Channel Attacks. IACR Cryptology
39817466cbSJens Wiklander  *     ePrint Archive, 2004, vol. 2004, p. 342.
40817466cbSJens Wiklander  *     <http://eprint.iacr.org/2004/342.pdf>
41817466cbSJens Wiklander  */
42817466cbSJens Wiklander 
43817466cbSJens Wiklander #if !defined(MBEDTLS_CONFIG_FILE)
44817466cbSJens Wiklander #include "mbedtls/config.h"
45817466cbSJens Wiklander #else
46817466cbSJens Wiklander #include MBEDTLS_CONFIG_FILE
47817466cbSJens Wiklander #endif
48817466cbSJens Wiklander 
49817466cbSJens Wiklander #if defined(MBEDTLS_ECP_C)
50817466cbSJens Wiklander 
51817466cbSJens Wiklander #include "mbedtls/ecp.h"
52817466cbSJens Wiklander #include "mbedtls/threading.h"
53817466cbSJens Wiklander 
54817466cbSJens Wiklander #include <string.h>
55817466cbSJens Wiklander 
56817466cbSJens Wiklander #if !defined(MBEDTLS_ECP_ALT)
57817466cbSJens Wiklander 
58817466cbSJens Wiklander #if defined(MBEDTLS_PLATFORM_C)
59817466cbSJens Wiklander #include "mbedtls/platform.h"
60817466cbSJens Wiklander #else
61817466cbSJens Wiklander #include <stdlib.h>
62817466cbSJens Wiklander #include <stdio.h>
63817466cbSJens Wiklander #define mbedtls_printf     printf
64817466cbSJens Wiklander #define mbedtls_calloc    calloc
65817466cbSJens Wiklander #define mbedtls_free       free
66817466cbSJens Wiklander #endif
67817466cbSJens Wiklander 
68817466cbSJens Wiklander #include "mbedtls/ecp_internal.h"
69817466cbSJens Wiklander 
70817466cbSJens Wiklander #if ( defined(__ARMCC_VERSION) || defined(_MSC_VER) ) && \
71817466cbSJens Wiklander     !defined(inline) && !defined(__cplusplus)
72817466cbSJens Wiklander #define inline __inline
73817466cbSJens Wiklander #endif
74817466cbSJens Wiklander 
75817466cbSJens Wiklander /* Implementation that should never be optimized out by the compiler */
76817466cbSJens Wiklander static void mbedtls_zeroize( void *v, size_t n ) {
77817466cbSJens Wiklander     volatile unsigned char *p = v; while( n-- ) *p++ = 0;
78817466cbSJens Wiklander }
79817466cbSJens Wiklander 
80817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
81817466cbSJens Wiklander /*
82817466cbSJens Wiklander  * Counts of point addition and doubling, and field multiplications.
83817466cbSJens Wiklander  * Used to test resistance of point multiplication to simple timing attacks.
84817466cbSJens Wiklander  */
85817466cbSJens Wiklander static unsigned long add_count, dbl_count, mul_count;
86817466cbSJens Wiklander #endif
87817466cbSJens Wiklander 
88817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED) ||   \
89817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED) ||   \
90817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED) ||   \
91817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED) ||   \
92817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED) ||   \
93817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)   ||   \
94817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)   ||   \
95817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)   ||   \
96817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED) ||   \
97817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED) ||   \
98817466cbSJens Wiklander     defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
99817466cbSJens Wiklander #define ECP_SHORTWEIERSTRASS
100817466cbSJens Wiklander #endif
101817466cbSJens Wiklander 
102817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_CURVE25519_ENABLED)
103817466cbSJens Wiklander #define ECP_MONTGOMERY
104817466cbSJens Wiklander #endif
105817466cbSJens Wiklander 
106817466cbSJens Wiklander /*
107817466cbSJens Wiklander  * Curve types: internal for now, might be exposed later
108817466cbSJens Wiklander  */
109817466cbSJens Wiklander typedef enum
110817466cbSJens Wiklander {
111817466cbSJens Wiklander     ECP_TYPE_NONE = 0,
112817466cbSJens Wiklander     ECP_TYPE_SHORT_WEIERSTRASS,    /* y^2 = x^3 + a x + b      */
113817466cbSJens Wiklander     ECP_TYPE_MONTGOMERY,           /* y^2 = x^3 + a x^2 + x    */
114817466cbSJens Wiklander } ecp_curve_type;
115817466cbSJens Wiklander 
116817466cbSJens Wiklander /*
117817466cbSJens Wiklander  * List of supported curves:
118817466cbSJens Wiklander  *  - internal ID
119817466cbSJens Wiklander  *  - TLS NamedCurve ID (RFC 4492 sec. 5.1.1, RFC 7071 sec. 2)
120817466cbSJens Wiklander  *  - size in bits
121817466cbSJens Wiklander  *  - readable name
122817466cbSJens Wiklander  *
123817466cbSJens Wiklander  * Curves are listed in order: largest curves first, and for a given size,
124817466cbSJens Wiklander  * fastest curves first. This provides the default order for the SSL module.
125817466cbSJens Wiklander  *
126817466cbSJens Wiklander  * Reminder: update profiles in x509_crt.c when adding a new curves!
127817466cbSJens Wiklander  */
128817466cbSJens Wiklander static const mbedtls_ecp_curve_info ecp_supported_curves[] =
129817466cbSJens Wiklander {
130817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP521R1_ENABLED)
131817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP521R1,    25,     521,    "secp521r1"         },
132817466cbSJens Wiklander #endif
133817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_BP512R1_ENABLED)
134817466cbSJens Wiklander     { MBEDTLS_ECP_DP_BP512R1,      28,     512,    "brainpoolP512r1"   },
135817466cbSJens Wiklander #endif
136817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP384R1_ENABLED)
137817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP384R1,    24,     384,    "secp384r1"         },
138817466cbSJens Wiklander #endif
139817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_BP384R1_ENABLED)
140817466cbSJens Wiklander     { MBEDTLS_ECP_DP_BP384R1,      27,     384,    "brainpoolP384r1"   },
141817466cbSJens Wiklander #endif
142817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP256R1_ENABLED)
143817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP256R1,    23,     256,    "secp256r1"         },
144817466cbSJens Wiklander #endif
145817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP256K1_ENABLED)
146817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP256K1,    22,     256,    "secp256k1"         },
147817466cbSJens Wiklander #endif
148817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_BP256R1_ENABLED)
149817466cbSJens Wiklander     { MBEDTLS_ECP_DP_BP256R1,      26,     256,    "brainpoolP256r1"   },
150817466cbSJens Wiklander #endif
151817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP224R1_ENABLED)
152817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP224R1,    21,     224,    "secp224r1"         },
153817466cbSJens Wiklander #endif
154817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP224K1_ENABLED)
155817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP224K1,    20,     224,    "secp224k1"         },
156817466cbSJens Wiklander #endif
157817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
158817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP192R1,    19,     192,    "secp192r1"         },
159817466cbSJens Wiklander #endif
160817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP192K1_ENABLED)
161817466cbSJens Wiklander     { MBEDTLS_ECP_DP_SECP192K1,    18,     192,    "secp192k1"         },
162817466cbSJens Wiklander #endif
163817466cbSJens Wiklander     { MBEDTLS_ECP_DP_NONE,          0,     0,      NULL                },
164817466cbSJens Wiklander };
165817466cbSJens Wiklander 
166817466cbSJens Wiklander #define ECP_NB_CURVES   sizeof( ecp_supported_curves ) /    \
167817466cbSJens Wiklander                         sizeof( ecp_supported_curves[0] )
168817466cbSJens Wiklander 
169817466cbSJens Wiklander static mbedtls_ecp_group_id ecp_supported_grp_id[ECP_NB_CURVES];
170817466cbSJens Wiklander 
171817466cbSJens Wiklander /*
172817466cbSJens Wiklander  * List of supported curves and associated info
173817466cbSJens Wiklander  */
174817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_list( void )
175817466cbSJens Wiklander {
176817466cbSJens Wiklander     return( ecp_supported_curves );
177817466cbSJens Wiklander }
178817466cbSJens Wiklander 
179817466cbSJens Wiklander /*
180817466cbSJens Wiklander  * List of supported curves, group ID only
181817466cbSJens Wiklander  */
182817466cbSJens Wiklander const mbedtls_ecp_group_id *mbedtls_ecp_grp_id_list( void )
183817466cbSJens Wiklander {
184817466cbSJens Wiklander     static int init_done = 0;
185817466cbSJens Wiklander 
186817466cbSJens Wiklander     if( ! init_done )
187817466cbSJens Wiklander     {
188817466cbSJens Wiklander         size_t i = 0;
189817466cbSJens Wiklander         const mbedtls_ecp_curve_info *curve_info;
190817466cbSJens Wiklander 
191817466cbSJens Wiklander         for( curve_info = mbedtls_ecp_curve_list();
192817466cbSJens Wiklander              curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
193817466cbSJens Wiklander              curve_info++ )
194817466cbSJens Wiklander         {
195817466cbSJens Wiklander             ecp_supported_grp_id[i++] = curve_info->grp_id;
196817466cbSJens Wiklander         }
197817466cbSJens Wiklander         ecp_supported_grp_id[i] = MBEDTLS_ECP_DP_NONE;
198817466cbSJens Wiklander 
199817466cbSJens Wiklander         init_done = 1;
200817466cbSJens Wiklander     }
201817466cbSJens Wiklander 
202817466cbSJens Wiklander     return( ecp_supported_grp_id );
203817466cbSJens Wiklander }
204817466cbSJens Wiklander 
205817466cbSJens Wiklander /*
206817466cbSJens Wiklander  * Get the curve info for the internal identifier
207817466cbSJens Wiklander  */
208817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_grp_id( mbedtls_ecp_group_id grp_id )
209817466cbSJens Wiklander {
210817466cbSJens Wiklander     const mbedtls_ecp_curve_info *curve_info;
211817466cbSJens Wiklander 
212817466cbSJens Wiklander     for( curve_info = mbedtls_ecp_curve_list();
213817466cbSJens Wiklander          curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
214817466cbSJens Wiklander          curve_info++ )
215817466cbSJens Wiklander     {
216817466cbSJens Wiklander         if( curve_info->grp_id == grp_id )
217817466cbSJens Wiklander             return( curve_info );
218817466cbSJens Wiklander     }
219817466cbSJens Wiklander 
220817466cbSJens Wiklander     return( NULL );
221817466cbSJens Wiklander }
222817466cbSJens Wiklander 
223817466cbSJens Wiklander /*
224817466cbSJens Wiklander  * Get the curve info from the TLS identifier
225817466cbSJens Wiklander  */
226817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_tls_id( uint16_t tls_id )
227817466cbSJens Wiklander {
228817466cbSJens Wiklander     const mbedtls_ecp_curve_info *curve_info;
229817466cbSJens Wiklander 
230817466cbSJens Wiklander     for( curve_info = mbedtls_ecp_curve_list();
231817466cbSJens Wiklander          curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
232817466cbSJens Wiklander          curve_info++ )
233817466cbSJens Wiklander     {
234817466cbSJens Wiklander         if( curve_info->tls_id == tls_id )
235817466cbSJens Wiklander             return( curve_info );
236817466cbSJens Wiklander     }
237817466cbSJens Wiklander 
238817466cbSJens Wiklander     return( NULL );
239817466cbSJens Wiklander }
240817466cbSJens Wiklander 
241817466cbSJens Wiklander /*
242817466cbSJens Wiklander  * Get the curve info from the name
243817466cbSJens Wiklander  */
244817466cbSJens Wiklander const mbedtls_ecp_curve_info *mbedtls_ecp_curve_info_from_name( const char *name )
245817466cbSJens Wiklander {
246817466cbSJens Wiklander     const mbedtls_ecp_curve_info *curve_info;
247817466cbSJens Wiklander 
248817466cbSJens Wiklander     for( curve_info = mbedtls_ecp_curve_list();
249817466cbSJens Wiklander          curve_info->grp_id != MBEDTLS_ECP_DP_NONE;
250817466cbSJens Wiklander          curve_info++ )
251817466cbSJens Wiklander     {
252817466cbSJens Wiklander         if( strcmp( curve_info->name, name ) == 0 )
253817466cbSJens Wiklander             return( curve_info );
254817466cbSJens Wiklander     }
255817466cbSJens Wiklander 
256817466cbSJens Wiklander     return( NULL );
257817466cbSJens Wiklander }
258817466cbSJens Wiklander 
259817466cbSJens Wiklander /*
260817466cbSJens Wiklander  * Get the type of a curve
261817466cbSJens Wiklander  */
262817466cbSJens Wiklander static inline ecp_curve_type ecp_get_type( const mbedtls_ecp_group *grp )
263817466cbSJens Wiklander {
264817466cbSJens Wiklander     if( grp->G.X.p == NULL )
265817466cbSJens Wiklander         return( ECP_TYPE_NONE );
266817466cbSJens Wiklander 
267817466cbSJens Wiklander     if( grp->G.Y.p == NULL )
268817466cbSJens Wiklander         return( ECP_TYPE_MONTGOMERY );
269817466cbSJens Wiklander     else
270817466cbSJens Wiklander         return( ECP_TYPE_SHORT_WEIERSTRASS );
271817466cbSJens Wiklander }
272817466cbSJens Wiklander 
273817466cbSJens Wiklander /*
274817466cbSJens Wiklander  * Initialize (the components of) a point
275817466cbSJens Wiklander  */
276817466cbSJens Wiklander void mbedtls_ecp_point_init( mbedtls_ecp_point *pt )
277817466cbSJens Wiklander {
278817466cbSJens Wiklander     if( pt == NULL )
279817466cbSJens Wiklander         return;
280817466cbSJens Wiklander 
281817466cbSJens Wiklander     mbedtls_mpi_init( &pt->X );
282817466cbSJens Wiklander     mbedtls_mpi_init( &pt->Y );
283817466cbSJens Wiklander     mbedtls_mpi_init( &pt->Z );
284817466cbSJens Wiklander }
285817466cbSJens Wiklander 
286817466cbSJens Wiklander /*
287817466cbSJens Wiklander  * Initialize (the components of) a group
288817466cbSJens Wiklander  */
289817466cbSJens Wiklander void mbedtls_ecp_group_init( mbedtls_ecp_group *grp )
290817466cbSJens Wiklander {
291817466cbSJens Wiklander     if( grp == NULL )
292817466cbSJens Wiklander         return;
293817466cbSJens Wiklander 
294817466cbSJens Wiklander     memset( grp, 0, sizeof( mbedtls_ecp_group ) );
295817466cbSJens Wiklander }
296817466cbSJens Wiklander 
297817466cbSJens Wiklander /*
298817466cbSJens Wiklander  * Initialize (the components of) a key pair
299817466cbSJens Wiklander  */
300817466cbSJens Wiklander void mbedtls_ecp_keypair_init( mbedtls_ecp_keypair *key )
301817466cbSJens Wiklander {
302817466cbSJens Wiklander     if( key == NULL )
303817466cbSJens Wiklander         return;
304817466cbSJens Wiklander 
305817466cbSJens Wiklander     mbedtls_ecp_group_init( &key->grp );
306817466cbSJens Wiklander     mbedtls_mpi_init( &key->d );
307817466cbSJens Wiklander     mbedtls_ecp_point_init( &key->Q );
308817466cbSJens Wiklander }
309817466cbSJens Wiklander 
310817466cbSJens Wiklander /*
311817466cbSJens Wiklander  * Unallocate (the components of) a point
312817466cbSJens Wiklander  */
313817466cbSJens Wiklander void mbedtls_ecp_point_free( mbedtls_ecp_point *pt )
314817466cbSJens Wiklander {
315817466cbSJens Wiklander     if( pt == NULL )
316817466cbSJens Wiklander         return;
317817466cbSJens Wiklander 
318817466cbSJens Wiklander     mbedtls_mpi_free( &( pt->X ) );
319817466cbSJens Wiklander     mbedtls_mpi_free( &( pt->Y ) );
320817466cbSJens Wiklander     mbedtls_mpi_free( &( pt->Z ) );
321817466cbSJens Wiklander }
322817466cbSJens Wiklander 
323817466cbSJens Wiklander /*
324817466cbSJens Wiklander  * Unallocate (the components of) a group
325817466cbSJens Wiklander  */
326817466cbSJens Wiklander void mbedtls_ecp_group_free( mbedtls_ecp_group *grp )
327817466cbSJens Wiklander {
328817466cbSJens Wiklander     size_t i;
329817466cbSJens Wiklander 
330817466cbSJens Wiklander     if( grp == NULL )
331817466cbSJens Wiklander         return;
332817466cbSJens Wiklander 
333817466cbSJens Wiklander     if( grp->h != 1 )
334817466cbSJens Wiklander     {
335817466cbSJens Wiklander         mbedtls_mpi_free( &grp->P );
336817466cbSJens Wiklander         mbedtls_mpi_free( &grp->A );
337817466cbSJens Wiklander         mbedtls_mpi_free( &grp->B );
338817466cbSJens Wiklander         mbedtls_ecp_point_free( &grp->G );
339817466cbSJens Wiklander         mbedtls_mpi_free( &grp->N );
340817466cbSJens Wiklander     }
341817466cbSJens Wiklander 
342817466cbSJens Wiklander     if( grp->T != NULL )
343817466cbSJens Wiklander     {
344817466cbSJens Wiklander         for( i = 0; i < grp->T_size; i++ )
345817466cbSJens Wiklander             mbedtls_ecp_point_free( &grp->T[i] );
346817466cbSJens Wiklander         mbedtls_free( grp->T );
347817466cbSJens Wiklander     }
348817466cbSJens Wiklander 
349817466cbSJens Wiklander     mbedtls_zeroize( grp, sizeof( mbedtls_ecp_group ) );
350817466cbSJens Wiklander }
351817466cbSJens Wiklander 
352817466cbSJens Wiklander /*
353817466cbSJens Wiklander  * Unallocate (the components of) a key pair
354817466cbSJens Wiklander  */
355817466cbSJens Wiklander void mbedtls_ecp_keypair_free( mbedtls_ecp_keypair *key )
356817466cbSJens Wiklander {
357817466cbSJens Wiklander     if( key == NULL )
358817466cbSJens Wiklander         return;
359817466cbSJens Wiklander 
360817466cbSJens Wiklander     mbedtls_ecp_group_free( &key->grp );
361817466cbSJens Wiklander     mbedtls_mpi_free( &key->d );
362817466cbSJens Wiklander     mbedtls_ecp_point_free( &key->Q );
363817466cbSJens Wiklander }
364817466cbSJens Wiklander 
365817466cbSJens Wiklander /*
366817466cbSJens Wiklander  * Copy the contents of a point
367817466cbSJens Wiklander  */
368817466cbSJens Wiklander int mbedtls_ecp_copy( mbedtls_ecp_point *P, const mbedtls_ecp_point *Q )
369817466cbSJens Wiklander {
370817466cbSJens Wiklander     int ret;
371817466cbSJens Wiklander 
372817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->X, &Q->X ) );
373817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Y, &Q->Y ) );
374817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &P->Z, &Q->Z ) );
375817466cbSJens Wiklander 
376817466cbSJens Wiklander cleanup:
377817466cbSJens Wiklander     return( ret );
378817466cbSJens Wiklander }
379817466cbSJens Wiklander 
380817466cbSJens Wiklander /*
381817466cbSJens Wiklander  * Copy the contents of a group object
382817466cbSJens Wiklander  */
383817466cbSJens Wiklander int mbedtls_ecp_group_copy( mbedtls_ecp_group *dst, const mbedtls_ecp_group *src )
384817466cbSJens Wiklander {
385817466cbSJens Wiklander     return mbedtls_ecp_group_load( dst, src->id );
386817466cbSJens Wiklander }
387817466cbSJens Wiklander 
388817466cbSJens Wiklander /*
389817466cbSJens Wiklander  * Set point to zero
390817466cbSJens Wiklander  */
391817466cbSJens Wiklander int mbedtls_ecp_set_zero( mbedtls_ecp_point *pt )
392817466cbSJens Wiklander {
393817466cbSJens Wiklander     int ret;
394817466cbSJens Wiklander 
395817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->X , 1 ) );
396817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Y , 1 ) );
397817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z , 0 ) );
398817466cbSJens Wiklander 
399817466cbSJens Wiklander cleanup:
400817466cbSJens Wiklander     return( ret );
401817466cbSJens Wiklander }
402817466cbSJens Wiklander 
403817466cbSJens Wiklander /*
404817466cbSJens Wiklander  * Tell if a point is zero
405817466cbSJens Wiklander  */
406817466cbSJens Wiklander int mbedtls_ecp_is_zero( mbedtls_ecp_point *pt )
407817466cbSJens Wiklander {
408817466cbSJens Wiklander     return( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 );
409817466cbSJens Wiklander }
410817466cbSJens Wiklander 
411817466cbSJens Wiklander /*
412817466cbSJens Wiklander  * Compare two points lazyly
413817466cbSJens Wiklander  */
414817466cbSJens Wiklander int mbedtls_ecp_point_cmp( const mbedtls_ecp_point *P,
415817466cbSJens Wiklander                            const mbedtls_ecp_point *Q )
416817466cbSJens Wiklander {
417817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &P->X, &Q->X ) == 0 &&
418817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 &&
419817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &P->Z, &Q->Z ) == 0 )
420817466cbSJens Wiklander     {
421817466cbSJens Wiklander         return( 0 );
422817466cbSJens Wiklander     }
423817466cbSJens Wiklander 
424817466cbSJens Wiklander     return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
425817466cbSJens Wiklander }
426817466cbSJens Wiklander 
427817466cbSJens Wiklander /*
428817466cbSJens Wiklander  * Import a non-zero point from ASCII strings
429817466cbSJens Wiklander  */
430817466cbSJens Wiklander int mbedtls_ecp_point_read_string( mbedtls_ecp_point *P, int radix,
431817466cbSJens Wiklander                            const char *x, const char *y )
432817466cbSJens Wiklander {
433817466cbSJens Wiklander     int ret;
434817466cbSJens Wiklander 
435817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->X, radix, x ) );
436817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &P->Y, radix, y ) );
437817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) );
438817466cbSJens Wiklander 
439817466cbSJens Wiklander cleanup:
440817466cbSJens Wiklander     return( ret );
441817466cbSJens Wiklander }
442817466cbSJens Wiklander 
443817466cbSJens Wiklander /*
444817466cbSJens Wiklander  * Export a point into unsigned binary data (SEC1 2.3.3)
445817466cbSJens Wiklander  */
446817466cbSJens Wiklander int mbedtls_ecp_point_write_binary( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *P,
447817466cbSJens Wiklander                             int format, size_t *olen,
448817466cbSJens Wiklander                             unsigned char *buf, size_t buflen )
449817466cbSJens Wiklander {
450817466cbSJens Wiklander     int ret = 0;
451817466cbSJens Wiklander     size_t plen;
452817466cbSJens Wiklander 
453817466cbSJens Wiklander     if( format != MBEDTLS_ECP_PF_UNCOMPRESSED &&
454817466cbSJens Wiklander         format != MBEDTLS_ECP_PF_COMPRESSED )
455817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
456817466cbSJens Wiklander 
457817466cbSJens Wiklander     /*
458817466cbSJens Wiklander      * Common case: P == 0
459817466cbSJens Wiklander      */
460817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 )
461817466cbSJens Wiklander     {
462817466cbSJens Wiklander         if( buflen < 1 )
463817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
464817466cbSJens Wiklander 
465817466cbSJens Wiklander         buf[0] = 0x00;
466817466cbSJens Wiklander         *olen = 1;
467817466cbSJens Wiklander 
468817466cbSJens Wiklander         return( 0 );
469817466cbSJens Wiklander     }
470817466cbSJens Wiklander 
471817466cbSJens Wiklander     plen = mbedtls_mpi_size( &grp->P );
472817466cbSJens Wiklander 
473817466cbSJens Wiklander     if( format == MBEDTLS_ECP_PF_UNCOMPRESSED )
474817466cbSJens Wiklander     {
475817466cbSJens Wiklander         *olen = 2 * plen + 1;
476817466cbSJens Wiklander 
477817466cbSJens Wiklander         if( buflen < *olen )
478817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
479817466cbSJens Wiklander 
480817466cbSJens Wiklander         buf[0] = 0x04;
481817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) );
482817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->Y, buf + 1 + plen, plen ) );
483817466cbSJens Wiklander     }
484817466cbSJens Wiklander     else if( format == MBEDTLS_ECP_PF_COMPRESSED )
485817466cbSJens Wiklander     {
486817466cbSJens Wiklander         *olen = plen + 1;
487817466cbSJens Wiklander 
488817466cbSJens Wiklander         if( buflen < *olen )
489817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
490817466cbSJens Wiklander 
491817466cbSJens Wiklander         buf[0] = 0x02 + mbedtls_mpi_get_bit( &P->Y, 0 );
492817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_write_binary( &P->X, buf + 1, plen ) );
493817466cbSJens Wiklander     }
494817466cbSJens Wiklander 
495817466cbSJens Wiklander cleanup:
496817466cbSJens Wiklander     return( ret );
497817466cbSJens Wiklander }
498817466cbSJens Wiklander 
499817466cbSJens Wiklander /*
500817466cbSJens Wiklander  * Import a point from unsigned binary data (SEC1 2.3.4)
501817466cbSJens Wiklander  */
502817466cbSJens Wiklander int mbedtls_ecp_point_read_binary( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt,
503817466cbSJens Wiklander                            const unsigned char *buf, size_t ilen )
504817466cbSJens Wiklander {
505817466cbSJens Wiklander     int ret;
506817466cbSJens Wiklander     size_t plen;
507817466cbSJens Wiklander 
508817466cbSJens Wiklander     if( ilen < 1 )
509817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
510817466cbSJens Wiklander 
511817466cbSJens Wiklander     if( buf[0] == 0x00 )
512817466cbSJens Wiklander     {
513817466cbSJens Wiklander         if( ilen == 1 )
514817466cbSJens Wiklander             return( mbedtls_ecp_set_zero( pt ) );
515817466cbSJens Wiklander         else
516817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
517817466cbSJens Wiklander     }
518817466cbSJens Wiklander 
519817466cbSJens Wiklander     plen = mbedtls_mpi_size( &grp->P );
520817466cbSJens Wiklander 
521817466cbSJens Wiklander     if( buf[0] != 0x04 )
522817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
523817466cbSJens Wiklander 
524817466cbSJens Wiklander     if( ilen != 2 * plen + 1 )
525817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
526817466cbSJens Wiklander 
527817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->X, buf + 1, plen ) );
528817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( &pt->Y, buf + 1 + plen, plen ) );
529817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) );
530817466cbSJens Wiklander 
531817466cbSJens Wiklander cleanup:
532817466cbSJens Wiklander     return( ret );
533817466cbSJens Wiklander }
534817466cbSJens Wiklander 
535817466cbSJens Wiklander /*
536817466cbSJens Wiklander  * Import a point from a TLS ECPoint record (RFC 4492)
537817466cbSJens Wiklander  *      struct {
538817466cbSJens Wiklander  *          opaque point <1..2^8-1>;
539817466cbSJens Wiklander  *      } ECPoint;
540817466cbSJens Wiklander  */
541817466cbSJens Wiklander int mbedtls_ecp_tls_read_point( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt,
542817466cbSJens Wiklander                         const unsigned char **buf, size_t buf_len )
543817466cbSJens Wiklander {
544817466cbSJens Wiklander     unsigned char data_len;
545817466cbSJens Wiklander     const unsigned char *buf_start;
546817466cbSJens Wiklander 
547817466cbSJens Wiklander     /*
548817466cbSJens Wiklander      * We must have at least two bytes (1 for length, at least one for data)
549817466cbSJens Wiklander      */
550817466cbSJens Wiklander     if( buf_len < 2 )
551817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
552817466cbSJens Wiklander 
553817466cbSJens Wiklander     data_len = *(*buf)++;
554817466cbSJens Wiklander     if( data_len < 1 || data_len > buf_len - 1 )
555817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
556817466cbSJens Wiklander 
557817466cbSJens Wiklander     /*
558817466cbSJens Wiklander      * Save buffer start for read_binary and update buf
559817466cbSJens Wiklander      */
560817466cbSJens Wiklander     buf_start = *buf;
561817466cbSJens Wiklander     *buf += data_len;
562817466cbSJens Wiklander 
563817466cbSJens Wiklander     return mbedtls_ecp_point_read_binary( grp, pt, buf_start, data_len );
564817466cbSJens Wiklander }
565817466cbSJens Wiklander 
566817466cbSJens Wiklander /*
567817466cbSJens Wiklander  * Export a point as a TLS ECPoint record (RFC 4492)
568817466cbSJens Wiklander  *      struct {
569817466cbSJens Wiklander  *          opaque point <1..2^8-1>;
570817466cbSJens Wiklander  *      } ECPoint;
571817466cbSJens Wiklander  */
572817466cbSJens Wiklander int mbedtls_ecp_tls_write_point( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt,
573817466cbSJens Wiklander                          int format, size_t *olen,
574817466cbSJens Wiklander                          unsigned char *buf, size_t blen )
575817466cbSJens Wiklander {
576817466cbSJens Wiklander     int ret;
577817466cbSJens Wiklander 
578817466cbSJens Wiklander     /*
579817466cbSJens Wiklander      * buffer length must be at least one, for our length byte
580817466cbSJens Wiklander      */
581817466cbSJens Wiklander     if( blen < 1 )
582817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
583817466cbSJens Wiklander 
584817466cbSJens Wiklander     if( ( ret = mbedtls_ecp_point_write_binary( grp, pt, format,
585817466cbSJens Wiklander                     olen, buf + 1, blen - 1) ) != 0 )
586817466cbSJens Wiklander         return( ret );
587817466cbSJens Wiklander 
588817466cbSJens Wiklander     /*
589817466cbSJens Wiklander      * write length to the first byte and update total length
590817466cbSJens Wiklander      */
591817466cbSJens Wiklander     buf[0] = (unsigned char) *olen;
592817466cbSJens Wiklander     ++*olen;
593817466cbSJens Wiklander 
594817466cbSJens Wiklander     return( 0 );
595817466cbSJens Wiklander }
596817466cbSJens Wiklander 
597817466cbSJens Wiklander /*
598817466cbSJens Wiklander  * Set a group from an ECParameters record (RFC 4492)
599817466cbSJens Wiklander  */
600817466cbSJens Wiklander int mbedtls_ecp_tls_read_group( mbedtls_ecp_group *grp, const unsigned char **buf, size_t len )
601817466cbSJens Wiklander {
602817466cbSJens Wiklander     uint16_t tls_id;
603817466cbSJens Wiklander     const mbedtls_ecp_curve_info *curve_info;
604817466cbSJens Wiklander 
605817466cbSJens Wiklander     /*
606817466cbSJens Wiklander      * We expect at least three bytes (see below)
607817466cbSJens Wiklander      */
608817466cbSJens Wiklander     if( len < 3 )
609817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
610817466cbSJens Wiklander 
611817466cbSJens Wiklander     /*
612817466cbSJens Wiklander      * First byte is curve_type; only named_curve is handled
613817466cbSJens Wiklander      */
614817466cbSJens Wiklander     if( *(*buf)++ != MBEDTLS_ECP_TLS_NAMED_CURVE )
615817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
616817466cbSJens Wiklander 
617817466cbSJens Wiklander     /*
618817466cbSJens Wiklander      * Next two bytes are the namedcurve value
619817466cbSJens Wiklander      */
620817466cbSJens Wiklander     tls_id = *(*buf)++;
621817466cbSJens Wiklander     tls_id <<= 8;
622817466cbSJens Wiklander     tls_id |= *(*buf)++;
623817466cbSJens Wiklander 
624817466cbSJens Wiklander     if( ( curve_info = mbedtls_ecp_curve_info_from_tls_id( tls_id ) ) == NULL )
625817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
626817466cbSJens Wiklander 
627817466cbSJens Wiklander     return mbedtls_ecp_group_load( grp, curve_info->grp_id );
628817466cbSJens Wiklander }
629817466cbSJens Wiklander 
630817466cbSJens Wiklander /*
631817466cbSJens Wiklander  * Write the ECParameters record corresponding to a group (RFC 4492)
632817466cbSJens Wiklander  */
633817466cbSJens Wiklander int mbedtls_ecp_tls_write_group( const mbedtls_ecp_group *grp, size_t *olen,
634817466cbSJens Wiklander                          unsigned char *buf, size_t blen )
635817466cbSJens Wiklander {
636817466cbSJens Wiklander     const mbedtls_ecp_curve_info *curve_info;
637817466cbSJens Wiklander 
638817466cbSJens Wiklander     if( ( curve_info = mbedtls_ecp_curve_info_from_grp_id( grp->id ) ) == NULL )
639817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
640817466cbSJens Wiklander 
641817466cbSJens Wiklander     /*
642817466cbSJens Wiklander      * We are going to write 3 bytes (see below)
643817466cbSJens Wiklander      */
644817466cbSJens Wiklander     *olen = 3;
645817466cbSJens Wiklander     if( blen < *olen )
646817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BUFFER_TOO_SMALL );
647817466cbSJens Wiklander 
648817466cbSJens Wiklander     /*
649817466cbSJens Wiklander      * First byte is curve_type, always named_curve
650817466cbSJens Wiklander      */
651817466cbSJens Wiklander     *buf++ = MBEDTLS_ECP_TLS_NAMED_CURVE;
652817466cbSJens Wiklander 
653817466cbSJens Wiklander     /*
654817466cbSJens Wiklander      * Next two bytes are the namedcurve value
655817466cbSJens Wiklander      */
656817466cbSJens Wiklander     buf[0] = curve_info->tls_id >> 8;
657817466cbSJens Wiklander     buf[1] = curve_info->tls_id & 0xFF;
658817466cbSJens Wiklander 
659817466cbSJens Wiklander     return( 0 );
660817466cbSJens Wiklander }
661817466cbSJens Wiklander 
662817466cbSJens Wiklander /*
663817466cbSJens Wiklander  * Wrapper around fast quasi-modp functions, with fall-back to mbedtls_mpi_mod_mpi.
664817466cbSJens Wiklander  * See the documentation of struct mbedtls_ecp_group.
665817466cbSJens Wiklander  *
666817466cbSJens Wiklander  * This function is in the critial loop for mbedtls_ecp_mul, so pay attention to perf.
667817466cbSJens Wiklander  */
668817466cbSJens Wiklander static int ecp_modp( mbedtls_mpi *N, const mbedtls_ecp_group *grp )
669817466cbSJens Wiklander {
670817466cbSJens Wiklander     int ret;
671817466cbSJens Wiklander 
672817466cbSJens Wiklander     if( grp->modp == NULL )
673817466cbSJens Wiklander         return( mbedtls_mpi_mod_mpi( N, N, &grp->P ) );
674817466cbSJens Wiklander 
675817466cbSJens Wiklander     /* N->s < 0 is a much faster test, which fails only if N is 0 */
676817466cbSJens Wiklander     if( ( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 ) ||
677817466cbSJens Wiklander         mbedtls_mpi_bitlen( N ) > 2 * grp->pbits )
678817466cbSJens Wiklander     {
679817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
680817466cbSJens Wiklander     }
681817466cbSJens Wiklander 
682817466cbSJens Wiklander     MBEDTLS_MPI_CHK( grp->modp( N ) );
683817466cbSJens Wiklander 
684817466cbSJens Wiklander     /* N->s < 0 is a much faster test, which fails only if N is 0 */
685817466cbSJens Wiklander     while( N->s < 0 && mbedtls_mpi_cmp_int( N, 0 ) != 0 )
686817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( N, N, &grp->P ) );
687817466cbSJens Wiklander 
688817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( N, &grp->P ) >= 0 )
689817466cbSJens Wiklander         /* we known P, N and the result are positive */
690817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( N, N, &grp->P ) );
691817466cbSJens Wiklander 
692817466cbSJens Wiklander cleanup:
693817466cbSJens Wiklander     return( ret );
694817466cbSJens Wiklander }
695817466cbSJens Wiklander 
696817466cbSJens Wiklander /*
697817466cbSJens Wiklander  * Fast mod-p functions expect their argument to be in the 0..p^2 range.
698817466cbSJens Wiklander  *
699817466cbSJens Wiklander  * In order to guarantee that, we need to ensure that operands of
700817466cbSJens Wiklander  * mbedtls_mpi_mul_mpi are in the 0..p range. So, after each operation we will
701817466cbSJens Wiklander  * bring the result back to this range.
702817466cbSJens Wiklander  *
703817466cbSJens Wiklander  * The following macros are shortcuts for doing that.
704817466cbSJens Wiklander  */
705817466cbSJens Wiklander 
706817466cbSJens Wiklander /*
707817466cbSJens Wiklander  * Reduce a mbedtls_mpi mod p in-place, general case, to use after mbedtls_mpi_mul_mpi
708817466cbSJens Wiklander  */
709817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
710817466cbSJens Wiklander #define INC_MUL_COUNT   mul_count++;
711817466cbSJens Wiklander #else
712817466cbSJens Wiklander #define INC_MUL_COUNT
713817466cbSJens Wiklander #endif
714817466cbSJens Wiklander 
715817466cbSJens Wiklander #define MOD_MUL( N )    do { MBEDTLS_MPI_CHK( ecp_modp( &N, grp ) ); INC_MUL_COUNT } \
716817466cbSJens Wiklander                         while( 0 )
717817466cbSJens Wiklander 
718817466cbSJens Wiklander /*
719817466cbSJens Wiklander  * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_sub_mpi
720817466cbSJens Wiklander  * N->s < 0 is a very fast test, which fails only if N is 0
721817466cbSJens Wiklander  */
722817466cbSJens Wiklander #define MOD_SUB( N )                                \
723817466cbSJens Wiklander     while( N.s < 0 && mbedtls_mpi_cmp_int( &N, 0 ) != 0 )   \
724817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &N, &N, &grp->P ) )
725817466cbSJens Wiklander 
726817466cbSJens Wiklander /*
727817466cbSJens Wiklander  * Reduce a mbedtls_mpi mod p in-place, to use after mbedtls_mpi_add_mpi and mbedtls_mpi_mul_int.
728817466cbSJens Wiklander  * We known P, N and the result are positive, so sub_abs is correct, and
729817466cbSJens Wiklander  * a bit faster.
730817466cbSJens Wiklander  */
731817466cbSJens Wiklander #define MOD_ADD( N )                                \
732817466cbSJens Wiklander     while( mbedtls_mpi_cmp_mpi( &N, &grp->P ) >= 0 )        \
733817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_abs( &N, &N, &grp->P ) )
734817466cbSJens Wiklander 
735817466cbSJens Wiklander #if defined(ECP_SHORTWEIERSTRASS)
736817466cbSJens Wiklander /*
737817466cbSJens Wiklander  * For curves in short Weierstrass form, we do all the internal operations in
738817466cbSJens Wiklander  * Jacobian coordinates.
739817466cbSJens Wiklander  *
740817466cbSJens Wiklander  * For multiplication, we'll use a comb method with coutermeasueres against
741817466cbSJens Wiklander  * SPA, hence timing attacks.
742817466cbSJens Wiklander  */
743817466cbSJens Wiklander 
744817466cbSJens Wiklander /*
745817466cbSJens Wiklander  * Normalize jacobian coordinates so that Z == 0 || Z == 1  (GECC 3.2.1)
746817466cbSJens Wiklander  * Cost: 1N := 1I + 3M + 1S
747817466cbSJens Wiklander  */
748817466cbSJens Wiklander static int ecp_normalize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt )
749817466cbSJens Wiklander {
750817466cbSJens Wiklander     int ret;
751817466cbSJens Wiklander     mbedtls_mpi Zi, ZZi;
752817466cbSJens Wiklander 
753817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &pt->Z, 0 ) == 0 )
754817466cbSJens Wiklander         return( 0 );
755817466cbSJens Wiklander 
756817466cbSJens Wiklander #if defined(MBEDTLS_ECP_NORMALIZE_JAC_ALT)
757817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
758817466cbSJens Wiklander     {
759817466cbSJens Wiklander         return mbedtls_internal_ecp_normalize_jac( grp, pt );
760817466cbSJens Wiklander     }
761817466cbSJens Wiklander #endif /* MBEDTLS_ECP_NORMALIZE_JAC_ALT */
762817466cbSJens Wiklander     mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi );
763817466cbSJens Wiklander 
764817466cbSJens Wiklander     /*
765817466cbSJens Wiklander      * X = X / Z^2  mod p
766817466cbSJens Wiklander      */
767817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &Zi,      &pt->Z,     &grp->P ) );
768817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi,     &Zi,        &Zi     ) ); MOD_MUL( ZZi );
769817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X,   &pt->X,     &ZZi    ) ); MOD_MUL( pt->X );
770817466cbSJens Wiklander 
771817466cbSJens Wiklander     /*
772817466cbSJens Wiklander      * Y = Y / Z^3  mod p
773817466cbSJens Wiklander      */
774817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y,   &pt->Y,     &ZZi    ) ); MOD_MUL( pt->Y );
775817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y,   &pt->Y,     &Zi     ) ); MOD_MUL( pt->Y );
776817466cbSJens Wiklander 
777817466cbSJens Wiklander     /*
778817466cbSJens Wiklander      * Z = 1
779817466cbSJens Wiklander      */
780817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &pt->Z, 1 ) );
781817466cbSJens Wiklander 
782817466cbSJens Wiklander cleanup:
783817466cbSJens Wiklander 
784817466cbSJens Wiklander     mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi );
785817466cbSJens Wiklander 
786817466cbSJens Wiklander     return( ret );
787817466cbSJens Wiklander }
788817466cbSJens Wiklander 
789817466cbSJens Wiklander /*
790817466cbSJens Wiklander  * Normalize jacobian coordinates of an array of (pointers to) points,
791817466cbSJens Wiklander  * using Montgomery's trick to perform only one inversion mod P.
792817466cbSJens Wiklander  * (See for example Cohen's "A Course in Computational Algebraic Number
793817466cbSJens Wiklander  * Theory", Algorithm 10.3.4.)
794817466cbSJens Wiklander  *
795817466cbSJens Wiklander  * Warning: fails (returning an error) if one of the points is zero!
796817466cbSJens Wiklander  * This should never happen, see choice of w in ecp_mul_comb().
797817466cbSJens Wiklander  *
798817466cbSJens Wiklander  * Cost: 1N(t) := 1I + (6t - 3)M + 1S
799817466cbSJens Wiklander  */
800817466cbSJens Wiklander static int ecp_normalize_jac_many( const mbedtls_ecp_group *grp,
801817466cbSJens Wiklander                                    mbedtls_ecp_point *T[], size_t t_len )
802817466cbSJens Wiklander {
803817466cbSJens Wiklander     int ret;
804817466cbSJens Wiklander     size_t i;
805817466cbSJens Wiklander     mbedtls_mpi *c, u, Zi, ZZi;
806817466cbSJens Wiklander 
807817466cbSJens Wiklander     if( t_len < 2 )
808817466cbSJens Wiklander         return( ecp_normalize_jac( grp, *T ) );
809817466cbSJens Wiklander 
810817466cbSJens Wiklander #if defined(MBEDTLS_ECP_NORMALIZE_JAC_MANY_ALT)
811817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
812817466cbSJens Wiklander     {
813817466cbSJens Wiklander         return mbedtls_internal_ecp_normalize_jac_many(grp, T, t_len);
814817466cbSJens Wiklander     }
815817466cbSJens Wiklander #endif
816817466cbSJens Wiklander 
817817466cbSJens Wiklander     if( ( c = mbedtls_calloc( t_len, sizeof( mbedtls_mpi ) ) ) == NULL )
818817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_ALLOC_FAILED );
819817466cbSJens Wiklander 
820817466cbSJens Wiklander     mbedtls_mpi_init( &u ); mbedtls_mpi_init( &Zi ); mbedtls_mpi_init( &ZZi );
821817466cbSJens Wiklander 
822817466cbSJens Wiklander     /*
823817466cbSJens Wiklander      * c[i] = Z_0 * ... * Z_i
824817466cbSJens Wiklander      */
825817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &c[0], &T[0]->Z ) );
826817466cbSJens Wiklander     for( i = 1; i < t_len; i++ )
827817466cbSJens Wiklander     {
828817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &c[i], &c[i-1], &T[i]->Z ) );
829817466cbSJens Wiklander         MOD_MUL( c[i] );
830817466cbSJens Wiklander     }
831817466cbSJens Wiklander 
832817466cbSJens Wiklander     /*
833817466cbSJens Wiklander      * u = 1 / (Z_0 * ... * Z_n) mod P
834817466cbSJens Wiklander      */
835817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &u, &c[t_len-1], &grp->P ) );
836817466cbSJens Wiklander 
837817466cbSJens Wiklander     for( i = t_len - 1; ; i-- )
838817466cbSJens Wiklander     {
839817466cbSJens Wiklander         /*
840817466cbSJens Wiklander          * Zi = 1 / Z_i mod p
841817466cbSJens Wiklander          * u = 1 / (Z_0 * ... * Z_i) mod P
842817466cbSJens Wiklander          */
843817466cbSJens Wiklander         if( i == 0 ) {
844817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &Zi, &u ) );
845817466cbSJens Wiklander         }
846817466cbSJens Wiklander         else
847817466cbSJens Wiklander         {
848817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Zi, &u, &c[i-1]  ) ); MOD_MUL( Zi );
849817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &u,  &u, &T[i]->Z ) ); MOD_MUL( u );
850817466cbSJens Wiklander         }
851817466cbSJens Wiklander 
852817466cbSJens Wiklander         /*
853817466cbSJens Wiklander          * proceed as in normalize()
854817466cbSJens Wiklander          */
855817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ZZi,     &Zi,      &Zi  ) ); MOD_MUL( ZZi );
856817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->X, &T[i]->X, &ZZi ) ); MOD_MUL( T[i]->X );
857817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &ZZi ) ); MOD_MUL( T[i]->Y );
858817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T[i]->Y, &T[i]->Y, &Zi  ) ); MOD_MUL( T[i]->Y );
859817466cbSJens Wiklander 
860817466cbSJens Wiklander         /*
861817466cbSJens Wiklander          * Post-precessing: reclaim some memory by shrinking coordinates
862817466cbSJens Wiklander          * - not storing Z (always 1)
863817466cbSJens Wiklander          * - shrinking other coordinates, but still keeping the same number of
864817466cbSJens Wiklander          *   limbs as P, as otherwise it will too likely be regrown too fast.
865817466cbSJens Wiklander          */
866817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->X, grp->P.n ) );
867817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_shrink( &T[i]->Y, grp->P.n ) );
868817466cbSJens Wiklander         mbedtls_mpi_free( &T[i]->Z );
869817466cbSJens Wiklander 
870817466cbSJens Wiklander         if( i == 0 )
871817466cbSJens Wiklander             break;
872817466cbSJens Wiklander     }
873817466cbSJens Wiklander 
874817466cbSJens Wiklander cleanup:
875817466cbSJens Wiklander 
876817466cbSJens Wiklander     mbedtls_mpi_free( &u ); mbedtls_mpi_free( &Zi ); mbedtls_mpi_free( &ZZi );
877817466cbSJens Wiklander     for( i = 0; i < t_len; i++ )
878817466cbSJens Wiklander         mbedtls_mpi_free( &c[i] );
879817466cbSJens Wiklander     mbedtls_free( c );
880817466cbSJens Wiklander 
881817466cbSJens Wiklander     return( ret );
882817466cbSJens Wiklander }
883817466cbSJens Wiklander 
884817466cbSJens Wiklander /*
885817466cbSJens Wiklander  * Conditional point inversion: Q -> -Q = (Q.X, -Q.Y, Q.Z) without leak.
886817466cbSJens Wiklander  * "inv" must be 0 (don't invert) or 1 (invert) or the result will be invalid
887817466cbSJens Wiklander  */
888817466cbSJens Wiklander static int ecp_safe_invert_jac( const mbedtls_ecp_group *grp,
889817466cbSJens Wiklander                             mbedtls_ecp_point *Q,
890817466cbSJens Wiklander                             unsigned char inv )
891817466cbSJens Wiklander {
892817466cbSJens Wiklander     int ret;
893817466cbSJens Wiklander     unsigned char nonzero;
894817466cbSJens Wiklander     mbedtls_mpi mQY;
895817466cbSJens Wiklander 
896817466cbSJens Wiklander     mbedtls_mpi_init( &mQY );
897817466cbSJens Wiklander 
898817466cbSJens Wiklander     /* Use the fact that -Q.Y mod P = P - Q.Y unless Q.Y == 0 */
899817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mQY, &grp->P, &Q->Y ) );
900817466cbSJens Wiklander     nonzero = mbedtls_mpi_cmp_int( &Q->Y, 0 ) != 0;
901817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &Q->Y, &mQY, inv & nonzero ) );
902817466cbSJens Wiklander 
903817466cbSJens Wiklander cleanup:
904817466cbSJens Wiklander     mbedtls_mpi_free( &mQY );
905817466cbSJens Wiklander 
906817466cbSJens Wiklander     return( ret );
907817466cbSJens Wiklander }
908817466cbSJens Wiklander 
909817466cbSJens Wiklander /*
910817466cbSJens Wiklander  * Point doubling R = 2 P, Jacobian coordinates
911817466cbSJens Wiklander  *
912817466cbSJens Wiklander  * Based on http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-1998-cmo-2 .
913817466cbSJens Wiklander  *
914817466cbSJens Wiklander  * We follow the variable naming fairly closely. The formula variations that trade a MUL for a SQR
915817466cbSJens Wiklander  * (plus a few ADDs) aren't useful as our bignum implementation doesn't distinguish squaring.
916817466cbSJens Wiklander  *
917817466cbSJens Wiklander  * Standard optimizations are applied when curve parameter A is one of { 0, -3 }.
918817466cbSJens Wiklander  *
919817466cbSJens Wiklander  * Cost: 1D := 3M + 4S          (A ==  0)
920817466cbSJens Wiklander  *             4M + 4S          (A == -3)
921817466cbSJens Wiklander  *             3M + 6S + 1a     otherwise
922817466cbSJens Wiklander  */
923817466cbSJens Wiklander static int ecp_double_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
924817466cbSJens Wiklander                            const mbedtls_ecp_point *P )
925817466cbSJens Wiklander {
926817466cbSJens Wiklander     int ret;
927817466cbSJens Wiklander     mbedtls_mpi M, S, T, U;
928817466cbSJens Wiklander 
929817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
930817466cbSJens Wiklander     dbl_count++;
931817466cbSJens Wiklander #endif
932817466cbSJens Wiklander 
933817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DOUBLE_JAC_ALT)
934817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
935817466cbSJens Wiklander     {
936817466cbSJens Wiklander         return mbedtls_internal_ecp_double_jac( grp, R, P );
937817466cbSJens Wiklander     }
938817466cbSJens Wiklander #endif /* MBEDTLS_ECP_DOUBLE_JAC_ALT */
939817466cbSJens Wiklander 
940817466cbSJens Wiklander     mbedtls_mpi_init( &M ); mbedtls_mpi_init( &S ); mbedtls_mpi_init( &T ); mbedtls_mpi_init( &U );
941817466cbSJens Wiklander 
942817466cbSJens Wiklander     /* Special case for A = -3 */
943817466cbSJens Wiklander     if( grp->A.p == NULL )
944817466cbSJens Wiklander     {
945817466cbSJens Wiklander         /* M = 3(X + Z^2)(X - Z^2) */
946817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S,  &P->Z,  &P->Z   ) ); MOD_MUL( S );
947817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &T,  &P->X,  &S      ) ); MOD_ADD( T );
948817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &U,  &P->X,  &S      ) ); MOD_SUB( U );
949817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S,  &T,     &U      ) ); MOD_MUL( S );
950817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M,  &S,     3       ) ); MOD_ADD( M );
951817466cbSJens Wiklander     }
952817466cbSJens Wiklander     else
953817466cbSJens Wiklander     {
954817466cbSJens Wiklander         /* M = 3.X^2 */
955817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S,  &P->X,  &P->X   ) ); MOD_MUL( S );
956817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &M,  &S,     3       ) ); MOD_ADD( M );
957817466cbSJens Wiklander 
958817466cbSJens Wiklander         /* Optimize away for "koblitz" curves with A = 0 */
959817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &grp->A, 0 ) != 0 )
960817466cbSJens Wiklander         {
961817466cbSJens Wiklander             /* M += A.Z^4 */
962817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S,  &P->Z,  &P->Z   ) ); MOD_MUL( S );
963817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T,  &S,     &S      ) ); MOD_MUL( T );
964817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S,  &T,     &grp->A ) ); MOD_MUL( S );
965817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &M,  &M,     &S      ) ); MOD_ADD( M );
966817466cbSJens Wiklander         }
967817466cbSJens Wiklander     }
968817466cbSJens Wiklander 
969817466cbSJens Wiklander     /* S = 4.X.Y^2 */
970817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T,  &P->Y,  &P->Y   ) ); MOD_MUL( T );
971817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &T,  1               ) ); MOD_ADD( T );
972817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S,  &P->X,  &T      ) ); MOD_MUL( S );
973817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &S,  1               ) ); MOD_ADD( S );
974817466cbSJens Wiklander 
975817466cbSJens Wiklander     /* U = 8.Y^4 */
976817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U,  &T,     &T      ) ); MOD_MUL( U );
977817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U,  1               ) ); MOD_ADD( U );
978817466cbSJens Wiklander 
979817466cbSJens Wiklander     /* T = M^2 - 2.S */
980817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T,  &M,     &M      ) ); MOD_MUL( T );
981817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T,  &T,     &S      ) ); MOD_SUB( T );
982817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T,  &T,     &S      ) ); MOD_SUB( T );
983817466cbSJens Wiklander 
984817466cbSJens Wiklander     /* S = M(S - T) - U */
985817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S,  &S,     &T      ) ); MOD_SUB( S );
986817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S,  &S,     &M      ) ); MOD_MUL( S );
987817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S,  &S,     &U      ) ); MOD_SUB( S );
988817466cbSJens Wiklander 
989817466cbSJens Wiklander     /* U = 2.Y.Z */
990817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &U,  &P->Y,  &P->Z   ) ); MOD_MUL( U );
991817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_shift_l( &U,  1               ) ); MOD_ADD( U );
992817466cbSJens Wiklander 
993817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &T ) );
994817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &S ) );
995817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &U ) );
996817466cbSJens Wiklander 
997817466cbSJens Wiklander cleanup:
998817466cbSJens Wiklander     mbedtls_mpi_free( &M ); mbedtls_mpi_free( &S ); mbedtls_mpi_free( &T ); mbedtls_mpi_free( &U );
999817466cbSJens Wiklander 
1000817466cbSJens Wiklander     return( ret );
1001817466cbSJens Wiklander }
1002817466cbSJens Wiklander 
1003817466cbSJens Wiklander /*
1004817466cbSJens Wiklander  * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
1005817466cbSJens Wiklander  *
1006817466cbSJens Wiklander  * The coordinates of Q must be normalized (= affine),
1007817466cbSJens Wiklander  * but those of P don't need to. R is not normalized.
1008817466cbSJens Wiklander  *
1009817466cbSJens Wiklander  * Special cases: (1) P or Q is zero, (2) R is zero, (3) P == Q.
1010817466cbSJens Wiklander  * None of these cases can happen as intermediate step in ecp_mul_comb():
1011817466cbSJens Wiklander  * - at each step, P, Q and R are multiples of the base point, the factor
1012817466cbSJens Wiklander  *   being less than its order, so none of them is zero;
1013817466cbSJens Wiklander  * - Q is an odd multiple of the base point, P an even multiple,
1014817466cbSJens Wiklander  *   due to the choice of precomputed points in the modified comb method.
1015817466cbSJens Wiklander  * So branches for these cases do not leak secret information.
1016817466cbSJens Wiklander  *
1017817466cbSJens Wiklander  * We accept Q->Z being unset (saving memory in tables) as meaning 1.
1018817466cbSJens Wiklander  *
1019817466cbSJens Wiklander  * Cost: 1A := 8M + 3S
1020817466cbSJens Wiklander  */
1021817466cbSJens Wiklander static int ecp_add_mixed( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
1022817466cbSJens Wiklander                           const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q )
1023817466cbSJens Wiklander {
1024817466cbSJens Wiklander     int ret;
1025817466cbSJens Wiklander     mbedtls_mpi T1, T2, T3, T4, X, Y, Z;
1026817466cbSJens Wiklander 
1027817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
1028817466cbSJens Wiklander     add_count++;
1029817466cbSJens Wiklander #endif
1030817466cbSJens Wiklander 
1031817466cbSJens Wiklander #if defined(MBEDTLS_ECP_ADD_MIXED_ALT)
1032817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
1033817466cbSJens Wiklander     {
1034817466cbSJens Wiklander         return mbedtls_internal_ecp_add_mixed( grp, R, P, Q );
1035817466cbSJens Wiklander     }
1036817466cbSJens Wiklander #endif /* MBEDTLS_ECP_ADD_MIXED_ALT */
1037817466cbSJens Wiklander 
1038817466cbSJens Wiklander     /*
1039817466cbSJens Wiklander      * Trivial cases: P == 0 or Q == 0 (case 1)
1040817466cbSJens Wiklander      */
1041817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &P->Z, 0 ) == 0 )
1042817466cbSJens Wiklander         return( mbedtls_ecp_copy( R, Q ) );
1043817466cbSJens Wiklander 
1044817466cbSJens Wiklander     if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 0 ) == 0 )
1045817466cbSJens Wiklander         return( mbedtls_ecp_copy( R, P ) );
1046817466cbSJens Wiklander 
1047817466cbSJens Wiklander     /*
1048817466cbSJens Wiklander      * Make sure Q coordinates are normalized
1049817466cbSJens Wiklander      */
1050817466cbSJens Wiklander     if( Q->Z.p != NULL && mbedtls_mpi_cmp_int( &Q->Z, 1 ) != 0 )
1051817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
1052817466cbSJens Wiklander 
1053817466cbSJens Wiklander     mbedtls_mpi_init( &T1 ); mbedtls_mpi_init( &T2 ); mbedtls_mpi_init( &T3 ); mbedtls_mpi_init( &T4 );
1054817466cbSJens Wiklander     mbedtls_mpi_init( &X ); mbedtls_mpi_init( &Y ); mbedtls_mpi_init( &Z );
1055817466cbSJens Wiklander 
1056817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1,  &P->Z,  &P->Z ) );  MOD_MUL( T1 );
1057817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2,  &T1,    &P->Z ) );  MOD_MUL( T2 );
1058817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T1,  &T1,    &Q->X ) );  MOD_MUL( T1 );
1059817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T2,  &T2,    &Q->Y ) );  MOD_MUL( T2 );
1060817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T1,  &T1,    &P->X ) );  MOD_SUB( T1 );
1061817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T2,  &T2,    &P->Y ) );  MOD_SUB( T2 );
1062817466cbSJens Wiklander 
1063817466cbSJens Wiklander     /* Special cases (2) and (3) */
1064817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &T1, 0 ) == 0 )
1065817466cbSJens Wiklander     {
1066817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &T2, 0 ) == 0 )
1067817466cbSJens Wiklander         {
1068817466cbSJens Wiklander             ret = ecp_double_jac( grp, R, P );
1069817466cbSJens Wiklander             goto cleanup;
1070817466cbSJens Wiklander         }
1071817466cbSJens Wiklander         else
1072817466cbSJens Wiklander         {
1073817466cbSJens Wiklander             ret = mbedtls_ecp_set_zero( R );
1074817466cbSJens Wiklander             goto cleanup;
1075817466cbSJens Wiklander         }
1076817466cbSJens Wiklander     }
1077817466cbSJens Wiklander 
1078817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &Z,   &P->Z,  &T1   ) );  MOD_MUL( Z  );
1079817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3,  &T1,    &T1   ) );  MOD_MUL( T3 );
1080817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4,  &T3,    &T1   ) );  MOD_MUL( T4 );
1081817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3,  &T3,    &P->X ) );  MOD_MUL( T3 );
1082817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_int( &T1,  &T3,    2     ) );  MOD_ADD( T1 );
1083817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &X,   &T2,    &T2   ) );  MOD_MUL( X  );
1084817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X,   &X,     &T1   ) );  MOD_SUB( X  );
1085817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &X,   &X,     &T4   ) );  MOD_SUB( X  );
1086817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &T3,  &T3,    &X    ) );  MOD_SUB( T3 );
1087817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T3,  &T3,    &T2   ) );  MOD_MUL( T3 );
1088817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &T4,  &T4,    &P->Y ) );  MOD_MUL( T4 );
1089817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &Y,   &T3,    &T4   ) );  MOD_SUB( Y  );
1090817466cbSJens Wiklander 
1091817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->X, &X ) );
1092817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Y, &Y ) );
1093817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &R->Z, &Z ) );
1094817466cbSJens Wiklander 
1095817466cbSJens Wiklander cleanup:
1096817466cbSJens Wiklander 
1097817466cbSJens Wiklander     mbedtls_mpi_free( &T1 ); mbedtls_mpi_free( &T2 ); mbedtls_mpi_free( &T3 ); mbedtls_mpi_free( &T4 );
1098817466cbSJens Wiklander     mbedtls_mpi_free( &X ); mbedtls_mpi_free( &Y ); mbedtls_mpi_free( &Z );
1099817466cbSJens Wiklander 
1100817466cbSJens Wiklander     return( ret );
1101817466cbSJens Wiklander }
1102817466cbSJens Wiklander 
1103817466cbSJens Wiklander /*
1104817466cbSJens Wiklander  * Randomize jacobian coordinates:
1105817466cbSJens Wiklander  * (X, Y, Z) -> (l^2 X, l^3 Y, l Z) for random l
1106817466cbSJens Wiklander  * This is sort of the reverse operation of ecp_normalize_jac().
1107817466cbSJens Wiklander  *
1108817466cbSJens Wiklander  * This countermeasure was first suggested in [2].
1109817466cbSJens Wiklander  */
1110817466cbSJens Wiklander static int ecp_randomize_jac( const mbedtls_ecp_group *grp, mbedtls_ecp_point *pt,
1111817466cbSJens Wiklander                 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
1112817466cbSJens Wiklander {
1113817466cbSJens Wiklander     int ret;
1114817466cbSJens Wiklander     mbedtls_mpi l, ll;
1115817466cbSJens Wiklander     size_t p_size;
1116817466cbSJens Wiklander     int count = 0;
1117817466cbSJens Wiklander 
1118817466cbSJens Wiklander #if defined(MBEDTLS_ECP_RANDOMIZE_JAC_ALT)
1119817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
1120817466cbSJens Wiklander     {
1121817466cbSJens Wiklander         return mbedtls_internal_ecp_randomize_jac( grp, pt, f_rng, p_rng );
1122817466cbSJens Wiklander     }
1123817466cbSJens Wiklander #endif /* MBEDTLS_ECP_RANDOMIZE_JAC_ALT */
1124817466cbSJens Wiklander 
1125817466cbSJens Wiklander     p_size = ( grp->pbits + 7 ) / 8;
1126817466cbSJens Wiklander     mbedtls_mpi_init( &l ); mbedtls_mpi_init( &ll );
1127817466cbSJens Wiklander 
1128817466cbSJens Wiklander     /* Generate l such that 1 < l < p */
1129817466cbSJens Wiklander     do
1130817466cbSJens Wiklander     {
1131817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) );
1132817466cbSJens Wiklander 
1133817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 )
1134817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) );
1135817466cbSJens Wiklander 
1136817466cbSJens Wiklander         if( count++ > 10 )
1137817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_RANDOM_FAILED );
1138817466cbSJens Wiklander     }
1139817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 );
1140817466cbSJens Wiklander 
1141817466cbSJens Wiklander     /* Z = l * Z */
1142817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Z,   &pt->Z,     &l  ) ); MOD_MUL( pt->Z );
1143817466cbSJens Wiklander 
1144817466cbSJens Wiklander     /* X = l^2 * X */
1145817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll,      &l,         &l  ) ); MOD_MUL( ll );
1146817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->X,   &pt->X,     &ll ) ); MOD_MUL( pt->X );
1147817466cbSJens Wiklander 
1148817466cbSJens Wiklander     /* Y = l^3 * Y */
1149817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &ll,      &ll,        &l  ) ); MOD_MUL( ll );
1150817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &pt->Y,   &pt->Y,     &ll ) ); MOD_MUL( pt->Y );
1151817466cbSJens Wiklander 
1152817466cbSJens Wiklander cleanup:
1153817466cbSJens Wiklander     mbedtls_mpi_free( &l ); mbedtls_mpi_free( &ll );
1154817466cbSJens Wiklander 
1155817466cbSJens Wiklander     return( ret );
1156817466cbSJens Wiklander }
1157817466cbSJens Wiklander 
1158817466cbSJens Wiklander /*
1159817466cbSJens Wiklander  * Check and define parameters used by the comb method (see below for details)
1160817466cbSJens Wiklander  */
1161817466cbSJens Wiklander #if MBEDTLS_ECP_WINDOW_SIZE < 2 || MBEDTLS_ECP_WINDOW_SIZE > 7
1162817466cbSJens Wiklander #error "MBEDTLS_ECP_WINDOW_SIZE out of bounds"
1163817466cbSJens Wiklander #endif
1164817466cbSJens Wiklander 
1165817466cbSJens Wiklander /* d = ceil( n / w ) */
1166817466cbSJens Wiklander #define COMB_MAX_D      ( MBEDTLS_ECP_MAX_BITS + 1 ) / 2
1167817466cbSJens Wiklander 
1168817466cbSJens Wiklander /* number of precomputed points */
1169817466cbSJens Wiklander #define COMB_MAX_PRE    ( 1 << ( MBEDTLS_ECP_WINDOW_SIZE - 1 ) )
1170817466cbSJens Wiklander 
1171817466cbSJens Wiklander /*
1172817466cbSJens Wiklander  * Compute the representation of m that will be used with our comb method.
1173817466cbSJens Wiklander  *
1174817466cbSJens Wiklander  * The basic comb method is described in GECC 3.44 for example. We use a
1175817466cbSJens Wiklander  * modified version that provides resistance to SPA by avoiding zero
1176817466cbSJens Wiklander  * digits in the representation as in [3]. We modify the method further by
1177817466cbSJens Wiklander  * requiring that all K_i be odd, which has the small cost that our
1178817466cbSJens Wiklander  * representation uses one more K_i, due to carries.
1179817466cbSJens Wiklander  *
1180817466cbSJens Wiklander  * Also, for the sake of compactness, only the seven low-order bits of x[i]
1181817466cbSJens Wiklander  * are used to represent K_i, and the msb of x[i] encodes the the sign (s_i in
1182817466cbSJens Wiklander  * the paper): it is set if and only if if s_i == -1;
1183817466cbSJens Wiklander  *
1184817466cbSJens Wiklander  * Calling conventions:
1185817466cbSJens Wiklander  * - x is an array of size d + 1
1186817466cbSJens Wiklander  * - w is the size, ie number of teeth, of the comb, and must be between
1187817466cbSJens Wiklander  *   2 and 7 (in practice, between 2 and MBEDTLS_ECP_WINDOW_SIZE)
1188817466cbSJens Wiklander  * - m is the MPI, expected to be odd and such that bitlength(m) <= w * d
1189817466cbSJens Wiklander  *   (the result will be incorrect if these assumptions are not satisfied)
1190817466cbSJens Wiklander  */
1191817466cbSJens Wiklander static void ecp_comb_fixed( unsigned char x[], size_t d,
1192817466cbSJens Wiklander                             unsigned char w, const mbedtls_mpi *m )
1193817466cbSJens Wiklander {
1194817466cbSJens Wiklander     size_t i, j;
1195817466cbSJens Wiklander     unsigned char c, cc, adjust;
1196817466cbSJens Wiklander 
1197817466cbSJens Wiklander     memset( x, 0, d+1 );
1198817466cbSJens Wiklander 
1199817466cbSJens Wiklander     /* First get the classical comb values (except for x_d = 0) */
1200817466cbSJens Wiklander     for( i = 0; i < d; i++ )
1201817466cbSJens Wiklander         for( j = 0; j < w; j++ )
1202817466cbSJens Wiklander             x[i] |= mbedtls_mpi_get_bit( m, i + d * j ) << j;
1203817466cbSJens Wiklander 
1204817466cbSJens Wiklander     /* Now make sure x_1 .. x_d are odd */
1205817466cbSJens Wiklander     c = 0;
1206817466cbSJens Wiklander     for( i = 1; i <= d; i++ )
1207817466cbSJens Wiklander     {
1208817466cbSJens Wiklander         /* Add carry and update it */
1209817466cbSJens Wiklander         cc   = x[i] & c;
1210817466cbSJens Wiklander         x[i] = x[i] ^ c;
1211817466cbSJens Wiklander         c = cc;
1212817466cbSJens Wiklander 
1213817466cbSJens Wiklander         /* Adjust if needed, avoiding branches */
1214817466cbSJens Wiklander         adjust = 1 - ( x[i] & 0x01 );
1215817466cbSJens Wiklander         c   |= x[i] & ( x[i-1] * adjust );
1216817466cbSJens Wiklander         x[i] = x[i] ^ ( x[i-1] * adjust );
1217817466cbSJens Wiklander         x[i-1] |= adjust << 7;
1218817466cbSJens Wiklander     }
1219817466cbSJens Wiklander }
1220817466cbSJens Wiklander 
1221817466cbSJens Wiklander /*
1222817466cbSJens Wiklander  * Precompute points for the comb method
1223817466cbSJens Wiklander  *
1224817466cbSJens Wiklander  * If i = i_{w-1} ... i_1 is the binary representation of i, then
1225817466cbSJens Wiklander  * T[i] = i_{w-1} 2^{(w-1)d} P + ... + i_1 2^d P + P
1226817466cbSJens Wiklander  *
1227817466cbSJens Wiklander  * T must be able to hold 2^{w - 1} elements
1228817466cbSJens Wiklander  *
1229817466cbSJens Wiklander  * Cost: d(w-1) D + (2^{w-1} - 1) A + 1 N(w-1) + 1 N(2^{w-1} - 1)
1230817466cbSJens Wiklander  */
1231817466cbSJens Wiklander static int ecp_precompute_comb( const mbedtls_ecp_group *grp,
1232817466cbSJens Wiklander                                 mbedtls_ecp_point T[], const mbedtls_ecp_point *P,
1233817466cbSJens Wiklander                                 unsigned char w, size_t d )
1234817466cbSJens Wiklander {
1235817466cbSJens Wiklander     int ret;
1236817466cbSJens Wiklander     unsigned char i, k;
1237817466cbSJens Wiklander     size_t j;
1238817466cbSJens Wiklander     mbedtls_ecp_point *cur, *TT[COMB_MAX_PRE - 1];
1239817466cbSJens Wiklander 
1240817466cbSJens Wiklander     /*
1241817466cbSJens Wiklander      * Set T[0] = P and
1242817466cbSJens Wiklander      * T[2^{l-1}] = 2^{dl} P for l = 1 .. w-1 (this is not the final value)
1243817466cbSJens Wiklander      */
1244817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &T[0], P ) );
1245817466cbSJens Wiklander 
1246817466cbSJens Wiklander     k = 0;
1247817466cbSJens Wiklander     for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 )
1248817466cbSJens Wiklander     {
1249817466cbSJens Wiklander         cur = T + i;
1250817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_copy( cur, T + ( i >> 1 ) ) );
1251817466cbSJens Wiklander         for( j = 0; j < d; j++ )
1252817466cbSJens Wiklander             MBEDTLS_MPI_CHK( ecp_double_jac( grp, cur, cur ) );
1253817466cbSJens Wiklander 
1254817466cbSJens Wiklander         TT[k++] = cur;
1255817466cbSJens Wiklander     }
1256817466cbSJens Wiklander 
1257817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) );
1258817466cbSJens Wiklander 
1259817466cbSJens Wiklander     /*
1260817466cbSJens Wiklander      * Compute the remaining ones using the minimal number of additions
1261817466cbSJens Wiklander      * Be careful to update T[2^l] only after using it!
1262817466cbSJens Wiklander      */
1263817466cbSJens Wiklander     k = 0;
1264817466cbSJens Wiklander     for( i = 1; i < ( 1U << ( w - 1 ) ); i <<= 1 )
1265817466cbSJens Wiklander     {
1266817466cbSJens Wiklander         j = i;
1267817466cbSJens Wiklander         while( j-- )
1268817466cbSJens Wiklander         {
1269817466cbSJens Wiklander             MBEDTLS_MPI_CHK( ecp_add_mixed( grp, &T[i + j], &T[j], &T[i] ) );
1270817466cbSJens Wiklander             TT[k++] = &T[i + j];
1271817466cbSJens Wiklander         }
1272817466cbSJens Wiklander     }
1273817466cbSJens Wiklander 
1274817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_normalize_jac_many( grp, TT, k ) );
1275817466cbSJens Wiklander 
1276817466cbSJens Wiklander cleanup:
1277817466cbSJens Wiklander 
1278817466cbSJens Wiklander     return( ret );
1279817466cbSJens Wiklander }
1280817466cbSJens Wiklander 
1281817466cbSJens Wiklander /*
1282817466cbSJens Wiklander  * Select precomputed point: R = sign(i) * T[ abs(i) / 2 ]
1283817466cbSJens Wiklander  */
1284817466cbSJens Wiklander static int ecp_select_comb( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
1285817466cbSJens Wiklander                             const mbedtls_ecp_point T[], unsigned char t_len,
1286817466cbSJens Wiklander                             unsigned char i )
1287817466cbSJens Wiklander {
1288817466cbSJens Wiklander     int ret;
1289817466cbSJens Wiklander     unsigned char ii, j;
1290817466cbSJens Wiklander 
1291817466cbSJens Wiklander     /* Ignore the "sign" bit and scale down */
1292817466cbSJens Wiklander     ii =  ( i & 0x7Fu ) >> 1;
1293817466cbSJens Wiklander 
1294817466cbSJens Wiklander     /* Read the whole table to thwart cache-based timing attacks */
1295817466cbSJens Wiklander     for( j = 0; j < t_len; j++ )
1296817466cbSJens Wiklander     {
1297817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->X, &T[j].X, j == ii ) );
1298817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &R->Y, &T[j].Y, j == ii ) );
1299817466cbSJens Wiklander     }
1300817466cbSJens Wiklander 
1301817466cbSJens Wiklander     /* Safely invert result if i is "negative" */
1302817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, i >> 7 ) );
1303817466cbSJens Wiklander 
1304817466cbSJens Wiklander cleanup:
1305817466cbSJens Wiklander     return( ret );
1306817466cbSJens Wiklander }
1307817466cbSJens Wiklander 
1308817466cbSJens Wiklander /*
1309817466cbSJens Wiklander  * Core multiplication algorithm for the (modified) comb method.
1310817466cbSJens Wiklander  * This part is actually common with the basic comb method (GECC 3.44)
1311817466cbSJens Wiklander  *
1312817466cbSJens Wiklander  * Cost: d A + d D + 1 R
1313817466cbSJens Wiklander  */
1314817466cbSJens Wiklander static int ecp_mul_comb_core( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
1315817466cbSJens Wiklander                               const mbedtls_ecp_point T[], unsigned char t_len,
1316817466cbSJens Wiklander                               const unsigned char x[], size_t d,
1317817466cbSJens Wiklander                               int (*f_rng)(void *, unsigned char *, size_t),
1318817466cbSJens Wiklander                               void *p_rng )
1319817466cbSJens Wiklander {
1320817466cbSJens Wiklander     int ret;
1321817466cbSJens Wiklander     mbedtls_ecp_point Txi;
1322817466cbSJens Wiklander     size_t i;
1323817466cbSJens Wiklander 
1324817466cbSJens Wiklander     mbedtls_ecp_point_init( &Txi );
1325817466cbSJens Wiklander 
1326817466cbSJens Wiklander     /* Start with a non-zero point and randomize its coordinates */
1327817466cbSJens Wiklander     i = d;
1328817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_select_comb( grp, R, T, t_len, x[i] ) );
1329817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 1 ) );
1330817466cbSJens Wiklander     if( f_rng != 0 )
1331817466cbSJens Wiklander         MBEDTLS_MPI_CHK( ecp_randomize_jac( grp, R, f_rng, p_rng ) );
1332817466cbSJens Wiklander 
1333817466cbSJens Wiklander     while( i-- != 0 )
1334817466cbSJens Wiklander     {
1335817466cbSJens Wiklander         MBEDTLS_MPI_CHK( ecp_double_jac( grp, R, R ) );
1336817466cbSJens Wiklander         MBEDTLS_MPI_CHK( ecp_select_comb( grp, &Txi, T, t_len, x[i] ) );
1337817466cbSJens Wiklander         MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, R, &Txi ) );
1338817466cbSJens Wiklander     }
1339817466cbSJens Wiklander 
1340817466cbSJens Wiklander cleanup:
1341817466cbSJens Wiklander 
1342817466cbSJens Wiklander     mbedtls_ecp_point_free( &Txi );
1343817466cbSJens Wiklander 
1344817466cbSJens Wiklander     return( ret );
1345817466cbSJens Wiklander }
1346817466cbSJens Wiklander 
1347817466cbSJens Wiklander /*
1348817466cbSJens Wiklander  * Multiplication using the comb method,
1349817466cbSJens Wiklander  * for curves in short Weierstrass form
1350817466cbSJens Wiklander  */
1351817466cbSJens Wiklander static int ecp_mul_comb( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
1352817466cbSJens Wiklander                          const mbedtls_mpi *m, const mbedtls_ecp_point *P,
1353817466cbSJens Wiklander                          int (*f_rng)(void *, unsigned char *, size_t),
1354817466cbSJens Wiklander                          void *p_rng )
1355817466cbSJens Wiklander {
1356817466cbSJens Wiklander     int ret;
1357817466cbSJens Wiklander     unsigned char w, m_is_odd, p_eq_g, pre_len, i;
1358817466cbSJens Wiklander     size_t d;
1359817466cbSJens Wiklander     unsigned char k[COMB_MAX_D + 1];
1360817466cbSJens Wiklander     mbedtls_ecp_point *T;
1361817466cbSJens Wiklander     mbedtls_mpi M, mm;
1362817466cbSJens Wiklander 
1363817466cbSJens Wiklander     mbedtls_mpi_init( &M );
1364817466cbSJens Wiklander     mbedtls_mpi_init( &mm );
1365817466cbSJens Wiklander 
1366817466cbSJens Wiklander     /* we need N to be odd to trnaform m in an odd number, check now */
1367817466cbSJens Wiklander     if( mbedtls_mpi_get_bit( &grp->N, 0 ) != 1 )
1368817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
1369817466cbSJens Wiklander 
1370817466cbSJens Wiklander     /*
1371817466cbSJens Wiklander      * Minimize the number of multiplications, that is minimize
1372817466cbSJens Wiklander      * 10 * d * w + 18 * 2^(w-1) + 11 * d + 7 * w, with d = ceil( nbits / w )
1373817466cbSJens Wiklander      * (see costs of the various parts, with 1S = 1M)
1374817466cbSJens Wiklander      */
1375817466cbSJens Wiklander     w = grp->nbits >= 384 ? 5 : 4;
1376817466cbSJens Wiklander 
1377817466cbSJens Wiklander     /*
1378817466cbSJens Wiklander      * If P == G, pre-compute a bit more, since this may be re-used later.
1379817466cbSJens Wiklander      * Just adding one avoids upping the cost of the first mul too much,
1380817466cbSJens Wiklander      * and the memory cost too.
1381817466cbSJens Wiklander      */
1382817466cbSJens Wiklander #if MBEDTLS_ECP_FIXED_POINT_OPTIM == 1
1383817466cbSJens Wiklander     p_eq_g = ( mbedtls_mpi_cmp_mpi( &P->Y, &grp->G.Y ) == 0 &&
1384817466cbSJens Wiklander                mbedtls_mpi_cmp_mpi( &P->X, &grp->G.X ) == 0 );
1385817466cbSJens Wiklander     if( p_eq_g )
1386817466cbSJens Wiklander         w++;
1387817466cbSJens Wiklander #else
1388817466cbSJens Wiklander     p_eq_g = 0;
1389817466cbSJens Wiklander #endif
1390817466cbSJens Wiklander 
1391817466cbSJens Wiklander     /*
1392817466cbSJens Wiklander      * Make sure w is within bounds.
1393817466cbSJens Wiklander      * (The last test is useful only for very small curves in the test suite.)
1394817466cbSJens Wiklander      */
1395817466cbSJens Wiklander     if( w > MBEDTLS_ECP_WINDOW_SIZE )
1396817466cbSJens Wiklander         w = MBEDTLS_ECP_WINDOW_SIZE;
1397817466cbSJens Wiklander     if( w >= grp->nbits )
1398817466cbSJens Wiklander         w = 2;
1399817466cbSJens Wiklander 
1400817466cbSJens Wiklander     /* Other sizes that depend on w */
1401817466cbSJens Wiklander     pre_len = 1U << ( w - 1 );
1402817466cbSJens Wiklander     d = ( grp->nbits + w - 1 ) / w;
1403817466cbSJens Wiklander 
1404817466cbSJens Wiklander     /*
1405817466cbSJens Wiklander      * Prepare precomputed points: if P == G we want to
1406817466cbSJens Wiklander      * use grp->T if already initialized, or initialize it.
1407817466cbSJens Wiklander      */
1408817466cbSJens Wiklander     T = p_eq_g ? grp->T : NULL;
1409817466cbSJens Wiklander 
1410817466cbSJens Wiklander     if( T == NULL )
1411817466cbSJens Wiklander     {
1412817466cbSJens Wiklander         T = mbedtls_calloc( pre_len, sizeof( mbedtls_ecp_point ) );
1413817466cbSJens Wiklander         if( T == NULL )
1414817466cbSJens Wiklander         {
1415817466cbSJens Wiklander             ret = MBEDTLS_ERR_ECP_ALLOC_FAILED;
1416817466cbSJens Wiklander             goto cleanup;
1417817466cbSJens Wiklander         }
1418817466cbSJens Wiklander 
1419817466cbSJens Wiklander         MBEDTLS_MPI_CHK( ecp_precompute_comb( grp, T, P, w, d ) );
1420817466cbSJens Wiklander 
1421817466cbSJens Wiklander         if( p_eq_g )
1422817466cbSJens Wiklander         {
1423817466cbSJens Wiklander             grp->T = T;
1424817466cbSJens Wiklander             grp->T_size = pre_len;
1425817466cbSJens Wiklander         }
1426817466cbSJens Wiklander     }
1427817466cbSJens Wiklander 
1428817466cbSJens Wiklander     /*
1429817466cbSJens Wiklander      * Make sure M is odd (M = m or M = N - m, since N is odd)
1430817466cbSJens Wiklander      * using the fact that m * P = - (N - m) * P
1431817466cbSJens Wiklander      */
1432817466cbSJens Wiklander     m_is_odd = ( mbedtls_mpi_get_bit( m, 0 ) == 1 );
1433817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &M, m ) );
1434817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &mm, &grp->N, m ) );
1435817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_assign( &M, &mm, ! m_is_odd ) );
1436817466cbSJens Wiklander 
1437817466cbSJens Wiklander     /*
1438817466cbSJens Wiklander      * Go for comb multiplication, R = M * P
1439817466cbSJens Wiklander      */
1440817466cbSJens Wiklander     ecp_comb_fixed( k, d, w, &M );
1441817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_mul_comb_core( grp, R, T, pre_len, k, d, f_rng, p_rng ) );
1442817466cbSJens Wiklander 
1443817466cbSJens Wiklander     /*
1444817466cbSJens Wiklander      * Now get m * P from M * P and normalize it
1445817466cbSJens Wiklander      */
1446817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_safe_invert_jac( grp, R, ! m_is_odd ) );
1447817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
1448817466cbSJens Wiklander 
1449817466cbSJens Wiklander cleanup:
1450817466cbSJens Wiklander 
1451817466cbSJens Wiklander     if( T != NULL && ! p_eq_g )
1452817466cbSJens Wiklander     {
1453817466cbSJens Wiklander         for( i = 0; i < pre_len; i++ )
1454817466cbSJens Wiklander             mbedtls_ecp_point_free( &T[i] );
1455817466cbSJens Wiklander         mbedtls_free( T );
1456817466cbSJens Wiklander     }
1457817466cbSJens Wiklander 
1458817466cbSJens Wiklander     mbedtls_mpi_free( &M );
1459817466cbSJens Wiklander     mbedtls_mpi_free( &mm );
1460817466cbSJens Wiklander 
1461817466cbSJens Wiklander     if( ret != 0 )
1462817466cbSJens Wiklander         mbedtls_ecp_point_free( R );
1463817466cbSJens Wiklander 
1464817466cbSJens Wiklander     return( ret );
1465817466cbSJens Wiklander }
1466817466cbSJens Wiklander 
1467817466cbSJens Wiklander #endif /* ECP_SHORTWEIERSTRASS */
1468817466cbSJens Wiklander 
1469817466cbSJens Wiklander #if defined(ECP_MONTGOMERY)
1470817466cbSJens Wiklander /*
1471817466cbSJens Wiklander  * For Montgomery curves, we do all the internal arithmetic in projective
1472817466cbSJens Wiklander  * coordinates. Import/export of points uses only the x coordinates, which is
1473817466cbSJens Wiklander  * internaly represented as X / Z.
1474817466cbSJens Wiklander  *
1475817466cbSJens Wiklander  * For scalar multiplication, we'll use a Montgomery ladder.
1476817466cbSJens Wiklander  */
1477817466cbSJens Wiklander 
1478817466cbSJens Wiklander /*
1479817466cbSJens Wiklander  * Normalize Montgomery x/z coordinates: X = X/Z, Z = 1
1480817466cbSJens Wiklander  * Cost: 1M + 1I
1481817466cbSJens Wiklander  */
1482817466cbSJens Wiklander static int ecp_normalize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P )
1483817466cbSJens Wiklander {
1484817466cbSJens Wiklander     int ret;
1485817466cbSJens Wiklander 
1486817466cbSJens Wiklander #if defined(MBEDTLS_ECP_NORMALIZE_MXZ_ALT)
1487817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
1488817466cbSJens Wiklander     {
1489817466cbSJens Wiklander         return mbedtls_internal_ecp_normalize_mxz( grp, P );
1490817466cbSJens Wiklander     }
1491817466cbSJens Wiklander #endif /* MBEDTLS_ECP_NORMALIZE_MXZ_ALT */
1492817466cbSJens Wiklander 
1493817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_inv_mod( &P->Z, &P->Z, &grp->P ) );
1494817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &P->Z ) ); MOD_MUL( P->X );
1495817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &P->Z, 1 ) );
1496817466cbSJens Wiklander 
1497817466cbSJens Wiklander cleanup:
1498817466cbSJens Wiklander     return( ret );
1499817466cbSJens Wiklander }
1500817466cbSJens Wiklander 
1501817466cbSJens Wiklander /*
1502817466cbSJens Wiklander  * Randomize projective x/z coordinates:
1503817466cbSJens Wiklander  * (X, Z) -> (l X, l Z) for random l
1504817466cbSJens Wiklander  * This is sort of the reverse operation of ecp_normalize_mxz().
1505817466cbSJens Wiklander  *
1506817466cbSJens Wiklander  * This countermeasure was first suggested in [2].
1507817466cbSJens Wiklander  * Cost: 2M
1508817466cbSJens Wiklander  */
1509817466cbSJens Wiklander static int ecp_randomize_mxz( const mbedtls_ecp_group *grp, mbedtls_ecp_point *P,
1510817466cbSJens Wiklander                 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
1511817466cbSJens Wiklander {
1512817466cbSJens Wiklander     int ret;
1513817466cbSJens Wiklander     mbedtls_mpi l;
1514817466cbSJens Wiklander     size_t p_size;
1515817466cbSJens Wiklander     int count = 0;
1516817466cbSJens Wiklander 
1517817466cbSJens Wiklander #if defined(MBEDTLS_ECP_RANDOMIZE_MXZ_ALT)
1518817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
1519817466cbSJens Wiklander     {
1520817466cbSJens Wiklander         return mbedtls_internal_ecp_randomize_mxz( grp, P, f_rng, p_rng );
1521817466cbSJens Wiklander     }
1522817466cbSJens Wiklander #endif /* MBEDTLS_ECP_RANDOMIZE_MXZ_ALT */
1523817466cbSJens Wiklander 
1524817466cbSJens Wiklander     p_size = ( grp->pbits + 7 ) / 8;
1525817466cbSJens Wiklander     mbedtls_mpi_init( &l );
1526817466cbSJens Wiklander 
1527817466cbSJens Wiklander     /* Generate l such that 1 < l < p */
1528817466cbSJens Wiklander     do
1529817466cbSJens Wiklander     {
1530817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( &l, p_size, f_rng, p_rng ) );
1531817466cbSJens Wiklander 
1532817466cbSJens Wiklander         while( mbedtls_mpi_cmp_mpi( &l, &grp->P ) >= 0 )
1533817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( &l, 1 ) );
1534817466cbSJens Wiklander 
1535817466cbSJens Wiklander         if( count++ > 10 )
1536817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_RANDOM_FAILED );
1537817466cbSJens Wiklander     }
1538817466cbSJens Wiklander     while( mbedtls_mpi_cmp_int( &l, 1 ) <= 0 );
1539817466cbSJens Wiklander 
1540817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->X, &P->X, &l ) ); MOD_MUL( P->X );
1541817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &P->Z, &P->Z, &l ) ); MOD_MUL( P->Z );
1542817466cbSJens Wiklander 
1543817466cbSJens Wiklander cleanup:
1544817466cbSJens Wiklander     mbedtls_mpi_free( &l );
1545817466cbSJens Wiklander 
1546817466cbSJens Wiklander     return( ret );
1547817466cbSJens Wiklander }
1548817466cbSJens Wiklander 
1549817466cbSJens Wiklander /*
1550817466cbSJens Wiklander  * Double-and-add: R = 2P, S = P + Q, with d = X(P - Q),
1551817466cbSJens Wiklander  * for Montgomery curves in x/z coordinates.
1552817466cbSJens Wiklander  *
1553817466cbSJens Wiklander  * http://www.hyperelliptic.org/EFD/g1p/auto-code/montgom/xz/ladder/mladd-1987-m.op3
1554817466cbSJens Wiklander  * with
1555817466cbSJens Wiklander  * d =  X1
1556817466cbSJens Wiklander  * P = (X2, Z2)
1557817466cbSJens Wiklander  * Q = (X3, Z3)
1558817466cbSJens Wiklander  * R = (X4, Z4)
1559817466cbSJens Wiklander  * S = (X5, Z5)
1560817466cbSJens Wiklander  * and eliminating temporary variables tO, ..., t4.
1561817466cbSJens Wiklander  *
1562817466cbSJens Wiklander  * Cost: 5M + 4S
1563817466cbSJens Wiklander  */
1564817466cbSJens Wiklander static int ecp_double_add_mxz( const mbedtls_ecp_group *grp,
1565817466cbSJens Wiklander                                mbedtls_ecp_point *R, mbedtls_ecp_point *S,
1566817466cbSJens Wiklander                                const mbedtls_ecp_point *P, const mbedtls_ecp_point *Q,
1567817466cbSJens Wiklander                                const mbedtls_mpi *d )
1568817466cbSJens Wiklander {
1569817466cbSJens Wiklander     int ret;
1570817466cbSJens Wiklander     mbedtls_mpi A, AA, B, BB, E, C, D, DA, CB;
1571817466cbSJens Wiklander 
1572817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT)
1573817466cbSJens Wiklander     if ( mbedtls_internal_ecp_grp_capable( grp ) )
1574817466cbSJens Wiklander     {
1575817466cbSJens Wiklander         return mbedtls_internal_ecp_double_add_mxz( grp, R, S, P, Q, d );
1576817466cbSJens Wiklander     }
1577817466cbSJens Wiklander #endif /* MBEDTLS_ECP_DOUBLE_ADD_MXZ_ALT */
1578817466cbSJens Wiklander 
1579817466cbSJens Wiklander     mbedtls_mpi_init( &A ); mbedtls_mpi_init( &AA ); mbedtls_mpi_init( &B );
1580817466cbSJens Wiklander     mbedtls_mpi_init( &BB ); mbedtls_mpi_init( &E ); mbedtls_mpi_init( &C );
1581817466cbSJens Wiklander     mbedtls_mpi_init( &D ); mbedtls_mpi_init( &DA ); mbedtls_mpi_init( &CB );
1582817466cbSJens Wiklander 
1583817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &A,    &P->X,   &P->Z ) ); MOD_ADD( A    );
1584817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &AA,   &A,      &A    ) ); MOD_MUL( AA   );
1585817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &B,    &P->X,   &P->Z ) ); MOD_SUB( B    );
1586817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &BB,   &B,      &B    ) ); MOD_MUL( BB   );
1587817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &E,    &AA,     &BB   ) ); MOD_SUB( E    );
1588817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &C,    &Q->X,   &Q->Z ) ); MOD_ADD( C    );
1589817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &D,    &Q->X,   &Q->Z ) ); MOD_SUB( D    );
1590817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &DA,   &D,      &A    ) ); MOD_MUL( DA   );
1591817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &CB,   &C,      &B    ) ); MOD_MUL( CB   );
1592817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &S->X, &DA,     &CB   ) ); MOD_MUL( S->X );
1593817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->X, &S->X,   &S->X ) ); MOD_MUL( S->X );
1594817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &S->Z, &DA,     &CB   ) ); MOD_SUB( S->Z );
1595817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, &S->Z,   &S->Z ) ); MOD_MUL( S->Z );
1596817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &S->Z, d,       &S->Z ) ); MOD_MUL( S->Z );
1597817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->X, &AA,     &BB   ) ); MOD_MUL( R->X );
1598817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &grp->A, &E    ) ); MOD_MUL( R->Z );
1599817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &R->Z, &BB,     &R->Z ) ); MOD_ADD( R->Z );
1600817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &R->Z, &E,      &R->Z ) ); MOD_MUL( R->Z );
1601817466cbSJens Wiklander 
1602817466cbSJens Wiklander cleanup:
1603817466cbSJens Wiklander     mbedtls_mpi_free( &A ); mbedtls_mpi_free( &AA ); mbedtls_mpi_free( &B );
1604817466cbSJens Wiklander     mbedtls_mpi_free( &BB ); mbedtls_mpi_free( &E ); mbedtls_mpi_free( &C );
1605817466cbSJens Wiklander     mbedtls_mpi_free( &D ); mbedtls_mpi_free( &DA ); mbedtls_mpi_free( &CB );
1606817466cbSJens Wiklander 
1607817466cbSJens Wiklander     return( ret );
1608817466cbSJens Wiklander }
1609817466cbSJens Wiklander 
1610817466cbSJens Wiklander /*
1611817466cbSJens Wiklander  * Multiplication with Montgomery ladder in x/z coordinates,
1612817466cbSJens Wiklander  * for curves in Montgomery form
1613817466cbSJens Wiklander  */
1614817466cbSJens Wiklander static int ecp_mul_mxz( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
1615817466cbSJens Wiklander                         const mbedtls_mpi *m, const mbedtls_ecp_point *P,
1616817466cbSJens Wiklander                         int (*f_rng)(void *, unsigned char *, size_t),
1617817466cbSJens Wiklander                         void *p_rng )
1618817466cbSJens Wiklander {
1619817466cbSJens Wiklander     int ret;
1620817466cbSJens Wiklander     size_t i;
1621817466cbSJens Wiklander     unsigned char b;
1622817466cbSJens Wiklander     mbedtls_ecp_point RP;
1623817466cbSJens Wiklander     mbedtls_mpi PX;
1624817466cbSJens Wiklander 
1625817466cbSJens Wiklander     mbedtls_ecp_point_init( &RP ); mbedtls_mpi_init( &PX );
1626817466cbSJens Wiklander 
1627817466cbSJens Wiklander     /* Save PX and read from P before writing to R, in case P == R */
1628817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_copy( &PX, &P->X ) );
1629817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_copy( &RP, P ) );
1630817466cbSJens Wiklander 
1631817466cbSJens Wiklander     /* Set R to zero in modified x/z coordinates */
1632817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->X, 1 ) );
1633817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &R->Z, 0 ) );
1634817466cbSJens Wiklander     mbedtls_mpi_free( &R->Y );
1635817466cbSJens Wiklander 
1636817466cbSJens Wiklander     /* RP.X might be sligtly larger than P, so reduce it */
1637817466cbSJens Wiklander     MOD_ADD( RP.X );
1638817466cbSJens Wiklander 
1639817466cbSJens Wiklander     /* Randomize coordinates of the starting point */
1640817466cbSJens Wiklander     if( f_rng != NULL )
1641817466cbSJens Wiklander         MBEDTLS_MPI_CHK( ecp_randomize_mxz( grp, &RP, f_rng, p_rng ) );
1642817466cbSJens Wiklander 
1643817466cbSJens Wiklander     /* Loop invariant: R = result so far, RP = R + P */
1644817466cbSJens Wiklander     i = mbedtls_mpi_bitlen( m ); /* one past the (zero-based) most significant bit */
1645817466cbSJens Wiklander     while( i-- > 0 )
1646817466cbSJens Wiklander     {
1647817466cbSJens Wiklander         b = mbedtls_mpi_get_bit( m, i );
1648817466cbSJens Wiklander         /*
1649817466cbSJens Wiklander          *  if (b) R = 2R + P else R = 2R,
1650817466cbSJens Wiklander          * which is:
1651817466cbSJens Wiklander          *  if (b) double_add( RP, R, RP, R )
1652817466cbSJens Wiklander          *  else   double_add( R, RP, R, RP )
1653817466cbSJens Wiklander          * but using safe conditional swaps to avoid leaks
1654817466cbSJens Wiklander          */
1655817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) );
1656817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) );
1657817466cbSJens Wiklander         MBEDTLS_MPI_CHK( ecp_double_add_mxz( grp, R, &RP, R, &RP, &PX ) );
1658817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->X, &RP.X, b ) );
1659817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_safe_cond_swap( &R->Z, &RP.Z, b ) );
1660817466cbSJens Wiklander     }
1661817466cbSJens Wiklander 
1662817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_normalize_mxz( grp, R ) );
1663817466cbSJens Wiklander 
1664817466cbSJens Wiklander cleanup:
1665817466cbSJens Wiklander     mbedtls_ecp_point_free( &RP ); mbedtls_mpi_free( &PX );
1666817466cbSJens Wiklander 
1667817466cbSJens Wiklander     return( ret );
1668817466cbSJens Wiklander }
1669817466cbSJens Wiklander 
1670817466cbSJens Wiklander #endif /* ECP_MONTGOMERY */
1671817466cbSJens Wiklander 
1672817466cbSJens Wiklander /*
1673817466cbSJens Wiklander  * Multiplication R = m * P
1674817466cbSJens Wiklander  */
1675817466cbSJens Wiklander int mbedtls_ecp_mul( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
1676817466cbSJens Wiklander              const mbedtls_mpi *m, const mbedtls_ecp_point *P,
1677817466cbSJens Wiklander              int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
1678817466cbSJens Wiklander {
1679817466cbSJens Wiklander     int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
1680817466cbSJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT)
1681817466cbSJens Wiklander     char is_grp_capable = 0;
1682817466cbSJens Wiklander #endif
1683817466cbSJens Wiklander 
1684817466cbSJens Wiklander     /* Common sanity checks */
1685817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &P->Z, 1 ) != 0 )
1686817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
1687817466cbSJens Wiklander 
1688817466cbSJens Wiklander     if( ( ret = mbedtls_ecp_check_privkey( grp, m ) ) != 0 ||
1689817466cbSJens Wiklander         ( ret = mbedtls_ecp_check_pubkey( grp, P ) ) != 0 )
1690817466cbSJens Wiklander         return( ret );
1691817466cbSJens Wiklander 
1692817466cbSJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT)
1693817466cbSJens Wiklander     if ( is_grp_capable = mbedtls_internal_ecp_grp_capable( grp )  )
1694817466cbSJens Wiklander     {
1695817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) );
1696817466cbSJens Wiklander     }
1697817466cbSJens Wiklander 
1698817466cbSJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */
1699817466cbSJens Wiklander #if defined(ECP_MONTGOMERY)
1700817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
1701817466cbSJens Wiklander         ret = ecp_mul_mxz( grp, R, m, P, f_rng, p_rng );
1702817466cbSJens Wiklander 
1703817466cbSJens Wiklander #endif
1704817466cbSJens Wiklander #if defined(ECP_SHORTWEIERSTRASS)
1705817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
1706817466cbSJens Wiklander         ret = ecp_mul_comb( grp, R, m, P, f_rng, p_rng );
1707817466cbSJens Wiklander 
1708817466cbSJens Wiklander #endif
1709817466cbSJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT)
1710817466cbSJens Wiklander cleanup:
1711817466cbSJens Wiklander 
1712817466cbSJens Wiklander     if ( is_grp_capable )
1713817466cbSJens Wiklander     {
1714817466cbSJens Wiklander         mbedtls_internal_ecp_free( grp );
1715817466cbSJens Wiklander     }
1716817466cbSJens Wiklander 
1717817466cbSJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */
1718817466cbSJens Wiklander     return( ret );
1719817466cbSJens Wiklander }
1720817466cbSJens Wiklander 
1721817466cbSJens Wiklander #if defined(ECP_SHORTWEIERSTRASS)
1722817466cbSJens Wiklander /*
1723817466cbSJens Wiklander  * Check that an affine point is valid as a public key,
1724817466cbSJens Wiklander  * short weierstrass curves (SEC1 3.2.3.1)
1725817466cbSJens Wiklander  */
1726817466cbSJens Wiklander static int ecp_check_pubkey_sw( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt )
1727817466cbSJens Wiklander {
1728817466cbSJens Wiklander     int ret;
1729817466cbSJens Wiklander     mbedtls_mpi YY, RHS;
1730817466cbSJens Wiklander 
1731817466cbSJens Wiklander     /* pt coordinates must be normalized for our checks */
1732817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &pt->X, 0 ) < 0 ||
1733817466cbSJens Wiklander         mbedtls_mpi_cmp_int( &pt->Y, 0 ) < 0 ||
1734817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 ||
1735817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 )
1736817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_INVALID_KEY );
1737817466cbSJens Wiklander 
1738817466cbSJens Wiklander     mbedtls_mpi_init( &YY ); mbedtls_mpi_init( &RHS );
1739817466cbSJens Wiklander 
1740817466cbSJens Wiklander     /*
1741817466cbSJens Wiklander      * YY = Y^2
1742817466cbSJens Wiklander      * RHS = X (X^2 + A) + B = X^3 + A X + B
1743817466cbSJens Wiklander      */
1744817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &YY,  &pt->Y,   &pt->Y  ) );  MOD_MUL( YY  );
1745817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &pt->X,   &pt->X  ) );  MOD_MUL( RHS );
1746817466cbSJens Wiklander 
1747817466cbSJens Wiklander     /* Special case for A = -3 */
1748817466cbSJens Wiklander     if( grp->A.p == NULL )
1749817466cbSJens Wiklander     {
1750817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_sub_int( &RHS, &RHS, 3       ) );  MOD_SUB( RHS );
1751817466cbSJens Wiklander     }
1752817466cbSJens Wiklander     else
1753817466cbSJens Wiklander     {
1754817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS, &grp->A ) );  MOD_ADD( RHS );
1755817466cbSJens Wiklander     }
1756817466cbSJens Wiklander 
1757817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_mul_mpi( &RHS, &RHS,     &pt->X  ) );  MOD_MUL( RHS );
1758817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_add_mpi( &RHS, &RHS,     &grp->B ) );  MOD_ADD( RHS );
1759817466cbSJens Wiklander 
1760817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &YY, &RHS ) != 0 )
1761817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_INVALID_KEY;
1762817466cbSJens Wiklander 
1763817466cbSJens Wiklander cleanup:
1764817466cbSJens Wiklander 
1765817466cbSJens Wiklander     mbedtls_mpi_free( &YY ); mbedtls_mpi_free( &RHS );
1766817466cbSJens Wiklander 
1767817466cbSJens Wiklander     return( ret );
1768817466cbSJens Wiklander }
1769817466cbSJens Wiklander #endif /* ECP_SHORTWEIERSTRASS */
1770817466cbSJens Wiklander 
1771817466cbSJens Wiklander /*
1772817466cbSJens Wiklander  * R = m * P with shortcuts for m == 1 and m == -1
1773817466cbSJens Wiklander  * NOT constant-time - ONLY for short Weierstrass!
1774817466cbSJens Wiklander  */
1775817466cbSJens Wiklander static int mbedtls_ecp_mul_shortcuts( mbedtls_ecp_group *grp,
1776817466cbSJens Wiklander                                       mbedtls_ecp_point *R,
1777817466cbSJens Wiklander                                       const mbedtls_mpi *m,
1778817466cbSJens Wiklander                                       const mbedtls_ecp_point *P )
1779817466cbSJens Wiklander {
1780817466cbSJens Wiklander     int ret;
1781817466cbSJens Wiklander 
1782817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( m, 1 ) == 0 )
1783817466cbSJens Wiklander     {
1784817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) );
1785817466cbSJens Wiklander     }
1786817466cbSJens Wiklander     else if( mbedtls_mpi_cmp_int( m, -1 ) == 0 )
1787817466cbSJens Wiklander     {
1788817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_copy( R, P ) );
1789817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( &R->Y, 0 ) != 0 )
1790817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_sub_mpi( &R->Y, &grp->P, &R->Y ) );
1791817466cbSJens Wiklander     }
1792817466cbSJens Wiklander     else
1793817466cbSJens Wiklander     {
1794817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_mul( grp, R, m, P, NULL, NULL ) );
1795817466cbSJens Wiklander     }
1796817466cbSJens Wiklander 
1797817466cbSJens Wiklander cleanup:
1798817466cbSJens Wiklander     return( ret );
1799817466cbSJens Wiklander }
1800817466cbSJens Wiklander 
1801817466cbSJens Wiklander /*
1802817466cbSJens Wiklander  * Linear combination
1803817466cbSJens Wiklander  * NOT constant-time
1804817466cbSJens Wiklander  */
1805817466cbSJens Wiklander int mbedtls_ecp_muladd( mbedtls_ecp_group *grp, mbedtls_ecp_point *R,
1806817466cbSJens Wiklander              const mbedtls_mpi *m, const mbedtls_ecp_point *P,
1807817466cbSJens Wiklander              const mbedtls_mpi *n, const mbedtls_ecp_point *Q )
1808817466cbSJens Wiklander {
1809817466cbSJens Wiklander     int ret;
1810817466cbSJens Wiklander     mbedtls_ecp_point mP;
1811817466cbSJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT)
1812817466cbSJens Wiklander     char is_grp_capable = 0;
1813817466cbSJens Wiklander #endif
1814817466cbSJens Wiklander 
1815817466cbSJens Wiklander     if( ecp_get_type( grp ) != ECP_TYPE_SHORT_WEIERSTRASS )
1816817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE );
1817817466cbSJens Wiklander 
1818817466cbSJens Wiklander     mbedtls_ecp_point_init( &mP );
1819817466cbSJens Wiklander 
1820817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, &mP, m, P ) );
1821817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul_shortcuts( grp, R,   n, Q ) );
1822817466cbSJens Wiklander 
1823817466cbSJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT)
1824817466cbSJens Wiklander     if (  is_grp_capable = mbedtls_internal_ecp_grp_capable( grp )  )
1825817466cbSJens Wiklander     {
1826817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_internal_ecp_init( grp ) );
1827817466cbSJens Wiklander     }
1828817466cbSJens Wiklander 
1829817466cbSJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */
1830817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_add_mixed( grp, R, &mP, R ) );
1831817466cbSJens Wiklander     MBEDTLS_MPI_CHK( ecp_normalize_jac( grp, R ) );
1832817466cbSJens Wiklander 
1833817466cbSJens Wiklander cleanup:
1834817466cbSJens Wiklander 
1835817466cbSJens Wiklander #if defined(MBEDTLS_ECP_INTERNAL_ALT)
1836817466cbSJens Wiklander     if ( is_grp_capable )
1837817466cbSJens Wiklander     {
1838817466cbSJens Wiklander         mbedtls_internal_ecp_free( grp );
1839817466cbSJens Wiklander     }
1840817466cbSJens Wiklander 
1841817466cbSJens Wiklander #endif /* MBEDTLS_ECP_INTERNAL_ALT */
1842817466cbSJens Wiklander     mbedtls_ecp_point_free( &mP );
1843817466cbSJens Wiklander 
1844817466cbSJens Wiklander     return( ret );
1845817466cbSJens Wiklander }
1846817466cbSJens Wiklander 
1847817466cbSJens Wiklander 
1848817466cbSJens Wiklander #if defined(ECP_MONTGOMERY)
1849817466cbSJens Wiklander /*
1850817466cbSJens Wiklander  * Check validity of a public key for Montgomery curves with x-only schemes
1851817466cbSJens Wiklander  */
1852817466cbSJens Wiklander static int ecp_check_pubkey_mx( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt )
1853817466cbSJens Wiklander {
1854817466cbSJens Wiklander     /* [Curve25519 p. 5] Just check X is the correct number of bytes */
1855817466cbSJens Wiklander     if( mbedtls_mpi_size( &pt->X ) > ( grp->nbits + 7 ) / 8 )
1856817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_INVALID_KEY );
1857817466cbSJens Wiklander 
1858817466cbSJens Wiklander     return( 0 );
1859817466cbSJens Wiklander }
1860817466cbSJens Wiklander #endif /* ECP_MONTGOMERY */
1861817466cbSJens Wiklander 
1862817466cbSJens Wiklander /*
1863817466cbSJens Wiklander  * Check that a point is valid as a public key
1864817466cbSJens Wiklander  */
1865817466cbSJens Wiklander int mbedtls_ecp_check_pubkey( const mbedtls_ecp_group *grp, const mbedtls_ecp_point *pt )
1866817466cbSJens Wiklander {
1867817466cbSJens Wiklander     /* Must use affine coordinates */
1868817466cbSJens Wiklander     if( mbedtls_mpi_cmp_int( &pt->Z, 1 ) != 0 )
1869817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_INVALID_KEY );
1870817466cbSJens Wiklander 
1871817466cbSJens Wiklander #if defined(ECP_MONTGOMERY)
1872817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
1873817466cbSJens Wiklander         return( ecp_check_pubkey_mx( grp, pt ) );
1874817466cbSJens Wiklander #endif
1875817466cbSJens Wiklander #if defined(ECP_SHORTWEIERSTRASS)
1876817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
1877817466cbSJens Wiklander         return( ecp_check_pubkey_sw( grp, pt ) );
1878817466cbSJens Wiklander #endif
1879817466cbSJens Wiklander     return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
1880817466cbSJens Wiklander }
1881817466cbSJens Wiklander 
1882817466cbSJens Wiklander /*
1883817466cbSJens Wiklander  * Check that an mbedtls_mpi is valid as a private key
1884817466cbSJens Wiklander  */
1885817466cbSJens Wiklander int mbedtls_ecp_check_privkey( const mbedtls_ecp_group *grp, const mbedtls_mpi *d )
1886817466cbSJens Wiklander {
1887817466cbSJens Wiklander #if defined(ECP_MONTGOMERY)
1888817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
1889817466cbSJens Wiklander     {
1890817466cbSJens Wiklander         /* see [Curve25519] page 5 */
1891817466cbSJens Wiklander         if( mbedtls_mpi_get_bit( d, 0 ) != 0 ||
1892817466cbSJens Wiklander             mbedtls_mpi_get_bit( d, 1 ) != 0 ||
1893817466cbSJens Wiklander             mbedtls_mpi_get_bit( d, 2 ) != 0 ||
1894817466cbSJens Wiklander             mbedtls_mpi_bitlen( d ) - 1 != grp->nbits ) /* mbedtls_mpi_bitlen is one-based! */
1895817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_INVALID_KEY );
1896817466cbSJens Wiklander         else
1897817466cbSJens Wiklander             return( 0 );
1898817466cbSJens Wiklander     }
1899817466cbSJens Wiklander #endif /* ECP_MONTGOMERY */
1900817466cbSJens Wiklander #if defined(ECP_SHORTWEIERSTRASS)
1901817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
1902817466cbSJens Wiklander     {
1903817466cbSJens Wiklander         /* see SEC1 3.2 */
1904817466cbSJens Wiklander         if( mbedtls_mpi_cmp_int( d, 1 ) < 0 ||
1905817466cbSJens Wiklander             mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 )
1906817466cbSJens Wiklander             return( MBEDTLS_ERR_ECP_INVALID_KEY );
1907817466cbSJens Wiklander         else
1908817466cbSJens Wiklander             return( 0 );
1909817466cbSJens Wiklander     }
1910817466cbSJens Wiklander #endif /* ECP_SHORTWEIERSTRASS */
1911817466cbSJens Wiklander 
1912817466cbSJens Wiklander     return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
1913817466cbSJens Wiklander }
1914817466cbSJens Wiklander 
1915817466cbSJens Wiklander /*
1916817466cbSJens Wiklander  * Generate a keypair with configurable base point
1917817466cbSJens Wiklander  */
1918817466cbSJens Wiklander int mbedtls_ecp_gen_keypair_base( mbedtls_ecp_group *grp,
1919817466cbSJens Wiklander                      const mbedtls_ecp_point *G,
1920817466cbSJens Wiklander                      mbedtls_mpi *d, mbedtls_ecp_point *Q,
1921817466cbSJens Wiklander                      int (*f_rng)(void *, unsigned char *, size_t),
1922817466cbSJens Wiklander                      void *p_rng )
1923817466cbSJens Wiklander {
1924817466cbSJens Wiklander     int ret;
1925817466cbSJens Wiklander     size_t n_size = ( grp->nbits + 7 ) / 8;
1926817466cbSJens Wiklander 
1927817466cbSJens Wiklander #if defined(ECP_MONTGOMERY)
1928817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_MONTGOMERY )
1929817466cbSJens Wiklander     {
1930817466cbSJens Wiklander         /* [M225] page 5 */
1931817466cbSJens Wiklander         size_t b;
1932817466cbSJens Wiklander 
1933817466cbSJens Wiklander         do {
1934817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_fill_random( d, n_size, f_rng, p_rng ) );
1935817466cbSJens Wiklander         } while( mbedtls_mpi_bitlen( d ) == 0);
1936817466cbSJens Wiklander 
1937817466cbSJens Wiklander         /* Make sure the most significant bit is nbits */
1938817466cbSJens Wiklander         b = mbedtls_mpi_bitlen( d ) - 1; /* mbedtls_mpi_bitlen is one-based */
1939817466cbSJens Wiklander         if( b > grp->nbits )
1940817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, b - grp->nbits ) );
1941817466cbSJens Wiklander         else
1942817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, grp->nbits, 1 ) );
1943817466cbSJens Wiklander 
1944817466cbSJens Wiklander         /* Make sure the last three bits are unset */
1945817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 0, 0 ) );
1946817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 1, 0 ) );
1947817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_set_bit( d, 2, 0 ) );
1948817466cbSJens Wiklander     }
1949817466cbSJens Wiklander     else
1950817466cbSJens Wiklander #endif /* ECP_MONTGOMERY */
1951817466cbSJens Wiklander #if defined(ECP_SHORTWEIERSTRASS)
1952817466cbSJens Wiklander     if( ecp_get_type( grp ) == ECP_TYPE_SHORT_WEIERSTRASS )
1953817466cbSJens Wiklander     {
1954817466cbSJens Wiklander         /* SEC1 3.2.1: Generate d such that 1 <= n < N */
1955817466cbSJens Wiklander         int count = 0;
1956817466cbSJens Wiklander         unsigned char rnd[MBEDTLS_ECP_MAX_BYTES];
1957817466cbSJens Wiklander 
1958817466cbSJens Wiklander         /*
1959817466cbSJens Wiklander          * Match the procedure given in RFC 6979 (deterministic ECDSA):
1960817466cbSJens Wiklander          * - use the same byte ordering;
1961817466cbSJens Wiklander          * - keep the leftmost nbits bits of the generated octet string;
1962817466cbSJens Wiklander          * - try until result is in the desired range.
1963817466cbSJens Wiklander          * This also avoids any biais, which is especially important for ECDSA.
1964817466cbSJens Wiklander          */
1965817466cbSJens Wiklander         do
1966817466cbSJens Wiklander         {
1967817466cbSJens Wiklander             MBEDTLS_MPI_CHK( f_rng( p_rng, rnd, n_size ) );
1968817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_read_binary( d, rnd, n_size ) );
1969817466cbSJens Wiklander             MBEDTLS_MPI_CHK( mbedtls_mpi_shift_r( d, 8 * n_size - grp->nbits ) );
1970817466cbSJens Wiklander 
1971817466cbSJens Wiklander             /*
1972817466cbSJens Wiklander              * Each try has at worst a probability 1/2 of failing (the msb has
1973817466cbSJens Wiklander              * a probability 1/2 of being 0, and then the result will be < N),
1974817466cbSJens Wiklander              * so after 30 tries failure probability is a most 2**(-30).
1975817466cbSJens Wiklander              *
1976817466cbSJens Wiklander              * For most curves, 1 try is enough with overwhelming probability,
1977817466cbSJens Wiklander              * since N starts with a lot of 1s in binary, but some curves
1978817466cbSJens Wiklander              * such as secp224k1 are actually very close to the worst case.
1979817466cbSJens Wiklander              */
1980817466cbSJens Wiklander             if( ++count > 30 )
1981817466cbSJens Wiklander                 return( MBEDTLS_ERR_ECP_RANDOM_FAILED );
1982817466cbSJens Wiklander         }
1983817466cbSJens Wiklander         while( mbedtls_mpi_cmp_int( d, 1 ) < 0 ||
1984817466cbSJens Wiklander                mbedtls_mpi_cmp_mpi( d, &grp->N ) >= 0 );
1985817466cbSJens Wiklander     }
1986817466cbSJens Wiklander     else
1987817466cbSJens Wiklander #endif /* ECP_SHORTWEIERSTRASS */
1988817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
1989817466cbSJens Wiklander 
1990817466cbSJens Wiklander cleanup:
1991817466cbSJens Wiklander     if( ret != 0 )
1992817466cbSJens Wiklander         return( ret );
1993817466cbSJens Wiklander 
1994817466cbSJens Wiklander     return( mbedtls_ecp_mul( grp, Q, d, G, f_rng, p_rng ) );
1995817466cbSJens Wiklander }
1996817466cbSJens Wiklander 
1997817466cbSJens Wiklander /*
1998817466cbSJens Wiklander  * Generate key pair, wrapper for conventional base point
1999817466cbSJens Wiklander  */
2000817466cbSJens Wiklander int mbedtls_ecp_gen_keypair( mbedtls_ecp_group *grp,
2001817466cbSJens Wiklander                              mbedtls_mpi *d, mbedtls_ecp_point *Q,
2002817466cbSJens Wiklander                              int (*f_rng)(void *, unsigned char *, size_t),
2003817466cbSJens Wiklander                              void *p_rng )
2004817466cbSJens Wiklander {
2005817466cbSJens Wiklander     return( mbedtls_ecp_gen_keypair_base( grp, &grp->G, d, Q, f_rng, p_rng ) );
2006817466cbSJens Wiklander }
2007817466cbSJens Wiklander 
2008817466cbSJens Wiklander /*
2009817466cbSJens Wiklander  * Generate a keypair, prettier wrapper
2010817466cbSJens Wiklander  */
2011817466cbSJens Wiklander int mbedtls_ecp_gen_key( mbedtls_ecp_group_id grp_id, mbedtls_ecp_keypair *key,
2012817466cbSJens Wiklander                 int (*f_rng)(void *, unsigned char *, size_t), void *p_rng )
2013817466cbSJens Wiklander {
2014817466cbSJens Wiklander     int ret;
2015817466cbSJens Wiklander 
2016817466cbSJens Wiklander     if( ( ret = mbedtls_ecp_group_load( &key->grp, grp_id ) ) != 0 )
2017817466cbSJens Wiklander         return( ret );
2018817466cbSJens Wiklander 
2019817466cbSJens Wiklander     return( mbedtls_ecp_gen_keypair( &key->grp, &key->d, &key->Q, f_rng, p_rng ) );
2020817466cbSJens Wiklander }
2021817466cbSJens Wiklander 
2022817466cbSJens Wiklander /*
2023817466cbSJens Wiklander  * Check a public-private key pair
2024817466cbSJens Wiklander  */
2025817466cbSJens Wiklander int mbedtls_ecp_check_pub_priv( const mbedtls_ecp_keypair *pub, const mbedtls_ecp_keypair *prv )
2026817466cbSJens Wiklander {
2027817466cbSJens Wiklander     int ret;
2028817466cbSJens Wiklander     mbedtls_ecp_point Q;
2029817466cbSJens Wiklander     mbedtls_ecp_group grp;
2030817466cbSJens Wiklander 
2031817466cbSJens Wiklander     if( pub->grp.id == MBEDTLS_ECP_DP_NONE ||
2032817466cbSJens Wiklander         pub->grp.id != prv->grp.id ||
2033817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &pub->Q.X, &prv->Q.X ) ||
2034817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &pub->Q.Y, &prv->Q.Y ) ||
2035817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &pub->Q.Z, &prv->Q.Z ) )
2036817466cbSJens Wiklander     {
2037817466cbSJens Wiklander         return( MBEDTLS_ERR_ECP_BAD_INPUT_DATA );
2038817466cbSJens Wiklander     }
2039817466cbSJens Wiklander 
2040817466cbSJens Wiklander     mbedtls_ecp_point_init( &Q );
2041817466cbSJens Wiklander     mbedtls_ecp_group_init( &grp );
2042817466cbSJens Wiklander 
2043817466cbSJens Wiklander     /* mbedtls_ecp_mul() needs a non-const group... */
2044817466cbSJens Wiklander     mbedtls_ecp_group_copy( &grp, &prv->grp );
2045817466cbSJens Wiklander 
2046817466cbSJens Wiklander     /* Also checks d is valid */
2047817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &Q, &prv->d, &prv->grp.G, NULL, NULL ) );
2048817466cbSJens Wiklander 
2049817466cbSJens Wiklander     if( mbedtls_mpi_cmp_mpi( &Q.X, &prv->Q.X ) ||
2050817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &Q.Y, &prv->Q.Y ) ||
2051817466cbSJens Wiklander         mbedtls_mpi_cmp_mpi( &Q.Z, &prv->Q.Z ) )
2052817466cbSJens Wiklander     {
2053817466cbSJens Wiklander         ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
2054817466cbSJens Wiklander         goto cleanup;
2055817466cbSJens Wiklander     }
2056817466cbSJens Wiklander 
2057817466cbSJens Wiklander cleanup:
2058817466cbSJens Wiklander     mbedtls_ecp_point_free( &Q );
2059817466cbSJens Wiklander     mbedtls_ecp_group_free( &grp );
2060817466cbSJens Wiklander 
2061817466cbSJens Wiklander     return( ret );
2062817466cbSJens Wiklander }
2063817466cbSJens Wiklander 
2064817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
2065817466cbSJens Wiklander 
2066817466cbSJens Wiklander /*
2067817466cbSJens Wiklander  * Checkup routine
2068817466cbSJens Wiklander  */
2069817466cbSJens Wiklander int mbedtls_ecp_self_test( int verbose )
2070817466cbSJens Wiklander {
2071817466cbSJens Wiklander     int ret;
2072817466cbSJens Wiklander     size_t i;
2073817466cbSJens Wiklander     mbedtls_ecp_group grp;
2074817466cbSJens Wiklander     mbedtls_ecp_point R, P;
2075817466cbSJens Wiklander     mbedtls_mpi m;
2076817466cbSJens Wiklander     unsigned long add_c_prev, dbl_c_prev, mul_c_prev;
2077817466cbSJens Wiklander     /* exponents especially adapted for secp192r1 */
2078817466cbSJens Wiklander     const char *exponents[] =
2079817466cbSJens Wiklander     {
2080817466cbSJens Wiklander         "000000000000000000000000000000000000000000000001", /* one */
2081817466cbSJens Wiklander         "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22830", /* N - 1 */
2082817466cbSJens Wiklander         "5EA6F389A38B8BC81E767753B15AA5569E1782E30ABE7D25", /* random */
2083817466cbSJens Wiklander         "400000000000000000000000000000000000000000000000", /* one and zeros */
2084817466cbSJens Wiklander         "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", /* all ones */
2085817466cbSJens Wiklander         "555555555555555555555555555555555555555555555555", /* 101010... */
2086817466cbSJens Wiklander     };
2087817466cbSJens Wiklander 
2088817466cbSJens Wiklander     mbedtls_ecp_group_init( &grp );
2089817466cbSJens Wiklander     mbedtls_ecp_point_init( &R );
2090817466cbSJens Wiklander     mbedtls_ecp_point_init( &P );
2091817466cbSJens Wiklander     mbedtls_mpi_init( &m );
2092817466cbSJens Wiklander 
2093817466cbSJens Wiklander     /* Use secp192r1 if available, or any available curve */
2094817466cbSJens Wiklander #if defined(MBEDTLS_ECP_DP_SECP192R1_ENABLED)
2095817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, MBEDTLS_ECP_DP_SECP192R1 ) );
2096817466cbSJens Wiklander #else
2097817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_group_load( &grp, mbedtls_ecp_curve_list()->grp_id ) );
2098817466cbSJens Wiklander #endif
2099817466cbSJens Wiklander 
2100817466cbSJens Wiklander     if( verbose != 0 )
2101817466cbSJens Wiklander         mbedtls_printf( "  ECP test #1 (constant op_count, base point G): " );
2102817466cbSJens Wiklander 
2103817466cbSJens Wiklander     /* Do a dummy multiplication first to trigger precomputation */
2104817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_lset( &m, 2 ) );
2105817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &P, &m, &grp.G, NULL, NULL ) );
2106817466cbSJens Wiklander 
2107817466cbSJens Wiklander     add_count = 0;
2108817466cbSJens Wiklander     dbl_count = 0;
2109817466cbSJens Wiklander     mul_count = 0;
2110817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) );
2111817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) );
2112817466cbSJens Wiklander 
2113817466cbSJens Wiklander     for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ )
2114817466cbSJens Wiklander     {
2115817466cbSJens Wiklander         add_c_prev = add_count;
2116817466cbSJens Wiklander         dbl_c_prev = dbl_count;
2117817466cbSJens Wiklander         mul_c_prev = mul_count;
2118817466cbSJens Wiklander         add_count = 0;
2119817466cbSJens Wiklander         dbl_count = 0;
2120817466cbSJens Wiklander         mul_count = 0;
2121817466cbSJens Wiklander 
2122817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) );
2123817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &grp.G, NULL, NULL ) );
2124817466cbSJens Wiklander 
2125817466cbSJens Wiklander         if( add_count != add_c_prev ||
2126817466cbSJens Wiklander             dbl_count != dbl_c_prev ||
2127817466cbSJens Wiklander             mul_count != mul_c_prev )
2128817466cbSJens Wiklander         {
2129817466cbSJens Wiklander             if( verbose != 0 )
2130817466cbSJens Wiklander                 mbedtls_printf( "failed (%u)\n", (unsigned int) i );
2131817466cbSJens Wiklander 
2132817466cbSJens Wiklander             ret = 1;
2133817466cbSJens Wiklander             goto cleanup;
2134817466cbSJens Wiklander         }
2135817466cbSJens Wiklander     }
2136817466cbSJens Wiklander 
2137817466cbSJens Wiklander     if( verbose != 0 )
2138817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2139817466cbSJens Wiklander 
2140817466cbSJens Wiklander     if( verbose != 0 )
2141817466cbSJens Wiklander         mbedtls_printf( "  ECP test #2 (constant op_count, other point): " );
2142817466cbSJens Wiklander     /* We computed P = 2G last time, use it */
2143817466cbSJens Wiklander 
2144817466cbSJens Wiklander     add_count = 0;
2145817466cbSJens Wiklander     dbl_count = 0;
2146817466cbSJens Wiklander     mul_count = 0;
2147817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[0] ) );
2148817466cbSJens Wiklander     MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) );
2149817466cbSJens Wiklander 
2150817466cbSJens Wiklander     for( i = 1; i < sizeof( exponents ) / sizeof( exponents[0] ); i++ )
2151817466cbSJens Wiklander     {
2152817466cbSJens Wiklander         add_c_prev = add_count;
2153817466cbSJens Wiklander         dbl_c_prev = dbl_count;
2154817466cbSJens Wiklander         mul_c_prev = mul_count;
2155817466cbSJens Wiklander         add_count = 0;
2156817466cbSJens Wiklander         dbl_count = 0;
2157817466cbSJens Wiklander         mul_count = 0;
2158817466cbSJens Wiklander 
2159817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_mpi_read_string( &m, 16, exponents[i] ) );
2160817466cbSJens Wiklander         MBEDTLS_MPI_CHK( mbedtls_ecp_mul( &grp, &R, &m, &P, NULL, NULL ) );
2161817466cbSJens Wiklander 
2162817466cbSJens Wiklander         if( add_count != add_c_prev ||
2163817466cbSJens Wiklander             dbl_count != dbl_c_prev ||
2164817466cbSJens Wiklander             mul_count != mul_c_prev )
2165817466cbSJens Wiklander         {
2166817466cbSJens Wiklander             if( verbose != 0 )
2167817466cbSJens Wiklander                 mbedtls_printf( "failed (%u)\n", (unsigned int) i );
2168817466cbSJens Wiklander 
2169817466cbSJens Wiklander             ret = 1;
2170817466cbSJens Wiklander             goto cleanup;
2171817466cbSJens Wiklander         }
2172817466cbSJens Wiklander     }
2173817466cbSJens Wiklander 
2174817466cbSJens Wiklander     if( verbose != 0 )
2175817466cbSJens Wiklander         mbedtls_printf( "passed\n" );
2176817466cbSJens Wiklander 
2177817466cbSJens Wiklander cleanup:
2178817466cbSJens Wiklander 
2179817466cbSJens Wiklander     if( ret < 0 && verbose != 0 )
2180817466cbSJens Wiklander         mbedtls_printf( "Unexpected error, return code = %08X\n", ret );
2181817466cbSJens Wiklander 
2182817466cbSJens Wiklander     mbedtls_ecp_group_free( &grp );
2183817466cbSJens Wiklander     mbedtls_ecp_point_free( &R );
2184817466cbSJens Wiklander     mbedtls_ecp_point_free( &P );
2185817466cbSJens Wiklander     mbedtls_mpi_free( &m );
2186817466cbSJens Wiklander 
2187817466cbSJens Wiklander     if( verbose != 0 )
2188817466cbSJens Wiklander         mbedtls_printf( "\n" );
2189817466cbSJens Wiklander 
2190817466cbSJens Wiklander     return( ret );
2191817466cbSJens Wiklander }
2192817466cbSJens Wiklander 
2193817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
2194817466cbSJens Wiklander 
2195817466cbSJens Wiklander #endif /* !MBEDTLS_ECP_ALT */
2196817466cbSJens Wiklander 
2197817466cbSJens Wiklander #endif /* MBEDTLS_ECP_C */
2198