blob: 242316b1a582260dc2000771236e266ba402bbf2 [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
157/*
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100158 * Addition: R = P + Q, generic case (P != Q, P != 0, Q != 0, R != 0)
159 * Cf SEC1 v2 p. 7, item 4
160 */
161static int ecp_add_generic( const ecp_group *grp, ecp_point *R,
162 const ecp_point *P, const ecp_point *Q )
163{
164 int ret = 0;
165 mpi DX, DY, K, L, LL, M, X, Y;
166
167 mpi_init( &DX ); mpi_init( &DY ); mpi_init( &K ); mpi_init( &L );
168 mpi_init( &LL ); mpi_init( &M ); mpi_init( &X ); mpi_init( &Y );
169
170 /*
171 * L = (Q.Y - P.Y) / (Q.X - P.X) mod p
172 */
173 MPI_CHK( mpi_sub_mpi( &DY, &Q->Y, &P->Y ) );
174 MPI_CHK( mpi_sub_mpi( &DX, &Q->X, &P->X ) );
175 MPI_CHK( mpi_inv_mod( &K, &DX, &grp->P ) );
176 MPI_CHK( mpi_mul_mpi( &K, &K, &DY ) );
177 MPI_CHK( mpi_mod_mpi( &L, &K, &grp->P ) );
178
179 /*
180 * LL = L^2 mod p
181 * M = L^2 - Q.X
182 * X = L^2 - P.X - Q.X
183 */
184 MPI_CHK( mpi_mul_mpi( &LL, &L, &L ) );
185 MPI_CHK( mpi_mod_mpi( &LL, &LL, &grp->P ) );
186 MPI_CHK( mpi_sub_mpi( &M, &LL, &Q->X ) );
187 MPI_CHK( mpi_sub_mpi( &X, &M, &P->X ) );
188
189 /*
190 * Y = L * (P.X - X) - P.Y = L * (-M) - P.Y
191 */
192 MPI_CHK( mpi_copy( &Y, &M ) );
193 Y.s = - Y.s;
194 MPI_CHK( mpi_mul_mpi( &Y, &Y, &L ) );
195 MPI_CHK( mpi_sub_mpi( &Y, &Y, &P->Y ) );
196
197 /*
198 * R = (X mod p, Y mod p)
199 */
200 R->is_zero = 0;
201 MPI_CHK( mpi_mod_mpi( &R->X, &X, &grp->P ) );
202 MPI_CHK( mpi_mod_mpi( &R->Y, &Y, &grp->P ) );
203
204cleanup:
205
206 mpi_free( &DX ); mpi_free( &DY ); mpi_free( &K ); mpi_free( &L );
207 mpi_free( &LL ); mpi_free( &M ); mpi_free( &X ); mpi_free( &Y );
208
209 return( ret );
210}
211
212/*
213 * Doubling: R = 2 * P, generic case (P != 0, R != 0)
Manuel Pégourié-Gonnardae180d02012-11-02 18:14:40 +0100214 */
215static int ecp_double_generic( const ecp_group *grp, ecp_point *R,
216 const ecp_point *P )
217{
218 int ret = 0;
219
220 (void) grp;
221 (void) R;
222 (void) P;
223
224 return( ret );
225}
226
227/*
228 * Addition: R = P + Q, cf p. 7 of SEC1 v2
229 */
230int ecp_add( const ecp_group *grp, ecp_point *R,
231 const ecp_point *P, const ecp_point *Q )
232{
233 int ret = 0;
234
235 if( P->is_zero )
236 {
237 ret = ecp_copy( R, Q );
238 }
239 else if( Q->is_zero )
240 {
241 ret = ecp_copy( R, P );
242 }
243 else if( mpi_cmp_mpi( &P->X, &Q->X ) != 0 )
244 {
245 ret = ecp_add_generic( grp, R, P, Q );
246 }
247 else if( mpi_cmp_int( &P->Y, 0 ) == 0 ||
248 mpi_cmp_mpi( &P->Y, &Q->Y ) != 0 )
249 {
250 ecp_set_zero( R );
251 }
252 else
253 {
254 /*
255 * P == Q
256 */
257 ret = ecp_double_generic( grp, R, P );
258 }
259
260 return ret;
261}
262
Manuel Pégourié-Gonnard5179e462012-10-31 19:37:54 +0100263
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100264#if defined(POLARSSL_SELF_TEST)
265
266/*
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100267 * Return true iff P and Q are the same point
268 */
269static int ecp_point_eq( const ecp_point *P, const ecp_point *Q )
270{
271 if( P->is_zero || Q->is_zero )
272 return( P->is_zero && Q->is_zero );
273
274 return( mpi_cmp_mpi( &P->X, &Q->X ) == 0 &&
275 mpi_cmp_mpi( &P->Y, &Q->Y ) == 0 );
276}
277
278/*
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100279 * Print a point assuming its components are small
280 */
281static void ecp_point_print( const ecp_point *P )
282{
283 if( P->is_zero )
284 printf("zero\n");
285 else
286 printf("(%lu, %lu)\n", P->X.p[0], P->Y.p[0]);
287}
288
289
290/*
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100291 * Checkup routine
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100292 *
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100293 * Data for basic tests with small values gathered from
294 * http://danher6.100webspace.net/ecc/#EFp_interactivo and double-checked
295 * using Pari-GP.
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100296 */
297int ecp_self_test( int verbose )
298{
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100299 int ret = 0;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100300 unsigned i;
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100301 ecp_group grp;
302 ecp_point O, A, B, C, D, E, F, G, TMP;
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100303 ecp_point *add_tbl[][3] =
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100304 {
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100305 {&O, &O, &O},
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100306 };
307
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100308 ecp_group_init( &grp );
309 ecp_point_init( &O ); ecp_point_init( &A ); ecp_point_init( &B );
310 ecp_point_init( &C ); ecp_point_init( &D ); ecp_point_init( &E );
311 ecp_point_init( &F ); ecp_point_init( &G ); ecp_point_init( &TMP );
312
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100313 ecp_set_zero( &O );
314 MPI_CHK( ecp_group_read_string( &grp, 10, "47", "4", "17", "42", "13" ) );
315 MPI_CHK( ecp_point_read_string( &A, 10, "13", "0" ) );
316 MPI_CHK( ecp_point_read_string( &B, 10, "14", "11" ) );
317 MPI_CHK( ecp_point_read_string( &C, 10, "14", "36" ) );
318 MPI_CHK( ecp_point_read_string( &D, 10, "37", "31" ) );
319 MPI_CHK( ecp_point_read_string( &E, 10, "34", "14" ) );
320 MPI_CHK( ecp_point_read_string( &F, 10, "45", "7" ) );
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100321 MPI_CHK( ecp_point_read_string( &G, 10, "21", "32" ) );
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100322
323 if( verbose != 0 )
324 printf( " ECP test #1 (ecp_add): " );
325
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100326 for( i = 0; i < sizeof( add_tbl ) / sizeof( add_tbl[0] ); i++ )
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100327 {
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100328 MPI_CHK( ecp_add( &grp, &TMP, add_tbl[i][0], add_tbl[i][1] ) );
329 if( ! ecp_point_eq( &TMP, add_tbl[i][2] ) )
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100330 {
331 if( verbose != 0 )
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100332 {
333 printf(" failed\n");
334 printf(" GOT: ");
335 ecp_point_print( &TMP );
336 printf(" EXPECTED: ");
337 ecp_point_print( add_tbl[i][2] );
338 }
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100339
340 return( 1 );
341 }
342 }
343
Manuel Pégourié-Gonnardb505c272012-11-05 17:27:54 +0100344 if (verbose != 0 )
345 printf( " passed\n" );
346
Manuel Pégourié-Gonnardd0dc6312012-11-05 16:28:33 +0100347cleanup:
348
349 if( ret != 0 && verbose != 0 )
350 printf( "Unexpected error, return code = %08X\n", ret );
351
352 ecp_group_free( &grp );
353 ecp_point_free( &O ); ecp_point_free( &A ); ecp_point_free( &B );
354 ecp_point_free( &C ); ecp_point_free( &D ); ecp_point_free( &E );
355 ecp_point_free( &F ); ecp_point_free( &G );
356
357 if( verbose != 0 )
358 printf( "\n" );
359
360 return( ret );
Manuel Pégourié-Gonnard39d2adb2012-10-31 09:26:55 +0100361}
362
363#endif
364
365#endif