ecp_mont.c revision 160815
1239268Sgonzo/* crypto/ec/ecp_mont.c */
2289865Sian/*
3239268Sgonzo * Originally written by Bodo Moeller for the OpenSSL project.
4239268Sgonzo */
5239268Sgonzo/* ====================================================================
6239268Sgonzo * Copyright (c) 1998-2001 The OpenSSL Project.  All rights reserved.
7239268Sgonzo *
8239268Sgonzo * Redistribution and use in source and binary forms, with or without
9239268Sgonzo * modification, are permitted provided that the following conditions
10239268Sgonzo * are met:
11239268Sgonzo *
12239268Sgonzo * 1. Redistributions of source code must retain the above copyright
13239268Sgonzo *    notice, this list of conditions and the following disclaimer.
14239268Sgonzo *
15239268Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
16239268Sgonzo *    notice, this list of conditions and the following disclaimer in
17239268Sgonzo *    the documentation and/or other materials provided with the
18239268Sgonzo *    distribution.
19239268Sgonzo *
20239268Sgonzo * 3. All advertising materials mentioning features or use of this
21239268Sgonzo *    software must display the following acknowledgment:
22239268Sgonzo *    "This product includes software developed by the OpenSSL Project
23239268Sgonzo *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
24239268Sgonzo *
25239268Sgonzo * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
26239268Sgonzo *    endorse or promote products derived from this software without
27239268Sgonzo *    prior written permission. For written permission, please contact
28239268Sgonzo *    openssl-core@openssl.org.
29239268Sgonzo *
30239268Sgonzo * 5. Products derived from this software may not be called "OpenSSL"
31239268Sgonzo *    nor may "OpenSSL" appear in their names without prior written
32239268Sgonzo *    permission of the OpenSSL Project.
33239268Sgonzo *
34239268Sgonzo * 6. Redistributions of any form whatsoever must retain the following
35239268Sgonzo *    acknowledgment:
36239268Sgonzo *    "This product includes software developed by the OpenSSL Project
37239268Sgonzo *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
38239268Sgonzo *
39239268Sgonzo * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
40239268Sgonzo * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41244469Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
42269321Sian * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
43239268Sgonzo * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
44239268Sgonzo * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
45239268Sgonzo * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
46239268Sgonzo * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47246713Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
48239268Sgonzo * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
49239268Sgonzo * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
50246713Skib * OF THE POSSIBILITY OF SUCH DAMAGE.
51239268Sgonzo * ====================================================================
52239268Sgonzo *
53239268Sgonzo * This product includes cryptographic software written by Eric Young
54239268Sgonzo * (eay@cryptsoft.com).  This product includes software written by Tim
55239268Sgonzo * Hudson (tjh@cryptsoft.com).
56244469Scognet *
57244469Scognet */
58239268Sgonzo/* ====================================================================
59239268Sgonzo * Copyright 2002 Sun Microsystems, Inc. ALL RIGHTS RESERVED.
60239268Sgonzo * Portions of this software developed by SUN MICROSYSTEMS, INC.,
61289759Sjah * and contributed to the OpenSSL project.
62239268Sgonzo */
63239268Sgonzo
64289851Sian#include <openssl/err.h>
65289851Sian
66289851Sian#include "ec_lcl.h"
67289851Sian
68289851Sian
69289851Sianconst EC_METHOD *EC_GFp_mont_method(void)
70239268Sgonzo	{
71239268Sgonzo	static const EC_METHOD ret = {
72239268Sgonzo		NID_X9_62_prime_field,
73239268Sgonzo		ec_GFp_mont_group_init,
74289851Sian		ec_GFp_mont_group_finish,
75289851Sian		ec_GFp_mont_group_clear_finish,
76289854Sian		ec_GFp_mont_group_copy,
77289851Sian		ec_GFp_mont_group_set_curve,
78289851Sian		ec_GFp_simple_group_get_curve,
79289851Sian		ec_GFp_simple_group_get_degree,
80289851Sian		ec_GFp_simple_group_check_discriminant,
81289851Sian		ec_GFp_simple_point_init,
82289851Sian		ec_GFp_simple_point_finish,
83289851Sian		ec_GFp_simple_point_clear_finish,
84289851Sian		ec_GFp_simple_point_copy,
85289851Sian		ec_GFp_simple_point_set_to_infinity,
86289851Sian		ec_GFp_simple_set_Jprojective_coordinates_GFp,
87289851Sian		ec_GFp_simple_get_Jprojective_coordinates_GFp,
88289851Sian		ec_GFp_simple_point_set_affine_coordinates,
89289851Sian		ec_GFp_simple_point_get_affine_coordinates,
90239268Sgonzo		ec_GFp_simple_set_compressed_coordinates,
91239268Sgonzo		ec_GFp_simple_point2oct,
92239268Sgonzo		ec_GFp_simple_oct2point,
93239268Sgonzo		ec_GFp_simple_add,
94239268Sgonzo		ec_GFp_simple_dbl,
95239268Sgonzo		ec_GFp_simple_invert,
96239268Sgonzo		ec_GFp_simple_is_at_infinity,
97239268Sgonzo		ec_GFp_simple_is_on_curve,
98239268Sgonzo		ec_GFp_simple_cmp,
99239268Sgonzo		ec_GFp_simple_make_affine,
100239268Sgonzo		ec_GFp_simple_points_make_affine,
101239268Sgonzo		0 /* mul */,
102239268Sgonzo		0 /* precompute_mult */,
103239268Sgonzo		0 /* have_precompute_mult */,
104289759Sjah		ec_GFp_mont_field_mul,
105289759Sjah		ec_GFp_mont_field_sqr,
106239268Sgonzo		0 /* field_div */,
107239268Sgonzo		ec_GFp_mont_field_encode,
108239268Sgonzo		ec_GFp_mont_field_decode,
109239268Sgonzo		ec_GFp_mont_field_set_to_one };
110239268Sgonzo
111286968Sian	return &ret;
112289759Sjah	}
113289759Sjah
114239268Sgonzo
115239268Sgonzoint ec_GFp_mont_group_init(EC_GROUP *group)
116239268Sgonzo	{
117239268Sgonzo	int ok;
118239268Sgonzo
119239268Sgonzo	ok = ec_GFp_simple_group_init(group);
120239268Sgonzo	group->field_data1 = NULL;
121239268Sgonzo	group->field_data2 = NULL;
122239268Sgonzo	return ok;
123239268Sgonzo	}
124239268Sgonzo
125239268Sgonzo
126239268Sgonzovoid ec_GFp_mont_group_finish(EC_GROUP *group)
127239268Sgonzo	{
128239268Sgonzo	if (group->field_data1 != NULL)
129239268Sgonzo		{
130239268Sgonzo		BN_MONT_CTX_free(group->field_data1);
131239268Sgonzo		group->field_data1 = NULL;
132239268Sgonzo		}
133239268Sgonzo	if (group->field_data2 != NULL)
134239268Sgonzo		{
135239268Sgonzo		BN_free(group->field_data2);
136239268Sgonzo		group->field_data2 = NULL;
137239268Sgonzo		}
138239268Sgonzo	ec_GFp_simple_group_finish(group);
139239268Sgonzo	}
140269217Sian
141269217Sian
142269217Sianvoid ec_GFp_mont_group_clear_finish(EC_GROUP *group)
143269217Sian	{
144269321Sian	if (group->field_data1 != NULL)
145269321Sian		{
146269321Sian		BN_MONT_CTX_free(group->field_data1);
147269321Sian		group->field_data1 = NULL;
148269321Sian		}
149269321Sian	if (group->field_data2 != NULL)
150269217Sian		{
151239268Sgonzo		BN_clear_free(group->field_data2);
152239268Sgonzo		group->field_data2 = NULL;
153239268Sgonzo		}
154269217Sian	ec_GFp_simple_group_clear_finish(group);
155269321Sian	}
156269217Sian
157269321Sian
158269217Sianint ec_GFp_mont_group_copy(EC_GROUP *dest, const EC_GROUP *src)
159269321Sian	{
160269217Sian	if (dest->field_data1 != NULL)
161269321Sian		{
162283366Sandrew		BN_MONT_CTX_free(dest->field_data1);
163269321Sian		dest->field_data1 = NULL;
164269321Sian		}
165269321Sian	if (dest->field_data2 != NULL)
166269321Sian		{
167269321Sian		BN_clear_free(dest->field_data2);
168269321Sian		dest->field_data2 = NULL;
169269321Sian		}
170269321Sian
171269321Sian	if (!ec_GFp_simple_group_copy(dest, src)) return 0;
172269321Sian
173269321Sian	if (src->field_data1 != NULL)
174239268Sgonzo		{
175269321Sian		dest->field_data1 = BN_MONT_CTX_new();
176239268Sgonzo		if (dest->field_data1 == NULL) return 0;
177239268Sgonzo		if (!BN_MONT_CTX_copy(dest->field_data1, src->field_data1)) goto err;
178289851Sian		}
179289851Sian	if (src->field_data2 != NULL)
180289851Sian		{
181289851Sian		dest->field_data2 = BN_dup(src->field_data2);
182289851Sian		if (dest->field_data2 == NULL) goto err;
183289851Sian		}
184289851Sian
185289851Sian	return 1;
186289851Sian
187289851Sian err:
188289851Sian	if (dest->field_data1 != NULL)
189239268Sgonzo		{
190269216Sian		BN_MONT_CTX_free(dest->field_data1);
191289851Sian		dest->field_data1 = NULL;
192289851Sian		}
193239268Sgonzo	return 0;
194239268Sgonzo	}
195239268Sgonzo
196239268Sgonzo
197239268Sgonzoint ec_GFp_mont_group_set_curve(EC_GROUP *group, const BIGNUM *p, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
198239268Sgonzo	{
199239268Sgonzo	BN_CTX *new_ctx = NULL;
200239268Sgonzo	BN_MONT_CTX *mont = NULL;
201239268Sgonzo	BIGNUM *one = NULL;
202289851Sian	int ret = 0;
203239268Sgonzo
204289851Sian	if (group->field_data1 != NULL)
205239268Sgonzo		{
206289759Sjah		BN_MONT_CTX_free(group->field_data1);
207289759Sjah		group->field_data1 = NULL;
208246713Skib		}
209246713Skib	if (group->field_data2 != NULL)
210246713Skib		{
211246713Skib		BN_free(group->field_data2);
212289759Sjah		group->field_data2 = NULL;
213289759Sjah		}
214239268Sgonzo
215244469Scognet	if (ctx == NULL)
216244469Scognet		{
217289858Sian		ctx = new_ctx = BN_CTX_new();
218289858Sian		if (ctx == NULL)
219289858Sian			return 0;
220289858Sian		}
221244469Scognet
222244469Scognet	mont = BN_MONT_CTX_new();
223244469Scognet	if (mont == NULL) goto err;
224252652Sgonzo	if (!BN_MONT_CTX_set(mont, p, ctx))
225244469Scognet		{
226269321Sian		ECerr(EC_F_EC_GFP_MONT_GROUP_SET_CURVE, ERR_R_BN_LIB);
227269321Sian		goto err;
228269321Sian		}
229269321Sian	one = BN_new();
230269321Sian	if (one == NULL) goto err;
231269321Sian	if (!BN_to_montgomery(one, BN_value_one(), mont, ctx)) goto err;
232269321Sian
233252652Sgonzo	group->field_data1 = mont;
234252652Sgonzo	mont = NULL;
235244469Scognet	group->field_data2 = one;
236283366Sandrew	one = NULL;
237244469Scognet
238283366Sandrew	ret = ec_GFp_simple_group_set_curve(group, p, a, b, ctx);
239244469Scognet
240252652Sgonzo	if (!ret)
241244469Scognet		{
242252652Sgonzo		BN_MONT_CTX_free(group->field_data1);
243283366Sandrew		group->field_data1 = NULL;
244252652Sgonzo		BN_free(group->field_data2);
245252652Sgonzo		group->field_data2 = NULL;
246252652Sgonzo		}
247252652Sgonzo
248252652Sgonzo err:
249252652Sgonzo	if (new_ctx != NULL)
250252652Sgonzo		BN_CTX_free(new_ctx);
251244469Scognet	if (mont != NULL)
252244469Scognet		BN_MONT_CTX_free(mont);
253244469Scognet	return ret;
254244469Scognet	}
255244469Scognet
256244469Scognet
257283366Sandrewint ec_GFp_mont_field_mul(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx)
258283366Sandrew	{
259252652Sgonzo	if (group->field_data1 == NULL)
260244469Scognet		{
261244469Scognet		ECerr(EC_F_EC_GFP_MONT_FIELD_MUL, EC_R_NOT_INITIALIZED);
262244469Scognet		return 0;
263244469Scognet		}
264289858Sian
265269321Sian	return BN_mod_mul_montgomery(r, a, b, group->field_data1, ctx);
266269321Sian	}
267244469Scognet
268269321Sian
269244469Scognetint ec_GFp_mont_field_sqr(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
270269136Sian	{
271269136Sian	if (group->field_data1 == NULL)
272269136Sian		{
273269136Sian		ECerr(EC_F_EC_GFP_MONT_FIELD_SQR, EC_R_NOT_INITIALIZED);
274269136Sian		return 0;
275269136Sian		}
276269136Sian
277269136Sian	return BN_mod_mul_montgomery(r, a, a, group->field_data1, ctx);
278269136Sian	}
279269136Sian
280269136Sian
281269136Sianint ec_GFp_mont_field_encode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
282269206Sian	{
283269207Sian	if (group->field_data1 == NULL)
284239268Sgonzo		{
285239268Sgonzo		ECerr(EC_F_EC_GFP_MONT_FIELD_ENCODE, EC_R_NOT_INITIALIZED);
286269136Sian		return 0;
287269136Sian		}
288269136Sian
289269136Sian	return BN_to_montgomery(r, a, (BN_MONT_CTX *)group->field_data1, ctx);
290239268Sgonzo	}
291269209Sian
292269209Sian
293239268Sgonzoint ec_GFp_mont_field_decode(const EC_GROUP *group, BIGNUM *r, const BIGNUM *a, BN_CTX *ctx)
294239268Sgonzo	{
295239268Sgonzo	if (group->field_data1 == NULL)
296239268Sgonzo		{
297239268Sgonzo		ECerr(EC_F_EC_GFP_MONT_FIELD_DECODE, EC_R_NOT_INITIALIZED);
298269206Sian		return 0;
299269207Sian		}
300269207Sian
301269207Sian	return BN_from_montgomery(r, a, group->field_data1, ctx);
302269207Sian	}
303269207Sian
304269207Sian
305269207Sianint ec_GFp_mont_field_set_to_one(const EC_GROUP *group, BIGNUM *r, BN_CTX *ctx)
306269207Sian	{
307269207Sian	if (group->field_data2 == NULL)
308269207Sian		{
309269206Sian		ECerr(EC_F_EC_GFP_MONT_FIELD_SET_TO_ONE, EC_R_NOT_INITIALIZED);
310269206Sian		return 0;
311269206Sian		}
312269206Sian
313269206Sian	if (!BN_copy(r, group->field_data2)) return 0;
314269206Sian	return 1;
315269206Sian	}
316269206Sian