More method functions for elliptic curves,
[openssl.git] / crypto / ec / ec_lib.c
1 /* crypto/ec/ec_lib.c */
2 /* ====================================================================
3  * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer. 
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in
14  *    the documentation and/or other materials provided with the
15  *    distribution.
16  *
17  * 3. All advertising materials mentioning features or use of this
18  *    software must display the following acknowledgment:
19  *    "This product includes software developed by the OpenSSL Project
20  *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21  *
22  * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23  *    endorse or promote products derived from this software without
24  *    prior written permission. For written permission, please contact
25  *    openssl-core@openssl.org.
26  *
27  * 5. Products derived from this software may not be called "OpenSSL"
28  *    nor may "OpenSSL" appear in their names without prior written
29  *    permission of the OpenSSL Project.
30  *
31  * 6. Redistributions of any form whatsoever must retain the following
32  *    acknowledgment:
33  *    "This product includes software developed by the OpenSSL Project
34  *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35  *
36  * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47  * OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This product includes cryptographic software written by Eric Young
51  * (eay@cryptsoft.com).  This product includes software written by Tim
52  * Hudson (tjh@cryptsoft.com).
53  *
54  */
55
56 #include <string.h>
57
58 #include <openssl/err.h>
59 #include <openssl/opensslv.h>
60
61 #include "ec_lcl.h"
62
63 static const char EC_version[] = "EC" OPENSSL_VERSION_PTEXT;
64
65
66 /* functions for EC_GROUP objects */
67
68 EC_GROUP *EC_GROUP_new(const EC_METHOD *meth)
69         {
70         EC_GROUP *ret;
71
72         if (meth == NULL)
73                 {
74                 ECerr(EC_F_EC_GROUP_NEW, ERR_R_PASSED_NULL_PARAMETER);
75                 return NULL;
76                 }
77         if (meth->group_init == 0)
78                 {
79                 ECerr(EC_F_EC_GROUP_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
80                 return NULL;
81                 }
82
83         ret = OPENSSL_malloc(sizeof *ret);
84         if (ret == NULL)
85                 {
86                 ECerr(EC_F_EC_GROUP_NEW, ERR_R_MALLOC_FAILURE);
87                 return NULL;
88                 }
89
90         ret->meth = meth;
91
92         ret->extra_data = NULL;
93         ret->extra_data_dup_func = 0;
94         ret->extra_data_free_func = 0;
95         ret->extra_data_clear_free_func = 0;
96         
97         if (!meth->group_init(ret))
98                 {
99                 OPENSSL_free(ret);
100                 return NULL;
101                 }
102         
103         return ret;
104         }
105
106
107 void EC_GROUP_free(EC_GROUP *group)
108         {
109         if (group->meth->group_finish != 0)
110                 group->meth->group_finish(group);
111
112         EC_GROUP_free_extra_data(group);
113
114         OPENSSL_free(group);
115         }
116  
117
118 void EC_GROUP_clear_free(EC_GROUP *group)
119         {
120         if (group->meth->group_clear_finish != 0)
121                 group->meth->group_clear_finish(group);
122         else if (group->meth != NULL && group->meth->group_finish != 0)
123                 group->meth->group_finish(group);
124
125         EC_GROUP_clear_free_extra_data(group);
126
127         memset(group, 0, sizeof *group);
128         OPENSSL_free(group);
129         }
130
131
132 int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src)
133         {
134         if (dest->meth->group_copy == 0)
135                 {
136                 ECerr(EC_F_EC_GROUP_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
137                 return 0;
138                 }
139         if (dest->meth != src->meth)
140                 {
141                 ECerr(EC_F_EC_GROUP_COPY, EC_R_INCOMPATIBLE_OBJECTS);
142                 return 0;
143                 }
144         if (dest == src)
145                 return 1;
146         
147         EC_GROUP_clear_free_extra_data(dest);
148         if (src->extra_data_dup_func)
149                 {
150                 if (src->extra_data != NULL)
151                         {
152                         dest->extra_data = src->extra_data_dup_func(src->extra_data);
153                         if (dest->extra_data == NULL)
154                                 return 0;
155                         }
156
157                 dest->extra_data_dup_func = src->extra_data_dup_func;
158                 dest->extra_data_free_func = src->extra_data_free_func;
159                 dest->extra_data_clear_free_func = src->extra_data_clear_free_func;
160                 }
161
162         return dest->meth->group_copy(dest, src);
163         }
164
165
166 int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
167         {
168         if (group->meth->group_set_curve_GFp == 0)
169                 {
170                 ECerr(EC_F_EC_GROUP_SET_CURVE_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
171                 return 0;
172                 }
173         return group->meth->group_set_curve_GFp(group, p, a, b, ctx);
174         }
175
176
177 int EC_GROUP_get_curve_GFp(EC_GROUP *group, BIGNUM *p, BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
178         {
179         if (group->meth->group_get_curve_GFp == 0)
180                 {
181                 ECerr(EC_F_EC_GROUP_GET_CURVE_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
182                 return 0;
183                 }
184         return group->meth->group_get_curve_GFp(group, p, a, b, ctx);
185         }
186
187
188 int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor)
189         {
190         if (group->meth->group_set_generator == 0)
191                 {
192                 ECerr(EC_F_EC_GROUP_SET_GENERATOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
193                 return 0;
194                 }
195         return group->meth->group_set_generator(group, generator, order, cofactor);
196         }
197
198
199 /* this has 'package' visibility */
200 int EC_GROUP_set_extra_data(EC_GROUP *group, void *extra_data, void *(*extra_data_dup_func)(void *),
201         void (*extra_data_free_func)(void *), void (*extra_data_clear_free_func)(void *))
202         {
203         if ((group->extra_data != NULL)
204                 || (group->extra_data_dup_func != 0)
205                 || (group->extra_data_free_func != 0)
206                 || (group->extra_data_clear_free_func != 0))
207                 {
208                 ECerr(EC_F_EC_GROUP_SET_EXTRA_DATA, EC_R_SLOT_FULL);
209                 return 0;
210                 }
211
212         group->extra_data = extra_data;
213         group->extra_data_dup_func = extra_data_dup_func;
214         group->extra_data_free_func = extra_data_free_func;
215         group->extra_data_clear_free_func = extra_data_clear_free_func;
216         return 1;
217         }
218
219
220 /* this has 'package' visibility */
221 void *EC_GROUP_get_extra_data(EC_GROUP *group, void *(*extra_data_dup_func)(void *),
222         void (*extra_data_free_func)(void *), void (*extra_data_clear_free_func)(void *))
223         {
224         if ((group->extra_data_dup_func != extra_data_dup_func)
225                 || (group->extra_data_free_func != extra_data_free_func)
226                 || (group->extra_data_clear_free_func != extra_data_clear_free_func))
227                 {
228                 ECerr(EC_F_EC_GROUP_GET_EXTRA_DATA, EC_R_NO_SUCH_EXTRA_DATA);
229                 return NULL;
230                 }
231
232         return group->extra_data;
233         }
234
235
236 /* this has 'package' visibility */
237 void EC_GROUP_free_extra_data(EC_GROUP *group)
238         {
239         if (group->extra_data_free_func)
240                 group->extra_data_free_func(group->extra_data);
241         group->extra_data = NULL;
242         group->extra_data_dup_func = 0;
243         group->extra_data_free_func = 0;
244         group->extra_data_clear_free_func = 0;
245         }
246
247
248 /* this has 'package' visibility */
249 void EC_GROUP_clear_free_extra_data(EC_GROUP *group)
250         {
251         if (group->extra_data_clear_free_func)
252                 group->extra_data_clear_free_func(group->extra_data);
253         else if (group->extra_data_free_func)
254                 group->extra_data_free_func(group->extra_data);
255         group->extra_data = NULL;
256         group->extra_data_dup_func = 0;
257         group->extra_data_free_func = 0;
258         group->extra_data_clear_free_func = 0;
259         }
260
261
262
263 /* functions for EC_POINT objects */
264
265 EC_POINT *EC_POINT_new(const EC_GROUP *group)
266         {
267         EC_POINT *ret;
268
269         if (group == NULL)
270                 {
271                 ECerr(EC_F_EC_POINT_NEW, ERR_R_PASSED_NULL_PARAMETER);
272                 return NULL;
273                 }
274         if (group->meth->point_init == 0)
275                 {
276                 ECerr(EC_F_EC_POINT_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
277                 return NULL;
278                 }
279
280         ret = OPENSSL_malloc(sizeof *ret);
281         if (ret == NULL)
282                 {
283                 ECerr(EC_F_EC_POINT_NEW, ERR_R_MALLOC_FAILURE);
284                 return NULL;
285                 }
286
287         ret->meth = group->meth;
288         
289         if (!ret->meth->point_init(ret))
290                 {
291                 OPENSSL_free(ret);
292                 return NULL;
293                 }
294         
295         return ret;
296         }
297
298
299 void EC_POINT_free(EC_POINT *point)
300         {
301         if (point->meth->point_finish != 0)
302                 point->meth->point_finish(point);
303         OPENSSL_free(point);
304         }
305  
306
307 void EC_POINT_clear_free(EC_POINT *point)
308         {
309         if (point->meth->point_clear_finish != 0)
310                 point->meth->point_clear_finish(point);
311         else if (point->meth != NULL && point->meth->point_finish != 0)
312                 point->meth->point_finish(point);
313         memset(point, 0, sizeof *point);
314         OPENSSL_free(point);
315         }
316
317
318 int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src)
319         {
320         if (dest->meth->point_copy == 0)
321                 {
322                 ECerr(EC_F_EC_POINT_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
323                 return 0;
324                 }
325         if (dest->meth != src->meth)
326                 {
327                 ECerr(EC_F_EC_POINT_COPY, EC_R_INCOMPATIBLE_OBJECTS);
328                 return 0;
329                 }
330         if (dest == src)
331                 return 1;
332         return dest->meth->point_copy(dest, src);
333         }
334
335
336 int EC_POINT_set_to_infinity(const EC_GROUP *group, EC_POINT *point)
337         {
338         if (group->meth->point_set_to_infinity == 0)
339                 {
340                 ECerr(EC_F_EC_POINT_SET_TO_INFINITY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
341                 return 0;
342                 }
343         if (group->meth != point->meth)
344                 {
345                 ECerr(EC_F_EC_POINT_SET_TO_INFINITY, EC_R_INCOMPATIBLE_OBJECTS);
346                 return 0;
347                 }
348         return group->meth->point_set_to_infinity(group, point);
349         }
350
351
352 int EC_POINT_set_Jprojective_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
353         const BIGNUM *x, const BIGNUM *y, const BIGNUM *z, BN_CTX *ctx)
354         {
355         if (group->meth->point_set_Jprojective_coordinates_GFp == 0)
356                 {
357                 ECerr(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
358                 return 0;
359                 }
360         if (group->meth != point->meth)
361                 {
362                 ECerr(EC_F_EC_POINT_SET_JPROJECTIVE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS);
363                 return 0;
364                 }
365         return group->meth->point_set_Jprojective_coordinates_GFp(group, point, x, y, z, ctx);
366         }
367
368
369 int EC_POINT_get_Jprojective_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point,
370         BIGNUM *x, BIGNUM *y, BIGNUM *z, BN_CTX *ctx)
371         {
372         if (group->meth->point_get_Jprojective_coordinates_GFp == 0)
373                 {
374                 ECerr(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
375                 return 0;
376                 }
377         if (group->meth != point->meth)
378                 {
379                 ECerr(EC_F_EC_POINT_GET_JPROJECTIVE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS);
380                 return 0;
381                 }
382         return group->meth->point_get_Jprojective_coordinates_GFp(group, point, x, y, z, ctx);
383         }
384
385
386 int EC_POINT_set_affine_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
387         const BIGNUM *x, const BIGNUM *y, BN_CTX *ctx)
388         {
389         if (group->meth->point_set_affine_coordinates_GFp == 0)
390                 {
391                 ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
392                 return 0;
393                 }
394         if (group->meth != point->meth)
395                 {
396                 ECerr(EC_F_EC_POINT_SET_AFFINE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS);
397                 return 0;
398                 }
399         return group->meth->point_set_affine_coordinates_GFp(group, point, x, y, ctx);
400         }
401
402
403 int EC_POINT_get_affine_coordinates_GFp(const EC_GROUP *group, const EC_POINT *point,
404         BIGNUM *x, BIGNUM *y, BN_CTX *ctx)
405         {
406         if (group->meth->point_get_affine_coordinates_GFp == 0)
407                 {
408                 ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
409                 return 0;
410                 }
411         if (group->meth != point->meth)
412                 {
413                 ECerr(EC_F_EC_POINT_GET_AFFINE_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS);
414                 return 0;
415                 }
416         return group->meth->point_get_affine_coordinates_GFp(group, point, x, y, ctx);
417         }
418
419
420 int EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group, EC_POINT *point,
421         const BIGNUM *x, int y_bit, BN_CTX *ctx)
422         {
423         if (group->meth->point_set_compressed_coordinates_GFp == 0)
424                 {
425                 ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
426                 return 0;
427                 }
428         if (group->meth != point->meth)
429                 {
430                 ECerr(EC_F_EC_POINT_SET_COMPRESSED_COORDINATES_GFP, EC_R_INCOMPATIBLE_OBJECTS);
431                 return 0;
432                 }
433         return group->meth->point_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx);
434         }
435
436
437 size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
438         unsigned char *buf, size_t len, BN_CTX *ctx)
439         {
440         if (group->meth->point2oct == 0)
441                 {
442                 ECerr(EC_F_EC_POINT_POINT2OCT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
443                 return 0;
444                 }
445         if (group->meth != point->meth)
446                 {
447                 ECerr(EC_F_EC_POINT_POINT2OCT, EC_R_INCOMPATIBLE_OBJECTS);
448                 return 0;
449                 }
450         return group->meth->point2oct(group, point, form, buf, len, ctx);
451         }
452
453
454 int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
455         const unsigned char *buf, size_t len, BN_CTX *ctx)
456         {
457         if (group->meth->oct2point == 0)
458                 {
459                 ECerr(EC_F_EC_POINT_OCT2POINT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
460                 return 0;
461                 }
462         if (group->meth != point->meth)
463                 {
464                 ECerr(EC_F_EC_POINT_OCT2POINT, EC_R_INCOMPATIBLE_OBJECTS);
465                 return 0;
466                 }
467         return group->meth->oct2point(group, point, buf, len, ctx);
468         }
469
470
471 int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
472         {
473         if (group->meth->add == 0)
474                 {
475                 ECerr(EC_F_EC_POINT_ADD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
476                 return 0;
477                 }
478         if ((group->meth != r->meth) || (r->meth != a->meth) || (a->meth != b->meth))
479                 {
480                 ECerr(EC_F_EC_POINT_ADD, EC_R_INCOMPATIBLE_OBJECTS);
481                 return 0;
482                 }
483         return group->meth->add(group, r, a, b, ctx);
484         }
485
486
487 int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
488         {
489         if (group->meth->dbl == 0)
490                 {
491                 ECerr(EC_F_EC_POINT_DBL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
492                 return 0;
493                 }
494         if ((group->meth != r->meth) || (r->meth != a->meth))
495                 {
496                 ECerr(EC_F_EC_POINT_DBL, EC_R_INCOMPATIBLE_OBJECTS);
497                 return 0;
498                 }
499         return group->meth->dbl(group, r, a, ctx);
500         }
501
502
503 int EC_POINT_invert(const EC_GROUP *group, EC_POINT *a, BN_CTX *ctx)
504         {
505         if (group->meth->dbl == 0)
506                 {
507                 ECerr(EC_F_EC_POINT_DBL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
508                 return 0;
509                 }
510         if (group->meth != a->meth)
511                 {
512                 ECerr(EC_F_EC_POINT_DBL, EC_R_INCOMPATIBLE_OBJECTS);
513                 return 0;
514                 }
515         return group->meth->invert(group, a, ctx);
516         }
517
518
519 int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
520         {
521         if (group->meth->is_at_infinity == 0)
522                 {
523                 ECerr(EC_F_EC_POINT_IS_AT_INFINITY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
524                 return 0;
525                 }
526         if (group->meth != point->meth)
527                 {
528                 ECerr(EC_F_EC_POINT_IS_AT_INFINITY, EC_R_INCOMPATIBLE_OBJECTS);
529                 return 0;
530                 }
531         return group->meth->is_at_infinity(group, point);
532         }
533
534
535 int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
536         {
537         if (group->meth->is_on_curve == 0)
538                 {
539                 ECerr(EC_F_EC_POINT_IS_ON_CURVE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
540                 return 0;
541                 }
542         if (group->meth != point->meth)
543                 {
544                 ECerr(EC_F_EC_POINT_IS_ON_CURVE, EC_R_INCOMPATIBLE_OBJECTS);
545                 return 0;
546                 }
547         return group->meth->is_on_curve(group, point, ctx);
548         }
549
550
551 int EC_POINT_cmp(const EC_GROUP *group, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
552         {
553         if (group->meth->point_cmp == 0)
554                 {
555                 ECerr(EC_F_EC_POINT_CMP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
556                 return 0;
557                 }
558         if ((group->meth != a->meth) || (a->meth != b->meth))
559                 {
560                 ECerr(EC_F_EC_POINT_CMP, EC_R_INCOMPATIBLE_OBJECTS);
561                 return 0;
562                 }
563         return group->meth->point_cmp(group, a, b, ctx);
564         }
565
566
567 int EC_POINT_make_affine(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
568         {
569         if (group->meth->make_affine == 0)
570                 {
571                 ECerr(EC_F_EC_POINT_MAKE_AFFINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
572                 return 0;
573                 }
574         if (group->meth != point->meth)
575                 {
576                 ECerr(EC_F_EC_POINT_MAKE_AFFINE, EC_R_INCOMPATIBLE_OBJECTS);
577                 return 0;
578                 }
579         return group->meth->make_affine(group, point, ctx);
580         }