blob: a22f1cc61cea545d4f47637bd9241fc62ac9ac11 [file] [log] [blame]
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +01001/*
2 * Elliptic curves over GF(p)
3 *
4 * Copyright (C) 2012, Brainspark B.V.
5 *
6 * This file is part of PolarSSL (http://www.polarssl.org)
7 * Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
8 *
9 * All rights reserved.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along
22 * with this program; if not, write to the Free Software Foundation, Inc.,
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25
26/*
27 * References:
28 *
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010029 * SEC1 http://www.secg.org/index.php?action=secg,docs_secg
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +010030 * GECC = Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +010031 * FIPS 186-3 http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010032 */
33
34#include "polarssl/config.h"
35
36#if defined(POLARSSL_ECP_C)
37
38#include "polarssl/ecp.h"
39
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010040/*
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010041 * Initialize (the components of) a point
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010042 */
43void ecp_point_init( ecp_point *pt )
44{
45 if( pt == NULL )
46 return;
47
48 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010049 mpi_init( &pt->X );
50 mpi_init( &pt->Y );
51}
52
53/*
54 * Initialize (the components of) a group
55 */
56void ecp_group_init( ecp_group *grp )
57{
58 if( grp == NULL )
59 return;
60
61 mpi_init( &grp->P );
62 mpi_init( &grp->B );
63 ecp_point_init( &grp->G );
64 mpi_init( &grp->N );
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +010065
66 grp->modp = NULL;
67 grp->pbits = 0;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010068}
69
70/*
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010071 * Unallocate (the components of) a point
72 */
73void ecp_point_free( ecp_point *pt )
74{
75 if( pt == NULL )
76 return;
77
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +010078 pt->is_zero = 1;
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010079 mpi_free( &( pt->X ) );
80 mpi_free( &( pt->Y ) );
81}
82
83/*
84 * Unallocate (the components of) a group
85 */
86void ecp_group_free( ecp_group *grp )
87{
88 if( grp == NULL )
89 return;
90
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010091 mpi_free( &grp->P );
92 mpi_free( &grp->B );
93 ecp_point_free( &grp->G );
94 mpi_free( &grp->N );
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010095}
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010096
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010097/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010098 * Set point to zero
99 */
100void ecp_set_zero( ecp_point *pt )
101{
102 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100103 mpi_free( &pt->X );
104 mpi_free( &pt->Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100105}
106
107/*
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100108 * Copy the contents of Q into P
109 */
110int ecp_copy( ecp_point *P, const ecp_point *Q )
111{
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100112 int ret = 0;
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100113
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100114 if( Q->is_zero ) {
115 ecp_set_zero( P );
116 return( ret );
117 }
118
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100119 P->is_zero = Q->is_zero;
120 MPI_CHK( mpi_copy( &P->X, &Q->X ) );
121 MPI_CHK( mpi_copy( &P->Y, &Q->Y ) );
122
123cleanup:
124 return( ret );
125}
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +0100126
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100127/*
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100128 * Import a non-zero point from ASCII strings
129 */
130int ecp_point_read_string( ecp_point *P, int radix,
131 const char *x, const char *y )
132{
133 int ret = 0;
134
135 P->is_zero = 0;
136 MPI_CHK( mpi_read_string( &P->X, radix, x ) );
137 MPI_CHK( mpi_read_string( &P->Y, radix, y ) );
138
139cleanup:
140 return( ret );
141}
142
143/*
144 * Import an ECP group from ASCII strings
145 */
146int ecp_group_read_string( ecp_group *grp, int radix,
147 const char *p, const char *b,
148 const char *gx, const char *gy, const char *n)
149{
150 int ret = 0;
151
152 MPI_CHK( mpi_read_string( &grp->P, radix, p ) );
153 MPI_CHK( mpi_read_string( &grp->B, radix, b ) );
154 MPI_CHK( ecp_point_read_string( &grp->G, radix, gx, gy ) );
155 MPI_CHK( mpi_read_string( &grp->N, radix, n ) );
156
157cleanup:
158 return( ret );
159}
160
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100161/*
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100162 * Wrapper around fast quasi-modp functions, with fallback to mpi_mod_mpi
163 *
164 * The quasi-modp functions expect an mpi N such that 0 <= N < 2^(2*pbits)
165 * and change it in-place so that it can easily be brought in the 0..P-1
166 * range by a few additions or substractions.
167 */
168static int ecp_modp( mpi *N, const ecp_group *grp )
169{
170 int ret = 0;
171
172 if( grp->modp == NULL )
173 return( mpi_mod_mpi( N, N, &grp->P ) );
174
175 if( mpi_cmp_int( N, 0 ) < 0 || mpi_msb( N ) > 2 * grp->pbits )
176 return( POLARSSL_ERR_ECP_GENERIC );
177
178 MPI_CHK( grp->modp( N ) );
179
180 while( mpi_cmp_int( N, 0 ) < 0 )
181 MPI_CHK( mpi_add_mpi( N, N, &grp->P ) );
182
183 while( mpi_cmp_mpi( N, &grp->P ) >= 0 )
184 MPI_CHK( mpi_sub_mpi( N, N, &grp->P ) );
185
186cleanup:
187 return( ret );
188}
189
190/*
191 * Size of p521 in terms of t_uint
192 */
193#define P521_SIZE_INT ( 521 / (sizeof( t_uint ) << 3) + 1 )
194
195/*
196 * Bits to keep in the most significant t_uint
197 */
198#if defined(POLARSS_HAVE_INT8)
199#define P521_MASK 0x01
200#else
201#define P521_MASK 0x01FF
202#endif
203
204/*
205 * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5)
206 *
207 * It is required that 0 <= N < 2^(2*521) on entry.
208 * On exit, it is only guaranteed that 0 <= N < 2^(521+1).
209 */
210static int ecp_mod_p521( mpi *N )
211{
212 int ret = 0;
213 t_uint Mp[P521_SIZE_INT];
214 mpi M;
215
216 if( N->n < P521_SIZE_INT )
217 return( 0 );
218
219 memset( Mp, 0, P521_SIZE_INT * sizeof( t_uint ) );
220 memcpy( Mp, N->p, P521_SIZE_INT * sizeof( t_uint ) );
221 Mp[P521_SIZE_INT - 1] &= P521_MASK;
222
223 M.s = 1;
224 M.n = P521_SIZE_INT;
225 M.p = Mp;
226
227 MPI_CHK( mpi_shift_r( N, 521 ) );
228
229 MPI_CHK( mpi_add_abs( N, N, &M ) );
230
231cleanup:
232 return( ret );
233}
234
235/*
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100236 * Set a group using well-known domain parameters
237 */
238int ecp_use_known_dp( ecp_group *grp, size_t index )
239{
240 switch( index )
241 {
242 case POLARSSL_ECP_DP_SECP192R1:
243 return( ecp_group_read_string( grp, 16,
244 POLARSSL_ECP_SECP192R1_P,
245 POLARSSL_ECP_SECP192R1_B,
246 POLARSSL_ECP_SECP192R1_GX,
247 POLARSSL_ECP_SECP192R1_GY,
248 POLARSSL_ECP_SECP192R1_N )
249 );
250 case POLARSSL_ECP_DP_SECP224R1:
251 return( ecp_group_read_string( grp, 16,
252 POLARSSL_ECP_SECP224R1_P,
253 POLARSSL_ECP_SECP224R1_B,
254 POLARSSL_ECP_SECP224R1_GX,
255 POLARSSL_ECP_SECP224R1_GY,
256 POLARSSL_ECP_SECP224R1_N )
257 );
258 case POLARSSL_ECP_DP_SECP256R1:
259 return( ecp_group_read_string( grp, 16,
260 POLARSSL_ECP_SECP256R1_P,
261 POLARSSL_ECP_SECP256R1_B,
262 POLARSSL_ECP_SECP256R1_GX,
263 POLARSSL_ECP_SECP256R1_GY,
264 POLARSSL_ECP_SECP256R1_N )
265 );
266 case POLARSSL_ECP_DP_SECP384R1:
267 return( ecp_group_read_string( grp, 16,
268 POLARSSL_ECP_SECP384R1_P,
269 POLARSSL_ECP_SECP384R1_B,
270 POLARSSL_ECP_SECP384R1_GX,
271 POLARSSL_ECP_SECP384R1_GY,
272 POLARSSL_ECP_SECP384R1_N )
273 );
274 case POLARSSL_ECP_DP_SECP521R1:
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100275 grp->modp = ecp_mod_p521;
276 grp->pbits = 521;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100277 return( ecp_group_read_string( grp, 16,
278 POLARSSL_ECP_SECP521R1_P,
279 POLARSSL_ECP_SECP521R1_B,
280 POLARSSL_ECP_SECP521R1_GX,
281 POLARSSL_ECP_SECP521R1_GY,
282 POLARSSL_ECP_SECP521R1_N )
283 );
284 }
285
286 return( POLARSSL_ERR_ECP_GENERIC );
287}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100288
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100289/*
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100290 * Reduce a mpi mod p in-place, general case, to use after mpi_mul_mpi
291 */
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100292#define MOD_MUL( N ) MPI_CHK( ecp_modp( &N, grp ) )
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100293
294/*
295 * Reduce a mpi mod p in-place, to use after mpi_sub_mpi
296 */
297#define MOD_SUB( N ) \
298 while( mpi_cmp_int( &N, 0 ) < 0 ) \
299 MPI_CHK( mpi_add_mpi( &N, &N, &grp->P ) )
300
301/*
302 * Reduce a mpi mod p in-place, to use after mpi_add_mpi and mpi_mul_int
303 */
304#define MOD_ADD( N ) \
305 while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \
306 MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) )
307
308/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100309 * Internal point format used for fast addition/doubling/multiplication:
310 * Jacobian coordinates (GECC example 3.20)
311 */
312typedef struct
313{
314 mpi X, Y, Z;
315}
316ecp_ptjac;
317
318/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100319 * Initialize a point in Jacobian coordinates
320 */
321static void ecp_ptjac_init( ecp_ptjac *P )
322{
323 mpi_init( &P->X ); mpi_init( &P->Y ); mpi_init( &P->Z );
324}
325
326/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100327 * Free a point in Jacobian coordinates
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100328 */
329static void ecp_ptjac_free( ecp_ptjac *P )
330{
331 mpi_free( &P->X ); mpi_free( &P->Y ); mpi_free( &P->Z );
332}
333
334/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100335 * Copy P to R in Jacobian coordinates
336 */
337static int ecp_ptjac_copy( ecp_ptjac *R, const ecp_ptjac *P )
338{
339 int ret = 0;
340
341 MPI_CHK( mpi_copy( &R->X, &P->X ) );
342 MPI_CHK( mpi_copy( &R->Y, &P->Y ) );
343 MPI_CHK( mpi_copy( &R->Z, &P->Z ) );
344
345cleanup:
346 return( ret );
347}
348
349/*
350 * Set P to zero in Jacobian coordinates
351 */
352static int ecp_ptjac_set_zero( ecp_ptjac *P )
353{
354 int ret = 0;
355
356 MPI_CHK( mpi_lset( &P->X, 1 ) );
357 MPI_CHK( mpi_lset( &P->Y, 1 ) );
358 MPI_CHK( mpi_lset( &P->Z, 0 ) );
359
360cleanup:
361 return( ret );
362}
363
364/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100365 * Convert from affine to Jacobian coordinates
366 */
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100367static int ecp_aff_to_jac( ecp_ptjac *jac, const ecp_point *aff )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100368{
369 int ret = 0;
370
371 if( aff->is_zero )
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100372 return( ecp_ptjac_set_zero( jac ) );
373
374 MPI_CHK( mpi_copy( &jac->X, &aff->X ) );
375 MPI_CHK( mpi_copy( &jac->Y, &aff->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100376 MPI_CHK( mpi_lset( &jac->Z, 1 ) );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100377
378cleanup:
379 return( ret );
380}
381
382/*
383 * Convert from Jacobian to affine coordinates
384 */
385static int ecp_jac_to_aff( const ecp_group *grp,
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100386 ecp_point *aff, const ecp_ptjac *jac )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100387{
388 int ret = 0;
389 mpi Zi, ZZi, T;
390
391 if( mpi_cmp_int( &jac->Z, 0 ) == 0 ) {
392 ecp_set_zero( aff );
393 return( 0 );
394 }
395
396 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
397
398 aff->is_zero = 0;
399
400 /*
401 * aff.X = jac.X / (jac.Z)^2 mod p
402 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100403 MPI_CHK( mpi_inv_mod( &Zi, &jac->Z, &grp->P ) );
404 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
405 MPI_CHK( mpi_mul_mpi( &aff->X, &jac->X, &ZZi ) ); MOD_MUL( aff->X );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100406
407 /*
408 * aff.Y = jac.Y / (jac.Z)^3 mod p
409 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100410 MPI_CHK( mpi_mul_mpi( &aff->Y, &jac->Y, &ZZi ) ); MOD_MUL( aff->Y );
411 MPI_CHK( mpi_mul_mpi( &aff->Y, &aff->Y, &Zi ) ); MOD_MUL( aff->Y );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100412
413cleanup:
414
415 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
416
417 return( ret );
418}
419
420/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100421 * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21)
422 */
423static int ecp_double_jac( const ecp_group *grp, ecp_ptjac *R,
424 const ecp_ptjac *P )
425{
426 int ret = 0;
427 mpi T1, T2, T3, X, Y, Z;
428
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100429 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
430 return( ecp_ptjac_set_zero( R ) );
431
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100432 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 );
433 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
434
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100435 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
436 MPI_CHK( mpi_sub_mpi( &T2, &P->X, &T1 ) ); MOD_SUB( T2 );
437 MPI_CHK( mpi_add_mpi( &T1, &P->X, &T1 ) ); MOD_ADD( T1 );
438 MPI_CHK( mpi_mul_mpi( &T2, &T2, &T1 ) ); MOD_MUL( T2 );
439 MPI_CHK( mpi_mul_int( &T2, &T2, 3 ) ); MOD_ADD( T2 );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100440 MPI_CHK( mpi_copy ( &Y, &P->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100441 MPI_CHK( mpi_shift_l( &Y, 1 ) ); MOD_ADD( Y );
442 MPI_CHK( mpi_mul_mpi( &Z, &Y, &P->Z ) ); MOD_MUL( Z );
443 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
444 MPI_CHK( mpi_mul_mpi( &T3, &Y, &P->X ) ); MOD_MUL( T3 );
445 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100446
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100447 /*
448 * For Y = Y / 2 mod p, we must make sure that Y is even before
449 * using right-shift. No need to reduce mod p afterwards.
450 */
451 if( mpi_get_bit( &Y, 0 ) == 1 )
452 MPI_CHK( mpi_add_mpi( &Y, &Y, &grp->P ) );
453 MPI_CHK( mpi_shift_r( &Y, 1 ) );
454
455 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
456 MPI_CHK( mpi_copy ( &T1, &T3 ) );
457 MPI_CHK( mpi_shift_l( &T1, 1 ) ); MOD_ADD( T1 );
458 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
459 MPI_CHK( mpi_sub_mpi( &T1, &T3, &X ) ); MOD_SUB( T1 );
460 MPI_CHK( mpi_mul_mpi( &T1, &T1, &T2 ) ); MOD_MUL( T1 );
461 MPI_CHK( mpi_sub_mpi( &Y, &T1, &Y ) ); MOD_SUB( Y );
462
463 MPI_CHK( mpi_copy( &R->X, &X ) );
464 MPI_CHK( mpi_copy( &R->Y, &Y ) );
465 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100466
467cleanup:
468
469 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 );
470 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
471
472 return( ret );
473}
474
475/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100476 * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100477 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100478static int ecp_add_mixed( const ecp_group *grp, ecp_ptjac *R,
479 const ecp_ptjac *P, const ecp_point *Q )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100480{
481 int ret = 0;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100482 mpi T1, T2, T3, T4, X, Y, Z;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100483
484 /*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100485 * Trivial cases: P == 0 or Q == 0
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100486 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100487 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
488 return( ecp_aff_to_jac( R, Q ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100489
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100490 if( Q->is_zero )
491 return( ecp_ptjac_copy( R, P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100492
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100493 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 ); mpi_init( &T4 );
494 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100495
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100496 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
497 MPI_CHK( mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
498 MPI_CHK( mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
499 MPI_CHK( mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
500 MPI_CHK( mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
501 MPI_CHK( mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100502
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100503 if( mpi_cmp_int( &T1, 0 ) == 0 )
504 {
505 if( mpi_cmp_int( &T2, 0 ) == 0 )
506 {
507 ret = ecp_double_jac( grp, R, P );
508 goto cleanup;
509 }
510 else
511 {
512 ret = ecp_ptjac_set_zero( R );
513 goto cleanup;
514 }
515 }
516
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100517 MPI_CHK( mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
518 MPI_CHK( mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
519 MPI_CHK( mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
520 MPI_CHK( mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
521 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
522 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
523 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
524 MPI_CHK( mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
525 MPI_CHK( mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
526 MPI_CHK( mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
527 MPI_CHK( mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
528 MPI_CHK( mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100529
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100530 MPI_CHK( mpi_copy( &R->X, &X ) );
531 MPI_CHK( mpi_copy( &R->Y, &Y ) );
532 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100533
534cleanup:
535
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100536 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 ); mpi_free( &T4 );
537 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100538
539 return( ret );
540}
541
542/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100543 * Addition: R = P + Q, affine wrapper
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100544 */
545int ecp_add( const ecp_group *grp, ecp_point *R,
546 const ecp_point *P, const ecp_point *Q )
547{
548 int ret = 0;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100549 ecp_ptjac J;
550
551 ecp_ptjac_init( &J );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100552
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100553 MPI_CHK( ecp_aff_to_jac( &J, P ) );
554 MPI_CHK( ecp_add_mixed( grp, &J, &J, Q ) );
555 MPI_CHK( ecp_jac_to_aff( grp, R, &J ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100556
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100557cleanup:
558
559 ecp_ptjac_free( &J );
560
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100561 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100562}
563
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100564/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100565 * Integer multiplication: R = m * P (GECC 5.7, SPA-resistant variant)
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100566 */
567int ecp_mul( const ecp_group *grp, ecp_point *R,
568 const mpi *m, const ecp_point *P )
569{
570 int ret = 0;
571 size_t pos;
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100572 ecp_ptjac Q[2];
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100573
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100574 ecp_ptjac_init( &Q[0] ); ecp_ptjac_init( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100575
576 /*
Manuel Pégourié-Gonnard27b1ba82012-11-08 18:24:10 +0100577 * The general method works only for m >= 1
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100578 */
579 if( mpi_cmp_int( m, 0 ) == 0 ) {
580 ecp_set_zero( R );
581 goto cleanup;
582 }
583
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100584 ecp_ptjac_set_zero( &Q[0] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100585
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100586 for( pos = mpi_msb( m ) - 1 ; ; pos-- )
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100587 {
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100588 MPI_CHK( ecp_double_jac( grp, &Q[0], &Q[0] ) );
589 MPI_CHK( ecp_add_mixed( grp, &Q[1], &Q[0], P ) );
590 MPI_CHK( ecp_ptjac_copy( &Q[0], &Q[ mpi_get_bit( m, pos ) ] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100591
592 if( pos == 0 )
593 break;
594 }
595
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100596 MPI_CHK( ecp_jac_to_aff( grp, R, &Q[0] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100597
598cleanup:
599
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100600 ecp_ptjac_free( &Q[0] ); ecp_ptjac_free( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100601
602 return( ret );
603}
604
605
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100606#if defined(POLARSSL_SELF_TEST)
607
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100608/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100609 * Checkup routine
610 */
611int ecp_self_test( int verbose )
612{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100613 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100614}
615
616#endif
617
618#endif