/*
* mplogic . c
*
* Bitwise logical operations on MPI values
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License , v . 2 . 0 . If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mpi-priv.h"
#include "mplogic.h"
/* {{{ Lookup table for population count */
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 ) - compute b = ~ a
mpl_and ( a , b , c ) - compute c = a & b
mpl_or ( a , b , c ) - compute c = a | b
mpl_xor ( a , b , c ) - compute c = a ^ b
*/
/* {{{ mpl_not(a, b) */
mp_err
mpl_not(mp_int *a, mp_int *b)
{
mp_err res;
unsigned int 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;
}
/* end mpl_not() */
/* }}} */
/* {{{ mpl_and(a, b, c) */
mp_err
mpl_and(mp_int *a, mp_int *b, mp_int *c)
{
mp_int *which, *other;
mp_err res;
unsigned int 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;
}
/* end mpl_and() */
/* }}} */
/* {{{ mpl_or(a, b, c) */
mp_err
mpl_or(mp_int *a, mp_int *b, mp_int *c)
{
mp_int *which, *other;
mp_err res;
unsigned int 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;
}
/* end mpl_or() */
/* }}} */
/* {{{ mpl_xor(a, b, c) */
mp_err
mpl_xor(mp_int *a, mp_int *b, mp_int *c)
{
mp_int *which, *other;
mp_err res;
unsigned int 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;
}
/* end mpl_xor() */
/* }}} */
/*------------------------------------------------------------------------*/
/*
mpl_rsh ( a , b , d ) - b = a > > d
mpl_lsh ( a , b , d ) - b = a < < d
*/
/* {{{ mpl_rsh(a, b, d) */
mp_err
mpl_rsh(
const mp_int *a, mp_int *b, mp_digit d)
{
mp_err res;
ARGCHK(a != NULL && b != NULL, MP_BADARG);
if ((res = mp_copy(a, b)) != MP_OKAY)
return res;
s_mp_div_2d(b, d);
return MP_OKAY;
}
/* end mpl_rsh() */
/* }}} */
/* {{{ mpl_lsh(a, b, d) */
mp_err
mpl_lsh(
const mp_int *a, mp_int *b, mp_digit d)
{
mp_err res;
ARGCHK(a != NULL && b != NULL, MP_BADARG);
if ((res = mp_copy(a, b)) != MP_OKAY)
return res;
return s_mp_mul_2d(b, d);
}
/* end mpl_lsh() */
/* }}} */
/*------------------------------------------------------------------------*/
/*
mpl_num_set ( a , num )
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 .
*/
/* {{{ mpl_num_set(a, num) */
mp_err
mpl_num_set(mp_int *a,
unsigned int *num)
{
unsigned int ix, db, nset =
0 ;
mp_digit cur;
unsigned char reg;
ARGCHK(a != NULL, MP_BADARG);
for (ix =
0 ; ix < USED(a); ix++) {
cur = DIGIT(a, ix);
for (db =
0 ; db <
sizeof (mp_digit); db++) {
reg = (
unsigned char )(cur >> (CHAR_BIT * db));
nset += bitc[reg];
}
}
if (num)
*num = nset;
return MP_OKAY;
}
/* end mpl_num_set() */
/* }}} */
/* {{{ mpl_num_clear(a, num) */
mp_err
mpl_num_clear(mp_int *a,
unsigned int *num)
{
unsigned int ix, db, nset =
0 ;
mp_digit cur;
unsigned char reg;
ARGCHK(a != NULL, MP_BADARG);
for (ix =
0 ; ix < USED(a); ix++) {
cur = DIGIT(a, ix);
for (db =
0 ; db <
sizeof (mp_digit); db++) {
reg = (
unsigned char )(cur >> (CHAR_BIT * db));
nset += bitc[UCHAR_MAX - reg];
}
}
if (num)
*num = nset;
return MP_OKAY;
}
/* end mpl_num_clear() */
/* }}} */
/*------------------------------------------------------------------------*/
/*
mpl_parity ( a )
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 .
*/
/* {{{ mpl_parity(a) */
mp_err
mpl_parity(mp_int *a)
{
unsigned int ix;
int par =
0 ;
mp_digit cur;
ARGCHK(a != NULL, MP_BADARG);
for (ix =
0 ; ix < USED(a); ix++) {
int 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;
}
/* end mpl_parity() */
/* }}} */
/*
mpl_set_bit
Returns MP_OKAY or some error code .
Grows a if needed to set a bit to 1 .
*/
mp_err
mpl_set_bit(mp_int *a, mp_size bitNum, mp_size value)
{
mp_size ix;
mp_err rv;
mp_digit mask;
ARGCHK(a != NULL, MP_BADARG);
ix = bitNum / MP_DIGIT_BIT;
if (ix +
1 > MP_USED(a)) {
rv = s_mp_pad(a, ix +
1 );
if (rv != MP_OKAY)
return rv;
}
bitNum = bitNum % MP_DIGIT_BIT;
mask = (mp_digit)
1 << bitNum;
if (value)
MP_DIGIT(a, ix) |= mask;
else
MP_DIGIT(a, ix) &= ~mask;
s_mp_clamp(a);
return MP_OKAY;
}
/*
mpl_get_bit
returns 0 or 1 or some ( negative ) error code .
*/
mp_err
mpl_get_bit(
const mp_int *a, mp_size bitNum)
{
mp_size bit, ix;
mp_err rv;
ARGCHK(a != NULL, MP_BADARG);
ix = bitNum / MP_DIGIT_BIT;
ARGCHK(ix <= MP_USED(a) -
1 , MP_RANGE);
bit = bitNum % MP_DIGIT_BIT;
rv = (mp_err)(MP_DIGIT(a, ix) >> bit) &
1 ;
return rv;
}
/*
mpl_get_bits
- Extracts numBits bits from a , where the least significant extracted bit
is bit lsbNum . Returns a negative value if error occurs .
- Because sign bit is used to indicate error , maximum number of bits to
be returned is the lesser of ( a ) the number of bits in an mp_digit , or
( b ) one less than the number of bits in an mp_err .
- lsbNum + numbits can be greater than the number of significant bits in
integer a , as long as bit lsbNum is in the high order digit of a .
*/
mp_err
mpl_get_bits(
const mp_int *a, mp_size lsbNum, mp_size numBits)
{
mp_size rshift = (lsbNum % MP_DIGIT_BIT);
mp_size lsWndx = (lsbNum / MP_DIGIT_BIT);
mp_digit *digit = MP_DIGITS(a) + lsWndx;
mp_digit mask = ((
1 << numBits) -
1 );
ARGCHK(numBits < CHAR_BIT *
sizeof mask, MP_BADARG);
ARGCHK(MP_HOWMANY(lsbNum, MP_DIGIT_BIT) <= MP_USED(a), MP_RANGE);
if ((numBits + lsbNum % MP_DIGIT_BIT <= MP_DIGIT_BIT) ||
(lsWndx +
1 >= MP_USED(a))) {
mask &= (digit[
0 ] >> rshift);
}
else {
mask &= ((digit[
0 ] >> rshift) | (digit[
1 ] << (MP_DIGIT_BIT - rshift)));
}
return (mp_err)mask;
}
#define LZCNTLOOP(i) \
do { \
x = d >> (i); \
mask = (
0 - x); \
mask = (
0 - (mask >> (MP_DIGIT_BIT -
1 ))); \
bits += (i)&mask; \
d ^= (x ^ d) & mask; \
}
while (
0 )
/*
mpl_significant_bits
returns number of significant bits in abs ( a ) .
In other words : floor ( lg ( abs ( a ) ) ) + 1 .
returns 1 if value is zero .
*/
mp_size
mpl_significant_bits(
const mp_int *a)
{
/*
start bits at 1 .
lg ( 0 ) = 0 = > bits = 1 by function semantics .
below does a binary search for the _ position_ of the top bit set ,
which is floor ( lg ( abs ( a ) ) ) for a ! = 0 .
*/
mp_size bits =
1 ;
int ix;
ARGCHK(a != NULL, MP_BADARG);
for (ix = MP_USED(a); ix >
0 ;) {
mp_digit d, x, mask;
if ((d = MP_DIGIT(a, --ix)) ==
0 )
continue ;
#if !
defined (MP_USE_UINT_DIGIT)
LZCNTLOOP(
32 );
#endif
LZCNTLOOP(
16 );
LZCNTLOOP(
8 );
LZCNTLOOP(
4 );
LZCNTLOOP(
2 );
LZCNTLOOP(
1 );
break ;
}
bits += ix * MP_DIGIT_BIT;
return bits;
}
#undef LZCNTLOOP
/*------------------------------------------------------------------------*/
/* HERE THERE BE DRAGONS */
Messung V0.5 in Prozent C=90 H=75 G=82
¤ Dauer der Verarbeitung: 0.22 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland