1/* Originally written by Bodo Moeller and Nils Larsch for the OpenSSL project.
2 * ====================================================================
3 * Copyright (c) 1998-2005 The OpenSSL Project.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in
14 *    the documentation and/or other materials provided with the
15 *    distribution.
16 *
17 * 3. All advertising materials mentioning features or use of this
18 *    software must display the following acknowledgment:
19 *    "This product includes software developed by the OpenSSL Project
20 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
21 *
22 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
23 *    endorse or promote products derived from this software without
24 *    prior written permission. For written permission, please contact
25 *    openssl-core@openssl.org.
26 *
27 * 5. Products derived from this software may not be called "OpenSSL"
28 *    nor may "OpenSSL" appear in their names without prior written
29 *    permission of the OpenSSL Project.
30 *
31 * 6. Redistributions of any form whatsoever must retain the following
32 *    acknowledgment:
33 *    "This product includes software developed by the OpenSSL Project
34 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
35 *
36 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
37 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
39 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
40 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
42 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
43 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
44 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
45 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
46 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
47 * OF THE POSSIBILITY OF SUCH DAMAGE.
48 * ====================================================================
49 *
50 * This product includes cryptographic software written by Eric Young
51 * (eay@cryptsoft.com).  This product includes software written by Tim
52 * Hudson (tjh@cryptsoft.com).
53 *
54 */
55/* ====================================================================
56 * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
57 *
58 * Portions of the attached software ("Contribution") are developed by
59 * SUN MICROSYSTEMS, INC., and are contributed to the OpenSSL project.
60 *
61 * The Contribution is licensed pursuant to the OpenSSL open source
62 * license provided above.
63 *
64 * The elliptic curve binary polynomial software is originally written by
65 * Sheueling Chang Shantz and Douglas Stebila of Sun Microsystems
66 * Laboratories. */
67
68#include <openssl/ec.h>
69
70#include <openssl/bn.h>
71#include <openssl/err.h>
72#include <openssl/mem.h>
73
74#include "internal.h"
75
76
77const EC_METHOD *EC_GFp_mont_method(void) {
78  static const EC_METHOD ret = {EC_FLAGS_DEFAULT_OCT,
79                                ec_GFp_mont_group_init,
80                                ec_GFp_mont_group_finish,
81                                ec_GFp_mont_group_clear_finish,
82                                ec_GFp_mont_group_copy,
83                                ec_GFp_mont_group_set_curve,
84                                ec_GFp_simple_group_get_curve,
85                                ec_GFp_simple_group_get_degree,
86                                ec_GFp_simple_group_check_discriminant,
87                                ec_GFp_simple_point_init,
88                                ec_GFp_simple_point_finish,
89                                ec_GFp_simple_point_clear_finish,
90                                ec_GFp_simple_point_copy,
91                                ec_GFp_simple_point_set_to_infinity,
92                                ec_GFp_simple_set_Jprojective_coordinates_GFp,
93                                ec_GFp_simple_get_Jprojective_coordinates_GFp,
94                                ec_GFp_simple_point_set_affine_coordinates,
95                                ec_GFp_simple_point_get_affine_coordinates,
96                                0,
97                                0,
98                                0,
99                                ec_GFp_simple_add,
100                                ec_GFp_simple_dbl,
101                                ec_GFp_simple_invert,
102                                ec_GFp_simple_is_at_infinity,
103                                ec_GFp_simple_is_on_curve,
104                                ec_GFp_simple_cmp,
105                                ec_GFp_simple_make_affine,
106                                ec_GFp_simple_points_make_affine,
107                                0 /* mul */,
108                                0 /* precompute_mult */,
109                                0 /* have_precompute_mult */,
110                                ec_GFp_mont_field_mul,
111                                ec_GFp_mont_field_sqr,
112                                0 /* field_div */,
113                                ec_GFp_mont_field_encode,
114                                ec_GFp_mont_field_decode,
115                                ec_GFp_mont_field_set_to_one};
116
117  return &ret;
118}
119
120int ec_GFp_mont_group_init(EC_GROUP *group) {
121  int ok;
122
123  ok = ec_GFp_simple_group_init(group);
124  group->field_data1 = NULL;
125  group->field_data2 = NULL;
126  return ok;
127}
128
129void ec_GFp_mont_group_finish(EC_GROUP *group) {
130  if (group->field_data1 != NULL) {
131    BN_MONT_CTX_free(group->field_data1);
132    group->field_data1 = NULL;
133  }
134  if (group->field_data2 != NULL) {
135    BN_free(group->field_data2);
136    group->field_data2 = NULL;
137  }
138  ec_GFp_simple_group_finish(group);
139}
140
141void ec_GFp_mont_group_clear_finish(EC_GROUP *group) {
142  if (group->field_data1 != NULL) {
143    BN_MONT_CTX_free(group->field_data1);
144    group->field_data1 = NULL;
145  }
146  if (group->field_data2 != NULL) {
147    BN_clear_free(group->field_data2);
148    group->field_data2 = NULL;
149  }
150  ec_GFp_simple_group_clear_finish(group);
151}
152
153int ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src) {
154  if (dest->field_data1 != NULL) {
155    BN_MONT_CTX_free(dest->field_data1);
156    dest->field_data1 = NULL;
157  }
158  if (dest->field_data2 != NULL) {
159    BN_clear_free(dest->field_data2);
160    dest->field_data2 = NULL;
161  }
162
163  if (!ec_GFp_simple_group_copy(dest, src))
164    return 0;
165
166  if (src->field_data1 != NULL) {
167    dest->field_data1 = BN_MONT_CTX_new();
168    if (dest->field_data1 == NULL)
169      return 0;
170    if (!BN_MONT_CTX_copy(dest->field_data1, src->field_data1))
171      goto err;
172  }
173  if (src->field_data2 != NULL) {
174    dest->field_data2 = BN_dup(src->field_data2);
175    if (dest->field_data2 == NULL)
176      goto err;
177  }
178
179  return 1;
180
181err:
182  if (dest->field_data1 != NULL) {
183    BN_MONT_CTX_free(dest->field_data1);
184    dest->field_data1 = NULL;
185  }
186  return 0;
187}
188
189int ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p,
190                                const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
191  BN_CTX *new_ctx = NULL;
192  BN_MONT_CTX *mont = NULL;
193  BIGNUM *one = NULL;
194  int ret = 0;
195
196  if (group->field_data1 != NULL) {
197    BN_MONT_CTX_free(group->field_data1);
198    group->field_data1 = NULL;
199  }
200  if (group->field_data2 != NULL) {
201    BN_free(group->field_data2);
202    group->field_data2 = NULL;
203  }
204
205  if (ctx == NULL) {
206    ctx = new_ctx = BN_CTX_new();
207    if (ctx == NULL)
208      return 0;
209  }
210
211  mont = BN_MONT_CTX_new();
212  if (mont == NULL)
213    goto err;
214  if (!BN_MONT_CTX_set(mont, p, ctx)) {
215    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_group_set_curve, ERR_R_BN_LIB);
216    goto err;
217  }
218  one = BN_new();
219  if (one == NULL)
220    goto err;
221  if (!BN_to_montgomery(one, BN_value_one(), mont, ctx))
222    goto err;
223
224  group->field_data1 = mont;
225  mont = NULL;
226  group->field_data2 = one;
227  one = NULL;
228
229  ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
230
231  if (!ret) {
232    BN_MONT_CTX_free(group->field_data1);
233    group->field_data1 = NULL;
234    BN_free(group->field_data2);
235    group->field_data2 = NULL;
236  }
237
238err:
239  if (new_ctx != NULL)
240    BN_CTX_free(new_ctx);
241  if (mont != NULL)
242    BN_MONT_CTX_free(mont);
243  return ret;
244}
245
246int ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
247                          const BIGNUM *b, BN_CTX *ctx) {
248  if (group->field_data1 == NULL) {
249    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_mul, EC_R_NOT_INITIALIZED);
250    return 0;
251  }
252
253  return BN_mod_mul_montgomery(r, a, b, group->field_data1, ctx);
254}
255
256int ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
257                          BN_CTX *ctx) {
258  if (group->field_data1 == NULL) {
259    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_sqr, EC_R_NOT_INITIALIZED);
260    return 0;
261  }
262
263  return BN_mod_mul_montgomery(r, a, a, group->field_data1, ctx);
264}
265
266int ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
267                             BN_CTX *ctx) {
268  if (group->field_data1 == NULL) {
269    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_encode, EC_R_NOT_INITIALIZED);
270    return 0;
271  }
272
273  return BN_to_montgomery(r, a, (BN_MONT_CTX *)group->field_data1, ctx);
274}
275
276int ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a,
277                             BN_CTX *ctx) {
278  if (group->field_data1 == NULL) {
279    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_decode, EC_R_NOT_INITIALIZED);
280    return 0;
281  }
282
283  return BN_from_montgomery(r, a, group->field_data1, ctx);
284}
285
286int ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r,
287                                 BN_CTX *ctx) {
288  if (group->field_data2 == NULL) {
289    OPENSSL_PUT_ERROR(EC, ec_GFp_mont_field_set_to_one, EC_R_NOT_INITIALIZED);
290    return 0;
291  }
292
293  if (!BN_copy(r, group->field_data2))
294    return 0;
295  return 1;
296}
297