From a996f28059d8c3282b4b525ea594f9799c9fbbec Mon Sep 17 00:00:00 2001 From: Holland Schutte Date: Sat, 2 Jun 2018 23:50:27 -0700 Subject: [PATCH 1/6] support for compilers which don't support dynamic array initialization syntax --- base58.c | 109 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 81 insertions(+), 28 deletions(-) diff --git a/base58.c b/base58.c index 71e687f..e5a11af 100644 --- a/base58.c +++ b/base58.c @@ -9,12 +9,15 @@ #include #else #include +#include #endif + #include #include #include #include +#include #include #include "libbase58.h" @@ -37,39 +40,70 @@ typedef uint32_t b58_almostmaxint_t; #define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) static const b58_almostmaxint_t b58_almostmaxint_mask = ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); +#define b58_log_err(msg, ...) applog(LOG_ERR, "[" __FUNCTION__ " - ERROR]: " msg, __VA_ARGS__) + +/* MSVC 2013 doesn't support the GCC (and probably clang) extension + for dynamic arrays in C */ +#ifdef _WIN32 +#define b58_alloc_mem(type, name, count) \ + type *name = NULL; \ + do { \ + name = calloc(count, sizeof(type)); \ + if (!name) { \ + b58_log_err("%s", "Could not allocate " #name); \ + return false; \ + } \ + } while (0) + +#define b58_free_mem(v) \ + do { \ + if ((v)) { \ + free((v)); \ + } \ + } while (0) +#else +/* not sure if this compiles */ +#define b58_alloc_mem(type, name, count) type name[count] +#define b58_free_mem +#endif + bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) { size_t binsz = *binszp; const unsigned char *b58u = (void*)b58; unsigned char *binu = bin; size_t outisz = (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t); - b58_almostmaxint_t outi[outisz]; + + /*b58_almostmaxint_t outi[outisz];*/ + + b58_alloc_mem(b58_almostmaxint_t, outi, outisz); + b58_maxint_t t; b58_almostmaxint_t c; size_t i, j; uint8_t bytesleft = binsz % sizeof(b58_almostmaxint_t); b58_almostmaxint_t zeromask = bytesleft ? (b58_almostmaxint_mask << (bytesleft * 8)) : 0; unsigned zerocount = 0; - + if (!b58sz) b58sz = strlen(b58); - + for (i = 0; i < outisz; ++i) { outi[i] = 0; } - + // Leading zeros, just count for (i = 0; i < b58sz && b58u[i] == '1'; ++i) ++zerocount; - + for ( ; i < b58sz; ++i) { if (b58u[i] & 0x80) // High-bit set on invalid digit - return false; + goto ret_false; if (b58digits_map[b58u[i]] == -1) // Invalid base58 digit - return false; + goto ret_false; c = (unsigned)b58digits_map[b58u[i]]; for (j = outisz; j--; ) { @@ -79,12 +113,12 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) } if (c) // Output number too big (carry to the next int32) - return false; + goto ret_false; if (outi[0] & zeromask) // Output number too big (last int32 filled too far) - return false; + goto ret_false; } - + j = 0; if (bytesleft) { for (i = bytesleft; i > 0; --i) { @@ -92,14 +126,14 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) } ++j; } - + for (; j < outisz; ++j) { for (i = sizeof(*outi); i > 0; --i) { *(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff; } } - + // Count canonical base58 byte count binu = bin; for (i = 0; i < binsz; ++i) @@ -109,8 +143,13 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) --*binszp; } *binszp += zerocount; - + + b58_free_mem(outi); return true; + +ret_false: + b58_free_mem(outi); + return false; } static @@ -131,13 +170,13 @@ int b58check(const void *bin, size_t binsz, const char *base58str, size_t b58sz) return -2; if (memcmp(&binc[binsz - 4], buf, 4)) return -1; - + // Check number of zeros is correct AFTER verifying checksum (to avoid possibility of accessing base58str beyond the end) for (i = 0; binc[i] == '\0' && base58str[i] == '1'; ++i) {} // Just finding the end of zeros, nothing to do in loop if (binc[i] == '\0' || base58str[i] == '1') return -3; - + return binc[0]; } @@ -149,14 +188,16 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) int carry; ssize_t i, j, high, zcount = 0; size_t size; - + while (zcount < binsz && !bin[zcount]) ++zcount; - + size = (binsz - zcount) * 138 / 100 + 1; - uint8_t buf[size]; + /*uint8_t buf[size];*/ + + b58_alloc_mem(uint8_t, buf, size); memset(buf, 0, size); - + for (i = zcount, high = size - 1; i < binsz; ++i, high = j) { for (carry = bin[i], j = size - 1; (j > high) || carry; --j) @@ -166,37 +207,49 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) carry /= 58; } } - + for (j = 0; j < size && !buf[j]; ++j); - + if (*b58sz <= zcount + size - j) { *b58sz = zcount + size - j + 1; - return false; + + goto error; } - + if (zcount) memset(b58, '1', zcount); for (i = zcount; j < size; ++i, ++j) b58[i] = b58digits_ordered[buf[j]]; b58[i] = '\0'; *b58sz = i + 1; - + return true; + +error: + b58_free_mem(buf); + return false; } bool b58check_enc(char *b58c, size_t *b58c_sz, uint8_t ver, const void *data, size_t datasz) { - uint8_t buf[1 + datasz + 0x20]; + /*uint8_t buf[1 + datasz + 0x20];*/ + + b58_alloc_mem(uint8_t, buf, 1 + datasz + 0x20); + uint8_t *hash = &buf[1 + datasz]; - + buf[0] = ver; memcpy(&buf[1], data, datasz); if (!my_dblsha256(hash, buf, datasz + 1)) { *b58c_sz = 0; + + b58_free_mem(buf); return false; } - - return b58enc(b58c, b58c_sz, buf, 1 + datasz + 4); + + bool rc = b58enc(b58c, b58c_sz, buf, 1 + datasz + 4); + b58_free_mem(buf); + return rc; } From 47a859290008acbe61f3fde410d52fdca7f75ed4 Mon Sep 17 00:00:00 2001 From: Holland Schutte Date: Sun, 3 Jun 2018 00:08:58 -0700 Subject: [PATCH 2/6] windows compat --- base58.c | 34 +++++++++++++++++++++------------- libbase58.h | 1 + 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/base58.c b/base58.c index e5a11af..af741b1 100644 --- a/base58.c +++ b/base58.c @@ -5,22 +5,31 @@ * under the terms of the standard MIT license. See COPYING for more details. */ -#ifndef WIN32 +#include "libbase58.h" + +#ifndef _WIN32 #include #else #include #include -#endif +#include + +#ifdef _WIN64 +typedef int64_t ssize_t; +#else +typedef int32_t ssize_t; +#endif +#endif #include #include -#include #include #include + #include -#include "libbase58.h" + bool (*b58_sha256_impl)(void *, const void *, size_t) = NULL; @@ -40,11 +49,11 @@ typedef uint32_t b58_almostmaxint_t; #define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) static const b58_almostmaxint_t b58_almostmaxint_mask = ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); -#define b58_log_err(msg, ...) applog(LOG_ERR, "[" __FUNCTION__ " - ERROR]: " msg, __VA_ARGS__) - -/* MSVC 2013 doesn't support the GCC (and probably clang) extension - for dynamic arrays in C */ +// MSVC 2013 doesn't support the GCC (and probably clang) extension +// for dynamic arrays in C #ifdef _WIN32 +#define b58_log_err(msg, ...) printf("[" __FUNCTION__ " - ERROR]: " msg, __VA_ARGS__) + #define b58_alloc_mem(type, name, count) \ type *name = NULL; \ do { \ @@ -62,9 +71,8 @@ static const b58_almostmaxint_t b58_almostmaxint_mask = ((((b58_maxint_t)1) << b } \ } while (0) #else -/* not sure if this compiles */ #define b58_alloc_mem(type, name, count) type name[count] -#define b58_free_mem +#define b58_free_mem(v) #endif bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) @@ -74,7 +82,7 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz) unsigned char *binu = bin; size_t outisz = (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t); - /*b58_almostmaxint_t outi[outisz];*/ + // b58_almostmaxint_t outi[outisz]; b58_alloc_mem(b58_almostmaxint_t, outi, outisz); @@ -193,7 +201,7 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) ++zcount; size = (binsz - zcount) * 138 / 100 + 1; - /*uint8_t buf[size];*/ + //uint8_t buf[size]; b58_alloc_mem(uint8_t, buf, size); memset(buf, 0, size); @@ -233,7 +241,7 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) bool b58check_enc(char *b58c, size_t *b58c_sz, uint8_t ver, const void *data, size_t datasz) { - /*uint8_t buf[1 + datasz + 0x20];*/ + //uint8_t buf[1 + datasz + 0x20]; b58_alloc_mem(uint8_t, buf, 1 + datasz + 0x20); diff --git a/libbase58.h b/libbase58.h index fafe653..fe52ac6 100644 --- a/libbase58.h +++ b/libbase58.h @@ -3,6 +3,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { From 4690c5d3c1d1d56d10fccb12e7d98b8b31d9cc06 Mon Sep 17 00:00:00 2001 From: Holland Schutte Date: Sun, 3 Jun 2018 00:10:02 -0700 Subject: [PATCH 3/6] tested extension with msvc 2017; it doesn't work either --- base58.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base58.c b/base58.c index af741b1..ed4cfc5 100644 --- a/base58.c +++ b/base58.c @@ -49,7 +49,7 @@ typedef uint32_t b58_almostmaxint_t; #define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) static const b58_almostmaxint_t b58_almostmaxint_mask = ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); -// MSVC 2013 doesn't support the GCC (and probably clang) extension +// MSVC 2017 doesn't support the GCC (and probably clang) extension // for dynamic arrays in C #ifdef _WIN32 #define b58_log_err(msg, ...) printf("[" __FUNCTION__ " - ERROR]: " msg, __VA_ARGS__) From ccb7b43e9b2c72c596d65715222d2a990f99fa39 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sun, 3 Jun 2018 22:06:13 +0000 Subject: [PATCH 4/6] tests: Check encoding with highest bit set Detects j dropping below 0 going unchecked. This bug was originally fixed in 2c6b7916b604b946904428466ff0271a35535297, but due to ssize_t being a POSIX extension, we are going to check it manually. --- Makefile.am | 1 + tests/encode-b58c-high.sh | 3 +++ 2 files changed, 4 insertions(+) create mode 100755 tests/encode-b58c-high.sh diff --git a/Makefile.am b/Makefile.am index f870182..f51e2c0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,6 +33,7 @@ TESTS = \ tests/decode-zero.sh \ tests/encode.sh \ tests/encode-b58c.sh \ + tests/encode-b58c-high.sh \ tests/encode-fail.sh \ tests/encode-small.sh SH_LOG_COMPILER = /bin/sh diff --git a/tests/encode-b58c-high.sh b/tests/encode-b58c-high.sh new file mode 100755 index 0000000..6c788f6 --- /dev/null +++ b/tests/encode-b58c-high.sh @@ -0,0 +1,3 @@ +#!/bin/sh +b58=$(echo 'ff5a1fc5dd9e6f03819fca94a2d89669469667f9a0' | xxd -r -p | base58 -c) +test x$b58 = x2mkQLxaN3Y4CwN5E9rdMWNgsXX7VS6UnfeT From 4aaeea028cba3c93b3d62063f07d94681af9791c Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sun, 3 Jun 2018 22:07:53 +0000 Subject: [PATCH 5/6] Avoid ssize_t type, since it is POSIX-specific Only j could become negative, so we simply check before it would --- base58.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/base58.c b/base58.c index 33566e0..810ebbe 100644 --- a/base58.c +++ b/base58.c @@ -15,7 +15,6 @@ #include #include #include -#include #include "libbase58.h" @@ -146,7 +145,7 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) { const uint8_t *bin = data; int carry; - ssize_t i, j, high, zcount = 0; + size_t i, j, high, zcount = 0; size_t size; while (zcount < binsz && !bin[zcount]) @@ -163,6 +162,10 @@ bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz) carry += 256 * buf[j]; buf[j] = carry % 58; carry /= 58; + if (!j) { + // Otherwise j wraps to maxint which is > high + break; + } } } From 7bd15e347d3a2881a696afa9413de5f430ff98db Mon Sep 17 00:00:00 2001 From: Holland Schutte Date: Sun, 3 Jun 2018 16:05:06 -0700 Subject: [PATCH 6/6] requested modifications for MSVC fix --- base58.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/base58.c b/base58.c index c2f7260..bf69844 100644 --- a/base58.c +++ b/base58.c @@ -11,15 +11,17 @@ #include #else #include +#ifdef _MSC_VER #include - #include #endif +#endif #include #include #include #include +#include #include @@ -41,26 +43,25 @@ typedef uint32_t b58_almostmaxint_t; #define b58_almostmaxint_bits (sizeof(b58_almostmaxint_t) * 8) static const b58_almostmaxint_t b58_almostmaxint_mask = ((((b58_maxint_t)1) << b58_almostmaxint_bits) - 1); -// MSVC 2017 doesn't support the GCC (and probably clang) extension -// for dynamic arrays in C -#ifdef _WIN32 +// MSVC 2017 C99 doesn't support dynamic arrays in C +#ifdef _MSC_VER #define b58_log_err(msg, ...) printf("[" __FUNCTION__ " - ERROR]: " msg, __VA_ARGS__) -#define b58_alloc_mem(type, name, count) \ - type *name = NULL; \ - do { \ - name = calloc(count, sizeof(type)); \ - if (!name) { \ +#define b58_alloc_mem(type, name, count) \ + type *name = NULL; \ + do { \ + name = _malloca(count * sizeof(type)); \ + if (!name) { \ b58_log_err("%s", "Could not allocate " #name); \ - return false; \ - } \ + return false; \ + } \ } while (0) -#define b58_free_mem(v) \ - do { \ - if ((v)) { \ - free((v)); \ - } \ +#define b58_free_mem(v) \ + do { \ + if ((v)) { \ + _freea((v)); \ + } \ } while (0) #else #define b58_alloc_mem(type, name, count) type name[count]