Skip to content

Commit

Permalink
Add support for output descriptors/miniscript.
Browse files Browse the repository at this point in the history
Co-authored-by: Jon Griffiths <jon_p_griffiths@yahoo.com>
  • Loading branch information
k-matsuzawa and jgriffiths committed Feb 7, 2023
1 parent 8bb8687 commit 4d430b8
Show file tree
Hide file tree
Showing 27 changed files with 4,873 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ docs/source/bip39.rst
docs/source/core.rst
docs/source/crypto.rst
docs/source/map.rst
docs/source/descriptor.rst
docs/source/psbt.rst
docs/source/psbt_members.rst
docs/source/script.rst
Expand Down
3 changes: 2 additions & 1 deletion docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ def extract_docs(infile, outfile):
else:
for m in [
'core', 'crypto', 'address', 'bip32', 'bip38', 'bip39', 'map',
'script', 'psbt', 'symmetric', 'transaction', 'elements', 'anti_exfil'
'script', 'psbt', 'descriptor', 'symmetric', 'transaction',
'elements', 'anti_exfil'
]:
extract_docs('../../include/wally_%s.h' % m, '%s.rst' % m)

Expand Down
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ libwally-core documentation
map
psbt
script
descriptor
symmetric
transaction
elements
Expand Down
54 changes: 54 additions & 0 deletions include/wally.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,60 @@ inline int cleanup(uint32_t flags) {
return ret;
}

template <class DESCRIPTOR>
inline int descriptor_canonicalize(const DESCRIPTOR& descriptor, uint32_t flags, char** output) {
int ret = ::wally_descriptor_canonicalize(detail::get_p(descriptor), flags, output);
return ret;
}

inline int descriptor_free(struct wally_descriptor* descriptor) {
int ret = ::wally_descriptor_free(descriptor);
return ret;
}

template <class DESCRIPTOR>
inline int descriptor_get_checksum(const DESCRIPTOR& descriptor, uint32_t flags, char** output) {
int ret = ::wally_descriptor_get_checksum(detail::get_p(descriptor), flags, output);
return ret;
}

template <class DESCRIPTOR>
inline int descriptor_get_features(const DESCRIPTOR& descriptor, uint32_t* value_out) {
int ret = ::wally_descriptor_get_features(detail::get_p(descriptor), value_out);
return ret;
}

template <class DESCRIPTOR, class VARS_IN>
inline int descriptor_parse(const DESCRIPTOR& descriptor, const VARS_IN& vars_in, uint32_t network, uint32_t flags, struct wally_descriptor** output) {
int ret = ::wally_descriptor_parse(detail::get_p(descriptor), detail::get_p(vars_in), network, flags, output);
return ret;
}

template <class DESCRIPTOR>
inline int descriptor_to_address(const DESCRIPTOR& descriptor, uint32_t variant, uint32_t child_num, uint32_t flags, char** output) {
int ret = ::wally_descriptor_to_address(detail::get_p(descriptor), variant, child_num, flags, output);
return ret;
}

template <class DESCRIPTOR>
inline int descriptor_to_addresses(const DESCRIPTOR& descriptor, uint32_t variant, uint32_t child_num, uint32_t flags, char** output, size_t num_outputs) {
int ret = ::wally_descriptor_to_addresses(detail::get_p(descriptor), variant, child_num, flags, output, num_outputs);
return ret;
}

template <class DESCRIPTOR, class BYTES_OUT>
inline int descriptor_to_script(const DESCRIPTOR& descriptor, uint32_t depth, uint32_t index, uint32_t variant, uint32_t child_num, uint32_t flags, BYTES_OUT& bytes_out, size_t* written = 0) {
size_t n;
int ret = ::wally_descriptor_to_script(detail::get_p(descriptor), depth, index, variant, child_num, flags, bytes_out.data(), bytes_out.size(), written ? written : &n);
return written || ret != WALLY_OK ? ret : n == static_cast<size_t>(bytes_out.size()) ? WALLY_OK : WALLY_EINVAL;
}

template <class DESCRIPTOR>
inline int descriptor_to_script_get_maximum_length(const DESCRIPTOR& descriptor, uint32_t flags, size_t* written) {
int ret = ::wally_descriptor_to_script_get_maximum_length(detail::get_p(descriptor), flags, written);
return ret;
}

