/* multiplies |a| * |b| and does not compute the lower digs digits
 * [meant to get the higher part of the product]
 */
int
s_mp_mul_high_digs(mp_int *a, mp_int *b, mp_int *c, int digs) {
    mp_int   t;
    int      res, pa, pb, ix, iy;
    mp_digit u;
    mp_word  r;
    mp_digit tmpx, *tmpt, *tmpy;

    /* can we use the fast multiplier? */
#ifdef BN_FAST_S_MP_MUL_HIGH_DIGS_C
    if (((a->used + b->used + 1) < MP_WARRAY) &&
            (MIN(a->used, b->used) < (1 << ((CHAR_BIT * sizeof(mp_word)) - (2 * DIGIT_BIT))))) {
        return fast_s_mp_mul_high_digs(a, b, c, digs);
    }
#endif

    if ((res = mp_init_size(&t, a->used + b->used + 1)) != MP_OKAY) {
        return res;
    }
    t.used = a->used + b->used + 1;

    pa = a->used;
    pb = b->used;
    for (ix = 0; ix < pa; ix++) {
        /* clear the carry */
        u = 0;

        /* left hand side of A[ix] * B[iy] */
        tmpx = a->dp[ix];

        /* alias to the address of where the digits will be stored */
        tmpt = &(t.dp[digs]);

        /* alias for where to read the right hand side from */
        tmpy = b->dp + (digs - ix);

        for (iy = digs - ix; iy < pb; iy++) {
            /* calculate the double precision result */
            r = (mp_word) * tmpt +
                ((mp_word)tmpx * (mp_word) * tmpy++) +
                (mp_word)u;

            /* get the lower part */
            *tmpt++ = (mp_digit)(r & ((mp_word)MP_MASK));

            /* carry the carry */
            u = (mp_digit)(r >> ((mp_word)DIGIT_BIT));
        }
        *tmpt = u;
    }
    mp_clamp(&t);
    mp_exch(&t, c);
    mp_clear(&t);
    return MP_OKAY;
}
Esempio n. 2
0
/* reduces x mod m, assumes 0 < x < m**2, mu is 
 * precomputed via mp_reduce_setup.
 * From HAC pp.604 Algorithm 14.42
 */
int mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
{
  mp_int  q;
  int     res, um = USED(m);

  /* q = x */
  if ((res = mp_init_copy (&q, x)) != MP_OKAY) {
    return res;
  }

  /* q1 = x / b**(k-1)  */
  mp_rshd (&q, um - 1);         

  /* according to HAC this optimization is ok */
  if (((unsigned long) um) > (((mp_digit)1) << (DIGIT_BIT - 1))) {
    if ((res = mp_mul (&q, mu, &q)) != MP_OKAY) {
      goto CLEANUP;
    }
  } else {
#ifdef BN_S_MP_MUL_HIGH_DIGS_C
    if ((res = s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
      goto CLEANUP;
    }
#elif defined(BN_FAST_S_MP_MUL_HIGH_DIGS_C)
    if ((res = fast_s_mp_mul_high_digs (&q, mu, &q, um)) != MP_OKAY) {
      goto CLEANUP;
    }
#else 
    { 
      res = MP_VAL;
      goto CLEANUP;
    }
#endif
  }

  /* q3 = q2 / b**(k+1) */
  mp_rshd (&q, um + 1);         

  /* x = x mod b**(k+1), quick (no division) */
  if ((res = mp_mod_2d (x, DIGIT_BIT * (um + 1), x)) != MP_OKAY) {
    goto CLEANUP;
  }

  /* q = q * m mod b**(k+1), quick (no division) */
  if ((res = s_mp_mul_digs (&q, m, &q, um + 1)) != MP_OKAY) {
    goto CLEANUP;
  }

  /* x = x - q */
  if ((res = mp_sub (x, &q, x)) != MP_OKAY) {
    goto CLEANUP;
  }

  /* If x < 0, add b**(k+1) to it */
  if (mp_cmp_d (x, 0) == MP_LT) {
    mp_set (&q, 1);
    if ((res = mp_lshd (&q, um + 1)) != MP_OKAY)
      goto CLEANUP;
    if ((res = mp_add (x, &q, x)) != MP_OKAY)
      goto CLEANUP;
  }

  /* Back off if it's too big */
  while (mp_cmp (x, m) != MP_LT) {
    if ((res = s_mp_sub (x, m, x)) != MP_OKAY) {
      goto CLEANUP;
    }
  }
  
CLEANUP:
  mp_clear (&q);

  return res;
}