blob: a773416a98b62ad56533149fc1a55b2970d94f11 [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"
Manuel Pégourié-Gonnard84338242012-11-11 20:45:18 +010039#include <limits.h>
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010040
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010041/*
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010042 * Initialize (the components of) a point
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010043 */
44void ecp_point_init( ecp_point *pt )
45{
46 if( pt == NULL )
47 return;
48
49 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010050 mpi_init( &pt->X );
51 mpi_init( &pt->Y );
52}
53
54/*
55 * Initialize (the components of) a group
56 */
57void ecp_group_init( ecp_group *grp )
58{
59 if( grp == NULL )
60 return;
61
62 mpi_init( &grp->P );
63 mpi_init( &grp->B );
64 ecp_point_init( &grp->G );
65 mpi_init( &grp->N );
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +010066
67 grp->modp = NULL;
68 grp->pbits = 0;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010069}
70
71/*
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010072 * Unallocate (the components of) a point
73 */
74void ecp_point_free( ecp_point *pt )
75{
76 if( pt == NULL )
77 return;
78
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +010079 pt->is_zero = 1;
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010080 mpi_free( &( pt->X ) );
81 mpi_free( &( pt->Y ) );
82}
83
84/*
85 * Unallocate (the components of) a group
86 */
87void ecp_group_free( ecp_group *grp )
88{
89 if( grp == NULL )
90 return;
91
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010092 mpi_free( &grp->P );
93 mpi_free( &grp->B );
94 ecp_point_free( &grp->G );
95 mpi_free( &grp->N );
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010096}
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010097
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010098/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010099 * Set point to zero
100 */
101void ecp_set_zero( ecp_point *pt )
102{
103 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100104 mpi_free( &pt->X );
105 mpi_free( &pt->Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100106}
107
108/*
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100109 * Copy the contents of Q into P
110 */
111int ecp_copy( ecp_point *P, const ecp_point *Q )
112{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100113 int ret;
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100114
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100115 if( Q->is_zero ) {
116 ecp_set_zero( P );
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100117 return( 0 );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100118 }
119
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100120 P->is_zero = Q->is_zero;
121 MPI_CHK( mpi_copy( &P->X, &Q->X ) );
122 MPI_CHK( mpi_copy( &P->Y, &Q->Y ) );
123
124cleanup:
125 return( ret );
126}
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +0100127
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100128/*
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100129 * Import a non-zero point from ASCII strings
130 */
131int ecp_point_read_string( ecp_point *P, int radix,
132 const char *x, const char *y )
133{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100134 int ret;
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100135
136 P->is_zero = 0;
137 MPI_CHK( mpi_read_string( &P->X, radix, x ) );
138 MPI_CHK( mpi_read_string( &P->Y, radix, y ) );
139
140cleanup:
141 return( ret );
142}
143
144/*
145 * Import an ECP group from ASCII strings
146 */
147int ecp_group_read_string( ecp_group *grp, int radix,
148 const char *p, const char *b,
149 const char *gx, const char *gy, const char *n)
150{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100151 int ret;
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100152
153 MPI_CHK( mpi_read_string( &grp->P, radix, p ) );
154 MPI_CHK( mpi_read_string( &grp->B, radix, b ) );
155 MPI_CHK( ecp_point_read_string( &grp->G, radix, gx, gy ) );
156 MPI_CHK( mpi_read_string( &grp->N, radix, n ) );
157
158cleanup:
159 return( ret );
160}
161
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100162/*
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100163 * Wrapper around fast quasi-modp functions, with fall-back to mpi_mod_mpi
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100164 */
165static int ecp_modp( mpi *N, const ecp_group *grp )
166{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100167 int ret;
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100168
169 if( grp->modp == NULL )
170 return( mpi_mod_mpi( N, N, &grp->P ) );
171
172 if( mpi_cmp_int( N, 0 ) < 0 || mpi_msb( N ) > 2 * grp->pbits )
173 return( POLARSSL_ERR_ECP_GENERIC );
174
175 MPI_CHK( grp->modp( N ) );
176
177 while( mpi_cmp_int( N, 0 ) < 0 )
178 MPI_CHK( mpi_add_mpi( N, N, &grp->P ) );
179
180 while( mpi_cmp_mpi( N, &grp->P ) >= 0 )
181 MPI_CHK( mpi_sub_mpi( N, N, &grp->P ) );
182
183cleanup:
184 return( ret );
185}
186
187/*
Manuel Pégourié-Gonnard84338242012-11-11 20:45:18 +0100188 * 192 bits in terms of t_uint
189 */
190#define P192_SIZE_INT ( 192 / CHAR_BIT / sizeof( t_uint ) )
191
192/*
193 * Table to get S1, S2, S3 of FIPS 186-3 D.2.1:
194 * -1 means let this chunk be 0
195 * a positive value i means A_i.
196 */
197#define P192_CHUNKS 3
198#define P192_CHUNK_CHAR ( 64 / CHAR_BIT )
199#define P192_CHUNK_INT ( P192_CHUNK_CHAR / sizeof( t_uint ) )
200
201const signed char p192_tbl[][P192_CHUNKS] = {
202 { -1, 3, 3 }, /* S1 */
203 { 4, 4, -1 }, /* S2 */
204 { 5, 5, 5 }, /* S3 */
205};
206
207/*
208 * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1)
209 */
210static int ecp_mod_p192( mpi *N )
211{
212 int ret;
213 unsigned char i, j, offset;
214 signed char chunk;
215 mpi tmp, acc;
216 t_uint tmp_p[P192_SIZE_INT], acc_p[P192_SIZE_INT + 1];
217
218 tmp.s = 1;
219 tmp.n = sizeof( tmp_p ) / sizeof( tmp_p[0] );
220 tmp.p = tmp_p;
221
222 acc.s = 1;
223 acc.n = sizeof( acc_p ) / sizeof( acc_p[0] );
224 acc.p = acc_p;
225
226 MPI_CHK( mpi_grow( N, P192_SIZE_INT * 2 ) );
227
228 /*
229 * acc = T
230 */
231 memset( acc_p, 0, sizeof( acc_p ) );
232 memcpy( acc_p, N->p, P192_CHUNK_CHAR * P192_CHUNKS );
233
234 for( i = 0; i < sizeof( p192_tbl ) / sizeof( p192_tbl[0] ); i++)
235 {
236 /*
237 * tmp = S_i
238 */
239 memset( tmp_p, 0, sizeof( tmp_p ) );
240 for( j = 0, offset = P192_CHUNKS - 1; j < P192_CHUNKS; j++, offset-- )
241 {
242 chunk = p192_tbl[i][j];
243 if( chunk >= 0 )
244 memcpy( tmp_p + offset * P192_CHUNK_INT,
245 N->p + chunk * P192_CHUNK_INT,
246 P192_CHUNK_CHAR );
247 }
248
249 /*
250 * acc += tmp
251 */
252 MPI_CHK( mpi_add_abs( &acc, &acc, &tmp ) );
253 }
254
255 MPI_CHK( mpi_copy( N, &acc ) );
256
257cleanup:
258 return( ret );
259}
260
261/*
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100262 * Size of p521 in terms of t_uint
263 */
Manuel Pégourié-Gonnard84338242012-11-11 20:45:18 +0100264#define P521_SIZE_INT ( 521 / CHAR_BIT / sizeof( t_uint ) + 1 )
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100265
266/*
267 * Bits to keep in the most significant t_uint
268 */
269#if defined(POLARSS_HAVE_INT8)
270#define P521_MASK 0x01
271#else
272#define P521_MASK 0x01FF
273#endif
274
275/*
276 * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5)
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100277 */
278static int ecp_mod_p521( mpi *N )
279{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100280 int ret;
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100281 t_uint Mp[P521_SIZE_INT];
282 mpi M;
283
284 if( N->n < P521_SIZE_INT )
285 return( 0 );
286
287 memset( Mp, 0, P521_SIZE_INT * sizeof( t_uint ) );
288 memcpy( Mp, N->p, P521_SIZE_INT * sizeof( t_uint ) );
289 Mp[P521_SIZE_INT - 1] &= P521_MASK;
290
291 M.s = 1;
292 M.n = P521_SIZE_INT;
293 M.p = Mp;
294
295 MPI_CHK( mpi_shift_r( N, 521 ) );
296
297 MPI_CHK( mpi_add_abs( N, N, &M ) );
298
299cleanup:
300 return( ret );
301}
302
303/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100304 * Domain parameters for secp192r1
305 */
306#define SECP192R1_P \
307 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"
308#define SECP192R1_B \
309 "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"
310#define SECP192R1_GX \
311 "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
312#define SECP192R1_GY \
313 "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"
314#define SECP192R1_N \
315 "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"
316
317/*
318 * Domain parameters for secp224r1
319 */
320#define SECP224R1_P \
321 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"
322#define SECP224R1_B \
323 "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"
324#define SECP224R1_GX \
325 "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
326#define SECP224R1_GY \
327 "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"
328#define SECP224R1_N \
329 "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"
330
331/*
332 * Domain parameters for secp256r1
333 */
334#define SECP256R1_P \
335 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
336#define SECP256R1_B \
337 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"
338#define SECP256R1_GX \
339 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
340#define SECP256R1_GY \
341 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
342#define SECP256R1_N \
343 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
344
345/*
346 * Domain parameters for secp384r1
347 */
348#define SECP384R1_P \
349 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
350 "FFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"
351#define SECP384R1_B \
352 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE814112" \
353 "0314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"
354#define SECP384R1_GX \
355 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B98" \
356 "59F741E082542A385502F25DBF55296C3A545E3872760AB7"
357#define SECP384R1_GY \
358 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147C" \
359 "E9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"
360#define SECP384R1_N \
361 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
362 "C7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"
363
364/*
365 * Domain parameters for secp521r1
366 */
367#define SECP521R1_P \
368 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
369 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
370 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
371#define SECP521R1_B \
372 "00000051953EB9618E1C9A1F929A21A0B68540EEA2DA725B" \
373 "99B315F3B8B489918EF109E156193951EC7E937B1652C0BD" \
374 "3BB1BF073573DF883D2C34F1EF451FD46B503F00"
375#define SECP521R1_GX \
376 "000000C6858E06B70404E9CD9E3ECB662395B4429C648139" \
377 "053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127" \
378 "A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
379#define SECP521R1_GY \
380 "0000011839296A789A3BC0045C8A5FB42C7D1BD998F54449" \
381 "579B446817AFBD17273E662C97EE72995EF42640C550B901" \
382 "3FAD0761353C7086A272C24088BE94769FD16650"
383#define SECP521R1_N \
384 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
385 "FFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148" \
386 "F709A5D03BB5C9B8899C47AEBB6FB71E91386409"
387
388/*
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100389 * Set a group using well-known domain parameters
390 */
391int ecp_use_known_dp( ecp_group *grp, size_t index )
392{
393 switch( index )
394 {
395 case POLARSSL_ECP_DP_SECP192R1:
Manuel Pégourié-Gonnard84338242012-11-11 20:45:18 +0100396 grp->modp = ecp_mod_p192;
397 grp->pbits = 192;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100398 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100399 SECP192R1_P, SECP192R1_B,
400 SECP192R1_GX, SECP192R1_GY, SECP192R1_N ) );
401
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100402 case POLARSSL_ECP_DP_SECP224R1:
403 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100404 SECP224R1_P, SECP224R1_B,
405 SECP224R1_GX, SECP224R1_GY, SECP224R1_N ) );
406
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100407 case POLARSSL_ECP_DP_SECP256R1:
408 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100409 SECP256R1_P, SECP256R1_B,
410 SECP256R1_GX, SECP256R1_GY, SECP256R1_N ) );
411
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100412 case POLARSSL_ECP_DP_SECP384R1:
413 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100414 SECP384R1_P, SECP384R1_B,
415 SECP384R1_GX, SECP384R1_GY, SECP384R1_N ) );
416
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100417 case POLARSSL_ECP_DP_SECP521R1:
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100418 grp->modp = ecp_mod_p521;
419 grp->pbits = 521;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100420 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100421 SECP521R1_P, SECP521R1_B,
422 SECP521R1_GX, SECP521R1_GY, SECP521R1_N ) );
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100423 }
424
425 return( POLARSSL_ERR_ECP_GENERIC );
426}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100427
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100428/*
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100429 * Fast mod-p functions expect their argument to be in the 0..p^2 range.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100430 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100431 * In order to guarantee that, we need to ensure that operands of
432 * mpi_mul_mpi are in the 0..p range. So, after each operation we will
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100433 * bring the result back to this range.
434 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100435 * The following macros are shortcuts for doing that.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100436 */
437
438/*
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100439 * Reduce a mpi mod p in-place, general case, to use after mpi_mul_mpi
440 */
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100441#define MOD_MUL( N ) MPI_CHK( ecp_modp( &N, grp ) )
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100442
443/*
444 * Reduce a mpi mod p in-place, to use after mpi_sub_mpi
445 */
446#define MOD_SUB( N ) \
447 while( mpi_cmp_int( &N, 0 ) < 0 ) \
448 MPI_CHK( mpi_add_mpi( &N, &N, &grp->P ) )
449
450/*
451 * Reduce a mpi mod p in-place, to use after mpi_add_mpi and mpi_mul_int
452 */
453#define MOD_ADD( N ) \
454 while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \
455 MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) )
456
457/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100458 * Internal point format used for fast (that is, without mpi_inv_mod)
459 * addition/doubling/multiplication: Jacobian coordinates (GECC ex 3.20)
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100460 */
461typedef struct
462{
463 mpi X, Y, Z;
464}
465ecp_ptjac;
466
467/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100468 * Initialize a point in Jacobian coordinates
469 */
470static void ecp_ptjac_init( ecp_ptjac *P )
471{
472 mpi_init( &P->X ); mpi_init( &P->Y ); mpi_init( &P->Z );
473}
474
475/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100476 * Free a point in Jacobian coordinates
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100477 */
478static void ecp_ptjac_free( ecp_ptjac *P )
479{
480 mpi_free( &P->X ); mpi_free( &P->Y ); mpi_free( &P->Z );
481}
482
483/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100484 * Copy P to R in Jacobian coordinates
485 */
486static int ecp_ptjac_copy( ecp_ptjac *R, const ecp_ptjac *P )
487{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100488 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100489
490 MPI_CHK( mpi_copy( &R->X, &P->X ) );
491 MPI_CHK( mpi_copy( &R->Y, &P->Y ) );
492 MPI_CHK( mpi_copy( &R->Z, &P->Z ) );
493
494cleanup:
495 return( ret );
496}
497
498/*
499 * Set P to zero in Jacobian coordinates
500 */
501static int ecp_ptjac_set_zero( ecp_ptjac *P )
502{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100503 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100504
505 MPI_CHK( mpi_lset( &P->X, 1 ) );
506 MPI_CHK( mpi_lset( &P->Y, 1 ) );
507 MPI_CHK( mpi_lset( &P->Z, 0 ) );
508
509cleanup:
510 return( ret );
511}
512
513/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100514 * Convert from affine to Jacobian coordinates
515 */
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100516static int ecp_aff_to_jac( ecp_ptjac *jac, const ecp_point *aff )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100517{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100518 int ret;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100519
520 if( aff->is_zero )
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100521 return( ecp_ptjac_set_zero( jac ) );
522
523 MPI_CHK( mpi_copy( &jac->X, &aff->X ) );
524 MPI_CHK( mpi_copy( &jac->Y, &aff->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100525 MPI_CHK( mpi_lset( &jac->Z, 1 ) );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100526
527cleanup:
528 return( ret );
529}
530
531/*
532 * Convert from Jacobian to affine coordinates
533 */
534static int ecp_jac_to_aff( const ecp_group *grp,
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100535 ecp_point *aff, const ecp_ptjac *jac )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100536{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100537 int ret;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100538 mpi Zi, ZZi, T;
539
540 if( mpi_cmp_int( &jac->Z, 0 ) == 0 ) {
541 ecp_set_zero( aff );
542 return( 0 );
543 }
544
545 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
546
547 aff->is_zero = 0;
548
549 /*
550 * aff.X = jac.X / (jac.Z)^2 mod p
551 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100552 MPI_CHK( mpi_inv_mod( &Zi, &jac->Z, &grp->P ) );
553 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
554 MPI_CHK( mpi_mul_mpi( &aff->X, &jac->X, &ZZi ) ); MOD_MUL( aff->X );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100555
556 /*
557 * aff.Y = jac.Y / (jac.Z)^3 mod p
558 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100559 MPI_CHK( mpi_mul_mpi( &aff->Y, &jac->Y, &ZZi ) ); MOD_MUL( aff->Y );
560 MPI_CHK( mpi_mul_mpi( &aff->Y, &aff->Y, &Zi ) ); MOD_MUL( aff->Y );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100561
562cleanup:
563
564 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
565
566 return( ret );
567}
568
569/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100570 * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21)
571 */
572static int ecp_double_jac( const ecp_group *grp, ecp_ptjac *R,
573 const ecp_ptjac *P )
574{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100575 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100576 mpi T1, T2, T3, X, Y, Z;
577
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100578 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
579 return( ecp_ptjac_set_zero( R ) );
580
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100581 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 );
582 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
583
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100584 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
585 MPI_CHK( mpi_sub_mpi( &T2, &P->X, &T1 ) ); MOD_SUB( T2 );
586 MPI_CHK( mpi_add_mpi( &T1, &P->X, &T1 ) ); MOD_ADD( T1 );
587 MPI_CHK( mpi_mul_mpi( &T2, &T2, &T1 ) ); MOD_MUL( T2 );
588 MPI_CHK( mpi_mul_int( &T2, &T2, 3 ) ); MOD_ADD( T2 );
589 MPI_CHK( mpi_mul_int( &Y, &P->Y, 2 ) ); MOD_ADD( Y );
590 MPI_CHK( mpi_mul_mpi( &Z, &Y, &P->Z ) ); MOD_MUL( Z );
591 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
592 MPI_CHK( mpi_mul_mpi( &T3, &Y, &P->X ) ); MOD_MUL( T3 );
593 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100594
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100595 /*
596 * For Y = Y / 2 mod p, we must make sure that Y is even before
597 * using right-shift. No need to reduce mod p afterwards.
598 */
599 if( mpi_get_bit( &Y, 0 ) == 1 )
600 MPI_CHK( mpi_add_mpi( &Y, &Y, &grp->P ) );
601 MPI_CHK( mpi_shift_r( &Y, 1 ) );
602
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100603 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
604 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
605 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
606 MPI_CHK( mpi_sub_mpi( &T1, &T3, &X ) ); MOD_SUB( T1 );
607 MPI_CHK( mpi_mul_mpi( &T1, &T1, &T2 ) ); MOD_MUL( T1 );
608 MPI_CHK( mpi_sub_mpi( &Y, &T1, &Y ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100609
610 MPI_CHK( mpi_copy( &R->X, &X ) );
611 MPI_CHK( mpi_copy( &R->Y, &Y ) );
612 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100613
614cleanup:
615
616 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 );
617 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
618
619 return( ret );
620}
621
622/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100623 * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100624 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100625static int ecp_add_mixed( const ecp_group *grp, ecp_ptjac *R,
626 const ecp_ptjac *P, const ecp_point *Q )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100627{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100628 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100629 mpi T1, T2, T3, T4, X, Y, Z;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100630
631 /*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100632 * Trivial cases: P == 0 or Q == 0
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100633 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100634 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
635 return( ecp_aff_to_jac( R, Q ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100636
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100637 if( Q->is_zero )
638 return( ecp_ptjac_copy( R, P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100639
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100640 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 ); mpi_init( &T4 );
641 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100642
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100643 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
644 MPI_CHK( mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
645 MPI_CHK( mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
646 MPI_CHK( mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
647 MPI_CHK( mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
648 MPI_CHK( mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100649
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100650 if( mpi_cmp_int( &T1, 0 ) == 0 )
651 {
652 if( mpi_cmp_int( &T2, 0 ) == 0 )
653 {
654 ret = ecp_double_jac( grp, R, P );
655 goto cleanup;
656 }
657 else
658 {
659 ret = ecp_ptjac_set_zero( R );
660 goto cleanup;
661 }
662 }
663
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100664 MPI_CHK( mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
665 MPI_CHK( mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
666 MPI_CHK( mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
667 MPI_CHK( mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
668 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
669 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
670 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
671 MPI_CHK( mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
672 MPI_CHK( mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
673 MPI_CHK( mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
674 MPI_CHK( mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
675 MPI_CHK( mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100676
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100677 MPI_CHK( mpi_copy( &R->X, &X ) );
678 MPI_CHK( mpi_copy( &R->Y, &Y ) );
679 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100680
681cleanup:
682
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100683 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 ); mpi_free( &T4 );
684 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100685
686 return( ret );
687}
688
689/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100690 * Addition: R = P + Q, affine wrapper
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100691 */
692int ecp_add( const ecp_group *grp, ecp_point *R,
693 const ecp_point *P, const ecp_point *Q )
694{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100695 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100696 ecp_ptjac J;
697
698 ecp_ptjac_init( &J );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100699
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100700 MPI_CHK( ecp_aff_to_jac( &J, P ) );
701 MPI_CHK( ecp_add_mixed( grp, &J, &J, Q ) );
702 MPI_CHK( ecp_jac_to_aff( grp, R, &J ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100703
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100704cleanup:
705
706 ecp_ptjac_free( &J );
707
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100708 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100709}
710
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100711/*
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100712 * Integer multiplication: R = m * P (GECC 5.7, SPA-resistant)
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100713 */
714int ecp_mul( const ecp_group *grp, ecp_point *R,
715 const mpi *m, const ecp_point *P )
716{
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100717 int ret, cmp;
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100718 size_t pos;
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100719 ecp_ptjac Q[2];
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100720
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100721 cmp = mpi_cmp_int( m, 0 );
722
723 if( cmp < 0 )
724 return( POLARSSL_ERR_ECP_GENERIC );
725
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100726 /*
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100727 * The general method works only for m != 0
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100728 */
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100729 if( cmp == 0 ) {
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100730 ecp_set_zero( R );
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100731 return( 0 );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100732 }
733
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100734 ecp_ptjac_init( &Q[0] ); ecp_ptjac_init( &Q[1] );
735
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100736 ecp_ptjac_set_zero( &Q[0] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100737
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100738 for( pos = mpi_msb( m ) - 1 ; ; pos-- )
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100739 {
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100740 MPI_CHK( ecp_double_jac( grp, &Q[0], &Q[0] ) );
741 MPI_CHK( ecp_add_mixed( grp, &Q[1], &Q[0], P ) );
742 MPI_CHK( ecp_ptjac_copy( &Q[0], &Q[ mpi_get_bit( m, pos ) ] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100743
744 if( pos == 0 )
745 break;
746 }
747
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100748 MPI_CHK( ecp_jac_to_aff( grp, R, &Q[0] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100749
750cleanup:
751
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100752 ecp_ptjac_free( &Q[0] ); ecp_ptjac_free( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100753
754 return( ret );
755}
756
757
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100758#if defined(POLARSSL_SELF_TEST)
759
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100760/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100761 * Checkup routine
762 */
763int ecp_self_test( int verbose )
764{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100765 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100766}
767
768#endif
769
770#endif