xref: /freebsd-src/crypto/libecc/src/nn/nn_logical.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 #include <libecc/nn/nn_logical.h>
17*f0865ec9SKyle Evans #include <libecc/nn/nn.h>
18*f0865ec9SKyle Evans 
19*f0865ec9SKyle Evans /*
20*f0865ec9SKyle Evans  * nn_lshift_fixedlen: left logical shift in N, i.e. compute out = (in << cnt).
21*f0865ec9SKyle Evans  *
22*f0865ec9SKyle Evans  * Aliasing is possible for 'in' and 'out', i.e. x <<= cnt can be computed
23*f0865ec9SKyle Evans  * using nn_lshift_fixedlen(x, x, cnt).
24*f0865ec9SKyle Evans  *
25*f0865ec9SKyle Evans  * The function supports 'in' and 'out' parameters of differents sizes.
26*f0865ec9SKyle Evans  *
27*f0865ec9SKyle Evans  * The operation time of the function depends on the size of 'in' and
28*f0865ec9SKyle Evans  * 'out' parameters and the value of 'cnt'. It does not depend on the
29*f0865ec9SKyle Evans  * value of 'in'.
30*f0865ec9SKyle Evans  *
31*f0865ec9SKyle Evans  * It is to be noted that the function uses out->wlen as the
32*f0865ec9SKyle Evans  * upper limit for its work, i.e. bits shifted above out->wlen
33*f0865ec9SKyle Evans  * are lost (the NN size of the output is not modified).
34*f0865ec9SKyle Evans  *
35*f0865ec9SKyle Evans  * The function returns 0 on sucess, -1 on error.
36*f0865ec9SKyle Evans  *
37*f0865ec9SKyle Evans  * Aliasing supported.
38*f0865ec9SKyle Evans  */
39*f0865ec9SKyle Evans int nn_lshift_fixedlen(nn_t out, nn_src_t in, bitcnt_t cnt)
40*f0865ec9SKyle Evans {
41*f0865ec9SKyle Evans 	int ipos, opos, dec, ret;
42*f0865ec9SKyle Evans 	bitcnt_t lshift, hshift;
43*f0865ec9SKyle Evans 	u8 owlen, iwlen;
44*f0865ec9SKyle Evans 
45*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
46*f0865ec9SKyle Evans 	ret = nn_check_initialized(out); EG(ret, err);
47*f0865ec9SKyle Evans 	owlen = out->wlen;
48*f0865ec9SKyle Evans 	iwlen = in->wlen;
49*f0865ec9SKyle Evans 
50*f0865ec9SKyle Evans 	dec = cnt / WORD_BITS;
51*f0865ec9SKyle Evans 	hshift = cnt % WORD_BITS;
52*f0865ec9SKyle Evans 	lshift = (bitcnt_t)(WORD_BITS - hshift);
53*f0865ec9SKyle Evans 
54*f0865ec9SKyle Evans 	for (opos = owlen - 1; opos >= 0; opos--) {
55*f0865ec9SKyle Evans 		word_t hipart = 0, lopart = 0;
56*f0865ec9SKyle Evans 
57*f0865ec9SKyle Evans 		ipos = opos - dec - 1;
58*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
59*f0865ec9SKyle Evans 			lopart = WRSHIFT(in->val[ipos], lshift);
60*f0865ec9SKyle Evans 		}
61*f0865ec9SKyle Evans 
62*f0865ec9SKyle Evans 		ipos = opos - dec;
63*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
64*f0865ec9SKyle Evans 			hipart = WLSHIFT(in->val[ipos], hshift);
65*f0865ec9SKyle Evans 		}
66*f0865ec9SKyle Evans 
67*f0865ec9SKyle Evans 		out->val[opos] = hipart | lopart;
68*f0865ec9SKyle Evans 	}
69*f0865ec9SKyle Evans 
70*f0865ec9SKyle Evans err:
71*f0865ec9SKyle Evans 	return ret;
72*f0865ec9SKyle Evans }
73*f0865ec9SKyle Evans 
74*f0865ec9SKyle Evans /*
75*f0865ec9SKyle Evans  * nn_lshift: left logical shift in N, i.e. compute out = (in << cnt).
76*f0865ec9SKyle Evans  *
77*f0865ec9SKyle Evans  * Aliasing is possible for 'in' and 'out', i.e. x <<= cnt can be computed
78*f0865ec9SKyle Evans  * using nn_lshift(x, x, cnt).
79*f0865ec9SKyle Evans  *
80*f0865ec9SKyle Evans  * The function supports 'in' and 'out' parameters of differents sizes.
81*f0865ec9SKyle Evans  *
82*f0865ec9SKyle Evans  * The operation time of the function depends on the size of 'in' and
83*f0865ec9SKyle Evans  * 'out' parameters and the value of 'cnt'. It does not depend on the
84*f0865ec9SKyle Evans  * value of 'in'.
85*f0865ec9SKyle Evans  *
86*f0865ec9SKyle Evans  * It is to be noted that the function computes the output bit length
87*f0865ec9SKyle Evans  * depending on the shift count and the input length, i.e. out bit length
88*f0865ec9SKyle Evans  * will be roughly in bit length  plus cnt, maxed to NN_MAX_BIT_LEN.
89*f0865ec9SKyle Evans  *
90*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
91*f0865ec9SKyle Evans  *
92*f0865ec9SKyle Evans  * Aliasing supported.
93*f0865ec9SKyle Evans  */
94*f0865ec9SKyle Evans int nn_lshift(nn_t out, nn_src_t in, bitcnt_t cnt)
95*f0865ec9SKyle Evans {
96*f0865ec9SKyle Evans 	bitcnt_t lshift, hshift, blen;
97*f0865ec9SKyle Evans 	int ipos, opos, dec, ret;
98*f0865ec9SKyle Evans 	u8 owlen, iwlen;
99*f0865ec9SKyle Evans 
100*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
101*f0865ec9SKyle Evans 	iwlen = in->wlen;
102*f0865ec9SKyle Evans 
103*f0865ec9SKyle Evans 	/* Initialize output if no aliasing is used */
104*f0865ec9SKyle Evans 	if (out != in) {
105*f0865ec9SKyle Evans 		ret = nn_init(out, 0); EG(ret, err);
106*f0865ec9SKyle Evans 	}
107*f0865ec9SKyle Evans 
108*f0865ec9SKyle Evans 	/* Adapt output length accordingly */
109*f0865ec9SKyle Evans 	ret = nn_bitlen(in, &blen); EG(ret, err);
110*f0865ec9SKyle Evans 	owlen = (u8)LOCAL_MIN(BIT_LEN_WORDS(cnt + blen),
111*f0865ec9SKyle Evans 			BIT_LEN_WORDS(NN_MAX_BIT_LEN));
112*f0865ec9SKyle Evans 	out->wlen = owlen;
113*f0865ec9SKyle Evans 
114*f0865ec9SKyle Evans 	dec = cnt / WORD_BITS;
115*f0865ec9SKyle Evans 	hshift = cnt % WORD_BITS;
116*f0865ec9SKyle Evans 	lshift = (bitcnt_t)(WORD_BITS - hshift);
117*f0865ec9SKyle Evans 
118*f0865ec9SKyle Evans 	for (opos = owlen - 1; opos >= 0; opos--) {
119*f0865ec9SKyle Evans 		word_t hipart = 0, lopart = 0;
120*f0865ec9SKyle Evans 
121*f0865ec9SKyle Evans 		ipos = opos - dec - 1;
122*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
123*f0865ec9SKyle Evans 			lopart = WRSHIFT(in->val[ipos], lshift);
124*f0865ec9SKyle Evans 		}
125*f0865ec9SKyle Evans 
126*f0865ec9SKyle Evans 		ipos = opos - dec;
127*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
128*f0865ec9SKyle Evans 			hipart = WLSHIFT(in->val[ipos], hshift);
129*f0865ec9SKyle Evans 		}
130*f0865ec9SKyle Evans 
131*f0865ec9SKyle Evans 		out->val[opos] = hipart | lopart;
132*f0865ec9SKyle Evans 	}
133*f0865ec9SKyle Evans 
134*f0865ec9SKyle Evans err:
135*f0865ec9SKyle Evans 	return ret;
136*f0865ec9SKyle Evans }
137*f0865ec9SKyle Evans 
138*f0865ec9SKyle Evans /*
139*f0865ec9SKyle Evans  * nn_rshift_fixedlen: right logical shift in N, i.e. compute out = (in >> cnt).
140*f0865ec9SKyle Evans  *
141*f0865ec9SKyle Evans  * Aliasing is possible for 'in' and 'out', i.e. x >>= cnt can be computed
142*f0865ec9SKyle Evans  * using nn_rshift_fixedlen(x, x, cnt).
143*f0865ec9SKyle Evans  *
144*f0865ec9SKyle Evans  * The function supports 'in' and 'out' parameters of differents sizes.
145*f0865ec9SKyle Evans  *
146*f0865ec9SKyle Evans  * The operation time of the function depends on the size of 'in' and
147*f0865ec9SKyle Evans  * 'out' parameters and the value of 'cnt'. It does not depend on the
148*f0865ec9SKyle Evans  * value of 'in'.
149*f0865ec9SKyle Evans  * It is to be noted that the function uses out->wlen as the
150*f0865ec9SKyle Evans  * upper limit for its work, which means zeroes are shifted in while
151*f0865ec9SKyle Evans  * keeping the same NN output size.
152*f0865ec9SKyle Evans  *
153*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
154*f0865ec9SKyle Evans  *
155*f0865ec9SKyle Evans  * Aliasing supported.
156*f0865ec9SKyle Evans  */
157*f0865ec9SKyle Evans int nn_rshift_fixedlen(nn_t out, nn_src_t in, bitcnt_t cnt)
158*f0865ec9SKyle Evans {
159*f0865ec9SKyle Evans 	int ipos, opos, dec, ret;
160*f0865ec9SKyle Evans 	bitcnt_t lshift, hshift;
161*f0865ec9SKyle Evans 	u8 owlen, iwlen;
162*f0865ec9SKyle Evans 
163*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
164*f0865ec9SKyle Evans 	ret = nn_check_initialized(out); EG(ret, err);
165*f0865ec9SKyle Evans 	owlen = out->wlen;
166*f0865ec9SKyle Evans 	iwlen = in->wlen;
167*f0865ec9SKyle Evans 
168*f0865ec9SKyle Evans 	dec = cnt / WORD_BITS;
169*f0865ec9SKyle Evans 	lshift = cnt % WORD_BITS;
170*f0865ec9SKyle Evans 	hshift = (bitcnt_t)(WORD_BITS - lshift);
171*f0865ec9SKyle Evans 
172*f0865ec9SKyle Evans 	for (opos = 0; opos < owlen; opos++) {
173*f0865ec9SKyle Evans 		word_t hipart = 0, lopart = 0;
174*f0865ec9SKyle Evans 
175*f0865ec9SKyle Evans 		ipos = opos + dec;
176*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
177*f0865ec9SKyle Evans 			lopart = WRSHIFT(in->val[ipos], lshift);
178*f0865ec9SKyle Evans 		}
179*f0865ec9SKyle Evans 
180*f0865ec9SKyle Evans 		ipos = opos + dec + 1;
181*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
182*f0865ec9SKyle Evans 			hipart = WLSHIFT(in->val[ipos], hshift);
183*f0865ec9SKyle Evans 		}
184*f0865ec9SKyle Evans 
185*f0865ec9SKyle Evans 		out->val[opos] = hipart | lopart;
186*f0865ec9SKyle Evans 	}
187*f0865ec9SKyle Evans 
188*f0865ec9SKyle Evans err:
189*f0865ec9SKyle Evans 	return ret;
190*f0865ec9SKyle Evans }
191*f0865ec9SKyle Evans 
192*f0865ec9SKyle Evans /*
193*f0865ec9SKyle Evans  * nn_rshift: right logical shift in N, i.e. compute out = (in >> cnt).
194*f0865ec9SKyle Evans  *
195*f0865ec9SKyle Evans  * Aliasing is possible for 'in' and 'out', i.e. x >>= cnt can be computed
196*f0865ec9SKyle Evans  * using nn_rshift_fixedlen(x, x, cnt).
197*f0865ec9SKyle Evans  *
198*f0865ec9SKyle Evans  * The function supports 'in' and 'out' parameters of differents sizes.
199*f0865ec9SKyle Evans  *
200*f0865ec9SKyle Evans  * The operation time of the function depends on the size of 'in' and
201*f0865ec9SKyle Evans  * 'out' parameters and the value of 'cnt'. It does not depend on the
202*f0865ec9SKyle Evans  * value of 'in'.
203*f0865ec9SKyle Evans  * It is to be noted that the function adapts the output size to
204*f0865ec9SKyle Evans  * the input size and the shift bit count, i.e. out bit lenth is roughly
205*f0865ec9SKyle Evans  * equal to input bit length minus cnt.
206*f0865ec9SKyle Evans  *
207*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
208*f0865ec9SKyle Evans  *
209*f0865ec9SKyle Evans  * Aliasing supported.
210*f0865ec9SKyle Evans  */
211*f0865ec9SKyle Evans int nn_rshift(nn_t out, nn_src_t in, bitcnt_t cnt)
212*f0865ec9SKyle Evans {
213*f0865ec9SKyle Evans 	int ipos, opos, dec, ret;
214*f0865ec9SKyle Evans 	bitcnt_t lshift, hshift;
215*f0865ec9SKyle Evans 	u8 owlen, iwlen;
216*f0865ec9SKyle Evans 	bitcnt_t blen;
217*f0865ec9SKyle Evans 
218*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
219*f0865ec9SKyle Evans 	iwlen = in->wlen;
220*f0865ec9SKyle Evans 	/* Initialize output if no aliasing is used */
221*f0865ec9SKyle Evans 	if (out != in) {
222*f0865ec9SKyle Evans 		ret = nn_init(out, 0); EG(ret, err);
223*f0865ec9SKyle Evans 	}
224*f0865ec9SKyle Evans 
225*f0865ec9SKyle Evans 	dec = cnt / WORD_BITS;
226*f0865ec9SKyle Evans 	lshift = cnt % WORD_BITS;
227*f0865ec9SKyle Evans 	hshift = (bitcnt_t)(WORD_BITS - lshift);
228*f0865ec9SKyle Evans 
229*f0865ec9SKyle Evans 	/* Adapt output length accordingly */
230*f0865ec9SKyle Evans 	ret = nn_bitlen(in, &blen); EG(ret, err);
231*f0865ec9SKyle Evans 	if (cnt > blen) {
232*f0865ec9SKyle Evans 		owlen = 0;
233*f0865ec9SKyle Evans 	} else {
234*f0865ec9SKyle Evans 		owlen = (u8)BIT_LEN_WORDS(blen - cnt);
235*f0865ec9SKyle Evans 	}
236*f0865ec9SKyle Evans 	/* Adapt output length in out */
237*f0865ec9SKyle Evans 	out->wlen = owlen;
238*f0865ec9SKyle Evans 
239*f0865ec9SKyle Evans 	for (opos = 0; opos < owlen; opos++) {
240*f0865ec9SKyle Evans 		word_t hipart = 0, lopart = 0;
241*f0865ec9SKyle Evans 
242*f0865ec9SKyle Evans 		ipos = opos + dec;
243*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
244*f0865ec9SKyle Evans 			lopart = WRSHIFT(in->val[ipos], lshift);
245*f0865ec9SKyle Evans 		}
246*f0865ec9SKyle Evans 
247*f0865ec9SKyle Evans 		ipos = opos + dec + 1;
248*f0865ec9SKyle Evans 		if ((ipos >= 0) && (ipos < iwlen)) {
249*f0865ec9SKyle Evans 			hipart = WLSHIFT(in->val[ipos], hshift);
250*f0865ec9SKyle Evans 		}
251*f0865ec9SKyle Evans 
252*f0865ec9SKyle Evans 		out->val[opos] = hipart | lopart;
253*f0865ec9SKyle Evans 	}
254*f0865ec9SKyle Evans 
255*f0865ec9SKyle Evans 	/*
256*f0865ec9SKyle Evans 	 * Zero the output upper part now that we don't need it anymore
257*f0865ec9SKyle Evans 	 * NB: as we cannot use our normalize helper here (since a consistency
258*f0865ec9SKyle Evans 	 * check is done on wlen and upper part), we have to do this manually
259*f0865ec9SKyle Evans 	 */
260*f0865ec9SKyle Evans 	for (opos = owlen; opos < NN_MAX_WORD_LEN; opos++) {
261*f0865ec9SKyle Evans 		out->val[opos] = 0;
262*f0865ec9SKyle Evans 	}
263*f0865ec9SKyle Evans 
264*f0865ec9SKyle Evans err:
265*f0865ec9SKyle Evans 	return ret;
266*f0865ec9SKyle Evans }
267*f0865ec9SKyle Evans 
268*f0865ec9SKyle Evans /*
269*f0865ec9SKyle Evans  * This function right rotates the input NN value by the value 'cnt' on the
270*f0865ec9SKyle Evans  * bitlen basis. The function does it in the following way; right rotation
271*f0865ec9SKyle Evans  * of x by cnt is "simply": (x >> cnt) ^ (x << (bitlen - cnt))
272*f0865ec9SKyle Evans  *
273*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
274*f0865ec9SKyle Evans  *
275*f0865ec9SKyle Evans  * Aliasing supported.
276*f0865ec9SKyle Evans  */
277*f0865ec9SKyle Evans int nn_rrot(nn_t out, nn_src_t in, bitcnt_t cnt, bitcnt_t bitlen)
278*f0865ec9SKyle Evans {
279*f0865ec9SKyle Evans 	u8 owlen = (u8)BIT_LEN_WORDS(bitlen);
280*f0865ec9SKyle Evans 	int ret;
281*f0865ec9SKyle Evans 	nn tmp;
282*f0865ec9SKyle Evans 	tmp.magic = WORD(0);
283*f0865ec9SKyle Evans 
284*f0865ec9SKyle Evans 	MUST_HAVE((bitlen <= NN_MAX_BIT_LEN), ret, err);
285*f0865ec9SKyle Evans 	MUST_HAVE((cnt < bitlen), ret, err);
286*f0865ec9SKyle Evans 
287*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
288*f0865ec9SKyle Evans 	ret = nn_init(&tmp, 0); EG(ret, err);
289*f0865ec9SKyle Evans 	ret = nn_lshift(&tmp, in, (bitcnt_t)(bitlen - cnt)); EG(ret, err);
290*f0865ec9SKyle Evans 	ret = nn_set_wlen(&tmp, owlen); EG(ret, err);
291*f0865ec9SKyle Evans 	ret = nn_rshift(out, in, cnt); EG(ret, err);
292*f0865ec9SKyle Evans 	ret = nn_set_wlen(out, owlen); EG(ret, err);
293*f0865ec9SKyle Evans 	ret = nn_xor(out, out, &tmp); EG(ret, err);
294*f0865ec9SKyle Evans 
295*f0865ec9SKyle Evans 	/* Mask the last word if necessary */
296*f0865ec9SKyle Evans 	if (((bitlen % WORD_BITS) != 0) && (out->wlen > 0)) {
297*f0865ec9SKyle Evans 		/* shift operation below is ok (less than WORD_BITS) */
298*f0865ec9SKyle Evans 		word_t mask = (word_t)(((word_t)(WORD(1) << (bitlen % WORD_BITS))) - 1);
299*f0865ec9SKyle Evans 		out->val[out->wlen - 1] &= mask;
300*f0865ec9SKyle Evans 	}
301*f0865ec9SKyle Evans 
302*f0865ec9SKyle Evans err:
303*f0865ec9SKyle Evans 	nn_uninit(&tmp);
304*f0865ec9SKyle Evans 
305*f0865ec9SKyle Evans 	return ret;
306*f0865ec9SKyle Evans }
307*f0865ec9SKyle Evans 
308*f0865ec9SKyle Evans /*
309*f0865ec9SKyle Evans  * This function left rotates the input NN value by the value 'cnt' on the
310*f0865ec9SKyle Evans  * bitlen basis. The function does it in the following way; Left rotation
311*f0865ec9SKyle Evans  * of x by cnt is "simply": (x << cnt) ^ (x >> (bitlen - cnt))
312*f0865ec9SKyle Evans  *
313*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
314*f0865ec9SKyle Evans  *
315*f0865ec9SKyle Evans  * Aliasing supported.
316*f0865ec9SKyle Evans  */
317*f0865ec9SKyle Evans int nn_lrot(nn_t out, nn_src_t in, bitcnt_t cnt, bitcnt_t bitlen)
318*f0865ec9SKyle Evans {
319*f0865ec9SKyle Evans 	u8 owlen = (u8)BIT_LEN_WORDS(bitlen);
320*f0865ec9SKyle Evans 	int ret;
321*f0865ec9SKyle Evans 	nn tmp;
322*f0865ec9SKyle Evans 	tmp.magic = WORD(0);
323*f0865ec9SKyle Evans 
324*f0865ec9SKyle Evans 	MUST_HAVE(!(bitlen > NN_MAX_BIT_LEN), ret, err);
325*f0865ec9SKyle Evans 	MUST_HAVE(!(cnt >= bitlen), ret, err);
326*f0865ec9SKyle Evans 
327*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
328*f0865ec9SKyle Evans 	ret = nn_init(&tmp, 0); EG(ret, err);
329*f0865ec9SKyle Evans 	ret = nn_lshift(&tmp, in, cnt); EG(ret, err);
330*f0865ec9SKyle Evans 	ret = nn_set_wlen(&tmp, owlen); EG(ret, err);
331*f0865ec9SKyle Evans 	ret = nn_rshift(out, in, (bitcnt_t)(bitlen - cnt)); EG(ret, err);
332*f0865ec9SKyle Evans 	ret = nn_set_wlen(out, owlen); EG(ret, err);
333*f0865ec9SKyle Evans 	ret = nn_xor(out, out, &tmp); EG(ret, err);
334*f0865ec9SKyle Evans 
335*f0865ec9SKyle Evans 	/* Mask the last word if necessary */
336*f0865ec9SKyle Evans 	if (((bitlen % WORD_BITS) != 0) && (out->wlen > 0)) {
337*f0865ec9SKyle Evans 		word_t mask = (word_t)(((word_t)(WORD(1) << (bitlen % WORD_BITS))) - 1);
338*f0865ec9SKyle Evans 		out->val[out->wlen - 1] &= mask;
339*f0865ec9SKyle Evans 	}
340*f0865ec9SKyle Evans 
341*f0865ec9SKyle Evans err:
342*f0865ec9SKyle Evans 	nn_uninit(&tmp);
343*f0865ec9SKyle Evans 
344*f0865ec9SKyle Evans 	return ret;
345*f0865ec9SKyle Evans }
346*f0865ec9SKyle Evans 
347*f0865ec9SKyle Evans /*
348*f0865ec9SKyle Evans  * Compute XOR between B and C and put the result in A. B and C must be
349*f0865ec9SKyle Evans  * initialized. Aliasing is supported, i.e. A can be one of the parameter B or
350*f0865ec9SKyle Evans  * C. If aliasing is not used, A will be initialized by the function. Function
351*f0865ec9SKyle Evans  * execution time depends on the word length of larger parameter but not on its
352*f0865ec9SKyle Evans  * particular value.
353*f0865ec9SKyle Evans  *
354*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
355*f0865ec9SKyle Evans  *
356*f0865ec9SKyle Evans  * Aliasing supported.
357*f0865ec9SKyle Evans  */
358*f0865ec9SKyle Evans int nn_xor(nn_t A, nn_src_t B, nn_src_t C)
359*f0865ec9SKyle Evans {
360*f0865ec9SKyle Evans 	int ret;
361*f0865ec9SKyle Evans 	u8 i;
362*f0865ec9SKyle Evans 
363*f0865ec9SKyle Evans 	ret = nn_check_initialized(B); EG(ret, err);
364*f0865ec9SKyle Evans 	ret = nn_check_initialized(C); EG(ret, err);
365*f0865ec9SKyle Evans 
366*f0865ec9SKyle Evans 	/* Initialize the output if no aliasing is used */
367*f0865ec9SKyle Evans 	if ((A != B) && (A != C)) {
368*f0865ec9SKyle Evans 		ret = nn_init(A, 0);  EG(ret, err);
369*f0865ec9SKyle Evans 	}
370*f0865ec9SKyle Evans 
371*f0865ec9SKyle Evans 	/* Set output wlen accordingly */
372*f0865ec9SKyle Evans 	A->wlen = (C->wlen < B->wlen) ? B->wlen : C->wlen;
373*f0865ec9SKyle Evans 
374*f0865ec9SKyle Evans 	for (i = 0; i < A->wlen; i++) {
375*f0865ec9SKyle Evans 		A->val[i] = (B->val[i] ^ C->val[i]);
376*f0865ec9SKyle Evans 	}
377*f0865ec9SKyle Evans 
378*f0865ec9SKyle Evans err:
379*f0865ec9SKyle Evans 	return ret;
380*f0865ec9SKyle Evans }
381*f0865ec9SKyle Evans 
382*f0865ec9SKyle Evans /*
383*f0865ec9SKyle Evans  * Compute logical OR between B and C and put the result in A. B and C must be
384*f0865ec9SKyle Evans  * initialized. Aliasing is supported, i.e. A can be one of the parameter B or
385*f0865ec9SKyle Evans  * C. If aliasing is not used, A will be initialized by the function. Function
386*f0865ec9SKyle Evans  * execution time depends on the word length of larger parameter but not on its
387*f0865ec9SKyle Evans  * particular value.
388*f0865ec9SKyle Evans  *
389*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
390*f0865ec9SKyle Evans  *
391*f0865ec9SKyle Evans  * Aliasing supported.
392*f0865ec9SKyle Evans  */
393*f0865ec9SKyle Evans int nn_or(nn_t A, nn_src_t B, nn_src_t C)
394*f0865ec9SKyle Evans {
395*f0865ec9SKyle Evans 	int ret;
396*f0865ec9SKyle Evans 	u8 i;
397*f0865ec9SKyle Evans 
398*f0865ec9SKyle Evans 	ret = nn_check_initialized(B); EG(ret, err);
399*f0865ec9SKyle Evans 	ret = nn_check_initialized(C); EG(ret, err);
400*f0865ec9SKyle Evans 
401*f0865ec9SKyle Evans 	/* Initialize the output if no aliasing is used */
402*f0865ec9SKyle Evans 	if ((A != B) && (A != C)) {
403*f0865ec9SKyle Evans 		ret = nn_init(A, 0); EG(ret, err);
404*f0865ec9SKyle Evans 	}
405*f0865ec9SKyle Evans 
406*f0865ec9SKyle Evans 	/* Set output wlen accordingly */
407*f0865ec9SKyle Evans 	A->wlen = (C->wlen < B->wlen) ? B->wlen : C->wlen;
408*f0865ec9SKyle Evans 
409*f0865ec9SKyle Evans 	for (i = 0; i < A->wlen; i++) {
410*f0865ec9SKyle Evans 		A->val[i] = (B->val[i] | C->val[i]);
411*f0865ec9SKyle Evans 	}
412*f0865ec9SKyle Evans 
413*f0865ec9SKyle Evans err:
414*f0865ec9SKyle Evans 	return ret;
415*f0865ec9SKyle Evans }
416*f0865ec9SKyle Evans 
417*f0865ec9SKyle Evans /*
418*f0865ec9SKyle Evans  * Compute logical AND between B and C and put the result in A. B and C must be
419*f0865ec9SKyle Evans  * initialized. Aliasing is supported, i.e. A can be one of the parameter B or
420*f0865ec9SKyle Evans  * C. If aliasing is not used, A will be initialized by the function. Function
421*f0865ec9SKyle Evans  * execution time depends on the word length of larger parameter but not on its
422*f0865ec9SKyle Evans  * particular value.
423*f0865ec9SKyle Evans  *
424*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
425*f0865ec9SKyle Evans  *
426*f0865ec9SKyle Evans  * Aliasing supported.
427*f0865ec9SKyle Evans  */
428*f0865ec9SKyle Evans int nn_and(nn_t A, nn_src_t B, nn_src_t C)
429*f0865ec9SKyle Evans {
430*f0865ec9SKyle Evans 	int ret;
431*f0865ec9SKyle Evans 	u8 i;
432*f0865ec9SKyle Evans 
433*f0865ec9SKyle Evans 	ret = nn_check_initialized(B); EG(ret, err);
434*f0865ec9SKyle Evans 	ret = nn_check_initialized(C); EG(ret, err);
435*f0865ec9SKyle Evans 
436*f0865ec9SKyle Evans 	/* Initialize the output if no aliasing is used */
437*f0865ec9SKyle Evans 	if ((A != B) && (A != C)) {
438*f0865ec9SKyle Evans 		ret = nn_init(A, 0); EG(ret, err);
439*f0865ec9SKyle Evans 	}
440*f0865ec9SKyle Evans 
441*f0865ec9SKyle Evans 	/* Set output wlen accordingly */
442*f0865ec9SKyle Evans 	A->wlen = (C->wlen < B->wlen) ? B->wlen : C->wlen;
443*f0865ec9SKyle Evans 
444*f0865ec9SKyle Evans 	for (i = 0; i < A->wlen; i++) {
445*f0865ec9SKyle Evans 		A->val[i] = (B->val[i] & C->val[i]);
446*f0865ec9SKyle Evans 	}
447*f0865ec9SKyle Evans 
448*f0865ec9SKyle Evans err:
449*f0865ec9SKyle Evans 	return ret;
450*f0865ec9SKyle Evans }
451*f0865ec9SKyle Evans 
452*f0865ec9SKyle Evans /*
453*f0865ec9SKyle Evans  * Compute logical NOT of B and put the result in A. B must be initialized.
454*f0865ec9SKyle Evans  * Aliasing is supported. If aliasing is not used, A will be initialized by
455*f0865ec9SKyle Evans  * the function.
456*f0865ec9SKyle Evans  *
457*f0865ec9SKyle Evans  * The function returns 0 on success, -1 on error.
458*f0865ec9SKyle Evans  *
459*f0865ec9SKyle Evans  * Aliasing supported.
460*f0865ec9SKyle Evans  */
461*f0865ec9SKyle Evans int nn_not(nn_t A, nn_src_t B)
462*f0865ec9SKyle Evans {
463*f0865ec9SKyle Evans 	int ret;
464*f0865ec9SKyle Evans 	u8 i;
465*f0865ec9SKyle Evans 
466*f0865ec9SKyle Evans 	ret = nn_check_initialized(B); EG(ret, err);
467*f0865ec9SKyle Evans 
468*f0865ec9SKyle Evans 	/* Initialize the output if no aliasing is used */
469*f0865ec9SKyle Evans 	if (A != B) {
470*f0865ec9SKyle Evans 		ret = nn_init(A, 0); EG(ret, err);
471*f0865ec9SKyle Evans 	}
472*f0865ec9SKyle Evans 
473*f0865ec9SKyle Evans 	/* Set output wlen accordingly */
474*f0865ec9SKyle Evans 	A->wlen = B->wlen;
475*f0865ec9SKyle Evans 
476*f0865ec9SKyle Evans 	for (i = 0; i < A->wlen; i++) {
477*f0865ec9SKyle Evans 		A->val[i] = (word_t)(~(B->val[i]));
478*f0865ec9SKyle Evans 	}
479*f0865ec9SKyle Evans 
480*f0865ec9SKyle Evans err:
481*f0865ec9SKyle Evans 	return ret;
482*f0865ec9SKyle Evans }
483*f0865ec9SKyle Evans 
484*f0865ec9SKyle Evans /* Count leading zeros of a word. This is constant time */
485*f0865ec9SKyle Evans ATTRIBUTE_WARN_UNUSED_RET static u8 wclz(word_t A)
486*f0865ec9SKyle Evans {
487*f0865ec9SKyle Evans 	u8 cnt = WORD_BITS, over = 0;
488*f0865ec9SKyle Evans 	int i;
489*f0865ec9SKyle Evans 
490*f0865ec9SKyle Evans 	for (i = (WORD_BITS - 1); i >= 0; i--) {
491*f0865ec9SKyle Evans 		/* i is less than WORD_BITS so shift operations below are ok */
492*f0865ec9SKyle Evans 		u8 mask = (u8)(((A & (WORD(1) << i)) >> i) & 0x1);
493*f0865ec9SKyle Evans 		over |= mask;
494*f0865ec9SKyle Evans 		cnt = (u8)(cnt - over);
495*f0865ec9SKyle Evans 	}
496*f0865ec9SKyle Evans 
497*f0865ec9SKyle Evans 	return cnt;
498*f0865ec9SKyle Evans }
499*f0865ec9SKyle Evans 
500*f0865ec9SKyle Evans /*
501*f0865ec9SKyle Evans  * Count leading zeros of an initialized nn. This is NOT constant time. The
502*f0865ec9SKyle Evans  * function returns 0 on success, -1 on error. On success, the number of
503*f0865ec9SKyle Evans  * leading zeroes is available in 'lz'. 'lz' is not meaningful on error.
504*f0865ec9SKyle Evans  */
505*f0865ec9SKyle Evans int nn_clz(nn_src_t in, bitcnt_t *lz)
506*f0865ec9SKyle Evans {
507*f0865ec9SKyle Evans 	bitcnt_t cnt = 0;
508*f0865ec9SKyle Evans 	int ret;
509*f0865ec9SKyle Evans 	u8 i;
510*f0865ec9SKyle Evans 
511*f0865ec9SKyle Evans 	/* Sanity check */
512*f0865ec9SKyle Evans 	MUST_HAVE((lz != NULL), ret, err);
513*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
514*f0865ec9SKyle Evans 
515*f0865ec9SKyle Evans 	for (i = in->wlen; i > 0; i--) {
516*f0865ec9SKyle Evans 		if (in->val[i - 1] == 0) {
517*f0865ec9SKyle Evans 			cnt = (bitcnt_t)(cnt +  WORD_BITS);
518*f0865ec9SKyle Evans 		} else {
519*f0865ec9SKyle Evans 			cnt = (bitcnt_t)(cnt + wclz(in->val[i - 1]));
520*f0865ec9SKyle Evans 			break;
521*f0865ec9SKyle Evans 		}
522*f0865ec9SKyle Evans 	}
523*f0865ec9SKyle Evans 	*lz = cnt;
524*f0865ec9SKyle Evans 
525*f0865ec9SKyle Evans err:
526*f0865ec9SKyle Evans 	return ret;
527*f0865ec9SKyle Evans }
528*f0865ec9SKyle Evans 
529*f0865ec9SKyle Evans /*
530*f0865ec9SKyle Evans  * Compute bit length of given nn. This is NOT constant-time.  The
531*f0865ec9SKyle Evans  * function returns 0 on success, -1 on error. On success, the bit length
532*f0865ec9SKyle Evans  * of 'in' is available in 'blen'. 'blen' is not meaningful on error.
533*f0865ec9SKyle Evans  */
534*f0865ec9SKyle Evans int nn_bitlen(nn_src_t in, bitcnt_t *blen)
535*f0865ec9SKyle Evans {
536*f0865ec9SKyle Evans 	bitcnt_t _blen = 0;
537*f0865ec9SKyle Evans 	int ret;
538*f0865ec9SKyle Evans 	u8 i;
539*f0865ec9SKyle Evans 
540*f0865ec9SKyle Evans 	/* Sanity check */
541*f0865ec9SKyle Evans 	MUST_HAVE((blen != NULL), ret, err);
542*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
543*f0865ec9SKyle Evans 
544*f0865ec9SKyle Evans 	for (i = in->wlen; i > 0; i--) {
545*f0865ec9SKyle Evans 		if (in->val[i - 1] != 0) {
546*f0865ec9SKyle Evans 			_blen = (bitcnt_t)((i * WORD_BITS) - wclz(in->val[i - 1]));
547*f0865ec9SKyle Evans 			break;
548*f0865ec9SKyle Evans 		}
549*f0865ec9SKyle Evans 	}
550*f0865ec9SKyle Evans 	(*blen) = _blen;
551*f0865ec9SKyle Evans 
552*f0865ec9SKyle Evans err:
553*f0865ec9SKyle Evans 	return ret;
554*f0865ec9SKyle Evans }
555*f0865ec9SKyle Evans 
556*f0865ec9SKyle Evans /*
557*f0865ec9SKyle Evans  * On success (return value is 0), the function provides via 'bitval' the value
558*f0865ec9SKyle Evans  * of the bit at position 'bit' in 'in' nn. 'bitval' in not meaningful error
559*f0865ec9SKyle Evans  * (when return value is -1).
560*f0865ec9SKyle Evans  */
561*f0865ec9SKyle Evans int nn_getbit(nn_src_t in, bitcnt_t bit, u8 *bitval)
562*f0865ec9SKyle Evans {
563*f0865ec9SKyle Evans 	bitcnt_t widx = bit / WORD_BITS;
564*f0865ec9SKyle Evans 	u8 bidx = bit % WORD_BITS;
565*f0865ec9SKyle Evans 	int ret;
566*f0865ec9SKyle Evans 
567*f0865ec9SKyle Evans 	/* Sanity check */
568*f0865ec9SKyle Evans 	MUST_HAVE((bitval != NULL), ret, err);
569*f0865ec9SKyle Evans 	ret = nn_check_initialized(in); EG(ret, err);
570*f0865ec9SKyle Evans 	MUST_HAVE((bit < NN_MAX_BIT_LEN), ret, err);
571*f0865ec9SKyle Evans 
572*f0865ec9SKyle Evans 	/* bidx is less than WORD_BITS so shift operations below are ok */
573*f0865ec9SKyle Evans 	(*bitval) = (u8)((((in->val[widx]) & (WORD(1) << bidx)) >> bidx) & 0x1);
574*f0865ec9SKyle Evans 
575*f0865ec9SKyle Evans err:
576*f0865ec9SKyle Evans 	return ret;
577*f0865ec9SKyle Evans }
578