2 * Copyright 2011-2016 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 /* ====================================================================
11 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
13 * The Elliptic Curve Public-Key Crypto Library (ECC Code) included
14 * herein is developed by SUN MICROSYSTEMS, INC., and is contributed
15 * to the OpenSSL project.
17 * The ECC Code is licensed pursuant to the OpenSSL open source
18 * license provided below.
20 * The software is originally written by Sheueling Chang Shantz and
21 * Douglas Stebila of Sun Microsystems Laboratories.
25 #include <openssl/err.h>
29 #ifndef OPENSSL_NO_EC2M
32 * Calculates and sets the affine coordinates of an EC_POINT from the given
33 * compressed coordinates. Uses algorithm 2.3.4 of SEC 1.
34 * Note that the simple implementation only uses affine coordinates.
36 * The method is from the following publication:
38 * Harper, Menezes, Vanstone:
39 * "Public-Key Cryptosystems with Very Small Key Lengths",
40 * EUROCRYPT '92, Springer-Verlag LNCS 658,
41 * published February 1993
43 * US Patents 6,141,420 and 6,618,483 (Vanstone, Mullin, Agnew) describe
44 * the same method, but claim no priority date earlier than July 29, 1994
45 * (and additionally fail to cite the EUROCRYPT '92 publication as prior art).
47 int ec_GF2m_simple_set_compressed_coordinates(const EC_GROUP *group,
49 const BIGNUM *x_, int y_bit,
52 BN_CTX *new_ctx = NULL;
53 BIGNUM *tmp, *x, *y, *z;
56 /* clear error queue */
60 ctx = new_ctx = BN_CTX_new();
65 y_bit = (y_bit != 0) ? 1 : 0;
68 tmp = BN_CTX_get(ctx);
75 if (!BN_GF2m_mod_arr(x, x_, group->poly))
78 if (!BN_GF2m_mod_sqrt_arr(y, group->b, group->poly, ctx))
81 if (!group->meth->field_sqr(group, tmp, x, ctx))
83 if (!group->meth->field_div(group, tmp, group->b, tmp, ctx))
85 if (!BN_GF2m_add(tmp, group->a, tmp))
87 if (!BN_GF2m_add(tmp, x, tmp))
89 if (!BN_GF2m_mod_solve_quad_arr(z, tmp, group->poly, ctx)) {
90 unsigned long err = ERR_peek_last_error();
92 if (ERR_GET_LIB(err) == ERR_LIB_BN
93 && ERR_GET_REASON(err) == BN_R_NO_SOLUTION) {
95 ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES,
96 EC_R_INVALID_COMPRESSED_POINT);
98 ECerr(EC_F_EC_GF2M_SIMPLE_SET_COMPRESSED_COORDINATES,
102 z0 = (BN_is_odd(z)) ? 1 : 0;
103 if (!group->meth->field_mul(group, y, x, z, ctx))
106 if (!BN_GF2m_add(y, y, x))
111 if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx))
118 BN_CTX_free(new_ctx);
123 * Converts an EC_POINT to an octet string. If buf is NULL, the encoded
124 * length will be returned. If the length len of buf is smaller than required
125 * an error will be returned.
127 size_t ec_GF2m_simple_point2oct(const EC_GROUP *group, const EC_POINT *point,
128 point_conversion_form_t form,
129 unsigned char *buf, size_t len, BN_CTX *ctx)
132 BN_CTX *new_ctx = NULL;
135 size_t field_len, i, skip;
137 if ((form != POINT_CONVERSION_COMPRESSED)
138 && (form != POINT_CONVERSION_UNCOMPRESSED)
139 && (form != POINT_CONVERSION_HYBRID)) {
140 ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_INVALID_FORM);
144 if (EC_POINT_is_at_infinity(group, point)) {
145 /* encodes to a single 0 octet */
148 ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
156 /* ret := required output buffer length */
157 field_len = (EC_GROUP_get_degree(group) + 7) / 8;
160 POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
162 /* if 'buf' is NULL, just return required length */
165 ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, EC_R_BUFFER_TOO_SMALL);
170 ctx = new_ctx = BN_CTX_new();
179 yxi = BN_CTX_get(ctx);
183 if (!EC_POINT_get_affine_coordinates_GF2m(group, point, x, y, ctx))
187 if ((form != POINT_CONVERSION_UNCOMPRESSED) && !BN_is_zero(x)) {
188 if (!group->meth->field_div(group, yxi, y, x, ctx))
196 skip = field_len - BN_num_bytes(x);
197 if (skip > field_len) {
198 ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
205 skip = BN_bn2bin(x, buf + i);
207 if (i != 1 + field_len) {
208 ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
212 if (form == POINT_CONVERSION_UNCOMPRESSED
213 || form == POINT_CONVERSION_HYBRID) {
214 skip = field_len - BN_num_bytes(y);
215 if (skip > field_len) {
216 ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
223 skip = BN_bn2bin(y, buf + i);
228 ECerr(EC_F_EC_GF2M_SIMPLE_POINT2OCT, ERR_R_INTERNAL_ERROR);
235 BN_CTX_free(new_ctx);
241 BN_CTX_free(new_ctx);
246 * Converts an octet string representation to an EC_POINT. Note that the
247 * simple implementation only uses affine coordinates.
249 int ec_GF2m_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
250 const unsigned char *buf, size_t len,
253 point_conversion_form_t form;
255 BN_CTX *new_ctx = NULL;
257 size_t field_len, enc_len;
261 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_BUFFER_TOO_SMALL);
267 if ((form != 0) && (form != POINT_CONVERSION_COMPRESSED)
268 && (form != POINT_CONVERSION_UNCOMPRESSED)
269 && (form != POINT_CONVERSION_HYBRID)) {
270 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
273 if ((form == 0 || form == POINT_CONVERSION_UNCOMPRESSED) && y_bit) {
274 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
280 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
284 return EC_POINT_set_to_infinity(group, point);
287 field_len = (EC_GROUP_get_degree(group) + 7) / 8;
290 POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
292 if (len != enc_len) {
293 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
298 ctx = new_ctx = BN_CTX_new();
306 yxi = BN_CTX_get(ctx);
310 if (!BN_bin2bn(buf + 1, field_len, x))
312 if (BN_ucmp(x, group->field) >= 0) {
313 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
317 if (form == POINT_CONVERSION_COMPRESSED) {
318 if (!EC_POINT_set_compressed_coordinates_GF2m
319 (group, point, x, y_bit, ctx))
322 if (!BN_bin2bn(buf + 1 + field_len, field_len, y))
324 if (BN_ucmp(y, group->field) >= 0) {
325 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
328 if (form == POINT_CONVERSION_HYBRID) {
329 if (!group->meth->field_div(group, yxi, y, x, ctx))
331 if (y_bit != BN_is_odd(yxi)) {
332 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_INVALID_ENCODING);
337 if (!EC_POINT_set_affine_coordinates_GF2m(group, point, x, y, ctx))
341 /* test required by X9.62 */
342 if (EC_POINT_is_on_curve(group, point, ctx) <= 0) {
343 ECerr(EC_F_EC_GF2M_SIMPLE_OCT2POINT, EC_R_POINT_IS_NOT_ON_CURVE);
351 BN_CTX_free(new_ctx);