Home | History | Annotate | Download | only in libtommath
      1 #include <tommath.h>
      2 #ifdef BN_MP_REDUCE_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 
     18 /* reduces x mod m, assumes 0 < x < m**2, mu is
     19  * precomputed via mp_reduce_setup.
     20  * From HAC pp.604 Algorithm 14.42
     21  */
     22 int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
     23 {
     24   mp_int  q;
     25   int     res, um = m->used;
     26 
     27   /* q = x */
     28   if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
     29     return res;
     30   }
     31 
     32   /* q1 = x / b**(k-1)  */
     33   mp_rshd (&q, um - 1);
     34 
     35   /* according to HAC this optimization is ok */
     36   if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
     37     if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
     38       goto CLEANUP;
     39     }
     40   } else {
     41 #ifdef BN_S_MP_MUL_HIGH_DIGS_C
     42     if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
     43       goto CLEANUP;
     44     }
     45 #elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
     46     if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
     47       goto CLEANUP;
     48     }
     49 #else
     50     {
     51       res = MP_VAL;
     52       goto CLEANUP;
     53     }
     54 #endif
     55   }
     56 
     57   /* q3 = q2 / b**(k+1) */
     58   mp_rshd (&q, um + 1);
     59 
     60   /* x = x mod b**(k+1), quick (no division) */
     61   if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
     62     goto CLEANUP;
     63   }
     64 
     65   /* q = q * m mod b**(k+1), quick (no division) */
     66   if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
     67     goto CLEANUP;
     68   }
     69 
     70   /* x = x - q */
     71   if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
     72     goto CLEANUP;
     73   }
     74 
     75   /* If x < 0, add b**(k+1) to it */
     76   if (mp_cmp_d (x, 0) == MP_LT) {
     77     mp_set (&q, 1);
     78     if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
     79       goto CLEANUP;
     80     if ((res = mp_add (x, &q, x)) != MP_OKAY)
     81       goto CLEANUP;
     82   }
     83 
     84   /* Back off if it's too big */
     85   while (mp_cmp (x, m) != MP_LT) {
     86     if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
     87       goto CLEANUP;
     88     }
     89   }
     90 
     91 CLEANUP:
     92   mp_clear (&q);
     93 
     94   return res;
     95 }
     96 #endif
     97 
     98 /* $Source: /cvs/libtom/libtommath/bn_mp_reduce.c,v $ */
     99 /* $Revision: 1.3 $ */
    100 /* $Date: 2006/03/31 14:18:44 $ */
    101