Home | History | Annotate | Download | only in libtommath
      1 #include <tommath.h>
      2 #ifdef BN_MP_N_ROOT_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 /* find the n'th root of an integer
     19  *
     20  * Result found such that (c)**b <= a and (c+1)**b > a
     21  *
     22  * This algorithm uses Newton's approximation
     23  * x[i+1] = x[i] - f(x[i])/f'(x[i])
     24  * which will find the root in log(N) time where
     25  * each step involves a fair bit.  This is not meant to
     26  * find huge roots [square and cube, etc].
     27  */
     28 int mp_n_root (mp_int * a, mp_digit b, mp_int * c)
     29 {
     30   mp_int  t1, t2, t3;
     31   int     res, neg;
     32 
     33   /* input must be positive if b is even */
     34   if ((b & 1) == 0 && a->sign == MP_NEG) {
     35     return MP_VAL;
     36   }
     37 
     38   if ((res = mp_init (&t1)) != MP_OKAY) {
     39     return res;
     40   }
     41 
     42   if ((res = mp_init (&t2)) != MP_OKAY) {
     43     goto LBL_T1;
     44   }
     45 
     46   if ((res = mp_init (&t3)) != MP_OKAY) {
     47     goto LBL_T2;
     48   }
     49 
     50   /* if a is negative fudge the sign but keep track */
     51   neg     = a->sign;
     52   a->sign = MP_ZPOS;
     53 
     54   /* t2 = 2 */
     55   mp_set (&t2, 2);
     56 
     57   do {
     58     /* t1 = t2 */
     59     if ((res = mp_copy (&t2, &t1)) != MP_OKAY) {
     60       goto LBL_T3;
     61     }
     62 
     63     /* t2 = t1 - ((t1**b - a) / (b * t1**(b-1))) */
     64 
     65     /* t3 = t1**(b-1) */
     66     if ((res = mp_expt_d (&t1, b - 1, &t3)) != MP_OKAY) {
     67       goto LBL_T3;
     68     }
     69 
     70     /* numerator */
     71     /* t2 = t1**b */
     72     if ((res = mp_mul (&t3, &t1, &t2)) != MP_OKAY) {
     73       goto LBL_T3;
     74     }
     75 
     76     /* t2 = t1**b - a */
     77     if ((res = mp_sub (&t2, a, &t2)) != MP_OKAY) {
     78       goto LBL_T3;
     79     }
     80 
     81     /* denominator */
     82     /* t3 = t1**(b-1) * b  */
     83     if ((res = mp_mul_d (&t3, b, &t3)) != MP_OKAY) {
     84       goto LBL_T3;
     85     }
     86 
     87     /* t3 = (t1**b - a)/(b * t1**(b-1)) */
     88     if ((res = mp_div (&t2, &t3, &t3, NULL)) != MP_OKAY) {
     89       goto LBL_T3;
     90     }
     91 
     92     if ((res = mp_sub (&t1, &t3, &t2)) != MP_OKAY) {
     93       goto LBL_T3;
     94     }
     95   }  while (mp_cmp (&t1, &t2) != MP_EQ);
     96 
     97   /* result can be off by a few so check */
     98   for (;;) {
     99     if ((res = mp_expt_d (&t1, b, &t2)) != MP_OKAY) {
    100       goto LBL_T3;
    101     }
    102 
    103     if (mp_cmp (&t2, a) == MP_GT) {
    104       if ((res = mp_sub_d (&t1, 1, &t1)) != MP_OKAY) {
    105          goto LBL_T3;
    106       }
    107     } else {
    108       break;
    109     }
    110   }
    111 
    112   /* reset the sign of a first */
    113   a->sign = neg;
    114 
    115   /* set the result */
    116   mp_exch (&t1, c);
    117 
    118   /* set the sign of the result */
    119   c->sign = neg;
    120 
    121   res = MP_OKAY;
    122 
    123 LBL_T3:mp_clear (&t3);
    124 LBL_T2:mp_clear (&t2);
    125 LBL_T1:mp_clear (&t1);
    126   return res;
    127 }
    128 #endif
    129 
    130 /* $Source: /cvs/libtom/libtommath/bn_mp_n_root.c,v $ */
    131 /* $Revision: 1.3 $ */
    132 /* $Date: 2006/03/31 14:18:44 $ */
    133