Compare commits

...

38 Commits

Author SHA1 Message Date
Luke Dashjr
b1dd03fa8d Merge commit '66526fb' 2020-10-02 15:49:46 +00:00
Luke Dashjr
f4ef2ae23b Merge branch 'bugfix_test_builddir' 2020-10-02 15:49:38 +00:00
Luke Dashjr
66526fb70f INSTALL: Remove trailing space 2020-10-02 13:14:50 +00:00
Luke Dashjr
c821364d6e Bugfix: Tests need the build directory in PATH, not source directory 2020-10-02 13:12:25 +00:00
Luke Dashjr
d759139844
Merge pull request #11 from CoperNick8/master
Make README as Markdown format
2018-07-03 11:58:41 +00:00
CoperNick8
f0e2b756cd Make README as Markdown format 2018-07-03 13:32:30 +02:00
Luke Dashjr
1c9930a246
Merge pull request #8 from luke-jr/avoid_ssize_t
Avoid ssize_t
2018-06-03 23:14:43 +00:00
Luke Dashjr
afa117ae92
Merge pull request #10 from luke-jr/fix_travis
Fix Travis
2018-06-03 23:05:30 +00:00
Luke Dashjr
9cd68e803e Travis: Update mingw package names 2018-06-03 22:51:33 +00:00
Luke Dashjr
4aaeea028c Avoid ssize_t type, since it is POSIX-specific
Only j could become negative, so we simply check before it would
2018-06-03 22:07:56 +00:00
Luke Dashjr
ccb7b43e9b tests: Check encoding with highest bit set
Detects j dropping below 0 going unchecked.
This bug was originally fixed in 2c6b7916b6, but due to ssize_t being a POSIX extension, we are going to check it manually.
2018-06-03 22:06:15 +00:00
Luke Dashjr
cca7f63c6c
Merge pull request #3 from luke-jr/dyn_intsize
Refactor b58tobin to be more easily reconfigured for using different integer sizes
2018-03-18 19:41:28 +00:00
Luke Dashjr
6b23367527
Merge pull request #5 from randolf/patch-1
Added dependency information in INSTALL about "xxd"
2018-03-18 19:40:57 +00:00
Randolf Richardson
48fdd386d2
Added dependency information about "xxd" 2018-03-18 09:10:25 -07:00
e271828-
1cb26b5bff Add INSTALL, fix README typo. 2017-04-06 11:52:25 -07:00
Jon Griffiths
bee00a6e88 Test case 2016-04-10 14:14:46 +12:00
Jon Griffiths
a861d3c57f Revert variable signedness changes.
In the line:

    for (carry = bin[i], j = size - 1; (j > high) || carry; --j)

my analysis missed that the compare (j > high) is always true when
high is 0 and j wraps around. So although the loop does not store
through a negative 'j' offset, it does require j to become negative
in order to terminate the loop in that case. My apologies.
2016-04-10 02:22:01 +12:00
Jon Griffiths
5df7d3b19a b58enc: Make loop variables unsigned
size can only be positive (and non-zero) as it is set to a positive expr + 1.
high is initialised with size-1 which is never negative, and then set to j at
the end of each loop iteration. It therefore can only be negative if j can.
The heart of the loop assigns to buf[j] which is on the stack. If j can become
negative during the loop then this is clearly undefined behaviour.

