Home | History | Annotate | Download | only in libtommath
      1 #include <tommath.h>
      2 #ifdef BN_S_MP_EXPTMOD_C
      3 /* LibTomMath, multiple-precision integer library -- Tom St Denis
      4  *
      5  * LibTomMath is a library that provides multiple-precision
      6  * integer arithmetic as well as number theoretic functionality.
      7  *
      8  * The library was designed directly after the MPI library by
      9  * Michael Fromberger but has been written from scratch with
     10  * additional optimizations in place.
     11  *
     12  * The library is free for all purposes without any express
     13  * guarantee it works.
     14  *
     15  * Tom St Denis, tomstdenis (at) gmail.com, http://math.libtomcrypt.com
     16  */
     17 #ifdef MP_LOW_MEM
     18    #define TAB_SIZE 32
     19 #else
     20    #define TAB_SIZE 256
     21 #endif
     22 
     23 int s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
     24 {
     25   mp_int  M[TAB_SIZE], res, mu;
     26   mp_digit buf;
     27   int     err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
     28   int (*redux)(mp_int*,mp_int*,mp_int*);
     29 
     30   /* find window size */
     31   x = mp_count_bits (X);
     32   if (x <= 7) {
     33     winsize = 2;
     34   } else if (x <= 36) {
     35     winsize = 3;
     36   } else if (x <= 140) {
     37     winsize = 4;
     38   } else if (x <= 450) {
     39     winsize = 5;
     40   } else if (x <= 1303) {
     41     winsize = 6;
     42   } else if (x <= 3529) {
     43     winsize = 7;
     44   } else {
     45     winsize = 8;
     46   }
     47 
     48 #ifdef MP_LOW_MEM
     49     if (winsize > 5) {
     50        winsize = 5;
     51     }
     52 #endif
     53 
     54   /* init M array */
     55   /* init first cell */
     56   if ((err = mp_init(&M[1])) != MP_OKAY) {
     57      return err;
     58   }
     59 
     60   /* now init the second half of the array */
     61   for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
     62     if ((err = mp_init(&M[x])) != MP_OKAY) {
     63       for (y = 1<<(winsize-1); y < x; y++) {
     64         mp_clear (&M[y]);
     65       }
     66       mp_clear(&M[1]);
     67       return err;
     68     }
     69   }
     70 
     71   /* create mu, used for Barrett reduction */
     72   if ((err = mp_init (&mu)) != MP_OKAY) {
     73     goto LBL_M;
     74   }
     75 
     76   if (redmode == 0) {
     77      if ((err = mp_reduce_setup (&mu, P)) != MP_OKAY) {
     78         goto LBL_MU;
     79      }
     80      redux = mp_reduce;
     81   } else {
     82      if ((err = mp_reduce_2k_setup_l (P, &mu)) != MP_OKAY) {
     83         goto LBL_MU;
     84      }
     85      redux = mp_reduce_2k_l;
     86   }
     87 
     88   /* create M table
     89    *
     90    * The M table contains powers of the base,
     91    * e.g. M[x] = G**x mod P
     92    *
     93    * The first half of the table is not
     94    * computed though accept for M[0] and M[1]
     95    */
     96   if ((err = mp_mod (G, P, &M[1])) != MP_OKAY) {
     97     goto LBL_MU;
     98   }
     99 
    100   /* compute the value at M[1<<(winsize-1)] by squaring
    101    * M[1] (winsize-1) times
    102    */
    103   if ((err = mp_copy (&M[1], &M[1 << (winsize - 1)])) != MP_OKAY) {
    104     goto LBL_MU;
    105   }
    106 
    107   for (x = 0; x < (winsize - 1); x++) {
    108     /* square it */
    109     if ((err = mp_sqr (&M[1 << (winsize - 1)],
    110                        &M[1 << (winsize - 1)])) != MP_OKAY) {
    111       goto LBL_MU;
    112     }
    113 
    114     /* reduce modulo P */
    115     if ((err = redux (&M[1 << (winsize - 1)], P, &mu)) != MP_OKAY) {
    116       goto LBL_MU;
    117     }
    118   }
    119 
    120   /* create upper table, that is M[x] = M[x-1] * M[1] (mod P)
    121    * for x = (2**(winsize - 1) + 1) to (2**winsize - 1)
    122    */
    123   for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
    124     if ((err = mp_mul (&M[x - 1], &M[1], &M[x])) != MP_OKAY) {
    125       goto LBL_MU;
    126     }
    127     if ((err = redux (&M[x], P, &mu)) != MP_OKAY) {
    128       goto LBL_MU;
    129     }
    130   }
    131 
    132   /* setup result */
    133   if ((err = mp_init (&res)) != MP_OKAY) {
    134     goto LBL_MU;
    135   }
    136   mp_set (&res, 1);
    137 
    138   /* set initial mode and bit cnt */
    139   mode   = 0;
    140   bitcnt = 1;
    141   buf    = 0;
    142   digidx = X->used - 1;
    143   bitcpy = 0;
    144   bitbuf = 0;
    145 
    146   for (;;) {
    147     /* grab next digit as required */
    148     if (--bitcnt == 0) {
    149       /* if digidx == -1 we are out of digits */
    150       if (digidx == -1) {
    151         break;
    152       }
    153       /* read next digit and reset the bitcnt */
    154       buf    = X->dp[digidx--];
    155       bitcnt = (int) DIGIT_BIT;
    156     }
    157 
    158     /* grab the next msb from the exponent */
    159     y     = (buf >> (mp_digit)(DIGIT_BIT - 1)) & 1;
    160     buf <<= (mp_digit)1;
    161 
    162     /* if the bit is zero and mode == 0 then we ignore it
    163      * These represent the leading zero bits before the first 1 bit
    164      * in the exponent.  Technically this opt is not required but it
    165      * does lower the # of trivial squaring/reductions used
    166      */
    167     if (mode == 0 && y == 0) {
    168       continue;
    169     }
    170 
    171     /* if the bit is zero and mode == 1 then we square */
    172     if (mode == 1 && y == 0) {
    173       if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
    174         goto LBL_RES;
    175       }
    176       if ((err = redux (&res, P, &mu)) != MP_OKAY) {
    177         goto LBL_RES;
    178       }
    179       continue;
    180     }
    181 
    182     /* else we add it to the window */
    183     bitbuf |= (y << (winsize - ++bitcpy));
    184     mode    = 2;
    185 
    186     if (bitcpy == winsize) {
    187       /* ok window is filled so square as required and multiply  */
    188       /* square first */
    189       for (x = 0; x < winsize; x++) {
    190         if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
    191           goto LBL_RES;
    192         }
    193         if ((err = redux (&res, P, &mu)) != MP_OKAY) {
    194           goto LBL_RES;
    195         }
    196       }
    197 
    198       /* then multiply */
    199       if ((err = mp_mul (&res, &M[bitbuf], &res)) != MP_OKAY) {
    200         goto LBL_RES;
    201       }
    202       if ((err = redux (&res, P, &mu)) != MP_OKAY) {
    203         goto LBL_RES;
    204       }
    205 
    206       /* empty window and reset */
    207       bitcpy = 0;
    208       bitbuf = 0;
    209       mode   = 1;
    210     }
    211   }
    212 
    213   /* if bits remain then square/multiply */
    214   if (mode == 2 && bitcpy > 0) {
    215     /* square then multiply if the bit is set */
    216     for (x = 0; x < bitcpy; x++) {
    217       if ((err = mp_sqr (&res, &res)) != MP_OKAY) {
    218         goto LBL_RES;
    219       }
    220       if ((err = redux (&res, P, &mu)) != MP_OKAY) {
    221         goto LBL_RES;
    222       }
    223 
    224       bitbuf <<= 1;
    225       if ((bitbuf & (1 << winsize)) != 0) {
    226         /* then multiply */
    227         if ((err = mp_mul (&res, &M[1], &res)) != MP_OKAY) {
    228           goto LBL_RES;
    229         }
    230         if ((err = redux (&res, P, &mu)) != MP_OKAY) {
    231           goto LBL_RES;
    232         }
    233       }
    234     }
    235   }
    236 
    237   mp_exch (&res, Y);
    238   err = MP_OKAY;
    239 LBL_RES:mp_clear (&res);
    240 LBL_MU:mp_clear (&mu);
    241 LBL_M:
    242   mp_clear(&M[1]);
    243   for (x = 1<<(winsize-1); x < (1 << winsize); x++) {
    244     mp_clear (&M[x]);
    245   }
    246   return err;
    247 }
    248 #endif
    249 
    250 /* $Source: /cvs/libtom/libtommath/bn_s_mp_exptmod.c,v $ */
    251 /* $Revision: 1.4 $ */
    252 /* $Date: 2006/03/31 14:18:44 $ */
    253