diff --git a/CHANGES.md b/CHANGES.md index ce7bbda30..d5f9bdd64 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,9 +1,15 @@ # Changes -## Version 1.5.5 +## Version 1.5.6 ### Fixed -- De-optimize some memcpy calls on x86 to prevent leaks via extended registers. +- internal: De-optimize some memcpy calls on x86 to prevent leaks via extended registers. +- descriptor: Require base miniscript expressions for sh()/wsh(). +- descriptor: Reject nested expressions with unconsumed trailing input. + +## Version 1.5.5 + +(Unreleased) ## Version 1.5.4 diff --git a/README.md b/README.md index 1b93d1425..8efe7fc9a 100644 --- a/README.md +++ b/README.md @@ -125,7 +125,7 @@ installed. For non-development use, you can install wally from PyPI with `pip` as follows: ``` -pip install wallycore==1.5.5 +pip install wallycore==1.5.6 ``` For development, you can build and install wally using: diff --git a/_CMakeLists.txt b/_CMakeLists.txt index f12bf9e36..9cab08299 100644 --- a/_CMakeLists.txt +++ b/_CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.18) project( libwallycore - VERSION 1.5.5 + VERSION 1.5.6 DESCRIPTION "A collection of useful primitives for cryptocurrency wallets" LANGUAGES C ) diff --git a/configure.ac b/configure.ac index ea3d71077..c46255cda 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ AC_PREREQ([2.60]) -AC_INIT([libwallycore],[1.5.5]) +AC_INIT([libwallycore],[1.5.6]) AC_CONFIG_AUX_DIR([tools/build-aux]) AC_CONFIG_MACRO_DIR([tools/build-aux/m4]) AC_CONFIG_SRCDIR([src/mnemonic.h]) diff --git a/docs/source/conf.py b/docs/source/conf.py index c30530e61..441cd7c43 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -168,7 +168,7 @@ def extract_docs(infile, outfile): # built documents. # # The short X.Y version. -version = u'1.5.5' +version = u'1.5.6' # The full version, including alpha/beta/rc tags. release = version diff --git a/include/wally_core.h b/include/wally_core.h index e8c5c9897..eb3e1df14 100644 --- a/include/wally_core.h +++ b/include/wally_core.h @@ -31,8 +31,8 @@ extern "C" { /** Library version */ #define WALLY_MAJOR_VER 1 #define WALLY_MINOR_VER 5 -#define WALLY_PATCH_VER 5 -#define WALLY_BUILD_VER 0x10505 +#define WALLY_PATCH_VER 6 +#define WALLY_BUILD_VER 0x10506 /** * Initialize wally. diff --git a/setup.py b/setup.py index 016fbdf34..209280c61 100644 --- a/setup.py +++ b/setup.py @@ -172,7 +172,7 @@ def _call(args, cwd=ABS_PATH): kwargs = { 'name': 'wallycore', - 'version': '1.5.5', + 'version': '1.5.6', 'description': 'libwally Bitcoin library', 'long_description': 'Python bindings for the libwally Bitcoin library', 'url': 'https://github.com/ElementsProject/libwally-core', diff --git a/src/ctest/test_descriptor.c b/src/ctest/test_descriptor.c index 93cb74428..34457e3f1 100644 --- a/src/ctest/test_descriptor.c +++ b/src/ctest/test_descriptor.c @@ -1247,6 +1247,38 @@ static const struct descriptor_test { "descriptor - wsh - multi-child", "wsh(03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556,03fff97bd5755eeea420453a14355235d382f6472f8568a18b2f057a1460297556)", WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - wsh - non-B top level miniscript (V)", + "wsh(v:pk(key_1))", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - wsh - non-B top level miniscript (K)", + "wsh(pk_k(key_1))", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - wsh - non-B top level miniscript (W)", + "wsh(a:pk(key_1))", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - sh - non-B top level miniscript", + "sh(v:pk(key_1))", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - sh-wsh - non-B top level miniscript", + "sh(wsh(v:pk(key_1)))", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - wsh - trailing garbage in nested expression", + "wsh(pk(key_1)garbage)", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - sh - trailing garbage in nested expression", + "sh(wsh(pk(key_1)garbage))", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD + },{ + "descriptor - wsh - trailing garbage in inner expression", + "wsh(and_v(v:pk(key_1),pk(key_2)garbage))", + WALLY_NETWORK_BITCOIN_MAINNET, 0, 0, 0, NULL, 0, NULL, "", VARS_STD },{ "descriptor - pk - non-key child", "pk(1)", diff --git a/src/descriptor.c b/src/descriptor.c index fcddd7987..7c8aaf1bc 100644 --- a/src/descriptor.c +++ b/src/descriptor.c @@ -644,10 +644,20 @@ int wally_descriptor_free(ms_ctx *ctx) return WALLY_OK; } +static bool child_is_valid_script(const ms_node *node) +{ + /* Miniscript children must be top-level, i.e. type B. Descriptor-only + * children (e.g. sortedmulti) have no miniscript type and are not checked. + */ + return !(node->child->kind & KIND_MINISCRIPT) || + (node->child->type_properties & TYPE_B); +} + static int verify_sh(ms_ctx *ctx, ms_node *node) { (void)ctx; - if (!node_is_top(node) || !node->child->builtin) + if (!node_is_top(node) || !node->child->builtin || + !child_is_valid_script(node)) return WALLY_EINVAL; node->type_properties = node->child->type_properties; @@ -660,7 +670,8 @@ static int verify_wsh(ms_ctx *ctx, ms_node *node) if (node->parent && node->parent->kind != KIND_DESCRIPTOR_SH && node->parent->kind != KIND_DESCRIPTOR_CT) return WALLY_EINVAL; - if (!node->child->builtin || node_has_uncompressed_key(ctx, node)) + if (!node->child->builtin || !child_is_valid_script(node) || + node_has_uncompressed_key(ctx, node)) return WALLY_EINVAL; node->type_properties = node->child->type_properties; @@ -2676,6 +2687,11 @@ static int analyze_miniscript(ms_ctx *ctx, const char *str, size_t str_len, } } + /* A nested expression must consume its entire input. The top + * level is delimited by its checksum instead. */ + if (ret == WALLY_OK && parent && node->builtin && offset != str_len) + ret = WALLY_EINVAL; + if (ret == WALLY_OK && !seen_indent) { /* A constant value. Parse it ignoring any already added wrappers */ offset = node->wrapper_str[0] ? strlen(node->wrapper_str) + 1 : 0; diff --git a/src/wasm_package/package-lock.json b/src/wasm_package/package-lock.json index 491fd8300..21384cbe1 100644 --- a/src/wasm_package/package-lock.json +++ b/src/wasm_package/package-lock.json @@ -1,12 +1,12 @@ { "name": "wallycore", - "version": "1.5.5", + "version": "1.5.6", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wallycore", - "version": "1.5.5", + "version": "1.5.6", "license": "(MIT or BSD)", "devDependencies": { "buffer": "^6.0.3", diff --git a/src/wasm_package/package.json b/src/wasm_package/package.json index 06b1a54b1..9d1fd691f 100644 --- a/src/wasm_package/package.json +++ b/src/wasm_package/package.json @@ -1,6 +1,6 @@ { "name": "wallycore", - "version": "1.5.5", + "version": "1.5.6", "description": "JavaScript bindings for libwally", "main": "src/index.js", "type": "module", diff --git a/src/wasm_package/src/const.js b/src/wasm_package/src/const.js index 6ea43fccd..34c86bca3 100755 --- a/src/wasm_package/src/const.js +++ b/src/wasm_package/src/const.js @@ -109,7 +109,7 @@ export const WALLY_ADDRESS_VERSION_WIF_TESTNET = 0xEF; /** Wallet Import Format export const WALLY_BIP32_CHAIN_CODE_LEN = 32; export const WALLY_BIP32_TWEAK_SUM_LEN = 32; export const WALLY_BTC_MAX = 21000000; -export const WALLY_BUILD_VER = 0x10505; +export const WALLY_BUILD_VER = 0x10506; export const WALLY_CA_PREFIX_LIQUID = 0x0c; /** Liquid v1 confidential address prefix */ export const WALLY_CA_PREFIX_LIQUID_REGTEST = 0x04; /** Liquid v1 confidential address prefix for regtest */ export const WALLY_CA_PREFIX_LIQUID_TESTNET = 0x17; /** Liquid v1 confidential address prefix for testnet */ @@ -153,7 +153,7 @@ export const WALLY_NETWORK_LIQUID_TESTNET = 0x05; /** Liquid v1 testnet */ export const WALLY_NETWORK_NONE = 0x00; /** Used for miniscript parsing only */ export const WALLY_NO_CODESEPARATOR = 0xffffffff; /* No BIP342 code separator position */ export const WALLY_OK = 0; /** Success */ -export const WALLY_PATCH_VER = 5; +export const WALLY_PATCH_VER = 6; export const WALLY_PSBT_COMBINE_SIGS = 0x1; /* Combine the signatures from a signature-only PSBT */ export const WALLY_PSBT_EXTRACT_FINAL = 0x0; /* Extract a final transaction; fail if any inputs aren't finalized */ export const WALLY_PSBT_EXTRACT_NON_FINAL = 0x1; /* Extract without any final scriptsig and witness */