xref: /freebsd/crypto/libecc/src/curves/aff_pt_edwards.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 /* NOTE: Edwards here implies Twisted Edwards curves
14*f0865ec9SKyle Evans  * (these in fact include/extend basic form Edwards curves).
15*f0865ec9SKyle Evans  */
16*f0865ec9SKyle Evans 
17*f0865ec9SKyle Evans #define AFF_PT_EDWARDS_MAGIC ((word_t)(0x8390a9bc43d9ffabULL))
18*f0865ec9SKyle Evans 
19*f0865ec9SKyle Evans /* Verify that an affine point has already been initialized
20*f0865ec9SKyle Evans  *
21*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
22*f0865ec9SKyle Evans  */
aff_pt_edwards_check_initialized(aff_pt_edwards_src_t in)23*f0865ec9SKyle Evans int aff_pt_edwards_check_initialized(aff_pt_edwards_src_t in)
24*f0865ec9SKyle Evans {
25*f0865ec9SKyle Evans 	int ret;
26*f0865ec9SKyle Evans 
27*f0865ec9SKyle Evans 	MUST_HAVE(((in != NULL) && (in->magic == AFF_PT_EDWARDS_MAGIC)), ret, err);
28*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(in->crv);
29*f0865ec9SKyle Evans 
30*f0865ec9SKyle Evans err:
31*f0865ec9SKyle Evans 	return ret;
32*f0865ec9SKyle Evans }
33*f0865ec9SKyle Evans 
34*f0865ec9SKyle Evans /*
35*f0865ec9SKyle Evans  * Initialize pointed aff_pt_edwards structure to make it usable by library
36*f0865ec9SKyle Evans  * function on given curve.
37*f0865ec9SKyle Evans  *
38*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
39*f0865ec9SKyle Evans  */
aff_pt_edwards_init(aff_pt_edwards_t in,ec_edwards_crv_src_t curve)40*f0865ec9SKyle Evans int aff_pt_edwards_init(aff_pt_edwards_t in, ec_edwards_crv_src_t curve)
41*f0865ec9SKyle Evans {
42*f0865ec9SKyle Evans 	int ret;
43*f0865ec9SKyle Evans 
44*f0865ec9SKyle Evans 	MUST_HAVE((in != NULL), ret, err);
45*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(curve); EG(ret, err);
46*f0865ec9SKyle Evans 
47*f0865ec9SKyle Evans 	ret = fp_init(&(in->x), curve->a.ctx); EG(ret, err);
48*f0865ec9SKyle Evans 	ret = fp_init(&(in->y), curve->a.ctx); EG(ret, err);
49*f0865ec9SKyle Evans 
50*f0865ec9SKyle Evans 	in->crv = curve;
51*f0865ec9SKyle Evans 	in->magic = AFF_PT_EDWARDS_MAGIC;
52*f0865ec9SKyle Evans 
53*f0865ec9SKyle Evans err:
54*f0865ec9SKyle Evans 	return ret;
55*f0865ec9SKyle Evans }
56*f0865ec9SKyle Evans 
57*f0865ec9SKyle Evans /*
58*f0865ec9SKyle Evans  * Initialize pointed aff_pt_edwards structure to make it usable by library
59*f0865ec9SKyle Evans  * function on given curve with explicit coordinates.
60*f0865ec9SKyle Evans  *
61*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
62*f0865ec9SKyle Evans  */
aff_pt_edwards_init_from_coords(aff_pt_edwards_t in,ec_edwards_crv_src_t curve,fp_src_t xcoord,fp_src_t ycoord)63*f0865ec9SKyle Evans int aff_pt_edwards_init_from_coords(aff_pt_edwards_t in,
64*f0865ec9SKyle Evans 			     ec_edwards_crv_src_t curve,
65*f0865ec9SKyle Evans 			     fp_src_t xcoord, fp_src_t ycoord)
66*f0865ec9SKyle Evans {
67*f0865ec9SKyle Evans 	int ret;
68*f0865ec9SKyle Evans 
69*f0865ec9SKyle Evans 	ret = aff_pt_edwards_init(in, curve); EG(ret, err);
70*f0865ec9SKyle Evans 	ret = fp_copy(&(in->x), xcoord); EG(ret, err);
71*f0865ec9SKyle Evans 	ret = fp_copy(&(in->y), ycoord);
72*f0865ec9SKyle Evans 
73*f0865ec9SKyle Evans err:
74*f0865ec9SKyle Evans 	return ret;
75*f0865ec9SKyle Evans }
76*f0865ec9SKyle Evans 
77*f0865ec9SKyle Evans /*
78*f0865ec9SKyle Evans  * Uninitialize pointed affine point to prevent further use (magic field
79*f0865ec9SKyle Evans  * in the structure is zeroized) and zeroize associated storage space.
80*f0865ec9SKyle Evans  * Note that the curve context pointed to by the point element (passed
81*f0865ec9SKyle Evans  * during init) is left untouched.
82*f0865ec9SKyle Evans  *
83*f0865ec9SKyle Evans  */
aff_pt_edwards_uninit(aff_pt_edwards_t in)84*f0865ec9SKyle Evans void aff_pt_edwards_uninit(aff_pt_edwards_t in)
85*f0865ec9SKyle Evans {
86*f0865ec9SKyle Evans 	if ((in != NULL) && (in->magic == AFF_PT_EDWARDS_MAGIC) && (in->crv != NULL)) {
87*f0865ec9SKyle Evans 		fp_uninit(&(in->x));
88*f0865ec9SKyle Evans 		fp_uninit(&(in->y));
89*f0865ec9SKyle Evans 
90*f0865ec9SKyle Evans 		in->crv = NULL;
91*f0865ec9SKyle Evans 		in->magic = WORD(0);
92*f0865ec9SKyle Evans 	}
93*f0865ec9SKyle Evans 
94*f0865ec9SKyle Evans 	return;
95*f0865ec9SKyle Evans }
96*f0865ec9SKyle Evans 
97*f0865ec9SKyle Evans /*
98*f0865ec9SKyle Evans  * 'on_curve' set to 1 if the point of coordinates (u,v) is on the curve, i.e. if it
99*f0865ec9SKyle Evans  * verifies curve equation a*x^2 + y^2 = 1 + d*x^2*y^2. It is set to 0 otherwise.
100*f0865ec9SKyle Evans  * 'on_curve' is not meaningful on error.
101*f0865ec9SKyle Evans  *
102*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
103*f0865ec9SKyle Evans  */
is_on_edwards_curve(fp_src_t x,fp_src_t y,ec_edwards_crv_src_t curve,int * on_curve)104*f0865ec9SKyle Evans int is_on_edwards_curve(fp_src_t x, fp_src_t y,
105*f0865ec9SKyle Evans 			ec_edwards_crv_src_t curve,
106*f0865ec9SKyle Evans 			int *on_curve)
107*f0865ec9SKyle Evans {
108*f0865ec9SKyle Evans 	fp x2, y2, tmp1, tmp2;
109*f0865ec9SKyle Evans 	int ret, cmp;
110*f0865ec9SKyle Evans 	x2.magic = y2.magic = tmp1.magic = tmp2.magic = WORD(0);
111*f0865ec9SKyle Evans 
112*f0865ec9SKyle Evans 	MUST_HAVE((on_curve != NULL), ret, err);
113*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(curve); EG(ret, err);
114*f0865ec9SKyle Evans 
115*f0865ec9SKyle Evans 	ret = fp_check_initialized(x); EG(ret, err);
116*f0865ec9SKyle Evans 	ret = fp_check_initialized(y); EG(ret, err);
117*f0865ec9SKyle Evans 
118*f0865ec9SKyle Evans 	MUST_HAVE((x->ctx == y->ctx), ret, err);
119*f0865ec9SKyle Evans 	MUST_HAVE((x->ctx == curve->a.ctx), ret, err);
120*f0865ec9SKyle Evans 
121*f0865ec9SKyle Evans 	ret = fp_init(&x2, x->ctx); EG(ret, err);
122*f0865ec9SKyle Evans 	ret = fp_sqr(&x2, x); EG(ret, err);
123*f0865ec9SKyle Evans 	ret = fp_init(&y2, x->ctx); EG(ret, err);
124*f0865ec9SKyle Evans 	ret = fp_sqr(&y2, y); EG(ret, err);
125*f0865ec9SKyle Evans 
126*f0865ec9SKyle Evans 	ret = fp_init(&tmp1, x->ctx); EG(ret, err);
127*f0865ec9SKyle Evans 	ret = fp_init(&tmp2, x->ctx); EG(ret, err);
128*f0865ec9SKyle Evans 
129*f0865ec9SKyle Evans 	ret = fp_mul(&tmp1, &x2, &y2); EG(ret, err);
130*f0865ec9SKyle Evans 	ret = fp_mul(&tmp1, &tmp1, &(curve->d)); EG(ret, err);
131*f0865ec9SKyle Evans 	ret = fp_inc(&tmp1, &tmp1); EG(ret, err);
132*f0865ec9SKyle Evans 
133*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &x2, &(curve->a)); EG(ret, err);
134*f0865ec9SKyle Evans 	ret = fp_add(&tmp2, &tmp2, &y2); EG(ret, err);
135*f0865ec9SKyle Evans 
136*f0865ec9SKyle Evans 	ret = fp_cmp(&tmp1, &tmp2, &cmp);
137*f0865ec9SKyle Evans 
138*f0865ec9SKyle Evans 	if (!ret) {
139*f0865ec9SKyle Evans 		(*on_curve) = (!cmp);
140*f0865ec9SKyle Evans 	}
141*f0865ec9SKyle Evans 
142*f0865ec9SKyle Evans err:
143*f0865ec9SKyle Evans 	fp_uninit(&x2);
144*f0865ec9SKyle Evans 	fp_uninit(&y2);
145*f0865ec9SKyle Evans 	fp_uninit(&tmp1);
146*f0865ec9SKyle Evans 	fp_uninit(&tmp2);
147*f0865ec9SKyle Evans 
148*f0865ec9SKyle Evans 	return ret;
149*f0865ec9SKyle Evans }
150*f0865ec9SKyle Evans 
151*f0865ec9SKyle Evans /*
152*f0865ec9SKyle Evans  * Checks if affine coordinates point is on an Edwards curve. 'on_curve' is set
153*f0865ec9SKyle Evans  * to 1 if yes, 0 if no. 'on_curve' is not meaningful in case of error.
154*f0865ec9SKyle Evans  *
155*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
156*f0865ec9SKyle Evans  */
aff_pt_edwards_is_on_curve(aff_pt_edwards_src_t pt,int * on_curve)157*f0865ec9SKyle Evans int aff_pt_edwards_is_on_curve(aff_pt_edwards_src_t pt, int *on_curve)
158*f0865ec9SKyle Evans {
159*f0865ec9SKyle Evans 	int ret;
160*f0865ec9SKyle Evans 
161*f0865ec9SKyle Evans 	ret = aff_pt_edwards_check_initialized(pt); EG(ret, err);
162*f0865ec9SKyle Evans 
163*f0865ec9SKyle Evans 	ret = is_on_edwards_curve(&(pt->x), &(pt->y), pt->crv, on_curve);
164*f0865ec9SKyle Evans 
165*f0865ec9SKyle Evans err:
166*f0865ec9SKyle Evans 	return ret;
167*f0865ec9SKyle Evans }
168*f0865ec9SKyle Evans 
169*f0865ec9SKyle Evans /*
170*f0865ec9SKyle Evans  * Copy an Edwards affine point in an output. The output is initialized properly.
171*f0865ec9SKyle Evans  *
172*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
173*f0865ec9SKyle Evans  */
ec_edwards_aff_copy(aff_pt_edwards_t out,aff_pt_edwards_src_t in)174*f0865ec9SKyle Evans int ec_edwards_aff_copy(aff_pt_edwards_t out, aff_pt_edwards_src_t in)
175*f0865ec9SKyle Evans {
176*f0865ec9SKyle Evans 	int ret;
177*f0865ec9SKyle Evans 
178*f0865ec9SKyle Evans 	ret = aff_pt_edwards_check_initialized(in); EG(ret, err);
179*f0865ec9SKyle Evans 	ret = aff_pt_edwards_init(out, in->crv); EG(ret, err);
180*f0865ec9SKyle Evans 
181*f0865ec9SKyle Evans 	ret = fp_copy(&(out->x), &(in->x)); EG(ret, err);
182*f0865ec9SKyle Evans 	ret = fp_copy(&(out->y), &(in->y));
183*f0865ec9SKyle Evans 
184*f0865ec9SKyle Evans err:
185*f0865ec9SKyle Evans 	return ret;
186*f0865ec9SKyle Evans }
187*f0865ec9SKyle Evans 
188*f0865ec9SKyle Evans /*
189*f0865ec9SKyle Evans  * Compares two given affine points on an Edwards curve, it returns 0 in input
190*f0865ec9SKyle Evans  * 'cmp' if they correspond or not 0 if not. 'cmp' is not meaningful on error.
191*f0865ec9SKyle Evans  *
192*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
193*f0865ec9SKyle Evans  */
ec_edwards_aff_cmp(aff_pt_edwards_src_t in1,aff_pt_edwards_src_t in2,int * cmp)194*f0865ec9SKyle Evans int ec_edwards_aff_cmp(aff_pt_edwards_src_t in1, aff_pt_edwards_src_t in2,
195*f0865ec9SKyle Evans 		       int *cmp)
196*f0865ec9SKyle Evans {
197*f0865ec9SKyle Evans 	int ret, cmp1, cmp2;
198*f0865ec9SKyle Evans 
199*f0865ec9SKyle Evans 	MUST_HAVE((cmp != NULL), ret, err);
200*f0865ec9SKyle Evans 	ret = aff_pt_edwards_check_initialized(in1); EG(ret, err);
201*f0865ec9SKyle Evans 	ret = aff_pt_edwards_check_initialized(in2); EG(ret, err);
202*f0865ec9SKyle Evans 
203*f0865ec9SKyle Evans 	MUST_HAVE((in1->crv == in2->crv), ret, err);
204*f0865ec9SKyle Evans 
205*f0865ec9SKyle Evans 	ret = fp_cmp(&(in1->x), &(in2->x), &cmp1); EG(ret, err);
206*f0865ec9SKyle Evans 	ret = fp_cmp(&(in1->y), &(in2->y), &cmp2);
207*f0865ec9SKyle Evans 
208*f0865ec9SKyle Evans 	if (!ret) {
209*f0865ec9SKyle Evans 		(*cmp) = (cmp1 | cmp2);
210*f0865ec9SKyle Evans 	}
211*f0865ec9SKyle Evans 
212*f0865ec9SKyle Evans err:
213*f0865ec9SKyle Evans 	return ret;
214*f0865ec9SKyle Evans }
215*f0865ec9SKyle Evans 
216*f0865ec9SKyle Evans /*
217*f0865ec9SKyle Evans  * Import an Edwards affine point from a buffer with the following layout; the 2
218*f0865ec9SKyle Evans  * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len
219*f0865ec9SKyle Evans  * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each
220*f0865ec9SKyle Evans  * coordinate is encoded in big endian. Size of buffer must exactly match
221*f0865ec9SKyle Evans  * 2 * p_len.
222*f0865ec9SKyle Evans  *
223*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
224*f0865ec9SKyle Evans  */
aff_pt_edwards_import_from_buf(aff_pt_edwards_t pt,const u8 * pt_buf,u16 pt_buf_len,ec_edwards_crv_src_t crv)225*f0865ec9SKyle Evans int aff_pt_edwards_import_from_buf(aff_pt_edwards_t pt,
226*f0865ec9SKyle Evans 				   const u8 *pt_buf,
227*f0865ec9SKyle Evans 				   u16 pt_buf_len, ec_edwards_crv_src_t crv)
228*f0865ec9SKyle Evans {
229*f0865ec9SKyle Evans 	fp_ctx_src_t ctx;
230*f0865ec9SKyle Evans 	u16 coord_len;
231*f0865ec9SKyle Evans 	int ret, on_curve;
232*f0865ec9SKyle Evans 
233*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(crv); EG(ret, err);
234*f0865ec9SKyle Evans 	MUST_HAVE(((pt_buf != NULL) && (pt != NULL)), ret, err);
235*f0865ec9SKyle Evans 
236*f0865ec9SKyle Evans 	ctx = crv->a.ctx;
237*f0865ec9SKyle Evans 	coord_len = (u16)BYTECEIL(ctx->p_bitlen);
238*f0865ec9SKyle Evans 
239*f0865ec9SKyle Evans 	MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);
240*f0865ec9SKyle Evans 
241*f0865ec9SKyle Evans 	ret = fp_init_from_buf(&(pt->x), ctx, pt_buf, coord_len); EG(ret, err);
242*f0865ec9SKyle Evans 	ret = fp_init_from_buf(&(pt->y), ctx, pt_buf + coord_len, coord_len); EG(ret, err);
243*f0865ec9SKyle Evans 
244*f0865ec9SKyle Evans 	/* Set the curve */
245*f0865ec9SKyle Evans 	pt->crv = crv;
246*f0865ec9SKyle Evans 
247*f0865ec9SKyle Evans 	/* Mark the point as initialized */
248*f0865ec9SKyle Evans 	pt->magic = AFF_PT_EDWARDS_MAGIC;
249*f0865ec9SKyle Evans 
250*f0865ec9SKyle Evans 	/* Check that the point is indeed on the provided curve, uninitialize it
251*f0865ec9SKyle Evans 	 * if this is not the case.
252*f0865ec9SKyle Evans 	 */
253*f0865ec9SKyle Evans 	ret = aff_pt_edwards_is_on_curve(pt, &on_curve); EG(ret, err);
254*f0865ec9SKyle Evans 	if (!on_curve) {
255*f0865ec9SKyle Evans 		aff_pt_edwards_uninit(pt);
256*f0865ec9SKyle Evans 		ret = -1;
257*f0865ec9SKyle Evans 	}
258*f0865ec9SKyle Evans 
259*f0865ec9SKyle Evans err:
260*f0865ec9SKyle Evans 	return ret;
261*f0865ec9SKyle Evans }
262*f0865ec9SKyle Evans 
263*f0865ec9SKyle Evans 
264*f0865ec9SKyle Evans /* Export an Edwards affine point to a buffer with the following layout; the 2
265*f0865ec9SKyle Evans  * coordinates (elements of Fp) are each encoded on p_len bytes, where p_len
266*f0865ec9SKyle Evans  * is the size of p in bytes (e.g. 66 for a prime p of 521 bits). Each
267*f0865ec9SKyle Evans  * coordinate is encoded in big endian. Size of buffer must exactly match
268*f0865ec9SKyle Evans  * 2 * p_len.
269*f0865ec9SKyle Evans  *
270*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
271*f0865ec9SKyle Evans  */
aff_pt_edwards_export_to_buf(aff_pt_edwards_src_t pt,u8 * pt_buf,u32 pt_buf_len)272*f0865ec9SKyle Evans int aff_pt_edwards_export_to_buf(aff_pt_edwards_src_t pt,
273*f0865ec9SKyle Evans 				 u8 *pt_buf, u32 pt_buf_len)
274*f0865ec9SKyle Evans {
275*f0865ec9SKyle Evans 	fp_ctx_src_t ctx;
276*f0865ec9SKyle Evans 	u16 coord_len;
277*f0865ec9SKyle Evans 	int ret, on_curve;
278*f0865ec9SKyle Evans 
279*f0865ec9SKyle Evans 	ret = aff_pt_edwards_check_initialized(pt); EG(ret, err);
280*f0865ec9SKyle Evans 	MUST_HAVE((pt_buf != NULL), ret, err);
281*f0865ec9SKyle Evans 
282*f0865ec9SKyle Evans 	/* The point to be exported must be on the curve */
283*f0865ec9SKyle Evans 	ret = aff_pt_edwards_is_on_curve(pt, &on_curve); EG(ret, err);
284*f0865ec9SKyle Evans 	MUST_HAVE(on_curve, ret, err);
285*f0865ec9SKyle Evans 
286*f0865ec9SKyle Evans 	ctx = pt->crv->a.ctx;
287*f0865ec9SKyle Evans 	coord_len = (u16)BYTECEIL(ctx->p_bitlen);
288*f0865ec9SKyle Evans 
289*f0865ec9SKyle Evans 	MUST_HAVE((pt_buf_len == (2 * coord_len)), ret, err);
290*f0865ec9SKyle Evans 
291*f0865ec9SKyle Evans 	/* Export the three coordinates */
292*f0865ec9SKyle Evans 	ret = fp_export_to_buf(pt_buf, coord_len, &(pt->x)); EG(ret, err);
293*f0865ec9SKyle Evans 	ret = fp_export_to_buf(pt_buf + coord_len, coord_len, &(pt->y));
294*f0865ec9SKyle Evans 
295*f0865ec9SKyle Evans err:
296*f0865ec9SKyle Evans 	return ret;
297*f0865ec9SKyle Evans }
298*f0865ec9SKyle Evans 
299*f0865ec9SKyle Evans /*
300*f0865ec9SKyle Evans  * Mapping curves from twisted Edwards to Montgomery.
301*f0865ec9SKyle Evans  *
302*f0865ec9SKyle Evans  *  E{a, d} is mapped to M{A, B} using the formula:
303*f0865ec9SKyle Evans  *    A = 2(a+d)/(a-d)
304*f0865ec9SKyle Evans  *    B = 4/((a-d) * alpha^2)
305*f0865ec9SKyle Evans  *
306*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
307*f0865ec9SKyle Evans  */
curve_edwards_to_montgomery(ec_edwards_crv_src_t edwards_crv,ec_montgomery_crv_t montgomery_crv,fp_src_t alpha_edwards)308*f0865ec9SKyle Evans int curve_edwards_to_montgomery(ec_edwards_crv_src_t edwards_crv,
309*f0865ec9SKyle Evans 				ec_montgomery_crv_t montgomery_crv,
310*f0865ec9SKyle Evans 				fp_src_t alpha_edwards)
311*f0865ec9SKyle Evans {
312*f0865ec9SKyle Evans 	fp tmp1, tmp2, A, B;
313*f0865ec9SKyle Evans 	int ret;
314*f0865ec9SKyle Evans 	tmp1.magic = tmp2.magic = A.magic = B.magic = WORD(0);
315*f0865ec9SKyle Evans 
316*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(edwards_crv); EG(ret, err);
317*f0865ec9SKyle Evans 	ret = fp_check_initialized(alpha_edwards); EG(ret, err);
318*f0865ec9SKyle Evans 	MUST_HAVE((edwards_crv->a.ctx == alpha_edwards->ctx), ret, err);
319*f0865ec9SKyle Evans 
320*f0865ec9SKyle Evans 	ret = fp_init(&tmp1, edwards_crv->a.ctx); EG(ret, err);
321*f0865ec9SKyle Evans 	ret = fp_init(&tmp2, edwards_crv->a.ctx); EG(ret, err);
322*f0865ec9SKyle Evans 	ret = fp_init(&A, edwards_crv->a.ctx); EG(ret, err);
323*f0865ec9SKyle Evans 	ret = fp_init(&B, edwards_crv->a.ctx); EG(ret, err);
324*f0865ec9SKyle Evans 
325*f0865ec9SKyle Evans 
326*f0865ec9SKyle Evans 	/* Compute Z = (alpha ^ 2) et T = 2 / ((a-d) * Z)
327*f0865ec9SKyle Evans 	 * and then:
328*f0865ec9SKyle Evans 	 *   A = 2(a+d)/(a-d) = Z * (a + d) * T
329*f0865ec9SKyle Evans 	 *   B = 4/((a-d) * alpha^2) = 2 * T
330*f0865ec9SKyle Evans 	 */
331*f0865ec9SKyle Evans 	ret = fp_sqr(&tmp1, alpha_edwards); EG(ret, err);
332*f0865ec9SKyle Evans 	ret = fp_sub(&tmp2, &(edwards_crv->a), &(edwards_crv->d)); EG(ret, err);
333*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, &tmp1); EG(ret, err);
334*f0865ec9SKyle Evans 	ret = fp_inv(&tmp2, &tmp2); EG(ret, err);
335*f0865ec9SKyle Evans 	ret = fp_set_word_value(&B, WORD(2)); EG(ret, err);
336*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, &B); EG(ret, err);
337*f0865ec9SKyle Evans 
338*f0865ec9SKyle Evans 	ret = fp_add(&A, &(edwards_crv->a), &(edwards_crv->d)); EG(ret, err);
339*f0865ec9SKyle Evans 	ret = fp_mul(&A, &A, &tmp1); EG(ret, err);
340*f0865ec9SKyle Evans 	ret = fp_mul(&A, &A, &tmp2); EG(ret, err);
341*f0865ec9SKyle Evans 	ret = fp_mul(&B, &B, &tmp2); EG(ret, err);
342*f0865ec9SKyle Evans 
343*f0865ec9SKyle Evans 	/* Initialize our Montgomery curve */
344*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_init(montgomery_crv, &A, &B, &(edwards_crv->order));
345*f0865ec9SKyle Evans 
346*f0865ec9SKyle Evans err:
347*f0865ec9SKyle Evans 	fp_uninit(&tmp1);
348*f0865ec9SKyle Evans 	fp_uninit(&tmp2);
349*f0865ec9SKyle Evans 	fp_uninit(&A);
350*f0865ec9SKyle Evans 	fp_uninit(&B);
351*f0865ec9SKyle Evans 
352*f0865ec9SKyle Evans 	return ret;
353*f0865ec9SKyle Evans }
354*f0865ec9SKyle Evans 
355*f0865ec9SKyle Evans /*
356*f0865ec9SKyle Evans  * Checks that an Edwards curve and Montgomery curve are compatible.
357*f0865ec9SKyle Evans  *
358*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
359*f0865ec9SKyle Evans  */
curve_edwards_montgomery_check(ec_edwards_crv_src_t e_crv,ec_montgomery_crv_src_t m_crv,fp_src_t alpha_edwards)360*f0865ec9SKyle Evans int curve_edwards_montgomery_check(ec_edwards_crv_src_t e_crv,
361*f0865ec9SKyle Evans 				   ec_montgomery_crv_src_t m_crv,
362*f0865ec9SKyle Evans 				   fp_src_t alpha_edwards)
363*f0865ec9SKyle Evans {
364*f0865ec9SKyle Evans 	int ret, cmp;
365*f0865ec9SKyle Evans 	ec_montgomery_crv check;
366*f0865ec9SKyle Evans 	check.magic = WORD(0);
367*f0865ec9SKyle Evans 
368*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(m_crv); EG(ret, err);
369*f0865ec9SKyle Evans 	ret = curve_edwards_to_montgomery(e_crv, &check, alpha_edwards); EG(ret, err);
370*f0865ec9SKyle Evans 
371*f0865ec9SKyle Evans 	/* Check elements */
372*f0865ec9SKyle Evans 	MUST_HAVE((!fp_cmp(&(check.A), &(m_crv->A), &cmp)) && (!cmp), ret, err);
373*f0865ec9SKyle Evans 	MUST_HAVE((!fp_cmp(&(check.B), &(m_crv->B), &cmp)) && (!cmp), ret, err);
374*f0865ec9SKyle Evans 	MUST_HAVE((!nn_cmp(&(check.order), &(m_crv->order), &cmp)) && (!cmp), ret, err);
375*f0865ec9SKyle Evans 
376*f0865ec9SKyle Evans err:
377*f0865ec9SKyle Evans 	ec_montgomery_crv_uninit(&check);
378*f0865ec9SKyle Evans 
379*f0865ec9SKyle Evans 	return ret;
380*f0865ec9SKyle Evans }
381*f0865ec9SKyle Evans 
382*f0865ec9SKyle Evans /*
383*f0865ec9SKyle Evans  * Mapping curves from Montgomery to twisted Edwards.
384*f0865ec9SKyle Evans  *
385*f0865ec9SKyle Evans  *  M{A, B} is mapped to E{a, d} using the formula:
386*f0865ec9SKyle Evans  *    a = (A+2)/(B * alpha^2)
387*f0865ec9SKyle Evans  *    d = (A-2)/(B * alpha^2)
388*f0865ec9SKyle Evans  *
389*f0865ec9SKyle Evans  *  Or the inverse (switch a and d roles).
390*f0865ec9SKyle Evans  *
391*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
392*f0865ec9SKyle Evans  */
curve_montgomery_to_edwards(ec_montgomery_crv_src_t m_crv,ec_edwards_crv_t e_crv,fp_src_t alpha_edwards)393*f0865ec9SKyle Evans int curve_montgomery_to_edwards(ec_montgomery_crv_src_t m_crv,
394*f0865ec9SKyle Evans 				ec_edwards_crv_t e_crv,
395*f0865ec9SKyle Evans 				fp_src_t alpha_edwards)
396*f0865ec9SKyle Evans {
397*f0865ec9SKyle Evans 	int ret, cmp;
398*f0865ec9SKyle Evans 	fp tmp, tmp2, a, d;
399*f0865ec9SKyle Evans 	tmp.magic = tmp2.magic = a.magic = d.magic = WORD(0);
400*f0865ec9SKyle Evans 
401*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(m_crv); EG(ret, err);
402*f0865ec9SKyle Evans 	ret = fp_check_initialized(alpha_edwards); EG(ret, err);
403*f0865ec9SKyle Evans 	MUST_HAVE((m_crv->A.ctx == alpha_edwards->ctx), ret, err);
404*f0865ec9SKyle Evans 
405*f0865ec9SKyle Evans 	ret = fp_init(&tmp, m_crv->A.ctx); EG(ret, err);
406*f0865ec9SKyle Evans 	ret = fp_init(&tmp2, m_crv->A.ctx); EG(ret, err);
407*f0865ec9SKyle Evans 	ret = fp_init(&a, m_crv->A.ctx); EG(ret, err);
408*f0865ec9SKyle Evans 	ret = fp_init(&d, m_crv->A.ctx); EG(ret, err);
409*f0865ec9SKyle Evans 
410*f0865ec9SKyle Evans 	ret = fp_set_word_value(&tmp, WORD(2)); EG(ret, err);
411*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &(m_crv->B), alpha_edwards); EG(ret, err);
412*f0865ec9SKyle Evans 	ret = fp_mul(&tmp2, &tmp2, alpha_edwards); EG(ret, err);
413*f0865ec9SKyle Evans 	ret = fp_inv(&tmp2, &tmp2); EG(ret, err);
414*f0865ec9SKyle Evans 
415*f0865ec9SKyle Evans 	/* a = (A+2)/(B * alpha^2) */
416*f0865ec9SKyle Evans 	ret = fp_add(&a, &(m_crv->A), &tmp); EG(ret, err);
417*f0865ec9SKyle Evans 	ret = fp_mul(&a, &a, &tmp2); EG(ret, err);
418*f0865ec9SKyle Evans 
419*f0865ec9SKyle Evans 	/* d = (A-2)/(B * alpha^2) */
420*f0865ec9SKyle Evans 	ret = fp_sub(&d, &(m_crv->A), &tmp); EG(ret, err);
421*f0865ec9SKyle Evans 	ret = fp_mul(&d, &d, &tmp2); EG(ret, err);
422*f0865ec9SKyle Evans 
423*f0865ec9SKyle Evans 	/* Initialize our Edwards curve */
424*f0865ec9SKyle Evans 	/* Check if we have to inverse a and d */
425*f0865ec9SKyle Evans 	ret = fp_one(&tmp); EG(ret, err);
426*f0865ec9SKyle Evans 	ret = fp_cmp(&d, &tmp, &cmp); EG(ret, err);
427*f0865ec9SKyle Evans 	if (cmp == 0) {
428*f0865ec9SKyle Evans 		ret = ec_edwards_crv_init(e_crv, &d, &a, &(m_crv->order));
429*f0865ec9SKyle Evans 	} else {
430*f0865ec9SKyle Evans 		ret = ec_edwards_crv_init(e_crv, &a, &d, &(m_crv->order));
431*f0865ec9SKyle Evans 	}
432*f0865ec9SKyle Evans 
433*f0865ec9SKyle Evans err:
434*f0865ec9SKyle Evans 	fp_uninit(&tmp);
435*f0865ec9SKyle Evans 	fp_uninit(&tmp2);
436*f0865ec9SKyle Evans 	fp_uninit(&a);
437*f0865ec9SKyle Evans 	fp_uninit(&d);
438*f0865ec9SKyle Evans 
439*f0865ec9SKyle Evans 	return ret;
440*f0865ec9SKyle Evans }
441*f0865ec9SKyle Evans 
442*f0865ec9SKyle Evans /*
443*f0865ec9SKyle Evans  * Mapping curve from Edwards to short Weierstrass.
444*f0865ec9SKyle Evans  *
445*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
446*f0865ec9SKyle Evans  */
curve_edwards_to_shortw(ec_edwards_crv_src_t edwards_crv,ec_shortw_crv_t shortw_crv,fp_src_t alpha_edwards)447*f0865ec9SKyle Evans int curve_edwards_to_shortw(ec_edwards_crv_src_t edwards_crv,
448*f0865ec9SKyle Evans 			    ec_shortw_crv_t shortw_crv,
449*f0865ec9SKyle Evans 			    fp_src_t alpha_edwards)
450*f0865ec9SKyle Evans {
451*f0865ec9SKyle Evans 	int ret;
452*f0865ec9SKyle Evans 	ec_montgomery_crv montgomery_crv;
453*f0865ec9SKyle Evans 	montgomery_crv.magic = WORD(0);
454*f0865ec9SKyle Evans 
455*f0865ec9SKyle Evans 	ret = curve_edwards_to_montgomery(edwards_crv, &montgomery_crv, alpha_edwards); EG(ret, err);
456*f0865ec9SKyle Evans 	ret = curve_montgomery_to_shortw(&montgomery_crv, shortw_crv);
457*f0865ec9SKyle Evans 
458*f0865ec9SKyle Evans err:
459*f0865ec9SKyle Evans 	ec_montgomery_crv_uninit(&montgomery_crv);
460*f0865ec9SKyle Evans 
461*f0865ec9SKyle Evans 	return ret;
462*f0865ec9SKyle Evans }
463*f0865ec9SKyle Evans 
464*f0865ec9SKyle Evans /* Checking if an Edwards curve and short Weierstrass curve are compliant (through Montgomery mapping).
465*f0865ec9SKyle Evans  *
466*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
467*f0865ec9SKyle Evans  */
curve_edwards_shortw_check(ec_edwards_crv_src_t edwards_crv,ec_shortw_crv_src_t shortw_crv,fp_src_t alpha_edwards)468*f0865ec9SKyle Evans int curve_edwards_shortw_check(ec_edwards_crv_src_t edwards_crv,
469*f0865ec9SKyle Evans 			       ec_shortw_crv_src_t shortw_crv,
470*f0865ec9SKyle Evans 			       fp_src_t alpha_edwards)
471*f0865ec9SKyle Evans {
472*f0865ec9SKyle Evans 	int ret;
473*f0865ec9SKyle Evans 	ec_montgomery_crv montgomery_crv;
474*f0865ec9SKyle Evans 	montgomery_crv.magic = WORD(0);
475*f0865ec9SKyle Evans 
476*f0865ec9SKyle Evans 	ret = curve_edwards_to_montgomery(edwards_crv, &montgomery_crv, alpha_edwards); EG(ret, err);
477*f0865ec9SKyle Evans 
478*f0865ec9SKyle Evans 	ret = curve_montgomery_shortw_check(&montgomery_crv, shortw_crv);
479*f0865ec9SKyle Evans 
480*f0865ec9SKyle Evans err:
481*f0865ec9SKyle Evans 	ec_montgomery_crv_uninit(&montgomery_crv);
482*f0865ec9SKyle Evans 
483*f0865ec9SKyle Evans 	return ret;
484*f0865ec9SKyle Evans }
485*f0865ec9SKyle Evans 
486*f0865ec9SKyle Evans /*
487*f0865ec9SKyle Evans  * Mapping curve from short Weierstrass to Edwards.
488*f0865ec9SKyle Evans  *
489*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
490*f0865ec9SKyle Evans  */
curve_shortw_to_edwards(ec_shortw_crv_src_t shortw_crv,ec_edwards_crv_t edwards_crv,fp_src_t alpha_montgomery,fp_src_t gamma_montgomery,fp_src_t alpha_edwards)491*f0865ec9SKyle Evans int curve_shortw_to_edwards(ec_shortw_crv_src_t shortw_crv,
492*f0865ec9SKyle Evans 			    ec_edwards_crv_t edwards_crv,
493*f0865ec9SKyle Evans 			    fp_src_t alpha_montgomery,
494*f0865ec9SKyle Evans 			    fp_src_t gamma_montgomery,
495*f0865ec9SKyle Evans 			    fp_src_t alpha_edwards)
496*f0865ec9SKyle Evans {
497*f0865ec9SKyle Evans 	int ret;
498*f0865ec9SKyle Evans 	ec_montgomery_crv montgomery_crv;
499*f0865ec9SKyle Evans 	montgomery_crv.magic = WORD(0);
500*f0865ec9SKyle Evans 
501*f0865ec9SKyle Evans 	ret = curve_shortw_to_montgomery(shortw_crv, &montgomery_crv, alpha_montgomery, gamma_montgomery); EG(ret, err);
502*f0865ec9SKyle Evans 
503*f0865ec9SKyle Evans 	ret = curve_montgomery_to_edwards(&montgomery_crv, edwards_crv, alpha_edwards);
504*f0865ec9SKyle Evans 
505*f0865ec9SKyle Evans err:
506*f0865ec9SKyle Evans 	ec_montgomery_crv_uninit(&montgomery_crv);
507*f0865ec9SKyle Evans 
508*f0865ec9SKyle Evans 	return ret;
509*f0865ec9SKyle Evans }
510*f0865ec9SKyle Evans 
511*f0865ec9SKyle Evans /*
512*f0865ec9SKyle Evans  * Mapping points from twisted Edwards to Montgomery.
513*f0865ec9SKyle Evans  *   Point E(x, y) is mapped to M(u, v) with the formula:
514*f0865ec9SKyle Evans  *       - (0, 1) mapped to the point at infinity (not possible in our affine coordinates)
515*f0865ec9SKyle Evans  *       - (0, -1) mapped to (0, 0)
516*f0865ec9SKyle Evans  *       - (u, v) mapped to ((1+y)/(1-y), alpha * (1+y)/((1-y)x))
517*f0865ec9SKyle Evans  *
518*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
519*f0865ec9SKyle Evans  */
aff_pt_edwards_to_montgomery(aff_pt_edwards_src_t in_edwards,ec_montgomery_crv_src_t montgomery_crv,aff_pt_montgomery_t out_montgomery,fp_src_t alpha_edwards)520*f0865ec9SKyle Evans int aff_pt_edwards_to_montgomery(aff_pt_edwards_src_t in_edwards,
521*f0865ec9SKyle Evans 				 ec_montgomery_crv_src_t montgomery_crv,
522*f0865ec9SKyle Evans 				 aff_pt_montgomery_t out_montgomery,
523*f0865ec9SKyle Evans 				 fp_src_t alpha_edwards)
524*f0865ec9SKyle Evans {
525*f0865ec9SKyle Evans 	/* NOTE: we attempt to perform the (0, -1) -> (0, 0) mapping in constant time.
526*f0865ec9SKyle Evans 	 * Hence the weird table selection.
527*f0865ec9SKyle Evans 	 */
528*f0865ec9SKyle Evans 	int ret, iszero, on_curve, cmp;
529*f0865ec9SKyle Evans 	fp tmp, tmp2, x, y;
530*f0865ec9SKyle Evans 	fp tab_x[2];
531*f0865ec9SKyle Evans 	fp_src_t tab_x_t[2] = { &tab_x[0], &tab_x[1] };
532*f0865ec9SKyle Evans 	fp tab_y[2];
533*f0865ec9SKyle Evans 	fp_src_t tab_y_t[2] = { &tab_y[0], &tab_y[1] };
534*f0865ec9SKyle Evans 	u8 idx = 0;
535*f0865ec9SKyle Evans 	tmp.magic = tmp2.magic = x.magic = y.magic = WORD(0);
536*f0865ec9SKyle Evans 	tab_x[0].magic = tab_x[1].magic = WORD(0);
537*f0865ec9SKyle Evans 	tab_y[0].magic = tab_y[1].magic = WORD(0);
538*f0865ec9SKyle Evans 
539*f0865ec9SKyle Evans 	ret = ec_montgomery_crv_check_initialized(montgomery_crv); EG(ret, err);
540*f0865ec9SKyle Evans 
541*f0865ec9SKyle Evans 	/* Check input point is on its curve */
542*f0865ec9SKyle Evans 	ret = aff_pt_edwards_is_on_curve(in_edwards, &on_curve); EG(ret, err);
543*f0865ec9SKyle Evans 	MUST_HAVE(on_curve, ret, err);
544*f0865ec9SKyle Evans 
545*f0865ec9SKyle Evans 	ret = curve_edwards_montgomery_check(in_edwards->crv, montgomery_crv, alpha_edwards); EG(ret, err);
546*f0865ec9SKyle Evans 
547*f0865ec9SKyle Evans 	ret = fp_init(&tmp, in_edwards->crv->a.ctx); EG(ret, err);
548*f0865ec9SKyle Evans 	ret = fp_init(&tmp2, in_edwards->crv->a.ctx); EG(ret, err);
549*f0865ec9SKyle Evans 	ret = fp_init(&x, in_edwards->crv->a.ctx); EG(ret, err);
550*f0865ec9SKyle Evans 	ret = fp_init(&y, in_edwards->crv->a.ctx); EG(ret, err);
551*f0865ec9SKyle Evans 	ret = fp_init(&tab_x[0], in_edwards->crv->a.ctx); EG(ret, err);
552*f0865ec9SKyle Evans 	ret = fp_init(&tab_x[1], in_edwards->crv->a.ctx); EG(ret, err);
553*f0865ec9SKyle Evans 	ret = fp_init(&tab_y[0], in_edwards->crv->a.ctx); EG(ret, err);
554*f0865ec9SKyle Evans 	ret = fp_init(&tab_y[1], in_edwards->crv->a.ctx); EG(ret, err);
555*f0865ec9SKyle Evans 
556*f0865ec9SKyle Evans 	ret = fp_one(&tmp); EG(ret, err);
557*f0865ec9SKyle Evans 	/* We do not handle point at infinity in affine coordinates */
558*f0865ec9SKyle Evans 	ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err);
559*f0865ec9SKyle Evans 	ret = fp_cmp(&(in_edwards->y), &tmp, &cmp); EG(ret, err);
560*f0865ec9SKyle Evans 	MUST_HAVE(!(iszero && (cmp == 0)), ret, err);
561*f0865ec9SKyle Evans 	/* Map (0, -1) to (0, 0) */
562*f0865ec9SKyle Evans 	ret = fp_zero(&tmp2); EG(ret, err);
563*f0865ec9SKyle Evans 	ret = fp_sub(&tmp2, &tmp2, &tmp); EG(ret, err);
564*f0865ec9SKyle Evans 	/* Copy 1 as x as dummy value */
565*f0865ec9SKyle Evans 	ret = fp_one(&tab_x[0]); EG(ret, err);
566*f0865ec9SKyle Evans 	ret = fp_copy(&tab_x[1], &(in_edwards->x)); EG(ret, err);
567*f0865ec9SKyle Evans 	/* Copy -1 as y to produce (0, 0) */
568*f0865ec9SKyle Evans 	ret = fp_copy(&tab_y[0], &tmp2); EG(ret, err);
569*f0865ec9SKyle Evans 	ret = fp_copy(&tab_y[1], &(in_edwards->y)); EG(ret, err);
570*f0865ec9SKyle Evans 
571*f0865ec9SKyle Evans 	ret = fp_iszero(&(in_edwards->x), &iszero); EG(ret, err);
572*f0865ec9SKyle Evans 	ret = fp_cmp(&(in_edwards->y), &tmp2, &cmp); EG(ret, err);
573*f0865ec9SKyle Evans 	idx = !(iszero && cmp);
574*f0865ec9SKyle Evans 	ret = fp_tabselect(&x, idx, tab_x_t, 2); EG(ret, err);
575*f0865ec9SKyle Evans 	ret = fp_tabselect(&y, idx, tab_y_t, 2); EG(ret, err);
576*f0865ec9SKyle Evans 
577*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_init(out_montgomery, montgomery_crv); EG(ret, err);
578*f0865ec9SKyle Evans 	/* Compute general case */
579*f0865ec9SKyle Evans 	ret = fp_copy(&tmp2, &tmp); EG(ret, err);
580*f0865ec9SKyle Evans 	/* Put 1/(1-y) in tmp */
581*f0865ec9SKyle Evans 	ret = fp_sub(&tmp, &tmp, &y); EG(ret, err);
582*f0865ec9SKyle Evans 	ret = fp_inv(&tmp, &tmp); EG(ret, err);
583*f0865ec9SKyle Evans 	/* Put (1+y) in tmp2 */
584*f0865ec9SKyle Evans 	ret = fp_add(&tmp2, &tmp2, &y); EG(ret, err);
585*f0865ec9SKyle Evans 	/* u = (1+y) / (1-y) */
586*f0865ec9SKyle Evans 	ret = fp_mul(&(out_montgomery->u), &tmp, &tmp2); EG(ret, err);
587*f0865ec9SKyle Evans 	/* v = alpha_edwards * (1+y)/((1-y)x) */
588*f0865ec9SKyle Evans 	ret = fp_inv(&(out_montgomery->v), &x); EG(ret, err);
589*f0865ec9SKyle Evans 	ret = fp_mul(&(out_montgomery->v), &(out_montgomery->v), alpha_edwards); EG(ret, err);
590*f0865ec9SKyle Evans 	ret = fp_mul(&(out_montgomery->v), &(out_montgomery->u), &(out_montgomery->v)); EG(ret, err);
591*f0865ec9SKyle Evans 
592*f0865ec9SKyle Evans 	/* Final check that the point is on the curve */
593*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_is_on_curve(out_montgomery, &on_curve); EG(ret, err);
594*f0865ec9SKyle Evans 	if (!on_curve) {
595*f0865ec9SKyle Evans 		ret = -1;
596*f0865ec9SKyle Evans 	}
597*f0865ec9SKyle Evans 
598*f0865ec9SKyle Evans err:
599*f0865ec9SKyle Evans 	fp_uninit(&tmp);
600*f0865ec9SKyle Evans 	fp_uninit(&tmp2);
601*f0865ec9SKyle Evans 	fp_uninit(&x);
602*f0865ec9SKyle Evans 	fp_uninit(&y);
603*f0865ec9SKyle Evans 	fp_uninit(&tab_x[0]);
604*f0865ec9SKyle Evans 	fp_uninit(&tab_x[1]);
605*f0865ec9SKyle Evans 	fp_uninit(&tab_y[0]);
606*f0865ec9SKyle Evans 	fp_uninit(&tab_y[1]);
607*f0865ec9SKyle Evans 
608*f0865ec9SKyle Evans 	return ret;
609*f0865ec9SKyle Evans }
610*f0865ec9SKyle Evans 
611*f0865ec9SKyle Evans /*
612*f0865ec9SKyle Evans  * Mapping points from Montgomery to twisted Edwards.
613*f0865ec9SKyle Evans  *   Point M(u, v) is mapped to E(x, y) with the formula:
614*f0865ec9SKyle Evans  *       - Point at infinity mapped to (0, 1) (not possible in our affine coordinates)
615*f0865ec9SKyle Evans  *       - (0, 0) mapped to (0, -1)
616*f0865ec9SKyle Evans  *       - (x, y) mapped to (alpha * (u/v), (u-1)/(u+1))
617*f0865ec9SKyle Evans  *
618*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
619*f0865ec9SKyle Evans  */
aff_pt_montgomery_to_edwards(aff_pt_montgomery_src_t in_montgomery,ec_edwards_crv_src_t edwards_crv,aff_pt_edwards_t out_edwards,fp_src_t alpha)620*f0865ec9SKyle Evans int aff_pt_montgomery_to_edwards(aff_pt_montgomery_src_t in_montgomery,
621*f0865ec9SKyle Evans 				 ec_edwards_crv_src_t edwards_crv,
622*f0865ec9SKyle Evans 				 aff_pt_edwards_t out_edwards,
623*f0865ec9SKyle Evans 				 fp_src_t alpha)
624*f0865ec9SKyle Evans {
625*f0865ec9SKyle Evans 	/* NOTE: we attempt to perform the (0, 0) -> (0, -1) mapping in constant time.
626*f0865ec9SKyle Evans 	 * Hence the weird table selection.
627*f0865ec9SKyle Evans 	 */
628*f0865ec9SKyle Evans 	int ret, iszero1, iszero2, on_curve;
629*f0865ec9SKyle Evans 	fp tmp, u, v;
630*f0865ec9SKyle Evans 	fp tab_u[2];
631*f0865ec9SKyle Evans 	fp_src_t tab_u_t[2] = { &tab_u[0], &tab_u[1] };
632*f0865ec9SKyle Evans 	fp tab_v[2];
633*f0865ec9SKyle Evans 	fp_src_t tab_v_t[2] = { &tab_v[0], &tab_v[1] };
634*f0865ec9SKyle Evans 	u8 idx = 0;
635*f0865ec9SKyle Evans 	tmp.magic = u.magic = v.magic  = 0;
636*f0865ec9SKyle Evans 	tab_u[0].magic = tab_u[1].magic = WORD(0);
637*f0865ec9SKyle Evans 	tab_v[0].magic = tab_v[1].magic = WORD(0);
638*f0865ec9SKyle Evans 
639*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(edwards_crv); EG(ret, err);
640*f0865ec9SKyle Evans 
641*f0865ec9SKyle Evans 	/* Check input point is on its curve */
642*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_is_on_curve(in_montgomery, &on_curve); EG(ret, err);
643*f0865ec9SKyle Evans 	MUST_HAVE(on_curve, ret, err);
644*f0865ec9SKyle Evans 
645*f0865ec9SKyle Evans 	ret = curve_edwards_montgomery_check(edwards_crv, in_montgomery->crv, alpha); EG(ret, err);
646*f0865ec9SKyle Evans 
647*f0865ec9SKyle Evans 	ret = fp_init(&tmp, in_montgomery->crv->A.ctx); EG(ret, err);
648*f0865ec9SKyle Evans 	ret = fp_init(&u, in_montgomery->crv->A.ctx); EG(ret, err);
649*f0865ec9SKyle Evans 	ret = fp_init(&v, in_montgomery->crv->A.ctx); EG(ret, err);
650*f0865ec9SKyle Evans 	ret = fp_init(&tab_u[0], in_montgomery->crv->A.ctx); EG(ret, err);
651*f0865ec9SKyle Evans 	ret = fp_init(&tab_u[1], in_montgomery->crv->A.ctx); EG(ret, err);
652*f0865ec9SKyle Evans 	ret = fp_init(&tab_v[0], in_montgomery->crv->A.ctx); EG(ret, err);
653*f0865ec9SKyle Evans 	ret = fp_init(&tab_v[1], in_montgomery->crv->A.ctx); EG(ret, err);
654*f0865ec9SKyle Evans 
655*f0865ec9SKyle Evans 	ret = fp_one(&tmp); EG(ret, err);
656*f0865ec9SKyle Evans 	/* Map (0, 0) to (0, -1) */
657*f0865ec9SKyle Evans 	/* Copy 0 as u as dummy value */
658*f0865ec9SKyle Evans 	ret = fp_zero(&tab_u[0]); EG(ret, err);
659*f0865ec9SKyle Evans 	ret = fp_copy(&tab_u[1], &(in_montgomery->u)); EG(ret, err);
660*f0865ec9SKyle Evans 	/* Copy 1 as v dummy value to produce (0, -1) */
661*f0865ec9SKyle Evans 	ret = fp_copy(&tab_v[0], &tmp); EG(ret, err);
662*f0865ec9SKyle Evans 	ret = fp_copy(&tab_v[1], &(in_montgomery->v)); EG(ret, err);
663*f0865ec9SKyle Evans 
664*f0865ec9SKyle Evans 	ret = fp_iszero(&(in_montgomery->u), &iszero1); EG(ret, err);
665*f0865ec9SKyle Evans 	ret = fp_iszero(&(in_montgomery->v), &iszero2); EG(ret, err);
666*f0865ec9SKyle Evans 	idx = (iszero1 && iszero2) ? 0 : 1;
667*f0865ec9SKyle Evans 	ret = fp_tabselect(&u, idx, tab_u_t, 2); EG(ret, err);
668*f0865ec9SKyle Evans 	ret = fp_tabselect(&v, idx, tab_v_t, 2); EG(ret, err);
669*f0865ec9SKyle Evans 
670*f0865ec9SKyle Evans 	ret = aff_pt_edwards_init(out_edwards, edwards_crv); EG(ret, err);
671*f0865ec9SKyle Evans 	/* x = alpha * (u / v) */
672*f0865ec9SKyle Evans 	ret = fp_inv(&(out_edwards->x), &v); EG(ret, err);
673*f0865ec9SKyle Evans 	ret = fp_mul(&(out_edwards->x), &(out_edwards->x), alpha); EG(ret, err);
674*f0865ec9SKyle Evans 	ret = fp_mul(&(out_edwards->x), &(out_edwards->x), &u); EG(ret, err);
675*f0865ec9SKyle Evans 	/* y = (u-1)/(u+1) */
676*f0865ec9SKyle Evans 	ret = fp_add(&(out_edwards->y), &u, &tmp); EG(ret, err);
677*f0865ec9SKyle Evans 	ret = fp_inv(&(out_edwards->y), &(out_edwards->y)); EG(ret, err);
678*f0865ec9SKyle Evans 	ret = fp_sub(&tmp, &u, &tmp); EG(ret, err);
679*f0865ec9SKyle Evans 	ret = fp_mul(&(out_edwards->y), &(out_edwards->y), &tmp); EG(ret, err);
680*f0865ec9SKyle Evans 
681*f0865ec9SKyle Evans 	/* Final check that the point is on the curve */
682*f0865ec9SKyle Evans 	ret = aff_pt_edwards_is_on_curve(out_edwards, &on_curve); EG(ret, err);
683*f0865ec9SKyle Evans 	if (!on_curve) {
684*f0865ec9SKyle Evans 		ret = -1;
685*f0865ec9SKyle Evans 	}
686*f0865ec9SKyle Evans 
687*f0865ec9SKyle Evans err:
688*f0865ec9SKyle Evans 	fp_uninit(&tmp);
689*f0865ec9SKyle Evans 	fp_uninit(&u);
690*f0865ec9SKyle Evans 	fp_uninit(&v);
691*f0865ec9SKyle Evans 	fp_uninit(&tab_u[0]);
692*f0865ec9SKyle Evans 	fp_uninit(&tab_u[1]);
693*f0865ec9SKyle Evans 	fp_uninit(&tab_v[0]);
694*f0865ec9SKyle Evans 	fp_uninit(&tab_v[1]);
695*f0865ec9SKyle Evans 
696*f0865ec9SKyle Evans 	return ret;
697*f0865ec9SKyle Evans }
698*f0865ec9SKyle Evans 
699*f0865ec9SKyle Evans 
700*f0865ec9SKyle Evans /*
701*f0865ec9SKyle Evans  * Map points from Edwards to short Weierstrass through Montgomery (composition mapping).
702*f0865ec9SKyle Evans  *
703*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
704*f0865ec9SKyle Evans  */
aff_pt_edwards_to_shortw(aff_pt_edwards_src_t in_edwards,ec_shortw_crv_src_t shortw_crv,aff_pt_t out_shortw,fp_src_t alpha_edwards)705*f0865ec9SKyle Evans int aff_pt_edwards_to_shortw(aff_pt_edwards_src_t in_edwards,
706*f0865ec9SKyle Evans 			     ec_shortw_crv_src_t shortw_crv,
707*f0865ec9SKyle Evans 			     aff_pt_t out_shortw, fp_src_t alpha_edwards)
708*f0865ec9SKyle Evans {
709*f0865ec9SKyle Evans 	int ret;
710*f0865ec9SKyle Evans 	aff_pt_montgomery inter_montgomery;
711*f0865ec9SKyle Evans 	ec_montgomery_crv inter_montgomery_crv;
712*f0865ec9SKyle Evans 	inter_montgomery.magic = inter_montgomery_crv.magic = WORD(0);
713*f0865ec9SKyle Evans 
714*f0865ec9SKyle Evans 	/* First, map from Edwards to Montgomery */
715*f0865ec9SKyle Evans 	ret = aff_pt_edwards_check_initialized(in_edwards); EG(ret, err);
716*f0865ec9SKyle Evans 	ret = curve_edwards_to_montgomery(in_edwards->crv, &inter_montgomery_crv, alpha_edwards); EG(ret, err);
717*f0865ec9SKyle Evans 	ret = aff_pt_edwards_to_montgomery(in_edwards, &inter_montgomery_crv, &inter_montgomery, alpha_edwards); EG(ret, err);
718*f0865ec9SKyle Evans 
719*f0865ec9SKyle Evans 	/* Then map from Montgomery to short Weierstrass */
720*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_to_shortw(&inter_montgomery, shortw_crv, out_shortw);
721*f0865ec9SKyle Evans 
722*f0865ec9SKyle Evans err:
723*f0865ec9SKyle Evans 	aff_pt_montgomery_uninit(&inter_montgomery);
724*f0865ec9SKyle Evans 	ec_montgomery_crv_uninit(&inter_montgomery_crv);
725*f0865ec9SKyle Evans 
726*f0865ec9SKyle Evans 	return ret;
727*f0865ec9SKyle Evans }
728*f0865ec9SKyle Evans 
729*f0865ec9SKyle Evans /*
730*f0865ec9SKyle Evans  * Map points from projective short Weierstrass to Edwards through Montgomery (composition mapping).
731*f0865ec9SKyle Evans  *
732*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
733*f0865ec9SKyle Evans  */
aff_pt_shortw_to_edwards(aff_pt_src_t in_shortw,ec_edwards_crv_src_t edwards_crv,aff_pt_edwards_t out_edwards,fp_src_t alpha_edwards)734*f0865ec9SKyle Evans int aff_pt_shortw_to_edwards(aff_pt_src_t in_shortw,
735*f0865ec9SKyle Evans 			     ec_edwards_crv_src_t edwards_crv,
736*f0865ec9SKyle Evans 			     aff_pt_edwards_t out_edwards,
737*f0865ec9SKyle Evans 			     fp_src_t alpha_edwards)
738*f0865ec9SKyle Evans {
739*f0865ec9SKyle Evans 	int ret;
740*f0865ec9SKyle Evans 	aff_pt_montgomery inter_montgomery;
741*f0865ec9SKyle Evans 	ec_montgomery_crv inter_montgomery_crv;
742*f0865ec9SKyle Evans 	inter_montgomery.magic = inter_montgomery_crv.magic = WORD(0);
743*f0865ec9SKyle Evans 
744*f0865ec9SKyle Evans 	/* First, map from short Weierstrass to Montgomery */
745*f0865ec9SKyle Evans 	ret = curve_edwards_to_montgomery(edwards_crv, &inter_montgomery_crv, alpha_edwards); EG(ret, err);
746*f0865ec9SKyle Evans 	ret = aff_pt_shortw_to_montgomery(in_shortw, &inter_montgomery_crv, &inter_montgomery); EG(ret, err);
747*f0865ec9SKyle Evans 
748*f0865ec9SKyle Evans 	/* Then map from Montgomery to Edwards */
749*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_to_edwards(&inter_montgomery, edwards_crv, out_edwards, alpha_edwards);
750*f0865ec9SKyle Evans 
751*f0865ec9SKyle Evans err:
752*f0865ec9SKyle Evans 	aff_pt_montgomery_uninit(&inter_montgomery);
753*f0865ec9SKyle Evans 	ec_montgomery_crv_uninit(&inter_montgomery_crv);
754*f0865ec9SKyle Evans 
755*f0865ec9SKyle Evans 	return ret;
756*f0865ec9SKyle Evans }
757*f0865ec9SKyle Evans 
758*f0865ec9SKyle Evans /*
759*f0865ec9SKyle Evans  * Recover the two possible y coordinates from one x on a given
760*f0865ec9SKyle Evans  * curve.
761*f0865ec9SKyle Evans  * The two outputs y1 and y2 are initialized in the function.
762*f0865ec9SKyle Evans  *
763*f0865ec9SKyle Evans  * The function returns -1 on error, 0 on success.
764*f0865ec9SKyle Evans  *
765*f0865ec9SKyle Evans  */
aff_pt_edwards_y_from_x(fp_t y1,fp_t y2,fp_src_t x,ec_edwards_crv_src_t crv)766*f0865ec9SKyle Evans int aff_pt_edwards_y_from_x(fp_t y1, fp_t y2, fp_src_t x, ec_edwards_crv_src_t crv)
767*f0865ec9SKyle Evans {
768*f0865ec9SKyle Evans         int ret;
769*f0865ec9SKyle Evans 	fp tmp;
770*f0865ec9SKyle Evans 	tmp.magic = WORD(0);
771*f0865ec9SKyle Evans 
772*f0865ec9SKyle Evans 	/* Sanity checks */
773*f0865ec9SKyle Evans 	ret = fp_check_initialized(x); EG(ret, err);
774*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(crv); EG(ret, err);
775*f0865ec9SKyle Evans 	MUST_HAVE((x->ctx == crv->a.ctx) && (x->ctx == crv->d.ctx), ret, err);
776*f0865ec9SKyle Evans 	MUST_HAVE((y1 != NULL) && (y2 != NULL), ret, err);
777*f0865ec9SKyle Evans 	/* Aliasing is not supported */
778*f0865ec9SKyle Evans 	MUST_HAVE((y1 != y2) && (y1 != x), ret, err);
779*f0865ec9SKyle Evans 
780*f0865ec9SKyle Evans 	ret = fp_init(y1, x->ctx); EG(ret, err);
781*f0865ec9SKyle Evans 	ret = fp_init(y2, x->ctx); EG(ret, err);
782*f0865ec9SKyle Evans 	ret = fp_init(&tmp, x->ctx); EG(ret, err);
783*f0865ec9SKyle Evans 
784*f0865ec9SKyle Evans 	/* In order to find our two possible y, we have to find the square
785*f0865ec9SKyle Evans 	 * roots of (1 - a x**2) / (1 - d * x**2).
786*f0865ec9SKyle Evans 	 */
787*f0865ec9SKyle Evans 	ret = fp_one(&tmp); EG(ret, err);
788*f0865ec9SKyle Evans 	/* (1 - a x**2) */
789*f0865ec9SKyle Evans 	ret = fp_mul(y1, x, &(crv->a)); EG(ret, err);
790*f0865ec9SKyle Evans 	ret = fp_mul(y1, y1, x); EG(ret, err);
791*f0865ec9SKyle Evans 	ret = fp_sub(y1, &tmp, y1); EG(ret, err);
792*f0865ec9SKyle Evans 	/* 1 / (1 - d * x**2) */
793*f0865ec9SKyle Evans 	ret = fp_mul(y2, x, &(crv->d)); EG(ret, err);
794*f0865ec9SKyle Evans 	ret = fp_mul(y2, y2, x); EG(ret, err);
795*f0865ec9SKyle Evans 	ret = fp_sub(y2, &tmp, y2); EG(ret, err);
796*f0865ec9SKyle Evans 	ret = fp_inv(y2, y2); EG(ret, err);
797*f0865ec9SKyle Evans 
798*f0865ec9SKyle Evans 	ret = fp_mul(&tmp, y1, y2); EG(ret, err);
799*f0865ec9SKyle Evans 
800*f0865ec9SKyle Evans 	ret = fp_sqrt(y1, y2, &tmp);
801*f0865ec9SKyle Evans 
802*f0865ec9SKyle Evans err:
803*f0865ec9SKyle Evans 	fp_uninit(&tmp);
804*f0865ec9SKyle Evans 
805*f0865ec9SKyle Evans 	return ret;
806*f0865ec9SKyle Evans }
807*f0865ec9SKyle Evans 
808*f0865ec9SKyle Evans /*
809*f0865ec9SKyle Evans  * Recover the two possible x coordinates from one y on a given
810*f0865ec9SKyle Evans  * curve.
811*f0865ec9SKyle Evans  * The two outputs x1 and x2 are initialized in the function.
812*f0865ec9SKyle Evans  *
813*f0865ec9SKyle Evans  * The function returns -1 on error, 0 on success.
814*f0865ec9SKyle Evans  *
815*f0865ec9SKyle Evans  */
aff_pt_edwards_x_from_y(fp_t x1,fp_t x2,fp_src_t y,ec_edwards_crv_src_t crv)816*f0865ec9SKyle Evans int aff_pt_edwards_x_from_y(fp_t x1, fp_t x2, fp_src_t y, ec_edwards_crv_src_t crv)
817*f0865ec9SKyle Evans {
818*f0865ec9SKyle Evans         int ret;
819*f0865ec9SKyle Evans 	fp tmp;
820*f0865ec9SKyle Evans 	tmp.magic = WORD(0);
821*f0865ec9SKyle Evans 
822*f0865ec9SKyle Evans 	/* Sanity checks */
823*f0865ec9SKyle Evans 	ret = fp_check_initialized(y); EG(ret, err);
824*f0865ec9SKyle Evans 	ret = ec_edwards_crv_check_initialized(crv); EG(ret, err);
825*f0865ec9SKyle Evans 	MUST_HAVE((y->ctx == crv->a.ctx) && (y->ctx == crv->d.ctx), ret, err);
826*f0865ec9SKyle Evans 	MUST_HAVE((x1 != NULL) && (x2 != NULL), ret, err);
827*f0865ec9SKyle Evans 	/* Aliasing is not supported */
828*f0865ec9SKyle Evans 	MUST_HAVE((x1 != x2) && (x1 != y), ret, err);
829*f0865ec9SKyle Evans 
830*f0865ec9SKyle Evans 	ret = fp_init(x1, y->ctx); EG(ret, err);
831*f0865ec9SKyle Evans 	ret = fp_init(x2, y->ctx); EG(ret, err);
832*f0865ec9SKyle Evans 	ret = fp_init(&tmp, y->ctx); EG(ret, err);
833*f0865ec9SKyle Evans 
834*f0865ec9SKyle Evans 	/* In order to find our two possible y, we have to find the square
835*f0865ec9SKyle Evans 	 * roots of (1 - y**2) / (a - d * y**2).
836*f0865ec9SKyle Evans 	 */
837*f0865ec9SKyle Evans 	ret = fp_one(&tmp); EG(ret, err);
838*f0865ec9SKyle Evans 	/* (1 - y**2) */
839*f0865ec9SKyle Evans 	ret = fp_mul(x1, y, y); EG(ret, err);
840*f0865ec9SKyle Evans 	ret = fp_sub(x1, &tmp, x1); EG(ret, err);
841*f0865ec9SKyle Evans 	/* 1 / (a - d * x**2) */
842*f0865ec9SKyle Evans 	ret = fp_mul(x2, y, &(crv->d)); EG(ret, err);
843*f0865ec9SKyle Evans 	ret = fp_mul(x2, x2, y); EG(ret, err);
844*f0865ec9SKyle Evans 	ret = fp_sub(x2, &(crv->a), x2); EG(ret, err);
845*f0865ec9SKyle Evans 	ret = fp_inv(x2, x2); EG(ret, err);
846*f0865ec9SKyle Evans 
847*f0865ec9SKyle Evans 	ret = fp_mul(&tmp, x1, x2); EG(ret, err);
848*f0865ec9SKyle Evans 
849*f0865ec9SKyle Evans 	ret = fp_sqrt(x1, x2, &tmp);
850*f0865ec9SKyle Evans 
851*f0865ec9SKyle Evans err:
852*f0865ec9SKyle Evans 	fp_uninit(&tmp);
853*f0865ec9SKyle Evans 
854*f0865ec9SKyle Evans 	return ret;
855*f0865ec9SKyle Evans }
856