diff --git a/Makefile.am b/Makefile.am index dad5bff..8a02a9b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4,6 +4,7 @@ lib_LTLIBRARIES = \ libblkmaker_@LIBBLKMAKER_API_VERSION@_la_SOURCES = \ + base58.c \ blkmaker.c \ blktemplate.c \ hex.c diff --git a/base58.c b/base58.c new file mode 100644 index 0000000..4a73849 --- /dev/null +++ b/base58.c @@ -0,0 +1,129 @@ +#ifndef WIN32 +#include +#else +#include +#endif + +#include +#include +#include + +#include + +#include "private.h" + +static const int8_t b58digits[] = { + -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,-1,-1,-1,-1,-1, +}; + +bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz) { + 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 i, j; + uint8_t bytesleft = binsz % 4; + uint32_t zeromask = ~((1 << ((bytesleft) * 8)) - 1); + + if (!b58sz) + b58sz = strlen(b58); + + memset(outi, 0, outisz * sizeof(*outi)); + + for (i = 0; i < b58sz; ++i) + { + if (b58u[i] & 0x80) + // High-bit set on invalid digit + return false; + if (b58digits[b58u[i]] == -1) + // Invalid base58 digit + return false; + c = b58digits[b58u[i]]; + for (j = outisz; j--; ) + { + t = ((uint64_t)outi[j]) * 58 + c; + c = (t & 0x3f00000000) >> 32; + outi[j] = t & 0xffffffff; + } + if (c) + // Output number too big (carry to the next int32) + return false; + if (outi[0] & zeromask) + // Output number too big (last int32 filled too far) + return false; + } + + 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; + } + + for (; j < outisz; ++j) + { + *((uint32_t*)binu) = htonl(outi[j]); + binu += sizeof(uint32_t); + } + return true; +} + +int _blkmk_b58check(void *bin, size_t binsz) { + unsigned char buf[32]; + unsigned char *binc = bin; + if (!_blkmk_dblsha256(buf, bin, binsz - 4)) + return -2; + if (memcmp(&binc[binsz - 4], buf, 4)) + return -1; + return binc[0]; +} + +size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr) { + unsigned char addrbin[25]; + unsigned char *cout = out; + int addrver; + size_t rv; + + if (!_blkmk_b58tobin(addrbin, sizeof(addrbin), addr, 0)) + return 0; + addrver = _blkmk_b58check(addrbin, sizeof(addrbin)); + switch (addrver) { + case 0: // Bitcoin pubkey hash + case 111: // Testnet pubkey hash + if (outsz < (rv = 24)) + return rv; + cout[ 0] = 0x76; // OP_DUP + cout[ 1] = 0xa9; // OP_HASH160 + cout[ 2] = 0x14; // push 20 bytes + memcpy(&cout[3], &addrbin[1], 20); + cout[22] = 0x88; // OP_EQUALVERIFY + cout[23] = 0xac; // OP_CHECKSIG + return rv; + case 5: // Bitcoin script hash + case 196: // Testnet script hash + if (outsz < (rv = 22)) + return rv; + cout[ 0] = 0xa9; // OP_HASH160 + cout[ 1] = 0x14; // push 20 bytes + memcpy(&cout[2], &addrbin[1], 20); + cout[21] = 0x87; // OP_EQUAL + return rv; + default: + return 0; + } +} diff --git a/blkmaker.c b/blkmaker.c index cc7f109..31530e4 100644 --- a/blkmaker.c +++ b/blkmaker.c @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -8,6 +9,8 @@ #include #include +#include "private.h" + static inline void my_htole32(unsigned char *buf, uint32_t n) { buf[0] = (n >> 0) % 256; @@ -16,6 +19,12 @@ void my_htole32(unsigned char *buf, uint32_t n) { buf[3] = (n >> 24) % 256; } +static inline +void my_htole64(unsigned char *buf, uint64_t n) { + for (int i = 0; i < 8; ++i) + buf[i] = (n >> (8*i)) & 0xff; +} + bool (*blkmk_sha256_impl)(void *, const void *, size_t) = NULL; @@ -25,6 +34,46 @@ bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz) { #define dblsha256 _blkmk_dblsha256 +uint64_t blkmk_init_generation(blktemplate_t *tmpl, void *script, size_t scriptsz) { + if (tmpl->cbtxn) + return 0; + + // Skip "no extranonce" scriptSig, since it would be too short (min 2 bytes) + ++tmpl->next_dataid; + + size_t datasz = 60 + scriptsz; + unsigned char *data = malloc(datasz); + if (!data) + return 0; + + memcpy(&data[0], + "\x01\0\0\0" // txn ver + "\x01" // input count + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" // prevout + "\xff\xff\xff\xff" // index (-1) + "\0" // scriptSig length (0; extranonce will bring up to 4) + "\xff\xff\xff\xff" // sequence + "\x01" // output count + , 47); + my_htole64(&data[47], tmpl->cbvalue); + data[55] = scriptsz; + memcpy(&data[56], script, scriptsz); + memset(&data[56 + scriptsz], 0, 4); // lock time + + struct blktxn_t *txn = calloc(1, sizeof(*tmpl->cbtxn)); + if (!tmpl->cbtxn) + { + free(data); + return 0; + } + + txn->data = data; + txn->datasz = datasz; + + tmpl->cbtxn = txn; + return tmpl->cbvalue; +} + static bool build_merkle_root(unsigned char *mrklroot_out, blktemplate_t *tmpl, unsigned char *cbtxndata, size_t cbtxndatasz) { size_t hashcount = tmpl->txncount + 1; diff --git a/blkmaker.h b/blkmaker.h index 10680d4..5523a27 100644 --- a/blkmaker.h +++ b/blkmaker.h @@ -2,6 +2,7 @@ #define BLKMAKER_H #include +#include #include @@ -10,6 +11,7 @@ extern bool (*blkmk_sha256_impl)(void *hash_out, const void *data, size_t datasz); +extern uint64_t blkmk_init_generation(blktemplate_t *, void *script, size_t scriptsz); extern ssize_t blkmk_append_coinbase_safe(blktemplate_t *, const void *append, size_t appendsz); extern bool _blkmk_extranonce(blktemplate_t *tmpl, void *vout, unsigned int workid, size_t *offs); extern size_t blkmk_get_data(blktemplate_t *, void *buf, size_t bufsz, time_t usetime, int16_t *out_expire, unsigned int *out_dataid); @@ -17,4 +19,6 @@ extern blktime_diff_t blkmk_time_left(const blktemplate_t *, time_t nowtime); extern unsigned long blkmk_work_left(const blktemplate_t *); #define BLKMK_UNLIMITED_WORK_COUNT ULONG_MAX +extern size_t blkmk_address_to_script(void *out, size_t outsz, const char *addr); + #endif diff --git a/example.c b/example.c index 04fd264..5d68e6f 100644 --- a/example.c +++ b/example.c @@ -9,8 +9,22 @@ #include #include +#include "private.h" #include "testinput.c" +void testb58() { + char bufx[26] = {'\xff'}; + char *buf = &bufx[1]; + if (!_blkmk_b58tobin(buf, 25, "1Baf75Ferj6A7AoN565gCQj9kGWbDMHfN9", 0)) + exit(1); + if (bufx[0] != '\xff') + exit(2); + char cbuf[51]; + _blkmk_bin2hex(cbuf, buf, 25); + printf("Base58 raw data: %s\n", cbuf); + printf("Base58 check: %d\n", _blkmk_b58check(buf, 25)); +} + static void send_json(json_t *req) { char *s = json_dumps(req, JSON_INDENT(2)); @@ -32,6 +46,8 @@ int main(int argc, char**argv) { blkmk_sha256_impl = my_sha256; + testb58(); + tmpl = blktmpl_create(); assert(tmpl); req = blktmpl_request_jansson(blktmpl_addcaps(tmpl), NULL); diff --git a/private.h b/private.h index f3608e0..d23b831 100644 --- a/private.h +++ b/private.h @@ -11,4 +11,8 @@ extern bool _blkmk_dblsha256(void *hash, const void *data, size_t datasz); extern void _blkmk_bin2hex(char *out, const void *data, size_t datasz); extern bool _blkmk_hex2bin(void *o, const char *x, size_t len); +// base58.c +extern bool _blkmk_b58tobin(void *bin, size_t binsz, const char *b58, size_t b58sz); +extern int _blkmk_b58check(void *bin, size_t binsz); + #endif