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