1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
/* LibTomMath, multiple-precision integer library -- Tom St Denis
*
* LibTomMath is library that provides for multiple-precision
* integer arithmetic as well as number theoretic functionality.
*
* The library is 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
*/
#include <tommath.h>
/* reduce "a" in place modulo "b" using the Diminished Radix algorithm.
*
* Based on algorithm from the paper
*
* "Generating Efficient Primes for Discrete Log Cryptosystems"
* Chae Hoon Lim, Pil Loong Lee,
* POSTECH Information Research Laboratories
*
* The modulus must be of a special format [see manual]
*/
int
mp_dr_reduce (mp_int * a, mp_int * b, mp_digit mp)
{
int err, i, j, k;
mp_word r;
mp_digit mu, *tmpj, *tmpi;
/* k = digits in modulus */
k = b->used;
/* ensure that "a" has at least 2k digits */
if (a->alloc < k + k) {
if ((err = mp_grow (a, k + k)) != MP_OKAY) {
return err;
}
}
/* alias for a->dp[i] */
tmpi = a->dp + k + k - 1;
/* for (i = 2k - 1; i >= k; i = i - 1)
*
* This is the main loop of the reduction. Note that at the end
* the words above position k are not zeroed as expected. The end
* result is that the digits from 0 to k-1 are the residue. So
* we have to clear those afterwards.
*/
for (i = k + k - 1; i >= k; i = i - 1) {
/* x[i - 1 : i - k] += x[i]*mp */
/* x[i] * mp */
r = ((mp_word) *tmpi--) * ((mp_word) mp);
/* now add r to x[i-1:i-k]
*
* First add it to the first digit x[i-k] then form the carry
* then enter the main loop
*/
j = i - k;
/* alias for a->dp[j] */
tmpj = a->dp + j;
/* add digit */
*tmpj += (mp_digit)(r & MP_MASK);
/* this is the carry */
mu = (r >> ((mp_word) DIGIT_BIT)) + (*tmpj >> DIGIT_BIT);
/* clear carry from a->dp[j] */
*tmpj++ &= MP_MASK;
/* now add rest of the digits
*
* Note this is basically a simple single digit addition to
* a larger multiple digit number. This is optimized somewhat
* because the propagation of carries is not likely to move
* more than a few digits.
*
*/
for (++j; mu != 0 && j <= (i - 1); ++j) {
*tmpj += mu;
mu = *tmpj >> DIGIT_BIT;
*tmpj++ &= MP_MASK;
}
/* if final carry */
if (mu != 0) {
/* add mp to this to correct */
j = i - k;
tmpj = a->dp + j;
*tmpj += mp;
mu = *tmpj >> DIGIT_BIT;
*tmpj++ &= MP_MASK;
/* now handle carries */
for (++j; mu != 0 && j <= (i - 1); j++) {
*tmpj += mu;
mu = *tmpj >> DIGIT_BIT;
*tmpj++ &= MP_MASK;
}
}
}
/* zero words above k */
tmpi = a->dp + k;
for (i = k; i < a->used; i++) {
*tmpi++ = 0;
}
/* clamp, sub and return */
mp_clamp (a);
if (mp_cmp_mag (a, b) != MP_LT) {
return s_mp_sub (a, b, a);
}
return MP_OKAY;
}
/* determines if a number is a valid DR modulus */
int mp_dr_is_modulus(mp_int *a)
{
int ix;
/* must be at least two digits */
if (a->used < 2) {
return 0;
}
for (ix = 1; ix < a->used; ix++) {
if (a->dp[ix] != MP_MASK) {
return 0;
}
}
return 1;
}
/* determines the setup value */
void mp_dr_setup(mp_int *a, mp_digit *d)
{
*d = (1 << DIGIT_BIT) - a->dp[0];
}