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