template <class PRIV_KEY>
inline int ec_private_key_verify(const PRIV_KEY& priv_key) {
int ret = ::wally_ec_private_key_verify(priv_key.data(), priv_key.size());
Expand Down
2 changes: 2 additions & 0 deletions include/wally_address.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ struct ext_key;
#define WALLY_CA_PREFIX_LIQUID_REGTEST 0x04 /** Liquid v1 confidential address prefix for regtest */
#define WALLY_CA_PREFIX_LIQUID_TESTNET 0x17 /** Liquid v1 confidential address prefix for testnet */

#define WALLY_NETWORK_NONE 0x00 /** Used for miniscript parsing only */
#define WALLY_NETWORK_BITCOIN_MAINNET 0x01 /** Bitcoin mainnet */
#define WALLY_NETWORK_BITCOIN_REGTEST 0xff /** Bitcoin regtest: Behaves as testnet except for segwit */
#define WALLY_NETWORK_BITCOIN_TESTNET 0x02 /** Bitcoin testnet */
#define WALLY_NETWORK_LIQUID 0x03 /** Liquid v1 */
#define WALLY_NETWORK_LIQUID_REGTEST 0x04 /** Liquid v1 regtest */
Expand Down
172 changes: 172 additions & 0 deletions include/wally_descriptor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#ifndef LIBWALLY_CORE_DESCRIPTOR_H
#define LIBWALLY_CORE_DESCRIPTOR_H

#include "wally_core.h"

#ifdef __cplusplus
extern "C" {
#endif

struct wally_map;
/** An opaque type holding a parsed minscript/descriptor expression */
struct wally_descriptor;

/* Miniscript type flag */
#define WALLY_MINISCRIPT_WITNESS_SCRIPT 0x00 /** Witness script */
#define WALLY_MINISCRIPT_TAPSCRIPT 0x01 /** Tapscript */
#define WALLY_MINISCRIPT_ONLY 0x02 /** Only allow miniscript (not descriptor) expressions */

#define WALLY_MS_IS_RANGED 0x01 /** Allows key ranges via '*' */


/**
* Parse an output descriptor or miniscript expression.
*
* :param descriptor: Output descriptor or miniscript expression to parse.
* :param vars_in: Map of variable names to values, or NULL.
* :param network: ``WALLY_NETWORK_`` constant descripting the network the
*| descriptor belongs to, or WALLY_NETWORK_NONE for miniscript-only expressions.
* :param flags: Include ``WALLY_MINISCRIPT_ONLY`` to disallow descriptor
*| expressions, ``WALLY_MINISCRIPT_TAPSCRIPT`` to use x-only pubkeys, or 0.
* :param output: Destination for the resulting parsed descriptor.
*| The descriptor returned should be freed using `wally_descriptor_free`.
*
* Variable names can be used in the descriptor string and will be substituted
* with the contents of ``vars_in`` during parsing. Key names for ``vars_in``
* must be 16 characters or less in length and start with a letter.
*/
WALLY_CORE_API int wally_descriptor_parse(
const char *descriptor,
const struct wally_map *vars_in,
uint32_t network,
uint32_t flags,
struct wally_descriptor **output);

/**
* Free a parsed output descriptor or miniscript expression.
*
* :param descriptor: Parsed output descriptor or miniscript expression to free.
*/
WALLY_CORE_API int wally_descriptor_free(
struct wally_descriptor *descriptor);

/**
* Canonicalize a descriptor.
*
* :param descriptor: Parsed output descriptor or miniscript expression.
* :param flags: For future use. Must be 0.
* :param output: Destination for the resulting canonical descriptor.
*| The string returned should be freed using `wally_free_string`.
*
* .. note:: Other canonicalization (hardened derivation indicator
* mapping, and private to public key mapping) is not yet implemented.
*/
WALLY_CORE_API int wally_descriptor_canonicalize(
const struct wally_descriptor *descriptor,
uint32_t flags,
char **output);

/**
* Create an output descriptor checksum.
*
* :param descriptor: Parsed output descriptor or miniscript expression.
* :param flags: For future use. Must be 0.
* :param output: Destination for the resulting descriptor checksum.
*| The string returned should be freed using `wally_free_string`.
*/
WALLY_CORE_API int wally_descriptor_get_checksum(
const struct wally_descriptor *descriptor,
uint32_t flags,
char **output);

/**
* Get the features used in a parsed output descriptor or miniscript expression.
*
* :param descriptor: Parsed output descriptor or miniscript expression.
* :param value_out: Destination for the resulting ``WALLY_MS_`` feature flags.
*/
WALLY_CORE_API int wally_descriptor_get_features(
const struct wally_descriptor *descriptor,
uint32_t *value_out);

/**
* Get the maximum length of a script corresponding to an output descriptor.
*
* :param descriptor: Parsed output descriptor or miniscript expression.
* :param flags: For future use. Must be 0.
* :param written: Destination for the resulting maximum script length.
*
* .. note:: This function overestimates the script size required, but is
*| cheap to compute (does not require script generation).
*/
WALLY_CORE_API int wally_descriptor_to_script_get_maximum_length(
const struct wally_descriptor *descriptor,
uint32_t flags,
size_t *written);

/**
* Create a script corresponding to an output descriptor or miniscript expression.
*
* :param descriptor: Parsed output descriptor or miniscript expression.
* :param depth: Depth of the expression tree to generate from. Pass 0 to generate from the root.
* :param index: The zero-based index of the child at depth ``depth`` to generate from.
* :param variant: The variant of descriptor to generate. Pass 0 for the default.
* :param child_num: The BIP32 child number to derive, or 0 for static descriptors.
* :param flags: For future use. Must be 0.
* :param bytes_out: Destination for the resulting scriptPubKey or script.
* :param len: The length of ``bytes_out`` in bytes.
* :param written: Destination for the number of bytes written to ``bytes_out``.
*/
WALLY_CORE_API int wally_descriptor_to_script(
struct wally_descriptor *descriptor,
uint32_t depth,
uint32_t index,
uint32_t variant,
uint32_t child_num,
uint32_t flags,
unsigned char *bytes_out,
size_t len,
size_t *written);

/**
* Create an address corresponding to an output descriptor.
*
* :param descriptor: Parsed output descriptor.
* :param variant: The variant of descriptor to generate. Pass 0 for the default.
* :param child_num: The BIP32 child number to derive, or zero for static descriptors.
* :param flags: For future use. Must be 0.
* :param output: Destination for the resulting addresss.
*| The string returned should be freed using `wally_free_string`.
*/
WALLY_CORE_API int wally_descriptor_to_address(
struct wally_descriptor *descriptor,
uint32_t variant,
uint32_t child_num,
uint32_t flags,
char **output);

/**
* Create addresses that correspond to the derived range of an output descriptor.
*
* :param descriptor: Parsed output descriptor.
* :param variant: The variant of descriptor to generate. Pass 0 for the default.
* :param child_num: The BIP32 child number to derive, or zero for static descriptors.
* :param flags: For future use. Must be 0.
* :param output: Destination for the resulting addresses.
* :param num_outputs: The number of items in ``output``. Addresses will be
*| generated into this array starting from child_num, incrementing by 1.
*| The addresses returned should be freed using `wally_free_string`.
*/
WALLY_CORE_API int wally_descriptor_to_addresses(
struct wally_descriptor *descriptor,
uint32_t variant,
uint32_t child_num,
uint32_t flags,
char **output,
size_t num_outputs);

#ifdef __cplusplus
}
#endif

#endif /* LIBWALLY_CORE_DESCRIPTOR_H */
15 changes: 15 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ include_HEADERS += $(top_srcdir)/include/wally_bip38.h
include_HEADERS += $(top_srcdir)/include/wally_bip39.h
include_HEADERS += $(top_srcdir)/include/wally_core.h
include_HEADERS += $(top_srcdir)/include/wally_crypto.h
include_HEADERS += $(top_srcdir)/include/wally_descriptor.h
include_HEADERS += $(top_srcdir)/include/wally_elements.h
include_HEADERS += $(top_srcdir)/include/wally_map.h
include_HEADERS += $(top_srcdir)/include/wally_psbt.h
Expand Down Expand Up @@ -109,6 +110,7 @@ all: swig_java/wallycore.jar

SWIG_JAVA_TEST_DEPS = \
$(sjs)/$(cbt)/test_bip32.class \
$(sjs)/$(cbt)/test_descriptor.class \
$(sjs)/$(cbt)/test_tx.class \
$(sjs)/$(cbt)/test_scripts.class \
$(sjs)/$(cbt)/test_mnemonic.class
Expand Down Expand Up @@ -141,6 +143,7 @@ libwallycore_la_SOURCES = \
bip38.c \
bip39.c \
bech32.c \
descriptor.c \
ecdh.c \
elements.c \
blech32.c \
Expand Down Expand Up @@ -173,6 +176,7 @@ libwallycore_la_INCLUDES = \
include/wally_bip39.h \
include/wally_core.h \
include/wally_crypto.h \
include/wally_descriptor.h \
include/wally_elements.h \
include/wally_map.h \
include/wally_psbt.h \
Expand Down Expand Up @@ -239,6 +243,14 @@ test_tx_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@
if PYTHON_MANYLINUX
test_tx_LDADD += $(PYTHON_LIBS)
endif
TESTS += test_descriptor
noinst_PROGRAMS += test_descriptor
test_descriptor_SOURCES = ctest/test_descriptor.c
test_descriptor_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS)
test_descriptor_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@
if PYTHON_MANYLINUX
test_descriptor_LDADD += $(PYTHON_LIBS)
endif
if BUILD_ELEMENTS
TESTS += test_elements_tx
noinst_PROGRAMS += test_elements_tx
Expand All @@ -265,6 +277,7 @@ check-libwallycore: $(PYTHON_TEST_DEPS)
$(AM_V_at)$(PYTHON_TEST) test/test_bip32.py
$(AM_V_at)$(PYTHON_TEST) test/test_bip38.py
$(AM_V_at)$(PYTHON_TEST) test/test_bip39.py
$(AM_V_at)$(PYTHON_TEST) test/test_descriptor.py
$(AM_V_at)$(PYTHON_TEST) test/test_ecdh.py
$(AM_V_at)$(PYTHON_TEST) test/test_hash.py
$(AM_V_at)$(PYTHON_TEST) test/test_hex.py
Expand All @@ -291,6 +304,7 @@ endif
if USE_SWIG_PYTHON
check-swig-python: $(SWIG_PYTHON_TEST_DEPS)
$(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/bip32.py
$(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/descriptor.py
$(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/mnemonic.py
$(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/psbt.py
$(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/sha.py
Expand All @@ -317,6 +331,7 @@ if BUILD_ELEMENTS
$(AM_V_at)$(JAVA_TEST)test_pegs
endif
$(AM_V_at)$(JAVA_TEST)test_bip32
$(AM_V_at)$(JAVA_TEST)test_descriptor
$(AM_V_at)$(JAVA_TEST)test_mnemonic
$(AM_V_at)$(JAVA_TEST)test_scripts
$(AM_V_at)$(JAVA_TEST)test_tx
Expand Down
2 changes: 2 additions & 0 deletions src/address.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ int wally_scriptpubkey_to_address(const unsigned char *scriptpubkey, size_t scri
case WALLY_NETWORK_BITCOIN_MAINNET:
bytes[0] = WALLY_ADDRESS_VERSION_P2PKH_MAINNET;
break;
case WALLY_NETWORK_BITCOIN_REGTEST:
case WALLY_NETWORK_BITCOIN_TESTNET:
bytes[0] = WALLY_ADDRESS_VERSION_P2PKH_TESTNET;
break;
Expand All @@ -188,6 +189,7 @@ int wally_scriptpubkey_to_address(const unsigned char *scriptpubkey, size_t scri
case WALLY_NETWORK_BITCOIN_MAINNET:
bytes[0] = WALLY_ADDRESS_VERSION_P2SH_MAINNET;
break;
case WALLY_NETWORK_BITCOIN_REGTEST:
case WALLY_NETWORK_BITCOIN_TESTNET:
bytes[0] = WALLY_ADDRESS_VERSION_P2SH_TESTNET;
break;
Expand Down
1 change: 1 addition & 0 deletions src/amalgamation/combined.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#include "bip32.c"
#include "bip38.c"
#include "bip39.c"
#include "descriptor.c"
#include "ecdh.c"
#include "elements.c"
#include "hex.c"
Expand Down
Loading

0 comments on commit 4d430b8

Please sign in to comment.