1160814Ssimon/* crypto/ec/ec2_smpl.c */
2160814Ssimon/* ====================================================================
3160814Ssimon * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
4160814Ssimon *
5160814Ssimon * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
6160814Ssimon * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
7160814Ssimon * to the OpenSSL project.
8160814Ssimon *
9160814Ssimon * The ECC Code is licensed pursuant to the OpenSSL open source
10160814Ssimon * license provided below.
11160814Ssimon *
12160814Ssimon * The software is originally written by Sheueling Chang Shantz and
13160814Ssimon * Douglas Stebila of Sun Microsystems Laboratories.
14160814Ssimon *
15160814Ssimon */
16160814Ssimon/* ====================================================================
17160814Ssimon * Copyright (c) 1998-2003 The OpenSSL Project.  All rights reserved.
18160814Ssimon *
19160814Ssimon * Redistribution and use in source and binary forms, with or without
20160814Ssimon * modification, are permitted provided that the following conditions
21160814Ssimon * are met:
22160814Ssimon *
23160814Ssimon * 1. Redistributions of source code must retain the above copyright
24296465Sdelphij *    notice, this list of conditions and the following disclaimer.
25160814Ssimon *
26160814Ssimon * 2. Redistributions in binary form must reproduce the above copyright
27160814Ssimon *    notice, this list of conditions and the following disclaimer in
28160814Ssimon *    the documentation and/or other materials provided with the
29160814Ssimon *    distribution.
30160814Ssimon *
31160814Ssimon * 3. All advertising materials mentioning features or use of this
32160814Ssimon *    software must display the following acknowledgment:
33160814Ssimon *    "This product includes software developed by the OpenSSL Project
34160814Ssimon *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
35160814Ssimon *
36160814Ssimon * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
37160814Ssimon *    endorse or promote products derived from this software without
38160814Ssimon *    prior written permission. For written permission, please contact
39160814Ssimon *    openssl-core@openssl.org.
40160814Ssimon *
41160814Ssimon * 5. Products derived from this software may not be called "OpenSSL"
42160814Ssimon *    nor may "OpenSSL" appear in their names without prior written
43160814Ssimon *    permission of the OpenSSL Project.
44160814Ssimon *
45160814Ssimon * 6. Redistributions of any form whatsoever must retain the following
46160814Ssimon *    acknowledgment:
47160814Ssimon *    "This product includes software developed by the OpenSSL Project
48160814Ssimon *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
49160814Ssimon *
50160814Ssimon * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
51160814Ssimon * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52160814Ssimon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53160814Ssimon * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
54160814Ssimon * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55160814Ssimon * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
56160814Ssimon * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
57160814Ssimon * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58160814Ssimon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
59160814Ssimon * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60160814Ssimon * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
61160814Ssimon * OF THE POSSIBILITY OF SUCH DAMAGE.
62160814Ssimon * ====================================================================
63160814Ssimon *
64160814Ssimon * This product includes cryptographic software written by Eric Young
65160814Ssimon * (eay@cryptsoft.com).  This product includes software written by Tim
66160814Ssimon * Hudson (tjh@cryptsoft.com).
67160814Ssimon *
68160814Ssimon */
69160814Ssimon
70160814Ssimon#include <openssl/err.h>
71160814Ssimon
72160814Ssimon#include "ec_lcl.h"
73160814Ssimon
74160814Ssimonconst EC_METHOD *EC_GF2m_simple_method(void)
75296465Sdelphij{
76296465Sdelphij    static const EC_METHOD ret = {
77296465Sdelphij        NID_X9_62_characteristic_two_field,
78296465Sdelphij        ec_GF2m_simple_group_init,
79296465Sdelphij        ec_GF2m_simple_group_finish,
80296465Sdelphij        ec_GF2m_simple_group_clear_finish,
81296465Sdelphij        ec_GF2m_simple_group_copy,
82296465Sdelphij        ec_GF2m_simple_group_set_curve,
83296465Sdelphij        ec_GF2m_simple_group_get_curve,
84296465Sdelphij        ec_GF2m_simple_group_get_degree,
85296465Sdelphij        ec_GF2m_simple_group_check_discriminant,
86296465Sdelphij        ec_GF2m_simple_point_init,
87296465Sdelphij        ec_GF2m_simple_point_finish,
88296465Sdelphij        ec_GF2m_simple_point_clear_finish,
89296465Sdelphij        ec_GF2m_simple_point_copy,
90296465Sdelphij        ec_GF2m_simple_point_set_to_infinity,
91296465Sdelphij        0 /* set_Jprojective_coordinates_GFp */ ,
92296465Sdelphij        0 /* get_Jprojective_coordinates_GFp */ ,
93296465Sdelphij        ec_GF2m_simple_point_set_affine_coordinates,
94296465Sdelphij        ec_GF2m_simple_point_get_affine_coordinates,
95296465Sdelphij        ec_GF2m_simple_set_compressed_coordinates,
96296465Sdelphij        ec_GF2m_simple_point2oct,
97296465Sdelphij        ec_GF2m_simple_oct2point,
98296465Sdelphij        ec_GF2m_simple_add,
99296465Sdelphij        ec_GF2m_simple_dbl,
100296465Sdelphij        ec_GF2m_simple_invert,
101296465Sdelphij        ec_GF2m_simple_is_at_infinity,
102296465Sdelphij        ec_GF2m_simple_is_on_curve,
103296465Sdelphij        ec_GF2m_simple_cmp,
104296465Sdelphij        ec_GF2m_simple_make_affine,
105296465Sdelphij        ec_GF2m_simple_points_make_affine,
106160814Ssimon
107296465Sdelphij        /*
108296465Sdelphij         * the following three method functions are defined in ec2_mult.c
109296465Sdelphij         */
110296465Sdelphij        ec_GF2m_simple_mul,
111296465Sdelphij        ec_GF2m_precompute_mult,
112296465Sdelphij        ec_GF2m_have_precompute_mult,
113160814Ssimon
114296465Sdelphij        ec_GF2m_simple_field_mul,
115296465Sdelphij        ec_GF2m_simple_field_sqr,
116296465Sdelphij        ec_GF2m_simple_field_div,
117296465Sdelphij        0 /* field_encode */ ,
118296465Sdelphij        0 /* field_decode */ ,
119296465Sdelphij        0                       /* field_set_to_one */
120296465Sdelphij    };
121160814Ssimon
122296465Sdelphij    return &ret;
123296465Sdelphij}
124160814Ssimon
125296465Sdelphij/*
126296465Sdelphij * Initialize a GF(2^m)-based EC_GROUP structure. Note that all other members
127296465Sdelphij * are handled by EC_GROUP_new.
128160814Ssimon */
129160814Ssimonint ec_GF2m_simple_group_init(EC_GROUP *group)
130296465Sdelphij{
131296465Sdelphij    BN_init(&group->field);
132296465Sdelphij    BN_init(&group->a);
133296465Sdelphij    BN_init(&group->b);
134296465Sdelphij    return 1;
135296465Sdelphij}
136160814Ssimon
137296465Sdelphij/*
138296465Sdelphij * Free a GF(2^m)-based EC_GROUP structure. Note that all other members are
139296465Sdelphij * handled by EC_GROUP_free.
140160814Ssimon */
141160814Ssimonvoid ec_GF2m_simple_group_finish(EC_GROUP *group)
142296465Sdelphij{
143296465Sdelphij    BN_free(&group->field);
144296465Sdelphij    BN_free(&group->a);
145296465Sdelphij    BN_free(&group->b);
146296465Sdelphij}
147160814Ssimon
148296465Sdelphij/*
149296465Sdelphij * Clear and free a GF(2^m)-based EC_GROUP structure. Note that all other
150296465Sdelphij * members are handled by EC_GROUP_clear_free.
151160814Ssimon */
152160814Ssimonvoid ec_GF2m_simple_group_clear_finish(EC_GROUP *group)
153296465Sdelphij{
154296465Sdelphij    BN_clear_free(&group->field);
155296465Sdelphij    BN_clear_free(&group->a);
156296465Sdelphij    BN_clear_free(&group->b);
157296465Sdelphij    group->poly[0] = 0;
158296465Sdelphij    group->poly[1] = 0;
159296465Sdelphij    group->poly[2] = 0;
160296465Sdelphij    group->poly[3] = 0;
161296465Sdelphij    group->poly[4] = 0;
162296465Sdelphij}
163160814Ssimon
164296465Sdelphij/*
165296465Sdelphij * Copy a GF(2^m)-based EC_GROUP structure. Note that all other members are
166296465Sdelphij * handled by EC_GROUP_copy.
167160814Ssimon */
168160814Ssimonint ec_GF2m_simple_group_copy(EC_GROUP *dest, const EC_GROUP *src)
169296465Sdelphij{
170296465Sdelphij    int i;
171296465Sdelphij    if (!BN_copy(&dest->field, &src->field))
172296465Sdelphij        return 0;
173296465Sdelphij    if (!BN_copy(&dest->a, &src->a))
174296465Sdelphij        return 0;
175296465Sdelphij    if (!BN_copy(&dest->b, &src->b))
176296465Sdelphij        return 0;
177296465Sdelphij    dest->poly[0] = src->poly[0];
178296465Sdelphij    dest->poly[1] = src->poly[1];
179296465Sdelphij    dest->poly[2] = src->poly[2];
180296465Sdelphij    dest->poly[3] = src->poly[3];
181296465Sdelphij    dest->poly[4] = src->poly[4];
182296465Sdelphij    if (bn_wexpand(&dest->a, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2)
183296465Sdelphij        == NULL)
184296465Sdelphij        return 0;
185296465Sdelphij    if (bn_wexpand(&dest->b, (int)(dest->poly[0] + BN_BITS2 - 1) / BN_BITS2)
186296465Sdelphij        == NULL)
187296465Sdelphij        return 0;
188296465Sdelphij    for (i = dest->a.top; i < dest->a.dmax; i++)
189296465Sdelphij        dest->a.d[i] = 0;
190296465Sdelphij    for (i = dest->b.top; i < dest->b.dmax; i++)
191296465Sdelphij        dest->b.d[i] = 0;
192296465Sdelphij    return 1;
193296465Sdelphij}
194160814Ssimon
195160814Ssimon/* Set the curve parameters of an EC_GROUP structure. */
196160814Ssimonint ec_GF2m_simple_group_set_curve(EC_GROUP *group,
197296465Sdelphij                                   const BIGNUM *p, const BIGNUM *a,
198296465Sdelphij                                   const BIGNUM *b, BN_CTX *ctx)
199296465Sdelphij{
200296465Sdelphij    int ret = 0, i;
201160814Ssimon
202296465Sdelphij    /* group->field */
203296465Sdelphij    if (!BN_copy(&group->field, p))
204296465Sdelphij        goto err;
205296465Sdelphij    i = BN_GF2m_poly2arr(&group->field, group->poly, 5);
206296465Sdelphij    if ((i != 5) && (i != 3)) {
207296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_SET_CURVE, EC_R_UNSUPPORTED_FIELD);
208296465Sdelphij        goto err;
209296465Sdelphij    }
210160814Ssimon
211296465Sdelphij    /* group->a */
212296465Sdelphij    if (!BN_GF2m_mod_arr(&group->a, a, group->poly))
213296465Sdelphij        goto err;
214296465Sdelphij    if (bn_wexpand(&group->a, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
215296465Sdelphij        == NULL)
216296465Sdelphij        goto err;
217296465Sdelphij    for (i = group->a.top; i < group->a.dmax; i++)
218296465Sdelphij        group->a.d[i] = 0;
219160814Ssimon
220296465Sdelphij    /* group->b */
221296465Sdelphij    if (!BN_GF2m_mod_arr(&group->b, b, group->poly))
222296465Sdelphij        goto err;
223296465Sdelphij    if (bn_wexpand(&group->b, (int)(group->poly[0] + BN_BITS2 - 1) / BN_BITS2)
224296465Sdelphij        == NULL)
225296465Sdelphij        goto err;
226296465Sdelphij    for (i = group->b.top; i < group->b.dmax; i++)
227296465Sdelphij        group->b.d[i] = 0;
228160814Ssimon
229296465Sdelphij    ret = 1;
230296465Sdelphij err:
231296465Sdelphij    return ret;
232296465Sdelphij}
233296465Sdelphij
234296465Sdelphij/*
235296465Sdelphij * Get the curve parameters of an EC_GROUP structure. If p, a, or b are NULL
236296465Sdelphij * then there values will not be set but the method will return with success.
237160814Ssimon */
238296465Sdelphijint ec_GF2m_simple_group_get_curve(const EC_GROUP *group, BIGNUM *p,
239296465Sdelphij                                   BIGNUM *a, BIGNUM *b, BN_CTX *ctx)
240296465Sdelphij{
241296465Sdelphij    int ret = 0;
242160814Ssimon
243296465Sdelphij    if (p != NULL) {
244296465Sdelphij        if (!BN_copy(p, &group->field))
245296465Sdelphij            return 0;
246296465Sdelphij    }
247160814Ssimon
248296465Sdelphij    if (a != NULL) {
249296465Sdelphij        if (!BN_copy(a, &group->a))
250296465Sdelphij            goto err;
251296465Sdelphij    }
252160814Ssimon
253296465Sdelphij    if (b != NULL) {
254296465Sdelphij        if (!BN_copy(b, &group->b))
255296465Sdelphij            goto err;
256296465Sdelphij    }
257160814Ssimon
258296465Sdelphij    ret = 1;
259160814Ssimon
260296465Sdelphij err:
261296465Sdelphij    return ret;
262296465Sdelphij}
263160814Ssimon
264296465Sdelphij/*
265296465Sdelphij * Gets the degree of the field.  For a curve over GF(2^m) this is the value
266296465Sdelphij * m.
267160814Ssimon */
268296465Sdelphijint ec_GF2m_simple_group_get_degree(const EC_GROUP *group)
269296465Sdelphij{
270296465Sdelphij    return BN_num_bits(&group->field) - 1;
271296465Sdelphij}
272160814Ssimon
273296465Sdelphij/*
274296465Sdelphij * Checks the discriminant of the curve. y^2 + x*y = x^3 + a*x^2 + b is an
275296465Sdelphij * elliptic curve <=> b != 0 (mod p)
276296465Sdelphij */
277296465Sdelphijint ec_GF2m_simple_group_check_discriminant(const EC_GROUP *group,
278296465Sdelphij                                            BN_CTX *ctx)
279296465Sdelphij{
280296465Sdelphij    int ret = 0;
281296465Sdelphij    BIGNUM *b;
282296465Sdelphij    BN_CTX *new_ctx = NULL;
283160814Ssimon
284296465Sdelphij    if (ctx == NULL) {
285296465Sdelphij        ctx = new_ctx = BN_CTX_new();
286296465Sdelphij        if (ctx == NULL) {
287296465Sdelphij            ECerr(EC_F_EC_GF2M_SIMPLE_GROUP_CHECK_DISCRIMINANT,
288296465Sdelphij                  ERR_R_MALLOC_FAILURE);
289296465Sdelphij            goto err;
290296465Sdelphij        }
291296465Sdelphij    }
292296465Sdelphij    BN_CTX_start(ctx);
293296465Sdelphij    b = BN_CTX_get(ctx);
294296465Sdelphij    if (b == NULL)
295296465Sdelphij        goto err;
296160814Ssimon
297296465Sdelphij    if (!BN_GF2m_mod_arr(b, &group->b, group->poly))
298296465Sdelphij        goto err;
299160814Ssimon
300296465Sdelphij    /*
301296465Sdelphij     * check the discriminant: y^2 + x*y = x^3 + a*x^2 + b is an elliptic
302296465Sdelphij     * curve <=> b != 0 (mod p)
303296465Sdelphij     */
304296465Sdelphij    if (BN_is_zero(b))
305296465Sdelphij        goto err;
306160814Ssimon
307296465Sdelphij    ret = 1;
308160814Ssimon
309296465Sdelphij err:
310296465Sdelphij    if (ctx != NULL)
311296465Sdelphij        BN_CTX_end(ctx);
312296465Sdelphij    if (new_ctx != NULL)
313296465Sdelphij        BN_CTX_free(new_ctx);
314296465Sdelphij    return ret;
315296465Sdelphij}
316296465Sdelphij
317160814Ssimon/* Initializes an EC_POINT. */
318160814Ssimonint ec_GF2m_simple_point_init(EC_POINT *point)
319296465Sdelphij{
320296465Sdelphij    BN_init(&point->X);
321296465Sdelphij    BN_init(&point->Y);
322296465Sdelphij    BN_init(&point->Z);
323296465Sdelphij    return 1;
324296465Sdelphij}
325160814Ssimon
326160814Ssimon/* Frees an EC_POINT. */
327160814Ssimonvoid ec_GF2m_simple_point_finish(EC_POINT *point)
328296465Sdelphij{
329296465Sdelphij    BN_free(&point->X);
330296465Sdelphij    BN_free(&point->Y);
331296465Sdelphij    BN_free(&point->Z);
332296465Sdelphij}
333160814Ssimon
334160814Ssimon/* Clears and frees an EC_POINT. */
335160814Ssimonvoid ec_GF2m_simple_point_clear_finish(EC_POINT *point)
336296465Sdelphij{
337296465Sdelphij    BN_clear_free(&point->X);
338296465Sdelphij    BN_clear_free(&point->Y);
339296465Sdelphij    BN_clear_free(&point->Z);
340296465Sdelphij    point->Z_is_one = 0;
341296465Sdelphij}
342160814Ssimon
343296465Sdelphij/*
344296465Sdelphij * Copy the contents of one EC_POINT into another.  Assumes dest is
345296465Sdelphij * initialized.
346296465Sdelphij */
347160814Ssimonint ec_GF2m_simple_point_copy(EC_POINT *dest, const EC_POINT *src)
348296465Sdelphij{
349296465Sdelphij    if (!BN_copy(&dest->X, &src->X))
350296465Sdelphij        return 0;
351296465Sdelphij    if (!BN_copy(&dest->Y, &src->Y))
352296465Sdelphij        return 0;
353296465Sdelphij    if (!BN_copy(&dest->Z, &src->Z))
354296465Sdelphij        return 0;
355296465Sdelphij    dest->Z_is_one = src->Z_is_one;
356160814Ssimon
357296465Sdelphij    return 1;
358296465Sdelphij}
359160814Ssimon
360296465Sdelphij/*
361296465Sdelphij * Set an EC_POINT to the point at infinity. A point at infinity is
362296465Sdelphij * represented by having Z=0.
363160814Ssimon */
364296465Sdelphijint ec_GF2m_simple_point_set_to_infinity(const EC_GROUP *group,
365296465Sdelphij                                         EC_POINT *point)
366296465Sdelphij{
367296465Sdelphij    point->Z_is_one = 0;
368296465Sdelphij    BN_zero(&point->Z);
369296465Sdelphij    return 1;
370296465Sdelphij}
371160814Ssimon
372296465Sdelphij/*
373296465Sdelphij * Set the coordinates of an EC_POINT using affine coordinates. Note that
374296465Sdelphij * the simple implementation only uses affine coordinates.
375160814Ssimon */
376296465Sdelphijint ec_GF2m_simple_point_set_affine_coordinates(const EC_GROUP *group,
377296465Sdelphij                                                EC_POINT *point,
378296465Sdelphij                                                const BIGNUM *x,
379296465Sdelphij                                                const BIGNUM *y, BN_CTX *ctx)
380296465Sdelphij{
381296465Sdelphij    int ret = 0;
382296465Sdelphij    if (x == NULL || y == NULL) {
383296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_POINT_SET_AFFINE_COORDINATES,
384296465Sdelphij              ERR_R_PASSED_NULL_PARAMETER);
385296465Sdelphij        return 0;
386296465Sdelphij    }
387160814Ssimon
388296465Sdelphij    if (!BN_copy(&point->X, x))
389296465Sdelphij        goto err;
390296465Sdelphij    BN_set_negative(&point->X, 0);
391296465Sdelphij    if (!BN_copy(&point->Y, y))
392296465Sdelphij        goto err;
393296465Sdelphij    BN_set_negative(&point->Y, 0);
394296465Sdelphij    if (!BN_copy(&point->Z, BN_value_one()))
395296465Sdelphij        goto err;
396296465Sdelphij    BN_set_negative(&point->Z, 0);
397296465Sdelphij    point->Z_is_one = 1;
398296465Sdelphij    ret = 1;
399160814Ssimon
400296465Sdelphij err:
401296465Sdelphij    return ret;
402296465Sdelphij}
403160814Ssimon
404296465Sdelphij/*
405296465Sdelphij * Gets the affine coordinates of an EC_POINT. Note that the simple
406296465Sdelphij * implementation only uses affine coordinates.
407160814Ssimon */
408296465Sdelphijint ec_GF2m_simple_point_get_affine_coordinates(const EC_GROUP *group,
409296465Sdelphij                                                const EC_POINT *point,
410296465Sdelphij                                                BIGNUM *x, BIGNUM *y,
411296465Sdelphij                                                BN_CTX *ctx)
412296465Sdelphij{
413296465Sdelphij    int ret = 0;
414160814Ssimon
415296465Sdelphij    if (EC_POINT_is_at_infinity(group, point)) {
416296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES,
417296465Sdelphij              EC_R_POINT_AT_INFINITY);
418296465Sdelphij        return 0;
419296465Sdelphij    }
420160814Ssimon
421296465Sdelphij    if (BN_cmp(&point->Z, BN_value_one())) {
422296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_POINT_GET_AFFINE_COORDINATES,
423296465Sdelphij              ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
424296465Sdelphij        return 0;
425296465Sdelphij    }
426296465Sdelphij    if (x != NULL) {
427296465Sdelphij        if (!BN_copy(x, &point->X))
428296465Sdelphij            goto err;
429296465Sdelphij        BN_set_negative(x, 0);
430296465Sdelphij    }
431296465Sdelphij    if (y != NULL) {
432296465Sdelphij        if (!BN_copy(y, &point->Y))
433296465Sdelphij            goto err;
434296465Sdelphij        BN_set_negative(y, 0);
435296465Sdelphij    }
436296465Sdelphij    ret = 1;
437296465Sdelphij
438160814Ssimon err:
439296465Sdelphij    return ret;
440296465Sdelphij}
441160814Ssimon
442160814Ssimon/* Include patented algorithms. */
443160814Ssimon#include "ec2_smpt.c"
444160814Ssimon
445296465Sdelphij/*
446296465Sdelphij * Converts an EC_POINT to an octet string. If buf is NULL, the encoded
447296465Sdelphij * length will be returned. If the length len of buf is smaller than required
448296465Sdelphij * an error will be returned. The point compression section of this function
449296465Sdelphij * is patented by Certicom Corp. under US Patent 6,141,420.  Point
450296465Sdelphij * compression is disabled by default and can be enabled by defining the
451296465Sdelphij * preprocessor macro OPENSSL_EC_BIN_PT_COMP at Configure-time.
452160814Ssimon */
453296465Sdelphijsize_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point,
454296465Sdelphij                                point_conversion_form_t form,
455296465Sdelphij                                unsigned char *buf, size_t len, BN_CTX *ctx)
456296465Sdelphij{
457296465Sdelphij    size_t ret;
458296465Sdelphij    BN_CTX *new_ctx = NULL;
459296465Sdelphij    int used_ctx = 0;
460296465Sdelphij    BIGNUM *x, *y, *yxi;
461296465Sdelphij    size_t field_len, i, skip;
462160814Ssimon
463160814Ssimon#ifndef OPENSSL_EC_BIN_PT_COMP
464296465Sdelphij    if ((form == POINT_CONVERSION_COMPRESSED)
465296465Sdelphij        || (form == POINT_CONVERSION_HYBRID)) {
466296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_DISABLED);
467296465Sdelphij        goto err;
468296465Sdelphij    }
469160814Ssimon#endif
470160814Ssimon
471296465Sdelphij    if ((form != POINT_CONVERSION_COMPRESSED)
472296465Sdelphij        && (form != POINT_CONVERSION_UNCOMPRESSED)
473296465Sdelphij        && (form != POINT_CONVERSION_HYBRID)) {
474296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
475296465Sdelphij        goto err;
476296465Sdelphij    }
477160814Ssimon
478296465Sdelphij    if (EC_POINT_is_at_infinity(group, point)) {
479296465Sdelphij        /* encodes to a single 0 octet */
480296465Sdelphij        if (buf != NULL) {
481296465Sdelphij            if (len < 1) {
482296465Sdelphij                ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
483296465Sdelphij                return 0;
484296465Sdelphij            }
485296465Sdelphij            buf[0] = 0;
486296465Sdelphij        }
487296465Sdelphij        return 1;
488296465Sdelphij    }
489160814Ssimon
490296465Sdelphij    /* ret := required output buffer length */
491296465Sdelphij    field_len = (EC_GROUP_get_degree(group) + 7) / 8;
492296465Sdelphij    ret =
493296465Sdelphij        (form ==
494296465Sdelphij         POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
495160814Ssimon
496296465Sdelphij    /* if 'buf' is NULL, just return required length */
497296465Sdelphij    if (buf != NULL) {
498296465Sdelphij        if (len < ret) {
499296465Sdelphij            ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
500296465Sdelphij            goto err;
501296465Sdelphij        }
502160814Ssimon
503296465Sdelphij        if (ctx == NULL) {
504296465Sdelphij            ctx = new_ctx = BN_CTX_new();
505296465Sdelphij            if (ctx == NULL)
506296465Sdelphij                return 0;
507296465Sdelphij        }
508160814Ssimon
509296465Sdelphij        BN_CTX_start(ctx);
510296465Sdelphij        used_ctx = 1;
511296465Sdelphij        x = BN_CTX_get(ctx);
512296465Sdelphij        y = BN_CTX_get(ctx);
513296465Sdelphij        yxi = BN_CTX_get(ctx);
514296465Sdelphij        if (yxi == NULL)
515296465Sdelphij            goto err;
516160814Ssimon
517296465Sdelphij        if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx))
518296465Sdelphij            goto err;
519160814Ssimon
520296465Sdelphij        buf[0] = form;
521160814Ssimon#ifdef OPENSSL_EC_BIN_PT_COMP
522296465Sdelphij        if ((form != POINT_CONVERSION_UNCOMPRESSED) && !BN_is_zero(x)) {
523296465Sdelphij            if (!group->meth->field_div(group, yxi, y, x, ctx))
524296465Sdelphij                goto err;
525296465Sdelphij            if (BN_is_odd(yxi))
526296465Sdelphij                buf[0]++;
527296465Sdelphij        }
528160814Ssimon#endif
529160814Ssimon
530296465Sdelphij        i = 1;
531160814Ssimon
532296465Sdelphij        skip = field_len - BN_num_bytes(x);
533296465Sdelphij        if (skip > field_len) {
534296465Sdelphij            ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
535296465Sdelphij            goto err;
536296465Sdelphij        }
537296465Sdelphij        while (skip > 0) {
538296465Sdelphij            buf[i++] = 0;
539296465Sdelphij            skip--;
540296465Sdelphij        }
541296465Sdelphij        skip = BN_bn2bin(x, buf + i);
542296465Sdelphij        i += skip;
543296465Sdelphij        if (i != 1 + field_len) {
544296465Sdelphij            ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
545296465Sdelphij            goto err;
546296465Sdelphij        }
547160814Ssimon
548296465Sdelphij        if (form == POINT_CONVERSION_UNCOMPRESSED
549296465Sdelphij            || form == POINT_CONVERSION_HYBRID) {
550296465Sdelphij            skip = field_len - BN_num_bytes(y);
551296465Sdelphij            if (skip > field_len) {
552296465Sdelphij                ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
553296465Sdelphij                goto err;
554296465Sdelphij            }
555296465Sdelphij            while (skip > 0) {
556296465Sdelphij                buf[i++] = 0;
557296465Sdelphij                skip--;
558296465Sdelphij            }
559296465Sdelphij            skip = BN_bn2bin(y, buf + i);
560296465Sdelphij            i += skip;
561296465Sdelphij        }
562160814Ssimon
563296465Sdelphij        if (i != ret) {
564296465Sdelphij            ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
565296465Sdelphij            goto err;
566296465Sdelphij        }
567296465Sdelphij    }
568296465Sdelphij
569296465Sdelphij    if (used_ctx)
570296465Sdelphij        BN_CTX_end(ctx);
571296465Sdelphij    if (new_ctx != NULL)
572296465Sdelphij        BN_CTX_free(new_ctx);
573296465Sdelphij    return ret;
574296465Sdelphij
575160814Ssimon err:
576296465Sdelphij    if (used_ctx)
577296465Sdelphij        BN_CTX_end(ctx);
578296465Sdelphij    if (new_ctx != NULL)
579296465Sdelphij        BN_CTX_free(new_ctx);
580296465Sdelphij    return 0;
581296465Sdelphij}
582160814Ssimon
583296465Sdelphij/*
584296465Sdelphij * Converts an octet string representation to an EC_POINT. Note that the
585296465Sdelphij * simple implementation only uses affine coordinates.
586160814Ssimon */
587160814Ssimonint ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
588296465Sdelphij                             const unsigned char *buf, size_t len,
589296465Sdelphij                             BN_CTX *ctx)
590296465Sdelphij{
591296465Sdelphij    point_conversion_form_t form;
592296465Sdelphij    int y_bit;
593296465Sdelphij    BN_CTX *new_ctx = NULL;
594296465Sdelphij    BIGNUM *x, *y, *yxi;
595296465Sdelphij    size_t field_len, enc_len;
596296465Sdelphij    int ret = 0;
597160814Ssimon
598296465Sdelphij    if (len == 0) {
599296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
600296465Sdelphij        return 0;
601296465Sdelphij    }
602296465Sdelphij    form = buf[0];
603296465Sdelphij    y_bit = form & 1;
604296465Sdelphij    form = form & ~1U;
605296465Sdelphij    if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
606296465Sdelphij        && (form != POINT_CONVERSION_UNCOMPRESSED)
607296465Sdelphij        && (form != POINT_CONVERSION_HYBRID)) {
608296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
609296465Sdelphij        return 0;
610296465Sdelphij    }
611296465Sdelphij    if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) {
612296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
613296465Sdelphij        return 0;
614296465Sdelphij    }
615160814Ssimon
616296465Sdelphij    if (form == 0) {
617296465Sdelphij        if (len != 1) {
618296465Sdelphij            ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
619296465Sdelphij            return 0;
620296465Sdelphij        }
621160814Ssimon
622296465Sdelphij        return EC_POINT_set_to_infinity(group, point);
623296465Sdelphij    }
624160814Ssimon
625296465Sdelphij    field_len = (EC_GROUP_get_degree(group) + 7) / 8;
626296465Sdelphij    enc_len =
627296465Sdelphij        (form ==
628296465Sdelphij         POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
629160814Ssimon
630296465Sdelphij    if (len != enc_len) {
631296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
632296465Sdelphij        return 0;
633296465Sdelphij    }
634160814Ssimon
635296465Sdelphij    if (ctx == NULL) {
636296465Sdelphij        ctx = new_ctx = BN_CTX_new();
637296465Sdelphij        if (ctx == NULL)
638296465Sdelphij            return 0;
639296465Sdelphij    }
640160814Ssimon
641296465Sdelphij    BN_CTX_start(ctx);
642296465Sdelphij    x = BN_CTX_get(ctx);
643296465Sdelphij    y = BN_CTX_get(ctx);
644296465Sdelphij    yxi = BN_CTX_get(ctx);
645296465Sdelphij    if (yxi == NULL)
646296465Sdelphij        goto err;
647160814Ssimon
648296465Sdelphij    if (!BN_bin2bn(buf + 1, field_len, x))
649296465Sdelphij        goto err;
650296465Sdelphij    if (BN_ucmp(x, &group->field) >= 0) {
651296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
652296465Sdelphij        goto err;
653296465Sdelphij    }
654160814Ssimon
655296465Sdelphij    if (form == POINT_CONVERSION_COMPRESSED) {
656296465Sdelphij        if (!EC_POINT_set_compressed_coordinates_GF2m
657296465Sdelphij            (group, point, x, y_bit, ctx))
658296465Sdelphij            goto err;
659296465Sdelphij    } else {
660296465Sdelphij        if (!BN_bin2bn(buf + 1 + field_len, field_len, y))
661296465Sdelphij            goto err;
662296465Sdelphij        if (BN_ucmp(y, &group->field) >= 0) {
663296465Sdelphij            ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
664296465Sdelphij            goto err;
665296465Sdelphij        }
666296465Sdelphij        if (form == POINT_CONVERSION_HYBRID) {
667296465Sdelphij            if (!group->meth->field_div(group, yxi, y, x, ctx))
668296465Sdelphij                goto err;
669296465Sdelphij            if (y_bit != BN_is_odd(yxi)) {
670296465Sdelphij                ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
671296465Sdelphij                goto err;
672296465Sdelphij            }
673296465Sdelphij        }
674160814Ssimon
675296465Sdelphij        if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx))
676296465Sdelphij            goto err;
677296465Sdelphij    }
678296465Sdelphij
679296465Sdelphij    /* test required by X9.62 */
680296465Sdelphij    if (EC_POINT_is_on_curve(group, point, ctx) <= 0) {
681296465Sdelphij        ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
682296465Sdelphij        goto err;
683296465Sdelphij    }
684296465Sdelphij
685296465Sdelphij    ret = 1;
686296465Sdelphij
687160814Ssimon err:
688296465Sdelphij    BN_CTX_end(ctx);
689296465Sdelphij    if (new_ctx != NULL)
690296465Sdelphij        BN_CTX_free(new_ctx);
691296465Sdelphij    return ret;
692296465Sdelphij}
693160814Ssimon
694296465Sdelphij/*
695296465Sdelphij * Computes a + b and stores the result in r.  r could be a or b, a could be
696296465Sdelphij * b. Uses algorithm A.10.2 of IEEE P1363.
697160814Ssimon */
698296465Sdelphijint ec_GF2m_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
699296465Sdelphij                       const EC_POINT *b, BN_CTX *ctx)
700296465Sdelphij{
701296465Sdelphij    BN_CTX *new_ctx = NULL;
702296465Sdelphij    BIGNUM *x0, *y0, *x1, *y1, *x2, *y2, *s, *t;
703296465Sdelphij    int ret = 0;
704160814Ssimon
705296465Sdelphij    if (EC_POINT_is_at_infinity(group, a)) {
706296465Sdelphij        if (!EC_POINT_copy(r, b))
707296465Sdelphij            return 0;
708296465Sdelphij        return 1;
709296465Sdelphij    }
710160814Ssimon
711296465Sdelphij    if (EC_POINT_is_at_infinity(group, b)) {
712296465Sdelphij        if (!EC_POINT_copy(r, a))
713296465Sdelphij            return 0;
714296465Sdelphij        return 1;
715296465Sdelphij    }
716160814Ssimon
717296465Sdelphij    if (ctx == NULL) {
718296465Sdelphij        ctx = new_ctx = BN_CTX_new();
719296465Sdelphij        if (ctx == NULL)
720296465Sdelphij            return 0;
721296465Sdelphij    }
722160814Ssimon
723296465Sdelphij    BN_CTX_start(ctx);
724296465Sdelphij    x0 = BN_CTX_get(ctx);
725296465Sdelphij    y0 = BN_CTX_get(ctx);
726296465Sdelphij    x1 = BN_CTX_get(ctx);
727296465Sdelphij    y1 = BN_CTX_get(ctx);
728296465Sdelphij    x2 = BN_CTX_get(ctx);
729296465Sdelphij    y2 = BN_CTX_get(ctx);
730296465Sdelphij    s = BN_CTX_get(ctx);
731296465Sdelphij    t = BN_CTX_get(ctx);
732296465Sdelphij    if (t == NULL)
733296465Sdelphij        goto err;
734160814Ssimon
735296465Sdelphij    if (a->Z_is_one) {
736296465Sdelphij        if (!BN_copy(x0, &a->X))
737296465Sdelphij            goto err;
738296465Sdelphij        if (!BN_copy(y0, &a->Y))
739296465Sdelphij            goto err;
740296465Sdelphij    } else {
741296465Sdelphij        if (!EC_POINT_get_affine_coordinates_GF2m(group, a, x0, y0, ctx))
742296465Sdelphij            goto err;
743296465Sdelphij    }
744296465Sdelphij    if (b->Z_is_one) {
745296465Sdelphij        if (!BN_copy(x1, &b->X))
746296465Sdelphij            goto err;
747296465Sdelphij        if (!BN_copy(y1, &b->Y))
748296465Sdelphij            goto err;
749296465Sdelphij    } else {
750296465Sdelphij        if (!EC_POINT_get_affine_coordinates_GF2m(group, b, x1, y1, ctx))
751296465Sdelphij            goto err;
752296465Sdelphij    }
753160814Ssimon
754296465Sdelphij    if (BN_GF2m_cmp(x0, x1)) {
755296465Sdelphij        if (!BN_GF2m_add(t, x0, x1))
756296465Sdelphij            goto err;
757296465Sdelphij        if (!BN_GF2m_add(s, y0, y1))
758296465Sdelphij            goto err;
759296465Sdelphij        if (!group->meth->field_div(group, s, s, t, ctx))
760296465Sdelphij            goto err;
761296465Sdelphij        if (!group->meth->field_sqr(group, x2, s, ctx))
762296465Sdelphij            goto err;
763296465Sdelphij        if (!BN_GF2m_add(x2, x2, &group->a))
764296465Sdelphij            goto err;
765296465Sdelphij        if (!BN_GF2m_add(x2, x2, s))
766296465Sdelphij            goto err;
767296465Sdelphij        if (!BN_GF2m_add(x2, x2, t))
768296465Sdelphij            goto err;
769296465Sdelphij    } else {
770296465Sdelphij        if (BN_GF2m_cmp(y0, y1) || BN_is_zero(x1)) {
771296465Sdelphij            if (!EC_POINT_set_to_infinity(group, r))
772296465Sdelphij                goto err;
773296465Sdelphij            ret = 1;
774296465Sdelphij            goto err;
775296465Sdelphij        }
776296465Sdelphij        if (!group->meth->field_div(group, s, y1, x1, ctx))
777296465Sdelphij            goto err;
778296465Sdelphij        if (!BN_GF2m_add(s, s, x1))
779296465Sdelphij            goto err;
780160814Ssimon
781296465Sdelphij        if (!group->meth->field_sqr(group, x2, s, ctx))
782296465Sdelphij            goto err;
783296465Sdelphij        if (!BN_GF2m_add(x2, x2, s))
784296465Sdelphij            goto err;
785296465Sdelphij        if (!BN_GF2m_add(x2, x2, &group->a))
786296465Sdelphij            goto err;
787296465Sdelphij    }
788160814Ssimon
789296465Sdelphij    if (!BN_GF2m_add(y2, x1, x2))
790296465Sdelphij        goto err;
791296465Sdelphij    if (!group->meth->field_mul(group, y2, y2, s, ctx))
792296465Sdelphij        goto err;
793296465Sdelphij    if (!BN_GF2m_add(y2, y2, x2))
794296465Sdelphij        goto err;
795296465Sdelphij    if (!BN_GF2m_add(y2, y2, y1))
796296465Sdelphij        goto err;
797160814Ssimon
798296465Sdelphij    if (!EC_POINT_set_affine_coordinates_GF2m(group, r, x2, y2, ctx))
799296465Sdelphij        goto err;
800160814Ssimon
801296465Sdelphij    ret = 1;
802296465Sdelphij
803160814Ssimon err:
804296465Sdelphij    BN_CTX_end(ctx);
805296465Sdelphij    if (new_ctx != NULL)
806296465Sdelphij        BN_CTX_free(new_ctx);
807296465Sdelphij    return ret;
808296465Sdelphij}
809160814Ssimon
810296465Sdelphij/*
811296465Sdelphij * Computes 2 * a and stores the result in r.  r could be a. Uses algorithm
812296465Sdelphij * A.10.2 of IEEE P1363.
813160814Ssimon */
814296465Sdelphijint ec_GF2m_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a,
815296465Sdelphij                       BN_CTX *ctx)
816296465Sdelphij{
817296465Sdelphij    return ec_GF2m_simple_add(group, r, a, a, ctx);
818296465Sdelphij}
819160814Ssimon
820160814Ssimonint ec_GF2m_simple_invert(const EC_GROUP *group, EC_POINT *point, BN_CTX *ctx)
821296465Sdelphij{
822296465Sdelphij    if (EC_POINT_is_at_infinity(group, point) || BN_is_zero(&point->Y))
823296465Sdelphij        /* point is its own inverse */
824296465Sdelphij        return 1;
825160814Ssimon
826296465Sdelphij    if (!EC_POINT_make_affine(group, point, ctx))
827296465Sdelphij        return 0;
828296465Sdelphij    return BN_GF2m_add(&point->Y, &point->X, &point->Y);
829296465Sdelphij}
830160814Ssimon
831160814Ssimon/* Indicates whether the given point is the point at infinity. */
832296465Sdelphijint ec_GF2m_simple_is_at_infinity(const EC_GROUP *group,
833296465Sdelphij                                  const EC_POINT *point)
834296465Sdelphij{
835296465Sdelphij    return BN_is_zero(&point->Z);
836296465Sdelphij}
837160814Ssimon
838296465Sdelphij/*-
839296465Sdelphij * Determines whether the given EC_POINT is an actual point on the curve defined
840160814Ssimon * in the EC_GROUP.  A point is valid if it satisfies the Weierstrass equation:
841160814Ssimon *      y^2 + x*y = x^3 + a*x^2 + b.
842160814Ssimon */
843296465Sdelphijint ec_GF2m_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point,
844296465Sdelphij                               BN_CTX *ctx)
845296465Sdelphij{
846296465Sdelphij    int ret = -1;
847296465Sdelphij    BN_CTX *new_ctx = NULL;
848296465Sdelphij    BIGNUM *lh, *y2;
849296465Sdelphij    int (*field_mul) (const EC_GROUP *, BIGNUM *, const BIGNUM *,
850296465Sdelphij                      const BIGNUM *, BN_CTX *);
851296465Sdelphij    int (*field_sqr) (const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *);
852160814Ssimon
853296465Sdelphij    if (EC_POINT_is_at_infinity(group, point))
854296465Sdelphij        return 1;
855160814Ssimon
856296465Sdelphij    field_mul = group->meth->field_mul;
857296465Sdelphij    field_sqr = group->meth->field_sqr;
858160814Ssimon
859296465Sdelphij    /* only support affine coordinates */
860296465Sdelphij    if (!point->Z_is_one)
861296465Sdelphij        return -1;
862160814Ssimon
863296465Sdelphij    if (ctx == NULL) {
864296465Sdelphij        ctx = new_ctx = BN_CTX_new();
865296465Sdelphij        if (ctx == NULL)
866296465Sdelphij            return -1;
867296465Sdelphij    }
868160814Ssimon
869296465Sdelphij    BN_CTX_start(ctx);
870296465Sdelphij    y2 = BN_CTX_get(ctx);
871296465Sdelphij    lh = BN_CTX_get(ctx);
872296465Sdelphij    if (lh == NULL)
873296465Sdelphij        goto err;
874160814Ssimon
875296465Sdelphij    /*-
876296465Sdelphij     * We have a curve defined by a Weierstrass equation
877296465Sdelphij     *      y^2 + x*y = x^3 + a*x^2 + b.
878296465Sdelphij     *  <=> x^3 + a*x^2 + x*y + b + y^2 = 0
879296465Sdelphij     *  <=> ((x + a) * x + y ) * x + b + y^2 = 0
880296465Sdelphij     */
881296465Sdelphij    if (!BN_GF2m_add(lh, &point->X, &group->a))
882296465Sdelphij        goto err;
883296465Sdelphij    if (!field_mul(group, lh, lh, &point->X, ctx))
884296465Sdelphij        goto err;
885296465Sdelphij    if (!BN_GF2m_add(lh, lh, &point->Y))
886296465Sdelphij        goto err;
887296465Sdelphij    if (!field_mul(group, lh, lh, &point->X, ctx))
888296465Sdelphij        goto err;
889296465Sdelphij    if (!BN_GF2m_add(lh, lh, &group->b))
890296465Sdelphij        goto err;
891296465Sdelphij    if (!field_sqr(group, y2, &point->Y, ctx))
892296465Sdelphij        goto err;
893296465Sdelphij    if (!BN_GF2m_add(lh, lh, y2))
894296465Sdelphij        goto err;
895296465Sdelphij    ret = BN_is_zero(lh);
896160814Ssimon err:
897296465Sdelphij    if (ctx)
898296465Sdelphij        BN_CTX_end(ctx);
899296465Sdelphij    if (new_ctx)
900296465Sdelphij        BN_CTX_free(new_ctx);
901296465Sdelphij    return ret;
902296465Sdelphij}
903160814Ssimon
904296465Sdelphij/*-
905296465Sdelphij * Indicates whether two points are equal.
906160814Ssimon * Return values:
907160814Ssimon *  -1   error
908160814Ssimon *   0   equal (in affine coordinates)
909160814Ssimon *   1   not equal
910160814Ssimon */
911296465Sdelphijint ec_GF2m_simple_cmp(const EC_GROUP *group, const EC_POINT *a,
912296465Sdelphij                       const EC_POINT *b, BN_CTX *ctx)
913296465Sdelphij{
914296465Sdelphij    BIGNUM *aX, *aY, *bX, *bY;
915296465Sdelphij    BN_CTX *new_ctx = NULL;
916296465Sdelphij    int ret = -1;
917160814Ssimon
918296465Sdelphij    if (EC_POINT_is_at_infinity(group, a)) {
919296465Sdelphij        return EC_POINT_is_at_infinity(group, b) ? 0 : 1;
920296465Sdelphij    }
921237998Sjkim
922296465Sdelphij    if (EC_POINT_is_at_infinity(group, b))
923296465Sdelphij        return 1;
924160814Ssimon
925296465Sdelphij    if (a->Z_is_one && b->Z_is_one) {
926296465Sdelphij        return ((BN_cmp(&a->X, &b->X) == 0)
927296465Sdelphij                && BN_cmp(&a->Y, &b->Y) == 0) ? 0 : 1;
928296465Sdelphij    }
929160814Ssimon
930296465Sdelphij    if (ctx == NULL) {
931296465Sdelphij        ctx = new_ctx = BN_CTX_new();
932296465Sdelphij        if (ctx == NULL)
933296465Sdelphij            return -1;
934296465Sdelphij    }
935160814Ssimon
936296465Sdelphij    BN_CTX_start(ctx);
937296465Sdelphij    aX = BN_CTX_get(ctx);
938296465Sdelphij    aY = BN_CTX_get(ctx);
939296465Sdelphij    bX = BN_CTX_get(ctx);
940296465Sdelphij    bY = BN_CTX_get(ctx);
941296465Sdelphij    if (bY == NULL)
942296465Sdelphij        goto err;
943160814Ssimon
944296465Sdelphij    if (!EC_POINT_get_affine_coordinates_GF2m(group, a, aX, aY, ctx))
945296465Sdelphij        goto err;
946296465Sdelphij    if (!EC_POINT_get_affine_coordinates_GF2m(group, b, bX, bY, ctx))
947296465Sdelphij        goto err;
948296465Sdelphij    ret = ((BN_cmp(aX, bX) == 0) && BN_cmp(aY, bY) == 0) ? 0 : 1;
949160814Ssimon
950296465Sdelphij err:
951296465Sdelphij    if (ctx)
952296465Sdelphij        BN_CTX_end(ctx);
953296465Sdelphij    if (new_ctx)
954296465Sdelphij        BN_CTX_free(new_ctx);
955296465Sdelphij    return ret;
956296465Sdelphij}
957160814Ssimon
958160814Ssimon/* Forces the given EC_POINT to internally use affine coordinates. */
959296465Sdelphijint ec_GF2m_simple_make_affine(const EC_GROUP *group, EC_POINT *point,
960296465Sdelphij                               BN_CTX *ctx)
961296465Sdelphij{
962296465Sdelphij    BN_CTX *new_ctx = NULL;
963296465Sdelphij    BIGNUM *x, *y;
964296465Sdelphij    int ret = 0;
965160814Ssimon
966296465Sdelphij    if (point->Z_is_one || EC_POINT_is_at_infinity(group, point))
967296465Sdelphij        return 1;
968160814Ssimon
969296465Sdelphij    if (ctx == NULL) {
970296465Sdelphij        ctx = new_ctx = BN_CTX_new();
971296465Sdelphij        if (ctx == NULL)
972296465Sdelphij            return 0;
973296465Sdelphij    }
974160814Ssimon
975296465Sdelphij    BN_CTX_start(ctx);
976296465Sdelphij    x = BN_CTX_get(ctx);
977296465Sdelphij    y = BN_CTX_get(ctx);
978296465Sdelphij    if (y == NULL)
979296465Sdelphij        goto err;
980160814Ssimon
981296465Sdelphij    if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx))
982296465Sdelphij        goto err;
983296465Sdelphij    if (!BN_copy(&point->X, x))
984296465Sdelphij        goto err;
985296465Sdelphij    if (!BN_copy(&point->Y, y))
986296465Sdelphij        goto err;
987296465Sdelphij    if (!BN_one(&point->Z))
988296465Sdelphij        goto err;
989160814Ssimon
990296465Sdelphij    ret = 1;
991160814Ssimon
992296465Sdelphij err:
993296465Sdelphij    if (ctx)
994296465Sdelphij        BN_CTX_end(ctx);
995296465Sdelphij    if (new_ctx)
996296465Sdelphij        BN_CTX_free(new_ctx);
997296465Sdelphij    return ret;
998296465Sdelphij}
999160814Ssimon
1000296465Sdelphij/*
1001296465Sdelphij * Forces each of the EC_POINTs in the given array to use affine coordinates.
1002296465Sdelphij */
1003296465Sdelphijint ec_GF2m_simple_points_make_affine(const EC_GROUP *group, size_t num,
1004296465Sdelphij                                      EC_POINT *points[], BN_CTX *ctx)
1005296465Sdelphij{
1006296465Sdelphij    size_t i;
1007160814Ssimon
1008296465Sdelphij    for (i = 0; i < num; i++) {
1009296465Sdelphij        if (!group->meth->make_affine(group, points[i], ctx))
1010296465Sdelphij            return 0;
1011296465Sdelphij    }
1012160814Ssimon
1013296465Sdelphij    return 1;
1014296465Sdelphij}
1015296465Sdelphij
1016160814Ssimon/* Wrapper to simple binary polynomial field multiplication implementation. */
1017296465Sdelphijint ec_GF2m_simple_field_mul(const EC_GROUP *group, BIGNUM *r,
1018296465Sdelphij                             const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
1019296465Sdelphij{
1020296465Sdelphij    return BN_GF2m_mod_mul_arr(r, a, b, group->poly, ctx);
1021296465Sdelphij}
1022160814Ssimon
1023160814Ssimon/* Wrapper to simple binary polynomial field squaring implementation. */
1024296465Sdelphijint ec_GF2m_simple_field_sqr(const EC_GROUP *group, BIGNUM *r,
1025296465Sdelphij                             const BIGNUM *a, BN_CTX *ctx)
1026296465Sdelphij{
1027296465Sdelphij    return BN_GF2m_mod_sqr_arr(r, a, group->poly, ctx);
1028296465Sdelphij}
1029160814Ssimon
1030160814Ssimon/* Wrapper to simple binary polynomial field division implementation. */
1031296465Sdelphijint ec_GF2m_simple_field_div(const EC_GROUP *group, BIGNUM *r,
1032296465Sdelphij                             const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
1033296465Sdelphij{
1034296465Sdelphij    return BN_GF2m_mod_div(r, a, b, &group->field, ctx);
1035296465Sdelphij}
1036