Home | History | Annotate | Line # | Download | only in mpz
powm_ui.c revision 1.1.1.2
      1  1.1.1.2  mrg /* mpz_powm_ui(res,base,exp,mod) -- Set R to (U^E) mod M.
      2      1.1  mrg 
      3  1.1.1.2  mrg    Contributed to the GNU project by Torbjorn Granlund.
      4  1.1.1.2  mrg 
      5  1.1.1.2  mrg Copyright 1991, 1993, 1994, 1996, 1997, 2000, 2001, 2002, 2005, 2008, 2009,
      6  1.1.1.2  mrg 2011, 2012, 2013 Free Software Foundation, Inc.
      7      1.1  mrg 
      8      1.1  mrg This file is part of the GNU MP Library.
      9      1.1  mrg 
     10      1.1  mrg The GNU MP Library is free software; you can redistribute it and/or modify
     11      1.1  mrg it under the terms of the GNU Lesser General Public License as published by
     12      1.1  mrg the Free Software Foundation; either version 3 of the License, or (at your
     13      1.1  mrg option) any later version.
     14      1.1  mrg 
     15      1.1  mrg The GNU MP Library is distributed in the hope that it will be useful, but
     16      1.1  mrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
     17      1.1  mrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
     18      1.1  mrg License for more details.
     19      1.1  mrg 
     20      1.1  mrg You should have received a copy of the GNU Lesser General Public License
     21      1.1  mrg along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
     22      1.1  mrg 
     23      1.1  mrg 
     24      1.1  mrg #include "gmp.h"
     25      1.1  mrg #include "gmp-impl.h"
     26      1.1  mrg #include "longlong.h"
     27      1.1  mrg 
     28  1.1.1.2  mrg 
     29  1.1.1.2  mrg /* This code is very old, and should be rewritten to current GMP standard.  It
     30  1.1.1.2  mrg    is slower than mpz_powm for large exponents, but also for small exponents
     31  1.1.1.2  mrg    when the mod argument is small.
     32  1.1.1.2  mrg 
     33  1.1.1.2  mrg    As an intermediate solution, we now deflect to mpz_powm for exponents >= 20.
     34  1.1.1.2  mrg */
     35  1.1.1.2  mrg 
     36  1.1.1.2  mrg /*
     37  1.1.1.2  mrg   b ^ e mod m   res
     38  1.1.1.2  mrg   0   0     0    ?
     39  1.1.1.2  mrg   0   e     0    ?
     40  1.1.1.2  mrg   0   0     m    ?
     41  1.1.1.2  mrg   0   e     m    0
     42  1.1.1.2  mrg   b   0     0    ?
     43  1.1.1.2  mrg   b   e     0    ?
     44  1.1.1.2  mrg   b   0     m    1 mod m
     45  1.1.1.2  mrg   b   e     m    b^e mod m
     46  1.1.1.2  mrg */
     47  1.1.1.2  mrg 
     48      1.1  mrg static void
     49  1.1.1.2  mrg mod (mp_ptr np, mp_size_t nn, mp_srcptr dp, mp_size_t dn, gmp_pi1_t *dinv, mp_ptr tp)
     50      1.1  mrg {
     51      1.1  mrg   mp_ptr qp;
     52      1.1  mrg   TMP_DECL;
     53      1.1  mrg   TMP_MARK;
     54      1.1  mrg 
     55  1.1.1.2  mrg   qp = tp;
     56  1.1.1.2  mrg 
     57  1.1.1.2  mrg   if (dn == 1)
     58  1.1.1.2  mrg     np[0] = mpn_divrem_1 (qp, (mp_size_t) 0, np, nn, dp[0]);
     59  1.1.1.2  mrg   else if (dn == 2)
     60  1.1.1.2  mrg     mpn_div_qr_2n_pi1 (qp, np, np, nn, dp[1], dp[0], dinv->inv32);
     61  1.1.1.2  mrg   else if (BELOW_THRESHOLD (dn, DC_DIV_QR_THRESHOLD) ||
     62  1.1.1.2  mrg 	   BELOW_THRESHOLD (nn - dn, DC_DIV_QR_THRESHOLD))
     63  1.1.1.2  mrg     mpn_sbpi1_div_qr (qp, np, nn, dp, dn, dinv->inv32);
     64  1.1.1.2  mrg   else if (BELOW_THRESHOLD (dn, MUPI_DIV_QR_THRESHOLD) ||   /* fast condition */
     65  1.1.1.2  mrg 	   BELOW_THRESHOLD (nn, 2 * MU_DIV_QR_THRESHOLD) || /* fast condition */
     66  1.1.1.2  mrg 	   (double) (2 * (MU_DIV_QR_THRESHOLD - MUPI_DIV_QR_THRESHOLD)) * dn /* slow... */
     67  1.1.1.2  mrg 	   + (double) MUPI_DIV_QR_THRESHOLD * nn > (double) dn * nn)    /* ...condition */
     68  1.1.1.2  mrg     {
     69  1.1.1.2  mrg       mpn_dcpi1_div_qr (qp, np, nn, dp, dn, dinv);
     70  1.1.1.2  mrg     }
     71  1.1.1.2  mrg   else
     72  1.1.1.2  mrg     {
     73  1.1.1.2  mrg       /* We need to allocate separate remainder area, since mpn_mu_div_qr does
     74  1.1.1.2  mrg 	 not handle overlap between the numerator and remainder areas.
     75  1.1.1.2  mrg 	 FIXME: Make it handle such overlap.  */
     76  1.1.1.2  mrg       mp_ptr rp = TMP_ALLOC_LIMBS (dn);
     77  1.1.1.2  mrg       mp_size_t itch = mpn_mu_div_qr_itch (nn, dn, 0);
     78  1.1.1.2  mrg       mp_ptr scratch = TMP_ALLOC_LIMBS (itch);
     79  1.1.1.2  mrg       mpn_mu_div_qr (qp, rp, np, nn, dp, dn, scratch);
     80  1.1.1.2  mrg       MPN_COPY (np, rp, dn);
     81  1.1.1.2  mrg     }
     82      1.1  mrg 
     83      1.1  mrg   TMP_FREE;
     84      1.1  mrg }
     85      1.1  mrg 
     86  1.1.1.2  mrg /* Compute t = a mod m, a is defined by (ap,an), m is defined by (mp,mn), and
     87  1.1.1.2  mrg    t is defined by (tp,mn).  */
     88  1.1.1.2  mrg static void
     89  1.1.1.2  mrg reduce (mp_ptr tp, mp_srcptr ap, mp_size_t an, mp_srcptr mp, mp_size_t mn, gmp_pi1_t *dinv)
     90      1.1  mrg {
     91  1.1.1.2  mrg   mp_ptr rp, scratch;
     92      1.1  mrg   TMP_DECL;
     93  1.1.1.2  mrg   TMP_MARK;
     94      1.1  mrg 
     95  1.1.1.2  mrg   rp = TMP_ALLOC_LIMBS (an);
     96  1.1.1.2  mrg   scratch = TMP_ALLOC_LIMBS (an - mn + 1);
     97  1.1.1.2  mrg   MPN_COPY (rp, ap, an);
     98  1.1.1.2  mrg   mod (rp, an, mp, mn, dinv, scratch);
     99  1.1.1.2  mrg   MPN_COPY (tp, rp, mn);
    100      1.1  mrg 
    101  1.1.1.2  mrg   TMP_FREE;
    102  1.1.1.2  mrg }
    103      1.1  mrg 
    104  1.1.1.2  mrg void
    105  1.1.1.2  mrg mpz_powm_ui (mpz_ptr r, mpz_srcptr b, unsigned long int el, mpz_srcptr m)
    106  1.1.1.2  mrg {
    107  1.1.1.2  mrg   if (el < 20)
    108      1.1  mrg     {
    109  1.1.1.2  mrg       mp_ptr xp, tp, mp, bp, scratch;
    110  1.1.1.2  mrg       mp_size_t xn, tn, mn, bn;
    111  1.1.1.2  mrg       int m_zero_cnt;
    112  1.1.1.2  mrg       int c;
    113  1.1.1.2  mrg       mp_limb_t e, m2;
    114  1.1.1.2  mrg       gmp_pi1_t dinv;
    115  1.1.1.2  mrg       TMP_DECL;
    116  1.1.1.2  mrg 
    117  1.1.1.2  mrg       mp = PTR(m);
    118  1.1.1.2  mrg       mn = ABSIZ(m);
    119  1.1.1.2  mrg       if (UNLIKELY (mn == 0))
    120  1.1.1.2  mrg 	DIVIDE_BY_ZERO;
    121      1.1  mrg 
    122  1.1.1.2  mrg       if (el == 0)
    123  1.1.1.2  mrg 	{
    124  1.1.1.2  mrg 	  /* Exponent is zero, result is 1 mod M, i.e., 1 or 0 depending on if
    125  1.1.1.2  mrg 	     M equals 1.  */
    126  1.1.1.2  mrg 	  SIZ(r) = (mn == 1 && mp[0] == 1) ? 0 : 1;
    127  1.1.1.2  mrg 	  PTR(r)[0] = 1;
    128  1.1.1.2  mrg 	  return;
    129  1.1.1.2  mrg 	}
    130      1.1  mrg 
    131  1.1.1.2  mrg       TMP_MARK;
    132      1.1  mrg 
    133  1.1.1.2  mrg       /* Normalize m (i.e. make its most significant bit set) as required by
    134  1.1.1.2  mrg 	 division functions below.  */
    135  1.1.1.2  mrg       count_leading_zeros (m_zero_cnt, mp[mn - 1]);
    136  1.1.1.2  mrg       m_zero_cnt -= GMP_NAIL_BITS;
    137  1.1.1.2  mrg       if (m_zero_cnt != 0)
    138  1.1.1.2  mrg 	{
    139  1.1.1.2  mrg 	  mp_ptr new_mp = TMP_ALLOC_LIMBS (mn);
    140  1.1.1.2  mrg 	  mpn_lshift (new_mp, mp, mn, m_zero_cnt);
    141  1.1.1.2  mrg 	  mp = new_mp;
    142  1.1.1.2  mrg 	}
    143      1.1  mrg 
    144  1.1.1.2  mrg       m2 = mn == 1 ? 0 : mp[mn - 2];
    145  1.1.1.2  mrg       invert_pi1 (dinv, mp[mn - 1], m2);
    146      1.1  mrg 
    147  1.1.1.2  mrg       bn = ABSIZ(b);
    148  1.1.1.2  mrg       bp = PTR(b);
    149  1.1.1.2  mrg       if (bn > mn)
    150  1.1.1.2  mrg 	{
    151  1.1.1.2  mrg 	  /* Reduce possibly huge base.  Use a function call to reduce, since we
    152  1.1.1.2  mrg 	     don't want the quotient allocation to live until function return.  */
    153  1.1.1.2  mrg 	  mp_ptr new_bp = TMP_ALLOC_LIMBS (mn);
    154  1.1.1.2  mrg 	  reduce (new_bp, bp, bn, mp, mn, &dinv);
    155  1.1.1.2  mrg 	  bp = new_bp;
    156  1.1.1.2  mrg 	  bn = mn;
    157  1.1.1.2  mrg 	  /* Canonicalize the base, since we are potentially going to multiply with
    158  1.1.1.2  mrg 	     it quite a few times.  */
    159  1.1.1.2  mrg 	  MPN_NORMALIZE (bp, bn);
    160  1.1.1.2  mrg 	}
    161      1.1  mrg 
    162  1.1.1.2  mrg       if (bn == 0)
    163  1.1.1.2  mrg 	{
    164  1.1.1.2  mrg 	  SIZ(r) = 0;
    165  1.1.1.2  mrg 	  TMP_FREE;
    166  1.1.1.2  mrg 	  return;
    167  1.1.1.2  mrg 	}
    168      1.1  mrg 
    169  1.1.1.2  mrg       tp = TMP_ALLOC_LIMBS (2 * mn + 1);
    170  1.1.1.2  mrg       xp = TMP_ALLOC_LIMBS (mn);
    171  1.1.1.2  mrg       scratch = TMP_ALLOC_LIMBS (mn + 1);
    172  1.1.1.2  mrg 
    173  1.1.1.2  mrg       MPN_COPY (xp, bp, bn);
    174  1.1.1.2  mrg       xn = bn;
    175  1.1.1.2  mrg 
    176  1.1.1.2  mrg       e = el;
    177  1.1.1.2  mrg       count_leading_zeros (c, e);
    178  1.1.1.2  mrg       e = (e << c) << 1;		/* shift the exp bits to the left, lose msb */
    179  1.1.1.2  mrg       c = GMP_LIMB_BITS - 1 - c;
    180  1.1.1.2  mrg 
    181  1.1.1.2  mrg       if (c == 0)
    182      1.1  mrg 	{
    183  1.1.1.2  mrg 	  /* If m is already normalized (high bit of high limb set), and b is
    184  1.1.1.2  mrg 	     the same size, but a bigger value, and e==1, then there's no
    185  1.1.1.2  mrg 	     modular reductions done and we can end up with a result out of
    186  1.1.1.2  mrg 	     range at the end. */
    187  1.1.1.2  mrg 	  if (xn == mn && mpn_cmp (xp, mp, mn) >= 0)
    188  1.1.1.2  mrg 	    mpn_sub_n (xp, xp, mp, mn);
    189      1.1  mrg 	}
    190      1.1  mrg       else
    191      1.1  mrg 	{
    192  1.1.1.2  mrg 	  /* Main loop. */
    193  1.1.1.2  mrg 	  do
    194  1.1.1.2  mrg 	    {
    195  1.1.1.2  mrg 	      mpn_sqr (tp, xp, xn);
    196  1.1.1.2  mrg 	      tn = 2 * xn; tn -= tp[tn - 1] == 0;
    197  1.1.1.2  mrg 	      if (tn < mn)
    198  1.1.1.2  mrg 		{
    199  1.1.1.2  mrg 		  MPN_COPY (xp, tp, tn);
    200  1.1.1.2  mrg 		  xn = tn;
    201  1.1.1.2  mrg 		}
    202  1.1.1.2  mrg 	      else
    203  1.1.1.2  mrg 		{
    204  1.1.1.2  mrg 		  mod (tp, tn, mp, mn, &dinv, scratch);
    205  1.1.1.2  mrg 		  MPN_COPY (xp, tp, mn);
    206  1.1.1.2  mrg 		  xn = mn;
    207  1.1.1.2  mrg 		}
    208  1.1.1.2  mrg 
    209  1.1.1.2  mrg 	      if ((mp_limb_signed_t) e < 0)
    210  1.1.1.2  mrg 		{
    211  1.1.1.2  mrg 		  mpn_mul (tp, xp, xn, bp, bn);
    212  1.1.1.2  mrg 		  tn = xn + bn; tn -= tp[tn - 1] == 0;
    213  1.1.1.2  mrg 		  if (tn < mn)
    214  1.1.1.2  mrg 		    {
    215  1.1.1.2  mrg 		      MPN_COPY (xp, tp, tn);
    216  1.1.1.2  mrg 		      xn = tn;
    217  1.1.1.2  mrg 		    }
    218  1.1.1.2  mrg 		  else
    219  1.1.1.2  mrg 		    {
    220  1.1.1.2  mrg 		      mod (tp, tn, mp, mn, &dinv, scratch);
    221  1.1.1.2  mrg 		      MPN_COPY (xp, tp, mn);
    222  1.1.1.2  mrg 		      xn = mn;
    223  1.1.1.2  mrg 		    }
    224  1.1.1.2  mrg 		}
    225  1.1.1.2  mrg 	      e <<= 1;
    226  1.1.1.2  mrg 	      c--;
    227  1.1.1.2  mrg 	    }
    228  1.1.1.2  mrg 	  while (c != 0);
    229      1.1  mrg 	}
    230      1.1  mrg 
    231  1.1.1.2  mrg       /* We shifted m left m_zero_cnt steps.  Adjust the result by reducing it
    232  1.1.1.2  mrg 	 with the original M.  */
    233  1.1.1.2  mrg       if (m_zero_cnt != 0)
    234      1.1  mrg 	{
    235  1.1.1.2  mrg 	  mp_limb_t cy;
    236  1.1.1.2  mrg 	  cy = mpn_lshift (tp, xp, xn, m_zero_cnt);
    237  1.1.1.2  mrg 	  tp[xn] = cy; xn += cy != 0;
    238  1.1.1.2  mrg 
    239  1.1.1.2  mrg 	  if (xn < mn)
    240      1.1  mrg 	    {
    241  1.1.1.2  mrg 	      MPN_COPY (xp, tp, xn);
    242      1.1  mrg 	    }
    243      1.1  mrg 	  else
    244      1.1  mrg 	    {
    245  1.1.1.2  mrg 	      mod (tp, xn, mp, mn, &dinv, scratch);
    246  1.1.1.2  mrg 	      MPN_COPY (xp, tp, mn);
    247      1.1  mrg 	      xn = mn;
    248      1.1  mrg 	    }
    249  1.1.1.2  mrg 	  mpn_rshift (xp, xp, xn, m_zero_cnt);
    250      1.1  mrg 	}
    251  1.1.1.2  mrg       MPN_NORMALIZE (xp, xn);
    252      1.1  mrg 
    253  1.1.1.2  mrg       if ((el & 1) != 0 && SIZ(b) < 0 && xn != 0)
    254      1.1  mrg 	{
    255  1.1.1.2  mrg 	  mp = PTR(m);			/* want original, unnormalized m */
    256  1.1.1.2  mrg 	  mpn_sub (xp, mp, mn, xp, xn);
    257      1.1  mrg 	  xn = mn;
    258  1.1.1.2  mrg 	  MPN_NORMALIZE (xp, xn);
    259      1.1  mrg 	}
    260  1.1.1.2  mrg       MPZ_REALLOC (r, xn);
    261  1.1.1.2  mrg       SIZ (r) = xn;
    262  1.1.1.2  mrg       MPN_COPY (PTR(r), xp, xn);
    263      1.1  mrg 
    264  1.1.1.2  mrg       TMP_FREE;
    265  1.1.1.2  mrg     }
    266  1.1.1.2  mrg   else
    267      1.1  mrg     {
    268  1.1.1.2  mrg       /* For large exponents, fake a mpz_t exponent and deflect to the more
    269  1.1.1.2  mrg 	 sophisticated mpz_powm.  */
    270  1.1.1.2  mrg       mpz_t e;
    271  1.1.1.2  mrg       mp_limb_t ep[LIMBS_PER_ULONG];
    272  1.1.1.2  mrg       MPZ_FAKE_UI (e, ep, el);
    273  1.1.1.2  mrg       mpz_powm (r, b, e, m);
    274      1.1  mrg     }
    275      1.1  mrg }
    276