xref: /freebsd-src/crypto/libecc/src/nn/nn.c (revision f0865ec9906d5a18fa2a3b61381f22ce16e606ad)
1*f0865ec9SKyle Evans /*
2*f0865ec9SKyle Evans  *  Copyright (C) 2017 - 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  *      Jean-Pierre FLORI <jean-pierre.flori@ssi.gouv.fr>
8*f0865ec9SKyle Evans  *
9*f0865ec9SKyle Evans  *  Contributors:
10*f0865ec9SKyle Evans  *      Nicolas VIVET <nicolas.vivet@ssi.gouv.fr>
11*f0865ec9SKyle Evans  *      Karim KHALFALLAH <karim.khalfallah@ssi.gouv.fr>
12*f0865ec9SKyle Evans  *
13*f0865ec9SKyle Evans  *  This software is licensed under a dual BSD and GPL v2 license.
14*f0865ec9SKyle Evans  *  See LICENSE file at the root folder of the project.
15*f0865ec9SKyle Evans  */
16*f0865ec9SKyle Evans #define NN_CONSISTENCY_CHECK
17*f0865ec9SKyle Evans #include <libecc/nn/nn.h>
18*f0865ec9SKyle Evans 
19*f0865ec9SKyle Evans /*
20*f0865ec9SKyle Evans  * Used for the conditional swap algorithm SCA
21*f0865ec9SKyle Evans  * resistance, see below in the implementation of
22*f0865ec9SKyle Evans  * nn_cnd_swap.
23*f0865ec9SKyle Evans  */
24*f0865ec9SKyle Evans #include <libecc/utils/utils_rand.h>
25*f0865ec9SKyle Evans 
26*f0865ec9SKyle Evans /*
27*f0865ec9SKyle Evans  * Except otherwise specified, all functions accept *initialized* nn.
28*f0865ec9SKyle Evans  * The WORD(NN_MAX_WORD_LEN + WORDSIZE) magic is here to detect modules
29*f0865ec9SKyle Evans  * compiled with different WORDSIZE or NN_MAX_WORD_LEN and are binary
30*f0865ec9SKyle Evans  * incompatible.
31*f0865ec9SKyle Evans  */
32*f0865ec9SKyle Evans 
33*f0865ec9SKyle Evans #define NN_MAGIC ((word_t)((0xb4cf5d56e2023316ULL ^ (WORD(NN_MAX_WORD_LEN + WORDSIZE)))))
34*f0865ec9SKyle Evans 
35*f0865ec9SKyle Evans /*
36*f0865ec9SKyle Evans  * Local helper internally used to check that the storage space
37*f0865ec9SKyle Evans  * above wlen is made of zero words. The function does NOT check
38*f0865ec9SKyle Evans  * if given nn has been initialized. This must have been done
39*f0865ec9SKyle Evans  * by the caller.
40*f0865ec9SKyle Evans  *
41*f0865ec9SKyle Evans  * Due to its performance cost, this consistency check is used
42*f0865ec9SKyle Evans  * in SHOULD_HAVE macros, meaning that it will only be present
43*f0865ec9SKyle Evans  * in DEBUG mode. Hence the ATTRIBUTE_UNUSED so that no warning
44*f0865ec9SKyle Evans  * (error in -Werror) is triggered at compilation time.
45*f0865ec9SKyle Evans  *
46*f0865ec9SKyle Evans  */
47*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int ATTRIBUTE_UNUSED __nn_is_wlen_consistent(nn_src_t A)
48*f0865ec9SKyle Evans {
49*f0865ec9SKyle Evans 	word_t val = 0;
50*f0865ec9SKyle Evans 	u8 i;
51*f0865ec9SKyle Evans 
52*f0865ec9SKyle Evans 	for (i = A->wlen; i < NN_MAX_WORD_LEN; i++) {
53*f0865ec9SKyle Evans 		val |= (A)->val[i];
54*f0865ec9SKyle Evans 	}
55*f0865ec9SKyle Evans 
56*f0865ec9SKyle Evans 	return (val == 0);
57*f0865ec9SKyle Evans }
58*f0865ec9SKyle Evans 
59*f0865ec9SKyle Evans /*
60*f0865ec9SKyle Evans  * Verify that pointed nn has already been initialized. This function
61*f0865ec9SKyle Evans  * should be used as a safety net in all function before using a nn
62*f0865ec9SKyle Evans  * received as parameter. Returns 0 on success, -1 on error.
63*f0865ec9SKyle Evans  */
64*f0865ec9SKyle Evans int nn_check_initialized(nn_src_t A)
65*f0865ec9SKyle Evans {
66*f0865ec9SKyle Evans 	int ret;
67*f0865ec9SKyle Evans 
68*f0865ec9SKyle Evans 	MUST_HAVE((A != NULL), ret, err);
69*f0865ec9SKyle Evans 	MUST_HAVE((A->magic == NN_MAGIC), ret, err);
70*f0865ec9SKyle Evans 	MUST_HAVE((A->wlen <= NN_MAX_WORD_LEN), ret, err);
71*f0865ec9SKyle Evans 	SHOULD_HAVE(__nn_is_wlen_consistent(A), ret, err);
72*f0865ec9SKyle Evans 
73*f0865ec9SKyle Evans 	ret = 0;
74*f0865ec9SKyle Evans 
75*f0865ec9SKyle Evans err:
76*f0865ec9SKyle Evans 	return ret;
77*f0865ec9SKyle Evans }
78*f0865ec9SKyle Evans 
79*f0865ec9SKyle Evans /*
80*f0865ec9SKyle Evans  * Initialize nn from expected initial byte length 'len', setting its wlen
81*f0865ec9SKyle Evans  * to associated (ceil) value and clearing whole storage space. Return 0
82*f0865ec9SKyle Evans  * on success, -1 on error.
83*f0865ec9SKyle Evans  */
84*f0865ec9SKyle Evans int nn_init(nn_t A, u16 len)
85*f0865ec9SKyle Evans {
86*f0865ec9SKyle Evans 	int ret;
87*f0865ec9SKyle Evans 	u8 i;
88*f0865ec9SKyle Evans 
89*f0865ec9SKyle Evans 	MUST_HAVE(((A != NULL) && (len <= NN_MAX_BYTE_LEN)), ret, err);
90*f0865ec9SKyle Evans 
91*f0865ec9SKyle Evans 	A->wlen = (u8)BYTE_LEN_WORDS(len);
92*f0865ec9SKyle Evans 	A->magic = NN_MAGIC;
93*f0865ec9SKyle Evans 
94*f0865ec9SKyle Evans 	for (i = 0; i < NN_MAX_WORD_LEN; i++) {
95*f0865ec9SKyle Evans 		A->val[i] = WORD(0);
96*f0865ec9SKyle Evans 	}
97*f0865ec9SKyle Evans 
98*f0865ec9SKyle Evans 	ret = 0;
99*f0865ec9SKyle Evans 
100*f0865ec9SKyle Evans err:
101*f0865ec9SKyle Evans 	return ret;
102*f0865ec9SKyle Evans }
103*f0865ec9SKyle Evans 
104*f0865ec9SKyle Evans /*
105*f0865ec9SKyle Evans  * Uninitialize the pointed nn to prevent further use (magic field in the
106*f0865ec9SKyle Evans  * structure is zeroized). The associated storage space is also zeroized. If
107*f0865ec9SKyle Evans  * given pointer is NULL or does not point to an initialized nn, the function
108*f0865ec9SKyle Evans  * does nothing.
109*f0865ec9SKyle Evans  */
110*f0865ec9SKyle Evans void nn_uninit(nn_t A)
111*f0865ec9SKyle Evans {
112*f0865ec9SKyle Evans 	if ((A != NULL) && (A->magic == NN_MAGIC)) {
113*f0865ec9SKyle Evans 		int i;
114*f0865ec9SKyle Evans 
115*f0865ec9SKyle Evans 		for (i = 0; i < NN_MAX_WORD_LEN; i++) {
116*f0865ec9SKyle Evans 			A->val[i] = WORD(0);
117*f0865ec9SKyle Evans 		}
118*f0865ec9SKyle Evans 
119*f0865ec9SKyle Evans 		A->wlen = 0;
120*f0865ec9SKyle Evans 		A->magic = WORD(0);
121*f0865ec9SKyle Evans 	}
122*f0865ec9SKyle Evans 
123*f0865ec9SKyle Evans 	return;
124*f0865ec9SKyle Evans }
125*f0865ec9SKyle Evans 
126*f0865ec9SKyle Evans /*
127*f0865ec9SKyle Evans  * Set current value of pointed initialized nn to 0. Returns 0 on success, -1
128*f0865ec9SKyle Evans  * on error.
129*f0865ec9SKyle Evans  */
130*f0865ec9SKyle Evans int nn_zero(nn_t A)
131*f0865ec9SKyle Evans {
132*f0865ec9SKyle Evans 	int ret;
133*f0865ec9SKyle Evans 
134*f0865ec9SKyle Evans 	ret = nn_check_initialized(A); EG(ret, err);
135*f0865ec9SKyle Evans 	ret = nn_init(A, 0);
136*f0865ec9SKyle Evans 
137*f0865ec9SKyle Evans err:
138*f0865ec9SKyle Evans 	return ret;
139*f0865ec9SKyle Evans }
140*f0865ec9SKyle Evans 
141*f0865ec9SKyle Evans /*
142*f0865ec9SKyle Evans  * Set current value of pointed initialized nn to given word value. Returns 0
143*f0865ec9SKyle Evans  * on success, -1 on error.
144*f0865ec9SKyle Evans  */
145*f0865ec9SKyle Evans int nn_set_word_value(nn_t A, word_t val)
146*f0865ec9SKyle Evans {
147*f0865ec9SKyle Evans 	int ret;
148*f0865ec9SKyle Evans 
149*f0865ec9SKyle Evans 	ret = nn_zero(A); EG(ret, err);
150*f0865ec9SKyle Evans 
151*f0865ec9SKyle Evans 	A->val[0] = val;
152*f0865ec9SKyle Evans 	A->wlen = 1;
153*f0865ec9SKyle Evans 
154*f0865ec9SKyle Evans err:
155*f0865ec9SKyle Evans 	return ret;
156*f0865ec9SKyle Evans }
157*f0865ec9SKyle Evans 
158*f0865ec9SKyle Evans /*
159*f0865ec9SKyle Evans  * Set current value of pointed initialized nn to 1. Returns 0 on success, -1
160*f0865ec9SKyle Evans  * on error.
161*f0865ec9SKyle Evans  */
162*f0865ec9SKyle Evans int nn_one(nn_t A)
163*f0865ec9SKyle Evans {
164*f0865ec9SKyle Evans 	return nn_set_word_value(A, WORD(1));
165*f0865ec9SKyle Evans }
166*f0865ec9SKyle Evans 
167*f0865ec9SKyle Evans /*
168*f0865ec9SKyle Evans  * Conditionally swap two nn's content *in constant time*. Swapping is done
169*f0865ec9SKyle Evans  * if 'cnd' is not zero. Nothing is done otherwise. Returns 0 on success, -1
170*f0865ec9SKyle Evans  * on error.
171*f0865ec9SKyle Evans  *
172*f0865ec9SKyle Evans  * Aliasing of inputs is supported.
173*f0865ec9SKyle Evans  */
174*f0865ec9SKyle Evans int nn_cnd_swap(int cnd, nn_t in1, nn_t in2)
175*f0865ec9SKyle Evans {
176*f0865ec9SKyle Evans 	word_t mask = WORD_MASK_IFNOTZERO(cnd);
177*f0865ec9SKyle Evans 	u8 len, i;
178*f0865ec9SKyle Evans 	word_t t, r;
179*f0865ec9SKyle Evans 	volatile word_t r_mask;
180*f0865ec9SKyle Evans 	int ret;
181*f0865ec9SKyle Evans 
182*f0865ec9SKyle Evans 	ret = nn_check_initialized(in1); EG(ret, err);
183*f0865ec9SKyle Evans 	ret = nn_check_initialized(in2); EG(ret, err);
184*f0865ec9SKyle Evans 
185*f0865ec9SKyle Evans 	MUST_HAVE((in1->wlen <= NN_MAX_WORD_LEN), ret, err);
186*f0865ec9SKyle Evans 	MUST_HAVE((in2->wlen <= NN_MAX_WORD_LEN), ret, err);
187*f0865ec9SKyle Evans 
188*f0865ec9SKyle Evans 	len = (in1->wlen >= in2->wlen) ? in1->wlen : in2->wlen;
189*f0865ec9SKyle Evans 
190*f0865ec9SKyle Evans 	/* Use a random word for randomly masking the delta value hamming
191*f0865ec9SKyle Evans 	 * weight as proposed in Algorithm 4 of "Nonce@once: A Single-Trace
192*f0865ec9SKyle Evans 	 * EM Side Channel Attack on Several Constant-Time Elliptic
193*f0865ec9SKyle Evans 	 * Curve Implementations in Mobile Platforms" by Alam et al.
194*f0865ec9SKyle Evans 	 */
195*f0865ec9SKyle Evans 	ret = get_unsafe_random((u8*)&r, sizeof(r)); EG(ret, err);
196*f0865ec9SKyle Evans 	r_mask = r;
197*f0865ec9SKyle Evans 
198*f0865ec9SKyle Evans 	for (i = 0; i < NN_MAX_WORD_LEN; i++) {
199*f0865ec9SKyle Evans 		word_t local_mask = WORD_MASK_IFNOTZERO((i < len));
200*f0865ec9SKyle Evans 		t = ((in1->val[i] ^ in2->val[i]) & mask) ^ r_mask;
201*f0865ec9SKyle Evans 		in1->val[i] ^= ((t & local_mask) ^ (r_mask & local_mask));
202*f0865ec9SKyle Evans 		in2->val[i] ^= ((t & local_mask) ^ (r_mask & local_mask));
203*f0865ec9SKyle Evans 	}
204*f0865ec9SKyle Evans 
205*f0865ec9SKyle Evans 	t = (word_t)(((in1->wlen ^ in2->wlen) & mask) ^ r_mask);
206*f0865ec9SKyle Evans 	in1->wlen ^= (u8)(t ^ r_mask);
207*f0865ec9SKyle Evans 	in2->wlen ^= (u8)(t ^ r_mask);
208*f0865ec9SKyle Evans 
209*f0865ec9SKyle Evans err:
210*f0865ec9SKyle Evans 	return ret;
211*f0865ec9SKyle Evans }
212*f0865ec9SKyle Evans 
213*f0865ec9SKyle Evans /*
214*f0865ec9SKyle Evans  * Adjust internal wlen attribute of given nn to new_wlen. If internal wlen
215*f0865ec9SKyle Evans  * attribute value is reduced, words above that limit in A are zeroized.
216*f0865ec9SKyle Evans  * new_wlen must be in [0, NN_MAX_WORD_LEN].
217*f0865ec9SKyle Evans  * The trimming is performed in constant time wrt to the length of the
218*f0865ec9SKyle Evans  * input to avoid leaking it.
219*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
220*f0865ec9SKyle Evans  */
221*f0865ec9SKyle Evans int nn_set_wlen(nn_t A, u8 new_wlen)
222*f0865ec9SKyle Evans {
223*f0865ec9SKyle Evans 	int ret;
224*f0865ec9SKyle Evans 	u8 i;
225*f0865ec9SKyle Evans 
226*f0865ec9SKyle Evans 	ret = nn_check_initialized(A); EG(ret, err);
227*f0865ec9SKyle Evans 	MUST_HAVE((new_wlen <= NN_MAX_WORD_LEN), ret, err);
228*f0865ec9SKyle Evans 	MUST_HAVE((A->wlen <= NN_MAX_WORD_LEN), ret, err);
229*f0865ec9SKyle Evans 
230*f0865ec9SKyle Evans 	/* Trimming performed in constant time */
231*f0865ec9SKyle Evans 	for (i = 0; i < NN_MAX_WORD_LEN; i++) {
232*f0865ec9SKyle Evans 		A->val[i] = (word_t)(A->val[i] & WORD_MASK_IFZERO((i >= new_wlen)));
233*f0865ec9SKyle Evans 	}
234*f0865ec9SKyle Evans 
235*f0865ec9SKyle Evans 	A->wlen = new_wlen;
236*f0865ec9SKyle Evans 
237*f0865ec9SKyle Evans err:
238*f0865ec9SKyle Evans 	return ret;
239*f0865ec9SKyle Evans }
240*f0865ec9SKyle Evans 
241*f0865ec9SKyle Evans /*
242*f0865ec9SKyle Evans  * The function tests if given nn value is zero. The result of the test is given
243*f0865ec9SKyle Evans  * using 'iszero' out parameter (1 if nn is zero, 0 if it is not). The function
244*f0865ec9SKyle Evans  * returns 0 on success, -1 on error. 'iszero' is not meaningfull on error.
245*f0865ec9SKyle Evans  * When A is valid, check is done *in constant time*.
246*f0865ec9SKyle Evans  */
247*f0865ec9SKyle Evans int nn_iszero(nn_src_t A, int *iszero)
248*f0865ec9SKyle Evans {
249*f0865ec9SKyle Evans 	int ret, notzero;
250*f0865ec9SKyle Evans 	u8 i;
251*f0865ec9SKyle Evans 
252*f0865ec9SKyle Evans 	ret = nn_check_initialized(A); EG(ret, err);
253*f0865ec9SKyle Evans 	MUST_HAVE((A->wlen <= NN_MAX_WORD_LEN), ret, err);
254*f0865ec9SKyle Evans 	MUST_HAVE((iszero != NULL), ret, err);
255*f0865ec9SKyle Evans 
256*f0865ec9SKyle Evans 	notzero = 0;
257*f0865ec9SKyle Evans 	for (i = 0; i < NN_MAX_WORD_LEN; i++) {
258*f0865ec9SKyle Evans 		int mask = ((i < A->wlen) ? 1 : 0);
259*f0865ec9SKyle Evans 		notzero |= ((A->val[i] != 0) & mask);
260*f0865ec9SKyle Evans 	}
261*f0865ec9SKyle Evans 
262*f0865ec9SKyle Evans 	*iszero = !notzero;
263*f0865ec9SKyle Evans 
264*f0865ec9SKyle Evans err:
265*f0865ec9SKyle Evans 	return ret;
266*f0865ec9SKyle Evans }
267*f0865ec9SKyle Evans 
268*f0865ec9SKyle Evans /*
269*f0865ec9SKyle Evans  * The function tests if given nn value is one. The result of the test is given
270*f0865ec9SKyle Evans  * using 'isone' out parameter (1 if nn is one, 0 if it is not). The function
271*f0865ec9SKyle Evans  * returns 0 on success, -1 on error. 'isone' is not meaningfull on error.
272*f0865ec9SKyle Evans  * When A is valid, check is done *in constant time*.
273*f0865ec9SKyle Evans  */
274*f0865ec9SKyle Evans int nn_isone(nn_src_t A, int *isone)
275*f0865ec9SKyle Evans {
276*f0865ec9SKyle Evans 	int ret, notone;
277*f0865ec9SKyle Evans 	u8 i;
278*f0865ec9SKyle Evans 
279*f0865ec9SKyle Evans 	ret = nn_check_initialized(A); EG(ret, err);
280*f0865ec9SKyle Evans 	MUST_HAVE(!(A->wlen > NN_MAX_WORD_LEN), ret, err);
281*f0865ec9SKyle Evans 	MUST_HAVE((isone != NULL), ret, err);
282*f0865ec9SKyle Evans 
283*f0865ec9SKyle Evans 	/* val[0] access is ok no matter wlen value */
284*f0865ec9SKyle Evans 	notone = (A->val[0] != 1);
285*f0865ec9SKyle Evans 	for (i = 1; i < NN_MAX_WORD_LEN; i++) {
286*f0865ec9SKyle Evans 		int mask = ((i < A->wlen) ? 1 : 0);
287*f0865ec9SKyle Evans 		notone |= ((A->val[i] != 0) & mask);
288*f0865ec9SKyle Evans 	}
289*f0865ec9SKyle Evans 
290*f0865ec9SKyle Evans 	*isone = !notone;
291*f0865ec9SKyle Evans 
292*f0865ec9SKyle Evans err:
293*f0865ec9SKyle Evans 	return ret;
294*f0865ec9SKyle Evans }
295*f0865ec9SKyle Evans 
296*f0865ec9SKyle Evans /*
297*f0865ec9SKyle Evans  * The function tests if given nn value is odd. The result of the test is given
298*f0865ec9SKyle Evans  * using 'isodd' out parameter (1 if nn is odd, 0 if it is not). The function
299*f0865ec9SKyle Evans  * returns 0 on success, -1 on error. 'isodd' is not meaningfull on error.
300*f0865ec9SKyle Evans  */
301*f0865ec9SKyle Evans int nn_isodd(nn_src_t A, int *isodd)
302*f0865ec9SKyle Evans {
303*f0865ec9SKyle Evans 	int ret;
304*f0865ec9SKyle Evans 
305*f0865ec9SKyle Evans 	ret = nn_check_initialized(A); EG(ret, err);
306*f0865ec9SKyle Evans 	MUST_HAVE((isodd != NULL), ret, err);
307*f0865ec9SKyle Evans 
308*f0865ec9SKyle Evans 	*isodd = (A->wlen != 0) && (A->val[0] & 1);
309*f0865ec9SKyle Evans 
310*f0865ec9SKyle Evans err:
311*f0865ec9SKyle Evans 	return ret;
312*f0865ec9SKyle Evans }
313*f0865ec9SKyle Evans 
314*f0865ec9SKyle Evans /*
315*f0865ec9SKyle Evans  * Compare given nn against given word value. This is done *in constant time*
316*f0865ec9SKyle Evans  * (only depending on the input length, not on its value or on the word value)
317*f0865ec9SKyle Evans  * when provided nn is valid. The function returns 0 on success and provides
318*f0865ec9SKyle Evans  * the comparison value in 'cmp' parameter. -1 is returned on error, in which
319*f0865ec9SKyle Evans  * case 'cmp' is not meaningful.
320*f0865ec9SKyle Evans  */
321*f0865ec9SKyle Evans int nn_cmp_word(nn_src_t in, word_t w, int *cmp)
322*f0865ec9SKyle Evans {
323*f0865ec9SKyle Evans 	int ret, tmp = 0;
324*f0865ec9SKyle Evans 	word_t mask;
325*f0865ec9SKyle Evans 	u8 i;
326*f0865ec9SKyle Evans 
327*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
328*f0865ec9SKyle Evans 	MUST_HAVE((cmp != NULL), ret, err);
329*f0865ec9SKyle Evans 
330*f0865ec9SKyle Evans 	/* No need to read, we can conclude */
331*f0865ec9SKyle Evans 	if (in->wlen == 0) {
332*f0865ec9SKyle Evans 		*cmp = -(w != 0);
333*f0865ec9SKyle Evans 		ret = 0;
334*f0865ec9SKyle Evans 		goto err;
335*f0865ec9SKyle Evans 	}
336*f0865ec9SKyle Evans 
337*f0865ec9SKyle Evans 	/*
338*f0865ec9SKyle Evans 	 * Let's loop on all words above first one to see if one
339*f0865ec9SKyle Evans 	 * of those is non-zero.
340*f0865ec9SKyle Evans 	 */
341*f0865ec9SKyle Evans 	for (i = (u8)(in->wlen - 1); i > 0; i--) {
342*f0865ec9SKyle Evans 		tmp |= (in->val[i] != 0);
343*f0865ec9SKyle Evans 	}
344*f0865ec9SKyle Evans 
345*f0865ec9SKyle Evans 	/*
346*f0865ec9SKyle Evans 	 * Compare first word of nn w/ w if needed. This
347*f0865ec9SKyle Evans 	 * is done w/ masking to avoid doing or not doing
348*f0865ec9SKyle Evans 	 * it based on 'tmp' (i.e. fact that a high word
349*f0865ec9SKyle Evans 	 * of nn is not zero).
350*f0865ec9SKyle Evans 	 */
351*f0865ec9SKyle Evans 	mask = WORD_MASK_IFZERO(tmp);
352*f0865ec9SKyle Evans 	tmp += (int)(((word_t)(in->val[i] > w)) & (mask));
353*f0865ec9SKyle Evans 	tmp -= (int)(((word_t)(in->val[i] < w)) & (mask));
354*f0865ec9SKyle Evans 	*cmp = tmp;
355*f0865ec9SKyle Evans 
356*f0865ec9SKyle Evans err:
357*f0865ec9SKyle Evans 	return ret;
358*f0865ec9SKyle Evans }
359*f0865ec9SKyle Evans 
360*f0865ec9SKyle Evans /*
361*f0865ec9SKyle Evans  * Compare given two nn 'A' and '. This is done *in constant time* (only
362*f0865ec9SKyle Evans  * depending on the largest length of the inputs, not on their values). The
363*f0865ec9SKyle Evans  * function returns 0 on success and provides the comparison value in
364*f0865ec9SKyle Evans  * 'cmp' parameter (0 if A == B, -1 if A < B, +1 if A > B). -1 is returned
365*f0865ec9SKyle Evans  * on error, in which case 'cmp' is not meaningful.
366*f0865ec9SKyle Evans  *
367*f0865ec9SKyle Evans  * Aliasing of inputs is supported.
368*f0865ec9SKyle Evans  */
369*f0865ec9SKyle Evans int nn_cmp(nn_src_t A, nn_src_t B, int *cmp)
370*f0865ec9SKyle Evans {
371*f0865ec9SKyle Evans 	int tmp, mask, ret, i;
372*f0865ec9SKyle Evans 	u8 cmp_len;
373*f0865ec9SKyle Evans 
374*f0865ec9SKyle Evans 	ret = nn_check_initialized(A); EG(ret, err);
375*f0865ec9SKyle Evans 	ret = nn_check_initialized(B); EG(ret, err);
376*f0865ec9SKyle Evans 	MUST_HAVE((cmp != NULL), ret, err);
377*f0865ec9SKyle Evans 
378*f0865ec9SKyle Evans 	cmp_len = (A->wlen >= B->wlen) ? A->wlen : B->wlen;
379*f0865ec9SKyle Evans 
380*f0865ec9SKyle Evans 	tmp = 0;
381*f0865ec9SKyle Evans 	for (i = (cmp_len - 1); i >= 0; i--) {	/* ok even if cmp_len is 0 */
382*f0865ec9SKyle Evans 		mask = !(tmp & 0x1);
383*f0865ec9SKyle Evans 		tmp += ((A->val[i] > B->val[i]) & mask);
384*f0865ec9SKyle Evans 		tmp -= ((A->val[i] < B->val[i]) & mask);
385*f0865ec9SKyle Evans 	}
386*f0865ec9SKyle Evans 	(*cmp) = tmp;
387*f0865ec9SKyle Evans 
388*f0865ec9SKyle Evans err:
389*f0865ec9SKyle Evans 	return ret;
390*f0865ec9SKyle Evans }
391*f0865ec9SKyle Evans 
392*f0865ec9SKyle Evans /*
393*f0865ec9SKyle Evans  * Copy given nn 'src_nn' value into 'dst_nn'. This is done *in constant time*.
394*f0865ec9SKyle Evans  * 'dst_nn' must point to a declared nn, but *need not be initialized*; it will
395*f0865ec9SKyle Evans  * be (manually) initialized by the function. 'src_nn' must have been
396*f0865ec9SKyle Evans  * initialized prior to the call. The function returns 0 on success, -1 on error.
397*f0865ec9SKyle Evans  *
398*f0865ec9SKyle Evans  * Alising of input and output is supported.
399*f0865ec9SKyle Evans  */
400*f0865ec9SKyle Evans int nn_copy(nn_t dst_nn, nn_src_t src_nn)
401*f0865ec9SKyle Evans {
402*f0865ec9SKyle Evans 	int ret;
403*f0865ec9SKyle Evans 	u8 i;
404*f0865ec9SKyle Evans 
405*f0865ec9SKyle Evans 	MUST_HAVE((dst_nn != NULL), ret, err);
406*f0865ec9SKyle Evans 	ret = nn_check_initialized(src_nn); EG(ret, err);
407*f0865ec9SKyle Evans 
408*f0865ec9SKyle Evans 	for (i = 0; i < NN_MAX_WORD_LEN; i++) {
409*f0865ec9SKyle Evans 		dst_nn->val[i] = src_nn->val[i];
410*f0865ec9SKyle Evans 	}
411*f0865ec9SKyle Evans 
412*f0865ec9SKyle Evans 	dst_nn->wlen = src_nn->wlen;
413*f0865ec9SKyle Evans 	dst_nn->magic = NN_MAGIC;
414*f0865ec9SKyle Evans 
415*f0865ec9SKyle Evans err:
416*f0865ec9SKyle Evans 	return ret;
417*f0865ec9SKyle Evans }
418*f0865ec9SKyle Evans 
419*f0865ec9SKyle Evans /*
420*f0865ec9SKyle Evans  * Update wlen value of given nn if a set of words below wlen value are zero.
421*f0865ec9SKyle Evans  * The function is *not constant time*, i.e. it depends on the input value.
422*f0865ec9SKyle Evans  * The function returns 0 on sucess, -1 on error.
423*f0865ec9SKyle Evans  */
424*f0865ec9SKyle Evans int nn_normalize(nn_t in1)
425*f0865ec9SKyle Evans {
426*f0865ec9SKyle Evans 	int ret;
427*f0865ec9SKyle Evans 
428*f0865ec9SKyle Evans 	ret = nn_check_initialized(in1); EG(ret, err);
429*f0865ec9SKyle Evans 
430*f0865ec9SKyle Evans 	while ((in1->wlen > 0) && (in1->val[in1->wlen - 1] == 0)) {
431*f0865ec9SKyle Evans 		in1->wlen--;
432*f0865ec9SKyle Evans 	}
433*f0865ec9SKyle Evans 
434*f0865ec9SKyle Evans err:
435*f0865ec9SKyle Evans 	return ret;
436*f0865ec9SKyle Evans }
437*f0865ec9SKyle Evans 
438*f0865ec9SKyle Evans /*
439*f0865ec9SKyle Evans  * Convert given consecutive WORD_BYTES bytes pointed by 'val' from network (big
440*f0865ec9SKyle Evans  * endian) order to host order. 'val' needs not point to a word-aligned region.
441*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error. On success, the result is
442*f0865ec9SKyle Evans  * provided in 'out'. 'out' is not meaningful on error.
443*f0865ec9SKyle Evans  */
444*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static int _ntohw(const u8 *val, word_t *out)
445*f0865ec9SKyle Evans {
446*f0865ec9SKyle Evans 	word_t res = 0;
447*f0865ec9SKyle Evans 	u8 *res_buf = (u8 *)(&res);
448*f0865ec9SKyle Evans 	int i, ret;
449*f0865ec9SKyle Evans 
450*f0865ec9SKyle Evans 	MUST_HAVE(((val != NULL) && (out != NULL)), ret, err);
451*f0865ec9SKyle Evans 
452*f0865ec9SKyle Evans 	if (arch_is_big_endian()) {
453*f0865ec9SKyle Evans 		/* copy bytes, one by one to avoid alignement issues */
454*f0865ec9SKyle Evans 		for (i = 0; i < WORD_BYTES; i++) {
455*f0865ec9SKyle Evans 			res_buf[i] = val[i];
456*f0865ec9SKyle Evans 		}
457*f0865ec9SKyle Evans 	} else {
458*f0865ec9SKyle Evans 		u8 tmp;
459*f0865ec9SKyle Evans 
460*f0865ec9SKyle Evans 		for (i = 0; i < (WORD_BYTES / 2); i++) {
461*f0865ec9SKyle Evans 			tmp = val[i];
462*f0865ec9SKyle Evans 			res_buf[i] = val[WORD_BYTES - i - 1];
463*f0865ec9SKyle Evans 			res_buf[WORD_BYTES - i - 1] = tmp;
464*f0865ec9SKyle Evans 		}
465*f0865ec9SKyle Evans 
466*f0865ec9SKyle Evans 		VAR_ZEROIFY(tmp);
467*f0865ec9SKyle Evans 	}
468*f0865ec9SKyle Evans 
469*f0865ec9SKyle Evans 	*out = res;
470*f0865ec9SKyle Evans 	ret = 0;
471*f0865ec9SKyle Evans 
472*f0865ec9SKyle Evans err:
473*f0865ec9SKyle Evans 	return ret;
474*f0865ec9SKyle Evans }
475*f0865ec9SKyle Evans 
476*f0865ec9SKyle Evans /* Same as previous function but from host to network byte order. */
477*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static inline int _htonw(const u8 *val, word_t *out)
478*f0865ec9SKyle Evans {
479*f0865ec9SKyle Evans 	return _ntohw(val, out);
480*f0865ec9SKyle Evans }
481*f0865ec9SKyle Evans 
482*f0865ec9SKyle Evans /*
483*f0865ec9SKyle Evans  * 'out_nn' is expected to point to the storage location of a declared nn,
484*f0865ec9SKyle Evans  * which will be initialized by the function (i.e. given nn need not be
485*f0865ec9SKyle Evans  * initialized). The function then imports value (expected to be in big
486*f0865ec9SKyle Evans  * endian) from given buffer 'buf' of length 'buflen' into it. The function
487*f0865ec9SKyle Evans  * expects (and enforces) that buflen is less than or equal to NN_MAX_BYTE_LEN.
488*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
489*f0865ec9SKyle Evans  */
490*f0865ec9SKyle Evans int nn_init_from_buf(nn_t out_nn, const u8 *buf, u16 buflen)
491*f0865ec9SKyle Evans {
492*f0865ec9SKyle Evans 	u8 tmp[NN_MAX_BYTE_LEN];
493*f0865ec9SKyle Evans 	u16 wpos;
494*f0865ec9SKyle Evans 	int ret;
495*f0865ec9SKyle Evans 
496*f0865ec9SKyle Evans 	MUST_HAVE(((out_nn != NULL) && (buf != NULL) &&
497*f0865ec9SKyle Evans 		  (buflen <= NN_MAX_BYTE_LEN)), ret, err);
498*f0865ec9SKyle Evans 
499*f0865ec9SKyle Evans 	ret = local_memset(tmp, 0, (u32)(NN_MAX_BYTE_LEN - buflen)); EG(ret, err);
500*f0865ec9SKyle Evans 	ret = local_memcpy(tmp + NN_MAX_BYTE_LEN - buflen, buf, buflen); EG(ret, err);
501*f0865ec9SKyle Evans 
502*f0865ec9SKyle Evans 	ret = nn_init(out_nn, buflen); EG(ret, err);
503*f0865ec9SKyle Evans 
504*f0865ec9SKyle Evans 	for (wpos = 0; wpos < NN_MAX_WORD_LEN; wpos++) {
505*f0865ec9SKyle Evans 		u16 buf_pos = (u16)((NN_MAX_WORD_LEN - wpos - 1) * WORD_BYTES);
506*f0865ec9SKyle Evans 		ret = _ntohw(tmp + buf_pos, &(out_nn->val[wpos])); EG(ret, err);
507*f0865ec9SKyle Evans 	}
508*f0865ec9SKyle Evans 
509*f0865ec9SKyle Evans 	ret = local_memset(tmp, 0, NN_MAX_BYTE_LEN);
510*f0865ec9SKyle Evans 
511*f0865ec9SKyle Evans err:
512*f0865ec9SKyle Evans 	return ret;
513*f0865ec9SKyle Evans }
514*f0865ec9SKyle Evans 
515*f0865ec9SKyle Evans /*
516*f0865ec9SKyle Evans  * Export 'buflen' LSB bytes of given nn as a big endian buffer. If buffer
517*f0865ec9SKyle Evans  * length is larger than effective size of input nn, padding w/ zero is
518*f0865ec9SKyle Evans  * performed. If buffer size is smaller than input nn effective size,
519*f0865ec9SKyle Evans  * MSB bytes are simply lost in exported buffer. The function returns 0
520*f0865ec9SKyle Evans  * on success, -1 on error.
521*f0865ec9SKyle Evans  */
522*f0865ec9SKyle Evans int nn_export_to_buf(u8 *buf, u16 buflen, nn_src_t in_nn)
523*f0865ec9SKyle Evans {
524*f0865ec9SKyle Evans 	u8 *src_word_ptr, *dst_word_ptr;
525*f0865ec9SKyle Evans 	const u8 wb = WORD_BYTES;
526*f0865ec9SKyle Evans 	u16 remain = buflen;
527*f0865ec9SKyle Evans 	int ret;
528*f0865ec9SKyle Evans 	u8 i;
529*f0865ec9SKyle Evans 
530*f0865ec9SKyle Evans 	MUST_HAVE((buf != NULL), ret, err);
531*f0865ec9SKyle Evans 	ret = nn_check_initialized(in_nn); EG(ret, err);
532*f0865ec9SKyle Evans 
533*f0865ec9SKyle Evans 	ret = local_memset(buf, 0, buflen); EG(ret, err);
534*f0865ec9SKyle Evans 
535*f0865ec9SKyle Evans 	/*
536*f0865ec9SKyle Evans 	 * We consider each word in input nn one at a time and convert
537*f0865ec9SKyle Evans 	 * it to big endian in a temporary word. Based on remaining
538*f0865ec9SKyle Evans 	 * length of output buffer, we copy the LSB bytes of temporary
539*f0865ec9SKyle Evans 	 * word into it at current position. That way, filling of the
540*f0865ec9SKyle Evans 	 * buffer is performed from its end to its beginning, word by
541*f0865ec9SKyle Evans 	 * word, except for the last one, which may be shorten if
542*f0865ec9SKyle Evans 	 * given buffer length is not a multiple of word length.
543*f0865ec9SKyle Evans 	 */
544*f0865ec9SKyle Evans 	for (i = 0; remain && (i < in_nn->wlen); i++) {
545*f0865ec9SKyle Evans 		u16 copylen = (remain > wb) ? wb : remain;
546*f0865ec9SKyle Evans 		word_t val;
547*f0865ec9SKyle Evans 
548*f0865ec9SKyle Evans 		ret = _htonw((const u8 *)&in_nn->val[i], &val); EG(ret, err);
549*f0865ec9SKyle Evans 
550*f0865ec9SKyle Evans 		dst_word_ptr = (buf + buflen - (i * wb) - copylen);
551*f0865ec9SKyle Evans 		src_word_ptr = (u8 *)(&val) + wb - copylen;
552*f0865ec9SKyle Evans 
553*f0865ec9SKyle Evans 		ret = local_memcpy(dst_word_ptr, src_word_ptr, copylen); EG(ret, err);
554*f0865ec9SKyle Evans 		src_word_ptr = NULL;
555*f0865ec9SKyle Evans 
556*f0865ec9SKyle Evans 		remain = (u16)(remain - copylen);
557*f0865ec9SKyle Evans 	}
558*f0865ec9SKyle Evans 
559*f0865ec9SKyle Evans err:
560*f0865ec9SKyle Evans 	return ret;
561*f0865ec9SKyle Evans }
562*f0865ec9SKyle Evans 
563*f0865ec9SKyle Evans /*
564*f0865ec9SKyle Evans  * Given a table 'tab' pointing to a set of 'tabsize' NN elements, the
565*f0865ec9SKyle Evans  * function copies the value of element at position idx (idx < tabsize)
566*f0865ec9SKyle Evans  * in 'out' parameters. Masking is used to avoid leaking which element
567*f0865ec9SKyle Evans  * was copied.
568*f0865ec9SKyle Evans  *
569*f0865ec9SKyle Evans  * Note that the main copying loop is done on the maximum bits for all
570*f0865ec9SKyle Evans  * NN elements and not based on the specific effective size of each
571*f0865ec9SKyle Evans  * NN elements in 'tab'
572*f0865ec9SKyle Evans  *
573*f0865ec9SKyle Evans  * Returns 0 on success, -1 on error.
574*f0865ec9SKyle Evans  *
575*f0865ec9SKyle Evans  * Aliasing of out and the selected element inside the tab is NOT supported.
576*f0865ec9SKyle Evans  */
577*f0865ec9SKyle Evans int nn_tabselect(nn_t out, u8 idx, nn_src_t *tab, u8 tabsize)
578*f0865ec9SKyle Evans {
579*f0865ec9SKyle Evans 	u8 i, k;
580*f0865ec9SKyle Evans 	word_t mask;
581*f0865ec9SKyle Evans 	int ret;
582*f0865ec9SKyle Evans 
583*f0865ec9SKyle Evans 	/* Basic sanity checks */
584*f0865ec9SKyle Evans 	MUST_HAVE(((tab != NULL) && (idx < tabsize)), ret, err);
585*f0865ec9SKyle Evans 
586*f0865ec9SKyle Evans 	ret = nn_check_initialized(out); EG(ret, err);
587*f0865ec9SKyle Evans 
588*f0865ec9SKyle Evans 	/* Zeroize out and enforce its size. */
589*f0865ec9SKyle Evans 	ret = nn_zero(out); EG(ret, err);
590*f0865ec9SKyle Evans 
591*f0865ec9SKyle Evans 	out->wlen = 0;
592*f0865ec9SKyle Evans 
593*f0865ec9SKyle Evans 	for (k = 0; k < tabsize; k++) {
594*f0865ec9SKyle Evans 		/* Check current element is initialized */
595*f0865ec9SKyle Evans 		ret = nn_check_initialized(tab[k]); EG(ret, err);
596*f0865ec9SKyle Evans 
597*f0865ec9SKyle Evans 		mask = WORD_MASK_IFNOTZERO(idx == k);
598*f0865ec9SKyle Evans 
599*f0865ec9SKyle Evans 		out->wlen = (u8)(out->wlen | ((tab[k]->wlen) & mask));
600*f0865ec9SKyle Evans 
601*f0865ec9SKyle Evans 		for (i = 0; i < NN_MAX_WORD_LEN; i++) {
602*f0865ec9SKyle Evans 			out->val[i] |= (tab[k]->val[i] & mask);
603*f0865ec9SKyle Evans 		}
604*f0865ec9SKyle Evans 	}
605*f0865ec9SKyle Evans 
606*f0865ec9SKyle Evans err:
607*f0865ec9SKyle Evans 	return ret;
608*f0865ec9SKyle Evans }
609