📄 mpi.c
字号:
/* }}} */
/*========================================================================*/
/*------------------------------------------------------------------------*/
/* Static function definitions (internal use only) */
/* {{{ Memory management */
/* {{{ s_mp_grow(mp, min) */
/* Make sure there are at least 'min' digits allocated to mp */
mp_err s_mp_grow(mp_int *mp, mp_size min)
{
if(min > ALLOC(mp)) {
mp_digit *tmp;
/* Set min to next nearest default precision block size */
min = ((min + (s_mp_defprec - 1)) / s_mp_defprec) * s_mp_defprec;
if((tmp = s_mp_alloc(min, sizeof(mp_digit))) == NULL)
return MP_MEM;
s_mp_copy(DIGITS(mp), tmp, USED(mp));
#if MP_CRYPTO
s_mp_setz(DIGITS(mp), ALLOC(mp));
#endif
s_mp_free(DIGITS(mp));
DIGITS(mp) = tmp;
ALLOC(mp) = min;
}
return MP_OKAY;
} /* end s_mp_grow() */
/* }}} */
/* {{{ s_mp_pad(mp, min) */
/* Make sure the used size of mp is at least 'min', growing if needed */
mp_err s_mp_pad(mp_int *mp, mp_size min)
{
if(min > USED(mp)) {
mp_err res;
/* Make sure there is room to increase precision */
if(min > ALLOC(mp) && (res = s_mp_grow(mp, min)) != MP_OKAY)
return res;
/* Increase precision; should already be 0-filled */
USED(mp) = min;
}
return MP_OKAY;
} /* end s_mp_pad() */
/* }}} */
/* {{{ s_mp_setz(dp, count) */
#if MP_MACRO == 0
/* Set 'count' digits pointed to by dp to be zeroes */
void s_mp_setz(mp_digit *dp, mp_size count)
{
#if MP_MEMSET == 0
int ix;
for(ix = 0; ix < count; ix++)
dp[ix] = 0;
#else
memset(dp, 0, count * sizeof(mp_digit));
#endif
} /* end s_mp_setz() */
#endif
/* }}} */
/* {{{ s_mp_copy(sp, dp, count) */
#if MP_MACRO == 0
/* Copy 'count' digits from sp to dp */
void s_mp_copy(mp_digit *sp, mp_digit *dp, mp_size count)
{
#if MP_MEMCPY == 0
int ix;
for(ix = 0; ix < count; ix++)
dp[ix] = sp[ix];
#else
memcpy(dp, sp, count * sizeof(mp_digit));
#endif
} /* end s_mp_copy() */
#endif
/* }}} */
/* {{{ s_mp_alloc(nb, ni) */
#if MP_MACRO == 0
/* Allocate ni records of nb bytes each, and return a pointer to that */
void *s_mp_alloc(size_t nb, size_t ni)
{
return calloc(nb, ni);
} /* end s_mp_alloc() */
#endif
/* }}} */
/* {{{ s_mp_free(ptr) */
#if MP_MACRO == 0
/* Free the memory pointed to by ptr */
void s_mp_free(void *ptr)
{
if(ptr)
free(ptr);
} /* end s_mp_free() */
#endif
/* }}} */
/* {{{ s_mp_clamp(mp) */
/* Remove leading zeroes from the given value */
void s_mp_clamp(mp_int *mp)
{
mp_size du = USED(mp);
mp_digit *zp = DIGITS(mp) + du - 1;
while(du > 1 && !*zp--)
--du;
USED(mp) = du;
} /* end s_mp_clamp() */
/* }}} */
/* {{{ s_mp_exch(a, b) */
/* Exchange the data for a and b; (b, a) = (a, b) */
void s_mp_exch(mp_int *a, mp_int *b)
{
mp_int tmp;
tmp = *a;
*a = *b;
*b = tmp;
} /* end s_mp_exch() */
/* }}} */
/* }}} */
/* {{{ Arithmetic helpers */
/* {{{ s_mp_lshd(mp, p) */
/*
Shift mp leftward by p digits, growing if needed, and zero-filling
the in-shifted digits at the right end. This is a convenient
alternative to multiplication by powers of the radix
*/
mp_err s_mp_lshd(mp_int *mp, mp_size p)
{
mp_err res;
mp_size pos;
mp_digit *dp;
int ix;
if(p == 0)
return MP_OKAY;
if((res = s_mp_pad(mp, USED(mp) + p)) != MP_OKAY)
return res;
pos = USED(mp) - 1;
dp = DIGITS(mp);
/* Shift all the significant figures over as needed */
for(ix = pos - p; ix >= 0; ix--)
dp[ix + p] = dp[ix];
/* Fill the bottom digits with zeroes */
for(ix = 0; ix < p; ix++)
dp[ix] = 0;
return MP_OKAY;
} /* end s_mp_lshd() */
/* }}} */
/* {{{ s_mp_rshd(mp, p) */
/*
Shift mp rightward by p digits. Maintains the invariant that
digits above the precision are all zero. Digits shifted off the
end are lost. Cannot fail.
*/
void s_mp_rshd(mp_int *mp, mp_size p)
{
mp_size ix;
mp_digit *dp;
if(p == 0)
return;
/* Shortcut when all digits are to be shifted off */
if(p >= USED(mp)) {
s_mp_setz(DIGITS(mp), ALLOC(mp));
USED(mp) = 1;
SIGN(mp) = MP_ZPOS;
return;
}
/* Shift all the significant figures over as needed */
dp = DIGITS(mp);
for(ix = p; ix < USED(mp); ix++)
dp[ix - p] = dp[ix];
/* Fill the top digits with zeroes */
ix -= p;
while(ix < USED(mp))
dp[ix++] = 0;
/* Strip off any leading zeroes */
s_mp_clamp(mp);
} /* end s_mp_rshd() */
/* }}} */
/* {{{ s_mp_div_2(mp) */
/* Divide by two -- take advantage of radix properties to do it fast */
void s_mp_div_2(mp_int *mp)
{
s_mp_div_2d(mp, 1);
} /* end s_mp_div_2() */
/* }}} */
/* {{{ s_mp_mul_2(mp) */
mp_err s_mp_mul_2(mp_int *mp)
{
mp_size ix;
mp_digit kin = 0, kout, *dp = DIGITS(mp);
mp_err res;
/* Shift digits leftward by 1 bit */
for(ix = 0; ix < USED(mp); ix++) {
kout = (dp[ix] >> (DIGIT_BIT - 1)) & 1;
dp[ix] = (dp[ix] << 1) | kin;
kin = kout;
}
/* Deal with rollover from last digit */
if(kin) {
if(ix >= ALLOC(mp)) {
if((res = s_mp_grow(mp, ALLOC(mp) + 1)) != MP_OKAY)
return res;
dp = DIGITS(mp);
}
dp[ix] = kin;
USED(mp) += 1;
}
return MP_OKAY;
} /* end s_mp_mul_2() */
/* }}} */
/* {{{ s_mp_mod_2d(mp, d) */
/*
Remainder the integer by 2^d, where d is a number of bits. This
amounts to a bitwise AND of the value, and does not require the full
division code
*/
void s_mp_mod_2d(mp_int *mp, mp_digit d)
{
unsigned int ndig = (d / DIGIT_BIT), nbit = (d % DIGIT_BIT);
unsigned int ix;
mp_digit dmask, *dp = DIGITS(mp);
if(ndig >= USED(mp))
return;
/* Flush all the bits above 2^d in its digit */
dmask = (1 << nbit) - 1;
dp[ndig] &= dmask;
/* Flush all digits above the one with 2^d in it */
for(ix = ndig + 1; ix < USED(mp); ix++)
dp[ix] = 0;
s_mp_clamp(mp);
} /* end s_mp_mod_2d() */
/* }}} */
/* {{{ s_mp_mul_2d(mp, d) */
/*
Multiply by the integer 2^d, where d is a number of bits. This
amounts to a bitwise shift of the value, and does not require the
full multiplication code.
*/
mp_err s_mp_mul_2d(mp_int *mp, mp_digit d)
{
mp_err res;
mp_digit save, next, mask, *dp;
mp_size used;
mp_size ix;
if((res = s_mp_lshd(mp, d / DIGIT_BIT)) != MP_OKAY)
return res;
dp = DIGITS(mp); used = USED(mp);
d %= DIGIT_BIT;
mask = (1 << d) - 1;
/* If the shift requires another digit, make sure we've got one to
work with */
if((dp[used - 1] >> (DIGIT_BIT - d)) & mask) {
if((res = s_mp_grow(mp, used + 1)) != MP_OKAY)
return res;
dp = DIGITS(mp);
}
/* Do the shifting... */
save = 0;
for(ix = 0; ix < used; ix++) {
next = (dp[ix] >> (DIGIT_BIT - d)) & mask;
dp[ix] = (dp[ix] << d) | save;
save = next;
}
/* If, at this point, we have a nonzero carryout into the next
digit, we'll increase the size by one digit, and store it...
*/
if(save) {
dp[used] = save;
USED(mp) += 1;
}
s_mp_clamp(mp);
return MP_OKAY;
} /* end s_mp_mul_2d() */
/* }}} */
/* {{{ s_mp_div_2d(mp, d) */
/*
Divide the integer by 2^d, where d is a number of bits. This
amounts to a bitwise shift of the value, and does not require the
full division code (used in Barrett reduction, see below)
*/
void s_mp_div_2d(mp_int *mp, mp_digit d)
{
int ix;
mp_digit save, next, mask, *dp = DIGITS(mp);
s_mp_rshd(mp, d / DIGIT_BIT);
d %= DIGIT_BIT;
mask = (1 << d) - 1;
save = 0;
for(ix = USED(mp) - 1; ix >= 0; ix--) {
next = dp[ix] & mask;
dp[ix] = (dp[ix] >> d) | (save << (DIGIT_BIT - d));
save = next;
}
s_mp_clamp(mp);
} /* end s_mp_div_2d() */
/* }}} */
/* {{{ s_mp_norm(a, b) */
/*
s_mp_norm(a, b)
Normalize a and b for division, where b is the divisor. In order
that we might make good guesses for quotient digits, we want the
leading digit of b to be at least half the radix, which we
accomplish by multiplying a and b by a constant. This constant is
returned (so that it can be divided back out of the remainder at the
end of the division process).
We multiply by the smallest power of 2 that gives us a leading digit
at least half the radix. By choosing a power of 2, we simplify the
multiplication and division steps to simple shifts.
*/
mp_digit s_mp_norm(mp_int *a, mp_int *b)
{
mp_digit t, d = 0;
t = DIGIT(b, USED(b) - 1);
while(t < (RADIX / 2)) {
t <<= 1;
++d;
}
if(d != 0) {
s_mp_mul_2d(a, d);
s_mp_mul_2d(b, d);
}
return d;
} /* end s_mp_norm() */
/* }}} */
/* }}} */
/* {{{ Primitive digit arithmetic */
/* {{{ s_mp_add_d(mp, d) */
/* Add d to |mp| in place */
mp_err s_mp_add_d(mp_int *mp, mp_digit d) /* unsigned digit addition */
{
mp_word w, k = 0;
mp_size ix = 1, used = USED(mp);
mp_digit *dp = DIGITS(mp);
w = dp[0] + d;
dp[0] = ACCUM(w);
k = CARRYOUT(w);
while(ix < used && k) {
w = dp[ix] + k;
dp[ix] = ACCUM(w);
k = CARRYOUT(w);
++ix;
}
if(k != 0) {
mp_err res;
if((res = s_mp_pad(mp, USED(mp) + 1)) != MP_OKAY)
return res;
DIGIT(mp, ix) = k;
}
return MP_OKAY;
} /* end s_mp_add_d() */
/* }}} */
/* {{{ s_mp_sub_d(mp, d) */
/* Subtract d from |mp| in place, assumes |mp| > d */
mp_err s_mp_sub_d(mp_int *mp, mp_digit d) /* unsigned digit subtract */
{
mp_word w, b = 0;
mp_size ix = 1, used = USED(mp);
mp_digit *dp = DIGITS(mp);
/* Compute initial subtraction */
w = (RADIX + dp[0]) - d;
b = CARRYOUT(w) ? 0 : 1;
dp[0] = ACCUM(w);
/* Propagate borrows leftward */
while(b && ix < used) {
w = (RADIX + dp[ix]) - b;
b = CARRYOUT(w) ? 0 : 1;
dp[ix] = ACCUM(w);
++ix;
}
/* Remove leading zeroes */
s_mp_clamp(mp);
/* If we have a borrow out, it's a violation of the input invariant */
if(b)
return MP_RANGE;
else
return MP_OKAY;
} /* end s_mp_sub_d() */
/* }}} */
/* {{{ s_mp_mul_d(a, d) */
/* Compute a = a * d, single digit multiplication */
mp_err s_mp_mul_d(mp_int *a, mp_digit d)
{
mp_word w, k = 0;
mp_size ix, max;
mp_err res;
mp_digit *dp = DIGITS(a);
/*
Single-digit multiplication will increase the precision of the
output by at most one digit. However, we can detect when this
will happen -- if the high-order digit of a, times d, gives a
two-digit result, then the precision of the result will increase;
otherwise it won't. We use this fact to avoid calling s_mp_pad()
unless absolutely necessary.
*/
max = USED(a);
w = dp[max - 1] * d;
if(CARRYOUT(w) != 0) {
if((res = s_mp_pad(a, max + 1)) != MP_OKAY)
return res;
dp = DIGITS(a);
}
for(ix = 0; ix < max; ix++) {
w = (dp[ix] * d) + k;
dp[ix] = ACCUM(w);
k = CARRYOUT(w);
}
/* If there is a precision increase, take care of it here; the above
test guarantees we have enough storage to do this safely.
*/
if(k) {
dp[max] = k;
USED(a) = max + 1;
}
s_mp_clamp(a);
return MP_OKAY;
} /* end s_mp_mul_d() */
/* }}} */
/* {{{ s_mp_div_d(mp, d, r) */
/*
s_mp_div_d(mp, d, r)
Compute the quotient mp = mp / d and remainder r = mp mod d, for a
single digit d. If r is null, the remainder will be discarded.
*/
mp_err s_mp_div_d(mp_int *mp, mp_digit d, mp_digit *r)
{
mp_word w = 0, t;
mp_int quot;
mp_err res;
mp_digit *dp = DIGITS(mp), *qp;
int ix;
if(d == 0)
return MP_RANGE;
/* Make room for the quotient */
if((res = mp_init_size(", USED(mp))) != MP_OKAY)
return res;
USED(") = USED(mp); /* so clamping will work below */
qp = DIGITS(");
/* Divide without subtraction */
for(ix = USED(mp) - 1; ix >= 0; ix--) {
w = (w << DIGIT_BIT) | dp[ix];
if(w >= d) {
t = w / d;
w = w % d;
} else {
t = 0;
}
qp[ix] = t;
}
/* Deliver the remainder, if desired */
if(r)
*r = w;
s_mp_clamp(");
mp_exch(", mp);
mp_clear(");
return MP_OKAY;
} /* end s_mp_div_d() */
/* }}} */
/* }}} */
/* {{{ Primitive full arithmetic */
/* {{{ s_mp_add(a, b) */
/* Compute a = |a| + |b|
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -