Implement dispatcher for EC_GROUP and EC_POINT method functions.
[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 <openssl/err.h>
57
58 #include "ec_lcl.h"
59
60
61 /* functions for EC_GROUP objects */
62
63 EC_GROUP *EC_GROUP_new(const EC_METHOD *meth)
64         {
65         EC_GROUP *ret;
66
67         if (meth == NULL)
68                 {
69                 ECerr(EC_F_EC_GROUP_NEW, ERR_R_PASSED_NULL_PARAMETER);
70                 return NULL;
71                 }
72         if (meth->group_init == 0)
73                 {
74                 ECerr(EC_F_EC_GROUP_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
75                 return NULL;
76                 }
77
78         ret = OPENSSL_malloc(sizeof *ret);
79         if (ret == NULL)
80                 {
81                 ECerr(EC_F_EC_GROUP_NEW, ERR_R_MALLOC_FAILURE);
82                 return NULL;
83                 }
84
85         ret->meth = meth;
86         
87         if (!meth->group_init(ret))
88                 {
89                 OPENSSL_free(ret);
90                 return NULL;
91                 }
92         
93         return ret;
94         }
95
96
97 int EC_GROUP_set_curve_GFp(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
98         {
99         if (group->meth->group_set_curve_GFp == 0)
100                 {
101                 ECerr(EC_F_EC_GROUP_SET_CURVE_GFP, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
102                 return 0;
103                 }
104         
105         return group->meth->group_set_curve_GFp(group, p, a, b, ctx);
106         }
107
108
109 void EC_GROUP_free(EC_GROUP *group)
110         {
111         if (group->meth->group_finish != 0)
112                 group->meth->group_finish(group);
113         OPENSSL_free(group);
114         }
115  
116
117 void EC_GROUP_clear_free(EC_GROUP *group)
118         {
119         if (group->meth->group_clear_finish != 0)
120                 group->meth->group_clear_finish(group);
121         else if (group->meth != NULL && group->meth->group_finish != 0)
122                 group->meth->group_finish(group);
123         OPENSSL_free(group);
124         }
125
126
127 int EC_GROUP_copy(EC_GROUP *dest, const EC_GROUP *src)
128         {
129         if (dest->meth->group_copy == 0)
130                 {
131                 ECerr(EC_F_EC_GROUP_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
132                 return 0;
133                 }
134         if (dest->meth != src->meth)
135                 {
136                 ECerr(EC_F_EC_GROUP_COPY, EC_R_INCOMPATIBLE_OBJECTS);
137                 return 0;
138                 }
139         
140         return dest->meth->group_copy(dest, src);
141         }
142
143
144 int EC_GROUP_set_generator(EC_GROUP *group, const EC_POINT *generator, const BIGNUM *order, const BIGNUM *cofactor)
145         {
146         if (group->meth->group_set_generator == 0)
147                 {
148                 ECerr(EC_F_EC_GROUP_SET_GENERATOR, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
149                 return 0;
150                 }
151         return group->meth->group_set_generator(group, generator, order, cofactor);
152         }
153
154
155 /* TODO: 'get' functions for EC_GROUPs */
156
157
158
159 /* functions for EC_POINT objects */
160
161 EC_POINT *EC_POINT_new(const EC_GROUP *group)
162         {
163         EC_POINT *ret;
164
165         if (group == NULL)
166                 {
167                 ECerr(EC_F_EC_POINT_NEW, ERR_R_PASSED_NULL_PARAMETER);
168                 return NULL;
169                 }
170         if (group->meth->point_init == 0)
171                 {
172                 ECerr(EC_F_EC_POINT_NEW, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
173                 return NULL;
174                 }
175
176         ret = OPENSSL_malloc(sizeof *ret);
177         if (ret == NULL)
178                 {
179                 ECerr(EC_F_EC_POINT_NEW, ERR_R_MALLOC_FAILURE);
180                 return NULL;
181                 }
182
183         ret->meth = group->meth;
184         
185         if (!ret->meth->point_init(ret))
186                 {
187                 OPENSSL_free(ret);
188                 return NULL;
189                 }
190         
191         return ret;
192         }
193
194
195 void EC_POINT_free(EC_POINT *point)
196         {
197         if (point->meth->point_finish != 0)
198                 point->meth->point_finish(point);
199         OPENSSL_free(point);
200         }
201  
202
203 void EC_POINT_clear_free(EC_POINT *point)
204         {
205         if (point->meth->point_clear_finish != 0)
206                 point->meth->point_clear_finish(point);
207         else if (point->meth != NULL && point->meth->point_finish != 0)
208                 point->meth->point_finish(point);
209         OPENSSL_free(point);
210         }
211
212
213 int EC_POINT_copy(EC_POINT *dest, const EC_POINT *src)
214         {
215         if (dest->meth->point_copy == 0)
216                 {
217                 ECerr(EC_F_EC_POINT_COPY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
218                 return 0;
219                 }
220         if (dest->meth != src->meth)
221                 {
222                 ECerr(EC_F_EC_POINT_COPY, EC_R_INCOMPATIBLE_OBJECTS);
223                 return 0;
224                 }
225         
226         return dest->meth->point_copy(dest, src);
227         }
228
229
230 /* TODO: 'set' and 'get' functions for EC_POINTs */
231
232
233 size_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point, point_conversion_form_t form,
234         unsigned char *buf, size_t len, BN_CTX *ctx)
235         {
236         if (group->meth->point2oct == 0)
237                 {
238                 ECerr(EC_F_EC_POINT_POINT2OCT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
239                 return 0;
240                 }
241         if (group->meth != point->meth)
242                 {
243                 ECerr(EC_F_EC_POINT_POINT2OCT, EC_R_INCOMPATIBLE_OBJECTS);
244                 return 0;
245                 }
246         return group->meth->point2oct(group, point, form, buf, len, ctx);
247         }
248
249
250 int EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
251         const unsigned char *buf, size_t len, BN_CTX *ctx)
252         {
253         if (group->meth->oct2point == 0)
254                 {
255                 ECerr(EC_F_EC_POINT_OCT2POINT, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
256                 return 0;
257                 }
258         if (group->meth != point->meth)
259                 {
260                 ECerr(EC_F_EC_POINT_OCT2POINT, EC_R_INCOMPATIBLE_OBJECTS);
261                 return 0;
262                 }
263         return group->meth->oct2point(group, point, buf, len, ctx);
264         }
265
266
267 int EC_POINT_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx)
268         {
269         if (group->meth->add == 0)
270                 {
271                 ECerr(EC_F_EC_POINT_ADD, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
272                 return 0;
273                 }
274         if ((group->meth != r->meth) || (r->meth != a->meth) || (a->meth != b->meth))
275                 {
276                 ECerr(EC_F_EC_POINT_ADD, EC_R_INCOMPATIBLE_OBJECTS);
277                 return 0;
278                 }
279         return group->meth->add(group, r, a, b, ctx);
280         }
281
282
283 int EC_POINT_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx)
284         {
285         if (group->meth->dbl == 0)
286                 {
287                 ECerr(EC_F_EC_POINT_DBL, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
288                 return 0;
289                 }
290         if ((group->meth != r->meth) || (r->meth != a->meth))
291                 {
292                 ECerr(EC_F_EC_POINT_DBL, EC_R_INCOMPATIBLE_OBJECTS);
293                 return 0;
294                 }
295         return group->meth->dbl(group, r, a, ctx);
296         }
297
298
299 int EC_POINT_is_at_infinity(const EC_GROUP *group, const EC_POINT *point)
300         {
301         if (group->meth->is_at_infinity == 0)
302                 {
303                 ECerr(EC_F_EC_POINT_IS_AT_INFINITY, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
304                 return 0;
305                 }
306         if (group->meth != point->meth)
307                 {
308                 ECerr(EC_F_EC_POINT_IS_AT_INFINITY, EC_R_INCOMPATIBLE_OBJECTS);
309                 return 0;
310                 }
311         return group->meth->is_at_infinity(group, point);
312         }
313
314
315 int EC_POINT_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
316         {
317         if (group->meth->is_on_curve == 0)
318                 {
319                 ECerr(EC_F_EC_POINT_IS_ON_CURVE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
320                 return 0;
321                 }
322         if (group->meth != point->meth)
323                 {
324                 ECerr(EC_F_EC_POINT_IS_ON_CURVE, EC_R_INCOMPATIBLE_OBJECTS);
325                 return 0;
326                 }
327         return group->meth->is_on_curve(group, point, ctx);
328         }
329
330
331 int EC_POINT_make_affine(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx)
332         {
333         if (group->meth->make_affine == 0)
334                 {
335                 ECerr(EC_F_EC_POINT_MAKE_AFFINE, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
336                 return 0;
337                 }
338         if (group->meth != point->meth)
339                 {
340                 ECerr(EC_F_EC_POINT_MAKE_AFFINE, EC_R_INCOMPATIBLE_OBJECTS);
341                 return 0;
342                 }
343         return group->meth->make_affine(group, point, ctx);
344         }