Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov(a)gmail.com>
---
bignum.c | 35 +++++++++++++++++++++++++++++++++++
bignum.h | 15 +++++++++++++++
testsuite/bignum-test.c | 29 +++++++++++++++++++++++++++++
3 files changed, 79 insertions(+)
diff --git a/bignum.c b/bignum.c
index 33525287..413a630c 100644
--- a/bignum.c
+++ b/bignum.c
@@ -133,12 +133,32 @@ nettle_mpz_get_str_256(size_t length, uint8_t *s, const mpz_t x)
}
}
+void
+nettle_mpz_get_str_256_u_le(size_t length, uint8_t *s, const mpz_t x)
+{
+ if (!length)
+ {
+ /* x must be zero */
+ assert(!mpz_sgn(x));
+ return;
+ }
+
+ size_t count;
+
+ assert(nettle_mpz_sizeinbase_256_u(x) <= length);
+ mpz_export(s, &count, -1, 1, 0, 0, x);
+ memset(s + count, 0, length - count);
+}
+
/* Converting from strings */
/* mpz_import was introduced in GMP-4.1 */
#define nettle_mpz_from_octets(x, length, s) \
mpz_import((x), (length), 1, 1, 0, 0, (s))
+#define nettle_mpz_from_octets_le(x, length, s) \
+ mpz_import((x), (length), -1, 1, 0, 0, (s))
+
void
nettle_mpz_set_str_256_u(mpz_t x,
size_t length, const uint8_t *s)
@@ -155,6 +175,21 @@ nettle_mpz_init_set_str_256_u(mpz_t x,
}
void
+nettle_mpz_set_str_256_u_le(mpz_t x,
+ size_t length, const uint8_t *s)
+{
+ nettle_mpz_from_octets_le(x, length, s);
+}
+
+void
+nettle_mpz_init_set_str_256_u_le(mpz_t x,
+ size_t length, const uint8_t *s)
+{
+ mpz_init(x);
+ nettle_mpz_from_octets_le(x, length, s);
+}
+
+void
nettle_mpz_set_str_256_s(mpz_t x,
size_t length, const uint8_t *s)
{
diff --git a/bignum.h b/bignum.h
index 9afcd299..afea1887 100644
--- a/bignum.h
+++ b/bignum.h
@@ -72,6 +72,12 @@ nettle_mpz_sizeinbase_256_u(const mpz_t x);
void
nettle_mpz_get_str_256(size_t length, uint8_t *s, const mpz_t x);
+/* Writes an integer as length octets, using big endian byte order,
+ * and unsigned number format. */
+void
+nettle_mpz_get_str_256_u_le(size_t 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,
@@ -91,6 +97,15 @@ void
nettle_mpz_init_set_str_256_u(mpz_t x,
size_t length, const uint8_t *s);
+/* Similar, but for little endian byte order. */
+void
+nettle_mpz_set_str_256_u_le(mpz_t x,
+ size_t length, const uint8_t *s);
+
+void
+nettle_mpz_init_set_str_256_u_le(mpz_t x,
+ size_t length, const uint8_t *s);
+
/* Returns a uniformly distributed random number 0 <= x < 2^n */
void
nettle_mpz_random_size(mpz_t x,
diff --git a/testsuite/bignum-test.c b/testsuite/bignum-test.c
index 602554b5..79fd92e2 100644
--- a/testsuite/bignum-test.c
+++ b/testsuite/bignum-test.c
@@ -35,6 +35,30 @@ test_bignum(const char *hex, const struct tstring *base256)
}
static void
+test_bignum_le(const char *hex, const struct tstring *base256)
+{
+ mpz_t a;
+ mpz_t b;
+ uint8_t *buf;
+
+ mpz_init_set_str(a, hex, 16);
+ nettle_mpz_init_set_str_256_u_le(b, base256->length, base256->data);
+
+ ASSERT(mpz_cmp(a, b) == 0);
+
+ buf = xalloc(base256->length + 1);
+ memset(buf, 17, base256->length + 1);
+
+ nettle_mpz_get_str_256_u_le(base256->length, buf, a);
+ ASSERT(MEMEQ(base256->length, buf, base256->data));
+
+ ASSERT(buf[base256->length] == 17);
+
+ mpz_clear(a); mpz_clear(b);
+ free(buf);
+}
+
+static void
test_size(long x, unsigned size)
{
mpz_t t;
@@ -86,6 +110,11 @@ test_main(void)
test_bignum("-7fff", SHEX( "8001"));
test_bignum("-8000", SHEX( "8000"));
test_bignum("-8001", SHEX("ff7fff"));
+
+ test_bignum_le("0", SHEX("00"));
+ test_bignum_le("010203040506", SHEX("060504030201"));
+ test_bignum_le("80010203040506", SHEX("06050403020180"));
+ test_bignum_le("01020304050680", SHEX("80060504030201"));
#else /* !WITH_HOGWEED */
SKIP();
--
2.11.0