summaryrefslogtreecommitdiffstats
path: root/mpi
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-04-22 19:55:19 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-04-22 19:55:19 -0700
commit150e147b77199684b32c327e4d3e2715fd2d7a0f (patch)
tree171ebf24ae26a036d04f04b0a6a0bfd2d56d9c87 /mpi
parent5f4b704f40f30d19468078ace5f7624c1225faa6 (diff)
downloadtxr-150e147b77199684b32c327e4d3e2715fd2d7a0f.tar.gz
txr-150e147b77199684b32c327e4d3e2715fd2d7a0f.tar.bz2
txr-150e147b77199684b32c327e4d3e2715fd2d7a0f.zip
add-bitops patch
Adding bit operations to MPI. * mpi/mpi.c (MAX, MIN): New macros. (mp_2comp, mp_and, mp_or, mp_xor, mp_comp, mp_trunc, mp_shift, mp_bit): New functions. * mpi/mpi.h (mp_2comp, mp_and, mp_or, mp_xor, mp_comp, mp_trunc, mp_shift, mp_bit): Declared.
Diffstat (limited to 'mpi')
-rw-r--r--mpi/mpi.c428
-rw-r--r--mpi/mpi.h13
2 files changed, 441 insertions, 0 deletions
diff --git a/mpi/mpi.c b/mpi/mpi.c
index 1d9da125..61575abc 100644
--- a/mpi/mpi.c
+++ b/mpi/mpi.c
@@ -16,6 +16,9 @@
#include <ctype.h>
#include <math.h>
+#define MAX(A, B) ((A) > (B) ? (A) : (B))
+#define MIN(A, B) ((A) < (B) ? (A) : (B))
+
typedef unsigned char mem_t;
extern mem_t *chk_calloc(size_t n, size_t size);
@@ -157,6 +160,7 @@ static const char *s_dmap_2 =
mp_err s_mp_grow(mp_int *mp, mp_size min); /* increase allocated size */
mp_err s_mp_pad(mp_int *mp, mp_size min); /* left pad with zeroes */
+static int s_highest_bit(mp_digit n);
int s_highest_bit_mp(mp_int *a);
mp_err s_mp_set_bit(mp_int *a, int bit);
@@ -2334,6 +2338,430 @@ X:
/* }}} */
+/*
+ * Convert a's bit vector to its two's complement, up to the
+ * number of words that it contains, storing result in b. The numeric value of
+ * this result depends on the size of mpi_digit. This is a building block for
+ * handling negative operands in the bit operations.
+ */
+mp_err mp_2comp(mp_int *a, mp_int *b, mp_size dig)
+{
+ mp_err res;
+ mp_size ix, adig = USED(a);
+ mp_digit *pa, *pb;
+ mp_digit padding = ISNEG(a) ? MP_DIGIT_MAX : 0;
+ mp_word w;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if (a != b) {
+ if ((res = mp_init_size(b, dig)) != MP_OKAY)
+ return res;
+ SIGN(b) = SIGN(a);
+ } else {
+ if((res = s_mp_pad(b, dig)) != MP_OKAY)
+ return res;
+ }
+
+ for (pa = DIGITS(a), pb = DIGITS(b), w = 0, ix = 0; ix < dig; ix++) {
+ w += (ix == 0);
+ w += (ix < adig) ? ~pa[ix] : padding;
+ pb[ix] = ACCUM(w);
+ w = CARRYOUT(w);
+ }
+
+ USED(b) = dig;
+
+ return MP_OKAY;
+}
+
+mp_err mp_and(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_err res = MP_OKAY;
+ mp_size ix, extent = 0;
+ mp_digit *pa, *pb, *pc;
+ mp_int tmp_a, tmp_b;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if (a == b)
+ return mp_copy(a, c);
+
+ if (ISNEG(a)) {
+ extent = USED(b);
+ mp_init(&tmp_a);
+ if ((res = mp_2comp(a, &tmp_a, extent)) != MP_OKAY)
+ goto out;
+ a = &tmp_a;
+ }
+
+ if (ISNEG(b)) {
+ extent = USED(a);
+ mp_init(&tmp_b);
+ if ((res = mp_2comp(b, &tmp_b, extent)) != MP_OKAY)
+ goto out;
+ b = &tmp_b;
+ }
+
+ if (!extent)
+ extent = MIN(USED(a), USED(b));
+
+ if (c != a && c != b) {
+ if ((res = mp_init_size(c, extent)) != MP_OKAY)
+ goto out;
+ }
+
+ for (pa = DIGITS(a), pb = DIGITS(b), pc = DIGITS(c), ix = 0;
+ ix < extent; ix++)
+ {
+ pc[ix] = pa[ix] & pb[ix];
+ }
+
+ USED(c) = extent;
+
+ if (ISNEG(a) && ISNEG(b)) {
+ mp_2comp(c, c, extent);
+ SIGN(c) = MP_NEG;
+ }
+
+ s_mp_clamp(c);
+
+out:
+ if (ISNEG(a))
+ mp_clear(&tmp_a);
+
+ if (ISNEG(b))
+ mp_clear(&tmp_b);
+
+ return res;
+}
+
+mp_err mp_or(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_err res;
+ mp_size ix, extent = 0;
+ mp_digit *pa, *pb, *pc;
+ mp_int tmp_a, tmp_b;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ extent = MAX(USED(a), USED(b));
+
+ if (a == b)
+ return mp_copy(a, c);
+
+ if (ISNEG(a)) {
+ mp_init(&tmp_a);
+ if ((res = mp_2comp(a, &tmp_a, extent)) != MP_OKAY)
+ goto out;
+ a = &tmp_a;
+ }
+
+ if (ISNEG(b)) {
+ mp_init(&tmp_b);
+ if ((res = mp_2comp(b, &tmp_b, extent)) != MP_OKAY)
+ goto out;
+ b = &tmp_b;
+ }
+
+
+ if (c != a && c != b)
+ res = mp_init_size(c, extent);
+ else
+ res = s_mp_pad(c, extent);
+
+ if (res != MP_OKAY)
+ goto out;
+
+ for (pa = DIGITS(a), pb = DIGITS(b), pc = DIGITS(c), ix = 0;
+ ix < extent; ix++)
+ {
+ pc[ix] = pa[ix] | pb[ix];
+ }
+
+ USED(c) = extent;
+
+ if (ISNEG(a) || ISNEG(b)) {
+ mp_2comp(c, c, extent);
+ SIGN(c) = MP_NEG;
+ }
+
+ s_mp_clamp(c);
+
+out:
+ if (ISNEG(a))
+ mp_clear(&tmp_a);
+
+ if (ISNEG(b))
+ mp_clear(&tmp_b);
+
+ return res;
+}
+
+mp_err mp_xor(mp_int *a, mp_int *b, mp_int *c)
+{
+ mp_err res;
+ mp_size ix, extent = 0;
+ mp_digit *pa, *pb, *pc;
+ mp_int tmp_a, tmp_b;
+
+ ARGCHK(a != NULL && b != NULL && c != NULL, MP_BADARG);
+
+ if (a == b) {
+ mp_zero(c);
+ return MP_OKAY;
+ }
+
+ extent = MAX(USED(a), USED(b));
+
+ if (ISNEG(a)) {
+ mp_init(&tmp_a);
+ if ((res = mp_2comp(a, &tmp_a, extent)) != MP_OKAY)
+ goto out;
+ a = &tmp_a;
+ }
+
+ if (ISNEG(b)) {
+ mp_init(&tmp_b);
+ if ((res = mp_2comp(b, &tmp_b, extent)) != MP_OKAY)
+ goto out;
+ b = &tmp_b;
+ }
+
+
+ if (c != a && c != b)
+ res = mp_init_size(c, extent);
+ else
+ res = s_mp_pad(c, extent);
+
+ if (res != MP_OKAY)
+ goto out;
+
+ for (pa = DIGITS(a), pb = DIGITS(b), pc = DIGITS(c), ix = 0;
+ ix < extent; ix++)
+ {
+ pc[ix] = pa[ix] ^ pb[ix];
+ }
+
+ USED(c) = extent;
+
+ if (ISNEG(a) ^ ISNEG(b)) {
+ mp_2comp(c, c, extent);
+ SIGN(c) = MP_NEG;
+ }
+
+ s_mp_clamp(c);
+
+out:
+ if (ISNEG(a))
+ mp_clear(&tmp_a);
+
+ if (ISNEG(b))
+ mp_clear(&tmp_b);
+
+ return res;
+}
+
+mp_err mp_comp(mp_int *a, mp_int *b)
+{
+ mp_err res;
+ mp_size ix, dig = USED(a);
+ mp_digit *pa, *pb;
+ mp_int tmp;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if (a != b)
+ res = mp_init_size(b, dig);
+ else
+ res = s_mp_pad(b, dig);
+
+ if (res != MP_OKAY)
+ return res;
+
+ if (ISNEG(a)) {
+ mp_init(&tmp);
+ if ((res = mp_2comp(a, &tmp, dig)) != MP_OKAY)
+ return res;
+ a = &tmp;
+ }
+
+ for (pa = DIGITS(a), pb = DIGITS(b), ix = 0; ix < dig; ix++)
+ pb[ix] = ~pa[ix];
+
+ USED(b) = dig;
+
+ if (ISNEG(a)) {
+ mp_clear(&tmp);
+ } else {
+ if ((res = mp_2comp(b, b, dig)) != MP_OKAY)
+ return res;
+ SIGN(b) = MP_NEG;
+ }
+
+ s_mp_clamp(b);
+ return MP_OKAY;
+}
+
+mp_err mp_trunc_comp(mp_int *a, mp_int *b, mp_digit bits)
+{
+ mp_err res;
+ mp_size ix, dig = bits / DIGIT_BIT, rembits = bits % DIGIT_BIT;
+ mp_size adig = USED(a);
+ mp_digit padding = ISNEG(a) ? MP_DIGIT_MAX : 0;
+ int extra = (rembits != 0);
+ mp_digit *pa, *pb;
+ mp_int tmp;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if (a != b)
+ res = mp_init_size(b, dig + extra);
+ else
+ res = s_mp_pad(b, dig + extra);
+
+ if (res != MP_OKAY)
+ return res;
+
+ if (ISNEG(a)) {
+ mp_init(&tmp);
+ if ((res = mp_2comp(a, &tmp, dig + extra)) != MP_OKAY)
+ return res;
+ a = &tmp;
+ }
+
+ for (pa = DIGITS(a), pb = DIGITS(b), ix = 0; ix < dig; ix++)
+ pb[ix] = (ix < adig) ? ~pa[ix] : ~padding;
+
+ if (rembits) {
+ mp_digit mask = (MP_DIGIT_MAX >> (DIGIT_BIT - rembits));
+ pb[ix] = (((ix < adig) ? pa[ix] : padding) & mask) ^ mask;
+ }
+
+ USED(b) = dig + extra;
+
+ if (ISNEG(a))
+ mp_clear(&tmp);
+
+ s_mp_clamp(b);
+ return MP_OKAY;
+}
+
+mp_err mp_trunc(mp_int *a, mp_int *b, mp_digit bits)
+{
+ mp_err res;
+ mp_size ix, dig = bits / DIGIT_BIT, rembits = bits % DIGIT_BIT;
+ mp_size adig = USED(a);
+ mp_digit padding = ISNEG(a) ? MP_DIGIT_MAX : 0;
+ int extra = (rembits != 0);
+ mp_digit *pa, *pb;
+ mp_int tmp;
+
+ ARGCHK(a != NULL && b != NULL, MP_BADARG);
+
+ if (a != b)
+ res = mp_init_size(b, dig + extra);
+ else
+ res = s_mp_pad(b, dig + extra);
+
+ if (res != MP_OKAY)
+ return res;
+
+ if (ISNEG(a)) {
+ mp_init(&tmp);
+ if ((res = mp_2comp(a, &tmp, dig + extra)) != MP_OKAY)
+ return res;
+ a = &tmp;
+ }
+
+ for (pa = DIGITS(a), pb = DIGITS(b), ix = 0; ix < dig; ix++)
+ pb[ix] = (ix < adig) ? pa[ix] : padding;
+
+ if (rembits) {
+ mp_digit mask = (MP_DIGIT_MAX >> (DIGIT_BIT - rembits));
+ pb[ix] = ((ix < adig) ? pa[ix] : padding) & mask;
+ }
+
+ USED(b) = dig + extra;
+
+ if (ISNEG(a))
+ mp_clear(&tmp);
+
+ s_mp_clamp(b);
+ return MP_OKAY;
+}
+
+mp_err mp_shift(mp_int *a, mp_int *b, int bits)
+{
+ mp_int tmp;
+ mp_err res;
+ int a_neg = ISNEG(a);
+
+ if (bits == 0)
+ return mp_copy(a, b);
+
+ if (a_neg) {
+ mp_size ua = USED(a);
+ mp_init(&tmp);
+ if ((res = mp_2comp(a, &tmp, ua)) != MP_OKAY)
+ return res;
+ SIGN(&tmp) = MP_ZPOS;
+ a = &tmp;
+ }
+
+ if (bits > 0)
+ res = mp_mul_2d(a, bits, b);
+ else
+ res = mp_div_2d(a, -bits, b, NULL);
+
+ if (res != MP_OKAY) {
+ if (a_neg)
+ mp_clear(&tmp);
+ return res;
+ }
+
+ if (a_neg) {
+ int hb, msd;
+ mp_digit *db;
+
+ mp_clear(&tmp);
+
+ msd = USED(b)-1;
+ db = DIGITS(b);
+ hb = s_highest_bit(db[msd]);
+
+ if (hb < DIGIT_BIT)
+ db[msd] |= MP_DIGIT_MAX << hb;
+
+ if ((res = mp_2comp(b, b, USED(b))) != MP_OKAY)
+ return res;
+
+ SIGN(b) = MP_NEG;
+ s_mp_clamp(b);
+ }
+
+ return MP_OKAY;
+}
+
+mp_err mp_bit(mp_int *a, mp_digit bit)
+{
+ mp_int tmp;
+ mp_err res;
+ int a_neg = ISNEG(a);
+ int digit = bit / MP_DIGIT_BIT;
+ mp_digit mask = ((mp_digit) 1 << (bit % MP_DIGIT_BIT));
+
+ if (a_neg) {
+ mp_init(&tmp);
+ if ((res = mp_2comp(a, &tmp, bit + 1)) != MP_OKAY)
+ return res;
+ SIGN(&tmp) = MP_ZPOS;
+ a = &tmp;
+ }
+
+ return (DIGITS(a)[digit] & mask) != 0 ? MP_YES : MP_NO;
+}
+
mp_err mp_to_double(mp_int *mp, double *d)
{
int ix;
diff --git a/mpi/mpi.h b/mpi/mpi.h
index c6136c15..98280247 100644
--- a/mpi/mpi.h
+++ b/mpi/mpi.h
@@ -54,6 +54,7 @@
/* Macros for accessing the mp_int internals */
#define SIGN(MP) ((MP)->sign)
+#define ISNEG(MP) ((MP)->sign == MP_NEG)
#define USED(MP) ((MP)->used)
#define ALLOC(MP) ((MP)->alloc)
#define DIGITS(MP) ((MP)->dp)
@@ -187,6 +188,18 @@ mp_err mp_invmod(mp_int *a, mp_int *m, mp_int *c);
#endif /* end MP_NUMTH */
/*------------------------------------------------------------------------*/
+/* Bit ops */
+mp_err mp_2comp(mp_int *a, mp_int *b, mp_size dig); /* peculiar semantics */
+mp_err mp_and(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_or(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_xor(mp_int *a, mp_int *b, mp_int *c);
+mp_err mp_comp(mp_int *a, mp_int *b);
+mp_err mp_trunc_comp(mp_int *a, mp_int *b, mp_digit bits);
+mp_err mp_trunc(mp_int *a, mp_int *b, mp_digit bits);
+mp_err mp_shift(mp_int *a, mp_int *b, int bits); /* + left, - right */
+mp_err mp_bit(mp_int *a, mp_digit bit);
+
+/*------------------------------------------------------------------------*/
/* Conversions */
mp_err mp_to_double(mp_int *mp, double *d);