xref: /kernel/linux/linux-6.6/lib/crypto/mpi/mpi-bit.c (revision 62306a36)
162306a36Sopenharmony_ci/* mpi-bit.c  -  MPI bit level functions
262306a36Sopenharmony_ci * Copyright (C) 1998, 1999 Free Software Foundation, Inc.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * This file is part of GnuPG.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * GnuPG is free software; you can redistribute it and/or modify
762306a36Sopenharmony_ci * it under the terms of the GNU General Public License as published by
862306a36Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or
962306a36Sopenharmony_ci * (at your option) any later version.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * GnuPG is distributed in the hope that it will be useful,
1262306a36Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
1362306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1462306a36Sopenharmony_ci * GNU General Public License for more details.
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License
1762306a36Sopenharmony_ci * along with this program; if not, write to the Free Software
1862306a36Sopenharmony_ci * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
1962306a36Sopenharmony_ci */
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "mpi-internal.h"
2262306a36Sopenharmony_ci#include "longlong.h"
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define A_LIMB_1 ((mpi_limb_t) 1)
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/****************
2762306a36Sopenharmony_ci * Sometimes we have MSL (most significant limbs) which are 0;
2862306a36Sopenharmony_ci * this is for some reasons not good, so this function removes them.
2962306a36Sopenharmony_ci */
3062306a36Sopenharmony_civoid mpi_normalize(MPI a)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	for (; a->nlimbs && !a->d[a->nlimbs - 1]; a->nlimbs--)
3362306a36Sopenharmony_ci		;
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_normalize);
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/****************
3862306a36Sopenharmony_ci * Return the number of bits in A.
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ciunsigned mpi_get_nbits(MPI a)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	unsigned n;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	mpi_normalize(a);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (a->nlimbs) {
4762306a36Sopenharmony_ci		mpi_limb_t alimb = a->d[a->nlimbs - 1];
4862306a36Sopenharmony_ci		if (alimb)
4962306a36Sopenharmony_ci			n = count_leading_zeros(alimb);
5062306a36Sopenharmony_ci		else
5162306a36Sopenharmony_ci			n = BITS_PER_MPI_LIMB;
5262306a36Sopenharmony_ci		n = BITS_PER_MPI_LIMB - n + (a->nlimbs - 1) * BITS_PER_MPI_LIMB;
5362306a36Sopenharmony_ci	} else
5462306a36Sopenharmony_ci		n = 0;
5562306a36Sopenharmony_ci	return n;
5662306a36Sopenharmony_ci}
5762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_get_nbits);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/****************
6062306a36Sopenharmony_ci * Test whether bit N is set.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_ciint mpi_test_bit(MPI a, unsigned int n)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	unsigned int limbno, bitno;
6562306a36Sopenharmony_ci	mpi_limb_t limb;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	limbno = n / BITS_PER_MPI_LIMB;
6862306a36Sopenharmony_ci	bitno  = n % BITS_PER_MPI_LIMB;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (limbno >= a->nlimbs)
7162306a36Sopenharmony_ci		return 0; /* too far left: this is a 0 */
7262306a36Sopenharmony_ci	limb = a->d[limbno];
7362306a36Sopenharmony_ci	return (limb & (A_LIMB_1 << bitno)) ? 1 : 0;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_test_bit);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/****************
7862306a36Sopenharmony_ci * Set bit N of A.
7962306a36Sopenharmony_ci */
8062306a36Sopenharmony_civoid mpi_set_bit(MPI a, unsigned int n)
8162306a36Sopenharmony_ci{
8262306a36Sopenharmony_ci	unsigned int i, limbno, bitno;
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci	limbno = n / BITS_PER_MPI_LIMB;
8562306a36Sopenharmony_ci	bitno  = n % BITS_PER_MPI_LIMB;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	if (limbno >= a->nlimbs) {
8862306a36Sopenharmony_ci		for (i = a->nlimbs; i < a->alloced; i++)
8962306a36Sopenharmony_ci			a->d[i] = 0;
9062306a36Sopenharmony_ci		mpi_resize(a, limbno+1);
9162306a36Sopenharmony_ci		a->nlimbs = limbno+1;
9262306a36Sopenharmony_ci	}
9362306a36Sopenharmony_ci	a->d[limbno] |= (A_LIMB_1<<bitno);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/****************
9762306a36Sopenharmony_ci * Set bit N of A. and clear all bits above
9862306a36Sopenharmony_ci */
9962306a36Sopenharmony_civoid mpi_set_highbit(MPI a, unsigned int n)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	unsigned int i, limbno, bitno;
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	limbno = n / BITS_PER_MPI_LIMB;
10462306a36Sopenharmony_ci	bitno  = n % BITS_PER_MPI_LIMB;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	if (limbno >= a->nlimbs) {
10762306a36Sopenharmony_ci		for (i = a->nlimbs; i < a->alloced; i++)
10862306a36Sopenharmony_ci			a->d[i] = 0;
10962306a36Sopenharmony_ci		mpi_resize(a, limbno+1);
11062306a36Sopenharmony_ci		a->nlimbs = limbno+1;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci	a->d[limbno] |= (A_LIMB_1<<bitno);
11362306a36Sopenharmony_ci	for (bitno++; bitno < BITS_PER_MPI_LIMB; bitno++)
11462306a36Sopenharmony_ci		a->d[limbno] &= ~(A_LIMB_1 << bitno);
11562306a36Sopenharmony_ci	a->nlimbs = limbno+1;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_set_highbit);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/****************
12062306a36Sopenharmony_ci * clear bit N of A and all bits above
12162306a36Sopenharmony_ci */
12262306a36Sopenharmony_civoid mpi_clear_highbit(MPI a, unsigned int n)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	unsigned int limbno, bitno;
12562306a36Sopenharmony_ci
12662306a36Sopenharmony_ci	limbno = n / BITS_PER_MPI_LIMB;
12762306a36Sopenharmony_ci	bitno  = n % BITS_PER_MPI_LIMB;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	if (limbno >= a->nlimbs)
13062306a36Sopenharmony_ci		return; /* not allocated, therefore no need to clear bits :-) */
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	for ( ; bitno < BITS_PER_MPI_LIMB; bitno++)
13362306a36Sopenharmony_ci		a->d[limbno] &= ~(A_LIMB_1 << bitno);
13462306a36Sopenharmony_ci	a->nlimbs = limbno+1;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/****************
13862306a36Sopenharmony_ci * Clear bit N of A.
13962306a36Sopenharmony_ci */
14062306a36Sopenharmony_civoid mpi_clear_bit(MPI a, unsigned int n)
14162306a36Sopenharmony_ci{
14262306a36Sopenharmony_ci	unsigned int limbno, bitno;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	limbno = n / BITS_PER_MPI_LIMB;
14562306a36Sopenharmony_ci	bitno  = n % BITS_PER_MPI_LIMB;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	if (limbno >= a->nlimbs)
14862306a36Sopenharmony_ci		return; /* Don't need to clear this bit, it's far too left.  */
14962306a36Sopenharmony_ci	a->d[limbno] &= ~(A_LIMB_1 << bitno);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_clear_bit);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci/****************
15562306a36Sopenharmony_ci * Shift A by COUNT limbs to the right
15662306a36Sopenharmony_ci * This is used only within the MPI library
15762306a36Sopenharmony_ci */
15862306a36Sopenharmony_civoid mpi_rshift_limbs(MPI a, unsigned int count)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	mpi_ptr_t ap = a->d;
16162306a36Sopenharmony_ci	mpi_size_t n = a->nlimbs;
16262306a36Sopenharmony_ci	unsigned int i;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	if (count >= n) {
16562306a36Sopenharmony_ci		a->nlimbs = 0;
16662306a36Sopenharmony_ci		return;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	for (i = 0; i < n - count; i++)
17062306a36Sopenharmony_ci		ap[i] = ap[i+count];
17162306a36Sopenharmony_ci	ap[i] = 0;
17262306a36Sopenharmony_ci	a->nlimbs -= count;
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*
17662306a36Sopenharmony_ci * Shift A by N bits to the right.
17762306a36Sopenharmony_ci */
17862306a36Sopenharmony_civoid mpi_rshift(MPI x, MPI a, unsigned int n)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	mpi_size_t xsize;
18162306a36Sopenharmony_ci	unsigned int i;
18262306a36Sopenharmony_ci	unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
18362306a36Sopenharmony_ci	unsigned int nbits = (n%BITS_PER_MPI_LIMB);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (x == a) {
18662306a36Sopenharmony_ci		/* In-place operation.  */
18762306a36Sopenharmony_ci		if (nlimbs >= x->nlimbs) {
18862306a36Sopenharmony_ci			x->nlimbs = 0;
18962306a36Sopenharmony_ci			return;
19062306a36Sopenharmony_ci		}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci		if (nlimbs) {
19362306a36Sopenharmony_ci			for (i = 0; i < x->nlimbs - nlimbs; i++)
19462306a36Sopenharmony_ci				x->d[i] = x->d[i+nlimbs];
19562306a36Sopenharmony_ci			x->d[i] = 0;
19662306a36Sopenharmony_ci			x->nlimbs -= nlimbs;
19762306a36Sopenharmony_ci		}
19862306a36Sopenharmony_ci		if (x->nlimbs && nbits)
19962306a36Sopenharmony_ci			mpihelp_rshift(x->d, x->d, x->nlimbs, nbits);
20062306a36Sopenharmony_ci	} else if (nlimbs) {
20162306a36Sopenharmony_ci		/* Copy and shift by more or equal bits than in a limb. */
20262306a36Sopenharmony_ci		xsize = a->nlimbs;
20362306a36Sopenharmony_ci		x->sign = a->sign;
20462306a36Sopenharmony_ci		RESIZE_IF_NEEDED(x, xsize);
20562306a36Sopenharmony_ci		x->nlimbs = xsize;
20662306a36Sopenharmony_ci		for (i = 0; i < a->nlimbs; i++)
20762306a36Sopenharmony_ci			x->d[i] = a->d[i];
20862306a36Sopenharmony_ci		x->nlimbs = i;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci		if (nlimbs >= x->nlimbs) {
21162306a36Sopenharmony_ci			x->nlimbs = 0;
21262306a36Sopenharmony_ci			return;
21362306a36Sopenharmony_ci		}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci		if (nlimbs) {
21662306a36Sopenharmony_ci			for (i = 0; i < x->nlimbs - nlimbs; i++)
21762306a36Sopenharmony_ci				x->d[i] = x->d[i+nlimbs];
21862306a36Sopenharmony_ci			x->d[i] = 0;
21962306a36Sopenharmony_ci			x->nlimbs -= nlimbs;
22062306a36Sopenharmony_ci		}
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci		if (x->nlimbs && nbits)
22362306a36Sopenharmony_ci			mpihelp_rshift(x->d, x->d, x->nlimbs, nbits);
22462306a36Sopenharmony_ci	} else {
22562306a36Sopenharmony_ci		/* Copy and shift by less than bits in a limb.  */
22662306a36Sopenharmony_ci		xsize = a->nlimbs;
22762306a36Sopenharmony_ci		x->sign = a->sign;
22862306a36Sopenharmony_ci		RESIZE_IF_NEEDED(x, xsize);
22962306a36Sopenharmony_ci		x->nlimbs = xsize;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci		if (xsize) {
23262306a36Sopenharmony_ci			if (nbits)
23362306a36Sopenharmony_ci				mpihelp_rshift(x->d, a->d, x->nlimbs, nbits);
23462306a36Sopenharmony_ci			else {
23562306a36Sopenharmony_ci				/* The rshift helper function is not specified for
23662306a36Sopenharmony_ci				 * NBITS==0, thus we do a plain copy here.
23762306a36Sopenharmony_ci				 */
23862306a36Sopenharmony_ci				for (i = 0; i < x->nlimbs; i++)
23962306a36Sopenharmony_ci					x->d[i] = a->d[i];
24062306a36Sopenharmony_ci			}
24162306a36Sopenharmony_ci		}
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	MPN_NORMALIZE(x->d, x->nlimbs);
24462306a36Sopenharmony_ci}
24562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(mpi_rshift);
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci/****************
24862306a36Sopenharmony_ci * Shift A by COUNT limbs to the left
24962306a36Sopenharmony_ci * This is used only within the MPI library
25062306a36Sopenharmony_ci */
25162306a36Sopenharmony_civoid mpi_lshift_limbs(MPI a, unsigned int count)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	mpi_ptr_t ap;
25462306a36Sopenharmony_ci	int n = a->nlimbs;
25562306a36Sopenharmony_ci	int i;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (!count || !n)
25862306a36Sopenharmony_ci		return;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	RESIZE_IF_NEEDED(a, n+count);
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	ap = a->d;
26362306a36Sopenharmony_ci	for (i = n-1; i >= 0; i--)
26462306a36Sopenharmony_ci		ap[i+count] = ap[i];
26562306a36Sopenharmony_ci	for (i = 0; i < count; i++)
26662306a36Sopenharmony_ci		ap[i] = 0;
26762306a36Sopenharmony_ci	a->nlimbs += count;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * Shift A by N bits to the left.
27262306a36Sopenharmony_ci */
27362306a36Sopenharmony_civoid mpi_lshift(MPI x, MPI a, unsigned int n)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	unsigned int nlimbs = (n/BITS_PER_MPI_LIMB);
27662306a36Sopenharmony_ci	unsigned int nbits = (n%BITS_PER_MPI_LIMB);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	if (x == a && !n)
27962306a36Sopenharmony_ci		return;  /* In-place shift with an amount of zero.  */
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci	if (x != a) {
28262306a36Sopenharmony_ci		/* Copy A to X.  */
28362306a36Sopenharmony_ci		unsigned int alimbs = a->nlimbs;
28462306a36Sopenharmony_ci		int asign = a->sign;
28562306a36Sopenharmony_ci		mpi_ptr_t xp, ap;
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		RESIZE_IF_NEEDED(x, alimbs+nlimbs+1);
28862306a36Sopenharmony_ci		xp = x->d;
28962306a36Sopenharmony_ci		ap = a->d;
29062306a36Sopenharmony_ci		MPN_COPY(xp, ap, alimbs);
29162306a36Sopenharmony_ci		x->nlimbs = alimbs;
29262306a36Sopenharmony_ci		x->flags = a->flags;
29362306a36Sopenharmony_ci		x->sign = asign;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	if (nlimbs && !nbits) {
29762306a36Sopenharmony_ci		/* Shift a full number of limbs.  */
29862306a36Sopenharmony_ci		mpi_lshift_limbs(x, nlimbs);
29962306a36Sopenharmony_ci	} else if (n) {
30062306a36Sopenharmony_ci		/* We use a very dump approach: Shift left by the number of
30162306a36Sopenharmony_ci		 * limbs plus one and than fix it up by an rshift.
30262306a36Sopenharmony_ci		 */
30362306a36Sopenharmony_ci		mpi_lshift_limbs(x, nlimbs+1);
30462306a36Sopenharmony_ci		mpi_rshift(x, x, BITS_PER_MPI_LIMB - nbits);
30562306a36Sopenharmony_ci	}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	MPN_NORMALIZE(x->d, x->nlimbs);
30862306a36Sopenharmony_ci}
309