Blame mpn/generic/powlo.c

Packit 5c3484
/* mpn_powlo -- Compute R = U^E mod B^n, where B is the limb base.
Packit 5c3484
Packit 5c3484
Copyright 2007-2009, 2012, 2015 Free Software Foundation, Inc.
Packit 5c3484
Packit 5c3484
This file is part of the GNU MP Library.
Packit 5c3484
Packit 5c3484
The GNU MP Library is free software; you can redistribute it and/or modify
Packit 5c3484
it under the terms of either:
Packit 5c3484
Packit 5c3484
  * the GNU Lesser General Public License as published by the Free
Packit 5c3484
    Software Foundation; either version 3 of the License, or (at your
Packit 5c3484
    option) any later version.
Packit 5c3484
Packit 5c3484
or
Packit 5c3484
Packit 5c3484
  * the GNU General Public License as published by the Free Software
Packit 5c3484
    Foundation; either version 2 of the License, or (at your option) any
Packit 5c3484
    later version.
Packit 5c3484
Packit 5c3484
or both in parallel, as here.
Packit 5c3484
Packit 5c3484
The GNU MP Library is distributed in the hope that it will be useful, but
Packit 5c3484
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
Packit 5c3484
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
Packit 5c3484
for more details.
Packit 5c3484
Packit 5c3484
You should have received copies of the GNU General Public License and the
Packit 5c3484
GNU Lesser General Public License along with the GNU MP Library.  If not,
Packit 5c3484
see https://www.gnu.org/licenses/.  */
Packit 5c3484
Packit 5c3484
Packit 5c3484
#include "gmp.h"
Packit 5c3484
#include "gmp-impl.h"
Packit 5c3484
#include "longlong.h"
Packit 5c3484
Packit 5c3484
Packit 5c3484
#define getbit(p,bi) \
Packit 5c3484
  ((p[(bi - 1) / GMP_LIMB_BITS] >> (bi - 1) % GMP_LIMB_BITS) & 1)
