EC point multiplication: add `ladder` scaffold
[openssl.git] / crypto / ec / ec2_smpl.c
1 /*
2  * Copyright 2002-2018 The OpenSSL Project Authors. All Rights Reserved.
3  * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved
4  *
5  * Licensed under the OpenSSL license (the "License").  You may not use
6  * this file except in compliance with the License.  You can obtain a copy
7  * in the file LICENSE in the source distribution or at
8  * https://www.openssl.org/source/license.html
9  */
10
11 #include <openssl/err.h>
12
13 #include "internal/bn_int.h"
14 #include "ec_lcl.h"
15
16 #ifndef OPENSSL_NO_EC2M
17
18 const EC_METHOD *EC_GF2m_simple_method(void)
19 {
20     static const EC_METHOD ret = {
21         EC_FLAGS_DEFAULT_OCT,
22         NID_X9_62_characteristic_two_field,
23         ec_GF2m_simple_group_init,
24         ec_GF2m_simple_group_finish,
25         ec_GF2m_simple_group_clear_finish,
26         ec_GF2m_simple_group_copy,
27         ec_GF2m_simple_group_set_curve,
28         ec_GF2m_simple_group_get_curve,
29         ec_GF2m_simple_group_get_degree,
30         ec_group_simple_order_bits,
31         ec_GF2m_simple_group_check_discriminant,
32         ec_GF2m_simple_point_init,
33         ec_GF2m_simple_point_finish,
34         ec_GF2m_simple_point_clear_finish,
35         ec_GF2m_simple_point_copy,
36         ec_GF2m_simple_point_set_to_infinity,
37         0 /* set_Jprojective_coordinates_GFp */ ,
38         0 /* get_Jprojective_coordinates_GFp */ ,
39         ec_GF2m_simple_point_set_affine_coordinates,
40         ec_GF2m_simple_point_get_affine_coordinates,
41         0, 0, 0,
42         ec_GF2m_simple_add,
43         ec_GF2m_simple_dbl,
44         ec_GF2m_simple_invert,
45         ec_GF2m_simple_is_at_infinity,
46         ec_GF2m_simple_is_on_curve,
47         ec_GF2m_simple_cmp,
48         ec_GF2m_simple_make_affine,
49         ec_GF2m_simple_points_make_affine,
50         0 /* mul */,
51         0 /* precompute_mul */,
52         0 /* have_precompute_mul */,
53         ec_GF2m_simple_field_mul,
54         ec_GF2m_simple_field_sqr,
55         ec_GF2m_simple_field_div,
56         0 /* field_encode */ ,
57         0 /* field_decode */ ,
58         0,                      /* field_set_to_one */
59         ec_key_simple_priv2oct,
60         ec_key_simple_oct2priv,
61         0, /* set private */
62         ec_key_simple_generate_key,
63         ec_key_simple_check_key,
64         ec_key_simple_generate_public_key,
65         0, /* keycopy */
66         0, /* keyfinish */
67         ecdh_simple_compute_key,
68         0, /* field_inverse_mod_ord */
69         0, /* blind_coordinates */
70         0, /* ladder_pre */
71         0, /* ladder_step */
72         0  /* ladder_post */
73     };
74
75     return &ret;
76 }
77
78 /*
79  * Initialize a GF(2^m)-based EC_GROUP structure. Note that all other members
80  * are handled by EC_GROUP_new.
81  */
82 int ec_GF2m_simple_group_init(EC_GROUP *group)
83 {
84     group->field = BN_new();
85     group->a = BN_new();
86     group->b = BN_new();
87
88     if (group->field == NULL || group->a == NULL || group->b == NULL) {
89         BN_free(group->field);
90         BN_free(group->a);
91         BN_free(group->b);
92         return 0;
93     }
94     return 1;
95 }
96
97 /*
98  * Free a GF(2^m)-based EC_GROUP structure. Note that all other members are
99  * handled by EC_GROUP_free.
100  */
101 void ec_GF2m_simple_group_finish(EC_GROUP *group)
102 {
103     BN_free(group->field);
104     BN_free(group->a);
105     BN_free(group->b);
106 }
107
108 /*
109  * Clear and free a GF(2^m)-based EC_GROUP structure. Note that all other
110  * members are handled by EC_GROUP_clear_free.
111  */
112 void ec_GF2m_simple_group_clear_finish(EC_GROUP *group)
113 {
114     BN_clear_free(group->field);
115     BN_clear_free(group->a);
116     BN_clear_free(group->b);
117     group->poly[0] = 0;
118     group->poly[1] = 0;
119     group->poly[2] = 0;
120     group->poly[3] = 0;
121     group->poly[4] = 0;
122     group->poly[5] = -1;
123 }
124
125 /*
126  * Copy a GF(2^m)-based EC_GROUP structure. Note that all other members are
127  * handled by EC_GROUP_copy.
128  */
129 int ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
130 {
131     if (!BN_copy(dest->field, src->field))
132         return 0;
133     if (!BN_copy(dest->a, src->a))
134         return 0;
135     if (!BN_copy(dest->b, src->b))
136         return 0;
137     dest->poly[0] = src->poly[0];
138     dest->poly[1] = src->poly[1];
139     dest->poly[2] = src->poly[2];
140     dest->poly[3] = src->poly[3];
141     dest->poly[4] = src->poly[4];
142     dest->poly[5] = src->poly[5];
143     if (bn_wexpand(dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) ==
144         NULL)
145         return 0;
146     if (bn_wexpand(dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2) ==
147         NULL)
148         return 0;
149     bn_set_all_zero(dest->a);
150     bn_set_all_zero(dest->b);
151     return 1;
152 }
153
154 /* Set the curve parameters of an EC_GROUP structure. */
155 int ec_GF2m_simple_group_set_curve(EC_GROUP *group,
156                                    const BIGNUM *p, const BIGNUM *a,
157                                    const BIGNUM *b, BN_CTX *ctx)
158 {
159     int ret = 0, i;
160
161     /* group->field */
162     if (!BN_copy(group->field, p))
163         goto err;
164     i = BN_GF2m_poly2arr(group->field, group->poly, 6) - 1;
165     if ((i != 5) && (i != 3)) {
166         ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE, EC_R_UNSUPPORTED_FIELD);
167         goto err;
168     }
169
170     /* group->a */
171     if (!BN_GF2m_mod_arr(group->a, a, group->poly))
172         goto err;
173     if (bn_wexpand(group->a, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
174         == NULL)
175         goto err;
176     bn_set_all_zero(group->a);
177
178     /* group->b */
179     if (!BN_GF2m_mod_arr(group->b, b, group->poly))
180         goto err;
181     if (bn_wexpand(group->b, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
182         == NULL)
183         goto err;
184     bn_set_all_zero(group->b);
185
186     ret = 1;
187  err:
188     return ret;
189 }
190
191 /*
192  * Get the curve parameters of an EC_GROUP structure. If p, a, or b are NULL
193  * then there values will not be set but the method will return with success.
194  */
195 int ec_GF2m_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p,
196                                    BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
197 {
198     int ret = 0;
199
200     if (p != NULL) {
201         if (!BN_copy(p, group->field))
202             return 0;
203     }
204
205     if (a != NULL) {
206         if (!BN_copy(a, group->a))
207             goto err;
208     }
209
210     if (b != NULL) {
211         if (!BN_copy(b, group->b))
212             goto err;
213     }
214
215     ret = 1;
216
217  err:
218     return ret;
219 }
220
221 /*
222  * Gets the degree of the field.  For a curve over GF(2^m) this is the value
223  * m.
224  */
225 int ec_GF2m_simple_group_get_degree(const EC_GROUP *group)
226 {
227     return BN_num_bits(group->field) - 1;
228 }
229
230 /*
231  * Checks the discriminant of the curve. y^2 + x*y = x^3 + a*x^2 + b is an
232  * elliptic curve <=> b != 0 (mod p)
233  */
234 int ec_GF2m_simple_group_check_discriminant(const EC_GROUP *group,
235                                             BN_CTX *ctx)
236 {
237     int ret = 0;
238     BIGNUM *b;
239     BN_CTX *new_ctx = NULL;
240
241     if (ctx == NULL) {
242         ctx = new_ctx = BN_CTX_new();
243         if (ctx == NULL) {
244             ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT,
245                   ERR_R_MALLOC_FAILURE);
246             goto err;
247         }
248     }
249     BN_CTX_start(ctx);
250     b = BN_CTX_get(ctx);
251     if (b == NULL)
252         goto err;
253
254     if (!BN_GF2m_mod_arr(b, group->b, group->poly))
255         goto err;
256
257     /*
258      * check the discriminant: y^2 + x*y = x^3 + a*x^2 + b is an elliptic
259      * curve <=> b != 0 (mod p)
260      */
261     if (BN_is_zero(b))
262         goto err;
263
264     ret = 1;
265
266  err:
267     if (ctx != NULL)
268         BN_CTX_end(ctx);
269     BN_CTX_free(new_ctx);
270     return ret;
271 }
272
273 /* Initializes an EC_POINT. */
274 int ec_GF2m_simple_point_init(EC_POINT *point)
275 {
276     point->X = BN_new();
277     point->Y = BN_new();
278     point->Z = BN_new();
279
280     if (point->X == NULL || point->Y == NULL || point->Z == NULL) {
281         BN_free(point->X);
282         BN_free(point->Y);
283         BN_free(point->Z);
284         return 0;
285     }
286     return 1;
287 }
288
289 /* Frees an EC_POINT. */
290 void ec_GF2m_simple_point_finish(EC_POINT *point)
291 {
292     BN_free(point->X);
293     BN_free(point->Y);
294     BN_free(point->Z);
295 }
296
297 /* Clears and frees an EC_POINT. */
298 void ec_GF2m_simple_point_clear_finish(EC_POINT *point)
299 {
300     BN_clear_free(point->X);
301     BN_clear_free(point->Y);
302     BN_clear_free(point->Z);
303     point->Z_is_one = 0;
304 }
305
306 /*
307  * Copy the contents of one EC_POINT into another.  Assumes dest is
308  * initialized.
309  */
310 int ec_GF2m_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
311 {
312     if (!BN_copy(dest->X, src->X))
313         return 0;
314     if (!BN_copy(dest->Y, src->Y))
315         return 0;
316     if (!BN_copy(dest->Z, src->Z))
317         return 0;
318     dest->Z_is_one = src->Z_is_one;
319     dest->curve_name = src->curve_name;
320
321     return 1;
322 }
323
324 /*
325  * Set an EC_POINT to the point at infinity. A point at infinity is
326  * represented by having Z=0.
327  */
328 int ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *group,
329                                          EC_POINT *point)
330 {
331     point->Z_is_one = 0;
332     BN_zero(point->Z);
333     return 1;
334 }
335
336 /*
337  * Set the coordinates of an EC_POINT using affine coordinates. Note that
338  * the simple implementation only uses affine coordinates.
339  */
340 int ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *group,
341                                                 EC_POINT *point,
342                                                 const BIGNUM *x,
343                                                 const BIGNUM *y, BN_CTX *ctx)
344 {
345     int ret = 0;
346     if (x == NULL || y == NULL) {
347         ECerr(EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES,
348               ERR_R_PASSED_NULL_PARAMETER);
349         return 0;
350     }
351
352     if (!BN_copy(point->X, x))
353         goto err;
354     BN_set_negative(point->X, 0);
355     if (!BN_copy(point->Y, y))
356         goto err;
357     BN_set_negative(point->Y, 0);
358     if (!BN_copy(point->Z, BN_value_one()))
359         goto err;
360     BN_set_negative(point->Z, 0);
361     point->Z_is_one = 1;
362     ret = 1;
363
364  err:
365     return ret;
366 }
367
368 /*
369  * Gets the affine coordinates of an EC_POINT. Note that the simple
370  * implementation only uses affine coordinates.
371  */
372 int ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group,
373                                                 const EC_POINT *point,
374                                                 BIGNUM *x, BIGNUM *y,
375                                                 BN_CTX *ctx)
376 {
377     int ret = 0;
378
379     if (EC_POINT_is_at_infinity(group, point)) {
380         ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES,
381               EC_R_POINT_AT_INFINITY);
382         return 0;
383     }
384
385     if (BN_cmp(point->Z, BN_value_one())) {
386         ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES,
387               ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
388         return 0;
389     }
390     if (x != NULL) {
391         if (!BN_copy(x, point->X))
392             goto err;
393         BN_set_negative(x, 0);
394     }
395     if (y != NULL) {
396         if (!BN_copy(y, point->Y))
397             goto err;
398         BN_set_negative(y, 0);
399     }
400     ret = 1;
401
402  err:
403     return ret;
404 }
405
406 /*
407  * Computes a + b and stores the result in r.  r could be a or b, a could be
408  * b. Uses algorithm A.10.2 of IEEE P1363.
409  */
410 int ec_GF2m_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
411                        const EC_POINT *b, BN_CTX *ctx)
412 {
413     BN_CTX *new_ctx = NULL;
414     BIGNUM *x0, *y0, *x1, *y1, *x2, *y2, *s, *t;
415     int ret = 0;
416
417     if (EC_POINT_is_at_infinity(group, a)) {
418         if (!EC_POINT_copy(r, b))
419             return 0;
420         return 1;
421     }
422
423     if (EC_POINT_is_at_infinity(group, b)) {
424         if (!EC_POINT_copy(r, a))
425             return 0;
426         return 1;
427     }
428
429     if (ctx == NULL) {
430         ctx = new_ctx = BN_CTX_new();
431         if (ctx == NULL)
432             return 0;
433     }
434
435     BN_CTX_start(ctx);
436     x0 = BN_CTX_get(ctx);
437     y0 = BN_CTX_get(ctx);
438     x1 = BN_CTX_get(ctx);
439     y1 = BN_CTX_get(ctx);
440     x2 = BN_CTX_get(ctx);
441     y2 = BN_CTX_get(ctx);
442     s = BN_CTX_get(ctx);
443     t = BN_CTX_get(ctx);
444     if (t == NULL)
445         goto err;
446
447     if (a->Z_is_one) {
448         if (!BN_copy(x0, a->X))
449             goto err;
450         if (!BN_copy(y0, a->Y))
451             goto err;
452     } else {
453         if (!EC_POINT_get_affine_coordinates_GF2m(group, a, x0, y0, ctx))
454             goto err;
455     }
456     if (b->Z_is_one) {
457         if (!BN_copy(x1, b->X))
458             goto err;
459         if (!BN_copy(y1, b->Y))
460             goto err;
461     } else {
462         if (!EC_POINT_get_affine_coordinates_GF2m(group, b, x1, y1, ctx))
463             goto err;
464     }
465
466     if (BN_GF2m_cmp(x0, x1)) {
467         if (!BN_GF2m_add(t, x0, x1))
468             goto err;
469         if (!BN_GF2m_add(s, y0, y1))
470             goto err;
471         if (!group->meth->field_div(group, s, s, t, ctx))
472             goto err;
473         if (!group->meth->field_sqr(group, x2, s, ctx))
474             goto err;
475         if (!BN_GF2m_add(x2, x2, group->a))
476             goto err;
477         if (!BN_GF2m_add(x2, x2, s))
478             goto err;
479         if (!BN_GF2m_add(x2, x2, t))
480             goto err;
481     } else {
482         if (BN_GF2m_cmp(y0, y1) || BN_is_zero(x1)) {
483             if (!EC_POINT_set_to_infinity(group, r))
484                 goto err;
485             ret = 1;
486             goto err;
487         }
488         if (!group->meth->field_div(group, s, y1, x1, ctx))
489             goto err;
490         if (!BN_GF2m_add(s, s, x1))
491             goto err;
492
493         if (!group->meth->field_sqr(group, x2, s, ctx))
494             goto err;
495         if (!BN_GF2m_add(x2, x2, s))
496             goto err;
497         if (!BN_GF2m_add(x2, x2, group->a))
498             goto err;
499     }
500
501     if (!BN_GF2m_add(y2, x1, x2))
502         goto err;
503     if (!group->meth->field_mul(group, y2, y2, s, ctx))
504         goto err;
505     if (!BN_GF2m_add(y2, y2, x2))
506         goto err;
507     if (!BN_GF2m_add(y2, y2, y1))
508         goto err;
509
510     if (!EC_POINT_set_affine_coordinates_GF2m(group, r, x2, y2, ctx))
511         goto err;
512
513     ret = 1;
514
515  err:
516     BN_CTX_end(ctx);
517     BN_CTX_free(new_ctx);
518     return ret;
519 }
520
521 /*
522  * Computes 2 * a and stores the result in r.  r could be a. Uses algorithm
523  * A.10.2 of IEEE P1363.
524  */
525 int ec_GF2m_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
526                        BN_CTX *ctx)
527 {
528     return ec_GF2m_simple_add(group, r, a, a, ctx);
529 }
530
531 int ec_GF2m_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
532 {
533     if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(point->Y))
534         /* point is its own inverse */
535         return 1;
536
537     if (!EC_POINT_make_affine(group, point, ctx))
538         return 0;
539     return BN_GF2m_add(point->Y, point->X, point->Y);
540 }
541
542 /* Indicates whether the given point is the point at infinity. */
543 int ec_GF2m_simple_is_at_infinity(const EC_GROUP *group,
544                                   const EC_POINT *point)
545 {
546     return BN_is_zero(point->Z);
547 }
548
549 /*-
550  * Determines whether the given EC_POINT is an actual point on the curve defined
551  * in the EC_GROUP.  A point is valid if it satisfies the Weierstrass equation:
552  *      y^2 + x*y = x^3 + a*x^2 + b.
553  */
554 int ec_GF2m_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
555                                BN_CTX *ctx)
556 {
557     int ret = -1;
558     BN_CTX *new_ctx = NULL;
559     BIGNUM *lh, *y2;
560     int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
561                       const BIGNUM *, BN_CTX *);
562     int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
563
564     if (EC_POINT_is_at_infinity(group, point))
565         return 1;
566
567     field_mul = group->meth->field_mul;
568     field_sqr = group->meth->field_sqr;
569
570     /* only support affine coordinates */
571     if (!point->Z_is_one)
572         return -1;
573
574     if (ctx == NULL) {
575         ctx = new_ctx = BN_CTX_new();
576         if (ctx == NULL)
577             return -1;
578     }
579
580     BN_CTX_start(ctx);
581     y2 = BN_CTX_get(ctx);
582     lh = BN_CTX_get(ctx);
583     if (lh == NULL)
584         goto err;
585
586     /*-
587      * We have a curve defined by a Weierstrass equation
588      *      y^2 + x*y = x^3 + a*x^2 + b.
589      *  <=> x^3 + a*x^2 + x*y + b + y^2 = 0
590      *  <=> ((x + a) * x + y ) * x + b + y^2 = 0
591      */
592     if (!BN_GF2m_add(lh, point->X, group->a))
593         goto err;
594     if (!field_mul(group, lh, lh, point->X, ctx))
595         goto err;
596     if (!BN_GF2m_add(lh, lh, point->Y))
597         goto err;
598     if (!field_mul(group, lh, lh, point->X, ctx))
599         goto err;
600     if (!BN_GF2m_add(lh, lh, group->b))
601         goto err;
602     if (!field_sqr(group, y2, point->Y, ctx))
603         goto err;
604     if (!BN_GF2m_add(lh, lh, y2))
605         goto err;
606     ret = BN_is_zero(lh);
607
608  err:
609     BN_CTX_end(ctx);
610     BN_CTX_free(new_ctx);
611     return ret;
612 }
613
614 /*-
615  * Indicates whether two points are equal.
616  * Return values:
617  *  -1   error
618  *   0   equal (in affine coordinates)
619  *   1   not equal
620  */
621 int ec_GF2m_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
622                        const EC_POINT *b, BN_CTX *ctx)
623 {
624     BIGNUM *aX, *aY, *bX, *bY;
625     BN_CTX *new_ctx = NULL;
626     int ret = -1;
627
628     if (EC_POINT_is_at_infinity(group, a)) {
629         return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
630     }
631
632     if (EC_POINT_is_at_infinity(group, b))
633         return 1;
634
635     if (a->Z_is_one && b->Z_is_one) {
636         return ((BN_cmp(a->X, b->X) == 0) && BN_cmp(a->Y, b->Y) == 0) ? 0 : 1;
637     }
638
639     if (ctx == NULL) {
640         ctx = new_ctx = BN_CTX_new();
641         if (ctx == NULL)
642             return -1;
643     }
644
645     BN_CTX_start(ctx);
646     aX = BN_CTX_get(ctx);
647     aY = BN_CTX_get(ctx);
648     bX = BN_CTX_get(ctx);
649     bY = BN_CTX_get(ctx);
650     if (bY == NULL)
651         goto err;
652
653     if (!EC_POINT_get_affine_coordinates_GF2m(group, a, aX, aY, ctx))
654         goto err;
655     if (!EC_POINT_get_affine_coordinates_GF2m(group, b, bX, bY, ctx))
656         goto err;
657     ret = ((BN_cmp(aX, bX) == 0) && BN_cmp(aY, bY) == 0) ? 0 : 1;
658
659  err:
660     BN_CTX_end(ctx);
661     BN_CTX_free(new_ctx);
662     return ret;
663 }
664
665 /* Forces the given EC_POINT to internally use affine coordinates. */
666 int ec_GF2m_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
667                                BN_CTX *ctx)
668 {
669     BN_CTX *new_ctx = NULL;
670     BIGNUM *x, *y;
671     int ret = 0;
672
673     if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
674         return 1;
675
676     if (ctx == NULL) {
677         ctx = new_ctx = BN_CTX_new();
678         if (ctx == NULL)
679             return 0;
680     }
681
682     BN_CTX_start(ctx);
683     x = BN_CTX_get(ctx);
684     y = BN_CTX_get(ctx);
685     if (y == NULL)
686         goto err;
687
688     if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx))
689         goto err;
690     if (!BN_copy(point->X, x))
691         goto err;
692     if (!BN_copy(point->Y, y))
693         goto err;
694     if (!BN_one(point->Z))
695         goto err;
696     point->Z_is_one = 1;
697
698     ret = 1;
699
700  err:
701     BN_CTX_end(ctx);
702     BN_CTX_free(new_ctx);
703     return ret;
704 }
705
706 /*
707  * Forces each of the EC_POINTs in the given array to use affine coordinates.
708  */
709 int ec_GF2m_simple_points_make_affine(const EC_GROUP *group, size_t num,
710                                       EC_POINT *points[], BN_CTX *ctx)
711 {
712     size_t i;
713
714     for (i = 0; i < num; i++) {
715         if (!group->meth->make_affine(group, points[i], ctx))
716             return 0;
717     }
718
719     return 1;
720 }
721
722 /* Wrapper to simple binary polynomial field multiplication implementation. */
723 int ec_GF2m_simple_field_mul(const EC_GROUP *group, BIGNUM *r,
724                              const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
725 {
726     return BN_GF2m_mod_mul_arr(r, a, b, group->poly, ctx);
727 }
728
729 /* Wrapper to simple binary polynomial field squaring implementation. */
730 int ec_GF2m_simple_field_sqr(const EC_GROUP *group, BIGNUM *r,
731                              const BIGNUM *a, BN_CTX *ctx)
732 {
733     return BN_GF2m_mod_sqr_arr(r, a, group->poly, ctx);
734 }
735
736 /* Wrapper to simple binary polynomial field division implementation. */
737 int ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r,
738                              const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
739 {
740     return BN_GF2m_mod_div(r, a, b, group->field, ctx);
741 }
742
743 #endif