blob: 2fe456f8263d34af5009cbd1f6efd04cec2aca26 [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 */
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100193#define P521_SIZE_INT ( 521 / ( sizeof( t_uint ) << 3 ) + 1 )
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100194
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)
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100206 */
207static int ecp_mod_p521( mpi *N )
208{
209 int ret = 0;
210 t_uint Mp[P521_SIZE_INT];
211 mpi M;
212
213 if( N->n < P521_SIZE_INT )
214 return( 0 );
215
216 memset( Mp, 0, P521_SIZE_INT * sizeof( t_uint ) );
217 memcpy( Mp, N->p, P521_SIZE_INT * sizeof( t_uint ) );
218 Mp[P521_SIZE_INT - 1] &= P521_MASK;
219
220 M.s = 1;
221 M.n = P521_SIZE_INT;
222 M.p = Mp;
223
224 MPI_CHK( mpi_shift_r( N, 521 ) );
225
226 MPI_CHK( mpi_add_abs( N, N, &M ) );
227
228cleanup:
229 return( ret );
230}
231
232/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100233 * Domain parameters for secp192r1
234 */
235#define SECP192R1_P \
236 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"
237#define SECP192R1_B \
238 "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"
239#define SECP192R1_GX \
240 "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
241#define SECP192R1_GY \
242 "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"
243#define SECP192R1_N \
244 "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"
245
246/*
247 * Domain parameters for secp224r1
248 */
249#define SECP224R1_P \
250 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"
251#define SECP224R1_B \
252 "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"
253#define SECP224R1_GX \
254 "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
255#define SECP224R1_GY \
256 "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"
257#define SECP224R1_N \
258 "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"
259
260/*
261 * Domain parameters for secp256r1
262 */
263#define SECP256R1_P \
264 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
265#define SECP256R1_B \
266 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"
267#define SECP256R1_GX \
268 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
269#define SECP256R1_GY \
270 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
271#define SECP256R1_N \
272 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
273
274/*
275 * Domain parameters for secp384r1
276 */
277#define SECP384R1_P \
278 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
279 "FFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"
280#define SECP384R1_B \
281 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE814112" \
282 "0314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"
283#define SECP384R1_GX \
284 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B98" \
285 "59F741E082542A385502F25DBF55296C3A545E3872760AB7"
286#define SECP384R1_GY \
287 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147C" \
288 "E9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"
289#define SECP384R1_N \
290 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
291 "C7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"
292
293/*
294 * Domain parameters for secp521r1
295 */
296#define SECP521R1_P \
297 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
298 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
299 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
300#define SECP521R1_B \
301 "00000051953EB9618E1C9A1F929A21A0B68540EEA2DA725B" \
302 "99B315F3B8B489918EF109E156193951EC7E937B1652C0BD" \
303 "3BB1BF073573DF883D2C34F1EF451FD46B503F00"
304#define SECP521R1_GX \
305 "000000C6858E06B70404E9CD9E3ECB662395B4429C648139" \
306 "053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127" \
307 "A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
308#define SECP521R1_GY \
309 "0000011839296A789A3BC0045C8A5FB42C7D1BD998F54449" \
310 "579B446817AFBD17273E662C97EE72995EF42640C550B901" \
311 "3FAD0761353C7086A272C24088BE94769FD16650"
312#define SECP521R1_N \
313 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
314 "FFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148" \
315 "F709A5D03BB5C9B8899C47AEBB6FB71E91386409"
316
317/*
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100318 * Set a group using well-known domain parameters
319 */
320int ecp_use_known_dp( ecp_group *grp, size_t index )
321{
322 switch( index )
323 {
324 case POLARSSL_ECP_DP_SECP192R1:
325 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100326 SECP192R1_P, SECP192R1_B,
327 SECP192R1_GX, SECP192R1_GY, SECP192R1_N ) );
328
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100329 case POLARSSL_ECP_DP_SECP224R1:
330 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100331 SECP224R1_P, SECP224R1_B,
332 SECP224R1_GX, SECP224R1_GY, SECP224R1_N ) );
333
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100334 case POLARSSL_ECP_DP_SECP256R1:
335 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100336 SECP256R1_P, SECP256R1_B,
337 SECP256R1_GX, SECP256R1_GY, SECP256R1_N ) );
338
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100339 case POLARSSL_ECP_DP_SECP384R1:
340 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100341 SECP384R1_P, SECP384R1_B,
342 SECP384R1_GX, SECP384R1_GY, SECP384R1_N ) );
343
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100344 case POLARSSL_ECP_DP_SECP521R1:
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100345 grp->modp = ecp_mod_p521;
346 grp->pbits = 521;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100347 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100348 SECP521R1_P, SECP521R1_B,
349 SECP521R1_GX, SECP521R1_GY, SECP521R1_N ) );
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100350 }
351
352 return( POLARSSL_ERR_ECP_GENERIC );
353}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100354
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100355/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100356 * Fast mod-p functions expect an argument in the 0 .. p^2 range.
357 *
358 * In order to garantee that, we need to ensure that operands of
359 * mpi_mul_mpi are in the 0 .. p range. So, after each operation we will
360 * bring the result back to this range.
361 *
362 * The following macros are helpers for that.
363 */
364
365/*
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100366 * Reduce a mpi mod p in-place, general case, to use after mpi_mul_mpi
367 */
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100368#define MOD_MUL( N ) MPI_CHK( ecp_modp( &N, grp ) )
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100369
370/*
371 * Reduce a mpi mod p in-place, to use after mpi_sub_mpi
372 */
373#define MOD_SUB( N ) \
374 while( mpi_cmp_int( &N, 0 ) < 0 ) \
375 MPI_CHK( mpi_add_mpi( &N, &N, &grp->P ) )
376
377/*
378 * Reduce a mpi mod p in-place, to use after mpi_add_mpi and mpi_mul_int
379 */
380#define MOD_ADD( N ) \
381 while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \
382 MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) )
383
384/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100385 * Internal point format used for fast (that is, without mpi_inv_mod)
386 * addition/doubling/multiplication: Jacobian coordinates (GECC ex 3.20)
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100387 */
388typedef struct
389{
390 mpi X, Y, Z;
391}
392ecp_ptjac;
393
394/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100395 * Initialize a point in Jacobian coordinates
396 */
397static void ecp_ptjac_init( ecp_ptjac *P )
398{
399 mpi_init( &P->X ); mpi_init( &P->Y ); mpi_init( &P->Z );
400}
401
402/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100403 * Free a point in Jacobian coordinates
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100404 */
405static void ecp_ptjac_free( ecp_ptjac *P )
406{
407 mpi_free( &P->X ); mpi_free( &P->Y ); mpi_free( &P->Z );
408}
409
410/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100411 * Copy P to R in Jacobian coordinates
412 */
413static int ecp_ptjac_copy( ecp_ptjac *R, const ecp_ptjac *P )
414{
415 int ret = 0;
416
417 MPI_CHK( mpi_copy( &R->X, &P->X ) );
418 MPI_CHK( mpi_copy( &R->Y, &P->Y ) );
419 MPI_CHK( mpi_copy( &R->Z, &P->Z ) );
420
421cleanup:
422 return( ret );
423}
424
425/*
426 * Set P to zero in Jacobian coordinates
427 */
428static int ecp_ptjac_set_zero( ecp_ptjac *P )
429{
430 int ret = 0;
431
432 MPI_CHK( mpi_lset( &P->X, 1 ) );
433 MPI_CHK( mpi_lset( &P->Y, 1 ) );
434 MPI_CHK( mpi_lset( &P->Z, 0 ) );
435
436cleanup:
437 return( ret );
438}
439
440/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100441 * Convert from affine to Jacobian coordinates
442 */
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100443static int ecp_aff_to_jac( ecp_ptjac *jac, const ecp_point *aff )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100444{
445 int ret = 0;
446
447 if( aff->is_zero )
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100448 return( ecp_ptjac_set_zero( jac ) );
449
450 MPI_CHK( mpi_copy( &jac->X, &aff->X ) );
451 MPI_CHK( mpi_copy( &jac->Y, &aff->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100452 MPI_CHK( mpi_lset( &jac->Z, 1 ) );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100453
454cleanup:
455 return( ret );
456}
457
458/*
459 * Convert from Jacobian to affine coordinates
460 */
461static int ecp_jac_to_aff( const ecp_group *grp,
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100462 ecp_point *aff, const ecp_ptjac *jac )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100463{
464 int ret = 0;
465 mpi Zi, ZZi, T;
466
467 if( mpi_cmp_int( &jac->Z, 0 ) == 0 ) {
468 ecp_set_zero( aff );
469 return( 0 );
470 }
471
472 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
473
474 aff->is_zero = 0;
475
476 /*
477 * aff.X = jac.X / (jac.Z)^2 mod p
478 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100479 MPI_CHK( mpi_inv_mod( &Zi, &jac->Z, &grp->P ) );
480 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
481 MPI_CHK( mpi_mul_mpi( &aff->X, &jac->X, &ZZi ) ); MOD_MUL( aff->X );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100482
483 /*
484 * aff.Y = jac.Y / (jac.Z)^3 mod p
485 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100486 MPI_CHK( mpi_mul_mpi( &aff->Y, &jac->Y, &ZZi ) ); MOD_MUL( aff->Y );
487 MPI_CHK( mpi_mul_mpi( &aff->Y, &aff->Y, &Zi ) ); MOD_MUL( aff->Y );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100488
489cleanup:
490
491 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
492
493 return( ret );
494}
495
496/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100497 * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21)
498 */
499static int ecp_double_jac( const ecp_group *grp, ecp_ptjac *R,
500 const ecp_ptjac *P )
501{
502 int ret = 0;
503 mpi T1, T2, T3, X, Y, Z;
504
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100505 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
506 return( ecp_ptjac_set_zero( R ) );
507
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100508 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 );
509 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
510
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100511 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
512 MPI_CHK( mpi_sub_mpi( &T2, &P->X, &T1 ) ); MOD_SUB( T2 );
513 MPI_CHK( mpi_add_mpi( &T1, &P->X, &T1 ) ); MOD_ADD( T1 );
514 MPI_CHK( mpi_mul_mpi( &T2, &T2, &T1 ) ); MOD_MUL( T2 );
515 MPI_CHK( mpi_mul_int( &T2, &T2, 3 ) ); MOD_ADD( T2 );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100516 MPI_CHK( mpi_copy ( &Y, &P->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100517 MPI_CHK( mpi_shift_l( &Y, 1 ) ); MOD_ADD( Y );
518 MPI_CHK( mpi_mul_mpi( &Z, &Y, &P->Z ) ); MOD_MUL( Z );
519 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
520 MPI_CHK( mpi_mul_mpi( &T3, &Y, &P->X ) ); MOD_MUL( T3 );
521 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100522
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100523 /*
524 * For Y = Y / 2 mod p, we must make sure that Y is even before
525 * using right-shift. No need to reduce mod p afterwards.
526 */
527 if( mpi_get_bit( &Y, 0 ) == 1 )
528 MPI_CHK( mpi_add_mpi( &Y, &Y, &grp->P ) );
529 MPI_CHK( mpi_shift_r( &Y, 1 ) );
530
531 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
532 MPI_CHK( mpi_copy ( &T1, &T3 ) );
533 MPI_CHK( mpi_shift_l( &T1, 1 ) ); MOD_ADD( T1 );
534 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
535 MPI_CHK( mpi_sub_mpi( &T1, &T3, &X ) ); MOD_SUB( T1 );
536 MPI_CHK( mpi_mul_mpi( &T1, &T1, &T2 ) ); MOD_MUL( T1 );
537 MPI_CHK( mpi_sub_mpi( &Y, &T1, &Y ) ); MOD_SUB( Y );
538
539 MPI_CHK( mpi_copy( &R->X, &X ) );
540 MPI_CHK( mpi_copy( &R->Y, &Y ) );
541 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100542
543cleanup:
544
545 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 );
546 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
547
548 return( ret );
549}
550
551/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100552 * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100553 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100554static int ecp_add_mixed( const ecp_group *grp, ecp_ptjac *R,
555 const ecp_ptjac *P, const ecp_point *Q )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100556{
557 int ret = 0;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100558 mpi T1, T2, T3, T4, X, Y, Z;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100559
560 /*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100561 * Trivial cases: P == 0 or Q == 0
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100562 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100563 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
564 return( ecp_aff_to_jac( R, Q ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100565
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100566 if( Q->is_zero )
567 return( ecp_ptjac_copy( R, P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100568
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100569 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 ); mpi_init( &T4 );
570 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100571
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100572 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
573 MPI_CHK( mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
574 MPI_CHK( mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
575 MPI_CHK( mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
576 MPI_CHK( mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
577 MPI_CHK( mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100578
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100579 if( mpi_cmp_int( &T1, 0 ) == 0 )
580 {
581 if( mpi_cmp_int( &T2, 0 ) == 0 )
582 {
583 ret = ecp_double_jac( grp, R, P );
584 goto cleanup;
585 }
586 else
587 {
588 ret = ecp_ptjac_set_zero( R );
589 goto cleanup;
590 }
591 }
592
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100593 MPI_CHK( mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
594 MPI_CHK( mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
595 MPI_CHK( mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
596 MPI_CHK( mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
597 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
598 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
599 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
600 MPI_CHK( mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
601 MPI_CHK( mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
602 MPI_CHK( mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
603 MPI_CHK( mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
604 MPI_CHK( mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100605
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100606 MPI_CHK( mpi_copy( &R->X, &X ) );
607 MPI_CHK( mpi_copy( &R->Y, &Y ) );
608 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100609
610cleanup:
611
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100612 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 ); mpi_free( &T4 );
613 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100614
615 return( ret );
616}
617
618/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100619 * Addition: R = P + Q, affine wrapper
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100620 */
621int ecp_add( const ecp_group *grp, ecp_point *R,
622 const ecp_point *P, const ecp_point *Q )
623{
624 int ret = 0;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100625 ecp_ptjac J;
626
627 ecp_ptjac_init( &J );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100628
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100629 MPI_CHK( ecp_aff_to_jac( &J, P ) );
630 MPI_CHK( ecp_add_mixed( grp, &J, &J, Q ) );
631 MPI_CHK( ecp_jac_to_aff( grp, R, &J ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100632
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100633cleanup:
634
635 ecp_ptjac_free( &J );
636
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100637 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100638}
639
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100640/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100641 * Integer multiplication: R = m * P (GECC 5.7, SPA-resistant variant)
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100642 */
643int ecp_mul( const ecp_group *grp, ecp_point *R,
644 const mpi *m, const ecp_point *P )
645{
646 int ret = 0;
647 size_t pos;
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100648 ecp_ptjac Q[2];
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100649
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100650 ecp_ptjac_init( &Q[0] ); ecp_ptjac_init( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100651
652 /*
Manuel Pégourié-Gonnard27b1ba82012-11-08 18:24:10 +0100653 * The general method works only for m >= 1
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100654 */
655 if( mpi_cmp_int( m, 0 ) == 0 ) {
656 ecp_set_zero( R );
657 goto cleanup;
658 }
659
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100660 ecp_ptjac_set_zero( &Q[0] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100661
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100662 for( pos = mpi_msb( m ) - 1 ; ; pos-- )
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100663 {
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100664 MPI_CHK( ecp_double_jac( grp, &Q[0], &Q[0] ) );
665 MPI_CHK( ecp_add_mixed( grp, &Q[1], &Q[0], P ) );
666 MPI_CHK( ecp_ptjac_copy( &Q[0], &Q[ mpi_get_bit( m, pos ) ] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100667
668 if( pos == 0 )
669 break;
670 }
671
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100672 MPI_CHK( ecp_jac_to_aff( grp, R, &Q[0] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100673
674cleanup:
675
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100676 ecp_ptjac_free( &Q[0] ); ecp_ptjac_free( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100677
678 return( ret );
679}
680
681
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100682#if defined(POLARSSL_SELF_TEST)
683
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100684/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100685 * Checkup routine
686 */
687int ecp_self_test( int verbose )
688{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100689 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100690}
691
692#endif
693
694#endif