blob: 01076a1861c2bde4fa030738195c2e9de96430ac [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é-Gonnard39d2adb2012-10-31 09:26:55 +010031 */
32
33#include "polarssl/config.h"
34
35#if defined(POLARSSL_ECP_C)
36
37#include "polarssl/ecp.h"
38
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010039/*
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010040 * Initialize (the components of) a point
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010041 */
42void ecp_point_init( ecp_point *pt )
43{
44 if( pt == NULL )
45 return;
46
47 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010048 mpi_init( &pt->X );
49 mpi_init( &pt->Y );
50}
51
52/*
53 * Initialize (the components of) a group
54 */
55void ecp_group_init( ecp_group *grp )
56{
57 if( grp == NULL )
58 return;
59
60 mpi_init( &grp->P );
61 mpi_init( &grp->B );
62 ecp_point_init( &grp->G );
63 mpi_init( &grp->N );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010064}
65
66/*
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010067 * Unallocate (the components of) a point
68 */
69void ecp_point_free( ecp_point *pt )
70{
71 if( pt == NULL )
72 return;
73
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +010074 pt->is_zero = 1;
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010075 mpi_free( &( pt->X ) );
76 mpi_free( &( pt->Y ) );
77}
78
79/*
80 * Unallocate (the components of) a group
81 */
82void ecp_group_free( ecp_group *grp )
83{
84 if( grp == NULL )
85 return;
86
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010087 mpi_free( &grp->P );
88 mpi_free( &grp->B );
89 ecp_point_free( &grp->G );
90 mpi_free( &grp->N );
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010091}
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010092
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010093/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010094 * Set point to zero
95 */
96void ecp_set_zero( ecp_point *pt )
97{
98 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010099 mpi_free( &pt->X );
100 mpi_free( &pt->Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100101}
102
103/*
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100104 * Copy the contents of Q into P
105 */
106int ecp_copy( ecp_point *P, const ecp_point *Q )
107{
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100108 int ret = 0;
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100109
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100110 if( Q->is_zero ) {
111 ecp_set_zero( P );
112 return( ret );
113 }
114
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100115 P->is_zero = Q->is_zero;
116 MPI_CHK( mpi_copy( &P->X, &Q->X ) );
117 MPI_CHK( mpi_copy( &P->Y, &Q->Y ) );
118
119cleanup:
120 return( ret );
121}
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +0100122
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100123/*
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100124 * Import a non-zero point from ASCII strings
125 */
126int ecp_point_read_string( ecp_point *P, int radix,
127 const char *x, const char *y )
128{
129 int ret = 0;
130
131 P->is_zero = 0;
132 MPI_CHK( mpi_read_string( &P->X, radix, x ) );
133 MPI_CHK( mpi_read_string( &P->Y, radix, y ) );
134
135cleanup:
136 return( ret );
137}
138
139/*
140 * Import an ECP group from ASCII strings
141 */
142int ecp_group_read_string( ecp_group *grp, int radix,
143 const char *p, const char *b,
144 const char *gx, const char *gy, const char *n)
145{
146 int ret = 0;
147
148 MPI_CHK( mpi_read_string( &grp->P, radix, p ) );
149 MPI_CHK( mpi_read_string( &grp->B, radix, b ) );
150 MPI_CHK( ecp_point_read_string( &grp->G, radix, gx, gy ) );
151 MPI_CHK( mpi_read_string( &grp->N, radix, n ) );
152
153cleanup:
154 return( ret );
155}
156
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100157/*
158 * Set a group using well-known domain parameters
159 */
160int ecp_use_known_dp( ecp_group *grp, size_t index )
161{
162 switch( index )
163 {
164 case POLARSSL_ECP_DP_SECP192R1:
165 return( ecp_group_read_string( grp, 16,
166 POLARSSL_ECP_SECP192R1_P,
167 POLARSSL_ECP_SECP192R1_B,
168 POLARSSL_ECP_SECP192R1_GX,
169 POLARSSL_ECP_SECP192R1_GY,
170 POLARSSL_ECP_SECP192R1_N )
171 );
172 case POLARSSL_ECP_DP_SECP224R1:
173 return( ecp_group_read_string( grp, 16,
174 POLARSSL_ECP_SECP224R1_P,
175 POLARSSL_ECP_SECP224R1_B,
176 POLARSSL_ECP_SECP224R1_GX,
177 POLARSSL_ECP_SECP224R1_GY,
178 POLARSSL_ECP_SECP224R1_N )
179 );
180 case POLARSSL_ECP_DP_SECP256R1:
181 return( ecp_group_read_string( grp, 16,
182 POLARSSL_ECP_SECP256R1_P,
183 POLARSSL_ECP_SECP256R1_B,
184 POLARSSL_ECP_SECP256R1_GX,
185 POLARSSL_ECP_SECP256R1_GY,
186 POLARSSL_ECP_SECP256R1_N )
187 );
188 case POLARSSL_ECP_DP_SECP384R1:
189 return( ecp_group_read_string( grp, 16,
190 POLARSSL_ECP_SECP384R1_P,
191 POLARSSL_ECP_SECP384R1_B,
192 POLARSSL_ECP_SECP384R1_GX,
193 POLARSSL_ECP_SECP384R1_GY,
194 POLARSSL_ECP_SECP384R1_N )
195 );
196 case POLARSSL_ECP_DP_SECP521R1:
197 return( ecp_group_read_string( grp, 16,
198 POLARSSL_ECP_SECP521R1_P,
199 POLARSSL_ECP_SECP521R1_B,
200 POLARSSL_ECP_SECP521R1_GX,
201 POLARSSL_ECP_SECP521R1_GY,
202 POLARSSL_ECP_SECP521R1_N )
203 );
204 }
205
206 return( POLARSSL_ERR_ECP_GENERIC );
207}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100208
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100209/*
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100210 * Reduce a mpi mod p in-place, general case, to use after mpi_mul_mpi
211 */
212#define MOD_MUL( N ) MPI_CHK( mpi_mod_mpi( &N, &N, &grp->P ) )
213
214/*
215 * Reduce a mpi mod p in-place, to use after mpi_sub_mpi
216 */
217#define MOD_SUB( N ) \
218 while( mpi_cmp_int( &N, 0 ) < 0 ) \
219 MPI_CHK( mpi_add_mpi( &N, &N, &grp->P ) )
220
221/*
222 * Reduce a mpi mod p in-place, to use after mpi_add_mpi and mpi_mul_int
223 */
224#define MOD_ADD( N ) \
225 while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \
226 MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) )
227
228/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100229 * Internal point format used for fast addition/doubling/multiplication:
230 * Jacobian coordinates (GECC example 3.20)
231 */
232typedef struct
233{
234 mpi X, Y, Z;
235}
236ecp_ptjac;
237
238/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100239 * Initialize a point in Jacobian coordinates
240 */
241static void ecp_ptjac_init( ecp_ptjac *P )
242{
243 mpi_init( &P->X ); mpi_init( &P->Y ); mpi_init( &P->Z );
244}
245
246/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100247 * Free a point in Jacobian coordinates
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100248 */
249static void ecp_ptjac_free( ecp_ptjac *P )
250{
251 mpi_free( &P->X ); mpi_free( &P->Y ); mpi_free( &P->Z );
252}
253
254/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100255 * Copy P to R in Jacobian coordinates
256 */
257static int ecp_ptjac_copy( ecp_ptjac *R, const ecp_ptjac *P )
258{
259 int ret = 0;
260
261 MPI_CHK( mpi_copy( &R->X, &P->X ) );
262 MPI_CHK( mpi_copy( &R->Y, &P->Y ) );
263 MPI_CHK( mpi_copy( &R->Z, &P->Z ) );
264
265cleanup:
266 return( ret );
267}
268
269/*
270 * Set P to zero in Jacobian coordinates
271 */
272static int ecp_ptjac_set_zero( ecp_ptjac *P )
273{
274 int ret = 0;
275
276 MPI_CHK( mpi_lset( &P->X, 1 ) );
277 MPI_CHK( mpi_lset( &P->Y, 1 ) );
278 MPI_CHK( mpi_lset( &P->Z, 0 ) );
279
280cleanup:
281 return( ret );
282}
283
284/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100285 * Convert from affine to Jacobian coordinates
286 */
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100287static int ecp_aff_to_jac( ecp_ptjac *jac, const ecp_point *aff )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100288{
289 int ret = 0;
290
291 if( aff->is_zero )
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100292 return( ecp_ptjac_set_zero( jac ) );
293
294 MPI_CHK( mpi_copy( &jac->X, &aff->X ) );
295 MPI_CHK( mpi_copy( &jac->Y, &aff->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100296 MPI_CHK( mpi_lset( &jac->Z, 1 ) );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100297
298cleanup:
299 return( ret );
300}
301
302/*
303 * Convert from Jacobian to affine coordinates
304 */
305static int ecp_jac_to_aff( const ecp_group *grp,
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100306 ecp_point *aff, const ecp_ptjac *jac )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100307{
308 int ret = 0;
309 mpi Zi, ZZi, T;
310
311 if( mpi_cmp_int( &jac->Z, 0 ) == 0 ) {
312 ecp_set_zero( aff );
313 return( 0 );
314 }
315
316 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
317
318 aff->is_zero = 0;
319
320 /*
321 * aff.X = jac.X / (jac.Z)^2 mod p
322 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100323 MPI_CHK( mpi_inv_mod( &Zi, &jac->Z, &grp->P ) );
324 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
325 MPI_CHK( mpi_mul_mpi( &aff->X, &jac->X, &ZZi ) ); MOD_MUL( aff->X );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100326
327 /*
328 * aff.Y = jac.Y / (jac.Z)^3 mod p
329 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100330 MPI_CHK( mpi_mul_mpi( &aff->Y, &jac->Y, &ZZi ) ); MOD_MUL( aff->Y );
331 MPI_CHK( mpi_mul_mpi( &aff->Y, &aff->Y, &Zi ) ); MOD_MUL( aff->Y );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100332
333cleanup:
334
335 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
336
337 return( ret );
338}
339
340/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100341 * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21)
342 */
343static int ecp_double_jac( const ecp_group *grp, ecp_ptjac *R,
344 const ecp_ptjac *P )
345{
346 int ret = 0;
347 mpi T1, T2, T3, X, Y, Z;
348
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100349 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
350 return( ecp_ptjac_set_zero( R ) );
351
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100352 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 );
353 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
354
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100355 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
356 MPI_CHK( mpi_sub_mpi( &T2, &P->X, &T1 ) ); MOD_SUB( T2 );
357 MPI_CHK( mpi_add_mpi( &T1, &P->X, &T1 ) ); MOD_ADD( T1 );
358 MPI_CHK( mpi_mul_mpi( &T2, &T2, &T1 ) ); MOD_MUL( T2 );
359 MPI_CHK( mpi_mul_int( &T2, &T2, 3 ) ); MOD_ADD( T2 );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100360 MPI_CHK( mpi_copy ( &Y, &P->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100361 MPI_CHK( mpi_shift_l( &Y, 1 ) ); MOD_ADD( Y );
362 MPI_CHK( mpi_mul_mpi( &Z, &Y, &P->Z ) ); MOD_MUL( Z );
363 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
364 MPI_CHK( mpi_mul_mpi( &T3, &Y, &P->X ) ); MOD_MUL( T3 );
365 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100366
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100367 /*
368 * For Y = Y / 2 mod p, we must make sure that Y is even before
369 * using right-shift. No need to reduce mod p afterwards.
370 */
371 if( mpi_get_bit( &Y, 0 ) == 1 )
372 MPI_CHK( mpi_add_mpi( &Y, &Y, &grp->P ) );
373 MPI_CHK( mpi_shift_r( &Y, 1 ) );
374
375 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
376 MPI_CHK( mpi_copy ( &T1, &T3 ) );
377 MPI_CHK( mpi_shift_l( &T1, 1 ) ); MOD_ADD( T1 );
378 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
379 MPI_CHK( mpi_sub_mpi( &T1, &T3, &X ) ); MOD_SUB( T1 );
380 MPI_CHK( mpi_mul_mpi( &T1, &T1, &T2 ) ); MOD_MUL( T1 );
381 MPI_CHK( mpi_sub_mpi( &Y, &T1, &Y ) ); MOD_SUB( Y );
382
383 MPI_CHK( mpi_copy( &R->X, &X ) );
384 MPI_CHK( mpi_copy( &R->Y, &Y ) );
385 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100386
387cleanup:
388
389 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 );
390 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
391
392 return( ret );
393}
394
395/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100396 * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100397 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100398static int ecp_add_mixed( const ecp_group *grp, ecp_ptjac *R,
399 const ecp_ptjac *P, const ecp_point *Q )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100400{
401 int ret = 0;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100402 mpi T1, T2, T3, T4, X, Y, Z;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100403
404 /*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100405 * Trivial cases: P == 0 or Q == 0
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100406 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100407 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
408 return( ecp_aff_to_jac( R, Q ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100409
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100410 if( Q->is_zero )
411 return( ecp_ptjac_copy( R, P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100412
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100413 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 ); mpi_init( &T4 );
414 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100415
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100416 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
417 MPI_CHK( mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
418 MPI_CHK( mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
419 MPI_CHK( mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
420 MPI_CHK( mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
421 MPI_CHK( mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100422
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100423 if( mpi_cmp_int( &T1, 0 ) == 0 )
424 {
425 if( mpi_cmp_int( &T2, 0 ) == 0 )
426 {
427 ret = ecp_double_jac( grp, R, P );
428 goto cleanup;
429 }
430 else
431 {
432 ret = ecp_ptjac_set_zero( R );
433 goto cleanup;
434 }
435 }
436
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100437 MPI_CHK( mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
438 MPI_CHK( mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
439 MPI_CHK( mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
440 MPI_CHK( mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
441 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
442 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
443 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
444 MPI_CHK( mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
445 MPI_CHK( mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
446 MPI_CHK( mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
447 MPI_CHK( mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
448 MPI_CHK( mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100449
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100450 MPI_CHK( mpi_copy( &R->X, &X ) );
451 MPI_CHK( mpi_copy( &R->Y, &Y ) );
452 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100453
454cleanup:
455
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100456 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 ); mpi_free( &T4 );
457 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100458
459 return( ret );
460}
461
462/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100463 * Addition: R = P + Q, affine wrapper
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100464 */
465int ecp_add( const ecp_group *grp, ecp_point *R,
466 const ecp_point *P, const ecp_point *Q )
467{
468 int ret = 0;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100469 ecp_ptjac J;
470
471 ecp_ptjac_init( &J );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100472
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100473 MPI_CHK( ecp_aff_to_jac( &J, P ) );
474 MPI_CHK( ecp_add_mixed( grp, &J, &J, Q ) );
475 MPI_CHK( ecp_jac_to_aff( grp, R, &J ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100476
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100477cleanup:
478
479 ecp_ptjac_free( &J );
480
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100481 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100482}
483
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100484/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100485 * Integer multiplication: R = m * P (GECC 5.7, SPA-resistant variant)
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100486 */
487int ecp_mul( const ecp_group *grp, ecp_point *R,
488 const mpi *m, const ecp_point *P )
489{
490 int ret = 0;
491 size_t pos;
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100492 ecp_ptjac Q[2];
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100493
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100494 ecp_ptjac_init( &Q[0] ); ecp_ptjac_init( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100495
496 /*
Manuel Pégourié-Gonnard27b1ba82012-11-08 18:24:10 +0100497 * The general method works only for m >= 1
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100498 */
499 if( mpi_cmp_int( m, 0 ) == 0 ) {
500 ecp_set_zero( R );
501 goto cleanup;
502 }
503
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100504 ecp_ptjac_set_zero( &Q[0] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100505
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100506 for( pos = mpi_msb( m ) - 1 ; ; pos-- )
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100507 {
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100508 MPI_CHK( ecp_double_jac( grp, &Q[0], &Q[0] ) );
509 MPI_CHK( ecp_add_mixed( grp, &Q[1], &Q[0], P ) );
510 MPI_CHK( ecp_ptjac_copy( &Q[0], &Q[ mpi_get_bit( m, pos ) ] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100511
512 if( pos == 0 )
513 break;
514 }
515
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100516 MPI_CHK( ecp_jac_to_aff( grp, R, &Q[0] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100517
518cleanup:
519
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100520 ecp_ptjac_free( &Q[0] ); ecp_ptjac_free( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100521
522 return( ret );
523}
524
525
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100526#if defined(POLARSSL_SELF_TEST)
527
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100528/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100529 * Checkup routine
530 */
531int ecp_self_test( int verbose )
532{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100533 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100534}
535
536#endif
537
538#endif