Following the loop, high is unused and j is reset to 0 and only incremented.
Thus both variables can be declared unsigned, and sys/types.h removed since
there are no more ssize_t variables remaining. This removes the last two sign
compare warnings from this file.
2016-04-04 21:16:13 +12:00
Jon Griffiths
e77d2999fe b58enc: Make loop variables unsigned
zcount can only ever be positive as it starts from 0 and is incremented.
i can only be positive as it starts from zcount and is incremented. This
removes one of three sign compare warnings in this function.
2016-04-04 21:15:21 +12:00
Luke Dashjr
8a92496475 Refactor b58tobin to be more easily reconfigured for using different integer sizes 2016-03-23 09:12:05 +00:00
Luke Dashjr
ae5fe61864 Travis: Use sudo-less infrastructure, and add simple Win32/64 builds 2016-02-10 05:12:44 +00:00
Luke Dashjr
e28341c60e Travis: Build and run tests 2016-02-04 01:01:45 +00:00
Luke Dashjr
16c2527608 Bump version to 0.1.4 2015-06-05 03:32:21 +00:00
Luke Dashjr
bca0d4bebd Merge remote-tracking branch 'origin-pull/1/head' into HEAD 2015-02-28 02:21:30 +00:00
Luke Dashjr
cdeed0709e tests: Check decode with high bits set fails
This doesn't catch out-of-bounds memory access, but it's a good test to have anyway.
2015-02-28 02:21:00 +00:00
Aaron Voisine
13dfa66514 fix for potential out-of-bounds memory access
if when counting leading zeros an invalid digit is encountered with it's high-bit set, the index into b58digits_map will be out-of-bounds
2015-02-27 12:21:24 -08:00
Luke Dashjr
b6adca8ebb Bugfix: Add missing <sys/types.h> include for ssize_t 2014-11-18 23:15:36 +00:00
Luke Dashjr
4317cf055e Bump version to 0.1.2 2014-10-29 14:31:21 +00:00
Luke Dashjr
2c6b7916b6 Bugfix: Use signed types so that j can go negative without underflow
In some cases, j made it negative which made (j > high) true creating a segfault condition
2014-10-26 00:26:42 +00:00
Luke Dashjr
5d53799021 Adapt tests so they can run with the serial harness used in older automake versions 2014-09-16 07:28:10 +00:00
Luke Dashjr
fa132f17c4 Address most LLVM warnings 2014-09-16 07:27:55 +00:00
Luke Dashjr
6d2d2c5f0e b58tobin: Simplify zeromask calculation (fixes bug encountered when compiling with LLVM) 2014-09-16 02:39:55 +00:00
Luke Dashjr
06e594e37f Include COPYING in dist_doc_DATA 2014-08-31 20:50:45 +00:00
Luke Dashjr
3850beffa1 Merge branch 'master' of github.com:bitcoin/libbase58 2014-08-31 20:50:18 +00:00
Luke Dashjr
619e4e15e3 configure: Check for AM_PATH_LIBGCRYPT macro explicitly, so autogen is possible without libgcrypt 2014-08-29 01:32:17 +00:00
Luke Dashjr
2b70e26f47 AUTHORS: List of contributors 2014-08-29 01:22:33 +00:00
Luke Dashjr
a3f784e608 configure: Require only automake 1.11, since that is sufficient 2014-08-29 01:20:14 +00:00
Wladimir J. van der Laan
a978f5f734 Add COPYING file with MIT license 2014-08-28 16:08:44 +02:00
24 changed files with 195 additions and 67 deletions

48
.travis.yml Normal file
View File

@ -0,0 +1,48 @@
os: linux
language: c
compiler: gcc
sudo: false
matrix:
include:
- compiler: ": Complete"
env: CONFIGURE_OPTS="--enable-tool --enable-static --enable-shared" MAKE_CHECK=1
addons:
apt:
packages:
- build-essential
- libgcrypt11-dev
- compiler: ": No tool/tests"
env: CONFIGURE_OPTS="--disable-tool --enable-static --enable-shared"
addons:
apt:
packages:
- build-essential
- compiler: ": Win32 - No tool/tests"
env: CONFIGURE_OPTS="--disable-tool --host=i686-w64-mingw32 --enable-static --enable-shared"
addons:
apt:
packages:
- gcc-mingw-w64-i686
- binutils-mingw-w64-i686
- mingw-w64-i686-dev
- compiler: ": Win64 - No tool/tests"
env: CONFIGURE_OPTS="--disable-tool --host=x86_64-w64-mingw32 --enable-static --enable-shared"
addons:
apt:
packages:
- gcc-mingw-w64-x86-64
- binutils-mingw-w64-x86-64
- mingw-w64-x86-64-dev
exclude:
- compiler: gcc
install:
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get update; fi
- if [ -n "$PACKAGES" ]; then travis_retry sudo apt-get install --no-install-recommends --no-upgrade -qq $PACKAGES; fi
script:
- unset CC
- ./autogen.sh
- ./configure $CONFIGURE_OPTS || tail -n 1000 config.log
- make
- test -z "$MAKE_CHECK" || make check
- make install DESTDIR=$PWD/ii
- cd ii && find

2
AUTHORS Normal file
View File

@ -0,0 +1,2 @@
Luke Dashjr <luke-jr+libbase58@utopios.org>
Huang Le <4tarhl@gmail.com>

19
COPYING Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2014 Luke Dashjr
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

20
INSTALL Normal file
View File

