From e0781d0536ba9e34911501c62329191b0c671a87 Mon Sep 17 00:00:00 2001 From: Jakub Sztandera Date: Wed, 10 Aug 2016 15:46:15 +0200 Subject: [PATCH] add multihash encoding refactor to use size_t --- include/mh/errors.h | 1 + include/mh/{assert.h => generic.h} | 6 ++- include/mh/multihash.h | 22 +++++++++- src/errors.c | 3 ++ src/hashes.c | 2 +- src/multihash.c | 68 +++++++++++++++++++++++++++--- tests/c/minunit.h | 29 +++++++++++++ tests/c/test_multihash_new.c | 54 ++++++++++++++++++++++++ 8 files changed, 174 insertions(+), 11 deletions(-) rename include/mh/{assert.h => generic.h} (63%) create mode 100644 tests/c/test_multihash_new.c diff --git a/include/mh/errors.h b/include/mh/errors.h index 77abbdb..5f58f59 100644 --- a/include/mh/errors.h +++ b/include/mh/errors.h @@ -7,6 +7,7 @@ #define MH_E_TOO_SHORT -2 #define MH_E_TOO_LONG -3 #define MH_E_VARINT_NOT_SUPPORTED -4 +#define MH_E_DIGSET_TOO_LONG -5 #define MH_E_LAST -5 diff --git a/include/mh/assert.h b/include/mh/generic.h similarity index 63% rename from include/mh/assert.h rename to include/mh/generic.h index 022b73c..a4855ce 100644 --- a/include/mh/assert.h +++ b/include/mh/generic.h @@ -1,6 +1,8 @@ -#ifndef MH_ASSERT -#define MH_ASSERT +#ifndef MH_GENERIC +#define MH_GENERIC #define mh_assert_static(isTrue) void mh_assert_static(char x[1 - (!(isTrue))]) +#define UNUSED(x) (void)(x) + #endif /* end of include guard */ diff --git a/include/mh/multihash.h b/include/mh/multihash.h index 23c3448..167f6ae 100644 --- a/include/mh/multihash.h +++ b/include/mh/multihash.h @@ -1,10 +1,28 @@ #ifndef MH_HULTIHASH_H #define MH_HULTIHASH_H +#include + // returns hash code or error (which is < 0) -int mh_multihash_hash(const unsigned char multihash[], int len); +int mh_multihash_hash(const unsigned char *multihash, size_t len); // returns length of multihash or error (which is < 0) -int mh_multihash_length(const unsigned char multihash[], int len); +int mh_multihash_length(const unsigned char *multihash, size_t len); + +// gives access to raw digset inside multihash buffer +// returns 0 or negative error +int mh_multihash_digset(const unsigned char *multihash, size_t len, + const unsigned char **digset, size_t *digset_len); + +// returns length in bytes of buffer needed to store multihash +// with given hashcode and with given digset length +// returns length or negative error code +int mh_new_length(int code, size_t digset_len); + +// writes multihash into a buffer, the buffer needs to be at least +// mh_new_length() bytes long. +// returns negative error code or 0 +int mh_new(unsigned char *buffer, int code, const unsigned char *digset, + size_t digset_len); #endif /* end of include guard */ diff --git a/src/errors.c b/src/errors.c index 5b66188..3ce3252 100644 --- a/src/errors.c +++ b/src/errors.c @@ -13,6 +13,9 @@ const char *mh_error_string(int code) { case MH_E_VARINT_NOT_SUPPORTED: return "c-multihash does not yet support" " varint encoding"; + case MH_E_DIGSET_TOO_LONG: + return "c-multihash does not support digsets" + " longer than 127 bytes yet"; default: return "unknown error code"; } diff --git a/src/hashes.c b/src/hashes.c index c931a67..4171e30 100644 --- a/src/hashes.c +++ b/src/hashes.c @@ -3,7 +3,7 @@ #include "mh/hashes.h" #include "mh/errors.h" -#include "mh/assert.h" +#include "mh/generic.h" static const struct hash_info { diff --git a/src/multihash.c b/src/multihash.c index 667040d..bae1453 100644 --- a/src/multihash.c +++ b/src/multihash.c @@ -2,15 +2,30 @@ #include "mh/hashes.h" #include "mh/errors.h" +#include "mh/generic.h" + +#include +#include #define VARINT_MASK (1 << 7) -static int check_multihash(const unsigned char mh[], int len) { - if (len < 3) { +static int check_len(size_t len) { + if (len < 1) { return MH_E_TOO_SHORT; - } else if (len >= 129) { + } else if (len >= 128) { return MH_E_TOO_LONG; - } else if (mh[0] & VARINT_MASK) { + } + + return MH_E_NO_ERROR; +} + +static int check_multihash(const unsigned char mh[], size_t len) { + int error; + + if (len < 3) + return MH_E_TOO_SHORT; + + if (mh[0] & VARINT_MASK) { // In near future multihash format will be // extended with varints, this is how we are protecting // against it. @@ -18,12 +33,18 @@ static int check_multihash(const unsigned char mh[], int len) { } else if (mh[1] & VARINT_MASK) { return MH_E_VARINT_NOT_SUPPORTED; } + + error = check_len(mh[1]); + if (error) + return error; + + return MH_E_NO_ERROR; } // returns hash code or error (which is < 0) -int mh_multihash_hash(const unsigned char mh[], int len) { +int mh_multihash_hash(const unsigned char *mh, size_t len) { if (check_multihash(mh, len)) return check_multihash(mh, len); return (int) mh[0]; @@ -31,9 +52,44 @@ int mh_multihash_hash(const unsigned char mh[], int len) { // returns length of multihash or error (which is < 0) -int mh_multihash_length(const unsigned char mh[], int len) { +int mh_multihash_length(const unsigned char *mh, size_t len) { if (check_multihash(mh, len)) return check_multihash(mh, len); return (int) mh[1]; } +// gives access to raw digset inside multihash buffer +// returns 0 or negative error +int mh_multihash_digset(unsigned char *multihash, size_t len, unsigned char **digset, + size_t *digset_len) { + int error = check_multihash(multihash, len); + if (error) + return error; + + (*digset_len) = (size_t) mh_multihash_length(multihash, len); + (*digset) = multihash + 2; // Always true without varint + + return MH_E_NO_ERROR; +} + +int mh_new_length(int code, size_t hash_len) { + // right now there is no varint support + // so length required is 2 + hash_len + UNUSED(code); + return 2 + hash_len; +} + +int mh_new(unsigned char *buffer, int code, const unsigned char *digset, + size_t digset_len) { + if (code & VARINT_MASK) + return MH_E_VARINT_NOT_SUPPORTED; + if (digset_len > 127) + return MH_E_DIGSET_TOO_LONG; + + buffer[0] = (unsigned char) ((unsigned int) code) & 255; + buffer[1] = (unsigned char) digset_len; + memcpy(buffer + 2, digset, digset_len); + + return MH_E_NO_ERROR; +} + diff --git a/tests/c/minunit.h b/tests/c/minunit.h index 83bf5cb..fc37941 100644 --- a/tests/c/minunit.h +++ b/tests/c/minunit.h @@ -4,6 +4,7 @@ #define mu_run_test(test) do { char *message; printf(" - run: %s\n", #test); \ message = test(); tests_run++; \ if (message) return message; } while (0) + int tests_run = 0; static char *mu_all_tests(void); @@ -21,3 +22,31 @@ int main(void) { return result != 0; } +void dump(const unsigned char *data, size_t size) { + char ascii[17]; + size_t i, j; + ascii[16] = '\0'; + for (i = 0; i < size; ++i) { + printf("%02X ", ((unsigned char*)data)[i]); + if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') { + ascii[i % 16] = ((unsigned char*)data)[i]; + } else { + ascii[i % 16] = '.'; + } + if ((i+1) % 8 == 0 || i+1 == size) { + printf(" "); + if ((i+1) % 16 == 0) { + printf("| %s \n", ascii); + } else if (i+1 == size) { + ascii[(i+1) % 16] = '\0'; + if ((i+1) % 16 <= 8) { + printf(" "); + } + for (j = (i+1) % 16; j < 16; ++j) { + printf(" "); + } + printf("| %s \n", ascii); + } + } + } +} diff --git a/tests/c/test_multihash_new.c b/tests/c/test_multihash_new.c new file mode 100644 index 0000000..4f7bc2d --- /dev/null +++ b/tests/c/test_multihash_new.c @@ -0,0 +1,54 @@ +#include +#include "minunit.h" +#include "mh/multihash.h" + +#include "mh/hashes.h" + +#include "examples.h" + +char error_buf[256]; + +static char *test_multihash_new_crafts_right_multihash(void) { + int error; + unsigned char buf[256]; // much bigger than needed + size_t digset_len = -1; + const unsigned char *digset = NULL; + + error = mh_multihash_digset(sha1_example, sha1_example_length, + &digset, &digset_len); + mu_assert("getting digset", error == MH_E_NO_ERROR); + + error = mh_new(buf, MH_H_SHA1, digset, digset_len); + mu_assert("creating multihash", error == MH_E_NO_ERROR); + + mu_assert("crafted multihash is the same", memcmp(sha1_example, buf, + sha1_example_length) == 0); + + return NULL; +} + +static char *test_multihash_new_is_reversible(void) { + int error = MH_E_NO_ERROR; + int code = MH_H_SHA3_512; + const unsigned char *digset = random_512; + const size_t digset_len = 512 / 8; + + unsigned char mh[256]; + const size_t mh_len = mh_new_length(code, digset_len); + + error = mh_new(mh, MH_H_SHA3_512, digset, digset_len); + mu_assert("creating multihash", error == MH_E_NO_ERROR); + + mu_assert("reading code", mh_multihash_hash(mh, mh_len) == MH_H_SHA3_512); + mu_assert("reading length", mh_multihash_length(mh, mh_len) == + (int) digset_len); + + return NULL; +} + +static char *mu_all_tests(void) { + mu_run_test(test_multihash_new_crafts_right_multihash); + mu_run_test(test_multihash_new_is_reversible); + return NULL; +} +