xref: /freebsd/crypto/libecc/src/ecdh/x25519_448.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/lib_ecc_config.h>
12*f0865ec9SKyle Evans #if defined(WITH_X25519) || defined(WITH_X448)
13*f0865ec9SKyle Evans 
14*f0865ec9SKyle Evans /*
15*f0865ec9SKyle Evans  * XXX: X25519 and X448 are incompatible with small stack devices for now ...
16*f0865ec9SKyle Evans  */
17*f0865ec9SKyle Evans #if defined(USE_SMALL_STACK)
18*f0865ec9SKyle Evans #error "Error: X25519 and X448 are incompatible with USE_SMALL_STACK (devices low on memory)"
19*f0865ec9SKyle Evans #endif
20*f0865ec9SKyle Evans 
21*f0865ec9SKyle Evans #if defined(WITH_X25519) && !defined(WITH_CURVE_WEI25519)
22*f0865ec9SKyle Evans #error "Error: X25519 needs curve WEI25519 to be defined! Please define it in libecc config file"
23*f0865ec9SKyle Evans #endif
24*f0865ec9SKyle Evans #if defined(WITH_X448) && !defined(WITH_CURVE_WEI448)
25*f0865ec9SKyle Evans #error "Error: X448 needs curve WEI448 to be defined! Please define it in libecc config file"
26*f0865ec9SKyle Evans #endif
27*f0865ec9SKyle Evans 
28*f0865ec9SKyle Evans #include <libecc/ecdh/x25519_448.h>
29*f0865ec9SKyle Evans 
30*f0865ec9SKyle Evans #include <libecc/curves/curves.h>
31*f0865ec9SKyle Evans #include <libecc/sig/ec_key.h>
32*f0865ec9SKyle Evans #include <libecc/utils/utils.h>
33*f0865ec9SKyle Evans #include <libecc/fp/fp_sqrt.h>
34*f0865ec9SKyle Evans 
35*f0865ec9SKyle Evans /* For randomness source */
36*f0865ec9SKyle Evans #include <libecc/external_deps/rand.h>
37*f0865ec9SKyle Evans 
38*f0865ec9SKyle Evans /* This module mainly implements the X25519 and X448 functions strictly as defined in
39*f0865ec9SKyle Evans  * RFC7748.
40*f0865ec9SKyle Evans  */
41*f0865ec9SKyle Evans 
42*f0865ec9SKyle Evans 
43*f0865ec9SKyle Evans /* Scalar clamping/decoding
44*f0865ec9SKyle Evans  *
45*f0865ec9SKyle Evans  * NOTE: the scalar encoding is mainly here to ensure that it is of the form
46*f0865ec9SKyle Evans  * 2^254 plus eight times a value between 0 and 2^251 - 1 inclusive for X25519
47*f0865ec9SKyle Evans  * (2^447 plus four times a value between 0 and 2^445 - 1 inclusive for X448).
48*f0865ec9SKyle Evans  *
49*f0865ec9SKyle Evans  * This ensures "clearing the cofactor" to avoid small subgroup attacks as well
50*f0865ec9SKyle Evans  * as setting the scalar MSB to avoid timing/SCA attacks on scalar multiplication.
51*f0865ec9SKyle Evans  * These two desirable properties are part of the rationale behind X25519/X448).
52*f0865ec9SKyle Evans  */
decode_scalar(u8 * scalar_decoded,const u8 * scalar,u8 len)53*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int decode_scalar(u8 *scalar_decoded, const u8 *scalar, u8 len)
54*f0865ec9SKyle Evans {
55*f0865ec9SKyle Evans         int ret;
56*f0865ec9SKyle Evans         u8 i;
57*f0865ec9SKyle Evans 
58*f0865ec9SKyle Evans         /* Aliasing is not supported */
59*f0865ec9SKyle Evans         MUST_HAVE((scalar != scalar_decoded), ret, err);
60*f0865ec9SKyle Evans 	/* Zero length is not accepted */
61*f0865ec9SKyle Evans 	MUST_HAVE((len > 0), ret, err);
62*f0865ec9SKyle Evans 
63*f0865ec9SKyle Evans 	/* Endianness swapping */
64*f0865ec9SKyle Evans         for(i = 0; i < len; i++){
65*f0865ec9SKyle Evans                 scalar_decoded[len - 1 - i] = scalar[i];
66*f0865ec9SKyle Evans         }
67*f0865ec9SKyle Evans 	if(len == X25519_SIZE){
68*f0865ec9SKyle Evans 		/* Curve25519 */
69*f0865ec9SKyle Evans 		scalar_decoded[len - 1] &= 248;
70*f0865ec9SKyle Evans         	scalar_decoded[0]       &= 127;
71*f0865ec9SKyle Evans 		scalar_decoded[0]       |= 64;
72*f0865ec9SKyle Evans 	}
73*f0865ec9SKyle Evans 	else if(len == X448_SIZE){
74*f0865ec9SKyle Evans 		/* Curve448 */
75*f0865ec9SKyle Evans 		scalar_decoded[len - 1] &= 252;
76*f0865ec9SKyle Evans 		scalar_decoded[0]       |= 128;
77*f0865ec9SKyle Evans 	}
78*f0865ec9SKyle Evans 	else{
79*f0865ec9SKyle Evans 		/* Error, unknown type */
80*f0865ec9SKyle Evans 		ret = -1;
81*f0865ec9SKyle Evans 		goto err;
82*f0865ec9SKyle Evans 	}
83*f0865ec9SKyle Evans 
84*f0865ec9SKyle Evans         ret = 0;
85*f0865ec9SKyle Evans 
86*f0865ec9SKyle Evans err:
87*f0865ec9SKyle Evans         return ret;
88*f0865ec9SKyle Evans }
89*f0865ec9SKyle Evans 
90*f0865ec9SKyle Evans /* U coordinate decoding, mainly endianness swapping  */
decode_u_coordinate(u8 * u_decoded,const u8 * u,u8 len)91*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int decode_u_coordinate(u8 *u_decoded, const u8 *u, u8 len)
92*f0865ec9SKyle Evans {
93*f0865ec9SKyle Evans 	int ret;
94*f0865ec9SKyle Evans 	u8 i;
95*f0865ec9SKyle Evans 
96*f0865ec9SKyle Evans 	/* Aliasing is not supported */
97*f0865ec9SKyle Evans 	MUST_HAVE((u != u_decoded), ret, err);
98*f0865ec9SKyle Evans 	/* Zero length is not accepted */
99*f0865ec9SKyle Evans 	MUST_HAVE((len > 0), ret, err);
100*f0865ec9SKyle Evans 
101*f0865ec9SKyle Evans 	for(i = 0; i < len; i++){
102*f0865ec9SKyle Evans 		u_decoded[len - 1 - i] = u[i];
103*f0865ec9SKyle Evans         }
104*f0865ec9SKyle Evans 
105*f0865ec9SKyle Evans 	ret = 0;
106*f0865ec9SKyle Evans 
107*f0865ec9SKyle Evans err:
108*f0865ec9SKyle Evans 	return ret;
109*f0865ec9SKyle Evans }
110*f0865ec9SKyle Evans 
111*f0865ec9SKyle Evans /* U coordinate encoding, mainly endianness swapping */
encode_u_coordinate(u8 * u_encoded,const u8 * u,u8 len)112*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int encode_u_coordinate(u8 *u_encoded, const u8 *u, u8 len)
113*f0865ec9SKyle Evans {
114*f0865ec9SKyle Evans 	return decode_u_coordinate(u_encoded, u, len);
115*f0865ec9SKyle Evans }
116*f0865ec9SKyle Evans 
117*f0865ec9SKyle Evans 
118*f0865ec9SKyle Evans /* Find V coordinate from U coordinate on Curve25519 or Curve448 */
compute_v_from_u(fp_src_t u,fp_t v,ec_montgomery_crv_src_t crv)119*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int compute_v_from_u(fp_src_t u, fp_t v, ec_montgomery_crv_src_t crv)
120*f0865ec9SKyle Evans {
121*f0865ec9SKyle Evans 	int ret;
122*f0865ec9SKyle Evans 	fp tmp;
123*f0865ec9SKyle Evans 
124*f0865ec9SKyle Evans 	tmp.magic = 0;
125*f0865ec9SKyle Evans 
126*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_v_from_u(v, &tmp, u, crv);
127*f0865ec9SKyle Evans 	/* NOTE: this square root is possibly non-existing if the
128*f0865ec9SKyle Evans 	 * u coordinate is on the quadratic twist of the curve.
129*f0865ec9SKyle Evans 	 * An error is returned in this case.
130*f0865ec9SKyle Evans 	 */
131*f0865ec9SKyle Evans 
132*f0865ec9SKyle Evans 	fp_uninit(&tmp);
133*f0865ec9SKyle Evans 
134*f0865ec9SKyle Evans 	return ret;
135*f0865ec9SKyle Evans }
136*f0865ec9SKyle Evans 
137*f0865ec9SKyle Evans 
138*f0865ec9SKyle Evans /*
139*f0865ec9SKyle Evans  * This is the core computation of X25519 and X448.
140*f0865ec9SKyle Evans  *
141*f0865ec9SKyle Evans  * NOTE: the user of this primitive should be warned and aware that is is not fully compliant with the
142*f0865ec9SKyle Evans  * RFC7748 description as u coordinates on the quadratic twist of the curve are rejected as well
143*f0865ec9SKyle Evans  * as non canonical u.
144*f0865ec9SKyle Evans  * See the explanations in the implementation of the function for more context and explanations.
145*f0865ec9SKyle Evans  */
x25519_448_core(const u8 * k,const u8 * u,u8 * res,u8 len)146*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int x25519_448_core(const u8 *k, const u8 *u, u8 *res, u8 len)
147*f0865ec9SKyle Evans {
148*f0865ec9SKyle Evans 	int ret, iszero, loaded, cmp;
149*f0865ec9SKyle Evans 	/* Note: our local variables holding scalar and coordinate have the maximum size
150*f0865ec9SKyle Evans 	 * (X448 size if it is defined, X25519 else).
151*f0865ec9SKyle Evans 	 */
152*f0865ec9SKyle Evans #if defined(WITH_X448)
153*f0865ec9SKyle Evans 	u8 k_[X448_SIZE], u_[X448_SIZE];
154*f0865ec9SKyle Evans #else
155*f0865ec9SKyle Evans 	u8 k_[X25519_SIZE], u_[X25519_SIZE];
156*f0865ec9SKyle Evans #endif
157*f0865ec9SKyle Evans 	aff_pt_montgomery _Tmp;
158*f0865ec9SKyle Evans 	prj_pt Q;
159*f0865ec9SKyle Evans 	ec_montgomery_crv montgomery_curve;
160*f0865ec9SKyle Evans 	ec_params shortw_curve_params;
161*f0865ec9SKyle Evans 	ec_shortw_crv_src_t shortw_curve;
162*f0865ec9SKyle Evans 	fp_src_t alpha_montgomery;
163*f0865ec9SKyle Evans 	fp_src_t gamma_montgomery;
164*f0865ec9SKyle Evans 	nn scalar;
165*f0865ec9SKyle Evans 	nn_t v_coord_nn;
166*f0865ec9SKyle Evans 	fp_t u_coord, v_coord;
167*f0865ec9SKyle Evans 	nn_t cofactor;
168*f0865ec9SKyle Evans 
169*f0865ec9SKyle Evans 	_Tmp.magic = montgomery_curve.magic = Q.magic = WORD(0);
170*f0865ec9SKyle Evans 	scalar.magic = WORD(0);
171*f0865ec9SKyle Evans 
172*f0865ec9SKyle Evans 	MUST_HAVE((k != NULL) && (u != NULL) && (res != NULL), ret, err);
173*f0865ec9SKyle Evans 	/* Sanity check on sizes */
174*f0865ec9SKyle Evans 	MUST_HAVE(((len == X25519_SIZE) || (len == X448_SIZE)), ret, err);
175*f0865ec9SKyle Evans 	MUST_HAVE(((sizeof(k_) >= len) && (sizeof(u_) >= len)), ret, err);
176*f0865ec9SKyle Evans 
177*f0865ec9SKyle Evans 	/* First of all, we clamp and decode the scalar and u */
178*f0865ec9SKyle Evans 	ret = decode_scalar(k_, k, len); EG(ret, err);
179*f0865ec9SKyle Evans 	ret = decode_u_coordinate(u_, u, len); EG(ret, err);
180*f0865ec9SKyle Evans 
181*f0865ec9SKyle Evans 	/* Import curve parameters */
182*f0865ec9SKyle Evans 	loaded = 0;
183*f0865ec9SKyle Evans #if defined(WITH_X25519)
184*f0865ec9SKyle Evans 	if(len == X25519_SIZE){
185*f0865ec9SKyle Evans 		ret = import_params(&shortw_curve_params, &wei25519_str_params); EG(ret, err);
186*f0865ec9SKyle Evans 		loaded = 1;
187*f0865ec9SKyle Evans 	}
188*f0865ec9SKyle Evans #endif
189*f0865ec9SKyle Evans #if defined(WITH_X448)
190*f0865ec9SKyle Evans 	if(len == X448_SIZE){
191*f0865ec9SKyle Evans 		ret = import_params(&shortw_curve_params, &wei448_str_params); EG(ret, err);
192*f0865ec9SKyle Evans 		loaded = 1;
193*f0865ec9SKyle Evans 	}
194*f0865ec9SKyle Evans #endif
195*f0865ec9SKyle Evans 	/* Sanity check that we have loaded our curve parameters */
196*f0865ec9SKyle Evans 	MUST_HAVE((loaded == 1), ret, err);
197*f0865ec9SKyle Evans 
198*f0865ec9SKyle Evans 	/* Make things more readable */
199*f0865ec9SKyle Evans 	shortw_curve = &(shortw_curve_params.ec_curve);
200*f0865ec9SKyle Evans 	cofactor = &(shortw_curve_params.ec_gen_cofactor);
201*f0865ec9SKyle Evans 	alpha_montgomery = &(shortw_curve_params.ec_alpha_montgomery);
202*f0865ec9SKyle Evans 	gamma_montgomery = &(shortw_curve_params.ec_gamma_montgomery);
203*f0865ec9SKyle Evans 	/* NOTE: we use the projective point Q Fp values as temporary
204*f0865ec9SKyle Evans 	 * space to save some stack here.
205*f0865ec9SKyle Evans 	 */
206*f0865ec9SKyle Evans 	u_coord = &(Q.X);
207*f0865ec9SKyle Evans 	v_coord = &(Q.Y);
208*f0865ec9SKyle Evans 	v_coord_nn = &(v_coord->fp_val);
209*f0865ec9SKyle Evans 
210*f0865ec9SKyle Evans 	/* Get the isogenic Montgomery curve */
211*f0865ec9SKyle Evans 	ret = curve_shortw_to_montgomery(shortw_curve, &montgomery_curve, alpha_montgomery,
212*f0865ec9SKyle Evans 			gamma_montgomery); EG(ret, err);
213*f0865ec9SKyle Evans 
214*f0865ec9SKyle Evans 	/* Import the u coordinate as a big integer and Fp element */
215*f0865ec9SKyle Evans 	ret = nn_init_from_buf(v_coord_nn, u_, len); EG(ret, err);
216*f0865ec9SKyle Evans 	/* Reject non canonical u values.
217*f0865ec9SKyle Evans 	 * NOTE: we use v here as a temporary value.
218*f0865ec9SKyle Evans 	 */
219*f0865ec9SKyle Evans 	ret = nn_cmp(v_coord_nn, &(montgomery_curve.A.ctx->p), &cmp); EG(ret, err);
220*f0865ec9SKyle Evans 	MUST_HAVE((cmp < 0), ret, err);
221*f0865ec9SKyle Evans 	/* Now initialize u as Fp element with the reduced value */
222*f0865ec9SKyle Evans 	ret = fp_init(u_coord, montgomery_curve.A.ctx); EG(ret, err);
223*f0865ec9SKyle Evans 	ret = fp_set_nn(u_coord, v_coord_nn); EG(ret, err);
224*f0865ec9SKyle Evans 
225*f0865ec9SKyle Evans 	/* Compute the v coordinate from u */
226*f0865ec9SKyle Evans 	ret = compute_v_from_u(u_coord, v_coord, &montgomery_curve); EG(ret, err);
227*f0865ec9SKyle Evans 	/* NOTE: since we use isogenies of the Curve25519/448, we must stick to points
228*f0865ec9SKyle Evans 	 * belonging to this curve. Since not all u coordinates provide a v coordinate
229*f0865ec9SKyle Evans 	 * (i.e. a square residue from the curve formula), the computation above can trigger an error.
230*f0865ec9SKyle Evans 	 * When this is the case, this means that the u coordinate is on the quadtratic twist of
231*f0865ec9SKyle Evans 	 * the Montgomery curve (which is a secure curve by design here). We could perform computations
232*f0865ec9SKyle Evans 	 * on an isogenic curve of this twist, however we choose to return an error instead.
233*f0865ec9SKyle Evans 	 *
234*f0865ec9SKyle Evans 	 * Although this is not compliant with the Curve2551/448 original spirit (that accepts any u
235*f0865ec9SKyle Evans 	 * coordinate thanks to the x-coordinate only computations with the Montgomery Ladder),
236*f0865ec9SKyle Evans 	 * we emphasize here that in the key exchange defined in RFC7748 all the exchanged points
237*f0865ec9SKyle Evans 	 * (i.e. public keys) are derived from base points that are on the curve and not on its twist, meaning
238*f0865ec9SKyle Evans 	 * that all the exchanged u coordinates should belong to the curve. Diverging from this behavior would
239*f0865ec9SKyle Evans 	 * suggest that an attacker is trying to inject other values, and we are safe to reject them in the
240*f0865ec9SKyle Evans 	 * context of Diffie-Hellman based key exchange as defined in RFC7748.
241*f0865ec9SKyle Evans 	 *
242*f0865ec9SKyle Evans 	 * On the other hand, the drawback of rejecting u coordinates on the quadratic twist is that
243*f0865ec9SKyle Evans 	 * using the current X25519/448 primitive in other contexts than RFC7748 Diffie-Hellman could be
244*f0865ec9SKyle Evans 	 * limited and non interoperable with other implementations of this primive. Another issue is that
245*f0865ec9SKyle Evans 	 * this specific divergence exposes our implementation to be distinguishable from other standard ones
246*f0865ec9SKyle Evans 	 * in a "black box" analysis context, which is generally not very desirable even if no real security
247*f0865ec9SKyle Evans 	 * issue is induced.
248*f0865ec9SKyle Evans 	 */
249*f0865ec9SKyle Evans 
250*f0865ec9SKyle Evans 	/* Get the affine point in Montgomery */
251*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_init_from_coords(&_Tmp, &montgomery_curve, u_coord, v_coord); EG(ret, err);
252*f0865ec9SKyle Evans 	/* Transfer from Montgomery to short Weierstrass using the isogeny */
253*f0865ec9SKyle Evans 	ret = aff_pt_montgomery_to_prj_pt_shortw(&_Tmp, shortw_curve, &Q); EG(ret, err);
254*f0865ec9SKyle Evans 
255*f0865ec9SKyle Evans 	/*
256*f0865ec9SKyle Evans 	 * Reject small order public keys: while this is not a strict requirement of RFC7748, there is no
257*f0865ec9SKyle Evans 	 * good reason to accept these weak values!
258*f0865ec9SKyle Evans 	 */
259*f0865ec9SKyle Evans 	ret = check_prj_pt_order(&Q, cofactor, PUBLIC_PT, &cmp); EG(ret, err);
260*f0865ec9SKyle Evans 	MUST_HAVE((!cmp), ret, err);
261*f0865ec9SKyle Evans 
262*f0865ec9SKyle Evans 	/* Import the scalar as big number NN value */
263*f0865ec9SKyle Evans 	ret = nn_init_from_buf(&scalar, k_, len); EG(ret, err);
264*f0865ec9SKyle Evans 	/* Now proceed with the scalar multiplication */
265*f0865ec9SKyle Evans #ifdef USE_SIG_BLINDING
266*f0865ec9SKyle Evans 	ret = prj_pt_mul_blind(&Q, &scalar, &Q); EG(ret, err);
267*f0865ec9SKyle Evans #else
268*f0865ec9SKyle Evans 	ret = prj_pt_mul(&Q, &scalar, &Q); EG(ret, err);
269*f0865ec9SKyle Evans #endif
270*f0865ec9SKyle Evans 
271*f0865ec9SKyle Evans 	/* Transfer back from short Weierstrass to Montgomery using the isogeny */
272*f0865ec9SKyle Evans 	ret = prj_pt_shortw_to_aff_pt_montgomery(&Q, &montgomery_curve, &_Tmp); EG(ret, err);
273*f0865ec9SKyle Evans 
274*f0865ec9SKyle Evans 	/* Reject the all zero output */
275*f0865ec9SKyle Evans 	ret = fp_iszero(&(_Tmp.u), &iszero); EG(ret, err);
276*f0865ec9SKyle Evans 	MUST_HAVE((!iszero), ret, err);
277*f0865ec9SKyle Evans 
278*f0865ec9SKyle Evans 	/* Now export the resulting u coordinate ... */
279*f0865ec9SKyle Evans 	ret = fp_export_to_buf(u_, len, &(_Tmp.u)); EG(ret, err);
280*f0865ec9SKyle Evans 	/* ... and encode it in the output */
281*f0865ec9SKyle Evans 	ret = encode_u_coordinate(res, u_, len);
282*f0865ec9SKyle Evans 
283*f0865ec9SKyle Evans err:
284*f0865ec9SKyle Evans 	IGNORE_RET_VAL(local_memset(u_, 0, sizeof(u_)));
285*f0865ec9SKyle Evans 	IGNORE_RET_VAL(local_memset(k_, 0, sizeof(k_)));
286*f0865ec9SKyle Evans 	IGNORE_RET_VAL(local_memset(&shortw_curve_params, 0, sizeof(shortw_curve_params)));
287*f0865ec9SKyle Evans 
288*f0865ec9SKyle Evans 	nn_uninit(&scalar);
289*f0865ec9SKyle Evans 	aff_pt_montgomery_uninit(&_Tmp);
290*f0865ec9SKyle Evans 	prj_pt_uninit(&Q);
291*f0865ec9SKyle Evans 	ec_montgomery_crv_uninit(&montgomery_curve);
292*f0865ec9SKyle Evans 
293*f0865ec9SKyle Evans 	PTR_NULLIFY(shortw_curve);
294*f0865ec9SKyle Evans 	PTR_NULLIFY(alpha_montgomery);
295*f0865ec9SKyle Evans 	PTR_NULLIFY(gamma_montgomery);
296*f0865ec9SKyle Evans 	PTR_NULLIFY(u_coord);
297*f0865ec9SKyle Evans 	PTR_NULLIFY(v_coord);
298*f0865ec9SKyle Evans 	PTR_NULLIFY(v_coord_nn);
299*f0865ec9SKyle Evans 	PTR_NULLIFY(cofactor);
300*f0865ec9SKyle Evans 
301*f0865ec9SKyle Evans         return ret;
302*f0865ec9SKyle Evans }
303*f0865ec9SKyle Evans 
x25519_448_gen_priv_key(u8 * priv_key,u8 len)304*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int x25519_448_gen_priv_key(u8 *priv_key, u8 len)
305*f0865ec9SKyle Evans {
306*f0865ec9SKyle Evans 	int ret;
307*f0865ec9SKyle Evans 
308*f0865ec9SKyle Evans 	MUST_HAVE((priv_key != NULL), ret, err);
309*f0865ec9SKyle Evans 	MUST_HAVE(((len == X25519_SIZE) || (len == X448_SIZE)), ret, err);
310*f0865ec9SKyle Evans 
311*f0865ec9SKyle Evans 	/* Generating a private key consists in generating a random byte string */
312*f0865ec9SKyle Evans 	ret = get_random(priv_key, len);
313*f0865ec9SKyle Evans 
314*f0865ec9SKyle Evans err:
315*f0865ec9SKyle Evans 	return ret;
316*f0865ec9SKyle Evans }
317*f0865ec9SKyle Evans 
318*f0865ec9SKyle Evans 
x25519_448_init_pub_key(const u8 * priv_key,u8 * pub_key,u8 len)319*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int x25519_448_init_pub_key(const u8 *priv_key, u8 *pub_key, u8 len)
320*f0865ec9SKyle Evans {
321*f0865ec9SKyle Evans 	int ret;
322*f0865ec9SKyle Evans 
323*f0865ec9SKyle Evans 	MUST_HAVE((priv_key != NULL) && (pub_key != NULL), ret, err);
324*f0865ec9SKyle Evans 	MUST_HAVE(((len == X25519_SIZE) || (len == X448_SIZE)), ret, err);
325*f0865ec9SKyle Evans 
326*f0865ec9SKyle Evans 	/* Computing the public key is x25519(priv_key, 9) or x448(priv_key, 5)
327*f0865ec9SKyle Evans 	 *
328*f0865ec9SKyle Evans 	 * NOTE: although we could optimize and accelerate the computation of the public
329*f0865ec9SKyle Evans 	 * key by skipping the Montgomery to Weierstrass mapping (as the base point on the two
330*f0865ec9SKyle Evans 	 * isomorphic curves are known), we rather use the regular x25519_448_core primitive
331*f0865ec9SKyle Evans 	 * as it has the advantages of keeping the code clean and simple (and the performance
332*f0865ec9SKyle Evans 	 * cost is not so expensive as the core scalar multiplication will take most of the
333*f0865ec9SKyle Evans 	 * cycles ...).
334*f0865ec9SKyle Evans 	 *
335*f0865ec9SKyle Evans 	 */
336*f0865ec9SKyle Evans 	if(len == X25519_SIZE){
337*f0865ec9SKyle Evans 		u8 u[X25519_SIZE];
338*f0865ec9SKyle Evans 
339*f0865ec9SKyle Evans 		ret = local_memset(u, 0, sizeof(u)); EG(ret, err);
340*f0865ec9SKyle Evans 		/* X25519 uses the base point with x-coordinate = 0x09 */
341*f0865ec9SKyle Evans 		u[0] = 0x09;
342*f0865ec9SKyle Evans 		ret = x25519_448_core(priv_key, u, pub_key, len);
343*f0865ec9SKyle Evans 	}
344*f0865ec9SKyle Evans 	else if(len == X448_SIZE){
345*f0865ec9SKyle Evans 		u8 u[X448_SIZE];
346*f0865ec9SKyle Evans 
347*f0865ec9SKyle Evans 		ret = local_memset(u, 0, sizeof(u)); EG(ret, err);
348*f0865ec9SKyle Evans 		/* X448 uses the base point with x-coordinate = 0x05 */
349*f0865ec9SKyle Evans 		u[0] = 0x05;
350*f0865ec9SKyle Evans 		ret = x25519_448_core(priv_key, u, pub_key, len);
351*f0865ec9SKyle Evans 	}
352*f0865ec9SKyle Evans 	else{
353*f0865ec9SKyle Evans 		ret = -1;
354*f0865ec9SKyle Evans 	}
355*f0865ec9SKyle Evans err:
356*f0865ec9SKyle Evans 	return ret;
357*f0865ec9SKyle Evans }
358*f0865ec9SKyle Evans 
x25519_448_derive_secret(const u8 * priv_key,const u8 * peer_pub_key,u8 * shared_secret,u8 len)359*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int x25519_448_derive_secret(const u8 *priv_key, const u8 *peer_pub_key, u8 *shared_secret, u8 len)
360*f0865ec9SKyle Evans {
361*f0865ec9SKyle Evans 	int ret;
362*f0865ec9SKyle Evans 
363*f0865ec9SKyle Evans 	MUST_HAVE((priv_key != NULL) && (peer_pub_key != NULL) && (shared_secret != NULL), ret, err);
364*f0865ec9SKyle Evans 	MUST_HAVE(((len == X25519_SIZE) || (len == X448_SIZE)), ret, err);
365*f0865ec9SKyle Evans 
366*f0865ec9SKyle Evans 	/* Computing the shared secret is x25519(priv_key, peer_pub_key) or x448(priv_key, peer_pub_key) */
367*f0865ec9SKyle Evans 	ret = x25519_448_core(priv_key, peer_pub_key, shared_secret, len);
368*f0865ec9SKyle Evans 
369*f0865ec9SKyle Evans err:
370*f0865ec9SKyle Evans 	return ret;
371*f0865ec9SKyle Evans }
372*f0865ec9SKyle Evans 
373*f0865ec9SKyle Evans 
374*f0865ec9SKyle Evans #if defined(WITH_X25519)
375*f0865ec9SKyle Evans /* The X25519 function as specified in RFC7748.
376*f0865ec9SKyle Evans  *
377*f0865ec9SKyle Evans  * NOTE: we use isogenies between Montgomery Curve25519 and short Weierstrass
378*f0865ec9SKyle Evans  * WEI25519 to perform the Elliptic Curves computations.
379*f0865ec9SKyle Evans  */
x25519(const u8 k[X25519_SIZE],const u8 u[X25519_SIZE],u8 res[X25519_SIZE])380*f0865ec9SKyle Evans int x25519(const u8 k[X25519_SIZE], const u8 u[X25519_SIZE], u8 res[X25519_SIZE])
381*f0865ec9SKyle Evans {
382*f0865ec9SKyle Evans 	return x25519_448_core(k, u, res, X25519_SIZE);
383*f0865ec9SKyle Evans }
384*f0865ec9SKyle Evans 
x25519_gen_priv_key(u8 priv_key[X25519_SIZE])385*f0865ec9SKyle Evans int x25519_gen_priv_key(u8 priv_key[X25519_SIZE])
386*f0865ec9SKyle Evans {
387*f0865ec9SKyle Evans 	return x25519_448_gen_priv_key(priv_key, X25519_SIZE);
388*f0865ec9SKyle Evans }
389*f0865ec9SKyle Evans 
x25519_init_pub_key(const u8 priv_key[X25519_SIZE],u8 pub_key[X25519_SIZE])390*f0865ec9SKyle Evans int x25519_init_pub_key(const u8 priv_key[X25519_SIZE], u8 pub_key[X25519_SIZE])
391*f0865ec9SKyle Evans {
392*f0865ec9SKyle Evans 	return x25519_448_init_pub_key(priv_key, pub_key, X25519_SIZE);
393*f0865ec9SKyle Evans }
394*f0865ec9SKyle Evans 
x25519_derive_secret(const u8 priv_key[X25519_SIZE],const u8 peer_pub_key[X25519_SIZE],u8 shared_secret[X25519_SIZE])395*f0865ec9SKyle Evans int x25519_derive_secret(const u8 priv_key[X25519_SIZE], const u8 peer_pub_key[X25519_SIZE], u8 shared_secret[X25519_SIZE])
396*f0865ec9SKyle Evans {
397*f0865ec9SKyle Evans 	return x25519_448_derive_secret(priv_key, peer_pub_key, shared_secret, X25519_SIZE);
398*f0865ec9SKyle Evans }
399*f0865ec9SKyle Evans #endif
400*f0865ec9SKyle Evans 
401*f0865ec9SKyle Evans #if defined(WITH_X448)
402*f0865ec9SKyle Evans /* The X448 function as specified in RFC7748.
403*f0865ec9SKyle Evans  *
404*f0865ec9SKyle Evans  * NOTE: we use isogenies between Montgomery Curve448 and short Weierstrass
405*f0865ec9SKyle Evans  * WEI448 to perform the Elliptic Curves computations.
406*f0865ec9SKyle Evans  */
x448(const u8 k[X448_SIZE],const u8 u[X448_SIZE],u8 res[X448_SIZE])407*f0865ec9SKyle Evans int x448(const u8 k[X448_SIZE], const u8 u[X448_SIZE], u8 res[X448_SIZE])
408*f0865ec9SKyle Evans {
409*f0865ec9SKyle Evans 	return x25519_448_core(k, u, res, X448_SIZE);
410*f0865ec9SKyle Evans }
411*f0865ec9SKyle Evans 
x448_gen_priv_key(u8 priv_key[X448_SIZE])412*f0865ec9SKyle Evans int x448_gen_priv_key(u8 priv_key[X448_SIZE])
413*f0865ec9SKyle Evans {
414*f0865ec9SKyle Evans 	return x25519_448_gen_priv_key(priv_key, X448_SIZE);
415*f0865ec9SKyle Evans }
416*f0865ec9SKyle Evans 
x448_init_pub_key(const u8 priv_key[X448_SIZE],u8 pub_key[X448_SIZE])417*f0865ec9SKyle Evans int x448_init_pub_key(const u8 priv_key[X448_SIZE], u8 pub_key[X448_SIZE])
418*f0865ec9SKyle Evans {
419*f0865ec9SKyle Evans 	return x25519_448_init_pub_key(priv_key, pub_key, X448_SIZE);
420*f0865ec9SKyle Evans }
421*f0865ec9SKyle Evans 
x448_derive_secret(const u8 priv_key[X448_SIZE],const u8 peer_pub_key[X448_SIZE],u8 shared_secret[X448_SIZE])422*f0865ec9SKyle Evans int x448_derive_secret(const u8 priv_key[X448_SIZE], const u8 peer_pub_key[X448_SIZE], u8 shared_secret[X448_SIZE])
423*f0865ec9SKyle Evans {
424*f0865ec9SKyle Evans 	return x25519_448_derive_secret(priv_key, peer_pub_key, shared_secret, X448_SIZE);
425*f0865ec9SKyle Evans }
426*f0865ec9SKyle Evans #endif
427*f0865ec9SKyle Evans 
428*f0865ec9SKyle Evans #else /* !(defined(WITH_X25519) || defined(WITH_X448)) */
429*f0865ec9SKyle Evans 
430*f0865ec9SKyle Evans /*
431*f0865ec9SKyle Evans  * Dummy definition to avoid the empty translation unit ISO C warning
432*f0865ec9SKyle Evans  */
433*f0865ec9SKyle Evans typedef int dummy;
434*f0865ec9SKyle Evans 
435*f0865ec9SKyle Evans #endif /* defined(WITH_X25519) || defined(WITH_X448) */
436