@ -0,0 +1,20 @@
Installation
--------------------
# Install libgcrypt first, e.g. via `brew install libgcrypt` on OS X or libgcrypt-dev on Linux
# Generate the final build scripts
./autogen.sh
# Build the CLI and library
./configure && make
Dependencies
--------------------
Many of the test scripts depend on the "xxd" tool to convert between hexadecimal and binary.
If this tool is not installed on your Operating System, you can probably get it as part of
the "vim" editor from https://www.vim.org/ or by installing the vim-share package.
Troubleshooting
--------------------
If libgcrypt isn't found after install, set AM_PATH_LIBGCRYPT env var to libgcrypt path
prior to running autogen.sh. For example, on OS X with ver 1.7.6:
export AM_PATH_LIBGCRYPT="/usr/local/Cellar/libgcrypt/1.7.6/lib"

View File

@ -14,7 +14,7 @@ pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libbase58.pc
dist_noinst_SCRIPTS = autogen.sh
dist_doc_DATA = README
dist_doc_DATA = AUTHORS COPYING INSTALL README.md
if USE_TOOL
bin_PROGRAMS = base58
@ -33,9 +33,12 @@ TESTS = \
tests/decode-zero.sh \
tests/encode.sh \
tests/encode-b58c.sh \
tests/encode-b58c-high.sh \
tests/encode-fail.sh \
tests/encode-neg-index.sh \
tests/encode-small.sh
SH_LOG_COMPILER = /bin/sh
AM_TESTS_ENVIRONMENT = PATH='$(srcdir)':"$$PATH"; export PATH;
AM_TESTS_ENVIRONMENT = PATH='$(abs_top_builddir)':"$$PATH"; export PATH;
TESTS_ENVIRONMENT = $(AM_TESTS_ENVIRONMENT)
endif
TEST_EXTENSIONS = .sh

View File

@ -3,8 +3,11 @@ Initialisation
Before you can use libbase58 for base58check, you must provide a SHA256
function. The required function signature is:
bool my_sha256(void *digest, const void *data, size_t datasz)
Simply assign your function to b58_sha256_impl:
b58_sha256_impl = my_sha256;
This is only required if base58check is used. Raw base58 does not need SHA256.
@ -15,7 +18,9 @@ Decoding Base58
Simply allocate a buffer to store the binary data in, and set a variable with
the buffer size, and call the b58tobin function:
bool b58tobin(void *bin, size_t *binsz, const char *b58, size_t b58sz)
The "canonical" base58 byte length will be assigned to binsz on success, which
may be larger than the actual buffer if the input has many leading zeros.
Regardless of the canonical byte length, the full binary buffer will be used.
@ -28,7 +33,9 @@ Validating Base58Check
After calling b58tobin, you can validate base58check data using the b58check
function:
int b58check(const void *bin, size_t binsz, const char *b58, size_t b58sz)
Call it with the same buffers used for b58tobin. If the return value is
negative, an error occurred. Otherwise, the return value is the base58check
"version" byte from the decoded data.
@ -39,7 +46,9 @@ Encoding Base58
Allocate a string to store the base58 content, create a size_t variable with the
size of that allocation, and call:
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
Note that you must pass a pointer to the string size variable, not the size
itself. When b58enc returns, the variable will be modified to contain the actual
number of bytes used (including the null terminator). If encoding fails for any
@ -50,7 +59,8 @@ return false. Otherwise, it returns true to indicate success.
Encoding Base58Check
--------------------
Targetting base58check is done similarly to raw base58 encoding, but you must
Targeting base58check is done similarly to raw base58 encoding, but you must
also provide a version byte:
bool b58check_enc(char *b58c, size_t *b58c_sz, uint8_t ver,
const void *data, size_t datasz)

View File

