blob: 68d2f4eb88668480b39b8d3bbab217b1a4cfaf70 [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
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +010067 grp->pbits = 0;
Manuel Pégourié-Gonnard773ed542012-11-18 13:19:07 +010068 grp->nbits = 0;
69
70 grp->modp = NULL;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010071}
72
73/*
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010074 * Unallocate (the components of) a point
75 */
76void ecp_point_free( ecp_point *pt )
77{
78 if( pt == NULL )
79 return;
80
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +010081 pt->is_zero = 1;
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010082 mpi_free( &( pt->X ) );
83 mpi_free( &( pt->Y ) );
84}
85
86/*
87 * Unallocate (the components of) a group
88 */
89void ecp_group_free( ecp_group *grp )
90{
91 if( grp == NULL )
92 return;
93
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010094 mpi_free( &grp->P );
95 mpi_free( &grp->B );
96 ecp_point_free( &grp->G );
97 mpi_free( &grp->N );
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010098}
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010099
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100100/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100101 * Set point to zero
102 */
103void ecp_set_zero( ecp_point *pt )
104{
105 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100106 mpi_free( &pt->X );
107 mpi_free( &pt->Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100108}
109
110/*
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100111 * Copy the contents of Q into P
112 */
113int ecp_copy( ecp_point *P, const ecp_point *Q )
114{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100115 int ret;
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100116
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100117 if( Q->is_zero ) {
118 ecp_set_zero( P );
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100119 return( 0 );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100120 }
121
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100122 P->is_zero = Q->is_zero;
123 MPI_CHK( mpi_copy( &P->X, &Q->X ) );
124 MPI_CHK( mpi_copy( &P->Y, &Q->Y ) );
125
126cleanup:
127 return( ret );
128}
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +0100129
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100130/*
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100131 * Import a non-zero point from ASCII strings
132 */
133int ecp_point_read_string( ecp_point *P, int radix,
134 const char *x, const char *y )
135{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100136 int ret;
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100137
138 P->is_zero = 0;
139 MPI_CHK( mpi_read_string( &P->X, radix, x ) );
140 MPI_CHK( mpi_read_string( &P->Y, radix, y ) );
141
142cleanup:
143 return( ret );
144}
145
146/*
147 * Import an ECP group from ASCII strings
148 */
149int ecp_group_read_string( ecp_group *grp, int radix,
150 const char *p, const char *b,
151 const char *gx, const char *gy, const char *n)
152{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100153 int ret;
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100154
155 MPI_CHK( mpi_read_string( &grp->P, radix, p ) );
156 MPI_CHK( mpi_read_string( &grp->B, radix, b ) );
157 MPI_CHK( ecp_point_read_string( &grp->G, radix, gx, gy ) );
158 MPI_CHK( mpi_read_string( &grp->N, radix, n ) );
159
Manuel Pégourié-Gonnard773ed542012-11-18 13:19:07 +0100160 grp->pbits = mpi_msb( &grp->P );
161 grp->nbits = mpi_msb( &grp->N );
162
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100163cleanup:
164 return( ret );
165}
166
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100167/*
Manuel Pégourié-Gonnard773ed542012-11-18 13:19:07 +0100168 * Wrapper around fast quasi-modp functions, with fall-back to mpi_mod_mpi.
169 * See the documentation of struct ecp_group.
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100170 */
171static int ecp_modp( mpi *N, const ecp_group *grp )
172{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100173 int ret;
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100174
175 if( grp->modp == NULL )
176 return( mpi_mod_mpi( N, N, &grp->P ) );
177
178 if( mpi_cmp_int( N, 0 ) < 0 || mpi_msb( N ) > 2 * grp->pbits )
179 return( POLARSSL_ERR_ECP_GENERIC );
180
181 MPI_CHK( grp->modp( N ) );
182
183 while( mpi_cmp_int( N, 0 ) < 0 )
184 MPI_CHK( mpi_add_mpi( N, N, &grp->P ) );
185
186 while( mpi_cmp_mpi( N, &grp->P ) >= 0 )
187 MPI_CHK( mpi_sub_mpi( N, N, &grp->P ) );
188
189cleanup:
190 return( ret );
191}
192
193/*
Manuel Pégourié-Gonnard84338242012-11-11 20:45:18 +0100194 * 192 bits in terms of t_uint
195 */
196#define P192_SIZE_INT ( 192 / CHAR_BIT / sizeof( t_uint ) )
197
198/*
199 * Table to get S1, S2, S3 of FIPS 186-3 D.2.1:
200 * -1 means let this chunk be 0
201 * a positive value i means A_i.
202 */
203#define P192_CHUNKS 3
204#define P192_CHUNK_CHAR ( 64 / CHAR_BIT )
205#define P192_CHUNK_INT ( P192_CHUNK_CHAR / sizeof( t_uint ) )
206
207const signed char p192_tbl[][P192_CHUNKS] = {
208 { -1, 3, 3 }, /* S1 */
209 { 4, 4, -1 }, /* S2 */
210 { 5, 5, 5 }, /* S3 */
211};
212
213/*
214 * Fast quasi-reduction modulo p192 (FIPS 186-3 D.2.1)
215 */
216static int ecp_mod_p192( mpi *N )
217{
218 int ret;
219 unsigned char i, j, offset;
220 signed char chunk;
221 mpi tmp, acc;
222 t_uint tmp_p[P192_SIZE_INT], acc_p[P192_SIZE_INT + 1];
223
224 tmp.s = 1;
225 tmp.n = sizeof( tmp_p ) / sizeof( tmp_p[0] );
226 tmp.p = tmp_p;
227
228 acc.s = 1;
229 acc.n = sizeof( acc_p ) / sizeof( acc_p[0] );
230 acc.p = acc_p;
231
232 MPI_CHK( mpi_grow( N, P192_SIZE_INT * 2 ) );
233
234 /*
235 * acc = T
236 */
237 memset( acc_p, 0, sizeof( acc_p ) );
238 memcpy( acc_p, N->p, P192_CHUNK_CHAR * P192_CHUNKS );
239
240 for( i = 0; i < sizeof( p192_tbl ) / sizeof( p192_tbl[0] ); i++)
241 {
242 /*
243 * tmp = S_i
244 */
245 memset( tmp_p, 0, sizeof( tmp_p ) );
246 for( j = 0, offset = P192_CHUNKS - 1; j < P192_CHUNKS; j++, offset-- )
247 {
248 chunk = p192_tbl[i][j];
249 if( chunk >= 0 )
250 memcpy( tmp_p + offset * P192_CHUNK_INT,
251 N->p + chunk * P192_CHUNK_INT,
252 P192_CHUNK_CHAR );
253 }
254
255 /*
256 * acc += tmp
257 */
258 MPI_CHK( mpi_add_abs( &acc, &acc, &tmp ) );
259 }
260
261 MPI_CHK( mpi_copy( N, &acc ) );
262
263cleanup:
264 return( ret );
265}
266
267/*
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100268 * Size of p521 in terms of t_uint
269 */
Manuel Pégourié-Gonnard84338242012-11-11 20:45:18 +0100270#define P521_SIZE_INT ( 521 / CHAR_BIT / sizeof( t_uint ) + 1 )
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100271
272/*
273 * Bits to keep in the most significant t_uint
274 */
275#if defined(POLARSS_HAVE_INT8)
276#define P521_MASK 0x01
277#else
278#define P521_MASK 0x01FF
279#endif
280
281/*
282 * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5)
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100283 */
284static int ecp_mod_p521( mpi *N )
285{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100286 int ret;
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100287 t_uint Mp[P521_SIZE_INT];
288 mpi M;
289
290 if( N->n < P521_SIZE_INT )
291 return( 0 );
292
293 memset( Mp, 0, P521_SIZE_INT * sizeof( t_uint ) );
294 memcpy( Mp, N->p, P521_SIZE_INT * sizeof( t_uint ) );
295 Mp[P521_SIZE_INT - 1] &= P521_MASK;
296
297 M.s = 1;
298 M.n = P521_SIZE_INT;
299 M.p = Mp;
300
301 MPI_CHK( mpi_shift_r( N, 521 ) );
302
303 MPI_CHK( mpi_add_abs( N, N, &M ) );
304
305cleanup:
306 return( ret );
307}
308
309/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100310 * Domain parameters for secp192r1
311 */
312#define SECP192R1_P \
313 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"
314#define SECP192R1_B \
315 "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"
316#define SECP192R1_GX \
317 "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
318#define SECP192R1_GY \
319 "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"
320#define SECP192R1_N \
321 "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"
322
323/*
324 * Domain parameters for secp224r1
325 */
326#define SECP224R1_P \
327 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"
328#define SECP224R1_B \
329 "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"
330#define SECP224R1_GX \
331 "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
332#define SECP224R1_GY \
333 "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"
334#define SECP224R1_N \
335 "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"
336
337/*
338 * Domain parameters for secp256r1
339 */
340#define SECP256R1_P \
341 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
342#define SECP256R1_B \
343 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"
344#define SECP256R1_GX \
345 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
346#define SECP256R1_GY \
347 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
348#define SECP256R1_N \
349 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
350
351/*
352 * Domain parameters for secp384r1
353 */
354#define SECP384R1_P \
355 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
356 "FFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"
357#define SECP384R1_B \
358 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE814112" \
359 "0314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"
360#define SECP384R1_GX \
361 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B98" \
362 "59F741E082542A385502F25DBF55296C3A545E3872760AB7"
363#define SECP384R1_GY \
364 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147C" \
365 "E9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"
366#define SECP384R1_N \
367 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
368 "C7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"
369
370/*
371 * Domain parameters for secp521r1
372 */
373#define SECP521R1_P \
374 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
375 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
376 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
377#define SECP521R1_B \
378 "00000051953EB9618E1C9A1F929A21A0B68540EEA2DA725B" \
379 "99B315F3B8B489918EF109E156193951EC7E937B1652C0BD" \
380 "3BB1BF073573DF883D2C34F1EF451FD46B503F00"
381#define SECP521R1_GX \
382 "000000C6858E06B70404E9CD9E3ECB662395B4429C648139" \
383 "053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127" \
384 "A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
385#define SECP521R1_GY \
386 "0000011839296A789A3BC0045C8A5FB42C7D1BD998F54449" \
387 "579B446817AFBD17273E662C97EE72995EF42640C550B901" \
388 "3FAD0761353C7086A272C24088BE94769FD16650"
389#define SECP521R1_N \
390 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
391 "FFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148" \
392 "F709A5D03BB5C9B8899C47AEBB6FB71E91386409"
393
394/*
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100395 * Set a group using well-known domain parameters
396 */
397int ecp_use_known_dp( ecp_group *grp, size_t index )
398{
399 switch( index )
400 {
401 case POLARSSL_ECP_DP_SECP192R1:
Manuel Pégourié-Gonnard84338242012-11-11 20:45:18 +0100402 grp->modp = ecp_mod_p192;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100403 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100404 SECP192R1_P, SECP192R1_B,
405 SECP192R1_GX, SECP192R1_GY, SECP192R1_N ) );
406
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100407 case POLARSSL_ECP_DP_SECP224R1:
408 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100409 SECP224R1_P, SECP224R1_B,
410 SECP224R1_GX, SECP224R1_GY, SECP224R1_N ) );
411
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100412 case POLARSSL_ECP_DP_SECP256R1:
413 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100414 SECP256R1_P, SECP256R1_B,
415 SECP256R1_GX, SECP256R1_GY, SECP256R1_N ) );
416
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100417 case POLARSSL_ECP_DP_SECP384R1:
418 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100419 SECP384R1_P, SECP384R1_B,
420 SECP384R1_GX, SECP384R1_GY, SECP384R1_N ) );
421
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100422 case POLARSSL_ECP_DP_SECP521R1:
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100423 grp->modp = ecp_mod_p521;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100424 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100425 SECP521R1_P, SECP521R1_B,
426 SECP521R1_GX, SECP521R1_GY, SECP521R1_N ) );
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100427 }
428
429 return( POLARSSL_ERR_ECP_GENERIC );
430}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100431
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100432/*
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100433 * Fast mod-p functions expect their argument to be in the 0..p^2 range.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100434 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100435 * In order to guarantee that, we need to ensure that operands of
436 * mpi_mul_mpi are in the 0..p range. So, after each operation we will
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100437 * bring the result back to this range.
438 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100439 * The following macros are shortcuts for doing that.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100440 */
441
442/*
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100443 * Reduce a mpi mod p in-place, general case, to use after mpi_mul_mpi
444 */
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100445#define MOD_MUL( N ) MPI_CHK( ecp_modp( &N, grp ) )
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100446
447/*
448 * Reduce a mpi mod p in-place, to use after mpi_sub_mpi
449 */
450#define MOD_SUB( N ) \
451 while( mpi_cmp_int( &N, 0 ) < 0 ) \
452 MPI_CHK( mpi_add_mpi( &N, &N, &grp->P ) )
453
454/*
455 * Reduce a mpi mod p in-place, to use after mpi_add_mpi and mpi_mul_int
456 */
457#define MOD_ADD( N ) \
458 while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \
459 MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) )
460
461/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100462 * Internal point format used for fast (that is, without mpi_inv_mod)
463 * addition/doubling/multiplication: Jacobian coordinates (GECC ex 3.20)
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100464 */
465typedef struct
466{
467 mpi X, Y, Z;
468}
469ecp_ptjac;
470
471/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100472 * Initialize a point in Jacobian coordinates
473 */
474static void ecp_ptjac_init( ecp_ptjac *P )
475{
476 mpi_init( &P->X ); mpi_init( &P->Y ); mpi_init( &P->Z );
477}
478
479/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100480 * Free a point in Jacobian coordinates
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100481 */
482static void ecp_ptjac_free( ecp_ptjac *P )
483{
484 mpi_free( &P->X ); mpi_free( &P->Y ); mpi_free( &P->Z );
485}
486
487/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100488 * Copy P to R in Jacobian coordinates
489 */
490static int ecp_ptjac_copy( ecp_ptjac *R, const ecp_ptjac *P )
491{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100492 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100493
494 MPI_CHK( mpi_copy( &R->X, &P->X ) );
495 MPI_CHK( mpi_copy( &R->Y, &P->Y ) );
496 MPI_CHK( mpi_copy( &R->Z, &P->Z ) );
497
498cleanup:
499 return( ret );
500}
501
502/*
503 * Set P to zero in Jacobian coordinates
504 */
505static int ecp_ptjac_set_zero( ecp_ptjac *P )
506{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100507 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100508
509 MPI_CHK( mpi_lset( &P->X, 1 ) );
510 MPI_CHK( mpi_lset( &P->Y, 1 ) );
511 MPI_CHK( mpi_lset( &P->Z, 0 ) );
512
513cleanup:
514 return( ret );
515}
516
517/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100518 * Convert from affine to Jacobian coordinates
519 */
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100520static int ecp_aff_to_jac( ecp_ptjac *jac, const ecp_point *aff )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100521{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100522 int ret;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100523
524 if( aff->is_zero )
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100525 return( ecp_ptjac_set_zero( jac ) );
526
527 MPI_CHK( mpi_copy( &jac->X, &aff->X ) );
528 MPI_CHK( mpi_copy( &jac->Y, &aff->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100529 MPI_CHK( mpi_lset( &jac->Z, 1 ) );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100530
531cleanup:
532 return( ret );
533}
534
535/*
536 * Convert from Jacobian to affine coordinates
537 */
538static int ecp_jac_to_aff( const ecp_group *grp,
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100539 ecp_point *aff, const ecp_ptjac *jac )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100540{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100541 int ret;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100542 mpi Zi, ZZi, T;
543
544 if( mpi_cmp_int( &jac->Z, 0 ) == 0 ) {
545 ecp_set_zero( aff );
546 return( 0 );
547 }
548
549 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
550
551 aff->is_zero = 0;
552
553 /*
554 * aff.X = jac.X / (jac.Z)^2 mod p
555 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100556 MPI_CHK( mpi_inv_mod( &Zi, &jac->Z, &grp->P ) );
557 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
558 MPI_CHK( mpi_mul_mpi( &aff->X, &jac->X, &ZZi ) ); MOD_MUL( aff->X );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100559
560 /*
561 * aff.Y = jac.Y / (jac.Z)^3 mod p
562 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100563 MPI_CHK( mpi_mul_mpi( &aff->Y, &jac->Y, &ZZi ) ); MOD_MUL( aff->Y );
564 MPI_CHK( mpi_mul_mpi( &aff->Y, &aff->Y, &Zi ) ); MOD_MUL( aff->Y );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100565
566cleanup:
567
568 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
569
570 return( ret );
571}
572
573/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100574 * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21)
575 */
576static int ecp_double_jac( const ecp_group *grp, ecp_ptjac *R,
577 const ecp_ptjac *P )
578{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100579 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100580 mpi T1, T2, T3, X, Y, Z;
581
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100582 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
583 return( ecp_ptjac_set_zero( R ) );
584
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100585 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 );
586 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
587
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100588 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
589 MPI_CHK( mpi_sub_mpi( &T2, &P->X, &T1 ) ); MOD_SUB( T2 );
590 MPI_CHK( mpi_add_mpi( &T1, &P->X, &T1 ) ); MOD_ADD( T1 );
591 MPI_CHK( mpi_mul_mpi( &T2, &T2, &T1 ) ); MOD_MUL( T2 );
592 MPI_CHK( mpi_mul_int( &T2, &T2, 3 ) ); MOD_ADD( T2 );
593 MPI_CHK( mpi_mul_int( &Y, &P->Y, 2 ) ); MOD_ADD( Y );
594 MPI_CHK( mpi_mul_mpi( &Z, &Y, &P->Z ) ); MOD_MUL( Z );
595 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
596 MPI_CHK( mpi_mul_mpi( &T3, &Y, &P->X ) ); MOD_MUL( T3 );
597 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100598
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100599 /*
600 * For Y = Y / 2 mod p, we must make sure that Y is even before
601 * using right-shift. No need to reduce mod p afterwards.
602 */
603 if( mpi_get_bit( &Y, 0 ) == 1 )
604 MPI_CHK( mpi_add_mpi( &Y, &Y, &grp->P ) );
605 MPI_CHK( mpi_shift_r( &Y, 1 ) );
606
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100607 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
608 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
609 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
610 MPI_CHK( mpi_sub_mpi( &T1, &T3, &X ) ); MOD_SUB( T1 );
611 MPI_CHK( mpi_mul_mpi( &T1, &T1, &T2 ) ); MOD_MUL( T1 );
612 MPI_CHK( mpi_sub_mpi( &Y, &T1, &Y ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100613
614 MPI_CHK( mpi_copy( &R->X, &X ) );
615 MPI_CHK( mpi_copy( &R->Y, &Y ) );
616 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100617
618cleanup:
619
620 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 );
621 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
622
623 return( ret );
624}
625
626/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100627 * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100628 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100629static int ecp_add_mixed( const ecp_group *grp, ecp_ptjac *R,
630 const ecp_ptjac *P, const ecp_point *Q )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100631{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100632 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100633 mpi T1, T2, T3, T4, X, Y, Z;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100634
635 /*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100636 * Trivial cases: P == 0 or Q == 0
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100637 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100638 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
639 return( ecp_aff_to_jac( R, Q ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100640
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100641 if( Q->is_zero )
642 return( ecp_ptjac_copy( R, P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100643
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100644 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 ); mpi_init( &T4 );
645 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100646
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100647 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
648 MPI_CHK( mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
649 MPI_CHK( mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
650 MPI_CHK( mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
651 MPI_CHK( mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
652 MPI_CHK( mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100653
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100654 if( mpi_cmp_int( &T1, 0 ) == 0 )
655 {
656 if( mpi_cmp_int( &T2, 0 ) == 0 )
657 {
658 ret = ecp_double_jac( grp, R, P );
659 goto cleanup;
660 }
661 else
662 {
663 ret = ecp_ptjac_set_zero( R );
664 goto cleanup;
665 }
666 }
667
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100668 MPI_CHK( mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
669 MPI_CHK( mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
670 MPI_CHK( mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
671 MPI_CHK( mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
672 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
673 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
674 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
675 MPI_CHK( mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
676 MPI_CHK( mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
677 MPI_CHK( mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
678 MPI_CHK( mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
679 MPI_CHK( mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100680
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100681 MPI_CHK( mpi_copy( &R->X, &X ) );
682 MPI_CHK( mpi_copy( &R->Y, &Y ) );
683 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100684
685cleanup:
686
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100687 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 ); mpi_free( &T4 );
688 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100689
690 return( ret );
691}
692
693/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100694 * Addition: R = P + Q, affine wrapper
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100695 */
696int ecp_add( const ecp_group *grp, ecp_point *R,
697 const ecp_point *P, const ecp_point *Q )
698{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100699 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100700 ecp_ptjac J;
701
702 ecp_ptjac_init( &J );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100703
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100704 MPI_CHK( ecp_aff_to_jac( &J, P ) );
705 MPI_CHK( ecp_add_mixed( grp, &J, &J, Q ) );
706 MPI_CHK( ecp_jac_to_aff( grp, R, &J ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100707
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100708cleanup:
709
710 ecp_ptjac_free( &J );
711
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100712 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100713}
714
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100715/*
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100716 * Integer multiplication: R = m * P (GECC 5.7, SPA-resistant)
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100717 */
718int ecp_mul( const ecp_group *grp, ecp_point *R,
719 const mpi *m, const ecp_point *P )
720{
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100721 int ret, cmp;
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100722 size_t pos;
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100723 ecp_ptjac Q[2];
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100724
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100725 cmp = mpi_cmp_int( m, 0 );
726
727 if( cmp < 0 )
728 return( POLARSSL_ERR_ECP_GENERIC );
729
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100730 /*
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100731 * The general method works only for m != 0
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100732 */
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100733 if( cmp == 0 ) {
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100734 ecp_set_zero( R );
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100735 return( 0 );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100736 }
737
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100738 ecp_ptjac_init( &Q[0] ); ecp_ptjac_init( &Q[1] );
739
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100740 ecp_ptjac_set_zero( &Q[0] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100741
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100742 for( pos = mpi_msb( m ) - 1 ; ; pos-- )
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100743 {
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100744 MPI_CHK( ecp_double_jac( grp, &Q[0], &Q[0] ) );
745 MPI_CHK( ecp_add_mixed( grp, &Q[1], &Q[0], P ) );
746 MPI_CHK( ecp_ptjac_copy( &Q[0], &Q[ mpi_get_bit( m, pos ) ] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100747
748 if( pos == 0 )
749 break;
750 }
751
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100752 MPI_CHK( ecp_jac_to_aff( grp, R, &Q[0] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100753
754cleanup:
755
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100756 ecp_ptjac_free( &Q[0] ); ecp_ptjac_free( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100757
758 return( ret );
759}
760
761
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100762#if defined(POLARSSL_SELF_TEST)
763
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100764/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100765 * Checkup routine
766 */
767int ecp_self_test( int verbose )
768{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100769 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100770}
771
772#endif
773
774#endif