Packit 5c3484
Packit 5c3484
static inline mp_limb_t
Packit 5c3484
getbits (const mp_limb_t *p, mp_bitcnt_t bi, int nbits)
Packit 5c3484
{
Packit 5c3484
  int nbits_in_r;
Packit 5c3484
  mp_limb_t r;
Packit 5c3484
  mp_size_t i;
Packit 5c3484
Packit 5c3484
  if (bi < nbits)
Packit 5c3484
    {
Packit 5c3484
      return p[0] & (((mp_limb_t) 1 << bi) - 1);
Packit 5c3484
    }
Packit 5c3484
  else
Packit 5c3484
    {
Packit 5c3484
      bi -= nbits;			/* bit index of low bit to extract */
Packit 5c3484
      i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
Packit 5c3484
      bi %= GMP_NUMB_BITS;		/* bit index in low word */
Packit 5c3484
      r = p[i] >> bi;			/* extract (low) bits */
Packit 5c3484
      nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
Packit 5c3484
      if (nbits_in_r < nbits)		/* did we get enough bits? */
Packit 5c3484
	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
Packit 5c3484
      return r & (((mp_limb_t ) 1 << nbits) - 1);
Packit 5c3484
    }
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
static inline int
Packit 5c3484
win_size (mp_bitcnt_t eb)
Packit 5c3484
{
Packit 5c3484
  int k;
Packit 5c3484
  static mp_bitcnt_t x[] = {1,7,25,81,241,673,1793,4609,11521,28161,~(mp_bitcnt_t)0};
Packit 5c3484
  ASSERT (eb > 1);
Packit 5c3484
  for (k = 1; eb > x[k]; ++k)
Packit 5c3484
    ;
Packit 5c3484
  return k;
Packit 5c3484
}
Packit 5c3484
Packit 5c3484
/* rp[n-1..0] = bp[n-1..0] ^ ep[en-1..0] mod B^n, B is the limb base.
Packit 5c3484
   Requires that ep[en-1] is non-zero.
Packit 5c3484
   Uses scratch space tp[3n-1..0], i.e., 3n words.  */
Packit 5c3484
/* We only use n words in the scratch space, we should pass tp + n to
Packit 5c3484
   mullo/sqrlo as a temporary area, it is needed. */
Packit 5c3484
void
Packit 5c3484
mpn_powlo (mp_ptr rp, mp_srcptr bp,
Packit 5c3484
	   mp_srcptr ep, mp_size_t en,
Packit 5c3484
	   mp_size_t n, mp_ptr tp)
Packit 5c3484
{
Packit 5c3484
  int cnt;
Packit 5c3484
  mp_bitcnt_t ebi;
Packit 5c3484
  int windowsize, this_windowsize;
Packit 5c3484
  mp_limb_t expbits;
Packit 5c3484
  mp_limb_t *pp, *this_pp, *last_pp;
Packit 5c3484
  long i;
Packit 5c3484
  TMP_DECL;
Packit 5c3484
Packit 5c3484
  ASSERT (en > 1 || (en == 1 && ep[0] > 1));
Packit 5c3484
Packit 5c3484
  TMP_MARK;
Packit 5c3484
Packit 5c3484
  MPN_SIZEINBASE_2EXP(ebi, ep, en, 1);
Packit 5c3484
Packit 5c3484
  windowsize = win_size (ebi);
Packit 5c3484
  ASSERT (windowsize < ebi);
Packit 5c3484
Packit 5c3484
  pp = TMP_ALLOC_LIMBS ((n << (windowsize - 1)));
Packit 5c3484
Packit 5c3484
  this_pp = pp;
Packit 5c3484
Packit 5c3484
  MPN_COPY (this_pp, bp, n);
Packit 5c3484
Packit 5c3484
  /* Store b^2 in tp.  */
Packit 5c3484
  mpn_sqrlo (tp, bp, n);
Packit 5c3484
Packit 5c3484
  /* Precompute odd powers of b and put them in the temporary area at pp.  */
Packit 5c3484
  for (i = (1 << (windowsize - 1)) - 1; i > 0; i--)
Packit 5c3484
    {
Packit 5c3484
      last_pp = this_pp;
Packit 5c3484
      this_pp += n;
Packit 5c3484
      mpn_mullo_n (this_pp, last_pp, tp, n);
Packit 5c3484
    }
Packit 5c3484
Packit 5c3484
  expbits = getbits (ep, ebi, windowsize);
Packit 5c3484
Packit 5c3484
  /* FIXME: for even expbits, we can init with a mullo. */
Packit 5c3484
  count_trailing_zeros (cnt, expbits);
Packit 5c3484
  ebi -= windowsize;
Packit 5c3484
  ebi += cnt;
Packit 5c3484
  expbits >>= cnt;
Packit 5c3484
Packit 5c3484
  MPN_COPY (rp, pp + n * (expbits >> 1), n);
Packit 5c3484
Packit 5c3484
  do
Packit 5c3484
    {
Packit 5c3484
      while (getbit (ep, ebi) == 0)
Packit 5c3484
	{
Packit 5c3484
	  mpn_sqrlo (tp, rp, n);
Packit 5c3484
	  MPN_COPY (rp, tp, n);
Packit 5c3484
	  if (--ebi == 0)
Packit 5c3484
	    goto done;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      /* The next bit of the exponent is 1.  Now extract the largest block of
Packit 5c3484
	 bits <= windowsize, and such that the least significant bit is 1.  */
Packit 5c3484
Packit 5c3484
      expbits = getbits (ep, ebi, windowsize);
Packit 5c3484
      this_windowsize = windowsize;
Packit 5c3484
      if (ebi < windowsize)
Packit 5c3484
	{
Packit 5c3484
	  this_windowsize -= windowsize - ebi;
Packit 5c3484
	  ebi = 0;
Packit 5c3484
	}
Packit 5c3484
      else
Packit 5c3484
	ebi -= windowsize;
Packit 5c3484
Packit 5c3484
      count_trailing_zeros (cnt, expbits);
Packit 5c3484
      this_windowsize -= cnt;
Packit 5c3484
      ebi += cnt;
Packit 5c3484
      expbits >>= cnt;
Packit 5c3484
Packit 5c3484
      while (this_windowsize > 1)
Packit 5c3484
	{
Packit 5c3484
	  mpn_sqrlo (tp, rp, n);
Packit 5c3484
	  mpn_sqrlo (rp, tp, n);
Packit 5c3484
	  this_windowsize -= 2;
Packit 5c3484
	}
Packit 5c3484
Packit 5c3484
      if (this_windowsize != 0)
Packit 5c3484
	mpn_sqrlo (tp, rp, n);
Packit 5c3484
      else
Packit 5c3484
	MPN_COPY (tp, rp, n);
Packit 5c3484
      
Packit 5c3484
      mpn_mullo_n (rp, tp, pp + n * (expbits >> 1), n);
Packit 5c3484
    } while (ebi != 0);
Packit 5c3484
Packit 5c3484
 done:
Packit 5c3484
  TMP_FREE;
Packit 5c3484
}