blob: 99d57cd4c834946cfca117285c80d946e62aa58e [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é-Gonnard39d2adb2012-10-31 09:26:55 +010030 * Guide to Elliptic Curve Cryptography - Hankerson, Menezes, Vanstone
31 */
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é-Gonnardab38b702012-11-05 17:34:55 +0100157#define dbg(X) printf(#X " = %s%lu\n", X.s < 0 ? "-" : "", X.p[0])
158
Manuel Pégourié-Gonnard847395a2012-11-05 13:13:44 +0100159/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100160 * Addition: R = P + Q, generic case (P != Q, P != 0, Q != 0, R != 0)
161 * Cf SEC1 v2 p. 7, item 4
162 */
163static int ecp_add_generic( const ecp_group *grp, ecp_point *R,
164 const ecp_point *P, const ecp_point *Q )
165{
166 int ret = 0;
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100167 mpi DX, DY, K, L, LL, X, Y;
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100168
169 mpi_init( &DX ); mpi_init( &DY ); mpi_init( &K ); mpi_init( &L );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100170 mpi_init( &LL ); mpi_init( &X ); mpi_init( &Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100171
172 /*
173 * L = (Q.Y - P.Y) / (Q.X - P.X) mod p
174 */
175 MPI_CHK( mpi_sub_mpi( &DY, &Q->Y, &P->Y ) );
176 MPI_CHK( mpi_sub_mpi( &DX, &Q->X, &P->X ) );
177 MPI_CHK( mpi_inv_mod( &K, &DX, &grp->P ) );
178 MPI_CHK( mpi_mul_mpi( &K, &K, &DY ) );
179 MPI_CHK( mpi_mod_mpi( &L, &K, &grp->P ) );
180
181 /*
182 * LL = L^2 mod p
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100183 * X = L^2 - P.X - Q.X
184 */
185 MPI_CHK( mpi_mul_mpi( &LL, &L, &L ) );
186 MPI_CHK( mpi_mod_mpi( &LL, &LL, &grp->P ) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100187
188 /*
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100189 * X = L^2 - P.X - Q.X
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100190 */
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100191 MPI_CHK( mpi_sub_mpi( &X, &LL, &P->X ) );
192 MPI_CHK( mpi_sub_mpi( &X, &X, &Q->X ) );
193
194 /*
195 * Y = L * (P.X - X) - P.Y
196 */
197 MPI_CHK( mpi_sub_mpi( &Y, &P->X, &X) );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100198 MPI_CHK( mpi_mul_mpi( &Y, &Y, &L ) );
199 MPI_CHK( mpi_sub_mpi( &Y, &Y, &P->Y ) );
200
201 /*
202 * R = (X mod p, Y mod p)
203 */
204 R->is_zero = 0;
205 MPI_CHK( mpi_mod_mpi( &R->X, &X, &grp->P ) );
206 MPI_CHK( mpi_mod_mpi( &R->Y, &Y, &grp->P ) );
207
208cleanup:
209
210 mpi_free( &DX ); mpi_free( &DY ); mpi_free( &K ); mpi_free( &L );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100211 mpi_free( &LL ); mpi_free( &X ); mpi_free( &Y );
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100212
213 return( ret );
214}
215
216/*
217 * Doubling: R = 2 * P, generic case (P != 0, R != 0)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100218 */
219static int ecp_double_generic( const ecp_group *grp, ecp_point *R,
220 const ecp_point *P )
221{
222 int ret = 0;
223
224 (void) grp;
225 (void) R;
226 (void) P;
227
228 return( ret );
229}
230
231/*
232 * Addition: R = P + Q, cf p. 7 of SEC1 v2
233 */
234int ecp_add( const ecp_group *grp, ecp_point *R,
235 const ecp_point *P, const ecp_point *Q )
236{
237 int ret = 0;
238
239 if( P->is_zero )
240 {
241 ret = ecp_copy( R, Q );
242 }
243 else if( Q->is_zero )
244 {
245 ret = ecp_copy( R, P );
246 }
247 else if( mpi_cmp_mpi( &P->X, &Q->X ) != 0 )
248 {
249 ret = ecp_add_generic( grp, R, P, Q );
250 }
251 else if( mpi_cmp_int( &P->Y, 0 ) == 0 ||
252 mpi_cmp_mpi( &P->Y, &Q->Y ) != 0 )
253 {
254 ecp_set_zero( R );
255 }
256 else
257 {
258 /*
259 * P == Q
260 */
261 ret = ecp_double_generic( grp, R, P );
262 }
263
264 return ret;
265}
266
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +0100267
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100268#if defined(POLARSSL_SELF_TEST)
269
270/*
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100271 * Return true iff P and Q are the same point
272 */
273static int ecp_point_eq( const ecp_point *P, const ecp_point *Q )
274{
275 if( P->is_zero || Q->is_zero )
276 return( P->is_zero && Q->is_zero );
277
278 return( mpi_cmp_mpi( &P->X, &Q->X ) == 0 &&
279 mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 );
280}
281
282/*
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100283 * Print a point assuming its coordinates are small
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100284 */
285static void ecp_point_print( const ecp_point *P )
286{
287 if( P->is_zero )
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100288 printf( "zero\n" );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100289 else
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100290 printf( "(%lu, %lu)\n", P->X.p[0], P->Y.p[0] );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100291}
292
293
294/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100295 * Checkup routine
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100296 *
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100297 * Data for basic tests with small values gathered from
298 * http://danher6.100webspace.net/ecc/#EFp_interactivo and double-checked
299 * using Pari-GP.
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100300 */
301int ecp_self_test( int verbose )
302{
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100303 int ret = 0;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100304 unsigned i;
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100305 ecp_group grp;
306 ecp_point O, A, B, C, D, E, F, G, TMP;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100307 ecp_point *add_tbl[][3] =
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100308 {
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100309 {&O, &O, &O}, {&O, &A, &A}, {&A, &O, &A},
310 {&A, &A, &O}, {&B, &C, &O}, {&C, &B, &O},
311 {&A, &D, &E}, {&D, &A, &E},
312 {&B, &D, &F}, {&D, &B, &F},
313 // {&D, &D, &G},
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100314 };
315
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100316 ecp_group_init( &grp );
317 ecp_point_init( &O ); ecp_point_init( &A ); ecp_point_init( &B );
318 ecp_point_init( &C ); ecp_point_init( &D ); ecp_point_init( &E );
319 ecp_point_init( &F ); ecp_point_init( &G ); ecp_point_init( &TMP );
320
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100321 ecp_set_zero( &O );
322 MPI_CHK( ecp_group_read_string( &grp, 10, "47", "4", "17", "42", "13" ) );
323 MPI_CHK( ecp_point_read_string( &A, 10, "13", "0" ) );
324 MPI_CHK( ecp_point_read_string( &B, 10, "14", "11" ) );
325 MPI_CHK( ecp_point_read_string( &C, 10, "14", "36" ) );
326 MPI_CHK( ecp_point_read_string( &D, 10, "37", "31" ) );
327 MPI_CHK( ecp_point_read_string( &E, 10, "34", "14" ) );
328 MPI_CHK( ecp_point_read_string( &F, 10, "45", "7" ) );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100329 MPI_CHK( ecp_point_read_string( &G, 10, "21", "32" ) );
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100330
331 if( verbose != 0 )
332 printf( " ECP test #1 (ecp_add): " );
333
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100334 for( i = 0; i < sizeof( add_tbl ) / sizeof( add_tbl[0] ); i++ )
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100335 {
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100336 MPI_CHK( ecp_add( &grp, &TMP, add_tbl[i][0], add_tbl[i][1] ) );
337 if( ! ecp_point_eq( &TMP, add_tbl[i][2] ) )
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100338 {
339 if( verbose != 0 )
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100340 {
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100341 printf(" failed (%u)\n", i );
342 printf( " GOT: " );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100343 ecp_point_print( &TMP );
Manuel Pégourié-Gonnardab38b702012-11-05 17:34:55 +0100344 printf( " EXPECTED: " );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100345 ecp_point_print( add_tbl[i][2] );
346 }
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100347
348 return( 1 );
349 }
350 }
351
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100352 if (verbose != 0 )
353 printf( " passed\n" );
354
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100355cleanup:
356
357 if( ret != 0 && verbose != 0 )
358 printf( "Unexpected error, return code = %08X\n", ret );
359
360 ecp_group_free( &grp );
361 ecp_point_free( &O ); ecp_point_free( &A ); ecp_point_free( &B );
362 ecp_point_free( &C ); ecp_point_free( &D ); ecp_point_free( &E );
363 ecp_point_free( &F ); ecp_point_free( &G );
364
365 if( verbose != 0 )
366 printf( "\n" );
367
368 return( ret );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100369}
370
371#endif
372
373#endif