xref: /freebsd/crypto/libecc/src/curves/aff_pt_montgomery.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans  *  Copyright (C) 2021 - This file is part of libecc project
3*f0865ec9SKyle Evans  *
4*f0865ec9SKyle Evans  *  Authors:
5*f0865ec9SKyle Evans  *      Ryad BENADJILA <ryadbenadjila@gmail.com>
6*f0865ec9SKyle Evans  *      Arnaud EBALARD <arnaud.ebalard@ssi.gouv.fr>
7*f0865ec9SKyle Evans  *
8*f0865ec9SKyle Evans  *  This software is licensed under a dual BSD and GPL v2 license.
9*f0865ec9SKyle Evans  *  See LICENSE file at the root folder of the project.
10*f0865ec9SKyle Evans  */
11*f0865ec9SKyle Evans #include <libecc/curves/aff_pt.h>
12*f0865ec9SKyle Evans 
13*f0865ec9SKyle Evans #define AFF_PT_MONTGOMERY_MAGIC ((word_t)(0x7390a9bc43d94598ULL))
14*f0865ec9SKyle Evans 
15*f0865ec9SKyle Evans /* Verify that an affine point has already been initialized.
16*f0865ec9SKyle Evans  *
17*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
18*f0865ec9SKyle Evans  */
aff_pt_montgomery_check_initialized(aff_pt_montgomery_src_t in)19*f0865ec9SKyle Evans int aff_pt_montgomery_check_initialized(aff_pt_montgomery_src_t in)
20*f0865ec9SKyle Evans {
21*f0865ec9SKyle Evans 	int ret;
22*f0865ec9SKyle Evans 
23*f0865ec9SKyle Evans 	MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_MONTGOMERY_MAGIC)), ret, err);
24*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(in->crv);
25*f0865ec9SKyle Evans 
26*f0865ec9SKyle Evans err:
27*f0865ec9SKyle Evans 	return ret;
28*f0865ec9SKyle Evans }
29*f0865ec9SKyle Evans 
30*f0865ec9SKyle Evans /*
31*f0865ec9SKyle Evans  * Initialize pointed aff_pt_montgomery structure to make it usable by library
32*f0865ec9SKyle Evans  * function on given curve.
33*f0865ec9SKyle Evans  *
34*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
35*f0865ec9SKyle Evans  */
aff_pt_montgomery_init(aff_pt_montgomery_t in,ec_montgomery_crv_src_t curve)36*f0865ec9SKyle Evans int aff_pt_montgomery_init(aff_pt_montgomery_t in, ec_montgomery_crv_src_t curve)
37*f0865ec9SKyle Evans {
38*f0865ec9SKyle Evans 	int ret;
39*f0865ec9SKyle Evans 
40*f0865ec9SKyle Evans 	MUST_HAVE((in != NULL), ret, err);
41*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(curve); EG(ret, err);
42*f0865ec9SKyle Evans 
43*f0865ec9SKyle Evans 	ret = fp_init(&(in->u), curve->A.ctx); EG(ret, err);
44*f0865ec9SKyle Evans 	ret = fp_init(&(in->v), curve->A.ctx); EG(ret, err);
45*f0865ec9SKyle Evans 
46*f0865ec9SKyle Evans 	in->crv = curve;
47*f0865ec9SKyle Evans 	in->magic = AFF_PT_MONTGOMERY_MAGIC;
48*f0865ec9SKyle Evans 
49*f0865ec9SKyle Evans err:
50*f0865ec9SKyle Evans 	return ret;
51*f0865ec9SKyle Evans }
52*f0865ec9SKyle Evans 
53*f0865ec9SKyle Evans /*
54*f0865ec9SKyle Evans  * Initialize pointed aff_pt_montgomery structure to make it usable by library
55*f0865ec9SKyle Evans  * function on given curve with explicit coordinates.
56*f0865ec9SKyle Evans  *
57*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
58*f0865ec9SKyle Evans  */
aff_pt_montgomery_init_from_coords(aff_pt_montgomery_t in,ec_montgomery_crv_src_t curve,fp_src_t ucoord,fp_src_t vcoord)59*f0865ec9SKyle Evans int aff_pt_montgomery_init_from_coords(aff_pt_montgomery_t in,
60*f0865ec9SKyle Evans 			     ec_montgomery_crv_src_t curve,
61*f0865ec9SKyle Evans 			     fp_src_t ucoord, fp_src_t vcoord)
62*f0865ec9SKyle Evans {
63*f0865ec9SKyle Evans 	int ret;
64*f0865ec9SKyle Evans 
65*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_init(in, curve); EG(ret, err);
66*f0865ec9SKyle Evans 	ret = fp_copy(&(in->u), ucoord); EG(ret, err);
67*f0865ec9SKyle Evans 	ret = fp_copy(&(in->v), vcoord);
68*f0865ec9SKyle Evans 
69*f0865ec9SKyle Evans err:
70*f0865ec9SKyle Evans 	return ret;
71*f0865ec9SKyle Evans }
72*f0865ec9SKyle Evans 
73*f0865ec9SKyle Evans /*
74*f0865ec9SKyle Evans  * Uninitialize pointed affine point to prevent further use (magic field
75*f0865ec9SKyle Evans  * in the structure is zeroized) and zeroize associated storage space.
76*f0865ec9SKyle Evans  * Note that the curve context pointed to by the point element (passed
77*f0865ec9SKyle Evans  * during init) is left untouched.
78*f0865ec9SKyle Evans  *
79*f0865ec9SKyle Evans  */
aff_pt_montgomery_uninit(aff_pt_montgomery_t in)80*f0865ec9SKyle Evans void aff_pt_montgomery_uninit(aff_pt_montgomery_t in)
81*f0865ec9SKyle Evans {
82*f0865ec9SKyle Evans 	if ((in != NULL) && (in->magic == AFF_PT_MONTGOMERY_MAGIC) && (in->crv != NULL)) {
83*f0865ec9SKyle Evans 		fp_uninit(&(in->u));
84*f0865ec9SKyle Evans 		fp_uninit(&(in->v));
85*f0865ec9SKyle Evans 
86*f0865ec9SKyle Evans 		in->crv = NULL;
87*f0865ec9SKyle Evans 		in->magic = WORD(0);
88*f0865ec9SKyle Evans 	}
89*f0865ec9SKyle Evans 
90*f0865ec9SKyle Evans 	return;
91*f0865ec9SKyle Evans }
92*f0865ec9SKyle Evans 
93*f0865ec9SKyle Evans /*
94*f0865ec9SKyle Evans  * 'on_curve' set to 1 if the point of coordinates (u,v) is on the curve, i.e. if it
95*f0865ec9SKyle Evans  * verifies curve equation B*v^2 = u^3 + A*u^2 + u. It is set to 0 otherwise.
96*f0865ec9SKyle Evans  * 'on_curve' is not meaningful on error.
97*f0865ec9SKyle Evans  *
98*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
99*f0865ec9SKyle Evans  */
is_on_montgomery_curve(fp_src_t u,fp_src_t v,ec_montgomery_crv_src_t curve,int * on_curve)100*f0865ec9SKyle Evans int is_on_montgomery_curve(fp_src_t u, fp_src_t v, ec_montgomery_crv_src_t curve, int *on_curve)
101*f0865ec9SKyle Evans {
102*f0865ec9SKyle Evans 	fp Bv2, u3, Au2, tmp;
103*f0865ec9SKyle Evans 	int ret, cmp;
104*f0865ec9SKyle Evans 	Bv2.magic = u3.magic = Au2.magic = tmp.magic = WORD(0);
105*f0865ec9SKyle Evans 
106*f0865ec9SKyle Evans 	MUST_HAVE((on_curve != NULL), ret, err);
107*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(curve); EG(ret, err);
108*f0865ec9SKyle Evans 
109*f0865ec9SKyle Evans 	ret = fp_check_initialized(u); EG(ret, err);
110*f0865ec9SKyle Evans 	ret = fp_check_initialized(v); EG(ret, err);
111*f0865ec9SKyle Evans 
112*f0865ec9SKyle Evans 	MUST_HAVE((u->ctx == v->ctx), ret, err);
113*f0865ec9SKyle Evans 	MUST_HAVE((u->ctx == curve->A.ctx), ret, err);
114*f0865ec9SKyle Evans 
115*f0865ec9SKyle Evans 	ret = fp_init(&Bv2, v->ctx); EG(ret, err);
116*f0865ec9SKyle Evans 	ret = fp_sqr(&Bv2, v); EG(ret, err);
117*f0865ec9SKyle Evans 	ret = fp_mul(&Bv2, &(curve->B), &Bv2); EG(ret, err);
118*f0865ec9SKyle Evans 
119*f0865ec9SKyle Evans 	ret = fp_init(&Au2, u->ctx); EG(ret, err);
120*f0865ec9SKyle Evans 	ret = fp_sqr(&Au2, u); EG(ret, err);
121*f0865ec9SKyle Evans 	ret = fp_copy(&u3, &Au2); EG(ret, err);
122*f0865ec9SKyle Evans 	ret = fp_mul(&Au2, &(curve->A), &Au2); EG(ret, err);
123*f0865ec9SKyle Evans 
124*f0865ec9SKyle Evans 	ret = fp_mul(&u3, &u3, u); EG(ret, err);
125*f0865ec9SKyle Evans 
126*f0865ec9SKyle Evans 	ret = fp_init(&tmp, u->ctx); EG(ret, err);
127*f0865ec9SKyle Evans 	ret = fp_add(&tmp, &u3, &Au2); EG(ret, err);
128*f0865ec9SKyle Evans 	ret = fp_add(&tmp, &tmp, u); EG(ret, err);
129*f0865ec9SKyle Evans 
130*f0865ec9SKyle Evans 	ret = fp_cmp(&tmp, &Bv2, &cmp); EG(ret, err);
131*f0865ec9SKyle Evans 
132*f0865ec9SKyle Evans 	(*on_curve) = (!cmp);
133*f0865ec9SKyle Evans 
134*f0865ec9SKyle Evans err:
135*f0865ec9SKyle Evans 	fp_uninit(&Bv2);
136*f0865ec9SKyle Evans 	fp_uninit(&u3);
137*f0865ec9SKyle Evans 	fp_uninit(&Au2);
138*f0865ec9SKyle Evans 	fp_uninit(&tmp);
139*f0865ec9SKyle Evans 
140*f0865ec9SKyle Evans 	return ret;
141*f0865ec9SKyle Evans }
142*f0865ec9SKyle Evans 
143*f0865ec9SKyle Evans /* Checks if affine coordinates point is on a Montgomery curve. 'on_curve' is set to 1 if yes,
144*f0865ec9SKyle Evans  * 0 if no. 'on_curve' is not meaningful in case of error.
145*f0865ec9SKyle Evans  *
146*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
147*f0865ec9SKyle Evans  */
aff_pt_montgomery_is_on_curve(aff_pt_montgomery_src_t pt,int * on_curve)148*f0865ec9SKyle Evans int aff_pt_montgomery_is_on_curve(aff_pt_montgomery_src_t pt, int *on_curve)
149*f0865ec9SKyle Evans {
150*f0865ec9SKyle Evans 	int ret;
151*f0865ec9SKyle Evans 
152*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_check_initialized(pt); EG(ret, err);
153*f0865ec9SKyle Evans 
154*f0865ec9SKyle Evans 	ret = is_on_montgomery_curve(&(pt->u), &(pt->v), pt->crv, on_curve);
155*f0865ec9SKyle Evans 
156*f0865ec9SKyle Evans err:
157*f0865ec9SKyle Evans 	return ret;
158*f0865ec9SKyle Evans }
159*f0865ec9SKyle Evans 
160*f0865ec9SKyle Evans /* Copy a Montgomery affine point in an output. The output is initialized properly.
161*f0865ec9SKyle Evans  *
162*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
163*f0865ec9SKyle Evans  */
ec_montgomery_aff_copy(aff_pt_montgomery_t out,aff_pt_montgomery_src_t in)164*f0865ec9SKyle Evans int ec_montgomery_aff_copy(aff_pt_montgomery_t out, aff_pt_montgomery_src_t in)
165*f0865ec9SKyle Evans {
166*f0865ec9SKyle Evans 	int ret;
167*f0865ec9SKyle Evans 
168*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_check_initialized(in); EG(ret, err);
169*f0865ec9SKyle Evans 
170*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_init(out, in->crv); EG(ret, err);
171*f0865ec9SKyle Evans 	ret = fp_copy(&(out->u), &(in->u)); EG(ret, err);
172*f0865ec9SKyle Evans 	ret = fp_copy(&(out->v), &(in->v));
173*f0865ec9SKyle Evans 
174*f0865ec9SKyle Evans err:
175*f0865ec9SKyle Evans 	return ret;
176*f0865ec9SKyle Evans }
177*f0865ec9SKyle Evans 
178*f0865ec9SKyle Evans /*
179*f0865ec9SKyle Evans  * Compares two given affine points on a Montgomery curve, it returns 0 in input 'cmp' if
180*f0865ec9SKyle Evans  * they correspond or not 0 if not. 'cmp' is not meaningful on error.
181*f0865ec9SKyle Evans  *
182*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
183*f0865ec9SKyle Evans  */
ec_montgomery_aff_cmp(aff_pt_montgomery_src_t in1,aff_pt_montgomery_src_t in2,int * cmp)184*f0865ec9SKyle Evans int ec_montgomery_aff_cmp(aff_pt_montgomery_src_t in1, aff_pt_montgomery_src_t in2, int *cmp)
185*f0865ec9SKyle Evans {
186*f0865ec9SKyle Evans 	int ret, cmp1, cmp2;
187*f0865ec9SKyle Evans 
188*f0865ec9SKyle Evans 	MUST_HAVE((cmp != NULL), ret, err);
189*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_check_initialized(in1); EG(ret, err);
190*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_check_initialized(in2); EG(ret, err);
191*f0865ec9SKyle Evans 	MUST_HAVE((in1->crv == in2->crv), ret, err);
192*f0865ec9SKyle Evans 
193*f0865ec9SKyle Evans 	ret = fp_cmp(&(in1->u), &(in2->u), &cmp1); EG(ret, err);
194*f0865ec9SKyle Evans 	ret = fp_cmp(&(in1->v), &(in2->v), &cmp2); EG(ret, err);
195*f0865ec9SKyle Evans 
196*f0865ec9SKyle Evans 	(*cmp) = (cmp1 | cmp2);
197*f0865ec9SKyle Evans 
198*f0865ec9SKyle Evans err:
199*f0865ec9SKyle Evans 	return ret;
200*f0865ec9SKyle Evans }
201*f0865ec9SKyle Evans 
202*f0865ec9SKyle Evans /*
203*f0865ec9SKyle Evans  * Import an Montgomery affine point from a buffer with the following layout; the 2
204*f0865ec9SKyle Evans  * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len
205*f0865ec9SKyle Evans  * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each
206*f0865ec9SKyle Evans  * coordinate is encoded in big endian. Size of buffer must exactly match
207*f0865ec9SKyle Evans  * 2 * p_len.
208*f0865ec9SKyle Evans  *
209*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
210*f0865ec9SKyle Evans  */
aff_pt_montgomery_import_from_buf(aff_pt_montgomery_t pt,const u8 * pt_buf,u16 pt_buf_len,ec_montgomery_crv_src_t crv)211*f0865ec9SKyle Evans int aff_pt_montgomery_import_from_buf(aff_pt_montgomery_t pt,
212*f0865ec9SKyle Evans 			   const u8 *pt_buf,
213*f0865ec9SKyle Evans 			   u16 pt_buf_len, ec_montgomery_crv_src_t crv)
214*f0865ec9SKyle Evans {
215*f0865ec9SKyle Evans 	fp_ctx_src_t ctx;
216*f0865ec9SKyle Evans 	u16 coord_len;
217*f0865ec9SKyle Evans 	int ret, on_curve;
218*f0865ec9SKyle Evans 
219*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(crv); EG(ret, err);
220*f0865ec9SKyle Evans 	MUST_HAVE((pt_buf != NULL) && (pt != NULL), ret, err);
221*f0865ec9SKyle Evans 
222*f0865ec9SKyle Evans 	ctx = crv->A.ctx;
223*f0865ec9SKyle Evans 	coord_len = (u16)BYTECEIL(ctx->p_bitlen);
224*f0865ec9SKyle Evans 
225*f0865ec9SKyle Evans 	MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);
226*f0865ec9SKyle Evans 
227*f0865ec9SKyle Evans 	ret = fp_init_from_buf(&(pt->u), ctx, pt_buf, coord_len); EG(ret, err);
228*f0865ec9SKyle Evans 	ret = fp_init_from_buf(&(pt->v), ctx, pt_buf + coord_len, coord_len); EG(ret, err);
229*f0865ec9SKyle Evans 
230*f0865ec9SKyle Evans 	/* Set the curve */
231*f0865ec9SKyle Evans 	pt->crv = crv;
232*f0865ec9SKyle Evans 
233*f0865ec9SKyle Evans 	/* Mark the point as initialized */
234*f0865ec9SKyle Evans 	pt->magic = AFF_PT_MONTGOMERY_MAGIC;
235*f0865ec9SKyle Evans 
236*f0865ec9SKyle Evans 	/* Check that the point is indeed on the provided curve, uninitialize it
237*f0865ec9SKyle Evans 	 * if this is not the case.
238*f0865ec9SKyle Evans 	 */
239*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_is_on_curve(pt, &on_curve); EG(ret, err);
240*f0865ec9SKyle Evans 	if (!on_curve) {
241*f0865ec9SKyle Evans 		aff_pt_montgomery_uninit(pt);
242*f0865ec9SKyle Evans 		ret = -1;
243*f0865ec9SKyle Evans 	}
244*f0865ec9SKyle Evans 
245*f0865ec9SKyle Evans err:
246*f0865ec9SKyle Evans 	return ret;
247*f0865ec9SKyle Evans }
248*f0865ec9SKyle Evans 
249*f0865ec9SKyle Evans 
250*f0865ec9SKyle Evans /* Export an Montgomery affine point to a buffer with the following layout; the 2
251*f0865ec9SKyle Evans  * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len
252*f0865ec9SKyle Evans  * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each
253*f0865ec9SKyle Evans  * coordinate is encoded in big endian. Size of buffer must exactly match
254*f0865ec9SKyle Evans  * 2 * p_len.
255*f0865ec9SKyle Evans  *
256*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
257*f0865ec9SKyle Evans  */
aff_pt_montgomery_export_to_buf(aff_pt_montgomery_src_t pt,u8 * pt_buf,u32 pt_buf_len)258*f0865ec9SKyle Evans int aff_pt_montgomery_export_to_buf(aff_pt_montgomery_src_t pt, u8 *pt_buf, u32 pt_buf_len)
259*f0865ec9SKyle Evans {
260*f0865ec9SKyle Evans 	fp_ctx_src_t ctx;
261*f0865ec9SKyle Evans 	u16 coord_len;
262*f0865ec9SKyle Evans 	int ret, on_curve;
263*f0865ec9SKyle Evans 
264*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_check_initialized(pt); EG(ret, err);
265*f0865ec9SKyle Evans 	MUST_HAVE((pt_buf != NULL), ret, err);
266*f0865ec9SKyle Evans 
267*f0865ec9SKyle Evans 	/* The point to be exported must be on the curve */
268*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_is_on_curve(pt, &on_curve); EG(ret, err);
269*f0865ec9SKyle Evans 	MUST_HAVE(on_curve, ret, err);
270*f0865ec9SKyle Evans 
271*f0865ec9SKyle Evans 	ctx = pt->crv->A.ctx;
272*f0865ec9SKyle Evans 	coord_len = (u16)BYTECEIL(ctx->p_bitlen);
273*f0865ec9SKyle Evans 
274*f0865ec9SKyle Evans 	MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);
275*f0865ec9SKyle Evans 
276*f0865ec9SKyle Evans 	/* Export the three coordinates */
277*f0865ec9SKyle Evans 	ret = fp_export_to_buf(pt_buf, coord_len, &(pt->u)); EG(ret, err);
278*f0865ec9SKyle Evans 	ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->v));
279*f0865ec9SKyle Evans 
280*f0865ec9SKyle Evans err:
281*f0865ec9SKyle Evans 	return ret;
282*f0865ec9SKyle Evans }
283*f0865ec9SKyle Evans 
284*f0865ec9SKyle Evans /**** Mappings between curves *************/
285*f0865ec9SKyle Evans /*
286*f0865ec9SKyle Evans  * Mapping curves from Montgomery to short Weiertstrass.
287*f0865ec9SKyle Evans  *
288*f0865ec9SKyle Evans  *  M{A, B} is mapped to W{a, b} using the formula:
289*f0865ec9SKyle Evans  *    a = (3-A^2)/(3*B^2)
290*f0865ec9SKyle Evans  *    b = (2*A^3-9*A)/(27*B^3)
291*f0865ec9SKyle Evans  *
292*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
293*f0865ec9SKyle Evans  */
curve_montgomery_to_shortw(ec_montgomery_crv_src_t montgomery_crv,ec_shortw_crv_t shortw_crv)294*f0865ec9SKyle Evans int curve_montgomery_to_shortw(ec_montgomery_crv_src_t montgomery_crv, ec_shortw_crv_t shortw_crv)
295*f0865ec9SKyle Evans {
296*f0865ec9SKyle Evans 	fp tmp, tmp2, a, b;
297*f0865ec9SKyle Evans 	int ret;
298*f0865ec9SKyle Evans 	tmp.magic = tmp2.magic = a.magic = b.magic = WORD(0);
299*f0865ec9SKyle Evans 
300*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err);
301*f0865ec9SKyle Evans 
302*f0865ec9SKyle Evans 	ret = fp_init(&tmp, montgomery_crv->A.ctx); EG(ret, err);
303*f0865ec9SKyle Evans 	ret = fp_init(&tmp2, montgomery_crv->A.ctx); EG(ret, err);
304*f0865ec9SKyle Evans 	ret = fp_init(&a, montgomery_crv->A.ctx); EG(ret, err);
305*f0865ec9SKyle Evans 	ret = fp_init(&b, montgomery_crv->A.ctx); EG(ret, err);
306*f0865ec9SKyle Evans 
307*f0865ec9SKyle Evans 	/* Compute a */
308*f0865ec9SKyle Evans 	ret = fp_sqr(&tmp, &(montgomery_crv->B)); EG(ret, err);
309*f0865ec9SKyle Evans 	ret = fp_set_word_value(&tmp2, WORD(3)); EG(ret, err);
310*f0865ec9SKyle Evans 	/* 3*B^2 */
311*f0865ec9SKyle Evans 	ret = fp_mul(&tmp, &tmp, &tmp2); EG(ret, err);
312*f0865ec9SKyle Evans 	/* (3*B^2)^-1 */
313*f0865ec9SKyle Evans 	ret = fp_inv(&tmp, &tmp); EG(ret, err);
314*f0865ec9SKyle Evans 
315*f0865ec9SKyle Evans 	/* (3-A^2) */
316*f0865ec9SKyle Evans 	ret = fp_sqr(&tmp2, &(montgomery_crv->A)); EG(ret, err);
317*f0865ec9SKyle Evans 	ret = fp_set_word_value(&a, WORD(3)); EG(ret, err);
318*f0865ec9SKyle Evans 	ret = fp_sub(&tmp2, &a, &tmp2); EG(ret, err);
319*f0865ec9SKyle Evans 
320*f0865ec9SKyle Evans 	ret = fp_mul(&a, &tmp2, &tmp); EG(ret, err);
321*f0865ec9SKyle Evans 
322*f0865ec9SKyle Evans 	/* Compute b */
323*f0865ec9SKyle Evans 	ret = fp_sqr(&tmp, &(montgomery_crv->B)); EG(ret, err);
324*f0865ec9SKyle Evans 	ret = fp_mul(&tmp, &tmp, &(montgomery_crv->B)); EG(ret, err);
325*f0865ec9SKyle Evans 	ret = fp_set_word_value(&tmp2, WORD(27)); EG(ret, err);
326*f0865ec9SKyle Evans 	/* (27*B^3) */
327*f0865ec9SKyle Evans 	ret = fp_mul(&tmp, &tmp, &tmp2); EG(ret, err);
328*f0865ec9SKyle Evans 	/* (27*B^3)^-1 */
329*f0865ec9SKyle Evans 	ret = fp_inv(&tmp, &tmp); EG(ret, err);
330*f0865ec9SKyle Evans 
331*f0865ec9SKyle Evans 	/* (2*A^3-9*A) */
332*f0865ec9SKyle Evans 	ret = fp_set_word_value(&tmp2, WORD(2)); EG(ret, err);
333*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err);
334*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err);
335*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, &(montgomery_crv->A)); EG(ret, err);
336*f0865ec9SKyle Evans 
337*f0865ec9SKyle Evans 	ret = fp_set_word_value(&b, WORD(9)); EG(ret, err);
338*f0865ec9SKyle Evans 	ret = fp_mul(&b, &b, &(montgomery_crv->A)); EG(ret, err);
339*f0865ec9SKyle Evans 	ret = fp_sub(&b, &tmp2, &b); EG(ret, err);
340*f0865ec9SKyle Evans 
341*f0865ec9SKyle Evans 	ret = fp_mul(&b, &b, &tmp); EG(ret, err);
342*f0865ec9SKyle Evans 
343*f0865ec9SKyle Evans 	/* Initialize our short Weiertstrass curve */
344*f0865ec9SKyle Evans 	ret = ec_shortw_crv_init(shortw_crv, &a, &b, &(montgomery_crv->order));
345*f0865ec9SKyle Evans 
346*f0865ec9SKyle Evans err:
347*f0865ec9SKyle Evans 	fp_uninit(&a);
348*f0865ec9SKyle Evans 	fp_uninit(&b);
349*f0865ec9SKyle Evans 	fp_uninit(&tmp);
350*f0865ec9SKyle Evans 	fp_uninit(&tmp2);
351*f0865ec9SKyle Evans 
352*f0865ec9SKyle Evans 	return ret;
353*f0865ec9SKyle Evans }
354*f0865ec9SKyle Evans 
355*f0865ec9SKyle Evans /*
356*f0865ec9SKyle Evans  * Checks that a short Weiertstrass curve and Montgomery curve are compatible.
357*f0865ec9SKyle Evans  *
358*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
359*f0865ec9SKyle Evans  */
curve_montgomery_shortw_check(ec_montgomery_crv_src_t montgomery_crv,ec_shortw_crv_src_t shortw_crv)360*f0865ec9SKyle Evans int curve_montgomery_shortw_check(ec_montgomery_crv_src_t montgomery_crv,
361*f0865ec9SKyle Evans 				  ec_shortw_crv_src_t shortw_crv)
362*f0865ec9SKyle Evans {
363*f0865ec9SKyle Evans 	int ret, cmp;
364*f0865ec9SKyle Evans 	ec_shortw_crv check;
365*f0865ec9SKyle Evans 	check.magic = WORD(0);
366*f0865ec9SKyle Evans 
367*f0865ec9SKyle Evans 	ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err);
368*f0865ec9SKyle Evans 	ret = curve_montgomery_to_shortw(montgomery_crv, &check); EG(ret, err);
369*f0865ec9SKyle Evans 
370*f0865ec9SKyle Evans 	/* Check elements */
371*f0865ec9SKyle Evans 	MUST_HAVE((!fp_cmp(&(check.a), &(shortw_crv->a), &cmp)) && (!cmp), ret, err);
372*f0865ec9SKyle Evans 	MUST_HAVE((!fp_cmp(&(check.b), &(shortw_crv->b), &cmp)) && (!cmp), ret, err);
373*f0865ec9SKyle Evans 	MUST_HAVE((!nn_cmp(&(check.order), &(shortw_crv->order), &cmp)) && (!cmp), ret, err);
374*f0865ec9SKyle Evans 
375*f0865ec9SKyle Evans err:
376*f0865ec9SKyle Evans 	ec_shortw_crv_uninit(&check);
377*f0865ec9SKyle Evans 
378*f0865ec9SKyle Evans 	return ret;
379*f0865ec9SKyle Evans }
380*f0865ec9SKyle Evans 
381*f0865ec9SKyle Evans /*
382*f0865ec9SKyle Evans  * Mapping curves from short Weiertstrass to Montgomery
383*f0865ec9SKyle Evans  *
384*f0865ec9SKyle Evans  *  W{a, b} is mapped to M{A, B} using the formula:
385*f0865ec9SKyle Evans  *    A = 3 * alpha / gamma
386*f0865ec9SKyle Evans  *    B = 1 / gamma
387*f0865ec9SKyle Evans  *  with gamma square root of c = a + 3 * alpha**2
388*f0865ec9SKyle Evans  *
389*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
390*f0865ec9SKyle Evans  */
curve_shortw_to_montgomery(ec_shortw_crv_src_t shortw_crv,ec_montgomery_crv_t montgomery_crv,fp_src_t alpha,fp_src_t gamma)391*f0865ec9SKyle Evans int curve_shortw_to_montgomery(ec_shortw_crv_src_t shortw_crv,
392*f0865ec9SKyle Evans 			       ec_montgomery_crv_t montgomery_crv,
393*f0865ec9SKyle Evans 			       fp_src_t alpha, fp_src_t gamma)
394*f0865ec9SKyle Evans {
395*f0865ec9SKyle Evans 	int ret, cmp;
396*f0865ec9SKyle Evans 	fp c, gamma_inv, A, tmp;
397*f0865ec9SKyle Evans 	c.magic = gamma_inv.magic = A.magic = tmp.magic = WORD(0);
398*f0865ec9SKyle Evans 
399*f0865ec9SKyle Evans 	ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err);
400*f0865ec9SKyle Evans 	ret = fp_check_initialized(alpha); EG(ret, err);
401*f0865ec9SKyle Evans 	ret = fp_check_initialized(gamma); EG(ret, err);
402*f0865ec9SKyle Evans 	MUST_HAVE((alpha->ctx == shortw_crv->a.ctx) && (gamma->ctx == shortw_crv->a.ctx), ret, err);
403*f0865ec9SKyle Evans 
404*f0865ec9SKyle Evans 	ret = fp_init(&A, shortw_crv->a.ctx); EG(ret, err);
405*f0865ec9SKyle Evans 	ret = fp_init(&gamma_inv, shortw_crv->a.ctx); EG(ret, err);
406*f0865ec9SKyle Evans 	ret = fp_init(&c, shortw_crv->a.ctx); EG(ret, err);
407*f0865ec9SKyle Evans 	ret = fp_init(&tmp, shortw_crv->a.ctx); EG(ret, err);
408*f0865ec9SKyle Evans 
409*f0865ec9SKyle Evans 	/* Compute 1 / gamma */
410*f0865ec9SKyle Evans 	ret = fp_inv(&gamma_inv, gamma); EG(ret, err);
411*f0865ec9SKyle Evans 
412*f0865ec9SKyle Evans 	/* Compute A */
413*f0865ec9SKyle Evans 	ret = fp_set_word_value(&A, WORD(3)); EG(ret, err);
414*f0865ec9SKyle Evans 	ret = fp_mul(&A, &A, alpha); EG(ret, err);
415*f0865ec9SKyle Evans 	ret = fp_mul(&A, &A, &gamma_inv); EG(ret, err);
416*f0865ec9SKyle Evans 
417*f0865ec9SKyle Evans 	/* Sanity check on c */
418*f0865ec9SKyle Evans 	ret = fp_set_word_value(&c, WORD(3)); EG(ret, err);
419*f0865ec9SKyle Evans 	ret = fp_mul(&c, &c, alpha); EG(ret, err);
420*f0865ec9SKyle Evans 	ret = fp_mul(&c, &c, alpha); EG(ret, err);
421*f0865ec9SKyle Evans 	ret = fp_add(&c, &c, &(shortw_crv->a)); EG(ret, err);
422*f0865ec9SKyle Evans 	ret = fp_sqr(&tmp, gamma); EG(ret, err);
423*f0865ec9SKyle Evans 	/* gamma ** 2 must be equal to c */
424*f0865ec9SKyle Evans 	MUST_HAVE((!fp_cmp(&c, &tmp, &cmp)) && (!cmp), ret, err);
425*f0865ec9SKyle Evans 
426*f0865ec9SKyle Evans 	/* B is simply the inverse of gamma */
427*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_init(montgomery_crv, &A, &gamma_inv, &(shortw_crv->order));
428*f0865ec9SKyle Evans 
429*f0865ec9SKyle Evans err:
430*f0865ec9SKyle Evans 	fp_uninit(&A);
431*f0865ec9SKyle Evans 	fp_uninit(&gamma_inv);
432*f0865ec9SKyle Evans 	fp_uninit(&c);
433*f0865ec9SKyle Evans 	fp_uninit(&tmp);
434*f0865ec9SKyle Evans 
435*f0865ec9SKyle Evans 	return ret;
436*f0865ec9SKyle Evans }
437*f0865ec9SKyle Evans 
438*f0865ec9SKyle Evans /*
439*f0865ec9SKyle Evans  * Mapping points from Montgomery to short Weierstrass.
440*f0865ec9SKyle Evans  *   Point M(u, v) is mapped to W(x, y) with the formula:
441*f0865ec9SKyle Evans  *       - (x, y) = ((u/B)+(A/3B), v/B)
442*f0865ec9SKyle Evans  *
443*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
444*f0865ec9SKyle Evans  */
aff_pt_montgomery_to_shortw(aff_pt_montgomery_src_t in_montgomery,ec_shortw_crv_src_t shortw_crv,aff_pt_t out_shortw)445*f0865ec9SKyle Evans int aff_pt_montgomery_to_shortw(aff_pt_montgomery_src_t in_montgomery,
446*f0865ec9SKyle Evans 				ec_shortw_crv_src_t shortw_crv, aff_pt_t out_shortw)
447*f0865ec9SKyle Evans {
448*f0865ec9SKyle Evans 	int ret, on_curve;
449*f0865ec9SKyle Evans 	fp tmp, tmp2;
450*f0865ec9SKyle Evans 	tmp.magic = tmp2.magic = WORD(0);
451*f0865ec9SKyle Evans 
452*f0865ec9SKyle Evans 	ret = ec_shortw_crv_check_initialized(shortw_crv); EG(ret, err);
453*f0865ec9SKyle Evans 
454*f0865ec9SKyle Evans 	/* Check that our input point is on its curve */
455*f0865ec9SKyle Evans 	MUST_HAVE((!aff_pt_montgomery_is_on_curve(in_montgomery, &on_curve)) && on_curve, ret, err);
456*f0865ec9SKyle Evans 
457*f0865ec9SKyle Evans 	ret = fp_init(&tmp, in_montgomery->crv->A.ctx); EG(ret, err);
458*f0865ec9SKyle Evans 	ret = fp_init(&tmp2, in_montgomery->crv->A.ctx); EG(ret, err);
459*f0865ec9SKyle Evans 
460*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_check_initialized(in_montgomery); EG(ret, err);
461*f0865ec9SKyle Evans 	ret = curve_montgomery_shortw_check(in_montgomery->crv, shortw_crv); EG(ret, err);
462*f0865ec9SKyle Evans 
463*f0865ec9SKyle Evans 	ret = aff_pt_init(out_shortw, shortw_crv); EG(ret, err);
464*f0865ec9SKyle Evans 
465*f0865ec9SKyle Evans 	ret = fp_inv(&tmp, &(in_montgomery->crv->B)); EG(ret, err);
466*f0865ec9SKyle Evans 	ret = fp_mul(&tmp, &tmp, &(in_montgomery->u)); EG(ret, err);
467*f0865ec9SKyle Evans 
468*f0865ec9SKyle Evans 	ret = fp_set_word_value(&tmp2, WORD(3)); EG(ret, err);
469*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, &(in_montgomery->crv->B)); EG(ret, err);
470*f0865ec9SKyle Evans 	ret = fp_inv(&tmp2, &tmp2); EG(ret, err);
471*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, &(in_montgomery->crv->A)); EG(ret, err);
472*f0865ec9SKyle Evans 
473*f0865ec9SKyle Evans 	ret = fp_add(&(out_shortw->x), &tmp, &tmp2); EG(ret, err);
474*f0865ec9SKyle Evans 
475*f0865ec9SKyle Evans 	ret = fp_inv(&tmp, &(in_montgomery->crv->B)); EG(ret, err);
476*f0865ec9SKyle Evans 	ret = fp_mul(&(out_shortw->y), &tmp, &(in_montgomery->v)); EG(ret, err);
477*f0865ec9SKyle Evans 
478*f0865ec9SKyle Evans 	/* Final check that the point is on the curve */
479*f0865ec9SKyle Evans 	MUST_HAVE((!aff_pt_is_on_curve(out_shortw, &on_curve)) && on_curve, ret, err);
480*f0865ec9SKyle Evans 
481*f0865ec9SKyle Evans err:
482*f0865ec9SKyle Evans 	fp_uninit(&tmp);
483*f0865ec9SKyle Evans 	fp_uninit(&tmp2);
484*f0865ec9SKyle Evans 
485*f0865ec9SKyle Evans 	return ret;
486*f0865ec9SKyle Evans }
487*f0865ec9SKyle Evans 
488*f0865ec9SKyle Evans /*
489*f0865ec9SKyle Evans  * Mapping from short Weierstrass to Montgomery.
490*f0865ec9SKyle Evans  *   Point W(x, y) is mapped to M(u, v) with the formula:
491*f0865ec9SKyle Evans  *       - (u, v) = (((Bx)−(A/3), By)
492*f0865ec9SKyle Evans  *
493*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
494*f0865ec9SKyle Evans  */
aff_pt_shortw_to_montgomery(aff_pt_src_t in_shortw,ec_montgomery_crv_src_t montgomery_crv,aff_pt_montgomery_t out_montgomery)495*f0865ec9SKyle Evans int aff_pt_shortw_to_montgomery(aff_pt_src_t in_shortw,
496*f0865ec9SKyle Evans 				ec_montgomery_crv_src_t montgomery_crv,
497*f0865ec9SKyle Evans 				aff_pt_montgomery_t out_montgomery)
498*f0865ec9SKyle Evans {
499*f0865ec9SKyle Evans 	int ret, on_curve;
500*f0865ec9SKyle Evans 	fp tmp, tmp2;
501*f0865ec9SKyle Evans 	tmp.magic = tmp2.magic = WORD(0);
502*f0865ec9SKyle Evans 
503*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err);
504*f0865ec9SKyle Evans 
505*f0865ec9SKyle Evans 	/* Check that our input point is on its curve */
506*f0865ec9SKyle Evans 	MUST_HAVE((!aff_pt_is_on_curve(in_shortw, &on_curve)) && on_curve, ret, err);
507*f0865ec9SKyle Evans 
508*f0865ec9SKyle Evans 	ret = fp_init(&tmp, in_shortw->crv->a.ctx); EG(ret, err);
509*f0865ec9SKyle Evans 	ret = fp_init(&tmp2, in_shortw->crv->a.ctx); EG(ret, err);
510*f0865ec9SKyle Evans 
511*f0865ec9SKyle Evans 	ret = curve_montgomery_shortw_check(montgomery_crv, in_shortw->crv); EG(ret, err);
512*f0865ec9SKyle Evans 
513*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_init(out_montgomery, montgomery_crv); EG(ret, err);
514*f0865ec9SKyle Evans 
515*f0865ec9SKyle Evans 	/* A/3 */
516*f0865ec9SKyle Evans 	ret = fp_inv_word(&tmp, WORD(3)); EG(ret, err);
517*f0865ec9SKyle Evans 	ret = fp_mul(&tmp, &tmp, &(montgomery_crv->A)); EG(ret, err);
518*f0865ec9SKyle Evans 
519*f0865ec9SKyle Evans 	/* Bx */
520*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &(montgomery_crv->B), &(in_shortw->x)); EG(ret, err);
521*f0865ec9SKyle Evans 
522*f0865ec9SKyle Evans 	/* u = (Bx) - (A/3) */
523*f0865ec9SKyle Evans 	ret = fp_sub(&(out_montgomery->u), &tmp2, &tmp); EG(ret, err);
524*f0865ec9SKyle Evans 
525*f0865ec9SKyle Evans 	/* v = By */
526*f0865ec9SKyle Evans 	ret = fp_mul(&(out_montgomery->v), &(montgomery_crv->B), &(in_shortw->y)); EG(ret, err);
527*f0865ec9SKyle Evans 
528*f0865ec9SKyle Evans 	/* Final check that the point is on the curve */
529*f0865ec9SKyle Evans 	MUST_HAVE((!aff_pt_montgomery_is_on_curve(out_montgomery, &on_curve)) && on_curve, ret, err);
530*f0865ec9SKyle Evans 
531*f0865ec9SKyle Evans err:
532*f0865ec9SKyle Evans 	fp_uninit(&tmp);
533*f0865ec9SKyle Evans 	fp_uninit(&tmp2);
534*f0865ec9SKyle Evans 
535*f0865ec9SKyle Evans 	return ret;
536*f0865ec9SKyle Evans }
537*f0865ec9SKyle Evans 
538*f0865ec9SKyle Evans 
539*f0865ec9SKyle Evans /*
540*f0865ec9SKyle Evans  * Recover the two possible v coordinates from one u on a given
541*f0865ec9SKyle Evans  * curve.
542*f0865ec9SKyle Evans  * The two outputs v1 and v2 are initialized in the function.
543*f0865ec9SKyle Evans  *
544*f0865ec9SKyle Evans  * The function returns -1 on error, 0 on success.
545*f0865ec9SKyle Evans  *
546*f0865ec9SKyle Evans  */
aff_pt_montgomery_v_from_u(fp_t v1,fp_t v2,fp_src_t u,ec_montgomery_crv_src_t crv)547*f0865ec9SKyle Evans int aff_pt_montgomery_v_from_u(fp_t v1, fp_t v2, fp_src_t u, ec_montgomery_crv_src_t crv)
548*f0865ec9SKyle Evans {
549*f0865ec9SKyle Evans 	int ret;
550*f0865ec9SKyle Evans 
551*f0865ec9SKyle Evans 	/* Sanity checks */
552*f0865ec9SKyle Evans 	ret = fp_check_initialized(u); EG(ret, err);
553*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(crv); EG(ret, err);
554*f0865ec9SKyle Evans 	MUST_HAVE((u->ctx == crv->A.ctx) && (u->ctx == crv->B.ctx), ret, err);
555*f0865ec9SKyle Evans 	MUST_HAVE((v1 != NULL) && (v2 != NULL), ret, err);
556*f0865ec9SKyle Evans 	/* Aliasing is not supported */
557*f0865ec9SKyle Evans 	MUST_HAVE((v1 != v2) && (v1 != u), ret, err);
558*f0865ec9SKyle Evans 
559*f0865ec9SKyle Evans 	/* Initialize v1 and v2 with context */
560*f0865ec9SKyle Evans 	ret = fp_init(v1, u->ctx); EG(ret, err);
561*f0865ec9SKyle Evans 	ret = fp_init(v2, u->ctx); EG(ret, err);
562*f0865ec9SKyle Evans 
563*f0865ec9SKyle Evans 	/* v must satisfy the equation B v^2 = u^3 + A u^2 + u,
564*f0865ec9SKyle Evans 	 * so we compute square root for B^-1 * (u^3 + A u^2 + u)
565*f0865ec9SKyle Evans 	 */
566*f0865ec9SKyle Evans 	ret = fp_sqr(v2, u); EG(ret, err);
567*f0865ec9SKyle Evans 	ret = fp_mul(v1, v2, u); EG(ret, err);
568*f0865ec9SKyle Evans 	ret = fp_mul(v2, v2, &(crv->A)); EG(ret, err);
569*f0865ec9SKyle Evans 	ret = fp_add(v1, v1, v2); EG(ret, err);
570*f0865ec9SKyle Evans 	ret = fp_add(v1, v1, u); EG(ret, err);
571*f0865ec9SKyle Evans 	ret = fp_inv(v2, &(crv->B)); EG(ret, err);
572*f0865ec9SKyle Evans 	ret = fp_mul(v1, v1, v2); EG(ret, err);
573*f0865ec9SKyle Evans 
574*f0865ec9SKyle Evans 	/* Choose any of the two square roots as the solution */
575*f0865ec9SKyle Evans 	ret = fp_sqrt(v1, v2, v1);
576*f0865ec9SKyle Evans 
577*f0865ec9SKyle Evans err:
578*f0865ec9SKyle Evans 	return ret;
579*f0865ec9SKyle Evans }
580