@ -16,6 +16,8 @@
#include <stdint.h>
#include <string.h>
#include "libbase58.h"
bool (*b58_sha256_impl)(void *, const void *, size_t) = NULL;
static const int8_t b58digits_map[] = {
@ -29,27 +31,34 @@ static const int8_t b58digits_map[] = {
47,48,49,50,51,52,53,54, 55,56,57,-1,-1,-1,-1,-1,
};
typedef uint64_t b58_maxint_t;
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);
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 + 3) / 4;
uint32_t outi[outisz];
uint64_t t;
uint32_t c;
size_t outisz = (binsz + sizeof(b58_almostmaxint_t) - 1) / sizeof(b58_almostmaxint_t);
b58_almostmaxint_t outi[outisz];
b58_maxint_t t;
b58_almostmaxint_t c;
size_t i, j;
uint8_t bytesleft = binsz % 4;
uint32_t zeromask = ~((1 << ((bytesleft ?: 4) * 8)) - 1);
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);
memset(outi, 0, outisz * sizeof(*outi));
for (i = 0; i < outisz; ++i) {
outi[i] = 0;
}
// Leading zeros, just count
for (i = 0; i < b58sz && !b58digits_map[b58u[i]]; ++i)
for (i = 0; i < b58sz && b58u[i] == '1'; ++i)
++zerocount;
for ( ; i < b58sz; ++i)
@ -60,12 +69,12 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
if (b58digits_map[b58u[i]] == -1)
// Invalid base58 digit
return false;
c = b58digits_map[b58u[i]];
c = (unsigned)b58digits_map[b58u[i]];
for (j = outisz; j--; )
{
t = ((uint64_t)outi[j]) * 58 + c;
c = (t & 0x3f00000000) >> 32;
outi[j] = t & 0xffffffff;
t = ((b58_maxint_t)outi[j]) * 58 + c;
c = t >> b58_almostmaxint_bits;
outi[j] = t & b58_almostmaxint_mask;
}
if (c)
// Output number too big (carry to the next int32)
@ -76,24 +85,18 @@ bool b58tobin(void *bin, size_t *binszp, const char *b58, size_t b58sz)
}
j = 0;
switch (bytesleft) {
case 3:
*(binu++) = (outi[0] & 0xff0000) >> 16;
case 2:
*(binu++) = (outi[0] & 0xff00) >> 8;
case 1:
*(binu++) = (outi[0] & 0xff);
++j;
default:
break;
if (bytesleft) {
for (i = bytesleft; i > 0; --i) {
*(binu++) = (outi[0] >> (8 * (i - 1))) & 0xff;
}
++j;
}
for (; j < outisz; ++j)
{
*(binu++) = outi[j] >> 0x18;
*(binu++) = outi[j] >> 0x10;
*(binu++) = outi[j] >> 8;
*(binu++) = outi[j];
for (i = sizeof(*outi); i > 0; --i) {
*(binu++) = (outi[j] >> (8 * (i - 1))) & 0xff;
}
}
// Count canonical base58 byte count
@ -142,7 +145,8 @@ static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdef
bool b58enc(char *b58, size_t *b58sz, const void *data, size_t binsz)
{
const uint8_t *bin = data;
int i, j, carry, high, zcount = 0;
int carry;
size_t i, j, high, zcount = 0;
size_t size;
while (zcount < binsz && !bin[zcount])
@ -159,6 +163,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;
}
}
}

View File

@ -36,7 +36,7 @@ void usage(const char *prog)
int main(int argc, char **argv)
{
bool b58c = false;
int decode = 0;
size_t decode = 0;
int opt;
while ( (opt = getopt(argc, argv, "cd:h")) != -1)
{
@ -47,34 +47,39 @@ int main(int argc, char **argv)
b58_sha256_impl = my_sha256;
break;
case 'd':
decode = atoi(optarg);
{
int i = atoi(optarg);
if (i < 0 || (uintmax_t)i >= SIZE_MAX)
usage(argv[0]);
decode = (size_t)i;
break;
}
default:
usage(argv[0]);
}
}
size_t rt;
void *r;
union {
uint8_t *b;
char *s;
} r;
if (optind >= argc)
{
rt = 0;
r = NULL;
r.b = NULL;
while (!feof(stdin))
{
r = realloc(r, rt + 0x100);
rt += fread(r + rt, 1, 0x100, stdin);
r.b = realloc(r.b, rt + 0x100);
rt += fread(&r.b[rt], 1, 0x100, stdin);
}
if (decode)
{
char *rs = r;
while (isspace(rs[rt-1]))
while (isspace(r.s[rt-1]))
--rt;
}
}
else
{
r = argv[optind];
r.s = argv[optind];
rt = strlen(argv[optind]);
}
@ -82,11 +87,11 @@ int main(int argc, char **argv)
{
uint8_t bin[decode];
size_t ssz = decode;
if (!b58tobin(bin, &ssz, r, rt))
if (!b58tobin(bin, &ssz, r.s, rt))
return 2;
if (b58c)
{
int chk = b58check(bin, decode, r, rt);
int chk = b58check(bin, decode, r.s, rt);
if (chk < 0)
return chk;
if (fwrite(bin, decode, 1, stdout) != 1)
@ -115,15 +120,11 @@ int main(int argc, char **argv)
char s[ssz];
bool rv;
if (b58c)
{
uint8_t *verbyte = r;
r += 1;
rv = rt && b58check_enc(s, &ssz, *verbyte, r, rt-1);
}
rv = rt && b58check_enc(s, &ssz, r.b[0], &r.b[1], rt-1);
else
rv = b58enc(s, &ssz, r, rt);
rv = b58enc(s, &ssz, r.b, rt);
if (!rv)
return 2;
puts(s);
}
}
}

