Annotation of OpenXM/src/kan96xx/gmp-2.0.2-ssh-2/mpz/powm.c, Revision 1.1
1.1 ! takayama 1: /* mpz_powm(res,base,exp,mod) -- Set RES to (base**exp) mod MOD.
! 2:
! 3: Copyright (C) 1991, 1993, 1994, 1996 Free Software Foundation, Inc.
! 4:
! 5: This file is part of the GNU MP Library.
! 6:
! 7: The GNU MP Library is free software; you can redistribute it and/or modify
! 8: it under the terms of the GNU Library General Public License as published by
! 9: the Free Software Foundation; either version 2 of the License, or (at your
! 10: option) any later version.
! 11:
! 12: The GNU MP Library is distributed in the hope that it will be useful, but
! 13: WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 14: or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
! 15: License for more details.
! 16:
! 17: You should have received a copy of the GNU Library General Public License
! 18: along with the GNU MP Library; see the file COPYING.LIB. If not, write to
! 19: the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
! 20: MA 02111-1307, USA. */
! 21:
! 22: #include "gmp.h"
! 23: #include "gmp-impl.h"
! 24: #include "longlong.h"
! 25:
! 26: #ifndef BERKELEY_MP
! 27: void
! 28: #if __STDC__
! 29: mpz_powm (mpz_ptr res, mpz_srcptr base, mpz_srcptr exp, mpz_srcptr mod)
! 30: #else
! 31: mpz_powm (res, base, exp, mod)
! 32: mpz_ptr res;
! 33: mpz_srcptr base;
! 34: mpz_srcptr exp;
! 35: mpz_srcptr mod;
! 36: #endif
! 37: #else /* BERKELEY_MP */
! 38: void
! 39: #if __STDC__
! 40: pow (mpz_srcptr base, mpz_srcptr exp, mpz_srcptr mod, mpz_ptr res)
! 41: #else
! 42: pow (base, exp, mod, res)
! 43: mpz_srcptr base;
! 44: mpz_srcptr exp;
! 45: mpz_srcptr mod;
! 46: mpz_ptr res;
! 47: #endif
! 48: #endif /* BERKELEY_MP */
! 49: {
! 50: mp_ptr rp, ep, mp, bp;
! 51: mp_size_t esize, msize, bsize, rsize;
! 52: mp_size_t size;
! 53: int mod_shift_cnt;
! 54: int negative_result;
! 55: mp_limb_t *free_me = NULL;
! 56: size_t free_me_size;
! 57: TMP_DECL (marker);
! 58:
! 59: esize = ABS (exp->_mp_size);
! 60: msize = ABS (mod->_mp_size);
! 61: size = 2 * msize;
! 62:
! 63: rp = res->_mp_d;
! 64: ep = exp->_mp_d;
! 65:
! 66: if (msize == 0)
! 67: msize = 1 / msize; /* provoke a signal */
! 68:
! 69: if (esize == 0)
! 70: {
! 71: /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0
! 72: depending on if MOD equals 1. */
! 73: rp[0] = 1;
! 74: res->_mp_size = (msize == 1 && (mod->_mp_d)[0] == 1) ? 0 : 1;
! 75: return;
! 76: }
! 77:
! 78: TMP_MARK (marker);
! 79:
! 80: /* Normalize MOD (i.e. make its most significant bit set) as required by
! 81: mpn_divmod. This will make the intermediate values in the calculation
! 82: slightly larger, but the correct result is obtained after a final
! 83: reduction using the original MOD value. */
! 84:
! 85: mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
! 86: count_leading_zeros (mod_shift_cnt, mod->_mp_d[msize - 1]);
! 87: if (mod_shift_cnt != 0)
! 88: mpn_lshift (mp, mod->_mp_d, msize, mod_shift_cnt);
! 89: else
! 90: MPN_COPY (mp, mod->_mp_d, msize);
! 91:
! 92: bsize = ABS (base->_mp_size);
! 93: if (bsize > msize)
! 94: {
! 95: /* The base is larger than the module. Reduce it. */
! 96:
! 97: /* Allocate (BSIZE + 1) with space for remainder and quotient.
! 98: (The quotient is (bsize - msize + 1) limbs.) */
! 99: bp = (mp_ptr) TMP_ALLOC ((bsize + 1) * BYTES_PER_MP_LIMB);
! 100: MPN_COPY (bp, base->_mp_d, bsize);
! 101: /* We don't care about the quotient, store it above the remainder,
! 102: at BP + MSIZE. */
! 103: mpn_divmod (bp + msize, bp, bsize, mp, msize);
! 104: bsize = msize;
! 105: /* Canonicalize the base, since we are going to multiply with it
! 106: quite a few times. */
! 107: MPN_NORMALIZE (bp, bsize);
! 108: }
! 109: else
! 110: bp = base->_mp_d;
! 111:
! 112: if (bsize == 0)
! 113: {
! 114: res->_mp_size = 0;
! 115: TMP_FREE (marker);
! 116: return;
! 117: }
! 118:
! 119: if (res->_mp_alloc < size)
! 120: {
! 121: /* We have to allocate more space for RES. If any of the input
! 122: parameters are identical to RES, defer deallocation of the old
! 123: space. */
! 124:
! 125: if (rp == ep || rp == mp || rp == bp)
! 126: {
! 127: free_me = rp;
! 128: free_me_size = res->_mp_alloc;
! 129: }
! 130: else
! 131: (*_mp_free_func) (rp, res->_mp_alloc * BYTES_PER_MP_LIMB);
! 132:
! 133: rp = (mp_ptr) (*_mp_allocate_func) (size * BYTES_PER_MP_LIMB);
! 134: res->_mp_alloc = size;
! 135: res->_mp_d = rp;
! 136: }
! 137: else
! 138: {
! 139: /* Make BASE, EXP and MOD not overlap with RES. */
! 140: if (rp == bp)
! 141: {
! 142: /* RES and BASE are identical. Allocate temp. space for BASE. */
! 143: bp = (mp_ptr) TMP_ALLOC (bsize * BYTES_PER_MP_LIMB);
! 144: MPN_COPY (bp, rp, bsize);
! 145: }
! 146: if (rp == ep)
! 147: {
! 148: /* RES and EXP are identical. Allocate temp. space for EXP. */
! 149: ep = (mp_ptr) TMP_ALLOC (esize * BYTES_PER_MP_LIMB);
! 150: MPN_COPY (ep, rp, esize);
! 151: }
! 152: if (rp == mp)
! 153: {
! 154: /* RES and MOD are identical. Allocate temporary space for MOD. */
! 155: mp = (mp_ptr) TMP_ALLOC (msize * BYTES_PER_MP_LIMB);
! 156: MPN_COPY (mp, rp, msize);
! 157: }
! 158: }
! 159:
! 160: MPN_COPY (rp, bp, bsize);
! 161: rsize = bsize;
! 162:
! 163: {
! 164: mp_size_t i;
! 165: mp_ptr xp = (mp_ptr) TMP_ALLOC (2 * (msize + 1) * BYTES_PER_MP_LIMB);
! 166: int c;
! 167: mp_limb_t e;
! 168: mp_limb_t carry_limb;
! 169:
! 170: negative_result = (ep[0] & 1) && base->_mp_size < 0;
! 171:
! 172: i = esize - 1;
! 173: e = ep[i];
! 174: count_leading_zeros (c, e);
! 175: e = (e << c) << 1; /* shift the exp bits to the left, lose msb */
! 176: c = BITS_PER_MP_LIMB - 1 - c;
! 177:
! 178: /* Main loop.
! 179:
! 180: Make the result be pointed to alternately by XP and RP. This
! 181: helps us avoid block copying, which would otherwise be necessary
! 182: with the overlap restrictions of mpn_divmod. With 50% probability
! 183: the result after this loop will be in the area originally pointed
! 184: by RP (==RES->_mp_d), and with 50% probability in the area originally
! 185: pointed to by XP. */
! 186:
! 187: for (;;)
! 188: {
! 189: while (c != 0)
! 190: {
! 191: mp_ptr tp;
! 192: mp_size_t xsize;
! 193:
! 194: mpn_mul_n (xp, rp, rp, rsize);
! 195: xsize = 2 * rsize;
! 196: if (xsize > msize)
! 197: {
! 198: mpn_divmod (xp + msize, xp, xsize, mp, msize);
! 199: xsize = msize;
! 200: }
! 201:
! 202: tp = rp; rp = xp; xp = tp;
! 203: rsize = xsize;
! 204:
! 205: if ((mp_limb_signed_t) e < 0)
! 206: {
! 207: mpn_mul (xp, rp, rsize, bp, bsize);
! 208: xsize = rsize + bsize;
! 209: if (xsize > msize)
! 210: {
! 211: mpn_divmod (xp + msize, xp, xsize, mp, msize);
! 212: xsize = msize;
! 213: }
! 214:
! 215: tp = rp; rp = xp; xp = tp;
! 216: rsize = xsize;
! 217: }
! 218: e <<= 1;
! 219: c--;
! 220: }
! 221:
! 222: i--;
! 223: if (i < 0)
! 224: break;
! 225: e = ep[i];
! 226: c = BITS_PER_MP_LIMB;
! 227: }
! 228:
! 229: /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT
! 230: steps. Adjust the result by reducing it with the original MOD.
! 231:
! 232: Also make sure the result is put in RES->_mp_d (where it already
! 233: might be, see above). */
! 234:
! 235: if (mod_shift_cnt != 0)
! 236: {
! 237: carry_limb = mpn_lshift (res->_mp_d, rp, rsize, mod_shift_cnt);
! 238: rp = res->_mp_d;
! 239: if (carry_limb != 0)
! 240: {
! 241: rp[rsize] = carry_limb;
! 242: rsize++;
! 243: }
! 244: }
! 245: else
! 246: {
! 247: MPN_COPY (res->_mp_d, rp, rsize);
! 248: rp = res->_mp_d;
! 249: }
! 250:
! 251: if (rsize >= msize)
! 252: {
! 253: mpn_divmod (rp + msize, rp, rsize, mp, msize);
! 254: rsize = msize;
! 255: }
! 256:
! 257: /* Remove any leading zero words from the result. */
! 258: if (mod_shift_cnt != 0)
! 259: mpn_rshift (rp, rp, rsize, mod_shift_cnt);
! 260: MPN_NORMALIZE (rp, rsize);
! 261: }
! 262:
! 263: if (negative_result && rsize != 0)
! 264: {
! 265: if (mod_shift_cnt != 0)
! 266: mpn_rshift (mp, mp, msize, mod_shift_cnt);
! 267: mpn_sub (rp, mp, msize, rp, rsize);
! 268: rsize = msize;
! 269: MPN_NORMALIZE (rp, rsize);
! 270: }
! 271: res->_mp_size = rsize;
! 272:
! 273: if (free_me != NULL)
! 274: (*_mp_free_func) (free_me, free_me_size * BYTES_PER_MP_LIMB);
! 275: TMP_FREE (marker);
! 276: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>