1d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* Originally written by Bodo Moeller for the OpenSSL project.
2d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ====================================================================
3d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
4d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
5d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Redistribution and use in source and binary forms, with or without
6d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * modification, are permitted provided that the following conditions
7d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * are met:
8d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
9d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 1. Redistributions of source code must retain the above copyright
10d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer.
11d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
12d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 2. Redistributions in binary form must reproduce the above copyright
13d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    notice, this list of conditions and the following disclaimer in
14d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    the documentation and/or other materials provided with the
15d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    distribution.
16d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
17d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 3. All advertising materials mentioning features or use of this
18d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    software must display the following acknowledgment:
19d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes software developed by the OpenSSL Project
20d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
22d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    endorse or promote products derived from this software without
24d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    prior written permission. For written permission, please contact
25d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    openssl-core@openssl.org.
26d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
27d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 5. Products derived from this software may not be called "OpenSSL"
28d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    nor may "OpenSSL" appear in their names without prior written
29d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    permission of the OpenSSL Project.
30d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
31d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * 6. Redistributions of any form whatsoever must retain the following
32d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    acknowledgment:
33d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    "This product includes software developed by the OpenSSL Project
34d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
36d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * OF THE POSSIBILITY OF SUCH DAMAGE.
48d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * ====================================================================
49d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
50d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * This product includes cryptographic software written by Eric Young
51d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * (eay@cryptsoft.com).  This product includes software written by Tim
52d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Hudson (tjh@cryptsoft.com).
53d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
54d9e397b599b13d642138480a28c14db7a136bf0Adam Langley */
55d9e397b599b13d642138480a28c14db7a136bf0Adam Langley/* ====================================================================
56d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
57d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
58d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Portions of the attached software ("Contribution") are developed by
59d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
60d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
61d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * The Contribution is licensed pursuant to the OpenSSL open source
62d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * license provided above.
63d9e397b599b13d642138480a28c14db7a136bf0Adam Langley *
64d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * The elliptic curve binary polynomial software is originally written by
65d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
66d9e397b599b13d642138480a28c14db7a136bf0Adam Langley * Laboratories. */
67d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
68d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/ec.h>
69d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
70d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/bn.h>
71d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include <openssl/err.h>
72d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
73d9e397b599b13d642138480a28c14db7a136bf0Adam Langley#include "internal.h"
74d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
75d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
76d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic size_t ec_GFp_simple_point2oct(const EC_GROUP *group,
77d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                      const EC_POINT *point,
78d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                      point_conversion_form_t form,
79d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                      uint8_t *buf, size_t len, BN_CTX *ctx) {
80d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  size_t ret;
81d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BN_CTX *new_ctx = NULL;
82d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int used_ctx = 0;
83d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIGNUM *x, *y;
84d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  size_t field_len, i;
85d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
86d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if ((form != POINT_CONVERSION_COMPRESSED) &&
87d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      (form != POINT_CONVERSION_UNCOMPRESSED)) {
88b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_FORM);
89d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
90d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
91d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
92d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (EC_POINT_is_at_infinity(group, point)) {
934139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley    OPENSSL_PUT_ERROR(EC, EC_R_POINT_AT_INFINITY);
944139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley    goto err;
95d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
96d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
97d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* ret := required output buffer length */
98d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  field_len = BN_num_bytes(&group->field);
99d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret =
100d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
101d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
102d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* if 'buf' is NULL, just return required length */
103d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (buf != NULL) {
104d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (len < ret) {
105b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
106d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
107d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
108d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
109d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (ctx == NULL) {
110d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      ctx = new_ctx = BN_CTX_new();
111d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (ctx == NULL) {
1124139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley        goto err;
113d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
114d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
115d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
116d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    BN_CTX_start(ctx);
117d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    used_ctx = 1;
118d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    x = BN_CTX_get(ctx);
119d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    y = BN_CTX_get(ctx);
120d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (y == NULL) {
121d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
122d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
123d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
124d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!EC_POINT_get_affine_coordinates_GFp(group, point, x, y, ctx)) {
125d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
126d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
127d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
128d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if ((form == POINT_CONVERSION_COMPRESSED) &&
129d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        BN_is_odd(y)) {
130d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      buf[0] = form + 1;
131d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    } else {
132d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      buf[0] = form;
133d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
134d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    i = 1;
135d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
136d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!BN_bn2bin_padded(buf + i, field_len, x)) {
137b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
138d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
139d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
140d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    i += field_len;
141d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
142d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (form == POINT_CONVERSION_UNCOMPRESSED) {
143d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (!BN_bn2bin_padded(buf + i, field_len, y)) {
144b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root        OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
145d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        goto err;
146d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
147d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      i += field_len;
148d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
149d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
150d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (i != ret) {
151b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
152d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
153d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
154d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
155d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
156d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (used_ctx) {
157d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    BN_CTX_end(ctx);
158d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
159e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  BN_CTX_free(new_ctx);
160d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
161d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
162d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyerr:
163d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (used_ctx) {
164d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    BN_CTX_end(ctx);
165d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
166e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  BN_CTX_free(new_ctx);
167d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return 0;
168d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
169d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
170d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
171d9e397b599b13d642138480a28c14db7a136bf0Adam Langleystatic int ec_GFp_simple_oct2point(const EC_GROUP *group, EC_POINT *point,
172d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                   const uint8_t *buf, size_t len,
173d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                   BN_CTX *ctx) {
174d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  point_conversion_form_t form;
175d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int y_bit;
176d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BN_CTX *new_ctx = NULL;
177d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIGNUM *x, *y;
178d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  size_t field_len, enc_len;
179d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int ret = 0;
180d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
181d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (len == 0) {
182b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_BUFFER_TOO_SMALL);
183d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
184d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
185d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  form = buf[0];
186d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  y_bit = form & 1;
187d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  form = form & ~1U;
1884139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley  if ((form != POINT_CONVERSION_COMPRESSED &&
1894139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley       form != POINT_CONVERSION_UNCOMPRESSED) ||
1904139edb02e59e7ad48e0a8f4c02e45923bc8a344Adam Langley      (form == POINT_CONVERSION_UNCOMPRESSED && y_bit)) {
191b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
192d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
193d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
194d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
195d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  field_len = BN_num_bytes(&group->field);
196d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  enc_len =
197d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      (form == POINT_CONVERSION_COMPRESSED) ? 1 + field_len : 1 + 2 * field_len;
198d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
199d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (len != enc_len) {
200b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
201d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
202d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
203d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
204d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (ctx == NULL) {
205d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ctx = new_ctx = BN_CTX_new();
206e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    if (ctx == NULL) {
207d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return 0;
208e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    }
209d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
210d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
211d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BN_CTX_start(ctx);
212d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  x = BN_CTX_get(ctx);
213d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  y = BN_CTX_get(ctx);
214b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root  if (x == NULL || y == NULL) {
215d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
216e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
217d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
218e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  if (!BN_bin2bn(buf + 1, field_len, x)) {
219d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
220e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
221d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (BN_ucmp(x, &group->field) >= 0) {
222b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
223d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
224d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
225d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
226d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (form == POINT_CONVERSION_COMPRESSED) {
227e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    if (!EC_POINT_set_compressed_coordinates_GFp(group, point, x, y_bit, ctx)) {
228d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
229e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    }
230d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } else {
231e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    if (!BN_bin2bn(buf + 1 + field_len, field_len, y)) {
232d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
233e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    }
234d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (BN_ucmp(y, &group->field) >= 0) {
235b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      OPENSSL_PUT_ERROR(EC, EC_R_INVALID_ENCODING);
236d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
237d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
238d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
239e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
240d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
241e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley    }
242d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
243d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
244d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret = 1;
245d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
246d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyerr:
247d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BN_CTX_end(ctx);
248e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  BN_CTX_free(new_ctx);
249d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
250d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
251d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
252d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint EC_POINT_oct2point(const EC_GROUP *group, EC_POINT *point,
253d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                       const uint8_t *buf, size_t len, BN_CTX *ctx) {
254d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (group->meth != point->meth) {
255b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
256d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
257d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
258e99801b603dea8893dcc61c70b327ef2d00b652cKenny Root  return ec_GFp_simple_oct2point(group, point, buf, len, ctx);
259d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
260d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
261d9e397b599b13d642138480a28c14db7a136bf0Adam Langleysize_t EC_POINT_point2oct(const EC_GROUP *group, const EC_POINT *point,
262d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                          point_conversion_form_t form, uint8_t *buf,
263d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                          size_t len, BN_CTX *ctx) {
264d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (group->meth != point->meth) {
265b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
266d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
267d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
268e99801b603dea8893dcc61c70b327ef2d00b652cKenny Root  return ec_GFp_simple_point2oct(group, point, form, buf, len, ctx);
269d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
270d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
271d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint ec_GFp_simple_set_compressed_coordinates(const EC_GROUP *group,
272d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                             EC_POINT *point, const BIGNUM *x_,
273d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                             int y_bit, BN_CTX *ctx) {
274d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BN_CTX *new_ctx = NULL;
275d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BIGNUM *tmp1, *tmp2, *x, *y;
276d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  int ret = 0;
277d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
278d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ERR_clear_error();
279d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
280d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (ctx == NULL) {
281d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    ctx = new_ctx = BN_CTX_new();
282d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (ctx == NULL) {
283d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      return 0;
284d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
285d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
286d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
287d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  y_bit = (y_bit != 0);
288d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
289d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BN_CTX_start(ctx);
290d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  tmp1 = BN_CTX_get(ctx);
291d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  tmp2 = BN_CTX_get(ctx);
292d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  x = BN_CTX_get(ctx);
293d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  y = BN_CTX_get(ctx);
294d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (y == NULL) {
295d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
296d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
297d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
298d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* Recover y.  We have a Weierstrass equation
299d9e397b599b13d642138480a28c14db7a136bf0Adam Langley   *     y^2 = x^3 + a*x + b,
300d9e397b599b13d642138480a28c14db7a136bf0Adam Langley   * so  y  is one of the square roots of  x^3 + a*x + b. */
301d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
302d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* tmp1 := x^3 */
303d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!BN_nnmod(x, x_, &group->field, ctx)) {
304d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
305d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
306d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
307d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (group->meth->field_decode == 0) {
308d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    /* field_{sqr,mul} work on standard representation */
309d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!group->meth->field_sqr(group, tmp2, x_, ctx) ||
310d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        !group->meth->field_mul(group, tmp1, tmp2, x_, ctx)) {
311d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
312d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
313d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } else {
314d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!BN_mod_sqr(tmp2, x_, &group->field, ctx) ||
315d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        !BN_mod_mul(tmp1, tmp2, x_, &group->field, ctx)) {
316d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
317d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
318d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
319d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
320d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* tmp1 := tmp1 + a*x */
321d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (group->a_is_minus3) {
322d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!BN_mod_lshift1_quick(tmp2, x, &group->field) ||
323d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        !BN_mod_add_quick(tmp2, tmp2, x, &group->field) ||
324d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        !BN_mod_sub_quick(tmp1, tmp1, tmp2, &group->field)) {
325d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
326d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
327d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } else {
328d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (group->meth->field_decode) {
329d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (!group->meth->field_decode(group, tmp2, &group->a, ctx) ||
330d9e397b599b13d642138480a28c14db7a136bf0Adam Langley          !BN_mod_mul(tmp2, tmp2, x, &group->field, ctx)) {
331d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        goto err;
332d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
333d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    } else {
334d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      /* field_mul works on standard representation */
335d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (!group->meth->field_mul(group, tmp2, &group->a, x, ctx)) {
336d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        goto err;
337d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
338d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
339d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
340d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
341d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
342d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
343d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
344d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
345d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  /* tmp1 := tmp1 + b */
346d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (group->meth->field_decode) {
347d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!group->meth->field_decode(group, tmp2, &group->b, ctx) ||
348d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        !BN_mod_add_quick(tmp1, tmp1, tmp2, &group->field)) {
349d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
350d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
351d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  } else {
352d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!BN_mod_add_quick(tmp1, tmp1, &group->b, &group->field)) {
353d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
354d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
355d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
356d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
357d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (!BN_mod_sqrt(y, tmp1, &group->field, ctx)) {
358d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    unsigned long err = ERR_peek_last_error();
359d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
360d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (ERR_GET_LIB(err) == ERR_LIB_BN &&
361d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        ERR_GET_REASON(err) == BN_R_NOT_A_SQUARE) {
362d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      ERR_clear_error();
363b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
364d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    } else {
365b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root      OPENSSL_PUT_ERROR(EC, ERR_R_BN_LIB);
366d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
367d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
368d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
369d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
370d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (y_bit != BN_is_odd(y)) {
371d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (BN_is_zero(y)) {
372d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      int kron;
373d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
374d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      kron = BN_kronecker(x, &group->field, ctx);
375d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (kron == -2) {
376d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        goto err;
377d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
378d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
379d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      if (kron == 1) {
380b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root        OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSION_BIT);
381d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      } else {
382d9e397b599b13d642138480a28c14db7a136bf0Adam Langley        /* BN_mod_sqrt() should have cought this error (not a square) */
383b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root        OPENSSL_PUT_ERROR(EC, EC_R_INVALID_COMPRESSED_POINT);
384d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      }
385d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
386d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
387d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    if (!BN_usub(y, &group->field, y)) {
388d9e397b599b13d642138480a28c14db7a136bf0Adam Langley      goto err;
389d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    }
390d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
391d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (y_bit != BN_is_odd(y)) {
392b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
393d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
394d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
395d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
396e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  if (!EC_POINT_set_affine_coordinates_GFp(group, point, x, y, ctx)) {
397d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    goto err;
398e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  }
399d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
400d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  ret = 1;
401d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
402d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyerr:
403d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  BN_CTX_end(ctx);
404e9ada863a7b3e81f5d2b1e3bdd2305da902a87f5Adam Langley  BN_CTX_free(new_ctx);
405d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  return ret;
406d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
407d9e397b599b13d642138480a28c14db7a136bf0Adam Langley
408d9e397b599b13d642138480a28c14db7a136bf0Adam Langleyint EC_POINT_set_compressed_coordinates_GFp(const EC_GROUP *group,
409d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                            EC_POINT *point, const BIGNUM *x,
410d9e397b599b13d642138480a28c14db7a136bf0Adam Langley                                            int y_bit, BN_CTX *ctx) {
411d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  if (group->meth != point->meth) {
412b8494591d1b1a143f3b192d845c238bbf3bc629dKenny Root    OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
413d9e397b599b13d642138480a28c14db7a136bf0Adam Langley    return 0;
414d9e397b599b13d642138480a28c14db7a136bf0Adam Langley  }
415e99801b603dea8893dcc61c70b327ef2d00b652cKenny Root  return ec_GFp_simple_set_compressed_coordinates(group, point, x, y_bit, ctx);
416d9e397b599b13d642138480a28c14db7a136bf0Adam Langley}
417