Signed-off-by: Dmitry Eremin-Solenikov dbaryshkov@gmail.com --- bignum.c | 35 +++++++++++++++++++++++++++++++++++ bignum.h | 17 +++++++++++++++++ testsuite/bignum-test.c | 29 +++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+)
diff --git a/bignum.c b/bignum.c index 335252876544..413a630cb3aa 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) @@ -154,6 +174,21 @@ nettle_mpz_init_set_str_256_u(mpz_t x, nettle_mpz_from_octets(x, length, s); }
+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 7871d843168c..42a97e63d6b6 100644 --- a/bignum.h +++ b/bignum.h @@ -68,11 +68,19 @@ nettle_mpz_sizeinbase_256_s(const mpz_t x); size_t nettle_mpz_sizeinbase_256_u(const mpz_t x);
+#define nettle_mpz_sizeinbase_256_u_le nettle_mpz_sizeinbase_256_u + /* Writes an integer as length octets, using big endian byte order, * and two's complement for negative numbers. */ 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, @@ -92,6 +100,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 602554b53941..79fd92e2d37d 100644 --- a/testsuite/bignum-test.c +++ b/testsuite/bignum-test.c @@ -34,6 +34,30 @@ test_bignum(const char *hex, const struct tstring *base256) free(buf); }
+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) { @@ -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();