add multihash encoding
refactor to use size_t
This commit is contained in:
parent
f3d2a1fd95
commit
e0781d0536
8 changed files with 174 additions and 11 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -1,10 +1,28 @@
|
|||
#ifndef MH_HULTIHASH_H
|
||||
#define MH_HULTIHASH_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
// 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 */
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -2,15 +2,30 @@
|
|||
|
||||
#include "mh/hashes.h"
|
||||
#include "mh/errors.h"
|
||||
#include "mh/generic.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
54
tests/c/test_multihash_new.c
Normal file
54
tests/c/test_multihash_new.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
|
Loading…
Reference in a new issue