From 43152353176dfadc83a880dcec2f21312bf6fa19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niels=20M=C3=B6ller?= <nisse@lysator.liu.se> Date: Fri, 15 Nov 2002 08:57:42 +0100 Subject: [PATCH] (nettle_mpz_sizeinbase_256_s): New function. (nettle_mpz_sizeinbase_256_u): New name, was nettle_mpz_sizeinbase_256. (nettle_mpz_to_octets): New function. (nettle_mpz_get_str_256): Handle negative numbers. (nettle_mpz_from_octets): New function. (nettle_mpz_set_str_256_u): New name, was nettle_mpz_set_str_256. (nettle_mpz_init_set_str_256_u): New name, was nettle_mpz_init_set_str_256. (nettle_mpz_set_str_256_s): New function, handling negative two's complement numbers. (nettle_mpz_init_set_str_256_s): And an init variant. Rev: src/nettle/bignum.c:1.5 Rev: src/nettle/bignum.h:1.6 --- bignum.c | 137 +++++++++++++++++++++++++++++++++++++++++++++---------- bignum.h | 32 ++++++++++--- 2 files changed, 138 insertions(+), 31 deletions(-) diff --git a/bignum.c b/bignum.c index 67abe5d8..d923d702 100644 --- a/bignum.c +++ b/bignum.c @@ -34,29 +34,54 @@ #include <assert.h> #include <string.h> +/* Two's complement negation means that -x = ~x + 1, ~x = -(x+1), + * and we use that x = ~~x = ~(-x-1). + * + * Examples: + * + * x ~x = -x+1 ~~x = x + * -1 0 ff + * -2 1 fe + * -7f 7e 81 + * -80 7f 80 + * -81 80 ff7f + */ + +/* Including extra sign bit, if needed. Also one byte for zero. */ unsigned -nettle_mpz_sizeinbase_256(const mpz_t x) +nettle_mpz_sizeinbase_256_s(const mpz_t x) { - return (mpz_sizeinbase(x, 2) + 7) / 8; + if (mpz_sgn(x) >= 0) + return 1 + mpz_sizeinbase(x, 2) / 8; + else + { + /* We'll output ~~x, so we need as many bits as for ~x */ + unsigned size; + mpz_t c; + + mpz_init(c); + mpz_com(c, x); /* Same as c = - x - 1 = |x| + 1 */ + size = 1 + mpz_sizeinbase(c,2) / 8; + mpz_clear(c); + + return size; + } } -void -nettle_mpz_get_str_256(unsigned length, uint8_t *s, const mpz_t x) +unsigned +nettle_mpz_sizeinbase_256_u(const mpz_t x) +{ + return (mpz_sizeinbase(x,2) + 7) / 8; +} + +static void +nettle_mpz_to_octets(unsigned length, uint8_t *s, + const mpz_t x, uint8_t sign) { uint8_t *dst = s + length - 1; unsigned size = mpz_size(x); unsigned i; - - if (!length) - { - /* x must be zero */ - assert(!mpz_sgn(x)); - return; - } - assert(mpz_sgn(x) >= 0); - assert(nettle_mpz_sizeinbase_256(x) <= length); - for (i = 0; i<size; i++) { mp_limb_t limb = mpz_getlimbn(x, i); @@ -64,28 +89,58 @@ nettle_mpz_get_str_256(unsigned length, uint8_t *s, const mpz_t x) for (j = 0; length && j < sizeof(mp_limb_t); j++) { - *dst-- = limb & 0xff; + *dst-- = sign ^ (limb & 0xff); limb >>= 8; length--; } } if (length) - memset(s, 0, length); + memset(s, sign, length); } void -nettle_mpz_set_str_256(mpz_t x, - unsigned length, const uint8_t *s) +nettle_mpz_get_str_256(unsigned length, uint8_t *s, const mpz_t x) +{ + if (!length) + { + /* x must be zero */ + assert(!mpz_sgn(x)); + return; + } + + if (mpz_sgn(x) >= 0) + { + assert(nettle_mpz_sizeinbase_256_u(x) <= length); + nettle_mpz_to_octets(length, s, x, 0); + } + else + { + mpz_t c; + mpz_init(c); + mpz_com(c, x); + + assert(nettle_mpz_sizeinbase_256_u(c) <= length); + nettle_mpz_to_octets(length, s, c, 0xff); + + mpz_clear(c); + } +} + +/* Converting from strings */ +static void +nettle_mpz_from_octets(mpz_t x, + unsigned length, const uint8_t *s, + uint8_t sign) { - size_t i; + unsigned i; mpz_t digit; mpz_init(digit); - mpz_set_ui(x, 0); + for (i = 0; i < length; i++) { - mpz_set_ui(digit, s[i]); + mpz_set_ui(digit, sign ^ s[i]); mpz_mul_2exp(digit, digit, (length - i - 1) * 8); mpz_ior(x, x, digit); } @@ -93,11 +148,45 @@ nettle_mpz_set_str_256(mpz_t x, } void -nettle_mpz_init_set_str_256(mpz_t x, - unsigned length, const uint8_t *s) +nettle_mpz_set_str_256_u(mpz_t x, + unsigned length, const uint8_t *s) +{ + mpz_set_ui(x, 0); + nettle_mpz_from_octets(x, length, s, 0); +} + +void +nettle_mpz_init_set_str_256_u(mpz_t x, + unsigned length, const uint8_t *s) +{ + mpz_init_set_ui(x, 0); + nettle_mpz_from_octets(x, length, s, 0); +} + +void +nettle_mpz_set_str_256_s(mpz_t x, + unsigned length, const uint8_t *s) +{ + mpz_set_ui(x, 0); + + if (!length) + return; + + if (s[0] & 0x80) + { + nettle_mpz_from_octets(x, length, s, 0xff); + mpz_com(x, x); + } + else + nettle_mpz_from_octets(x, length, s, 0); +} + +void +nettle_mpz_init_set_str_256_s(mpz_t x, + unsigned length, const uint8_t *s) { mpz_init(x); - nettle_mpz_set_str_256(x, length, s); + nettle_mpz_set_str_256_s(x, length, s); } #endif /* HAVE_LIBGMP */ diff --git a/bignum.h b/bignum.h index f4c9ed07..3ba8ea5d 100644 --- a/bignum.h +++ b/bignum.h @@ -31,21 +31,39 @@ #include <gmp.h> #include <inttypes.h> +/* Size needed for signed encoding, including extra sign byte if + * necessary. */ unsigned -nettle_mpz_sizeinbase_256(const mpz_t x); +nettle_mpz_sizeinbase_256_s(const mpz_t x); -/* Writes an unsigned integer as length octets, using big endian byte - * order. */ +/* Size needed for unsigned encoding */ +unsigned +nettle_mpz_sizeinbase_256_u(const mpz_t x); + +/* Writes an integer as length octets, using big endian byte order, + * and two's complement for negative numbers. */ +/* FIXME: Change order of arguments, putting the mpz_t first? */ void nettle_mpz_get_str_256(unsigned length, uint8_t *s, const mpz_t x); +/* Reads a big endian, two's complement, integer. */ +void +nettle_mpz_set_str_256_s(mpz_t x, + unsigned length, const uint8_t *s); + +void +nettle_mpz_init_set_str_256_s(mpz_t x, + unsigned length, const uint8_t *s); + +/* Similar, but for unsigned format. These function don't interpret + * the most significant bit as the sign. */ void -nettle_mpz_set_str_256(mpz_t x, - unsigned length, const uint8_t *s); +nettle_mpz_set_str_256_u(mpz_t x, + unsigned length, const uint8_t *s); void -nettle_mpz_init_set_str_256(mpz_t x, - unsigned length, const uint8_t *s); +nettle_mpz_init_set_str_256_u(mpz_t x, + unsigned length, const uint8_t *s); /* Returns a uniformly distributed random number 0 <= x < 2^n */ void -- GitLab