Edit

kc3-lang/libtommath/bn_mp_montgomery_reduce.c

Branch :

  • Show log

    Commit

  • Author : Tom St Denis
    Date : 2004-10-29 22:07:18
    Hash : e549ccfe
    Message : added libtommath-0.32

  • bn_mp_montgomery_reduce.c
  • #include <tommath.h>
    #ifdef BN_MP_MONTGOMERY_REDUCE_C
    /* LibTomMath, multiple-precision integer library -- Tom St Denis
     *
     * LibTomMath is a library that provides multiple-precision
     * integer arithmetic as well as number theoretic functionality.
     *
     * The library was designed directly after the MPI library by
     * Michael Fromberger but has been written from scratch with
     * additional optimizations in place.
     *
     * The library is free for all purposes without any express
     * guarantee it works.
     *
     * Tom St Denis, tomstdenis@iahu.ca, http://math.libtomcrypt.org
     */
    
    /* computes xR**-1 == x (mod N) via Montgomery Reduction */
    int
    mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
    {
      int     ix, res, digs;
      mp_digit mu;
    
      /* can the fast reduction [comba] method be used?
       *
       * Note that unlike in mul you're safely allowed *less*
       * than the available columns [255 per default] since carries
       * are fixed up in the inner loop.
       */
      digs = n->used * 2 + 1;
      if ((digs < MP_WARRAY) &&
          n->used <
          (1 << ((CHAR_BIT * sizeof (mp_word)) - (2 * DIGIT_BIT)))) {
        return fast_mp_montgomery_reduce (x, n, rho);
      }
    
      /* grow the input as required */
      if (x->alloc < digs) {
        if ((res = mp_grow (x, digs)) != MP_OKAY) {
          return res;
        }
      }
      x->used = digs;
    
      for (ix = 0; ix < n->used; ix++) {
        /* mu = ai * rho mod b
         *
         * The value of rho must be precalculated via
         * montgomery_setup() such that
         * it equals -1/n0 mod b this allows the
         * following inner loop to reduce the
         * input one digit at a time
         */
        mu = (mp_digit) (((mp_word)x->dp[ix]) * ((mp_word)rho) & MP_MASK);
    
        /* a = a + mu * m * b**i */
        {
          register int iy;
          register mp_digit *tmpn, *tmpx, u;
          register mp_word r;
    
          /* alias for digits of the modulus */
          tmpn = n->dp;
    
          /* alias for the digits of x [the input] */
          tmpx = x->dp + ix;
    
          /* set the carry to zero */
          u = 0;
    
          /* Multiply and add in place */
          for (iy = 0; iy < n->used; iy++) {
            /* compute product and sum */
            r       = ((mp_word)mu) * ((mp_word)*tmpn++) +
                      ((mp_word) u) + ((mp_word) * tmpx);
    
            /* get carry */
            u       = (mp_digit)(r >> ((mp_word) DIGIT_BIT));
    
            /* fix digit */
            *tmpx++ = (mp_digit)(r & ((mp_word) MP_MASK));
          }
          /* At this point the ix'th digit of x should be zero */
    
    
          /* propagate carries upwards as required*/
          while (u) {
            *tmpx   += u;
            u        = *tmpx >> DIGIT_BIT;
            *tmpx++ &= MP_MASK;
          }
        }
      }
    
      /* at this point the n.used'th least
       * significant digits of x are all zero
       * which means we can shift x to the
       * right by n.used digits and the
       * residue is unchanged.
       */
    
      /* x = x/b**n.used */
      mp_clamp(x);
      mp_rshd (x, n->used);
    
      /* if x >= n then x = x - n */
      if (mp_cmp_mag (x, n) != MP_LT) {
        return s_mp_sub (x, n, x);
      }
    
      return MP_OKAY;
    }
    #endif