xref: /dragonfly/contrib/gmp/mpn/generic/powlo.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /* mpn_powlo -- Compute R = U^E mod B^n, where B is the limb base.
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino Copyright 2007, 2008, 2009 Free Software Foundation, Inc.
4*86d7f5d3SJohn Marino 
5*86d7f5d3SJohn Marino This file is part of the GNU MP Library.
6*86d7f5d3SJohn Marino 
7*86d7f5d3SJohn Marino The GNU MP Library is free software; you can redistribute it and/or modify
8*86d7f5d3SJohn Marino it under the terms of the GNU Lesser General Public License as published by
9*86d7f5d3SJohn Marino the Free Software Foundation; either version 3 of the License, or (at your
10*86d7f5d3SJohn Marino option) any later version.
11*86d7f5d3SJohn Marino 
12*86d7f5d3SJohn Marino The GNU MP Library is distributed in the hope that it will be useful, but
13*86d7f5d3SJohn Marino WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14*86d7f5d3SJohn Marino or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15*86d7f5d3SJohn Marino License for more details.
16*86d7f5d3SJohn Marino 
17*86d7f5d3SJohn Marino You should have received a copy of the GNU Lesser General Public License
18*86d7f5d3SJohn Marino along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19*86d7f5d3SJohn Marino 
20*86d7f5d3SJohn Marino 
21*86d7f5d3SJohn Marino #include "gmp.h"
22*86d7f5d3SJohn Marino #include "gmp-impl.h"
23*86d7f5d3SJohn Marino #include "longlong.h"
24*86d7f5d3SJohn Marino 
25*86d7f5d3SJohn Marino 
26*86d7f5d3SJohn Marino #define getbit(p,bi) \
27*86d7f5d3SJohn Marino   ((p[(bi - 1) / GMP_LIMB_BITS] >> (bi - 1) % GMP_LIMB_BITS) & 1)
28*86d7f5d3SJohn Marino 
29*86d7f5d3SJohn Marino static inline mp_limb_t
getbits(const mp_limb_t * p,mp_bitcnt_t bi,int nbits)30*86d7f5d3SJohn Marino getbits (const mp_limb_t *p, mp_bitcnt_t bi, int nbits)
31*86d7f5d3SJohn Marino {
32*86d7f5d3SJohn Marino   int nbits_in_r;
33*86d7f5d3SJohn Marino   mp_limb_t r;
34*86d7f5d3SJohn Marino   mp_size_t i;
35*86d7f5d3SJohn Marino 
36*86d7f5d3SJohn Marino   if (bi < nbits)
37*86d7f5d3SJohn Marino     {
38*86d7f5d3SJohn Marino       return p[0] & (((mp_limb_t) 1 << bi) - 1);
39*86d7f5d3SJohn Marino     }
40*86d7f5d3SJohn Marino   else
41*86d7f5d3SJohn Marino     {
42*86d7f5d3SJohn Marino       bi -= nbits;			/* bit index of low bit to extract */
43*86d7f5d3SJohn Marino       i = bi / GMP_NUMB_BITS;		/* word index of low bit to extract */
44*86d7f5d3SJohn Marino       bi %= GMP_NUMB_BITS;		/* bit index in low word */
45*86d7f5d3SJohn Marino       r = p[i] >> bi;			/* extract (low) bits */
46*86d7f5d3SJohn Marino       nbits_in_r = GMP_NUMB_BITS - bi;	/* number of bits now in r */
47*86d7f5d3SJohn Marino       if (nbits_in_r < nbits)		/* did we get enough bits? */
48*86d7f5d3SJohn Marino 	r += p[i + 1] << nbits_in_r;	/* prepend bits from higher word */
49*86d7f5d3SJohn Marino       return r & (((mp_limb_t ) 1 << nbits) - 1);
50*86d7f5d3SJohn Marino     }
51*86d7f5d3SJohn Marino }
52*86d7f5d3SJohn Marino 
53*86d7f5d3SJohn Marino static inline int
win_size(mp_bitcnt_t eb)54*86d7f5d3SJohn Marino win_size (mp_bitcnt_t eb)
55*86d7f5d3SJohn Marino {
56*86d7f5d3SJohn Marino   int k;
57*86d7f5d3SJohn Marino   static mp_bitcnt_t x[] = {1,7,25,81,241,673,1793,4609,11521,28161,~(mp_bitcnt_t)0};
58*86d7f5d3SJohn Marino   for (k = 0; eb > x[k]; k++)
59*86d7f5d3SJohn Marino     ;
60*86d7f5d3SJohn Marino   return k;
61*86d7f5d3SJohn Marino }
62*86d7f5d3SJohn Marino 
63*86d7f5d3SJohn Marino /* rp[n-1..0] = bp[n-1..0] ^ ep[en-1..0] mod B^n, B is the limb base.
64*86d7f5d3SJohn Marino    Requires that ep[en-1] is non-zero.
65*86d7f5d3SJohn Marino    Uses scratch space tp[3n-1..0], i.e., 3n words.  */
66*86d7f5d3SJohn Marino void
mpn_powlo(mp_ptr rp,mp_srcptr bp,mp_srcptr ep,mp_size_t en,mp_size_t n,mp_ptr tp)67*86d7f5d3SJohn Marino mpn_powlo (mp_ptr rp, mp_srcptr bp,
68*86d7f5d3SJohn Marino 	   mp_srcptr ep, mp_size_t en,
69*86d7f5d3SJohn Marino 	   mp_size_t n, mp_ptr tp)
70*86d7f5d3SJohn Marino {
71*86d7f5d3SJohn Marino   int cnt;
72*86d7f5d3SJohn Marino   mp_bitcnt_t ebi;
73*86d7f5d3SJohn Marino   int windowsize, this_windowsize;
74*86d7f5d3SJohn Marino   mp_limb_t expbits;
75*86d7f5d3SJohn Marino   mp_limb_t *pp, *this_pp, *last_pp;
76*86d7f5d3SJohn Marino   mp_limb_t *b2p;
77*86d7f5d3SJohn Marino   long i;
78*86d7f5d3SJohn Marino   TMP_DECL;
79*86d7f5d3SJohn Marino 
80*86d7f5d3SJohn Marino   ASSERT (en > 1 || (en == 1 && ep[0] > 1));
81*86d7f5d3SJohn Marino 
82*86d7f5d3SJohn Marino   TMP_MARK;
83*86d7f5d3SJohn Marino 
84*86d7f5d3SJohn Marino   count_leading_zeros (cnt, ep[en - 1]);
85*86d7f5d3SJohn Marino   ebi = (mp_bitcnt_t) en * GMP_LIMB_BITS - cnt;
86*86d7f5d3SJohn Marino 
87*86d7f5d3SJohn Marino   windowsize = win_size (ebi);
88*86d7f5d3SJohn Marino 
89*86d7f5d3SJohn Marino   pp = TMP_ALLOC_LIMBS ((n << (windowsize - 1)) + n); /* + n is for mullo ign part */
90*86d7f5d3SJohn Marino 
91*86d7f5d3SJohn Marino   this_pp = pp;
92*86d7f5d3SJohn Marino 
93*86d7f5d3SJohn Marino   MPN_COPY (this_pp, bp, n);
94*86d7f5d3SJohn Marino 
95*86d7f5d3SJohn Marino   b2p = tp + 2*n;
96*86d7f5d3SJohn Marino 
97*86d7f5d3SJohn Marino   /* Store b^2 in b2.  */
98*86d7f5d3SJohn Marino   mpn_sqr (tp, bp, n);	/* FIXME: Use "mpn_sqrlo" */
99*86d7f5d3SJohn Marino   MPN_COPY (b2p, tp, n);
100*86d7f5d3SJohn Marino 
101*86d7f5d3SJohn Marino   /* Precompute odd powers of b and put them in the temporary area at pp.  */
102*86d7f5d3SJohn Marino   for (i = (1 << (windowsize - 1)) - 1; i > 0; i--)
103*86d7f5d3SJohn Marino     {
104*86d7f5d3SJohn Marino       last_pp = this_pp;
105*86d7f5d3SJohn Marino       this_pp += n;
106*86d7f5d3SJohn Marino       mpn_mullo_n (this_pp, last_pp, b2p, n);
107*86d7f5d3SJohn Marino     }
108*86d7f5d3SJohn Marino 
109*86d7f5d3SJohn Marino   expbits = getbits (ep, ebi, windowsize);
110*86d7f5d3SJohn Marino   if (ebi < windowsize)
111*86d7f5d3SJohn Marino     ebi = 0;
112*86d7f5d3SJohn Marino   else
113*86d7f5d3SJohn Marino     ebi -= windowsize;
114*86d7f5d3SJohn Marino 
115*86d7f5d3SJohn Marino   count_trailing_zeros (cnt, expbits);
116*86d7f5d3SJohn Marino   ebi += cnt;
117*86d7f5d3SJohn Marino   expbits >>= cnt;
118*86d7f5d3SJohn Marino 
119*86d7f5d3SJohn Marino   MPN_COPY (rp, pp + n * (expbits >> 1), n);
120*86d7f5d3SJohn Marino 
121*86d7f5d3SJohn Marino   while (ebi != 0)
122*86d7f5d3SJohn Marino     {
123*86d7f5d3SJohn Marino       while (getbit (ep, ebi) == 0)
124*86d7f5d3SJohn Marino 	{
125*86d7f5d3SJohn Marino 	  mpn_sqr (tp, rp, n);	/* FIXME: Use "mpn_sqrlo" */
126*86d7f5d3SJohn Marino 	  MPN_COPY (rp, tp, n);
127*86d7f5d3SJohn Marino 	  ebi--;
128*86d7f5d3SJohn Marino 	  if (ebi == 0)
129*86d7f5d3SJohn Marino 	    goto done;
130*86d7f5d3SJohn Marino 	}
131*86d7f5d3SJohn Marino 
132*86d7f5d3SJohn Marino       /* The next bit of the exponent is 1.  Now extract the largest block of
133*86d7f5d3SJohn Marino 	 bits <= windowsize, and such that the least significant bit is 1.  */
134*86d7f5d3SJohn Marino 
135*86d7f5d3SJohn Marino       expbits = getbits (ep, ebi, windowsize);
136*86d7f5d3SJohn Marino       this_windowsize = windowsize;
137*86d7f5d3SJohn Marino       if (ebi < windowsize)
138*86d7f5d3SJohn Marino 	{
139*86d7f5d3SJohn Marino 	  this_windowsize -= windowsize - ebi;
140*86d7f5d3SJohn Marino 	  ebi = 0;
141*86d7f5d3SJohn Marino 	}
142*86d7f5d3SJohn Marino       else
143*86d7f5d3SJohn Marino 	ebi -= windowsize;
144*86d7f5d3SJohn Marino 
145*86d7f5d3SJohn Marino       count_trailing_zeros (cnt, expbits);
146*86d7f5d3SJohn Marino       this_windowsize -= cnt;
147*86d7f5d3SJohn Marino       ebi += cnt;
148*86d7f5d3SJohn Marino       expbits >>= cnt;
149*86d7f5d3SJohn Marino 
150*86d7f5d3SJohn Marino       do
151*86d7f5d3SJohn Marino 	{
152*86d7f5d3SJohn Marino 	  mpn_sqr (tp, rp, n);
153*86d7f5d3SJohn Marino 	  MPN_COPY (rp, tp, n);
154*86d7f5d3SJohn Marino 	  this_windowsize--;
155*86d7f5d3SJohn Marino 	}
156*86d7f5d3SJohn Marino       while (this_windowsize != 0);
157*86d7f5d3SJohn Marino 
158*86d7f5d3SJohn Marino       mpn_mullo_n (tp, rp, pp + n * (expbits >> 1), n);
159*86d7f5d3SJohn Marino       MPN_COPY (rp, tp, n);
160*86d7f5d3SJohn Marino     }
161*86d7f5d3SJohn Marino 
162*86d7f5d3SJohn Marino  done:
163*86d7f5d3SJohn Marino   TMP_FREE;
164*86d7f5d3SJohn Marino }
165