summaryrefslogtreecommitdiff
path: root/bignum.c
diff options
context:
space:
mode:
authorNiels Möller <nisse@lysator.liu.se>2002-11-15 08:57:42 +0100
committerNiels Möller <nisse@lysator.liu.se>2002-11-15 08:57:42 +0100
commit43152353176dfadc83a880dcec2f21312bf6fa19 (patch)
tree1d0f8ef41280da69cc11c4f0fe6eacbd3c523e1b /bignum.c
parent52c695fff9d1a7e24d7b63247421a46b07b94346 (diff)
downloadnettle-43152353176dfadc83a880dcec2f21312bf6fa19.tar.gz
(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
Diffstat (limited to 'bignum.c')
-rw-r--r--bignum.c137
1 files changed, 113 insertions, 24 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 */