blob: 748cccb93e292801c5328e75de1f0f4c183405f7 [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
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010049 mpi_init( &pt->X );
50 mpi_init( &pt->Y );
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +010051 mpi_init( &pt->Z );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010052}
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
81 mpi_free( &( pt->X ) );
82 mpi_free( &( pt->Y ) );
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +010083 mpi_free( &( pt->Z ) );
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010084}
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 */
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100103int ecp_set_zero( ecp_point *pt )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100104{
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100105 int ret;
106
107 MPI_CHK( mpi_lset( &pt->X , 1 ) );
108 MPI_CHK( mpi_lset( &pt->Y , 1 ) );
109 MPI_CHK( mpi_lset( &pt->Z , 0 ) );
110
111cleanup:
112 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100113}
114
115/*
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100116 * Copy the contents of Q into P
117 */
118int ecp_copy( ecp_point *P, const ecp_point *Q )
119{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100120 int ret;
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100121
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100122 MPI_CHK( mpi_copy( &P->X, &Q->X ) );
123 MPI_CHK( mpi_copy( &P->Y, &Q->Y ) );
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100124 MPI_CHK( mpi_copy( &P->Z, &Q->Z ) );
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100125
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
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100138 MPI_CHK( mpi_read_string( &P->X, radix, x ) );
139 MPI_CHK( mpi_read_string( &P->Y, radix, y ) );
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100140 MPI_CHK( mpi_lset( &P->Z, 1 ) );
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100141
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é-Gonnard1c2782c2012-11-19 20:16:28 +0100462 * Normalize jacobian coordinates so that Z == 0 || Z == 1 (GECC 3.2.1)
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100463 */
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100464static int ecp_normalize( const ecp_group *grp, ecp_point *pt )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100465{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100466 int ret;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100467 mpi Zi, ZZi, T;
468
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100469 if( mpi_cmp_int( &pt->Z, 0 ) == 0 )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100470 return( 0 );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100471
472 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
473
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100474 /*
475 * X = X / Z^2 mod p
476 */
477 MPI_CHK( mpi_inv_mod( &Zi, &pt->Z, &grp->P ) );
478 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
479 MPI_CHK( mpi_mul_mpi( &pt->X, &pt->X, &ZZi ) ); MOD_MUL( pt->X );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100480
481 /*
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100482 * Y = Y / Z^3 mod p
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100483 */
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100484 MPI_CHK( mpi_mul_mpi( &pt->Y, &pt->Y, &ZZi ) ); MOD_MUL( pt->Y );
485 MPI_CHK( mpi_mul_mpi( &pt->Y, &pt->Y, &Zi ) ); MOD_MUL( pt->Y );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100486
487 /*
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100488 * Z = 1
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100489 */
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100490 MPI_CHK( mpi_lset( &pt->Z, 1 ) );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100491
492cleanup:
493
494 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
495
496 return( ret );
497}
498
499/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100500 * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21)
501 */
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100502static int ecp_double_jac( const ecp_group *grp, ecp_point *R,
503 const ecp_point *P )
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100504{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100505 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100506 mpi T1, T2, T3, X, Y, Z;
507
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100508 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100509 return( ecp_set_zero( R ) );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100510
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100511 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 );
512 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
513
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100514 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
515 MPI_CHK( mpi_sub_mpi( &T2, &P->X, &T1 ) ); MOD_SUB( T2 );
516 MPI_CHK( mpi_add_mpi( &T1, &P->X, &T1 ) ); MOD_ADD( T1 );
517 MPI_CHK( mpi_mul_mpi( &T2, &T2, &T1 ) ); MOD_MUL( T2 );
518 MPI_CHK( mpi_mul_int( &T2, &T2, 3 ) ); MOD_ADD( T2 );
519 MPI_CHK( mpi_mul_int( &Y, &P->Y, 2 ) ); MOD_ADD( Y );
520 MPI_CHK( mpi_mul_mpi( &Z, &Y, &P->Z ) ); MOD_MUL( Z );
521 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
522 MPI_CHK( mpi_mul_mpi( &T3, &Y, &P->X ) ); MOD_MUL( T3 );
523 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100524
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100525 /*
526 * For Y = Y / 2 mod p, we must make sure that Y is even before
527 * using right-shift. No need to reduce mod p afterwards.
528 */
529 if( mpi_get_bit( &Y, 0 ) == 1 )
530 MPI_CHK( mpi_add_mpi( &Y, &Y, &grp->P ) );
531 MPI_CHK( mpi_shift_r( &Y, 1 ) );
532
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100533 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
534 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
535 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
536 MPI_CHK( mpi_sub_mpi( &T1, &T3, &X ) ); MOD_SUB( T1 );
537 MPI_CHK( mpi_mul_mpi( &T1, &T1, &T2 ) ); MOD_MUL( T1 );
538 MPI_CHK( mpi_sub_mpi( &Y, &T1, &Y ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100539
540 MPI_CHK( mpi_copy( &R->X, &X ) );
541 MPI_CHK( mpi_copy( &R->Y, &Y ) );
542 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100543
544cleanup:
545
546 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 );
547 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
548
549 return( ret );
550}
551
552/*
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +0100553 * Addition or subtraction: R = P + Q or R = P + Q,
554 * mixed affine-Jacobian coordinates (GECC 3.22)
555 *
556 * The coordinates of Q must be normalized (= affine),
557 * but those of P don't need to. R is not normalized.
558 *
559 * If sign >= 0, perform addition, otherwise perform subtraction,
560 * taking advantage of the fact that, for Q != 0, we have
561 * -Q = (Q.X, -Q.Y, Q.Z)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100562 */
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100563static int ecp_add_mixed( const ecp_group *grp, ecp_point *R,
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +0100564 const ecp_point *P, const ecp_point *Q,
565 signed char sign )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100566{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100567 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100568 mpi T1, T2, T3, T4, X, Y, Z;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100569
570 /*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100571 * Trivial cases: P == 0 or Q == 0
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +0100572 * (Check Q first, so that we know Q != 0 when we compute -Q.)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100573 */
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100574 if( mpi_cmp_int( &Q->Z, 0 ) == 0 )
575 return( ecp_copy( R, P ) );
576
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +0100577 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
578 {
579 ret = ecp_copy( R, Q );
580
581 /*
582 * -R.Y mod P = P - R.Y unless R.Y == 0
583 */
584 if( ret == 0 && sign < 0)
585 if( mpi_cmp_int( &R->Y, 0 ) != 0 )
586 ret = mpi_sub_mpi( &R->Y, &grp->P, &R->Y );
587
588 return( ret );
589 }
590
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100591 /*
592 * Make sure Q coordinates are normalized
593 */
594 if( mpi_cmp_int( &Q->Z, 1 ) != 0 )
595 return( POLARSSL_ERR_ECP_GENERIC );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100596
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100597 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 ); mpi_init( &T4 );
598 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100599
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100600 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
601 MPI_CHK( mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
602 MPI_CHK( mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
603 MPI_CHK( mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +0100604
605 /*
606 * For subtraction, -Q.Y should have been used instead of Q.Y,
607 * so we replace T2 by -T2, which is P - T2 mod P
608 */
609 if( sign < 0 )
610 {
611 MPI_CHK( mpi_sub_mpi( &T2, &grp->P, &T2 ) );
612 MOD_SUB( T2 );
613 }
614
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100615 MPI_CHK( mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
616 MPI_CHK( mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100617
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100618 if( mpi_cmp_int( &T1, 0 ) == 0 )
619 {
620 if( mpi_cmp_int( &T2, 0 ) == 0 )
621 {
622 ret = ecp_double_jac( grp, R, P );
623 goto cleanup;
624 }
625 else
626 {
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100627 ret = ecp_set_zero( R );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100628 goto cleanup;
629 }
630 }
631
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100632 MPI_CHK( mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
633 MPI_CHK( mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
634 MPI_CHK( mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
635 MPI_CHK( mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
636 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
637 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
638 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
639 MPI_CHK( mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
640 MPI_CHK( mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
641 MPI_CHK( mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
642 MPI_CHK( mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
643 MPI_CHK( mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100644
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100645 MPI_CHK( mpi_copy( &R->X, &X ) );
646 MPI_CHK( mpi_copy( &R->Y, &Y ) );
647 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100648
649cleanup:
650
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100651 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 ); mpi_free( &T4 );
652 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100653
654 return( ret );
655}
656
657/*
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100658 * Addition: R = P + Q, result's coordinates normalized
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100659 */
660int ecp_add( const ecp_group *grp, ecp_point *R,
661 const ecp_point *P, const ecp_point *Q )
662{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100663 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100664
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +0100665 MPI_CHK( ecp_add_mixed( grp, R, P, Q , 1 ) );
666 MPI_CHK( ecp_normalize( grp, R ) );
667
668cleanup:
669 return( ret );
670}
671
672/*
673 * Subtraction: R = P - Q, result's coordinates normalized
674 */
675int ecp_sub( const ecp_group *grp, ecp_point *R,
676 const ecp_point *P, const ecp_point *Q )
677{
678 int ret;
679
680 MPI_CHK( ecp_add_mixed( grp, R, P, Q, -1 ) );
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100681 MPI_CHK( ecp_normalize( grp, R ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100682
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100683cleanup:
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100684 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100685}
686
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100687/*
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100688 * Integer multiplication: R = m * P (GECC 5.7, SPA-resistant)
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100689 */
690int ecp_mul( const ecp_group *grp, ecp_point *R,
691 const mpi *m, const ecp_point *P )
692{
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100693 int ret, cmp;
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100694 size_t pos;
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100695 ecp_point Q[2];
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100696
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100697 cmp = mpi_cmp_int( m, 0 );
698
699 if( cmp < 0 )
700 return( POLARSSL_ERR_ECP_GENERIC );
701
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100702 /*
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100703 * The general method works only for m != 0
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100704 */
Manuel Pégourié-Gonnard4bdd47d2012-11-11 14:33:59 +0100705 if( cmp == 0 ) {
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100706 return( ecp_set_zero( R ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100707 }
708
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100709 ecp_point_init( &Q[0] ); ecp_point_init( &Q[1] );
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100710
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100711 MPI_CHK( ecp_set_zero( &Q[0] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100712
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100713 for( pos = mpi_msb( m ) - 1 ; ; pos-- )
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100714 {
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100715 MPI_CHK( ecp_double_jac( grp, &Q[0], &Q[0] ) );
Manuel Pégourié-Gonnard9674fd02012-11-19 21:23:27 +0100716 MPI_CHK( ecp_add_mixed( grp, &Q[1], &Q[0], P, 1 ) );
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100717 MPI_CHK( ecp_copy( &Q[0], &Q[ mpi_get_bit( m, pos ) ] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100718
719 if( pos == 0 )
720 break;
721 }
722
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100723 MPI_CHK( ecp_copy( R, &Q[0] ) );
724 MPI_CHK( ecp_normalize( grp, R ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100725
726cleanup:
727
Manuel Pégourié-Gonnard1c2782c2012-11-19 20:16:28 +0100728 ecp_point_free( &Q[0] ); ecp_point_free( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100729
730 return( ret );
731}
732
733
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100734#if defined(POLARSSL_SELF_TEST)
735
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100736/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100737 * Checkup routine
738 */
739int ecp_self_test( int verbose )
740{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100741 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100742}
743
744#endif
745
746#endif