/* mplogic.c
*
* by Michael J. Fromberger
* Developed 1998-2004.
* Assigned to the public domain as of 2002; see README.
*
* Bitwise logical operations on MPI values
*
* $Id: mplogic.c,v 1.1 2004/02/08 04:29:29 sting Exp $
*/
#include
#include "config.h"
#include "mplogic.h"
#if MP_ARGCHK == 2
#include
#endif
#ifdef __cplusplus
#define convert(TYPE, EXPR) (static_cast(EXPR))
#else
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#endif
#if MP_ARGCHK == 1
#define ARGCHK(X,Y) {if (!(X)){return (Y);}}
#elif MP_ARGCHK == 2
#define ARGCHK(X,Y) assert(X)
#else
#define ARGCHK(X,Y)
#endif
#define DIGIT_BIT MP_DIGIT_BIT
#define DIGIT_MAX MP_DIGIT_MAX
/* Some things from the guts of the MPI library we make use of... */
extern mp_err s_mp_lshd(mp_int *mp, mp_size p);
extern void s_mp_rshd(mp_int *mp, mp_size p);
#define s_mp_clamp(mp)\
{ while (USED(mp) > 1 && DIGIT((mp), USED(mp) - 1) == 0) USED(mp) -= 1; }
static unsigned char bitc[] = {
0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
};
/* mpl_not(a, b) = b = ~a
* mpl_and(a, b, c) = c = a & b
* mpl_or(a, b, c) = c = a | b
* mpl_xor(a, b, c) = c = a ^ b
*/
mp_err mpl_not(mp_int *a, mp_int *b)
{
mp_err res;
mp_size ix;
ARGCHK(a != NULL && b != NULL, MP_BADARG);
if ((res = mp_copy(a, b)) != MP_OKAY)
return res;
/* This relies on the fact that the digit type is unsigned */
for (ix = 0; ix < USED(b); ix++)
DIGIT(b, ix) = ~DIGIT(b, ix);
s_mp_clamp(b);
return MP_OKAY;
}
mp_err mpl_and(mp_int *a, mp_int *b, mp_int *c)
{
mp_int *which, *other;
mp_err res;
mp_size ix;
ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
if (USED(a) <= USED(b)) {
which = a;
other = b;
} else {
which = b;
other = a;
}
if ((res = mp_copy(which, c)) != MP_OKAY)
return res;
for (ix = 0; ix < USED(which); ix++)
DIGIT(c, ix) &= DIGIT(other, ix);
s_mp_clamp(c);
return MP_OKAY;
}
mp_err mpl_or(mp_int *a, mp_int *b, mp_int *c)
{
mp_int *which, *other;
mp_err res;
mp_size ix;
ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
if (USED(a) >= USED(b)) {
which = a;
other = b;
} else {
which = b;
other = a;
}
if ((res = mp_copy(which, c)) != MP_OKAY)
return res;
for (ix = 0; ix < USED(which); ix++)
DIGIT(c, ix) |= DIGIT(other, ix);
return MP_OKAY;
}
mp_err mpl_xor(mp_int *a, mp_int *b, mp_int *c)
{
mp_int *which, *other;
mp_err res;
mp_size ix;
ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
if (USED(a) >= USED(b)) {
which = a;
other = b;
} else {
which = b;
other = a;
}
if ((res = mp_copy(which, c)) != MP_OKAY)
return res;
for (ix = 0; ix < USED(which); ix++)
DIGIT(c, ix) ^= DIGIT(other, ix);
s_mp_clamp(c);
return MP_OKAY;
}
/* mpl_rsh(a, b, d) = b = a >> d
* mpl_lsh(a, b, d) = b = a << d
*/
mp_err mpl_rsh(mp_int *a, mp_int *b, mp_digit d)
{
mp_err res;
mp_size dshift, bshift;
ARGCHK(a != NULL && b != NULL, MP_BADARG);
dshift = d / DIGIT_BIT; /* How many whole digits to shift by */
bshift = d % DIGIT_BIT; /* How many bits to shift by */
if ((res = mp_copy(a, b)) != MP_OKAY)
return res;
/* Shift over as many whole digits as necessary */
if (dshift)
s_mp_rshd(b, dshift);
/* Now handle any remaining bit shifting */
if (bshift)
{
mp_digit prev = 0, next, mask = (convert(mp_digit, 1) << bshift) - 1;
mp_size ix;
/* 'mask' is a digit with the lower bshift bits set, the rest
* clear. It is used to mask off the bottom bshift bits of each
* digit, which are then shifted on to the top of the next lower
* digit.
*/
for (ix = USED(b) - 1; ix < MP_SIZE_MAX; ix--) {
/* Take off the lower bits and shift them up... */
next = (DIGIT(b, ix) & mask) << (DIGIT_BIT - bshift);
/* Shift down the current digit, and mask in the bits saved
* from the previous digit
*/
DIGIT(b, ix) = (DIGIT(b, ix) >> bshift) | prev;
prev = next;
}
}
s_mp_clamp(b);
return MP_OKAY;
}
mp_err mpl_lsh(mp_int *a, mp_int *b, mp_digit d)
{
mp_err res;
mp_size dshift, bshift;
ARGCHK(a != NULL && b != NULL, MP_BADARG);
dshift = d / DIGIT_BIT;
bshift = d % DIGIT_BIT;
if ((res = mp_copy(a, b)) != MP_OKAY)
return res;
if (dshift)
if ((res = s_mp_lshd(b, dshift)) != MP_OKAY)
return res;
if (bshift) {
mp_size ix;
mp_digit prev = 0, next, mask = (convert(mp_digit, 1) << bshift) - 1;
for (ix = 0; ix < USED(b); ix++) {
next = (DIGIT(b, ix) >> (DIGIT_BIT - bshift)) & mask;
DIGIT(b, ix) = (DIGIT(b, ix) << bshift) | prev;
prev = next;
}
}
s_mp_clamp(b);
return MP_OKAY;
}
/* Count the number of set bits in the binary representation of a.
* Returns MP_OKAY and sets 'num' to be the number of such bits, if
* possible. If num is NULL, the result is thrown away, but it is
* not considered an error.
*
* mpl_num_clear() does basically the same thing for clear bits.
*/
mp_err mpl_num_set(mp_int *a, mp_size *num)
{
mp_size ix, nset = 0;
mp_digit cur;
unsigned char reg;
ARGCHK(a != NULL, MP_BADARG);
for (ix = 0; ix < USED(a); ix++) {
size_t i;
cur = DIGIT(a, ix);
for (i = 0; i < sizeof (mp_digit); i++) {
reg = (cur >> (CHAR_BIT * i)) & UCHAR_MAX;
nset += bitc[reg];
}
}
if (num)
*num = nset;
return MP_OKAY;
}
mp_err mpl_num_clear(mp_int *a, mp_size *num)
{
mp_size ix, nset = 0;
mp_digit cur;
unsigned char reg;
ARGCHK(a != NULL, MP_BADARG);
for (ix = 0; ix < USED(a); ix++) {
size_t i;
cur = DIGIT(a, ix);
for (i = 0; i < sizeof (mp_digit); i++) {
reg = (cur >> (CHAR_BIT * i)) & UCHAR_MAX;
nset += bitc[UCHAR_MAX - reg];
}
}
if (num)
*num = nset;
return MP_OKAY;
}
/* Determines the bitwise parity of the value given. Returns MP_EVEN
* if an even number of digits are set, MP_ODD if an odd number are
* set.
*/
mp_err mpl_parity(mp_int *a)
{
mp_size ix;
unsigned par = 0;
mp_digit cur;
ARGCHK(a != NULL, MP_BADARG);
for (ix = 0; ix < USED(a); ix++) {
unsigned shft = (sizeof (mp_digit) * CHAR_BIT) / 2;
cur = DIGIT(a, ix);
/* Compute parity for current digit */
while (shft != 0) {
cur ^= (cur >> shft);
shft >>= 1;
}
cur &= 1;
/* XOR with running parity so far */
par ^= cur;
}
if (par)
return MP_ODD;
else
return MP_EVEN;
}