blob: 6812718a55d52276010d2584fd8f3a2ecbc380f0 [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é-Gonnard39d2adb2012-10-31 09:26:55 +010031 */
32
33#include "polarssl/config.h"
34
35#if defined(POLARSSL_ECP_C)
36
37#include "polarssl/ecp.h"
38
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010039/*
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010040 * Initialize (the components of) a point
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010041 */
42void ecp_point_init( ecp_point *pt )
43{
44 if( pt == NULL )
45 return;
46
47 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010048 mpi_init( &pt->X );
49 mpi_init( &pt->Y );
50}
51
52/*
53 * Initialize (the components of) a group
54 */
55void ecp_group_init( ecp_group *grp )
56{
57 if( grp == NULL )
58 return;
59
60 mpi_init( &grp->P );
61 mpi_init( &grp->B );
62 ecp_point_init( &grp->G );
63 mpi_init( &grp->N );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010064}
65
66/*
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010067 * Unallocate (the components of) a point
68 */
69void ecp_point_free( ecp_point *pt )
70{
71 if( pt == NULL )
72 return;
73
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +010074 pt->is_zero = 1;
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010075 mpi_free( &( pt->X ) );
76 mpi_free( &( pt->Y ) );
77}
78
79/*
80 * Unallocate (the components of) a group
81 */
82void ecp_group_free( ecp_group *grp )
83{
84 if( grp == NULL )
85 return;
86
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010087 mpi_free( &grp->P );
88 mpi_free( &grp->B );
89 ecp_point_free( &grp->G );
90 mpi_free( &grp->N );
Manuel Pégourié-Gonnard1e8c8ec2012-10-31 19:24:21 +010091}
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +010092
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +010093/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +010094 * Set point to zero
95 */
96void ecp_set_zero( ecp_point *pt )
97{
98 pt->is_zero = 1;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +010099 mpi_free( &pt->X );
100 mpi_free( &pt->Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100101}
102
103/*
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100104 * Copy the contents of Q into P
105 */
106int ecp_copy( ecp_point *P, const ecp_point *Q )
107{
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100108 int ret = 0;
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100109
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100110 if( Q->is_zero ) {
111 ecp_set_zero( P );
112 return( ret );
113 }
114
Manuel Pégourié-Gonnard883f3132012-11-02 09:40:25 +0100115 P->is_zero = Q->is_zero;
116 MPI_CHK( mpi_copy( &P->X, &Q->X ) );
117 MPI_CHK( mpi_copy( &P->Y, &Q->Y ) );
118
119cleanup:
120 return( ret );
121}
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +0100122
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100123/*
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100124 * Import a non-zero point from ASCII strings
125 */
126int ecp_point_read_string( ecp_point *P, int radix,
127 const char *x, const char *y )
128{
129 int ret = 0;
130
131 P->is_zero = 0;
132 MPI_CHK( mpi_read_string( &P->X, radix, x ) );
133 MPI_CHK( mpi_read_string( &P->Y, radix, y ) );
134
135cleanup:
136 return( ret );
137}
138
139/*
140 * Import an ECP group from ASCII strings
141 */
142int ecp_group_read_string( ecp_group *grp, int radix,
143 const char *p, const char *b,
144 const char *gx, const char *gy, const char *n)
145{
146 int ret = 0;
147
148 MPI_CHK( mpi_read_string( &grp->P, radix, p ) );
149 MPI_CHK( mpi_read_string( &grp->B, radix, b ) );
150 MPI_CHK( ecp_point_read_string( &grp->G, radix, gx, gy ) );
151 MPI_CHK( mpi_read_string( &grp->N, radix, n ) );
152
153cleanup:
154 return( ret );
155}
156
Manuel Pégourié-Gonnarda5402fe2012-11-07 20:24:05 +0100157/*
158 * Set a group using well-known domain parameters
159 */
160int ecp_use_known_dp( ecp_group *grp, size_t index )
161{
162 switch( index )
163 {
164 case POLARSSL_ECP_DP_SECP192R1:
165 return( ecp_group_read_string( grp, 16,
166 POLARSSL_ECP_SECP192R1_P,
167 POLARSSL_ECP_SECP192R1_B,
168 POLARSSL_ECP_SECP192R1_GX,
169 POLARSSL_ECP_SECP192R1_GY,
170 POLARSSL_ECP_SECP192R1_N )
171 );
172 case POLARSSL_ECP_DP_SECP224R1:
173 return( ecp_group_read_string( grp, 16,
174 POLARSSL_ECP_SECP224R1_P,
175 POLARSSL_ECP_SECP224R1_B,
176 POLARSSL_ECP_SECP224R1_GX,
177 POLARSSL_ECP_SECP224R1_GY,
178 POLARSSL_ECP_SECP224R1_N )
179 );
180 case POLARSSL_ECP_DP_SECP256R1:
181 return( ecp_group_read_string( grp, 16,
182 POLARSSL_ECP_SECP256R1_P,
183 POLARSSL_ECP_SECP256R1_B,
184 POLARSSL_ECP_SECP256R1_GX,
185 POLARSSL_ECP_SECP256R1_GY,
186 POLARSSL_ECP_SECP256R1_N )
187 );
188 case POLARSSL_ECP_DP_SECP384R1:
189 return( ecp_group_read_string( grp, 16,
190 POLARSSL_ECP_SECP384R1_P,
191 POLARSSL_ECP_SECP384R1_B,
192 POLARSSL_ECP_SECP384R1_GX,
193 POLARSSL_ECP_SECP384R1_GY,
194 POLARSSL_ECP_SECP384R1_N )
195 );
196 case POLARSSL_ECP_DP_SECP521R1:
197 return( ecp_group_read_string( grp, 16,
198 POLARSSL_ECP_SECP521R1_P,
199 POLARSSL_ECP_SECP521R1_B,
200 POLARSSL_ECP_SECP521R1_GX,
201 POLARSSL_ECP_SECP521R1_GY,
202 POLARSSL_ECP_SECP521R1_N )
203 );
204 }
205
206 return( POLARSSL_ERR_ECP_GENERIC );
207}
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100208
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100209/*
Manuel Pégourié-Gonnardd070f512012-11-08 17:40:51 +0100210 * Internal point format used for fast addition/doubling/multiplication:
211 * Jacobian coordinates (GECC example 3.20)
212 */
213typedef struct
214{
215 mpi X, Y, Z;
216}
217ecp_ptjac;
218
219/*
220 * Convert from affine to Jacobian coordinates
221 */
222static int ecp_aff_to_jac( ecp_ptjac *jac, ecp_point *aff )
223{
224 int ret = 0;
225
226 if( aff->is_zero )
227 {
228 MPI_CHK( mpi_lset( &jac->X, 1 ) );
229 MPI_CHK( mpi_lset( &jac->Y, 1 ) );
230 MPI_CHK( mpi_lset( &jac->Z, 0 ) );
231 }
232 else
233 {
234 MPI_CHK( mpi_copy( &jac->X, &aff->X ) );
235 MPI_CHK( mpi_copy( &jac->Y, &aff->Y ) );
236 MPI_CHK( mpi_lset( &jac->Z, 1 ) );
237 }
238
239cleanup:
240 return( ret );
241}
242
243/*
244 * Convert from Jacobian to affine coordinates
245 */
246static int ecp_jac_to_aff( const ecp_group *grp,
247 ecp_point *aff, ecp_ptjac *jac )
248{
249 int ret = 0;
250 mpi Zi, ZZi, T;
251
252 if( mpi_cmp_int( &jac->Z, 0 ) == 0 ) {
253 ecp_set_zero( aff );
254 return( 0 );
255 }
256
257 mpi_init( &Zi ); mpi_init( &ZZi ); mpi_init( &T );
258
259 aff->is_zero = 0;
260
261 /*
262 * aff.X = jac.X / (jac.Z)^2 mod p
263 */
264 MPI_CHK( mpi_inv_mod( &Zi, &jac->Z, &grp->P ) );
265 MPI_CHK( mpi_mul_mpi( &ZZi, &Zi, &Zi ) );
266 MPI_CHK( mpi_mul_mpi( &T, &jac->X, &ZZi ) );
267 MPI_CHK( mpi_mod_mpi( &aff->X, &T, &grp->P ) );
268
269 /*
270 * aff.Y = jac.Y / (jac.Z)^3 mod p
271 */
272 MPI_CHK( mpi_mul_mpi( &T, &jac->Y, &ZZi ) );
273 MPI_CHK( mpi_mul_mpi( &T, &T, &Zi ) );
274 MPI_CHK( mpi_mod_mpi( &aff->Y, &T, &grp->P ) );
275
276cleanup:
277
278 mpi_free( &Zi ); mpi_free( &ZZi ); mpi_free( &T );
279
280 return( ret );
281}
282
283/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100284 * Addition: R = P + Q, generic case (P != Q, P != 0, Q != 0, R != 0)
285 * Cf SEC1 v2 p. 7, item 4
286 */
287static int ecp_add_generic( const ecp_group *grp, ecp_point *R,
288 const ecp_point *P, const ecp_point *Q )
289{
290 int ret = 0;
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100291 mpi DX, DY, K, L, LL, X, Y;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100292
293 mpi_init( &DX ); mpi_init( &DY ); mpi_init( &K ); mpi_init( &L );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100294 mpi_init( &LL ); mpi_init( &X ); mpi_init( &Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100295
296 /*
297 * L = (Q.Y - P.Y) / (Q.X - P.X) mod p
298 */
299 MPI_CHK( mpi_sub_mpi( &DY, &Q->Y, &P->Y ) );
300 MPI_CHK( mpi_sub_mpi( &DX, &Q->X, &P->X ) );
301 MPI_CHK( mpi_inv_mod( &K, &DX, &grp->P ) );
302 MPI_CHK( mpi_mul_mpi( &K, &K, &DY ) );
303 MPI_CHK( mpi_mod_mpi( &L, &K, &grp->P ) );
304
305 /*
306 * LL = L^2 mod p
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100307 */
308 MPI_CHK( mpi_mul_mpi( &LL, &L, &L ) );
309 MPI_CHK( mpi_mod_mpi( &LL, &LL, &grp->P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100310
311 /*
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100312 * X = L^2 - P.X - Q.X
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100313 */
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100314 MPI_CHK( mpi_sub_mpi( &X, &LL, &P->X ) );
315 MPI_CHK( mpi_sub_mpi( &X, &X, &Q->X ) );
316
317 /*
318 * Y = L * (P.X - X) - P.Y
319 */
320 MPI_CHK( mpi_sub_mpi( &Y, &P->X, &X) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100321 MPI_CHK( mpi_mul_mpi( &Y, &Y, &L ) );
322 MPI_CHK( mpi_sub_mpi( &Y, &Y, &P->Y ) );
323
324 /*
325 * R = (X mod p, Y mod p)
326 */
327 R->is_zero = 0;
328 MPI_CHK( mpi_mod_mpi( &R->X, &X, &grp->P ) );
329 MPI_CHK( mpi_mod_mpi( &R->Y, &Y, &grp->P ) );
330
331cleanup:
332
333 mpi_free( &DX ); mpi_free( &DY ); mpi_free( &K ); mpi_free( &L );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100334 mpi_free( &LL ); mpi_free( &X ); mpi_free( &Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100335
336 return( ret );
337}
338
339/*
340 * Doubling: R = 2 * P, generic case (P != 0, R != 0)
Manuel Pégourié-Gonnardde532ee2012-11-06 16:10:47 +0100341 * Cf SEC1 v2 p. 7, item 5
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100342 */
343static int ecp_double_generic( const ecp_group *grp, ecp_point *R,
344 const ecp_point *P )
345{
346 int ret = 0;
Manuel Pégourié-Gonnardde532ee2012-11-06 16:10:47 +0100347 mpi LN, LD, K, L, LL, X, Y;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100348
Manuel Pégourié-Gonnardde532ee2012-11-06 16:10:47 +0100349 mpi_init( &LN ); mpi_init( &LD ); mpi_init( &K ); mpi_init( &L );
350 mpi_init( &LL ); mpi_init( &X ); mpi_init( &Y );
351
352 /*
353 * L = 3 (P.X - 1) (P.X + 1) / (2 P.Y) mod p
354 */
355 MPI_CHK( mpi_copy( &LD, &P->Y ) );
356 MPI_CHK( mpi_shift_l( &LD, 1 ) );
357 MPI_CHK( mpi_inv_mod( &K, &LD, &grp->P ) );
358 MPI_CHK( mpi_mul_int( &K, &K, 3 ) );
359 MPI_CHK( mpi_sub_int( &LN, &P->X, 1 ) );
360 MPI_CHK( mpi_mul_mpi( &K, &K, &LN ) );
361 MPI_CHK( mpi_add_int( &LN, &P->X, 1 ) );
362 MPI_CHK( mpi_mul_mpi( &K, &K, &LN ) );
363 MPI_CHK( mpi_mod_mpi( &L, &K, &grp->P ) );
364
365 /*
366 * LL = L^2 mod p
367 */
368 MPI_CHK( mpi_mul_mpi( &LL, &L, &L ) );
369 MPI_CHK( mpi_mod_mpi( &LL, &LL, &grp->P ) );
370
371 /*
372 * X = L^2 - 2 * P.X
373 */
374 MPI_CHK( mpi_sub_mpi( &X, &LL, &P->X ) );
375 MPI_CHK( mpi_sub_mpi( &X, &X, &P->X ) );
376
377 /*
378 * Y = L * (P.X - X) - P.Y
379 */
380 MPI_CHK( mpi_sub_mpi( &Y, &P->X, &X) );
381 MPI_CHK( mpi_mul_mpi( &Y, &Y, &L ) );
382 MPI_CHK( mpi_sub_mpi( &Y, &Y, &P->Y ) );
383
384 /*
385 * R = (X mod p, Y mod p)
386 */
387 R->is_zero = 0;
388 MPI_CHK( mpi_mod_mpi( &R->X, &X, &grp->P ) );
389 MPI_CHK( mpi_mod_mpi( &R->Y, &Y, &grp->P ) );
390
391cleanup:
392
Manuel Pégourié-Gonnardb4ab8a82012-11-06 18:13:32 +0100393 mpi_free( &LN ); mpi_free( &LD ); mpi_free( &K ); mpi_free( &L );
394 mpi_free( &LL ); mpi_free( &X ); mpi_free( &Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100395
396 return( ret );
397}
398
399/*
400 * Addition: R = P + Q, cf p. 7 of SEC1 v2
401 */
402int ecp_add( const ecp_group *grp, ecp_point *R,
403 const ecp_point *P, const ecp_point *Q )
404{
405 int ret = 0;
406
407 if( P->is_zero )
408 {
409 ret = ecp_copy( R, Q );
410 }
411 else if( Q->is_zero )
412 {
413 ret = ecp_copy( R, P );
414 }
415 else if( mpi_cmp_mpi( &P->X, &Q->X ) != 0 )
416 {
417 ret = ecp_add_generic( grp, R, P, Q );
418 }
419 else if( mpi_cmp_int( &P->Y, 0 ) == 0 ||
420 mpi_cmp_mpi( &P->Y, &Q->Y ) != 0 )
421 {
422 ecp_set_zero( R );
423 }
424 else
425 {
426 /*
427 * P == Q
428 */
429 ret = ecp_double_generic( grp, R, P );
430 }
431
432 return ret;
433}
434
Manuel Pégourié-Gonnardefaa31e2012-11-06 21:34:35 +0100435/*
436 * Integer multiplication: R = m * P
437 * Using Montgomery's Ladder to avoid leaking information about m
438 */
439int ecp_mul( const ecp_group *grp, ecp_point *R,
440 const mpi *m, const ecp_point *P )
441{
442 int ret = 0;
443 size_t pos;
444 ecp_point A, B;
445
446 ecp_point_init( &A ); ecp_point_init( &B );
447
448 /*
449 * The general method works only for m >= 2
450 */
451 if( mpi_cmp_int( m, 0 ) == 0 ) {
452 ecp_set_zero( R );
453 goto cleanup;
454 }
455
456 if( mpi_cmp_int( m, 1 ) == 0 ) {
457 MPI_CHK( ecp_copy( R, P ) );
458 goto cleanup;
459 }
460
461 MPI_CHK( ecp_copy( &A, P ) );
462 MPI_CHK( ecp_add( grp, &B, P, P ) );
463
464 for( pos = mpi_msb( m ) - 2; ; pos-- )
465 {
466 if( mpi_get_bit( m, pos ) == 0 )
467 {
468 MPI_CHK( ecp_add( grp, &B, &A, &B ) );
469 MPI_CHK( ecp_add( grp, &A, &A, &A ) ) ;
470 }
471 else
472 {
473 MPI_CHK( ecp_add( grp, &A, &A, &B ) );
474 MPI_CHK( ecp_add( grp, &B, &B, &B ) ) ;
475 }
476
477 if( pos == 0 )
478 break;
479 }
480
481 MPI_CHK( ecp_copy( R, &A ) );
482
483cleanup:
484
485 ecp_point_free( &A ); ecp_point_free( &B );
486
487 return( ret );
488}
489
490
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100491#if defined(POLARSSL_SELF_TEST)
492
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100493/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100494 * Checkup routine
495 */
496int ecp_self_test( int verbose )
497{
Manuel Pégourié-Gonnard4b8c3f22012-11-07 21:39:45 +0100498 return( verbose++ );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100499}
500
501#endif
502
503#endif