xref: /linux/lib/crypto/mpi/mpi-bit.c (revision 5d666496c24129edeb2bcb500498b87cc64e7f07)
1  /* mpi-bit.c  -  MPI bit level functions
2   * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
3   *
4   * This file is part of GnuPG.
5   *
6   * GnuPG is free software; you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by
8   * the Free Software Foundation; either version 2 of the License, or
9   * (at your option) any later version.
10   *
11   * GnuPG is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19   */
20  
21  #include "mpi-internal.h"
22  #include "longlong.h"
23  
24  #define A_LIMB_1 ((mpi_limb_t) 1)
25  
26  /****************
27   * Sometimes we have MSL (most significant limbs) which are 0;
28   * this is for some reasons not good, so this function removes them.
29   */
30  void mpi_normalize(MPI a)
31  {
32  	for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--)
33  		;
34  }
35  EXPORT_SYMBOL_GPL(mpi_normalize);
36  
37  /****************
38   * Return the number of bits in A.
39   */
40  unsigned mpi_get_nbits(MPI a)
41  {
42  	unsigned n;
43  
44  	mpi_normalize(a);
45  
46  	if (a->nlimbs) {
47  		mpi_limb_t alimb = a->d[a->nlimbs - 1];
48  		if (alimb)
49  			n = count_leading_zeros(alimb);
50  		else
51  			n = BITS_PER_MPI_LIMB;
52  		n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB;
53  	} else
54  		n = 0;
55  	return n;
56  }
57  EXPORT_SYMBOL_GPL(mpi_get_nbits);
58  
59  /****************
60   * Test whether bit N is set.
61   */
62  int mpi_test_bit(MPI a, unsigned int n)
63  {
64  	unsigned int limbno, bitno;
65  	mpi_limb_t limb;
66  
67  	limbno = n / BITS_PER_MPI_LIMB;
68  	bitno  = n % BITS_PER_MPI_LIMB;
69  
70  	if (limbno >= a->nlimbs)
71  		return 0; /* too far left: this is a 0 */
72  	limb = a->d[limbno];
73  	return (limb & (A_LIMB_1 << bitno)) ? 1 : 0;
74  }
75  EXPORT_SYMBOL_GPL(mpi_test_bit);
76  
77  /****************
78   * Set bit N of A.
79   */
80  void mpi_set_bit(MPI a, unsigned int n)
81  {
82  	unsigned int i, limbno, bitno;
83  
84  	limbno = n / BITS_PER_MPI_LIMB;
85  	bitno  = n % BITS_PER_MPI_LIMB;
86  
87  	if (limbno >= a->nlimbs) {
88  		for (i = a->nlimbs; i < a->alloced; i++)
89  			a->d[i] = 0;
90  		mpi_resize(a, limbno+1);
91  		a->nlimbs = limbno+1;
92  	}
93  	a->d[limbno] |= (A_LIMB_1<<bitno);
94  }
95  
96  /****************
97   * Set bit N of A. and clear all bits above
98   */
99  void mpi_set_highbit(MPI a, unsigned int n)
100  {
101  	unsigned int i, limbno, bitno;
102  
103  	limbno = n / BITS_PER_MPI_LIMB;
104  	bitno  = n % BITS_PER_MPI_LIMB;
105  
106  	if (limbno >= a->nlimbs) {
107  		for (i = a->nlimbs; i < a->alloced; i++)
108  			a->d[i] = 0;
109  		mpi_resize(a, limbno+1);
110  		a->nlimbs = limbno+1;
111  	}
112  	a->d[limbno] |= (A_LIMB_1<<bitno);
113  	for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++)
114  		a->d[limbno] &= ~(A_LIMB_1 << bitno);
115  	a->nlimbs = limbno+1;
116  }
117  EXPORT_SYMBOL_GPL(mpi_set_highbit);
118  
119  /****************
120   * clear bit N of A and all bits above
121   */
122  void mpi_clear_highbit(MPI a, unsigned int n)
123  {
124  	unsigned int limbno, bitno;
125  
126  	limbno = n / BITS_PER_MPI_LIMB;
127  	bitno  = n % BITS_PER_MPI_LIMB;
128  
129  	if (limbno >= a->nlimbs)
130  		return; /* not allocated, therefore no need to clear bits :-) */
131  
132  	for ( ; bitno < BITS_PER_MPI_LIMB; bitno++)
133  		a->d[limbno] &= ~(A_LIMB_1 << bitno);
134  	a->nlimbs = limbno+1;
135  }
136  
137  /****************
138   * Clear bit N of A.
139   */
140  void mpi_clear_bit(MPI a, unsigned int n)
141  {
142  	unsigned int limbno, bitno;
143  
144  	limbno = n / BITS_PER_MPI_LIMB;
145  	bitno  = n % BITS_PER_MPI_LIMB;
146  
147  	if (limbno >= a->nlimbs)
148  		return; /* Don't need to clear this bit, it's far too left.  */
149  	a->d[limbno] &= ~(A_LIMB_1 << bitno);
150  }
151  EXPORT_SYMBOL_GPL(mpi_clear_bit);
152  
153  
154  /****************
155   * Shift A by COUNT limbs to the right
156   * This is used only within the MPI library
157   */
158  void mpi_rshift_limbs(MPI a, unsigned int count)
159  {
160  	mpi_ptr_t ap = a->d;
161  	mpi_size_t n = a->nlimbs;
162  	unsigned int i;
163  
164  	if (count >= n) {
165  		a->nlimbs = 0;
166  		return;
167  	}
168  
169  	for (i = 0; i < n - count; i++)
170  		ap[i] = ap[i+count];
171  	ap[i] = 0;
172  	a->nlimbs -= count;
173  }
174  
175  /*
176   * Shift A by N bits to the right.
177   */
178  void mpi_rshift(MPI x, MPI a, unsigned int n)
179  {
180  	mpi_size_t xsize;
181  	unsigned int i;
182  	unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
183  	unsigned int nbits = (n%BITS_PER_MPI_LIMB);
184  
185  	if (x == a) {
186  		/* In-place operation.  */
187  		if (nlimbs >= x->nlimbs) {
188  			x->nlimbs = 0;
189  			return;
190  		}
191  
192  		if (nlimbs) {
193  			for (i = 0; i < x->nlimbs - nlimbs; i++)
194  				x->d[i] = x->d[i+nlimbs];
195  			x->d[i] = 0;
196  			x->nlimbs -= nlimbs;
197  		}
198  		if (x->nlimbs && nbits)
199  			mpihelp_rshift(x->d, x->d, x->nlimbs, nbits);
200  	} else if (nlimbs) {
201  		/* Copy and shift by more or equal bits than in a limb. */
202  		xsize = a->nlimbs;
203  		x->sign = a->sign;
204  		RESIZE_IF_NEEDED(x, xsize);
205  		x->nlimbs = xsize;
206  		for (i = 0; i < a->nlimbs; i++)
207  			x->d[i] = a->d[i];
208  		x->nlimbs = i;
209  
210  		if (nlimbs >= x->nlimbs) {
211  			x->nlimbs = 0;
212  			return;
213  		}
214  
215  		for (i = 0; i < x->nlimbs - nlimbs; i++)
216  			x->d[i] = x->d[i+nlimbs];
217  		x->d[i] = 0;
218  		x->nlimbs -= nlimbs;
219  
220  		if (x->nlimbs && nbits)
221  			mpihelp_rshift(x->d, x->d, x->nlimbs, nbits);
222  	} else {
223  		/* Copy and shift by less than bits in a limb.  */
224  		xsize = a->nlimbs;
225  		x->sign = a->sign;
226  		RESIZE_IF_NEEDED(x, xsize);
227  		x->nlimbs = xsize;
228  
229  		if (xsize) {
230  			if (nbits)
231  				mpihelp_rshift(x->d, a->d, x->nlimbs, nbits);
232  			else {
233  				/* The rshift helper function is not specified for
234  				 * NBITS==0, thus we do a plain copy here.
235  				 */
236  				for (i = 0; i < x->nlimbs; i++)
237  					x->d[i] = a->d[i];
238  			}
239  		}
240  	}
241  	MPN_NORMALIZE(x->d, x->nlimbs);
242  }
243  EXPORT_SYMBOL_GPL(mpi_rshift);
244  
245  /****************
246   * Shift A by COUNT limbs to the left
247   * This is used only within the MPI library
248   */
249  void mpi_lshift_limbs(MPI a, unsigned int count)
250  {
251  	mpi_ptr_t ap;
252  	int n = a->nlimbs;
253  	int i;
254  
255  	if (!count || !n)
256  		return;
257  
258  	RESIZE_IF_NEEDED(a, n+count);
259  
260  	ap = a->d;
261  	for (i = n-1; i >= 0; i--)
262  		ap[i+count] = ap[i];
263  	for (i = 0; i < count; i++)
264  		ap[i] = 0;
265  	a->nlimbs += count;
266  }
267  
268  /*
269   * Shift A by N bits to the left.
270   */
271  void mpi_lshift(MPI x, MPI a, unsigned int n)
272  {
273  	unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
274  	unsigned int nbits = (n%BITS_PER_MPI_LIMB);
275  
276  	if (x == a && !n)
277  		return;  /* In-place shift with an amount of zero.  */
278  
279  	if (x != a) {
280  		/* Copy A to X.  */
281  		unsigned int alimbs = a->nlimbs;
282  		int asign = a->sign;
283  		mpi_ptr_t xp, ap;
284  
285  		RESIZE_IF_NEEDED(x, alimbs+nlimbs+1);
286  		xp = x->d;
287  		ap = a->d;
288  		MPN_COPY(xp, ap, alimbs);
289  		x->nlimbs = alimbs;
290  		x->flags = a->flags;
291  		x->sign = asign;
292  	}
293  
294  	if (nlimbs && !nbits) {
295  		/* Shift a full number of limbs.  */
296  		mpi_lshift_limbs(x, nlimbs);
297  	} else if (n) {
298  		/* We use a very dump approach: Shift left by the number of
299  		 * limbs plus one and than fix it up by an rshift.
300  		 */
301  		mpi_lshift_limbs(x, nlimbs+1);
302  		mpi_rshift(x, x, BITS_PER_MPI_LIMB - nbits);
303  	}
304  
305  	MPN_NORMALIZE(x->d, x->nlimbs);
306  }
307