Codebase list libcryptx-perl / upstream/0.076 src / ltm / bn_mp_reduce.c
upstream/0.076

Tree @upstream/0.076 (Download .tar.gz)

bn_mp_reduce.c @upstream/0.076

7dcfba3
be43106
b7f589b
 
 
 
 
 
 
 
 
 
 
be43106
9bac49a
be43106
 
 
b7f589b
be43106
a7d3482
b7f589b
be43106
a7d3482
b7f589b
 
a7d3482
be43106
a7d3482
 
be43106
a7d3482
b7f589b
 
a7d3482
 
 
be43106
b7f589b
a7d3482
 
b7f589b
 
a7d3482
 
9bac49a
a7d3482
b7f589b
a7d3482
 
be43106
a7d3482
be43106
a7d3482
 
be43106
a7d3482
b7f589b
be43106
a7d3482
 
 
b7f589b
be43106
a7d3482
be43106
a7d3482
b7f589b
be43106
a7d3482
 
 
 
 
b7f589b
a7d3482
b7f589b
a7d3482
 
 
 
 
b7f589b
a7d3482
 
 
9bac49a
be43106
a7d3482
be43106
b7f589b
be43106
 
b7f589b
 
 
 
#include "tommath_private.h"
#ifdef BN_MP_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.
 *
 * SPDX-License-Identifier: Unlicense
 */

/* 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, const mp_int *m, const mp_int *mu)
{
   mp_int  q;
   int     res, um = m->used;

   /* 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 ((mp_digit)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, 0uL) == MP_LT) {
      mp_set(&q, 1uL);
      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;
}
#endif

/* ref:         $Format:%D$ */
/* git commit:  $Format:%H$ */
/* commit time: $Format:%ai$ */