blob: 574b181dbd7764b8121645dd0be92177434ab4c8 [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é-Gonnard47123252012-11-10 14:44:24 +0100112 int ret;
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 );
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100116 return( 0 );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100117 }
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{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100133 int ret;
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100134
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{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100150 int ret;
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100151
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é-Gonnard47123252012-11-10 14:44:24 +0100162 * Wrapper around fast quasi-modp functions, with fall-back to mpi_mod_mpi
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100163 */
164static int ecp_modp( mpi *N, const ecp_group *grp )
165{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100166 int ret;
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100167
168 if( grp->modp == NULL )
169 return( mpi_mod_mpi( N, N, &grp->P ) );
170
171 if( mpi_cmp_int( N, 0 ) < 0 || mpi_msb( N ) > 2 * grp->pbits )
172 return( POLARSSL_ERR_ECP_GENERIC );
173
174 MPI_CHK( grp->modp( N ) );
175
176 while( mpi_cmp_int( N, 0 ) < 0 )
177 MPI_CHK( mpi_add_mpi( N, N, &grp->P ) );
178
179 while( mpi_cmp_mpi( N, &grp->P ) >= 0 )
180 MPI_CHK( mpi_sub_mpi( N, N, &grp->P ) );
181
182cleanup:
183 return( ret );
184}
185
186/*
187 * Size of p521 in terms of t_uint
188 */
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100189#define P521_SIZE_INT ( 521 / ( sizeof( t_uint ) << 3 ) + 1 )
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100190
191/*
192 * Bits to keep in the most significant t_uint
193 */
194#if defined(POLARSS_HAVE_INT8)
195#define P521_MASK 0x01
196#else
197#define P521_MASK 0x01FF
198#endif
199
200/*
201 * Fast quasi-reduction modulo p521 (FIPS 186-3 D.2.5)
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100202 */
203static int ecp_mod_p521( mpi *N )
204{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100205 int ret;
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100206 t_uint Mp[P521_SIZE_INT];
207 mpi M;
208
209 if( N->n < P521_SIZE_INT )
210 return( 0 );
211
212 memset( Mp, 0, P521_SIZE_INT * sizeof( t_uint ) );
213 memcpy( Mp, N->p, P521_SIZE_INT * sizeof( t_uint ) );
214 Mp[P521_SIZE_INT - 1] &= P521_MASK;
215
216 M.s = 1;
217 M.n = P521_SIZE_INT;
218 M.p = Mp;
219
220 MPI_CHK( mpi_shift_r( N, 521 ) );
221
222 MPI_CHK( mpi_add_abs( N, N, &M ) );
223
224cleanup:
225 return( ret );
226}
227
228/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100229 * Domain parameters for secp192r1
230 */
231#define SECP192R1_P \
232 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"
233#define SECP192R1_B \
234 "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"
235#define SECP192R1_GX \
236 "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
237#define SECP192R1_GY \
238 "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"
239#define SECP192R1_N \
240 "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"
241
242/*
243 * Domain parameters for secp224r1
244 */
245#define SECP224R1_P \
246 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"
247#define SECP224R1_B \
248 "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"
249#define SECP224R1_GX \
250 "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
251#define SECP224R1_GY \
252 "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"
253#define SECP224R1_N \
254 "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"
255
256/*
257 * Domain parameters for secp256r1
258 */
259#define SECP256R1_P \
260 "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
261#define SECP256R1_B \
262 "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"
263#define SECP256R1_GX \
264 "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
265#define SECP256R1_GY \
266 "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
267#define SECP256R1_N \
268 "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
269
270/*
271 * Domain parameters for secp384r1
272 */
273#define SECP384R1_P \
274 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
275 "FFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"
276#define SECP384R1_B \
277 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE814112" \
278 "0314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"
279#define SECP384R1_GX \
280 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B98" \
281 "59F741E082542A385502F25DBF55296C3A545E3872760AB7"
282#define SECP384R1_GY \
283 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147C" \
284 "E9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"
285#define SECP384R1_N \
286 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
287 "C7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"
288
289/*
290 * Domain parameters for secp521r1
291 */
292#define SECP521R1_P \
293 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
294 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
295 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"
296#define SECP521R1_B \
297 "00000051953EB9618E1C9A1F929A21A0B68540EEA2DA725B" \
298 "99B315F3B8B489918EF109E156193951EC7E937B1652C0BD" \
299 "3BB1BF073573DF883D2C34F1EF451FD46B503F00"
300#define SECP521R1_GX \
301 "000000C6858E06B70404E9CD9E3ECB662395B4429C648139" \
302 "053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127" \
303 "A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
304#define SECP521R1_GY \
305 "0000011839296A789A3BC0045C8A5FB42C7D1BD998F54449" \
306 "579B446817AFBD17273E662C97EE72995EF42640C550B901" \
307 "3FAD0761353C7086A272C24088BE94769FD16650"
308#define SECP521R1_N \
309 "000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \
310 "FFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148" \
311 "F709A5D03BB5C9B8899C47AEBB6FB71E91386409"
312
313/*
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100314 * Set a group using well-known domain parameters
315 */
316int ecp_use_known_dp( ecp_group *grp, size_t index )
317{
318 switch( index )
319 {
320 case POLARSSL_ECP_DP_SECP192R1:
321 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100322 SECP192R1_P, SECP192R1_B,
323 SECP192R1_GX, SECP192R1_GY, SECP192R1_N ) );
324
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100325 case POLARSSL_ECP_DP_SECP224R1:
326 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100327 SECP224R1_P, SECP224R1_B,
328 SECP224R1_GX, SECP224R1_GY, SECP224R1_N ) );
329
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100330 case POLARSSL_ECP_DP_SECP256R1:
331 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100332 SECP256R1_P, SECP256R1_B,
333 SECP256R1_GX, SECP256R1_GY, SECP256R1_N ) );
334
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100335 case POLARSSL_ECP_DP_SECP384R1:
336 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100337 SECP384R1_P, SECP384R1_B,
338 SECP384R1_GX, SECP384R1_GY, SECP384R1_N ) );
339
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100340 case POLARSSL_ECP_DP_SECP521R1:
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100341 grp->modp = ecp_mod_p521;
342 grp->pbits = 521;
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100343 return( ecp_group_read_string( grp, 16,
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100344 SECP521R1_P, SECP521R1_B,
345 SECP521R1_GX, SECP521R1_GY, SECP521R1_N ) );
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100346 }
347
348 return( POLARSSL_ERR_ECP_GENERIC );
349}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100350
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100351/*
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100352 * Fast mod-p functions expect their argument to be in the 0..p^2 range.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100353 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100354 * In order to guarantee that, we need to ensure that operands of
355 * mpi_mul_mpi are in the 0..p range. So, after each operation we will
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100356 * bring the result back to this range.
357 *
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100358 * The following macros are shortcuts for doing that.
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100359 */
360
361/*
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100362 * Reduce a mpi mod p in-place, general case, to use after mpi_mul_mpi
363 */
Manuel Pégourié-Gonnard62aad142012-11-10 00:27:12 +0100364#define MOD_MUL( N ) MPI_CHK( ecp_modp( &N, grp ) )
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100365
366/*
367 * Reduce a mpi mod p in-place, to use after mpi_sub_mpi
368 */
369#define MOD_SUB( N ) \
370 while( mpi_cmp_int( &N, 0 ) < 0 ) \
371 MPI_CHK( mpi_add_mpi( &N, &N, &grp->P ) )
372
373/*
374 * Reduce a mpi mod p in-place, to use after mpi_add_mpi and mpi_mul_int
375 */
376#define MOD_ADD( N ) \
377 while( mpi_cmp_mpi( &N, &grp->P ) >= 0 ) \
378 MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) )
379
380/*
Manuel Pégourié-Gonnarddada4da2012-11-10 14:23:17 +0100381 * Internal point format used for fast (that is, without mpi_inv_mod)
382 * addition/doubling/multiplication: Jacobian coordinates (GECC ex 3.20)
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100383 */
384typedef struct
385{
386 mpi X, Y, Z;
387}
388ecp_ptjac;
389
390/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100391 * Initialize a point in Jacobian coordinates
392 */
393static void ecp_ptjac_init( ecp_ptjac *P )
394{
395 mpi_init( &P->X ); mpi_init( &P->Y ); mpi_init( &P->Z );
396}
397
398/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100399 * Free a point in Jacobian coordinates
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100400 */
401static void ecp_ptjac_free( ecp_ptjac *P )
402{
403 mpi_free( &P->X ); mpi_free( &P->Y ); mpi_free( &P->Z );
404}
405
406/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100407 * Copy P to R in Jacobian coordinates
408 */
409static int ecp_ptjac_copy( ecp_ptjac *R, const ecp_ptjac *P )
410{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100411 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100412
413 MPI_CHK( mpi_copy( &R->X, &P->X ) );
414 MPI_CHK( mpi_copy( &R->Y, &P->Y ) );
415 MPI_CHK( mpi_copy( &R->Z, &P->Z ) );
416
417cleanup:
418 return( ret );
419}
420
421/*
422 * Set P to zero in Jacobian coordinates
423 */
424static int ecp_ptjac_set_zero( ecp_ptjac *P )
425{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100426 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100427
428 MPI_CHK( mpi_lset( &P->X, 1 ) );
429 MPI_CHK( mpi_lset( &P->Y, 1 ) );
430 MPI_CHK( mpi_lset( &P->Z, 0 ) );
431
432cleanup:
433 return( ret );
434}
435
436/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100437 * Convert from affine to Jacobian coordinates
438 */
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100439static int ecp_aff_to_jac( ecp_ptjac *jac, const ecp_point *aff )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100440{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100441 int ret;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100442
443 if( aff->is_zero )
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100444 return( ecp_ptjac_set_zero( jac ) );
445
446 MPI_CHK( mpi_copy( &jac->X, &aff->X ) );
447 MPI_CHK( mpi_copy( &jac->Y, &aff->Y ) );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100448 MPI_CHK( mpi_lset( &jac->Z, 1 ) );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100449
450cleanup:
451 return( ret );
452}
453
454/*
455 * Convert from Jacobian to affine coordinates
456 */
457static int ecp_jac_to_aff( const ecp_group *grp,
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100458 ecp_point *aff, const ecp_ptjac *jac )
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100459{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100460 int ret;
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100461 mpi Zi, ZZi, T;
462
463 if( mpi_cmp_int( &jac->Z, 0 ) == 0 ) {
464 ecp_set_zero( aff );
465 return( 0 );
466 }
467
468 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
469
470 aff->is_zero = 0;
471
472 /*
473 * aff.X = jac.X / (jac.Z)^2 mod p
474 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100475 MPI_CHK( mpi_inv_mod( &Zi, &jac->Z, &grp->P ) );
476 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) ); MOD_MUL( ZZi );
477 MPI_CHK( mpi_mul_mpi( &aff->X, &jac->X, &ZZi ) ); MOD_MUL( aff->X );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100478
479 /*
480 * aff.Y = jac.Y / (jac.Z)^3 mod p
481 */
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100482 MPI_CHK( mpi_mul_mpi( &aff->Y, &jac->Y, &ZZi ) ); MOD_MUL( aff->Y );
483 MPI_CHK( mpi_mul_mpi( &aff->Y, &aff->Y, &Zi ) ); MOD_MUL( aff->Y );
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100484
485cleanup:
486
487 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
488
489 return( ret );
490}
491
492/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100493 * Point doubling R = 2 P, Jacobian coordinates (GECC 3.21)
494 */
495static int ecp_double_jac( const ecp_group *grp, ecp_ptjac *R,
496 const ecp_ptjac *P )
497{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100498 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100499 mpi T1, T2, T3, X, Y, Z;
500
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100501 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
502 return( ecp_ptjac_set_zero( R ) );
503
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100504 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 );
505 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
506
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100507 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
508 MPI_CHK( mpi_sub_mpi( &T2, &P->X, &T1 ) ); MOD_SUB( T2 );
509 MPI_CHK( mpi_add_mpi( &T1, &P->X, &T1 ) ); MOD_ADD( T1 );
510 MPI_CHK( mpi_mul_mpi( &T2, &T2, &T1 ) ); MOD_MUL( T2 );
511 MPI_CHK( mpi_mul_int( &T2, &T2, 3 ) ); MOD_ADD( T2 );
512 MPI_CHK( mpi_mul_int( &Y, &P->Y, 2 ) ); MOD_ADD( Y );
513 MPI_CHK( mpi_mul_mpi( &Z, &Y, &P->Z ) ); MOD_MUL( Z );
514 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
515 MPI_CHK( mpi_mul_mpi( &T3, &Y, &P->X ) ); MOD_MUL( T3 );
516 MPI_CHK( mpi_mul_mpi( &Y, &Y, &Y ) ); MOD_MUL( Y );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100517
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100518 /*
519 * For Y = Y / 2 mod p, we must make sure that Y is even before
520 * using right-shift. No need to reduce mod p afterwards.
521 */
522 if( mpi_get_bit( &Y, 0 ) == 1 )
523 MPI_CHK( mpi_add_mpi( &Y, &Y, &grp->P ) );
524 MPI_CHK( mpi_shift_r( &Y, 1 ) );
525
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100526 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
527 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
528 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
529 MPI_CHK( mpi_sub_mpi( &T1, &T3, &X ) ); MOD_SUB( T1 );
530 MPI_CHK( mpi_mul_mpi( &T1, &T1, &T2 ) ); MOD_MUL( T1 );
531 MPI_CHK( mpi_sub_mpi( &Y, &T1, &Y ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100532
533 MPI_CHK( mpi_copy( &R->X, &X ) );
534 MPI_CHK( mpi_copy( &R->Y, &Y ) );
535 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100536
537cleanup:
538
539 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 );
540 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
541
542 return( ret );
543}
544
545/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100546 * Addition: R = P + Q, mixed affine-Jacobian coordinates (GECC 3.22)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100547 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100548static int ecp_add_mixed( const ecp_group *grp, ecp_ptjac *R,
549 const ecp_ptjac *P, const ecp_point *Q )
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100550{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100551 int ret;
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100552 mpi T1, T2, T3, T4, X, Y, Z;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100553
554 /*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100555 * Trivial cases: P == 0 or Q == 0
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100556 */
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100557 if( mpi_cmp_int( &P->Z, 0 ) == 0 )
558 return( ecp_aff_to_jac( R, Q ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100559
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100560 if( Q->is_zero )
561 return( ecp_ptjac_copy( R, P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100562
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100563 mpi_init( &T1 ); mpi_init( &T2 ); mpi_init( &T3 ); mpi_init( &T4 );
564 mpi_init( &X ); mpi_init( &Y ); mpi_init( &Z );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100565
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100566 MPI_CHK( mpi_mul_mpi( &T1, &P->Z, &P->Z ) ); MOD_MUL( T1 );
567 MPI_CHK( mpi_mul_mpi( &T2, &T1, &P->Z ) ); MOD_MUL( T2 );
568 MPI_CHK( mpi_mul_mpi( &T1, &T1, &Q->X ) ); MOD_MUL( T1 );
569 MPI_CHK( mpi_mul_mpi( &T2, &T2, &Q->Y ) ); MOD_MUL( T2 );
570 MPI_CHK( mpi_sub_mpi( &T1, &T1, &P->X ) ); MOD_SUB( T1 );
571 MPI_CHK( mpi_sub_mpi( &T2, &T2, &P->Y ) ); MOD_SUB( T2 );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100572
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100573 if( mpi_cmp_int( &T1, 0 ) == 0 )
574 {
575 if( mpi_cmp_int( &T2, 0 ) == 0 )
576 {
577 ret = ecp_double_jac( grp, R, P );
578 goto cleanup;
579 }
580 else
581 {
582 ret = ecp_ptjac_set_zero( R );
583 goto cleanup;
584 }
585 }
586
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100587 MPI_CHK( mpi_mul_mpi( &Z, &P->Z, &T1 ) ); MOD_MUL( Z );
588 MPI_CHK( mpi_mul_mpi( &T3, &T1, &T1 ) ); MOD_MUL( T3 );
589 MPI_CHK( mpi_mul_mpi( &T4, &T3, &T1 ) ); MOD_MUL( T4 );
590 MPI_CHK( mpi_mul_mpi( &T3, &T3, &P->X ) ); MOD_MUL( T3 );
591 MPI_CHK( mpi_mul_int( &T1, &T3, 2 ) ); MOD_ADD( T1 );
592 MPI_CHK( mpi_mul_mpi( &X, &T2, &T2 ) ); MOD_MUL( X );
593 MPI_CHK( mpi_sub_mpi( &X, &X, &T1 ) ); MOD_SUB( X );
594 MPI_CHK( mpi_sub_mpi( &X, &X, &T4 ) ); MOD_SUB( X );
595 MPI_CHK( mpi_sub_mpi( &T3, &T3, &X ) ); MOD_SUB( T3 );
596 MPI_CHK( mpi_mul_mpi( &T3, &T3, &T2 ) ); MOD_MUL( T3 );
597 MPI_CHK( mpi_mul_mpi( &T4, &T4, &P->Y ) ); MOD_MUL( T4 );
598 MPI_CHK( mpi_sub_mpi( &Y, &T3, &T4 ) ); MOD_SUB( Y );
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100599
Manuel Pégourié-Gonnard84d1aea2012-11-09 02:09:38 +0100600 MPI_CHK( mpi_copy( &R->X, &X ) );
601 MPI_CHK( mpi_copy( &R->Y, &Y ) );
602 MPI_CHK( mpi_copy( &R->Z, &Z ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100603
604cleanup:
605
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100606 mpi_free( &T1 ); mpi_free( &T2 ); mpi_free( &T3 ); mpi_free( &T4 );
607 mpi_free( &X ); mpi_free( &Y ); mpi_free( &Z );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100608
609 return( ret );
610}
611
612/*
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100613 * Addition: R = P + Q, affine wrapper
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100614 */
615int ecp_add( const ecp_group *grp, ecp_point *R,
616 const ecp_point *P, const ecp_point *Q )
617{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100618 int ret;
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100619 ecp_ptjac J;
620
621 ecp_ptjac_init( &J );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100622
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100623 MPI_CHK( ecp_aff_to_jac( &J, P ) );
624 MPI_CHK( ecp_add_mixed( grp, &J, &J, Q ) );
625 MPI_CHK( ecp_jac_to_aff( grp, R, &J ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100626
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100627cleanup:
628
629 ecp_ptjac_free( &J );
630
Manuel Pégourié-Gonnard7e0adfb2012-11-08 23:21:46 +0100631 return( ret );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100632}
633
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100634/*
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100635 * Integer multiplication: R = m * P (GECC 5.7, SPA-resistant variant)
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100636 */
637int ecp_mul( const ecp_group *grp, ecp_point *R,
638 const mpi *m, const ecp_point *P )
639{
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100640 int ret;
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100641 size_t pos;
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100642 ecp_ptjac Q[2];
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100643
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100644 /*
Manuel Pégourié-Gonnard27b1ba82012-11-08 18:24:10 +0100645 * The general method works only for m >= 1
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100646 */
647 if( mpi_cmp_int( m, 0 ) == 0 ) {
648 ecp_set_zero( R );
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100649 return( 0 );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100650 }
651
Manuel Pégourié-Gonnard47123252012-11-10 14:44:24 +0100652 ecp_ptjac_init( &Q[0] ); ecp_ptjac_init( &Q[1] );
653
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100654 ecp_ptjac_set_zero( &Q[0] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100655
Manuel Pégourié-Gonnard989c32b2012-11-08 22:02:42 +0100656 for( pos = mpi_msb( m ) - 1 ; ; pos-- )
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100657 {
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100658 MPI_CHK( ecp_double_jac( grp, &Q[0], &Q[0] ) );
659 MPI_CHK( ecp_add_mixed( grp, &Q[1], &Q[0], P ) );
660 MPI_CHK( ecp_ptjac_copy( &Q[0], &Q[ mpi_get_bit( m, pos ) ] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100661
662 if( pos == 0 )
663 break;
664 }
665
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100666 MPI_CHK( ecp_jac_to_aff( grp, R, &Q[0] ) );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100667
668cleanup:
669
Manuel Pégourié-Gonnarde0c16922012-11-08 23:27:28 +0100670 ecp_ptjac_free( &Q[0] ); ecp_ptjac_free( &Q[1] );
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100671
672 return( ret );
673}
674
675
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100676#if defined(POLARSSL_SELF_TEST)
677
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100678/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100679 * Checkup routine
680 */
681int ecp_self_test( int verbose )
682{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100683 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100684}
685
686#endif
687
688#endif