diff --git a/configure.ac b/configure.ac index ea90ec33..46a09ff5 100644 --- a/configure.ac +++ b/configure.ac @@ -32,7 +32,7 @@ AC_FUNC_ALLOCA PKG_PROG_PKG_CONFIG() AC_CHECK_HEADERS(stdio.h stdlib.h fcntl.h sys/time.h unistd.h) -AC_CHECK_HEADERS(ctype.h errno.h byteswap.h) +AC_CHECK_HEADERS(ctype.h errno.h byteswap.h string.h) AC_CHECK_HEADERS(endian.h sys/endian.h arpa/inet.h) AC_CHECK_HEADERS(alloca.h pthread.h) AC_CHECK_HEADERS(sys/types.h sys/socket.h) diff --git a/src/ckpool.h b/src/ckpool.h index 7b6f4ff8..5be7fb14 100644 --- a/src/ckpool.h +++ b/src/ckpool.h @@ -67,6 +67,9 @@ #define __maybe_unused __attribute__((unused)) #define uninitialised_var(x) x = x +/* Typedefs are evil but we use this one so often... */ +typedef unsigned char uchar; + static inline void swap_256(void *dest_p, const void *src_p) { uint32_t *dest = dest_p; diff --git a/src/libckpool.c b/src/libckpool.c index 7e5167d0..e9f78aa4 100644 --- a/src/libckpool.c +++ b/src/libckpool.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include "ckpool.h" #include "libckpool.h" @@ -34,3 +37,158 @@ void keep_sockalive(int fd) setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &tcp_keepidle, sizeof(tcp_keepidle)); setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &tcp_keepintvl, sizeof(tcp_keepintvl)); } + +/* Align a size_t to 4 byte boundaries for fussy arches */ +void align_len(size_t *len) +{ + if (*len % 4) + *len += 4 - (*len % 4); +} + +/* Adequate size s==len*2 + 1 must be alloced to use this variant */ +void __bin2hex(uchar *s, const uchar *p, size_t len) +{ + static const char hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + int i; + + for (i = 0; i < (int)len; i++) { + *s++ = hex[p[i] >> 4]; + *s++ = hex[p[i] & 0xF]; + } + *s++ = '\0'; +} + +/* Returns a malloced array string of a binary value of arbitrary length. The + * array is rounded up to a 4 byte size to appease architectures that need + * aligned array sizes */ +void *bin2hex(const uchar *p, size_t len) +{ + size_t slen; + uchar *s; + + slen = len * 2 + 1; + align_len(&slen); + s = calloc(slen, 1); + if (likely(s)) + __bin2hex(s, p, len); + + /* Returns NULL if calloc failed. */ + return s; +} + +static const int hex2bin_tbl[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; + +/* Does the reverse of bin2hex but does not allocate any ram */ +bool hex2bin(uchar *p, const uchar *hexstr, size_t len) +{ + int nibble1, nibble2; + uchar idx; + bool ret = false; + + while (*hexstr && len) { + if (unlikely(!hexstr[1])) + return ret; + + idx = *hexstr++; + nibble1 = hex2bin_tbl[idx]; + idx = *hexstr++; + nibble2 = hex2bin_tbl[idx]; + + if (unlikely((nibble1 < 0) || (nibble2 < 0))) + return ret; + + *p++ = (((uchar)nibble1) << 4) | ((uchar)nibble2); + --len; + } + + if (likely(len == 0 && *hexstr == 0)) + ret = true; + return ret; +} + +static const int b58tobin_tbl[] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, -1, -1, -1, -1, -1, -1, + -1, 9, 10, 11, 12, 13, 14, 15, 16, -1, 17, 18, 19, 20, 21, -1, + 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1, -1, -1, + -1, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, -1, 44, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57 +}; + +/* b58bin should always be at least 25 bytes long and already checked to be + * valid. */ +void b58tobin(uchar *b58bin, const uchar *b58) +{ + uint32_t c, bin32[7]; + int len, i, j; + uint64_t t; + + memset(bin32, 0, 7 * sizeof(uint32_t)); + len = strlen((const char *)b58); + for (i = 0; i < len; i++) { + c = b58[i]; + c = b58tobin_tbl[c]; + for (j = 6; j >= 0; j--) { + t = ((uint64_t)bin32[j]) * 58 + c; + c = (t & 0x3f00000000ull) >> 32; + bin32[j] = t & 0xffffffffull; + } + } + *(b58bin++) = bin32[0] & 0xff; + for (i = 1; i < 7; i++) { + *((uint32_t *)b58bin) = htobe32(bin32[i]); + b58bin += sizeof(uint32_t); + } +} + +void address_to_pubkeyhash(uchar *pkh, const uchar *addr) +{ + uchar b58bin[25]; + + memset(b58bin, 0, 25); + b58tobin(b58bin, addr); + pkh[0] = 0x76; + pkh[1] = 0xa9; + pkh[2] = 0x14; + memcpy(&pkh[3], &b58bin[1], 20); + pkh[23] = 0x88; + pkh[24] = 0xac; +} + +/* For encoding nHeight into coinbase, return how many bytes were used */ +int ser_number(uchar *s, int32_t val) +{ + int32_t *i32 = (int32_t *)&s[1]; + int len; + + if (val < 128) + len = 1; + else if (val < 16512) + len = 2; + else if (val < 2113664) + len = 3; + else + len = 4; + *i32 = htole32(val); + s[0] = len++; + return len; +} diff --git a/src/libckpool.h b/src/libckpool.h index a169170c..a0b8cc76 100644 --- a/src/libckpool.h +++ b/src/libckpool.h @@ -12,6 +12,15 @@ #ifndef LIBCKPOOL_H #define LIBCKPOOL_H +#include + void keep_sockalive(int fd); +void align_len(size_t *len); +void __bin2hex(uchar *s, const uchar *p, size_t len); +void *bin2hex(const uchar *p, size_t len); +bool hex2bin(uchar *p, const uchar *hexstr, size_t len); +void b58tobin(uchar *b58bin, const uchar *b58); +void address_to_pubkeyhash(uchar *pkh, const uchar *addr); +int ser_number(uchar *s, int32_t val); #endif /* LIBCKPOOL_H */