View File

@ -5,12 +5,12 @@ dnl * under the terms of the standard MIT license. See COPYING for more details
AC_INIT(
[libbase58],
[0.1],
[0.1.4],
[luke_libbase58@dashjr.org],
[libbase58])
AC_CONFIG_AUX_DIR([.])
AC_PREREQ([2.59])
AM_INIT_AUTOMAKE([1.12 -Wall dist-xz foreign])
AM_INIT_AUTOMAKE([1.11 -Wall dist-xz foreign])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CC_C99
@ -18,7 +18,7 @@ m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT([])
# http://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
AC_SUBST([LIBBASE58_SO_VERSION], [0:0:0])
AC_SUBST([LIBBASE58_SO_VERSION], [0:2:0])
AC_CONFIG_FILES([Makefile
libbase58.pc:libbase58.pc.in
@ -26,20 +26,24 @@ AC_CONFIG_FILES([Makefile
AC_CHECK_LIB([ws2_32], [strchr])
AC_ARG_ENABLE([tool],
[AC_HELP_STRING([--disable-tool],[Compile command line base58 tool (default enabled)])],
[use_tool=$enableval],
[use_tool=auto])
if test x$use_tool != xno; then
AM_PATH_LIBGCRYPT([],[
use_tool=yes
],[
if test x$use_tool = xyes; then
AC_MSG_ERROR([libgcrypt not found; use --disable-tool])
fi
use_tool=no
])
fi
m4_ifdef([AM_PATH_LIBGCRYPT], [
AC_ARG_ENABLE([tool],
[AC_HELP_STRING([--disable-tool],[Compile command line base58 tool (default enabled)])],
[use_tool=$enableval],
[use_tool=auto])
if test x$use_tool != xno; then
AM_PATH_LIBGCRYPT([],[
use_tool=yes
],[
if test x$use_tool = xyes; then
AC_MSG_ERROR([libgcrypt not found; use --disable-tool])
fi
use_tool=no
])
fi
],[
m4_warn([syntax], [AM_PATH_LIBGCRYPT missing; CLI tool will not be available])
])
AM_CONDITIONAL([USE_TOOL], [test x$use_tool = xyes])
AC_OUTPUT

0
tests/decode-b58c-fail.sh Normal file → Executable file
View File

0
tests/decode-b58c-null.sh Normal file → Executable file
View File

0
tests/decode-b58c-toolong.sh Normal file → Executable file
View File

0
tests/decode-b58c-tooshort.sh Normal file → Executable file
View File

0
tests/decode-b58c.sh Normal file → Executable file
View File

View File

@ -0,0 +1,3 @@
#!/bin/sh
hex=$(echo 993233 | xxd -r -p | base58 -d 25 || echo FAIL)
test "x${hex}" = "xFAIL"

3
tests/decode-highbit.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/sh
hex=$(echo 319932 | xxd -r -p | base58 -d 25 || echo FAIL)
test "x${hex}" = "xFAIL"

0
tests/decode-small.sh Normal file → Executable file
View File

0
tests/decode-zero.sh Normal file → Executable file
View File

0
tests/decode.sh Normal file → Executable file
View File

3
tests/encode-b58c-high.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
b58=$(echo 'ff5a1fc5dd9e6f03819fca94a2d89669469667f9a0' | xxd -r -p | base58 -c)
test x$b58 = x2mkQLxaN3Y4CwN5E9rdMWNgsXX7VS6UnfeT

0
tests/encode-b58c.sh Normal file → Executable file
View File

0
tests/encode-fail.sh Normal file → Executable file
View File

4
tests/encode-neg-index.sh Executable file
View File

@ -0,0 +1,4 @@
#!/bin/sh
# This input causes the loop iteration counter to go negative
b58=$(echo '00CEF022FA' | xxd -r -p | base58)
test x$b58 = x16Ho7Hs

0
tests/encode-small.sh Normal file → Executable file
View File