From 79d8fadbc035aaee7cd7de6a86e5494c6d9f6a77 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 13:35:48 +1200 Subject: [PATCH 001/205] Use WALLY_TXHASH_LEN for tx hash lengths. Doesn't affect functionality since SHA256_LEN is the same size, but this reads better. --- include/wally_transaction.h | 2 +- src/psbt.c | 20 ++++++++++---------- src/swig_java/swig.i | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 602725867..0f6b953fc 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -899,7 +899,7 @@ WALLY_CORE_API int wally_tx_get_elements_signature_hash( * Calculate the asset entropy from a prevout and the Ricardian contract hash. * * :param txhash: The prevout transaction hash. - * :param txhash_len: Size of ``txhash`` in bytes. Must be ``SHA256_LEN``. + * :param txhash_len: Size of ``txhash`` in bytes. Must be ``WALLY_TXHASH_LEN``. * :param index: The prevout index. * :param contract_hash: The issuer specified Ricardian contract hash. * :param contract_hash_len: Size of ``contract hash`` in bytes. Must be ``SHA256_LEN``. diff --git a/src/psbt.c b/src/psbt.c index 34a5e0244..e7c5661b0 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2218,7 +2218,7 @@ static int get_txid( size_t calc, written; int ret = WALLY_OK; - if (!tx || !txid || txid_len != SHA256_LEN) { + if (!tx || !txid || txid_len != WALLY_TXHASH_LEN) { return WALLY_EINVAL; } @@ -2229,7 +2229,7 @@ static int get_txid( return WALLY_ENOMEM; } if ((ret = wally_tx_to_bytes(tx, 0, bytes, calc, &written)) == WALLY_OK) { - ret = wally_sha256d(bytes, written, txid, SHA256_LEN); + ret = wally_sha256d(bytes, written, txid, txid_len); } wally_free(bytes); @@ -2445,7 +2445,7 @@ int wally_combine_psbts( struct wally_psbt **output) { struct wally_psbt *result; - unsigned char global_txid[SHA256_LEN]; + unsigned char global_txid[WALLY_TXHASH_LEN]; size_t i, j; int ret = WALLY_OK; @@ -2456,7 +2456,7 @@ int wally_combine_psbts( } /* Get info from the first psbt and use it as the template */ - if ((ret = get_txid(psbts->tx, global_txid, SHA256_LEN)) != WALLY_OK) { + if ((ret = get_txid(psbts->tx, global_txid, sizeof(global_txid))) != WALLY_OK) { return ret; } @@ -2471,13 +2471,13 @@ int wally_combine_psbts( result->num_outputs = psbts[0].num_outputs; for (i = 0; i < psbts_len; ++i) { - unsigned char txid[SHA256_LEN]; + unsigned char txid[sizeof(global_txid)]; /* Compare the txids */ - if ((ret = get_txid(psbts[i].tx, txid, SHA256_LEN)) != WALLY_OK) { + if ((ret = get_txid(psbts[i].tx, txid, sizeof(txid))) != WALLY_OK) { goto fail; } - if (memcmp(global_txid, txid, SHA256_LEN) != 0) { + if (memcmp(global_txid, txid, sizeof(txid)) != 0) { ret = WALLY_EINVAL; goto fail; } @@ -2626,12 +2626,12 @@ int wally_sign_psbt( } if (input->non_witness_utxo) { - unsigned char txid[SHA256_LEN]; + unsigned char txid[WALLY_TXHASH_LEN]; - if ((ret = get_txid(input->non_witness_utxo, txid, SHA256_LEN)) != WALLY_OK) { + if ((ret = get_txid(input->non_witness_utxo, txid, sizeof(txid))) != WALLY_OK) { return ret; } - if (memcmp((char *)txid, (char *)txin->txhash, SHA256_LEN) != 0) { + if (memcmp((char *)txid, (char *)txin->txhash, sizeof(txid)) != 0) { return WALLY_EINVAL; } diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index d78b190fc..aba0dd17a 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -578,7 +578,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(wally_tx_input_get_script_len); %rename("_tx_input_get_sequence") wally_tx_input_get_sequence; %returns_size_t(_tx_input_get_sequence); -%returns_array_(wally_tx_input_get_txhash, 2, 3, SHA256_LEN); +%returns_array_(wally_tx_input_get_txhash, 2, 3, WALLY_TXHASH_LEN); %rename("_tx_input_get_witness") wally_tx_input_get_witness; %returns_size_t(_tx_input_get_witness); %returns_size_t(wally_tx_input_get_witness_len); From fabb45b4cf78de082aa5da5740df95a4e6674466 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 13:39:18 +1200 Subject: [PATCH 002/205] transaction: Use GET_TX_B_FIXED instead of mostly duplicated GET_TX_ARRAY --- src/transaction.c | 21 ++++++--------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/src/transaction.c b/src/transaction.c index e87ec6d3c..ed2915846 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -2883,19 +2883,20 @@ static int tx_getb_impl(const void *input, return WALLY_OK; } -#define GET_TX_ARRAY(typ, name, siz) \ +#define GET_TX_B_FIXED(typ, name, siz, n) \ int wally_ ## typ ## _get_ ## name(const struct wally_ ## typ *input, \ unsigned char *bytes_out, size_t len) { \ size_t written; \ - if (!input || len != siz) \ + if (!input || len != n) \ return WALLY_EINVAL; \ return tx_getb_impl(input, input->name, siz, bytes_out, len, &written); \ } -GET_TX_ARRAY(tx_input, txhash, WALLY_TXHASH_LEN) + +GET_TX_B_FIXED(tx_input, txhash, WALLY_TXHASH_LEN, WALLY_TXHASH_LEN) #ifdef BUILD_ELEMENTS -GET_TX_ARRAY(tx_input, blinding_nonce, SHA256_LEN) -GET_TX_ARRAY(tx_input, entropy, SHA256_LEN) +GET_TX_B_FIXED(tx_input, blinding_nonce, SHA256_LEN, SHA256_LEN) +GET_TX_B_FIXED(tx_input, entropy, SHA256_LEN, SHA256_LEN) #endif /* BUILD_ELEMENTS */ @@ -2907,16 +2908,6 @@ GET_TX_ARRAY(tx_input, entropy, SHA256_LEN) return tx_getb_impl(input, input->name, siz, bytes_out, len, written); \ } -#define GET_TX_B_FIXED(typ, name, siz, n) \ - int wally_ ## typ ## _get_ ## name(const struct wally_ ## typ *input, \ - unsigned char *bytes_out, size_t len) { \ - size_t written; \ - if (!input) \ - return WALLY_EINVAL; \ - int ret = len != n ? WALLY_EINVAL : tx_getb_impl(input, input->name, siz, bytes_out, len, &written); \ - return ret; \ - } - #define GET_TX_I(typ, name, outtyp) \ int wally_ ## typ ## _get_ ## name(const struct wally_ ## typ *input, outtyp * written) { \ if (written) *written = 0; \ From 995245dbf517899223cd8695e5cf69e110d5391b Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 13:57:04 +1200 Subject: [PATCH 003/205] Java: Add missing tx_input_get_txhash wrapper --- src/swig_java/jni_extra.java_in | 4 ++++ src/swig_java/src/com/blockstream/test/test_tx.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index 3f91335f3..bc90fe0ac 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -139,6 +139,10 @@ return tx_get_input_txhash(jarg1, jarg2, null); } + public final static byte[] tx_input_get_txhash(Object jarg1) { + return tx_input_get_txhash(jarg1, null); + } + public final static byte[] ec_sig_to_der(byte[] sig) { final byte[] buf = new byte[EC_SIGNATURE_DER_MAX_LEN]; final int len = ec_sig_to_der(sig, buf); diff --git a/src/swig_java/src/com/blockstream/test/test_tx.java b/src/swig_java/src/com/blockstream/test/test_tx.java index f8d73a127..a93bd76cd 100644 --- a/src/swig_java/src/com/blockstream/test/test_tx.java +++ b/src/swig_java/src/com/blockstream/test/test_tx.java @@ -46,7 +46,7 @@ public void test() { assert_eq(25, tx_get_output_script.length, "output script length mismatch"); assert_eq("76a9142bc89c2702e0e618db7d59eb5ce2f0f147b4075488ac", h(tx_get_output_script), "output script mismatch"); assert_eq( 0, Wally.tx_get_witness_count(tx), "witness count mismatch"); - assert_eq(p2pkh_hex_first_input_hash, h(Wally.tx_input_get_txhash(tx_input, null)), "hash of prevout 0 from tx_input does not match"); + assert_eq(p2pkh_hex_first_input_hash, h(Wally.tx_input_get_txhash(tx_input)), "hash of prevout 0 from tx_input does not match"); assert_eq(p2pkh_hex_first_input_script, h(tx_input_get_script), "script hex mismatch"); assert_eq(4294967295L, Wally.tx_input_get_sequence(tx_input), "sequence mismatch from tx_input"); assert_eq(118307L, Wally.tx_get_output_satoshi(tx,0), "output 0, satoshi mismatch"); From 67c913282ceb3948a8765c64a47512b8c1462bee Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 14:17:49 +1200 Subject: [PATCH 004/205] bech32: Prevent witness version wrap-around bypassing allowed range check Checked in here to not lose it until this is pushed upstream. Wally only uses v0 addresses at the time of commiting. Note that the inverse function segwit_addr_decode() isn't affected as it implicitly casts uint8 -> int32 so witver cannot be negative on return. --- src/bech32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bech32.c b/src/bech32.c index 5e32d831b..11df0c1d6 100644 --- a/src/bech32.c +++ b/src/bech32.c @@ -168,7 +168,7 @@ static int convert_bits(uint8_t *out, size_t *outlen, int outbits, const uint8_t static int segwit_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { uint8_t data[65]; size_t datalen = 0; - if (witver > 16) goto fail; + if (witver < 0 || witver > 16) goto fail; if (witver == 0 && witprog_len != 20 && witprog_len != 32) goto fail; if (witprog_len < 2 || witprog_len > 40) goto fail; data[0] = witver; From bbb17be1bfee951b51ba03f24fb4a7c933ab29d6 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 13:32:42 +1200 Subject: [PATCH 005/205] blech32: Add witness version check as per bech32 --- src/blech32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/blech32.c b/src/blech32.c index 9da31c958..20f53cb05 100644 --- a/src/blech32.c +++ b/src/blech32.c @@ -171,7 +171,7 @@ static int blech32_convert_bits(uint8_t *out, size_t *outlen, int outbits, const static int blech32_addr_encode(char *output, const char *hrp, int witver, const uint8_t *witprog, size_t witprog_len) { uint8_t data[WALLY_BLECH32_MAXLEN]; size_t datalen = 0; - if (witver > 16) goto fail; + if (witver < 0 || witver > 16) goto fail; if (witver == 0 && witprog_len != 53 && witprog_len != 65) goto fail; if (witprog_len < 2 || witprog_len > 65) goto fail; data[0] = witver; From eebe38af86cdef8560df68013b60957ec428ff55 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 13:28:15 +1200 Subject: [PATCH 006/205] blech32: Formatting consistency nits --- src/blech32.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/blech32.c b/src/blech32.c index 20f53cb05..857dac5b5 100644 --- a/src/blech32.c +++ b/src/blech32.c @@ -279,9 +279,9 @@ int wally_confidential_addr_from_addr_segwit( if (output) *output = NULL; - if (!address || !addr_family || !confidential_addr_family || !pub_key - || pub_key_len != EC_PUBLIC_KEY_LEN || !output - || strlen(confidential_addr_family) >= WALLY_BLECH32_MAXLEN) + if (!address || !addr_family || !confidential_addr_family || !pub_key || + pub_key_len != EC_PUBLIC_KEY_LEN || !output || + strlen(confidential_addr_family) >= WALLY_BLECH32_MAXLEN) return WALLY_EINVAL; /* get v0 witness programs script */ From 1ddc85a850aac37536229bb92cfe9d16053b9a4b Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 14:33:23 +1200 Subject: [PATCH 007/205] pytest: Don't use built-in function 'input' as a variable name --- src/test/test_psbt.py | 6 +++--- src/test/test_transaction.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index f9d07258d..a4eb72507 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -40,10 +40,10 @@ def test_serialization(self): tx = pointer(wally_tx()) self.assertEqual(WALLY_OK, wally_tx_init_alloc(2, 0, 2, 2, tx)) for txin in creator['inputs']: - input = pointer(wally_tx_input()) + tx_in = pointer(wally_tx_input()) txid = binascii.unhexlify(txin['txid'])[::-1] - self.assertEqual(WALLY_OK, wally_tx_input_init_alloc(txid, len(txid), txin['vout'], 0xffffffff, None, 0, None, input)) - self.assertEqual(WALLY_OK, wally_tx_add_input(tx, input)) + self.assertEqual(WALLY_OK, wally_tx_input_init_alloc(txid, len(txid), txin['vout'], 0xffffffff, None, 0, None, tx_in)) + self.assertEqual(WALLY_OK, wally_tx_add_input(tx, tx_in)) for txout in creator['outputs']: addr = txout['addr'] amt = txout['amt'] diff --git a/src/test/test_transaction.py b/src/test/test_transaction.py index ef5b038da..6b1d06db4 100644 --- a/src/test/test_transaction.py +++ b/src/test/test_transaction.py @@ -182,9 +182,9 @@ def test_get_signature_hash(self): self.assertEqual(WALLY_EINVAL, wally_tx_get_btc_signature_hash(*args)) def sha256d(hex_): - input, input_len = make_cbuffer(hex_) + bin_input, bin_input_len = make_cbuffer(hex_) buf, buf_len = make_cbuffer('00'*32) - self.assertEqual(WALLY_OK, wally_sha256d(input, input_len, buf, buf_len)) + self.assertEqual(WALLY_OK, wally_sha256d(bin_input, bin_input_len, buf, buf_len)) return h(buf) script, script_len = make_cbuffer('00') From 897768f033e011eba4747c59ed9d1a387e9608d5 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 14:49:55 +1200 Subject: [PATCH 008/205] pytest: Remove hashlib use from test_sign.py --- src/test/test_sign.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/test_sign.py b/src/test/test_sign.py index 6497be0c0..f01d20fd9 100755 --- a/src/test/test_sign.py +++ b/src/test/test_sign.py @@ -1,6 +1,5 @@ import unittest from util import * -from hashlib import sha256 FLAG_ECDSA, FLAG_SCHNORR, FLAG_GRIND_R, FLAG_RECOVERABLE = 1, 2, 4, 8 EX_PRIV_KEY_LEN, EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_UNCOMPRESSED_LEN = 32, 33, 65 @@ -177,7 +176,9 @@ def test_format_message(self): for flags in (0, BITCOIN_MESSAGE_HASH_FLAG): expected = PREFIX + varint + msg if flags: - expected = sha256(sha256(expected).digest()).digest() + buf, buf_len = make_cbuffer('00'*32) + self.assertEqual(WALLY_OK, wally_sha256d(expected, len(expected), buf, buf_len)) + expected = buf ret, written = fn(flags, out_len) self.assertEqual((ret, written), (WALLY_OK, len(expected))) From dffd215b115dcb4618884b4cd5118168b3efa377 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 15:45:34 +1200 Subject: [PATCH 009/205] Docs: received -> receive --- docs/source/Liquid.rst | 2 +- include/wally_elements.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Liquid.rst b/docs/source/Liquid.rst index 1ac62b42a..98b09b4a3 100644 --- a/docs/source/Liquid.rst +++ b/docs/source/Liquid.rst @@ -39,7 +39,7 @@ network version. :start-after: start-create_conf_address :end-before: end-create_conf_address -The confidential address can now be passed to liquid-cli to received +The confidential address can now be passed to liquid-cli to receive funds. We'll send 1.1 BTC to our confidential address and save the raw hex transaction for further processing. diff --git a/include/wally_elements.h b/include/wally_elements.h index 229bc1432..172b5142b 100644 --- a/include/wally_elements.h +++ b/include/wally_elements.h @@ -49,7 +49,7 @@ WALLY_CORE_API int wally_asset_generator_from_bytes( * :param abf_len: Length of ``abf`` in bytes. Must be ``values_len`` * ``BLINDING_FACTOR_LEN``. * :param vbf: Array of bytes representing (``values_len`` - 1) value blinding factors. * :param vbf_len: Length of ``vbf`` in bytes. Must be (``values_len`` - 1) * ``BLINDING_FACTOR_LEN``. - * :param bytes_out: Buffer to received the final value blinding factor. + * :param bytes_out: Buffer to receive the final value blinding factor. * :param len: Length of ``bytes_out``. Must be ``BLINDING_FACTOR_LEN``. */ WALLY_CORE_API int wally_asset_final_vbf( From 3ebb7d9846d34c1cd7c376a9bde3122677db4042 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 15:47:59 +1200 Subject: [PATCH 010/205] docs: Add symmetric docs with minor fixes --- .gitignore | 1 + docs/source/conf.py | 4 ++-- docs/source/index.rst | 1 + include/wally_symmetric.h | 4 ++-- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index e5f983e03..51e4fc112 100644 --- a/.gitignore +++ b/.gitignore @@ -82,6 +82,7 @@ docs/source/core.rst docs/source/crypto.rst docs/source/psbt.rst docs/source/script.rst +docs/source/symmetric.rst docs/source/transaction.rst docs/source/elements.rst .idea/ diff --git a/docs/source/conf.py b/docs/source/conf.py index c728bbc8e..7249033c8 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -53,8 +53,8 @@ def extract_docs(infile, outfile): # Generate the documentation source files for m in [ - 'core', 'crypto', 'address', 'bip32', 'bip38', 'bip39', 'script', 'psbt', 'transaction', - 'elements' + 'core', 'crypto', 'address', 'bip32', 'bip38', 'bip39', 'script', 'psbt', + 'symmetric', 'transaction', 'elements' ]: extract_docs('../../include/wally_%s.h' % m, '%s.rst' % m) diff --git a/docs/source/index.rst b/docs/source/index.rst index 06e8ae9d9..4fb0697d2 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -13,6 +13,7 @@ libwally-core documentation bip39 psbt script + symmetric transaction elements diff --git a/include/wally_symmetric.h b/include/wally_symmetric.h index 1102bb230..96f67ae2a 100644 --- a/include/wally_symmetric.h +++ b/include/wally_symmetric.h @@ -31,7 +31,7 @@ WALLY_CORE_API int wally_symmetric_key_from_seed( * Create a new child symmetric key from a parent key. * * :param bytes: Parent key to use. - * :param bytes_len: Size of ``bytes`` in bytes. Must be one of ``HMAC_SHA512_LEN``. + * :param bytes_len: Size of ``bytes`` in bytes. Must be ``HMAC_SHA512_LEN``. * :param version: Version byte to prepend to ``label``. Must be zero. * :param label: Label to use for the child. * :param label_len: Size of ``label`` in bytes. @@ -51,4 +51,4 @@ WALLY_CORE_API int wally_symmetric_key_from_parent( } #endif -#endif /* LIBWALLY_CORE_ELEMENTS_H */ +#endif /* LIBWALLY_CORE_SYMMETRIC_H */ From d8bacc3ee0208e727cdf1db652999d4baf0cffc0 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 17:07:22 +1200 Subject: [PATCH 011/205] symmetric: Add java wrappers + test, pass given len Also update version to uin32_t (currently always passed as 0). --- include/wally_symmetric.h | 2 +- src/swig_java/jni_extra.java_in | 8 ++++++++ src/swig_java/src/com/blockstream/test/test_assets.java | 8 ++++++++ src/symmetric.c | 6 +++--- 4 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/wally_symmetric.h b/include/wally_symmetric.h index 96f67ae2a..5ce1e3170 100644 --- a/include/wally_symmetric.h +++ b/include/wally_symmetric.h @@ -41,7 +41,7 @@ WALLY_CORE_API int wally_symmetric_key_from_seed( WALLY_CORE_API int wally_symmetric_key_from_parent( const unsigned char *bytes, size_t bytes_len, - unsigned char version, + uint32_t version, const unsigned char *label, size_t label_len, unsigned char *bytes_out, diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index bc90fe0ac..64867caad 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -278,6 +278,14 @@ return _is_elements_build() != 0; } + public final static byte[] symmetric_key_from_seed(byte[] jarg1) { + return symmetric_key_from_seed(jarg1, null); + } + + public final static byte[] symmetric_key_from_parent(byte[] jarg1, long jarg2, byte[] jarg3) { + return symmetric_key_from_parent(jarg1, jarg2, jarg3, null); + } + public final static void cleanup() { _cleanup(0); } diff --git a/src/swig_java/src/com/blockstream/test/test_assets.java b/src/swig_java/src/com/blockstream/test/test_assets.java index 9f3f9c183..e453c637e 100644 --- a/src/swig_java/src/com/blockstream/test/test_assets.java +++ b/src/swig_java/src/com/blockstream/test/test_assets.java @@ -40,6 +40,13 @@ public void test_blinding_keys() { throw new RuntimeException("Unexpected public_blinding_key result"); } + public void test_symmetric() { + // Just test our wrappers; the values are tested by test_blinding_keys() above + final byte[] seed = h("fecd7938b912091cdedb47f70d4f3742f59f77e3bac780c0c498e2aaf6f9f4ab"); + final byte[] master_key = Wally.symmetric_key_from_seed(seed); + final byte[] child_key = Wally.symmetric_key_from_parent(master_key, 0, new String("foo").getBytes()); + } + private void test_confidential_address() { // hexes from local regtest testing final String addr = "Q7qcjTLsYGoMA7TjUp97R6E6AM5VKqBik6"; @@ -79,6 +86,7 @@ public static void main(final String[] args) { final test_assets t = new test_assets(); t.test_blinding(); t.test_blinding_keys(); + t.test_symmetric(); t.test_confidential_address(); t.test_confidential_values(); } diff --git a/src/symmetric.c b/src/symmetric.c index 4fb7a0038..df0a14529 100644 --- a/src/symmetric.c +++ b/src/symmetric.c @@ -25,13 +25,13 @@ int wally_symmetric_key_from_seed( if (!bytes || !is_valid_seed_length(bytes_len) || !bytes_out || len != HMAC_SHA512_LEN) return WALLY_EINVAL; - return wally_hmac_sha512(DOMAIN_STR, sizeof(DOMAIN_STR), bytes, bytes_len, bytes_out, HMAC_SHA512_LEN); + return wally_hmac_sha512(DOMAIN_STR, sizeof(DOMAIN_STR), bytes, bytes_len, bytes_out, len); } int wally_symmetric_key_from_parent( const unsigned char *bytes, size_t bytes_len, - unsigned char version, + uint32_t version, const unsigned char *label, size_t label_len, unsigned char *bytes_out, @@ -55,7 +55,7 @@ int wally_symmetric_key_from_parent( *buff_p = version; memcpy(buff_p + 1, label, label_len); - ret = wally_hmac_sha512(bytes, SYMMETRIC_KEY_LEN, buff_p, buff_len, bytes_out, HMAC_SHA512_LEN); + ret = wally_hmac_sha512(bytes, SYMMETRIC_KEY_LEN, buff_p, buff_len, bytes_out, len); if (buff_p != buff) wally_free(buff_p); From 01c690f9644ccbce5668e9b877d8257859bffd44 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 19:31:59 +1200 Subject: [PATCH 012/205] wally_asset_blinding_key_from_seed: remove redundant goto --- src/elements.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/elements.c b/src/elements.c index 1327c173f..e0c691ab7 100644 --- a/src/elements.c +++ b/src/elements.c @@ -545,20 +545,17 @@ int wally_asset_blinding_key_from_seed( size_t len) { unsigned char root[HMAC_SHA512_LEN]; - int ret = WALLY_OK; + int ret; if (!bytes || !bytes_out || len != HMAC_SHA512_LEN) return WALLY_EINVAL; - if ((ret = wally_symmetric_key_from_seed(bytes, bytes_len, root, sizeof(root))) != WALLY_OK) - return ret; - - if ((ret = wally_symmetric_key_from_parent(root, sizeof(root), 0, LABEL_STR, sizeof(LABEL_STR), - bytes_out, len)) != WALLY_OK) - goto cleanup; - -cleanup: - wally_clear(root, sizeof(root)); + ret = wally_symmetric_key_from_seed(bytes, bytes_len, root, sizeof(root)); + if (ret == WALLY_OK) { + ret = wally_symmetric_key_from_parent(root, sizeof(root), 0, LABEL_STR, sizeof(LABEL_STR), + bytes_out, len); + wally_clear(root, sizeof(root)); + } return ret; } From 4574c82b0071a3c1a338000c030deeb7023081f9 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 1 Jul 2020 20:59:47 +1200 Subject: [PATCH 013/205] wally_asset_blinding_key_to_ec_private_key: simplify logic --- src/elements.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/elements.c b/src/elements.c index e0c691ab7..a67ea0de7 100644 --- a/src/elements.c +++ b/src/elements.c @@ -568,15 +568,16 @@ int wally_asset_blinding_key_to_ec_private_key( unsigned char *bytes_out, size_t len) { - int ret = WALLY_OK; + int ret; if (!bytes || bytes_len != HMAC_SHA512_LEN || !script || !script_len || !bytes_out || len != EC_PRIVATE_KEY_LEN) return WALLY_EINVAL; - if ((ret = wally_hmac_sha256(bytes + SYMMETRIC_KEY_LEN, SYMMETRIC_KEY_LEN, script, script_len, bytes_out, len)) != WALLY_OK) - return ret; + ret = wally_hmac_sha256(bytes + SYMMETRIC_KEY_LEN, SYMMETRIC_KEY_LEN, script, script_len, bytes_out, len); + if (ret == WALLY_OK) + ret = wally_ec_private_key_verify(bytes_out, EC_PRIVATE_KEY_LEN); - return wally_ec_private_key_verify(bytes_out, EC_PRIVATE_KEY_LEN); + return ret; } int wally_asset_pak_whitelistproof_size( From 9ae32e9c3578bbee55f914407df2f3b5252e3214 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 09:17:49 +1200 Subject: [PATCH 014/205] docs: Fix function refs in Liquid developer guide --- docs/source/Liquid.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/Liquid.rst b/docs/source/Liquid.rst index 98b09b4a3..3a3f91d86 100644 --- a/docs/source/Liquid.rst +++ b/docs/source/Liquid.rst @@ -30,7 +30,7 @@ blinding key from a mnemonic. :start-after: start-derive_blinding_key :end-before: end-derive_blinding_key -Finally call the wally function `confidential_addr_from_addr` to combine +Finally call the wally function :c:func:`wally_confidential_addr_from_addr` to combine the non-confidential address with the public blinding key to create a confidential address. We also supply a blinding prefix indicating the network version. @@ -87,7 +87,7 @@ less some fixed ``fee``. Generate blinding factors for the outputs. These are asset blinding factors (abf) and value blinding factors (vbf). The blinding factors are random except for the final vbf which must be calculated by calling -:c:func:`asset_final_vbf`. +:c:func:`wally_asset_final_vbf`. .. literalinclude:: ../../src/pyexample/liquid/receive-send.py :start-after: start-blinding_factors @@ -95,7 +95,7 @@ random except for the final vbf which must be calculated by calling A confidential output address can be decomposed into a standard address plus the public blinding key, and the libwally function -`address_to_scriptpubkey` will provide the corresponding script pubkey. +:c:func:`wally_address_to_scriptpubkey` will provide the corresponding script pubkey. .. literalinclude:: ../../src/pyexample/liquid/receive-send.py :start-after: start-decompose_address @@ -130,7 +130,7 @@ Sign the transaction inputs. :end-before: end-sign The transaction is now ready to be broadcast, the hex value is easily -retrieved by calling `tx_to_hex`. +retrieved by calling :c:func:`wally_tx_to_hex`. .. literalinclude:: ../../src/pyexample/liquid/receive-send.py :start-after: start-to_hex From aebd38693bf384085a5ea3b3a3bbaf1dbe50124c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 09:18:23 +1200 Subject: [PATCH 015/205] docs: Fix sphinx warning --- include/wally_transaction.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 0f6b953fc..6e1350883 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -935,7 +935,7 @@ WALLY_CORE_API int wally_tx_elements_issuance_calculate_asset( * :param entropy: The asset entropy. * :param entropy_len: Size of ``entropy`` in bytes. Must be ``SHA256_LEN``. * :param flags: ``WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE`` if initial issuance was blinded, - * | pass 0 otherwise. + *| pass 0 otherwise. * :param bytes_out: Destination for the re-issuance token. * :param len: Size of ``bytes_out`` in bytes. Must be ``SHA256_LEN``. */ From 3a1f622766e256c80b0debc5266a67fa577f0479 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 09:19:26 +1200 Subject: [PATCH 016/205] elements: Remove redundant goto's --- src/elements.c | 52 +++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/src/elements.c b/src/elements.c index a67ea0de7..fc5d6b0eb 100644 --- a/src/elements.c +++ b/src/elements.c @@ -233,29 +233,25 @@ int wally_asset_rangeproof(uint64_t value, { const secp256k1_context *ctx = secp_ctx(); struct sha256 nonce_hash; - int ret = WALLY_EINVAL; + int ret; if (!ctx) return WALLY_ENOMEM; ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, &nonce_hash); - if (ret != WALLY_OK) - goto cleanup; - - ret = wally_asset_rangeproof_with_nonce(value, - nonce_hash.u.u8, SHA256_LEN, - asset, asset_len, - abf, abf_len, - vbf, vbf_len, - commitment, commitment_len, - extra, extra_len, - generator, generator_len, - min_value, exp, min_bits, - bytes_out, len, written); + if (ret == WALLY_OK) + ret = wally_asset_rangeproof_with_nonce(value, + nonce_hash.u.u8, SHA256_LEN, + asset, asset_len, + abf, abf_len, + vbf, vbf_len, + commitment, commitment_len, + extra, extra_len, + generator, generator_len, + min_value, exp, min_bits, + bytes_out, len, written); -cleanup: wally_clear(&nonce_hash, sizeof(nonce_hash)); - return ret; } @@ -331,22 +327,18 @@ int wally_asset_unblind(const unsigned char *pub_key, size_t pub_key_len, return WALLY_ENOMEM; ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, &nonce_hash); - if (ret != WALLY_OK) - goto cleanup; - - ret = wally_asset_unblind_with_nonce(nonce_hash.u.u8, SHA256_LEN, - proof, proof_len, - commitment, commitment_len, - extra, extra_len, - generator, generator_len, - asset_out, asset_out_len, - abf_out, abf_out_len, - vbf_out, vbf_out_len, - value_out); + if (ret == WALLY_OK) + ret = wally_asset_unblind_with_nonce(nonce_hash.u.u8, SHA256_LEN, + proof, proof_len, + commitment, commitment_len, + extra, extra_len, + generator, generator_len, + asset_out, asset_out_len, + abf_out, abf_out_len, + vbf_out, vbf_out_len, + value_out); -cleanup: wally_clear(&nonce_hash, sizeof(nonce_hash)); - return ret; } From 42805194b6ab3e3cf702fd464f36b94e1eb2138e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 09:20:51 +1200 Subject: [PATCH 017/205] tests: Actually check pubkey recovery results --- src/swig_java/src/com/blockstream/test/test_bip32.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/swig_java/src/com/blockstream/test/test_bip32.java b/src/swig_java/src/com/blockstream/test/test_bip32.java index 45251672b..dc2e38895 100644 --- a/src/swig_java/src/com/blockstream/test/test_bip32.java +++ b/src/swig_java/src/com/blockstream/test/test_bip32.java @@ -59,14 +59,18 @@ public void test() { message, EC_FLAG_ECDSA | EC_FLAG_RECOVERABLE); - Arrays.equals(signature, Arrays.copyOfRange(signatureRecoverable, 1, 65)); + if (!Arrays.equals(signature, Arrays.copyOfRange(signatureRecoverable, 1, 65))) { + throw new RuntimeException("Recoverable signature does not match"); + } final byte[] pubkey = Wally.bip32_key_get_pub_key(derivedKey); Wally.ec_sig_verify(pubkey, message, EC_FLAG_ECDSA, signature); Wally.ec_sig_verify(pubkey, message, EC_FLAG_ECDSA, Arrays.copyOfRange(signatureRecoverable, 1, 65)); final byte[] pubkey_recovered = Wally.ec_sig_to_public_key(message, signatureRecoverable); - Arrays.equals(pubkey, pubkey_recovered); + if (!Arrays.equals(pubkey, pubkey_recovered)) { + throw new RuntimeException("Failed to recover pubkey from signature"); + } Wally.bip32_key_free(initKey); Wally.bip32_key_free(derivedKey); From 5d7f840681abf617d60ac755c368c5ac29b6888f Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 09:23:12 +1200 Subject: [PATCH 018/205] docs: Fix sphinx warning --- include/wally_crypto.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/wally_crypto.h b/include/wally_crypto.h index 1a557d95e..ad30ef753 100644 --- a/include/wally_crypto.h +++ b/include/wally_crypto.h @@ -347,7 +347,7 @@ WALLY_CORE_API int wally_ec_public_key_decompress( * Negates a public key. * * :param pub_key: The public key to negate. - * :param pub_key_len:: The length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. + * :param pub_key_len: The length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. * :param bytes_out: Destination for the resulting public key. * :param len: The length of ``bytes_out`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. */ From 91b84a038552815ee2170f3260560bb1e326cda8 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 09:24:17 +1200 Subject: [PATCH 019/205] ecdh: Use priv_key for param name, fix docs, expose nicely to Java --- include/wally_crypto.h | 14 +++++++------- src/ecdh.c | 21 ++++++++++----------- src/swig_java/jni_extra.java_in | 4 ++++ 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/include/wally_crypto.h b/include/wally_crypto.h index ad30ef753..2cca1f9ba 100644 --- a/include/wally_crypto.h +++ b/include/wally_crypto.h @@ -495,16 +495,16 @@ WALLY_CORE_API int wally_format_bitcoin_message(const unsigned char *bytes, * Compute an EC Diffie-Hellman secret in constant time * * :param pub_key: The public key. - * :param pub_key_len: The length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. - * :param bytes: The private key. - * :param bytes_len: The length of ``privkey`` in bytes. Must be ``EC_PRIVATE_KEY_LEN``. - * :param output: Destination for the shared secret. - * :param output_len: The length of ``output`` in bytes. Must be ``SHA256_LEN``. + * :param pub_key_len: The length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. + * :param priv_key: The private key. + * :param priv_key_len: The length of ``priv_key`` in bytes. Must be ``EC_PRIVATE_KEY_LEN``. + * :param bytes_out: Destination for the shared secret. + * :param len: The length of ``bytes_out`` in bytes. Must be ``SHA256_LEN``. */ WALLY_CORE_API int wally_ecdh(const unsigned char *pub_key, size_t pub_key_len, - const unsigned char *bytes, - size_t bytes_len, + const unsigned char *priv_key, + size_t priv_key_len, unsigned char *bytes_out, size_t len); diff --git a/src/ecdh.c b/src/ecdh.c index 88844c519..b01c43bdf 100644 --- a/src/ecdh.c +++ b/src/ecdh.c @@ -4,30 +4,29 @@ #include "secp256k1/include/secp256k1_ecdh.h" int wally_ecdh(const unsigned char *pub_key, size_t pub_key_len, - const unsigned char *bytes, size_t bytes_len, + const unsigned char *priv_key, size_t priv_key_len, unsigned char *bytes_out, size_t len) { const secp256k1_context *ctx = secp_ctx(); secp256k1_pubkey pub; + int ret = WALLY_OK; if (!ctx) return WALLY_ENOMEM; if (!pub_key || pub_key_len != EC_PUBLIC_KEY_LEN || - !pubkey_parse(ctx, &pub, pub_key, pub_key_len) || - !bytes || bytes_len != EC_PRIVATE_KEY_LEN || - !secp256k1_ec_seckey_verify(ctx, bytes) || - !bytes_out || len != SHA256_LEN) { - wally_clear(&pub, sizeof(pub)); + !priv_key || priv_key_len != EC_PRIVATE_KEY_LEN || + !bytes_out || len != SHA256_LEN) return WALLY_EINVAL; - } - if (!secp256k1_ecdh(ctx, bytes_out, &pub, bytes, NULL, NULL)) { - wally_clear(&pub, sizeof(pub)); + if (!pubkey_parse(ctx, &pub, pub_key, pub_key_len) || + !secp256k1_ec_seckey_verify(ctx, priv_key)) { + ret = WALLY_EINVAL; + } else if (!secp256k1_ecdh(ctx, bytes_out, &pub, priv_key, NULL, NULL)) { wally_clear(bytes_out, len); - return WALLY_ERROR; + ret = WALLY_ERROR; } wally_clear(&pub, sizeof(pub)); - return WALLY_OK; + return ret; } diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index 64867caad..f656565c2 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -76,6 +76,10 @@ return bip38_to_private_key(jarg1, jarg2, jarg3, null); } + public final static byte[] ecdh(byte[] jarg1, byte[] jarg2) { + return ecdh(jarg1, jarg2, null); + } + public final static byte[] sha256(byte[] jarg1) { return sha256(jarg1, null); } From fe605a62d28903ca557a808dbc6bda67317af4cd Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 10:24:55 +1200 Subject: [PATCH 020/205] elements: Use wally for hashing in get_nonce_hash() --- src/elements.c | 49 ++++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 27 deletions(-) diff --git a/src/elements.c b/src/elements.c index fc5d6b0eb..0e4bfb23f 100644 --- a/src/elements.c +++ b/src/elements.c @@ -9,7 +9,6 @@ #include "src/secp256k1/include/secp256k1_surjectionproof.h" #include "src/secp256k1/include/secp256k1_whitelist.h" #include "secp256k1/include/secp256k1_ecdh.h" -#include "ccan/ccan/crypto/sha256/sha256.h" #include #ifdef BUILD_ELEMENTS @@ -39,29 +38,23 @@ static int get_commitment(const secp256k1_context *ctx, static int get_nonce_hash(const secp256k1_context *ctx, const unsigned char *pub_key, size_t pub_key_len, const unsigned char *priv_key, size_t priv_key_len, - struct sha256 *dest) { + unsigned char *bytes_out, size_t len) { secp256k1_pubkey pub; unsigned char nonce[32]; int ret = WALLY_EINVAL; - if (!pub_key || pub_key_len != EC_PUBLIC_KEY_LEN || - !pubkey_parse(ctx, &pub, pub_key, pub_key_len) || - wally_ec_private_key_verify(priv_key, priv_key_len) != WALLY_OK || - !dest) - goto cleanup; - - /* Create the nonce */ - if (!secp256k1_ecdh(ctx, nonce, &pub, priv_key, NULL, NULL)) { - ret = WALLY_ERROR; - goto cleanup; + /* Note that only compressed public keys are supported */ + if (pub_key && pub_key_len == EC_PUBLIC_KEY_LEN && + pubkey_parse(ctx, &pub, pub_key, pub_key_len) && + wally_ec_private_key_verify(priv_key, priv_key_len) == WALLY_OK && + bytes_out && len == SHA256_LEN) { + /* Create the nonce */ + if (secp256k1_ecdh(ctx, nonce, &pub, priv_key, NULL, NULL)) + ret = wally_sha256(nonce, sizeof(nonce), bytes_out, len); + else + ret = WALLY_ERROR; } - wally_sha256(nonce, sizeof(nonce), dest->u.u8, sizeof(*dest)); - - ret = WALLY_OK; - -cleanup: wally_clear_2(&pub, sizeof(pub), nonce, sizeof(nonce)); - return ret; } @@ -232,16 +225,17 @@ int wally_asset_rangeproof(uint64_t value, size_t *written) { const secp256k1_context *ctx = secp_ctx(); - struct sha256 nonce_hash; + unsigned char nonce_hash[SHA256_LEN]; int ret; if (!ctx) return WALLY_ENOMEM; - ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, &nonce_hash); + ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, + nonce_hash, sizeof(nonce_hash)); if (ret == WALLY_OK) ret = wally_asset_rangeproof_with_nonce(value, - nonce_hash.u.u8, SHA256_LEN, + nonce_hash, sizeof(nonce_hash), asset, asset_len, abf, abf_len, vbf, vbf_len, @@ -251,7 +245,7 @@ int wally_asset_rangeproof(uint64_t value, min_value, exp, min_bits, bytes_out, len, written); - wally_clear(&nonce_hash, sizeof(nonce_hash)); + wally_clear(nonce_hash, sizeof(nonce_hash)); return ret; } @@ -320,15 +314,16 @@ int wally_asset_unblind(const unsigned char *pub_key, size_t pub_key_len, uint64_t *value_out) { const secp256k1_context *ctx = secp_ctx(); - struct sha256 nonce_hash; - int ret = WALLY_EINVAL; + unsigned char nonce_hash[SHA256_LEN]; + int ret; if (!ctx) return WALLY_ENOMEM; - ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, &nonce_hash); + ret = get_nonce_hash(ctx, pub_key, pub_key_len, priv_key, priv_key_len, + nonce_hash, sizeof(nonce_hash)); if (ret == WALLY_OK) - ret = wally_asset_unblind_with_nonce(nonce_hash.u.u8, SHA256_LEN, + ret = wally_asset_unblind_with_nonce(nonce_hash, sizeof(nonce_hash), proof, proof_len, commitment, commitment_len, extra, extra_len, @@ -338,7 +333,7 @@ int wally_asset_unblind(const unsigned char *pub_key, size_t pub_key_len, vbf_out, vbf_out_len, value_out); - wally_clear(&nonce_hash, sizeof(nonce_hash)); + wally_clear(nonce_hash, sizeof(nonce_hash)); return ret; } From 1003309f7ae6213717060a403252b3bd8cc91081 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 10:37:44 +1200 Subject: [PATCH 021/205] SWIG: Add missing nonce_hash to Java bindings --- src/swig_java/swig.i | 1 + 1 file changed, 1 insertion(+) diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index aba0dd17a..f5466769a 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -234,6 +234,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %apply(char *STRING, size_t LENGTH) { (const unsigned char *output_asset, size_t output_asset_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *output_generator, size_t output_generator_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *nonce, size_t nonce_len) }; +%apply(char *STRING, size_t LENGTH) { (const unsigned char *nonce_hash, size_t nonce_hash_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *pass, size_t pass_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *parent160, size_t parent160_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *priv_key, size_t priv_key_len) }; From a28196170bdcf49985f82e407bd46c7a155c9907 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 11:14:33 +1200 Subject: [PATCH 022/205] SWIG: Silence JS wrapper build warnings --- src/wrap_js/src/combined.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wrap_js/src/combined.c b/src/wrap_js/src/combined.c index b8469ca23..27e8db552 100644 --- a/src/wrap_js/src/combined.c +++ b/src/wrap_js/src/combined.c @@ -36,6 +36,7 @@ void wally_silence_unused_warnings(void) assert_bip32_assumptions(); assert_bip38_assumptions(); assert_tx_assumptions(); + secp256k1_fe_inv_all_var(NULL, NULL, 0); secp256k1_ge_set_all_gej_var(NULL, NULL, 0); secp256k1_gej_has_quad_y_var(NULL); secp256k1_gej_is_valid_var(NULL); @@ -43,6 +44,8 @@ void wally_silence_unused_warnings(void) secp256k1_ecmult_multi_var(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); secp256k1_ecmult_strauss_batch_single(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); secp256k1_ecmult_pippenger_batch_single(NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0); + secp256k1_pippenger_scratch_size(0, 0); + secp256k1_scalar_chacha20(NULL, NULL, NULL, 0); tx_elements_input_issuance_proof_init(NULL, NULL, 0, NULL, 0); tx_elements_output_proof_init(NULL, NULL, 0, NULL, 0); witness_stack_from_bytes(NULL, NULL, NULL); From d2c5d2cb512f085cda2ac9d5a464bfc52fa29ef4 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 11:18:21 +1200 Subject: [PATCH 023/205] tests: Remove hashbangs from python tests --- src/test/test_address.py | 1 - src/test/test_wif.py | 1 - 2 files changed, 2 deletions(-) diff --git a/src/test/test_address.py b/src/test/test_address.py index ce4385c04..d9094e92f 100755 --- a/src/test/test_address.py +++ b/src/test/test_address.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python3 import unittest from util import * diff --git a/src/test/test_wif.py b/src/test/test_wif.py index f28a5b646..5b0f3841d 100644 --- a/src/test/test_wif.py +++ b/src/test/test_wif.py @@ -1,4 +1,3 @@ -#!/usr/bin/env python import unittest from util import * From 73cdf0a65f8a4515501ffe3f95f2148611364173 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 11:53:05 +1200 Subject: [PATCH 024/205] address.c: Remove unused includes --- src/address.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/address.c b/src/address.c index 492610aed..d4e11c93b 100644 --- a/src/address.c +++ b/src/address.c @@ -1,7 +1,5 @@ #include "internal.h" -#include "base58.h" #include -#include "ccan/ccan/build_assert/build_assert.h" #include #include #include From 2203ec38ff1b5d578d96dd6d30daeafc29142d02 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 12:01:45 +1200 Subject: [PATCH 025/205] wally_bip32_key_to_addr_segwit: Clear witness program before returning --- src/address.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/address.c b/src/address.c index d4e11c93b..c0ce07442 100644 --- a/src/address.c +++ b/src/address.c @@ -68,6 +68,8 @@ int wally_bip32_key_to_addr_segwit(const struct ext_key *hdkey, const char *addr return WALLY_EINVAL; ret = wally_addr_segwit_from_bytes(witness_program_bytes, HASH160_LEN + 2, addr_family, flags, output); + + wally_clear(witness_program_bytes, sizeof(witness_program_bytes)); return ret; } From 118cc76989db55c751f383e8d4ce9b53ca9cba19 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 12:36:22 +1200 Subject: [PATCH 026/205] SWIG: Java wrapper and test for ec_public_key_negate() --- src/swig_java/jni_extra.java_in | 4 ++++ .../src/com/blockstream/test/test_bip32.java | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index f656565c2..89e5b18a8 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -123,6 +123,10 @@ return ec_public_key_from_private_key(jarg1, null); } + public final static byte[] ec_public_key_negate(byte[] jarg1) { + return ec_public_key_negate(jarg1, null); + } + public final static byte[] ec_sig_from_bytes(byte[] jarg1, byte[] jarg2, long jarg3) { return ec_sig_from_bytes(jarg1, jarg2, jarg3, null); } diff --git a/src/swig_java/src/com/blockstream/test/test_bip32.java b/src/swig_java/src/com/blockstream/test/test_bip32.java index dc2e38895..c6512f2bb 100644 --- a/src/swig_java/src/com/blockstream/test/test_bip32.java +++ b/src/swig_java/src/com/blockstream/test/test_bip32.java @@ -72,6 +72,17 @@ public void test() { throw new RuntimeException("Failed to recover pubkey from signature"); } + // Test pubkey negation + final byte[] pubkey_negated = Wally.ec_public_key_negate(pubkey_recovered); + if (Arrays.equals(pubkey_recovered, pubkey_negated)) { + throw new RuntimeException("Failed to negate pubkey"); + } + + final byte[] pubkey_unnegated = Wally.ec_public_key_negate(pubkey_negated); + if (!Arrays.equals(pubkey_recovered, pubkey_unnegated)) { + throw new RuntimeException("Double negation did not return original pubkey"); + } + Wally.bip32_key_free(initKey); Wally.bip32_key_free(derivedKey); Wally.bip32_key_free(unserialized); From 333edf13e6c103a70af5d5247e4f8ded3323a740 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 12:56:00 +1200 Subject: [PATCH 027/205] Compare return codes to WALLY_OK for consistency --- src/bip32.c | 10 +++++----- src/wif.c | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bip32.c b/src/bip32.c index 7150b41c6..08275fb13 100644 --- a/src/bip32.c +++ b/src/bip32.c @@ -338,7 +338,7 @@ int bip32_key_unserialize_alloc(const unsigned char *bytes, size_t bytes_len, ALLOC_KEY(); ret = bip32_key_unserialize(bytes, bytes_len, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } @@ -505,7 +505,7 @@ int bip32_key_from_parent_alloc(const struct ext_key *hdkey, ALLOC_KEY(); ret = bip32_key_from_parent(hdkey, child_num, flags, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } @@ -561,7 +561,7 @@ int bip32_key_from_parent_path_alloc(const struct ext_key *hdkey, ALLOC_KEY(); ret = bip32_key_from_parent_path(hdkey, child_path, child_path_len, flags, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } @@ -608,7 +608,7 @@ int bip32_key_with_tweak_from_parent_path_alloc(const struct ext_key *hdkey, ALLOC_KEY(); ret = bip32_key_with_tweak_from_parent_path(hdkey, child_path, child_path_len, flags, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = NULL; } @@ -742,7 +742,7 @@ int bip32_key_from_base58_alloc(const char *base58, ALLOC_KEY(); ret = bip32_key_from_base58(base58, *output); - if (ret) { + if (ret != WALLY_OK) { wally_free(*output); *output = 0; } diff --git a/src/wif.c b/src/wif.c index 4a4535ca0..4e487acb1 100644 --- a/src/wif.c +++ b/src/wif.c @@ -74,7 +74,7 @@ int wally_wif_to_bytes(const char *wif, ret = is_uncompressed(wif, buf, sizeof(buf), &uncompressed); - if (ret || + if (ret != WALLY_OK || (buf[0] != prefix) || (uncompressed && flags != WALLY_WIF_FLAG_UNCOMPRESSED) || (!uncompressed && flags != WALLY_WIF_FLAG_COMPRESSED)) { @@ -139,7 +139,7 @@ int wally_wif_to_public_key(const char *wif, } else ret = wally_ec_public_key_from_private_key(&buf[1], EC_PRIVATE_KEY_LEN, bytes_out, EC_PUBLIC_KEY_LEN); - if (ret) + if (ret != WALLY_OK) *written = 0; wally_clear_2(buf, sizeof(buf), pub_key, sizeof(pub_key)); From 52cdf7cfe914823b5c9d9ae21726646812b757ef Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 13:58:55 +1200 Subject: [PATCH 028/205] pegin_contract_script_from_bytes: Don't use 'written' as a general variable This ensures we leave written as 0 in the case of an error. --- src/script.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/script.c b/src/script.c index ef5e9feeb..f8474bf01 100644 --- a/src/script.c +++ b/src/script.c @@ -1000,6 +1000,8 @@ int wally_elements_pegin_contract_script_from_bytes(const unsigned char *redeem_ secp256k1_pubkey pub_key_tweaked; const secp256k1_pubkey *pub_key_combination[2]; secp256k1_pubkey pub_key_combined; + size_t push_size; + if (!pubkey_parse(ctx, &pub_key, p + 1, EC_PUBLIC_KEY_LEN)) return WALLY_ERROR; memcpy(&pub_key_tweaked, &pub_key, sizeof(pub_key)); @@ -1009,9 +1011,8 @@ int wally_elements_pegin_contract_script_from_bytes(const unsigned char *redeem_ return WALLY_ERROR; if (!pubkey_serialize(ctx, ser_pub_key, &ser_len, &pub_key_tweaked, PUBKEY_COMPRESSED)) return WALLY_ERROR; - if ((ret = wally_script_push_from_bytes(ser_pub_key, ser_len, 0, q, bytes_len, written)) != WALLY_OK) + if ((ret = wally_script_push_from_bytes(ser_pub_key, ser_len, 0, q, bytes_len, &push_size)) != WALLY_OK) return ret; - /* sanity checks as per elementsd */ if (!pubkey_create(ctx, &pub_key_from_tweak, tweak)) return WALLY_ERROR; From e312d478511315f982fe48f695ab21dab414317e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 14:56:26 +1200 Subject: [PATCH 029/205] address_to_scriptpubkey: Use common variable name for consistency --- src/address.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/address.c b/src/address.c index c0ce07442..84749023b 100644 --- a/src/address.c +++ b/src/address.c @@ -118,29 +118,28 @@ int wally_address_to_scriptpubkey(const char *addr, uint32_t network, unsigned c size_t len, size_t *written) { uint32_t version, addr_network; - unsigned char bytes_base58_decode[1 + HASH160_LEN + BASE58_CHECKSUM_LEN]; - size_t written_base58_decode; + unsigned char decoded[1 + HASH160_LEN + BASE58_CHECKSUM_LEN]; + size_t decoded_len; if (written) *written = 0; - /* This returns WALLY_OK even if addr is too long for bytes_base58_decode */ - if (wally_base58_to_bytes(addr, BASE58_FLAG_CHECKSUM, bytes_base58_decode, sizeof(bytes_base58_decode), &written_base58_decode) != WALLY_OK) + if (wally_base58_to_bytes(addr, BASE58_FLAG_CHECKSUM, decoded, sizeof(decoded), &decoded_len) != WALLY_OK) return WALLY_EINVAL; - if (written_base58_decode != HASH160_LEN + 1) + if (decoded_len != HASH160_LEN + 1) return WALLY_EINVAL; - version = bytes_base58_decode[0]; + version = decoded[0]; if (network_from_addr_version(version, &addr_network) != WALLY_OK) return WALLY_EINVAL; if (network != addr_network) return WALLY_EINVAL; if (is_p2pkh(version)) { - return wally_scriptpubkey_p2pkh_from_bytes(bytes_base58_decode + 1, HASH160_LEN, 0, bytes_out, len, written); + return wally_scriptpubkey_p2pkh_from_bytes(decoded + 1, HASH160_LEN, 0, bytes_out, len, written); } else if (is_p2sh(version)) { - return wally_scriptpubkey_p2sh_from_bytes(bytes_base58_decode + 1, HASH160_LEN, 0, bytes_out, len, written); + return wally_scriptpubkey_p2sh_from_bytes(decoded + 1, HASH160_LEN, 0, bytes_out, len, written); } else { return WALLY_EINVAL; } From 5af73588cc4cd0706490888aa9c77ae1865e2531 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 15:01:23 +1200 Subject: [PATCH 030/205] scriptpubkey_to_address: Don't ignore base58 errors For example, output being NULL should return WALLY_EINVAL. --- src/address.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/address.c b/src/address.c index 84749023b..11f8da76b 100644 --- a/src/address.c +++ b/src/address.c @@ -199,6 +199,6 @@ int wally_scriptpubkey_to_address(const unsigned char *scriptpubkey, size_t scri } ret = wally_base58_from_bytes(bytes, sizeof(bytes), BASE58_FLAG_CHECKSUM, output); wally_clear(bytes, sizeof(bytes)); - return WALLY_OK; + return ret; } From ec215ea4e14235f1337537c82d1389c62ff032cd Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 16:00:05 +1200 Subject: [PATCH 031/205] clone_tx: Simplify, constify, ensure input is valid --- src/transaction.c | 35 +++++++++++++++-------------------- src/transaction_shared.h | 2 +- 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/transaction.c b/src/transaction.c index ed2915846..e0ff857a8 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -3236,34 +3236,29 @@ int wally_tx_input_set_script(struct wally_tx_input *input, TX_SET_B(input, script) -int clone_tx(struct wally_tx *tx, struct wally_tx **output) +int clone_tx(const struct wally_tx *tx, struct wally_tx **output) { - int ret = WALLY_OK; size_t i; struct wally_tx *result = NULL; + int ret; TX_CHECK_OUTPUT; - if ((ret = wally_tx_init_alloc(tx->version, tx->locktime, tx->num_inputs, tx->num_outputs, &result)) != WALLY_OK) { - goto fail; - } - for (i = 0; i < tx->num_inputs; ++i) { - if ((ret = wally_tx_add_input(result, &tx->inputs[i])) != WALLY_OK) { - goto fail; - } - } - for (i = 0; i < tx->num_outputs; ++i) { - if ((ret = wally_tx_add_output(result, &tx->outputs[i])) != WALLY_OK) { - goto fail; - } - } - *output = result; + if (!is_valid_tx(tx)) + return WALLY_EINVAL; - return WALLY_OK; + ret = wally_tx_init_alloc(tx->version, tx->locktime, tx->num_inputs, tx->num_outputs, &result); -fail: - if (result) { + for (i = 0; ret == WALLY_OK && i < tx->num_inputs; ++i) + ret = wally_tx_add_input(result, &tx->inputs[i]); + + for (i = 0; ret == WALLY_OK && i < tx->num_outputs; ++i) + ret = wally_tx_add_output(result, &tx->outputs[i]); + + if (ret == WALLY_OK) + *output = result; + else wally_tx_free(result); - } + return ret; } diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 109b7c0f1..cfca48e99 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -19,7 +19,7 @@ int analyze_tx(const unsigned char *bytes, size_t bytes_len, bool *expect_witnesses); struct wally_tx_witness_stack *clone_witness( const struct wally_tx_witness_stack *stack); -int clone_tx(struct wally_tx *tx, struct wally_tx **output); +int clone_tx(const struct wally_tx *tx, struct wally_tx **output); #ifdef __cplusplus } From e4c4ae9da4edaea0e14fd598580f5bfe28e24ccd Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 16:51:15 +1200 Subject: [PATCH 032/205] clone_tx: expose as wally_tx_clone, add tests --- include/wally.hpp | 1 + include/wally_transaction.h | 12 ++++++++++++ src/psbt.c | 10 +++++----- src/swig_java/swig.i | 1 + src/test/test_transaction.py | 34 +++++++++++++++++++++------------- src/test/util.py | 1 + src/transaction.c | 4 ++-- src/transaction_shared.h | 1 - 8 files changed, 43 insertions(+), 21 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index e35152b33..22ee8970d 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -406,6 +406,7 @@ WALLY_FN_P3B(tx_witness_stack_set, wally_tx_witness_stack_set) WALLY_FN_P3B633_B(tx_get_btc_signature_hash, wally_tx_get_btc_signature_hash) WALLY_FN_P3BB36333_B(tx_get_signature_hash, wally_tx_get_signature_hash) WALLY_FN_P3_A(bip32_key_to_base58, bip32_key_to_base58) +WALLY_FN_P3_A(tx_clone, wally_tx_clone) WALLY_FN_P3_A(tx_from_hex, wally_tx_from_hex) WALLY_FN_P3_A(tx_to_hex, wally_tx_to_hex) WALLY_FN_P3_B(bip32_key_serialize, bip32_key_serialize) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 6e1350883..46d9ea81e 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -269,6 +269,18 @@ WALLY_CORE_API int wally_tx_init_alloc( size_t outputs_allocation_len, struct wally_tx **output); +/** + * Create a new copy of a transaction. + * + * :param tx: The transaction to clone. + * :param flags: Flags controlling script creation. Must be 0. + * :param output: Destination for the resulting transaction copy. + */ +WALLY_CORE_API int wally_tx_clone( + const struct wally_tx *tx, + uint32_t flags, + struct wally_tx **output); + /** * Add a transaction input to a transaction. * diff --git a/src/psbt.c b/src/psbt.c index e7c5661b0..f3de130b2 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -448,7 +448,7 @@ int wally_psbt_input_set_non_witness_utxo( int ret = WALLY_OK; struct wally_tx *result_non_witness_utxo; - if ((ret = clone_tx(non_witness_utxo, &result_non_witness_utxo)) != WALLY_OK) { + if ((ret = wally_tx_clone(non_witness_utxo, 0, &result_non_witness_utxo)) != WALLY_OK) { return ret; } wally_tx_free(input->non_witness_utxo); @@ -787,7 +787,7 @@ int wally_psbt_set_global_tx( } } - if ((ret = clone_tx(tx, &psbt->tx)) != WALLY_OK) { + if ((ret = wally_tx_clone(tx, 0, &psbt->tx)) != WALLY_OK) { goto fail; } @@ -2302,7 +2302,7 @@ static int merge_input_into( int ret = WALLY_OK; size_t i, j; - if (!dst->non_witness_utxo && src->non_witness_utxo && (ret = clone_tx(src->non_witness_utxo, &dst->non_witness_utxo)) != WALLY_OK) { + if (!dst->non_witness_utxo && src->non_witness_utxo && (ret = wally_tx_clone(src->non_witness_utxo, 0, &dst->non_witness_utxo)) != WALLY_OK) { return ret; } if (!dst->witness_utxo && src->witness_utxo && (ret = wally_tx_output_init_alloc(src->witness_utxo->satoshi, src->witness_utxo->script, src->witness_utxo->script_len, &dst->witness_utxo)) != WALLY_OK) { @@ -2464,7 +2464,7 @@ int wally_combine_psbts( return ret; } - if ((ret = clone_tx(psbts[0].tx, &result->tx)) != WALLY_OK) { + if ((ret = wally_tx_clone(psbts[0].tx, 0, &result->tx)) != WALLY_OK) { goto fail; } result->num_inputs = psbts[0].num_inputs; @@ -2942,7 +2942,7 @@ int wally_extract_psbt( return WALLY_EINVAL; } - clone_tx(psbt->tx, &result); + wally_tx_clone(psbt->tx, 0, &result); for (i = 0; i < psbt->num_inputs; ++i) { struct wally_psbt_input *input = &psbt->inputs[i]; diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index f5466769a..3d4614d3c 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -557,6 +557,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(wally_tx_get_weight); %returns_size_t(wally_tx_get_witness_count); %returns_struct(wally_tx_init_alloc, wally_tx); +%returns_struct(wally_tx_clone, wally_tx); %rename("tx_init") wally_tx_init_alloc; %returns_void__(wally_tx_input_free); %returns_array_(wally_tx_input_get_blinding_nonce, 2, 3, SHA256_LEN); diff --git a/src/test/test_transaction.py b/src/test/test_transaction.py index 6b1d06db4..f9a5e0e96 100644 --- a/src/test/test_transaction.py +++ b/src/test/test_transaction.py @@ -24,33 +24,41 @@ def tx_serialize_hex(self, tx): def test_serialization(self): """Testing serialization and deserialization""" + tx_out = pointer(wally_tx()) + tx_copy = pointer(wally_tx()) for args in [ - (utf8(''), 0, pointer(wally_tx())), # Empty hex - (utf8('00'*5), 0, pointer(wally_tx())), # Short hex + (utf8(''), 0, tx_out), # Empty hex + (utf8('00'*5), 0, tx_out), # Short hex (TX_FAKE_HEX, 0, None), # Empty output - (TX_FAKE_HEX, 4, pointer(wally_tx())), # Unsupported flag - (TX_WITNESS_HEX[:11]+utf8('0')+TX_WITNESS_HEX[12:], 0, pointer(wally_tx())), # Invalid witness flag + (TX_FAKE_HEX, 4, tx_out), # Unsupported flag + (TX_WITNESS_HEX[:11]+utf8('0')+TX_WITNESS_HEX[12:], 0, tx_out), # Invalid witness flag ]: self.assertEqual(WALLY_EINVAL, wally_tx_from_hex(*args)) # deserialization is allowed, but the opposite is not for args in [ - (TX_FAKE_HEX[:9]+utf8('0')+TX_FAKE_HEX[92:], 0, pointer(wally_tx())), # No inputs - (TX_FAKE_HEX[:93]+utf8('0')+TX_FAKE_HEX[112:], 0, pointer(wally_tx())), # No outputs - (TX_FAKE_HEX, 2, pointer(wally_tx())), # Elements flag must not be set for serialization + (TX_FAKE_HEX[:9]+utf8('0')+TX_FAKE_HEX[92:], 0, tx_out), # No inputs + (TX_FAKE_HEX[:93]+utf8('0')+TX_FAKE_HEX[112:], 0, tx_out), # No outputs + (TX_FAKE_HEX, 2, tx_out), # Elements flag must not be set for serialization ]: self.assertEqual(WALLY_OK, wally_tx_from_hex(*args)) self.assertEqual(WALLY_EINVAL, wally_tx_to_hex(args[2][0], 0)[0]) + # Check the partial transaction can be cloned + self.assertEqual(WALLY_OK, wally_tx_clone(tx_out, 0, tx_copy)) for args in [ - (TX_HEX, 0, pointer(wally_tx())), - (utf8('00')+TX_HEX[2:], 0, pointer(wally_tx())), - (utf8('ff')+TX_FAKE_HEX[2:], 0, pointer(wally_tx())), - (TX_FAKE_HEX, 0, pointer(wally_tx())), - (TX_WITNESS_HEX, 0, pointer(wally_tx())), + (TX_HEX, 0, tx_out), + (utf8('00')+TX_HEX[2:], 0, tx_out), + (utf8('ff')+TX_FAKE_HEX[2:], 0, tx_out), + (TX_FAKE_HEX, 0, tx_out), + (TX_WITNESS_HEX, 0, tx_out), ]: self.assertEqual(WALLY_OK, wally_tx_from_hex(*args)) - self.assertEqual(args[0], utf8(self.tx_serialize_hex(args[2][0]))) + tx_hex = utf8(self.tx_serialize_hex(args[2][0])) + self.assertEqual(args[0], tx_hex) + # Check the transaction can be cloned and serializes to the same hex + self.assertEqual(WALLY_OK, wally_tx_clone(tx_out, 0, tx_copy)) + self.assertEqual(tx_hex, utf8(self.tx_serialize_hex(tx_copy))) def test_lengths(self): """Testing functions measuring different lengths for a tx""" diff --git a/src/test/util.py b/src/test/util.py index 0b197e77f..64f612ccd 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -280,6 +280,7 @@ class wally_psbt(Structure): ('wally_tx_to_bytes', c_int, [POINTER(wally_tx), c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_tx_from_bytes', c_int, [c_void_p, c_ulong, c_uint, POINTER(POINTER(wally_tx))]), ('wally_tx_init_alloc', c_int, [c_uint, c_uint, c_ulong, c_ulong, POINTER(POINTER(wally_tx))]), + ('wally_tx_clone', c_int, [POINTER(wally_tx), c_uint, POINTER(POINTER(wally_tx))]), ('wally_tx_free', c_int, [POINTER(wally_tx)]), ('wally_tx_get_length', c_int, [POINTER(wally_tx), c_uint, c_ulong_p]), ('wally_tx_get_vsize', c_int, [POINTER(wally_tx), c_ulong_p]), diff --git a/src/transaction.c b/src/transaction.c index e0ff857a8..9abd30a64 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -3236,7 +3236,7 @@ int wally_tx_input_set_script(struct wally_tx_input *input, TX_SET_B(input, script) -int clone_tx(const struct wally_tx *tx, struct wally_tx **output) +int wally_tx_clone(const struct wally_tx *tx, uint32_t flags, struct wally_tx **output) { size_t i; struct wally_tx *result = NULL; @@ -3244,7 +3244,7 @@ int clone_tx(const struct wally_tx *tx, struct wally_tx **output) TX_CHECK_OUTPUT; - if (!is_valid_tx(tx)) + if (!is_valid_tx(tx) || flags != 0) return WALLY_EINVAL; ret = wally_tx_init_alloc(tx->version, tx->locktime, tx->num_inputs, tx->num_outputs, &result); diff --git a/src/transaction_shared.h b/src/transaction_shared.h index cfca48e99..0eb351de0 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -19,7 +19,6 @@ int analyze_tx(const unsigned char *bytes, size_t bytes_len, bool *expect_witnesses); struct wally_tx_witness_stack *clone_witness( const struct wally_tx_witness_stack *stack); -int clone_tx(const struct wally_tx *tx, struct wally_tx **output); #ifdef __cplusplus } From 89ee3a3e2bb073440ee17d9f2bace50910a905ba Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 2 Jul 2020 19:16:21 +1200 Subject: [PATCH 033/205] key_strip_private_key: Use single impl, expose to Java and C++ --- include/wally.hpp | 1 + src/bip32.c | 17 ++++++----------- src/swig_java/swig.i | 5 +++-- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 22ee8970d..6e0f3da7d 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -393,6 +393,7 @@ WALLY_FN_B_S(scriptpubkey_get_type, wally_scriptpubkey_get_type) WALLY_FN_BB33_B(pbkdf2_hmac_sha256, wally_pbkdf2_hmac_sha256) WALLY_FN_BB33_B(pbkdf2_hmac_sha512, wally_pbkdf2_hmac_sha512) WALLY_FN_P(bip32_key_free, bip32_key_free) +WALLY_FN_P(bip32_key_strip_private_key, bip32_key_strip_private_key) WALLY_FN_P(get_operations, wally_get_operations) WALLY_FN_P(set_operations, wally_set_operations) WALLY_FN_P(tx_free, wally_tx_free) diff --git a/src/bip32.c b/src/bip32.c index 08275fb13..feb378df7 100644 --- a/src/bip32.c +++ b/src/bip32.c @@ -85,12 +85,6 @@ static bool key_is_private(const struct ext_key *hdkey) return hdkey->priv_key[0] == BIP32_FLAG_KEY_PRIVATE; } -static void key_strip_private_key(struct ext_key *key_out) -{ - key_out->priv_key[0] = BIP32_FLAG_KEY_PUBLIC; - wally_clear(key_out->priv_key + 1, sizeof(key_out->priv_key) - 1); -} - /* Compute a public key from a private key */ static int key_compute_pub_key(struct ext_key *key_out) { @@ -324,7 +318,7 @@ int bip32_key_unserialize(const unsigned char *bytes, size_t bytes_len, return wipe_key_fail(key_out); /* Public key data in private key */ copy_in(key_out->pub_key, bytes, sizeof(key_out->pub_key)); - key_strip_private_key(key_out); + bip32_key_strip_private_key(key_out); } key_compute_hash160(key_out); @@ -481,7 +475,7 @@ int bip32_key_from_parent(const struct ext_key *hdkey, uint32_t child_num, else key_out->version = BIP32_VER_TEST_PUBLIC; - key_strip_private_key(key_out); + bip32_key_strip_private_key(key_out); } key_out->depth = hdkey->depth + 1; @@ -749,11 +743,12 @@ int bip32_key_from_base58_alloc(const char *base58, return ret; } -int bip32_key_strip_private_key(struct ext_key *hdkey) +int bip32_key_strip_private_key(struct ext_key *key_out) { - if (!hdkey) + if (!key_out) return WALLY_EINVAL; - key_strip_private_key(hdkey); + key_out->priv_key[0] = BIP32_FLAG_KEY_PUBLIC; + wally_clear(key_out->priv_key + 1, sizeof(key_out->priv_key) - 1); return WALLY_OK; } diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index 3d4614d3c..4506c11b8 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -380,8 +380,6 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_struct(bip32_key_from_parent_path_alloc, ext_key); %rename("bip32_key_from_parent_path") bip32_key_from_parent_path_alloc; %returns_struct(bip32_key_from_seed_alloc, ext_key); -%returns_struct(bip32_key_with_tweak_from_parent_path_alloc, ext_key); -%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; %rename("bip32_key_from_seed") bip32_key_from_seed_alloc; %returns_array_(bip32_key_get_chain_code, 2, 3, member_size(ext_key, chain_code)); %returns_size_t(bip32_key_get_child_num); @@ -395,9 +393,12 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_struct(bip32_key_init_alloc, ext_key); %rename("bip32_key_init") bip32_key_init_alloc; %returns_array_(bip32_key_serialize, 3, 4, BIP32_SERIALIZED_LEN); +%returns_void__(bip32_key_strip_private_key); %returns_string(bip32_key_to_base58); %returns_struct(bip32_key_unserialize_alloc, ext_key); %rename("bip32_key_unserialize") bip32_key_unserialize_alloc; +%returns_struct(bip32_key_with_tweak_from_parent_path_alloc, ext_key); +%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; %returns_array_(bip38_raw_from_private_key, 6, 7, BIP38_SERIALIZED_LEN); %returns_string(bip38_from_private_key); %returns_array_(bip38_raw_to_private_key, 6, 7, 32); From 80c49bd4dc9f21bfd989e7a74510ec7100febed1 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 08:44:56 +1200 Subject: [PATCH 034/205] CHANGES: Remove non-API changes from CHANGES.md This file is intended only to show at a glance changes which require users to account for when upgrading. The general release notes are available on the github releases page and detailed changes can be fetched from the git history, so don't attempt to duplicate that info. --- CHANGES.md | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ee784e154..2b1680166 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,49 +2,32 @@ ## Version 0.7.8 -- Deprecate Python 2 wheels -- Honor CFLAGS, default to O2 -- Bug fixing +- Python 2 wheels are now deprecated. Users should move to Python 3 as soon as possible. ## Version 0.7.7 -- Expose wally_psbt_get_length -- Add wally_scriptpubkey_to_address -- Return written bytes in asset_pak_whitelistproof -- Elements bug fixes +- API change of wally_asset_pak_whitelistproof to return the number of bytes written. ## Version 0.7.6 -- Add flag to sort multisig keys (BIP67) -- Add bip32_key_get_fingerprint -- Add Liquid developer guide -- Add liquid support to address_to_scriptpubkey +- No API changes ## Version 0.7.5 -- Add support for P2PKH, P2SH-P2WPKH, P2WPKH address derivation from BIP32 key -- Add support for P2KH and P2SH address parsing -- Add support for PSBT -- Add support for blech32 -- Add support for pegin and pegout -- Bug fixing, build updates and improvements +- No API changes ## Version 0.7.4 -- Add support for recoverable signatures -- Generalize Elements function to use external nonces -- Expose blinding key functions to js wrapper -- doc improvement and bugs fixing +- No API changes ## Version 0.7.3 -- Exposed ECDH, added py3.7 x86_64 linux wheels to released artifacts, updated - JS bindings to support latest nodejs, doc typos and bug fixing. +- No API changes ## Version 0.7.2 - API change of wally_tx_to_bytes and wally_tx_to_hex to not accept - WALLY_TX_FLAG_USE_ELEMENTS bit set in flags. You should remove such flag when + WALLY_TX_FLAG_USE_ELEMENTS set in flags. You should remove this flag when upgrading. This change affects elements transactions only. ## Version 0.6.5 From 9c7e48e504df23b34d3d11708883e21cc9c8231e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 08:48:18 +1200 Subject: [PATCH 035/205] witness_p2wpkh_from_x: Simplify --- src/script.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/script.c b/src/script.c index f8474bf01..f731b4036 100644 --- a/src/script.c +++ b/src/script.c @@ -1097,18 +1097,15 @@ int wally_witness_p2wpkh_from_der( struct wally_tx_witness_stack **witness) { unsigned char script_sig[WALLY_SCRIPTSIG_P2PKH_MAX_LEN]; + size_t written; int ret; - size_t script_sig_len; - if ((ret = wally_scriptsig_p2pkh_from_der(pub_key, pub_key_len, sig, sig_len, script_sig, WALLY_SCRIPTSIG_P2PKH_MAX_LEN, &script_sig_len)) != WALLY_OK) { - return ret; - } + ret = wally_scriptsig_p2pkh_from_der(pub_key, pub_key_len, sig, sig_len, script_sig, sizeof(script_sig), &written); - if ((ret = scriptsig_to_witness(script_sig, script_sig_len, witness)) != WALLY_OK) { - return ret; - } + if (ret == WALLY_OK) + ret = scriptsig_to_witness(script_sig, written, witness); - return WALLY_OK; + return ret; } int wally_witness_p2wpkh_from_sig( @@ -1120,18 +1117,15 @@ int wally_witness_p2wpkh_from_sig( struct wally_tx_witness_stack **witness) { unsigned char script_sig[WALLY_SCRIPTSIG_P2PKH_MAX_LEN]; + size_t written; int ret; - size_t script_sig_len; - if ((ret = wally_scriptsig_p2pkh_from_sig(pub_key, pub_key_len, sig, sig_len, sighash, script_sig, WALLY_SCRIPTSIG_P2PKH_MAX_LEN, &script_sig_len)) != WALLY_OK) { - return ret; - } + ret = wally_scriptsig_p2pkh_from_sig(pub_key, pub_key_len, sig, sig_len, sighash, script_sig, sizeof(script_sig), &written); - if ((ret = scriptsig_to_witness(script_sig, script_sig_len, witness)) != WALLY_OK) { - return ret; - } + if (ret == WALLY_OK) + ret = scriptsig_to_witness(script_sig, written, witness); - return WALLY_OK; + return ret; } int wally_witness_multisig_from_bytes( From 576235a045cb91a6bd4e8c66c6395e89b4006e27 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 08:49:55 +1200 Subject: [PATCH 036/205] SWIG: Expose wally_address_to_scriptpubkey to Java --- src/swig_java/swig.i | 1 + 1 file changed, 1 insertion(+) diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index 4506c11b8..c9cb36707 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -414,6 +414,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(bip39_mnemonic_to_seed); %returns_string(wally_addr_segwit_from_bytes); %returns_size_t(wally_addr_segwit_to_bytes); +%returns_size_t(wally_address_to_scriptpubkey); %returns_array_(wally_aes, 6, 7, AES_BLOCK_LEN); %returns_size_t(wally_aes_cbc); %returns_array_(wally_asset_final_vbf, 8, 9, ASSET_TAG_LEN); From cd85f67137a58de5b246a8c5a2fdccdc982a2ad7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 10:16:27 +1200 Subject: [PATCH 037/205] tests: Move scriptpubkey tests to cffi and de-duplicate --- src/Makefile.am | 1 - src/swig_python/contrib/address.py | 24 --------------- src/test/test_address.py | 47 +++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 39 deletions(-) delete mode 100644 src/swig_python/contrib/address.py diff --git a/src/Makefile.am b/src/Makefile.am index f69b4cefe..1d13baadf 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -276,7 +276,6 @@ if RUN_PYTHON_TESTS $(AM_V_at)$(PYTHON_TEST) test/test_wif.py $(AM_V_at)$(PYTHON_TEST) test/test_wordlist.py if USE_SWIG_PYTHON - $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/address.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/bip32.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/mnemonic.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/sha.py diff --git a/src/swig_python/contrib/address.py b/src/swig_python/contrib/address.py deleted file mode 100644 index 6b1faab7b..000000000 --- a/src/swig_python/contrib/address.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Tests for addresses""" -import unittest -from wallycore import * - - -h2b = hex_to_bytes - - -class AddressTests(unittest.TestCase): - - def test_b58_address(self): - for address, scriptpubkey, network in [ - ('mxvewdhKCenLkYgNa8irv1UM2omEWPMdEE', h2b('76a914bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe88ac'), WALLY_NETWORK_BITCOIN_TESTNET), # p2pkh - ('2N5XyEfAXtVde7mv6idZDXp5NFwajYEj9TD', h2b('a91486cc442a97817c245ce90ed0d31d6dbcde3841f987'), WALLY_NETWORK_BITCOIN_TESTNET), # p2sh - ('1JQheacLPdM5ySCkrZkV66G2ApAXe1mqLj', h2b('76a914bef5a2f9a56a94aab12459f72ad9cf8cf19c7bbe88ac'), WALLY_NETWORK_BITCOIN_MAINNET), # p2pkh - ('3DymAvEWH38HuzHZ3VwLus673bNZnYwNXu', h2b('a91486cc442a97817c245ce90ed0d31d6dbcde3841f987'), WALLY_NETWORK_BITCOIN_MAINNET), # p2sh - ('XYtnYoGoSeE9ouMEVi6mfeujhjT2VnJncA', h2b('a914ec51ffb65120594389733bf8625f542446d97f7987'), WALLY_NETWORK_LIQUID_REGTEST), - ('H5nswXhfo8AMt159sgA5FWT35De34hVR4o', h2b('a914f80278b2011573a2ac59c83fadf929b0fc57ad0187'), WALLY_NETWORK_LIQUID), - ]: - self.assertEqual(address_to_scriptpubkey(address, network), scriptpubkey) - self.assertEqual(scriptpubkey_to_address(scriptpubkey, network), address) - -if __name__ == '__main__': - unittest.main() diff --git a/src/test/test_address.py b/src/test/test_address.py index d9094e92f..b3e07545f 100755 --- a/src/test/test_address.py +++ b/src/test/test_address.py @@ -12,11 +12,14 @@ ADDRESS_VERSION_P2PKH_MAINNET = 0x00 ADDRESS_VERSION_P2PKH_TESTNET = 0x6F -ADDRESS_VERSION_P2SH_MAINNET = 0x05 -ADDRESS_VERSION_P2SH_TESTNET = 0xC4 +ADDRESS_VERSION_P2SH_MAINNET = 0x05 +ADDRESS_VERSION_P2SH_TESTNET = 0xC4 NETWORK_BITCOIN_MAINNET = 0x01 NETWORK_BITCOIN_TESTNET = 0x02 +NETWORK_LIQUID_MAINNET = 0x03 +NETWORK_LIQUID_REGTEST = 0x04 + # Vector from test_bip32.py. We only need an xpub to derive addresses. vec = { @@ -96,29 +99,29 @@ def do_test_vector(self, vec, path, network): # Address type flag is mandatory version = ADDRESS_VERSION_P2PKH_MAINNET if network == NETWORK_BITCOIN_MAINNET else ADDRESS_VERSION_P2PKH_TESTNET - ret, out = wally_bip32_key_to_address(key, 0, version) + ret, new_addr = wally_bip32_key_to_address(key, 0, version) self.assertEqual(ret, WALLY_EINVAL) # Obtain legacy address (P2PKH) - ret, out = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2PKH, version) + ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2PKH, version) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_legacy']) + self.assertEqual(new_addr, vec[path]['address_legacy']) # Obtain wrapped SegWit address (P2SH_P2WPKH) version = ADDRESS_VERSION_P2SH_MAINNET if network == NETWORK_BITCOIN_MAINNET else ADDRESS_VERSION_P2SH_TESTNET - ret, out = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2SH_P2WPKH, version) + ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2SH_P2WPKH, version) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_p2sh_segwit']) + self.assertEqual(new_addr, vec[path]['address_p2sh_segwit']) # wally_bip32_key_to_address does not support bech32 native SegWit (P2WPKH) - ret, out = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2WPKH, version) + ret, new_addr = wally_bip32_key_to_address(key, ADDRESS_TYPE_P2WPKH, version) self.assertEqual(ret, WALLY_EINVAL) # Obtain native SegWit address (P2WPKH) bech32_prefix = 'bc' if network == NETWORK_BITCOIN_MAINNET else 'tb' - ret, out = wally_bip32_key_to_addr_segwit(key, utf8(bech32_prefix), 0) + ret, new_addr = wally_bip32_key_to_addr_segwit(key, utf8(bech32_prefix), 0) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_segwit']) + self.assertEqual(new_addr, vec[path]['address_segwit']) # Parse legacy address (P2PKH): out, out_len = make_cbuffer('00' * (25)) @@ -128,9 +131,9 @@ def do_test_vector(self, vec, path, network): self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_legacy'])) # Get address for P2PKH scriptPubKey - ret, out = wally_scriptpubkey_to_address(out, written, network) + ret, new_addr = wally_scriptpubkey_to_address(out, written, network) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_legacy']) + self.assertEqual(new_addr, vec[path]['address_legacy']) # Parse wrapped SegWit address (P2SH_P2WPKH): out, out_len = make_cbuffer('00' * (25)) @@ -140,9 +143,9 @@ def do_test_vector(self, vec, path, network): self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_p2sh_segwit'])) # Get address for P2SH scriptPubKey - ret, out = wally_scriptpubkey_to_address(out, written, network) + ret, new_addr = wally_scriptpubkey_to_address(out, written, network) self.assertEqual(ret, WALLY_OK) - self.assertEqual(out, vec[path]['address_p2sh_segwit']) + self.assertEqual(new_addr, vec[path]['address_p2sh_segwit']) # Parse native SegWit address (P2WPKH): out, out_len = make_cbuffer('00' * (100)) @@ -150,5 +153,21 @@ def do_test_vector(self, vec, path, network): self.assertEqual(ret, WALLY_OK) self.assertEqual(hexlify(out[0:written]), utf8(vec[path]['scriptpubkey_segwit'])) + def test_address_scriptpubkey_liquid(self): + """Check that addresses can be converted to and from scriptpubkeys for Liquid""" + for addr, scriptpubkey, network in [ + ('XYtnYoGoSeE9ouMEVi6mfeujhjT2VnJncA', 'a914ec51ffb65120594389733bf8625f542446d97f7987', NETWORK_LIQUID_REGTEST), + ('H5nswXhfo8AMt159sgA5FWT35De34hVR4o', 'a914f80278b2011573a2ac59c83fadf929b0fc57ad0187', NETWORK_LIQUID_MAINNET), + ]: + out, out_len = make_cbuffer('00' * (100)) + ret, written = wally_address_to_scriptpubkey(utf8(addr), network, out, out_len) + self.assertEqual(ret, WALLY_OK) + self.assertEqual(hexlify(out[0:written]), utf8(scriptpubkey)) + + ret, new_addr = wally_scriptpubkey_to_address(out, written, network) + self.assertEqual(ret, WALLY_OK) + self.assertEqual(utf8(new_addr), utf8(addr)) + + if __name__ == '__main__': unittest.main() From 437e6c9a9758aedd6f5c6abc9fadd6dbefd4bd6f Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 13:29:41 +1200 Subject: [PATCH 038/205] psbt: Move FINGERPRINT_LEN to wally_bip32.h where it belongs --- include/wally_bip32.h | 3 +++ include/wally_core.h | 3 --- include/wally_psbt.h | 2 +- src/psbt.c | 4 +--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/include/wally_bip32.h b/include/wally_bip32.h index 7c9e0fe24..8f221fa42 100644 --- a/include/wally_bip32.h +++ b/include/wally_bip32.h @@ -12,6 +12,9 @@ extern "C" { #define BIP32_ENTROPY_LEN_256 32 #define BIP32_ENTROPY_LEN_512 64 +/** Length of a BIP32 key fingerprint */ +#define FINGERPRINT_LEN 4 + /** Length of an ext_key serialized using BIP32 format */ #define BIP32_SERIALIZED_LEN 78 diff --git a/include/wally_core.h b/include/wally_core.h index e75af8edb..6dbb9e9d9 100644 --- a/include/wally_core.h +++ b/include/wally_core.h @@ -28,9 +28,6 @@ extern "C" { #define WALLY_EINVAL -2 /** Invalid argument */ #define WALLY_ENOMEM -3 /** malloc() failed */ -/** BIP32 fingerprint length */ -#define FINGERPRINT_LEN 4 - /** * Initialize wally. * diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 1743c72f3..f96e24df3 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -2,7 +2,7 @@ #define LIBWALLY_CORE_PSBT_H #include "wally_transaction.h" -#include "wally_core.h" +#include "wally_bip32.h" #ifdef __cplusplus extern "C" { diff --git a/src/psbt.c b/src/psbt.c index f3de130b2..5e5d3116d 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -3,10 +3,8 @@ #include "ccan/ccan/base64/base64.h" #include "ccan/ccan/build_assert/build_assert.h" -#include -#include -#include #include +#include #include #include From fc33a40a44d9df22d54109d16c74ad7211208249 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 13:44:08 +1200 Subject: [PATCH 039/205] bip32: rename FINGERPRINT_LEN to BIP32_KEY_FINGERPRINT_LEN --- CHANGES.md | 5 +++++ include/wally_bip32.h | 4 ++-- include/wally_psbt.h | 4 ++-- src/bip32.c | 8 ++++---- src/psbt.c | 4 ++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 2b1680166..a674b07f4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,5 +1,10 @@ # Changes +## Version 0.7.9 + +- FINGERPRINT_LEN was renamed to BIP32_KEY_FINGERPRINT_LEN for + consistency - You should change any references in your source when upgrading. + ## Version 0.7.8 - Python 2 wheels are now deprecated. Users should move to Python 3 as soon as possible. diff --git a/include/wally_bip32.h b/include/wally_bip32.h index 8f221fa42..875cf4764 100644 --- a/include/wally_bip32.h +++ b/include/wally_bip32.h @@ -13,7 +13,7 @@ extern "C" { #define BIP32_ENTROPY_LEN_512 64 /** Length of a BIP32 key fingerprint */ -#define FINGERPRINT_LEN 4 +#define BIP32_KEY_FINGERPRINT_LEN 4 /** Length of an ext_key serialized using BIP32 format */ #define BIP32_SERIALIZED_LEN 78 @@ -335,7 +335,7 @@ WALLY_CORE_API int bip32_key_strip_private_key( * * :param hdkey: The extended key. * :param bytes_out: Destination for the fingerprint. - * :param len: Size of ``bytes_out`` in bytes. Must be ``FINGERPRINT_LEN``. + * :param len: Size of ``bytes_out`` in bytes. Must be ``BIP32_KEY_FINGERPRINT_LEN``. */ WALLY_CORE_API int bip32_key_get_fingerprint( struct ext_key *hdkey, diff --git a/include/wally_psbt.h b/include/wally_psbt.h index f96e24df3..49e158099 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -38,7 +38,7 @@ struct wally_psbt; /** Key origin data. Contains a BIP 32 fingerprint and the derivation path */ struct wally_key_origin_info { - unsigned char fingerprint[FINGERPRINT_LEN]; + unsigned char fingerprint[BIP32_KEY_FINGERPRINT_LEN]; uint32_t *path; size_t path_len; }; @@ -149,7 +149,7 @@ WALLY_CORE_API int wally_keypath_map_free(struct wally_keypath_map *keypaths); * :param pubkey: The pubkey to add * :param pubkey_len: The length of the pubkey. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN`` * :param fingerprint: The master key fingerprint for the pubkey - * :param fingerprint_len: The length of the fingerprint. Must be ``FINGERPRINT_LEN`` + * :param fingerprint_len: The length of the fingerprint. Must be ``BIP32_KEY_FINGERPRINT_LEN`` * :param path: The BIP32 derivation path for the pubkey * :param path_len: The number of items in path */ diff --git a/src/bip32.c b/src/bip32.c index feb378df7..5c144ef13 100644 --- a/src/bip32.c +++ b/src/bip32.c @@ -251,7 +251,7 @@ int bip32_key_serialize(const struct ext_key *hdkey, uint32_t flags, *out++ = hdkey->depth; /* Save the first 32 bits of the parent key (aka fingerprint) only */ - out = copy_out(out, hdkey->parent160, FINGERPRINT_LEN); + out = copy_out(out, hdkey->parent160, BIP32_KEY_FINGERPRINT_LEN); tmp32_be = cpu_to_be32(hdkey->child_num); out = copy_out(out, &tmp32_be, sizeof(tmp32_be)); @@ -299,7 +299,7 @@ int bip32_key_unserialize(const unsigned char *bytes, size_t bytes_len, * user will need to call bip32_key_set_parent() (FIXME: Implement) * later if they want it to be fully populated. */ - bytes = copy_in(key_out->parent160, bytes, FINGERPRINT_LEN); + bytes = copy_in(key_out->parent160, bytes, BIP32_KEY_FINGERPRINT_LEN); bytes = copy_in(&key_out->child_num, bytes, sizeof(key_out->child_num)); key_out->child_num = be32_to_cpu(key_out->child_num); bytes = copy_in(key_out->chain_code, bytes, sizeof(key_out->chain_code)); @@ -758,7 +758,7 @@ int bip32_key_get_fingerprint(struct ext_key *hdkey, /* Validate our arguments and then the input key */ if (!hdkey || !key_is_valid(hdkey) || - !bytes_out || len != FINGERPRINT_LEN) + !bytes_out || len != BIP32_KEY_FINGERPRINT_LEN) return WALLY_EINVAL; /* Derive hash160 if needed. */ @@ -767,7 +767,7 @@ int bip32_key_get_fingerprint(struct ext_key *hdkey, } /* Fingerprint is first 32 bits of the key hash. */ - memcpy(bytes_out, hdkey->hash160, FINGERPRINT_LEN); + memcpy(bytes_out, hdkey->hash160, BIP32_KEY_FINGERPRINT_LEN); return WALLY_OK; } diff --git a/src/psbt.c b/src/psbt.c index 5e5d3116d..90a51e937 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -93,7 +93,7 @@ int wally_add_new_keypath(struct wally_keypath_map *keypaths, { size_t latest; - if (fingerprint_len != FINGERPRINT_LEN || (pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN && pubkey_len != EC_PUBLIC_KEY_LEN)) { + if (fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || (pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN && pubkey_len != EC_PUBLIC_KEY_LEN)) { return WALLY_EINVAL; } @@ -137,7 +137,7 @@ static int add_keypath_item(struct wally_keypath_map *keypaths, struct wally_key return wally_add_new_keypath(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, item->origin.fingerprint, - FINGERPRINT_LEN, + BIP32_KEY_FINGERPRINT_LEN, item->origin.path, item->origin.path_len); } From f24fe1a21b12f4b3aad881cbdfe0b0088daaa076 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 14:19:36 +1200 Subject: [PATCH 040/205] bip32: Expose key_get_fingerprint to Java and C++ --- include/wally.hpp | 5 +++++ src/swig_java/jni_extra.java_in | 4 ++++ src/swig_java/swig.i | 1 + 3 files changed, 10 insertions(+) diff --git a/include/wally.hpp b/include/wally.hpp index 6e0f3da7d..d26cd38d6 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -320,6 +320,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), out); \ } +#define WALLY_FN_P_B(F, N) template inline int F(const P1 &p1, O & out) { \ + return ::N(WALLYP(p1), WALLYO(out)); \ +} + #define WALLY_FN_P_BS(F, N) template inline int F(const P1 &p1, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), WALLYO(out), written ? written : &n); \ @@ -438,6 +442,7 @@ WALLY_FN_PS_A(bip39_get_word, bip39_get_word) WALLY_FN_P_A(bip32_key_from_base58_alloc, bip32_key_from_base58_alloc) WALLY_FN_P_A(bip39_get_languages, bip39_get_languages) WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) +WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) WALLY_FN_P_S(base58_get_length, wally_base58_get_length) WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index 89e5b18a8..b80802b79 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -56,6 +56,10 @@ return bip32_key_get_priv_key(jarg1, null); } + public final static byte[] bip32_key_get_fingerprint(Object jarg1) { + return bip32_key_get_fingerprint(jarg1, null); + } + public final static byte[] bip32_key_get_hash160(Object jarg1) { return bip32_key_get_hash160(jarg1, null); } diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index c9cb36707..a9fb03915 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -384,6 +384,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_array_(bip32_key_get_chain_code, 2, 3, member_size(ext_key, chain_code)); %returns_size_t(bip32_key_get_child_num); %returns_size_t(bip32_key_get_depth); +%returns_array_(bip32_key_get_fingerprint, 2, 3, BIP32_KEY_FINGERPRINT_LEN); %returns_array_(bip32_key_get_hash160, 2, 3, member_size(ext_key, hash160)); %returns_array_(bip32_key_get_parent160, 2, 3, member_size(ext_key, parent160)); %returns_array_(bip32_key_get_priv_key, 2, 3, member_size(ext_key, priv_key) - 1); From 49b6095d37d165ad2f145408040f8492f825fb87 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 14:43:19 +1200 Subject: [PATCH 041/205] scriptpubkey_to_address: Expose to C++ --- include/wally.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/wally.hpp b/include/wally.hpp index d26cd38d6..ce5dc7ccc 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -420,6 +420,7 @@ WALLY_FN_P3_BS(base58_to_bytes, wally_base58_to_bytes) WALLY_FN_P3_BS(tx_to_bytes, wally_tx_to_bytes) WALLY_FN_P3_BS(wif_to_public_key, wally_wif_to_public_key) WALLY_FN_P3_S(tx_get_length, wally_tx_get_length) +WALLY_FN_P33_A(scriptpubkey_to_address, wally_scriptpubkey_to_address) WALLY_FN_P33_A(wif_to_address, wally_wif_to_address) WALLY_FN_P6B3(tx_add_raw_output, wally_tx_add_raw_output) WALLY_FN_PB(tx_witness_stack_add, wally_tx_witness_stack_add) From 619d7c4ec84a0f9075859b193feeb89cbc1ccdd9 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 14:49:54 +1200 Subject: [PATCH 042/205] SWIG: Fix psbt_get_length to allow python bindings to work --- include/wally_psbt.h | 4 ++-- src/psbt.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 49e158099..a18b4e900 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -497,11 +497,11 @@ WALLY_CORE_API int wally_psbt_from_bytes( * Get length of psbt when serialized to bytes. * * :param psbt: the PSBT. - * :param len: Length in bytes when serialized. + * :param written: Destination for the length in bytes when serialized. */ WALLY_CORE_API int wally_psbt_get_length( const struct wally_psbt *psbt, - size_t *len); + size_t *written); /** * Serialize a psbt to bytes. diff --git a/src/psbt.c b/src/psbt.c index 90a51e937..9c9e40181 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1757,15 +1757,15 @@ static int psbt_output_get_length( int wally_psbt_get_length( const struct wally_psbt *psbt, - size_t *len) + size_t *written) { int ret; size_t out, tx_len, i; - if (!len) { + if (!written) { return WALLY_EINVAL; } - *len = 0; + *written = 0; out = 5; /* Start with 5 byte magic */ /* Global tx */ @@ -1802,7 +1802,7 @@ int wally_psbt_get_length( out += output_len; } - *len = out; + *written = out; return WALLY_OK; } From 6c6997028de9f2e4ede2dac9e016dd2092b1f14c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 15:20:55 +1200 Subject: [PATCH 043/205] ec_sig_from_bytes: Prevent uninitialised read if EC_FLAG_GRIND_R and EC_FLAG_RECOVERABLE are both given, bytes_out[0] will be read unitialised, potentially leading to different signatures for the same inputs depending on its contents. --- src/sign.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sign.c b/src/sign.c index 523a77ef6..e90b90214 100644 --- a/src/sign.c +++ b/src/sign.c @@ -235,6 +235,7 @@ int wally_ec_sig_from_bytes(const unsigned char *priv_key, size_t priv_key_len, #endif } else { unsigned char extra_entropy[32] = {0}, *entropy_p = NULL; + unsigned char *bytes_out_p = flags & EC_FLAG_RECOVERABLE ? bytes_out + 1 : bytes_out; uint32_t counter = 0; secp256k1_ecdsa_recoverable_signature sig_secp; int recid; @@ -248,14 +249,13 @@ int wally_ec_sig_from_bytes(const unsigned char *priv_key, size_t priv_key_len, } /* Note this function is documented as never failing */ - secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, flags & EC_FLAG_RECOVERABLE ? bytes_out + 1 : bytes_out, &recid, &sig_secp); + secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, bytes_out_p, &recid, &sig_secp); - if (!(flags & EC_FLAG_GRIND_R) || bytes_out[0] < 0x80) { + if (!(flags & EC_FLAG_GRIND_R) || *bytes_out_p < 0x80) { wally_clear(&sig_secp, sizeof(sig_secp)); /* Note the following assumes the key is compressed */ - if (flags & EC_FLAG_RECOVERABLE) { + if (flags & EC_FLAG_RECOVERABLE) bytes_out[0] = 27 + recid + 4; - } return WALLY_OK; } From 6cd87b515a10aad02df8cbc839a29011fa3fa58d Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 3 Jul 2020 16:10:15 +1200 Subject: [PATCH 044/205] ec_sig_from_bytes: Simplify parameter checking logic --- src/sign.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/sign.c b/src/sign.c index e90b90214..d397f1ef3 100644 --- a/src/sign.c +++ b/src/sign.c @@ -28,6 +28,10 @@ static bool is_valid_ec_type(uint32_t flags) ((flags & EC_FLAGS_TYPES) == EC_FLAG_SCHNORR); } +static size_t get_expected_sig_len(uint32_t flags) +{ + return flags & EC_FLAG_RECOVERABLE ? EC_SIGNATURE_RECOVERABLE_LEN : EC_SIGNATURE_LEN; +} int wally_ec_private_key_verify(const unsigned char *priv_key, size_t priv_key_len) { @@ -215,24 +219,23 @@ int wally_ec_sig_from_bytes(const unsigned char *priv_key, size_t priv_key_len, if (!priv_key || priv_key_len != EC_PRIVATE_KEY_LEN || !bytes || bytes_len != EC_MESSAGE_HASH_LEN || !is_valid_ec_type(flags) || flags & ~EC_FLAGS_ALL || - (flags & EC_FLAG_SCHNORR && flags & EC_FLAG_RECOVERABLE) || - !bytes_out || - (len != EC_SIGNATURE_LEN && len != EC_SIGNATURE_RECOVERABLE_LEN) || - (len == EC_SIGNATURE_LEN && flags & EC_FLAG_RECOVERABLE) || - (len == EC_SIGNATURE_RECOVERABLE_LEN && ~flags & EC_FLAG_RECOVERABLE)) + !bytes_out || len != get_expected_sig_len(flags)) return WALLY_EINVAL; if (!ctx) return WALLY_ENOMEM; if (flags & EC_FLAG_SCHNORR) { - return WALLY_EINVAL; + if (flags & EC_FLAG_RECOVERABLE) + return WALLY_EINVAL; /* Only ECDSA is supported for recoverable sigs */ + #if 0 /*FIXME: Schnorr is unavailable in secp for now*/ if (!secp256k1_schnorr_sign(ctx, bytes_out, bytes, priv_key, nonce_fn, NULL)) return WALLY_EINVAL; /* Failed to sign */ return WALLY_OK; #endif + return WALLY_EINVAL; } else { unsigned char extra_entropy[32] = {0}, *entropy_p = NULL; unsigned char *bytes_out_p = flags & EC_FLAG_RECOVERABLE ? bytes_out + 1 : bytes_out; From b41fe014fecfbed24f297941150b629ea23ddecc Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 08:17:34 +1200 Subject: [PATCH 045/205] psbt: In wally_combine_psbts, don't leak result if merge_unknowns_into fails --- src/psbt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psbt.c b/src/psbt.c index 9c9e40181..34f2fb357 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2500,7 +2500,7 @@ int wally_combine_psbts( } if ((ret = merge_unknowns_into(result->unknowns, psbts[i].unknowns)) != WALLY_OK) { - return ret; + goto fail; } } } From dfe7cd63231f9bb5a1d840e5122ed81b03eb83cb Mon Sep 17 00:00:00 2001 From: k-matsuzawa Date: Tue, 10 Mar 2020 16:25:13 +0900 Subject: [PATCH 046/205] add WALLY_DISABLE_OP_CODE guard --- include/wally_script.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/wally_script.h b/include/wally_script.h index a2a7d4ca5..f94e83faa 100644 --- a/include/wally_script.h +++ b/include/wally_script.h @@ -37,6 +37,7 @@ extern "C" { #define WALLY_SCRIPT_MULTISIG_SORTED 0x8 /** Sort public keys (BIP67) */ /* Script opcodes */ +#ifndef WALLY_DISABLE_OP_CODE #define OP_0 0x00 #define OP_FALSE 0x00 #define OP_PUSHDATA1 0x4c @@ -164,6 +165,7 @@ extern "C" { #define OP_NOP10 0xb9 #define OP_INVALIDOPCODE 0xff +#endif /* WALLY_DISABLE_OP_CODE */ /** * Determine the type of a scriptPubkey script. From deb487339d42404525ac5ec95e16e561b26f63dd Mon Sep 17 00:00:00 2001 From: niftynei Date: Mon, 22 Jun 2020 12:34:54 -0500 Subject: [PATCH 047/205] psbt: return ENOMEM for any wally_malloc failures A few wally_malloc's were missing a NULL/ENOMEM check --- src/psbt.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/psbt.c b/src/psbt.c index 34f2fb357..6ff64d6ae 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -719,10 +719,16 @@ int wally_psbt_init_alloc( if (inputs_allocation_len) { new_inputs = wally_malloc(inputs_allocation_len * sizeof(struct wally_psbt_input)); + if (!new_inputs) { + return WALLY_ENOMEM; + } wally_bzero(new_inputs, inputs_allocation_len * sizeof(*new_inputs)); } if (outputs_allocation_len) { new_outputs = wally_malloc(outputs_allocation_len * sizeof(struct wally_psbt_output)); + if (!new_outputs) { + return WALLY_ENOMEM; + } wally_bzero(new_outputs, outputs_allocation_len * sizeof(*new_outputs)); } wally_unknowns_map_init_alloc(global_unknowns_allocation_len, &result->unknowns); @@ -1216,6 +1222,9 @@ static int psbt_input_from_bytes( /* Read the path itself */ keypaths->items[keypaths->num_items].origin.path = wally_malloc(path_len * sizeof(uint32_t)); + if (!keypaths->items[keypaths->num_items].origin.path) { + return WALLY_ENOMEM; + } for (i = 0; i < path_len; ++i) { p += uint32_from_le_bytes(p, &keypaths->items[keypaths->num_items].origin.path[i]); } @@ -1387,6 +1396,9 @@ static int psbt_output_from_bytes( /* Read the path itself */ keypaths->items[keypaths->num_items].origin.path = wally_malloc(path_len * sizeof(uint32_t)); + if (!keypaths->items[keypaths->num_items].origin.path) { + return WALLY_ENOMEM; + } for (i = 0; i < path_len; ++i) { p += uint32_from_le_bytes(p, &keypaths->items[keypaths->num_items].origin.path[i]); } @@ -2785,6 +2797,9 @@ int wally_finalize_psbt(struct wally_psbt *psbt) /* P2SH wrapped witness requires final scriptsig of pushing the redeemScript */ script_sig_len = varint_get_length(input->redeem_script_len) + input->redeem_script_len; input->final_script_sig = wally_malloc(script_sig_len); + if (!input->final_script_sig) { + return WALLY_ENOMEM; + } if ((ret = wally_script_push_from_bytes(input->redeem_script, input->redeem_script_len, 0, input->final_script_sig, script_sig_len, &written)) != WALLY_OK) { wally_free(input->final_script_sig); return ret; @@ -2895,6 +2910,9 @@ int wally_finalize_psbt(struct wally_psbt *psbt) /* P2SH wrapped witness requires final scriptsig of pushing the redeemScript */ script_sig_len = varint_get_length(input->redeem_script_len) + input->redeem_script_len; input->final_script_sig = wally_malloc(script_sig_len); + if (!input->final_script_sig) { + return WALLY_ENOMEM; + } if ((ret = wally_script_push_from_bytes(input->redeem_script, input->redeem_script_len, 0, input->final_script_sig, script_sig_len, &written)) != WALLY_OK) { wally_free(input->final_script_sig); return ret; From 63cf5427ba6667d3eaf042309e635e60a070ae05 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 10:14:32 +1200 Subject: [PATCH 048/205] psbt: Initial simplification of wally_psbt_init_alloc --- src/psbt.c | 41 ++++++++++++++--------------------------- 1 file changed, 14 insertions(+), 27 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 6ff64d6ae..a2531c712 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -710,44 +710,31 @@ int wally_psbt_init_alloc( size_t global_unknowns_allocation_len, struct wally_psbt **output) { - struct wally_psbt_input *new_inputs = NULL; - struct wally_psbt_output *new_outputs = NULL; struct wally_psbt *result; + int ret; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_psbt); if (inputs_allocation_len) { - new_inputs = wally_malloc(inputs_allocation_len * sizeof(struct wally_psbt_input)); - if (!new_inputs) { - return WALLY_ENOMEM; - } - wally_bzero(new_inputs, inputs_allocation_len * sizeof(*new_inputs)); + result->inputs = wally_malloc(inputs_allocation_len * sizeof(struct wally_psbt_input)); + if (result->inputs) + wally_bzero(result->inputs, inputs_allocation_len * sizeof(*result->inputs)); } if (outputs_allocation_len) { - new_outputs = wally_malloc(outputs_allocation_len * sizeof(struct wally_psbt_output)); - if (!new_outputs) { - return WALLY_ENOMEM; - } - wally_bzero(new_outputs, outputs_allocation_len * sizeof(*new_outputs)); - } - wally_unknowns_map_init_alloc(global_unknowns_allocation_len, &result->unknowns); - if ((inputs_allocation_len && !new_inputs) || - (outputs_allocation_len && !new_outputs) || - (global_unknowns_allocation_len && !result->unknowns)) { - wally_free(new_inputs); - wally_free(new_outputs); - wally_free(result->unknowns); - wally_free(result); - *output = NULL; - return WALLY_ENOMEM; + result->outputs = wally_malloc(outputs_allocation_len * sizeof(struct wally_psbt_output)); + if (result->outputs) + wally_bzero(result->outputs, outputs_allocation_len * sizeof(*result->outputs)); + } + ret = wally_unknowns_map_init_alloc(global_unknowns_allocation_len, &result->unknowns); + + if (ret != WALLY_OK || + (inputs_allocation_len && !result->inputs) || (outputs_allocation_len && !result->outputs)) { + wally_psbt_free(result); + return ret != WALLY_OK ? ret : WALLY_ENOMEM; } - result->inputs = new_inputs; - result->num_inputs = 0; result->inputs_allocation_len = inputs_allocation_len; - result->outputs = new_outputs; - result->num_outputs = 0; result->outputs_allocation_len = outputs_allocation_len; result->tx = NULL; return WALLY_OK; From bef7403f5a57895c1404ef17a55f682535ad0fc8 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 10:55:25 +1200 Subject: [PATCH 049/205] psbt: Remove unneded saves/restores of num_items members --- src/psbt.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index a2531c712..564744cb9 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -100,7 +100,6 @@ int wally_add_new_keypath(struct wally_keypath_map *keypaths, if (keypaths->num_items == keypaths->items_allocation_len) { struct wally_keypath_item *new_items; size_t new_alloc_len = 1; - size_t orig_num_items = keypaths->num_items; if (keypaths->items_allocation_len != 0) { new_alloc_len = keypaths->items_allocation_len * 2; } @@ -113,7 +112,6 @@ int wally_add_new_keypath(struct wally_keypath_map *keypaths, clear_and_free(keypaths->items, keypaths->items_allocation_len * sizeof(*keypaths->items)); keypaths->items = new_items; - keypaths->num_items = orig_num_items; keypaths->items_allocation_len = new_alloc_len; } @@ -219,7 +217,6 @@ int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, if (sigs->num_items == sigs->items_allocation_len) { struct wally_partial_sigs_item *new_items; size_t new_alloc_len = 1; - size_t orig_num_items = sigs->num_items; if (sigs->items_allocation_len != 0) { new_alloc_len = sigs->items_allocation_len * 2; } @@ -232,7 +229,6 @@ int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, clear_and_free(sigs->items, sigs->items_allocation_len * sizeof(*sigs->items)); sigs->items = new_items; - sigs->num_items = orig_num_items; sigs->items_allocation_len = new_alloc_len; } @@ -339,7 +335,6 @@ int wally_add_new_unknown(struct wally_unknowns_map *unknowns, if (unknowns->num_items == unknowns->items_allocation_len) { struct wally_unknowns_item *new_items; size_t new_alloc_len = 1; - size_t orig_num_items = unknowns->num_items; if (unknowns->items_allocation_len != 0) { new_alloc_len = unknowns->items_allocation_len * 2; } @@ -352,7 +347,6 @@ int wally_add_new_unknown(struct wally_unknowns_map *unknowns, clear_and_free(unknowns->items, unknowns->items_allocation_len * sizeof(*unknowns->items)); unknowns->items = new_items; - unknowns->num_items = orig_num_items; unknowns->items_allocation_len = new_alloc_len; } From 2a1e487cad71bc20341c6ec3f434035b5c9d8c0d Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 11:06:09 +1200 Subject: [PATCH 050/205] psbt: Don't set allocation len if allocation fails --- src/psbt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psbt.c b/src/psbt.c index 564744cb9..06c7ea95d 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -797,11 +797,11 @@ int wally_psbt_set_global_tx( } psbt->outputs_allocation_len = 0; psbt->outputs = wally_malloc(tx->num_outputs * sizeof(struct wally_psbt_output)); - psbt->outputs_allocation_len = tx->num_outputs; if (!psbt->outputs) { ret = WALLY_ENOMEM; goto fail; } + psbt->outputs_allocation_len = tx->num_outputs; } wally_bzero(psbt->outputs, psbt->outputs_allocation_len * sizeof(*psbt->outputs)); psbt->num_outputs = tx->num_outputs; From 612802db75db98df6cd7ef8f798b6c924f5b1528 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 13:28:55 +1200 Subject: [PATCH 051/205] psbt: Doc fixes --- include/wally_psbt.h | 227 +++++++++++++++++++++++-------------------- 1 file changed, 123 insertions(+), 104 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index a18b4e900..43c803108 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -85,7 +85,7 @@ struct wally_unknowns_map { size_t items_allocation_len; }; -/** A psbt input map */ +/** A PSBT input map */ struct wally_psbt_input { struct wally_tx *non_witness_utxo; struct wally_tx_output *witness_utxo; @@ -102,7 +102,7 @@ struct wally_psbt_input { uint32_t sighash_type; }; -/** A psbt output map */ +/** A PSBT output map */ struct wally_psbt_output { unsigned char *redeem_script; size_t redeem_script_len; @@ -129,9 +129,11 @@ struct wally_psbt { * Allocate and initialize a new keypath map. * * :param alloc_len: The number of items to allocate. - * :param output: Destination for the new keypath map + * :param output: Destination for the new keypath map. */ -WALLY_CORE_API int wally_keypath_map_init_alloc(size_t alloc_len, struct wally_keypath_map **output); +WALLY_CORE_API int wally_keypath_map_init_alloc( + size_t alloc_len, + struct wally_keypath_map **output); #ifndef SWIG_PYTHON /** @@ -139,35 +141,39 @@ WALLY_CORE_API int wally_keypath_map_init_alloc(size_t alloc_len, struct wally_k * * :param keypaths: The keypath map to free. */ -WALLY_CORE_API int wally_keypath_map_free(struct wally_keypath_map *keypaths); +WALLY_CORE_API int wally_keypath_map_free( + struct wally_keypath_map *keypaths); #endif /* SWIG_PYTHON */ /** * Add an item to a keypath map * - * :param keypaths: The keypath map to add to - * :param pubkey: The pubkey to add - * :param pubkey_len: The length of the pubkey. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN`` - * :param fingerprint: The master key fingerprint for the pubkey - * :param fingerprint_len: The length of the fingerprint. Must be ``BIP32_KEY_FINGERPRINT_LEN`` - * :param path: The BIP32 derivation path for the pubkey - * :param path_len: The number of items in path + * :param keypaths: The keypath map to add to. + * :param pubkey: The pubkey to add. + * :param pubkey_len: The length of the pubkey. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param fingerprint: The master key fingerprint for the pubkey. + * :param fingerprint_len: The length of the fingerprint. Must be ``BIP32_KEY_FINGERPRINT_LEN``. + * :param path: The BIP32 derivation path for the pubkey. + * :param path_len: The number of items in path. */ -WALLY_CORE_API int wally_add_new_keypath(struct wally_keypath_map *keypaths, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *fingerprint, - size_t fingerprint_len, - uint32_t *path, - size_t path_len); +WALLY_CORE_API int wally_add_new_keypath( + struct wally_keypath_map *keypaths, + unsigned char *pubkey, + size_t pubkey_len, + unsigned char *fingerprint, + size_t fingerprint_len, + uint32_t *path, + size_t path_len); /** * Allocate and initialize a new partial sigs map. * * :param alloc_len: The number of items to allocate. - * :param output: Destination for the new partial sigs map + * :param output: Destination for the new partial sigs map. */ -WALLY_CORE_API int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wally_partial_sigs_map **output); +WALLY_CORE_API int wally_partial_sigs_map_init_alloc( + size_t alloc_len, + struct wally_partial_sigs_map **output); #ifndef SWIG_PYTHON /** @@ -175,73 +181,79 @@ WALLY_CORE_API int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wa * * :param sigs: The partial sigs map to free. */ -WALLY_CORE_API int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs); +WALLY_CORE_API int wally_partial_sigs_map_free( + struct wally_partial_sigs_map *sigs); #endif /* SWIG_PYTHON */ /** * Add an item to a partial sigs map * - * :param sigs: The partial sigs map to add to - * :param pubkey: The pubkey to add + * :param sigs: The partial sigs map to add to. + * :param pubkey: The pubkey to add. * :param pubkey_len: Length of the public key. Must be ``EC_PUBLIC_KEY_LEN`` or ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` - * :param sig: The signature to add - * :param sig_len: The length of sig + * :param sig: The DER-encoded signature to add. + * :param sig_len: The length of sig in bytes. */ -WALLY_CORE_API int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *sig, - size_t sig_len); +WALLY_CORE_API int wally_add_new_partial_sig( + struct wally_partial_sigs_map *sigs, + unsigned char *pubkey, + size_t pubkey_len, + unsigned char *sig, + size_t sig_len); /** * Allocate and initialize a new unknowns map * * :param alloc_len: The number of items to allocate. - * :param output: Destination for the new unknowns map + * :param output: Destination for the new unknowns map. */ -WALLY_CORE_API int wally_unknowns_map_init_alloc(size_t alloc_len, struct wally_unknowns_map **output); +WALLY_CORE_API int wally_unknowns_map_init_alloc( + size_t alloc_len, + struct wally_unknowns_map **output); #ifndef SWIG_PYTHON /** * Free an unknowns map allocated by `wally_unknowns_map_init_alloc`. * - * :param unknowns: The unknowns map map to free. + * :param unknowns: The unknowns map to free. */ -WALLY_CORE_API int wally_unknowns_map_free(struct wally_unknowns_map *unknowns); +WALLY_CORE_API int wally_unknowns_map_free( + struct wally_unknowns_map *unknowns); #endif /* SWIG_PYTHON */ /** * Add an item to an unknowns map * - * :param unknowns: The unknowns map to add to - * :param key: The key to add - * :param key_len: The length of the key - * :param value: The value to add - * :param value_len: The length of value + * :param unknowns: The unknowns map to add to. + * :param key: The key to add. + * :param key_len: The length of the key in bytes. + * :param value: The value to add. + * :param value_len: The length of value in bytes. */ -WALLY_CORE_API int wally_add_new_unknown(struct wally_unknowns_map *unknowns, - unsigned char *key, - size_t key_len, - unsigned char *value, - size_t value_len); +WALLY_CORE_API int wally_add_new_unknown( + struct wally_unknowns_map *unknowns, + unsigned char *key, + size_t key_len, + unsigned char *value, + size_t value_len); /** - * Allocate and initialize a new psbt input. + * Allocate and initialize a new PSBT input. * * :param non_witness_utxo: The non witness utxo for this input if it exists. * :param witness_utxo: The witness utxo for this input if it exists. - * :param redeem_script: The redeem script for this input + * :param redeem_script: The redeem script for this input. * :param redeem_script_len: The length of the redeem script. - * :param witness_script: The witness script for this input + * :param witness_script: The witness script for this input. * :param witness_script_len: The length of the witness script. - * :param final_script_sig: The scriptSig for this input + * :param final_script_sig: The scriptSig for this input. * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. * :param final_witness: The witness stack for the input, or NULL if no witness is present. * :param keypaths: The HD keypaths for this input. * :param partial_sigs: The partial signatures for this input. * :param unknowns: The unknown key value pairs for this input. - * :param sighash_type: The sighash type for this input - * :param output: Destination for the resulting psbt input. + * :param sighash_type: The sighash type for this input. + * :param output: Destination for the resulting PSBT input. */ WALLY_CORE_API int wally_psbt_input_init_alloc( struct wally_tx *non_witness_utxo, @@ -283,7 +295,7 @@ WALLY_CORE_API int wally_psbt_input_set_witness_utxo( * Set the redeem_script in an input * * :param input: The input to update. - * :param redeem_script: The redeem script for this input + * :param redeem_script: The redeem script for this input. * :param redeem_script_len: The length of the redeem script. */ WALLY_CORE_API int wally_psbt_input_set_redeem_script( @@ -295,7 +307,7 @@ WALLY_CORE_API int wally_psbt_input_set_redeem_script( * Set the witness_script in an input * * :param input: The input to update. - * :param witness_script: The witness script for this input + * :param witness_script: The witness script for this input. * :param witness_script_len: The length of the witness script. */ WALLY_CORE_API int wally_psbt_input_set_witness_script( @@ -307,7 +319,7 @@ WALLY_CORE_API int wally_psbt_input_set_witness_script( * Set the final_script_sig in an input * * :param input: The input to update. - * :param final_script_sig: The scriptSig for this input + * :param final_script_sig: The scriptSig for this input. * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_final_script_sig( @@ -359,7 +371,7 @@ WALLY_CORE_API int wally_psbt_input_set_unknowns( * Set the partial_sigs in an input * * :param input: The input to update. - * :param sighash_type: The sighash type for this input + * :param sighash_type: The sighash type for this input. */ WALLY_CORE_API int wally_psbt_input_set_sighash_type( struct wally_psbt_input *input, @@ -367,23 +379,24 @@ WALLY_CORE_API int wally_psbt_input_set_sighash_type( #ifndef SWIG_PYTHON /** - * Free a psbt input allocated by `wally_psbt_input_init_alloc`. + * Free a PSBT input allocated by `wally_psbt_input_init_alloc`. * - * :param input: The psbt input to free. + * :param input: The PSBT input to free. */ -WALLY_CORE_API int wally_psbt_input_free(struct wally_psbt_input *input); +WALLY_CORE_API int wally_psbt_input_free( + struct wally_psbt_input *input); #endif /* SWIG_PYTHON */ /** - * Allocate and initialize a new psbt output. + * Allocate and initialize a new PSBT output. * - * :param redeem_script: The redeem script needed for spending this output + * :param redeem_script: The redeem script needed for spending this output. * :param redeem_script_len: The length of the redeem script. - * :param witness_script: The witness script needed for spending for this output + * :param witness_script: The witness script needed for spending for this output. * :param witness_script_len: The length of the witness script. - * :param keypaths: The HD keypaths for the keys needed for spending this output + * :param keypaths: The HD keypaths for the keys needed for spending this output. * :param unknowns: The unknown key value pairs for this output. - * :param output: Destination for the resulting psbt output. + * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_output_init_alloc( unsigned char *redeem_script, @@ -395,10 +408,10 @@ WALLY_CORE_API int wally_psbt_output_init_alloc( struct wally_psbt_output **output); /** - * Set the redeem_script in an output + * Set the redeem_script in an output. * * :param output: The input to update. - * :param redeem_script: The redeem script for this output + * :param redeem_script: The redeem script for this output. * :param redeem_script_len: The length of the redeem script. */ WALLY_CORE_API int wally_psbt_output_set_redeem_script( @@ -407,10 +420,10 @@ WALLY_CORE_API int wally_psbt_output_set_redeem_script( size_t redeem_script_len); /** - * Set the witness_script in an output + * Set the witness_script in an output. * * :param output: The output to update. - * :param witness_script: The witness script for this output + * :param witness_script: The witness script for this output. * :param witness_script_len: The length of the witness script. */ WALLY_CORE_API int wally_psbt_output_set_witness_script( @@ -419,7 +432,7 @@ WALLY_CORE_API int wally_psbt_output_set_witness_script( size_t witness_script_len); /** - * Set the keypaths in an output + * Set the keypaths in an output. * * :param output: The output to update. * :param keypaths: The HD keypaths for this output. @@ -429,7 +442,7 @@ WALLY_CORE_API int wally_psbt_output_set_keypaths( struct wally_keypath_map *keypaths); /** - * Set the partial_sigs in an output + * Set the partial_sigs in an output. * * :param output: The output to update. * :param unknowns: The unknown key value pairs for this output. @@ -440,20 +453,21 @@ WALLY_CORE_API int wally_psbt_output_set_unknowns( #ifndef SWIG_PYTHON /** - * Free a psbt output allocated by `wally_psbt_output_init_alloc`. + * Free a PSBT output allocated by `wally_psbt_output_init_alloc`. * - * :param output: The psbt output to free. + * :param output: The PSBT output to free. */ -WALLY_CORE_API int wally_psbt_output_free(struct wally_psbt_output *output); +WALLY_CORE_API int wally_psbt_output_free( + struct wally_psbt_output *output); #endif /* SWIG_PYTHON */ /** - * Allocate and initialize a new psbt. + * Allocate and initialize a new PSBT. * * :param inputs_allocation_len: The number of inputs to pre-allocate space for. * :param outputs_allocation_len: The number of outputs to pre-allocate space for. * :param global_unknowns_allocation_len: The number of global unknowns to allocate space for. - * :param output: Destination for the resulting psbt output. + * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_init_alloc( size_t inputs_allocation_len, @@ -463,30 +477,31 @@ WALLY_CORE_API int wally_psbt_init_alloc( #ifndef SWIG_PYTHON /** - * Free a psbt allocated by `wally_psbt_init_alloc`. + * Free a PSBT allocated by `wally_psbt_init_alloc`. * - * :param psbt: The psbt to free. + * :param psbt: The PSBT to free. */ -WALLY_CORE_API int wally_psbt_free(struct wally_psbt *psbt); +WALLY_CORE_API int wally_psbt_free( + struct wally_psbt *psbt); #endif /* SWIG_PYTHON */ /** - * Set the global transaction for a psbt. - * Also initializes all of the wally_psbt_input and wally_psbt_outputs necessary + * Set the global transaction for a PSBT. + * Also initializes all of the wally_psbt_input and wally_psbt_outputs necessary. * + * :param psbt: The PSBT to set the transaction for. * :param tx: The transaction to set. - * :param psbt: The psbt to set the transaction for */ WALLY_CORE_API int wally_psbt_set_global_tx( struct wally_psbt *psbt, struct wally_tx *tx); /** - * Create a psbt from its serialized bytes. + * Create a PSBT from its serialized bytes. * - * :param bytes: Bytes to create the psbt from. + * :param bytes: Bytes to create the PSBT from. * :param bytes_len: Length of ``bytes`` in bytes. - * :param output: Destination for the resulting psbt. + * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_from_bytes( const unsigned char *bytes, @@ -494,7 +509,7 @@ WALLY_CORE_API int wally_psbt_from_bytes( struct wally_psbt **output); /** - * Get length of psbt when serialized to bytes. + * Get the length of a PSBT when serialized to bytes. * * :param psbt: the PSBT. * :param written: Destination for the length in bytes when serialized. @@ -504,44 +519,45 @@ WALLY_CORE_API int wally_psbt_get_length( size_t *written); /** - * Serialize a psbt to bytes. + * Serialize a PSBT to bytes. * * :param psbt: the PSBT to serialize. * :param bytes_out: Bytes to create the transaction from. * :param bytes_len: Length of ``bytes`` in bytes (use `wally_psbt_get_length`). - * :param bytes_written: number of bytes written to bytes_out + * :param bytes_written: number of bytes written to bytes_out. */ WALLY_CORE_API int wally_psbt_to_bytes( const struct wally_psbt *psbt, - unsigned char *bytes_out, size_t bytes_len, + unsigned char *bytes_out, + size_t bytes_len, size_t *bytes_written); /** - * Create a psbt from the base64 string. + * Create a PSBT from its serialized base64 string. * - * :param string: Base64 string to create the psbt from. - * :param output: Destination for the resulting psbt. + * :param string: Base64 string to create the PSBT from. + * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_from_base64( const char *string, struct wally_psbt **output); /** - * Create a base64 string for a psbt + * Serialize a PSBT to a base64 string. * * :param psbt: the PSBT to serialize. - * :param output: Destination for the resulting psbt. + * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_to_base64( struct wally_psbt *psbt, char **output); /** - * Combine the metadata from multiple PSBTs into one + * Combine the metadata from multiple PSBTs into one PSBT. * - * :param psbts: Array of PSBTs to combine - * :param psbts_len: Number of PSBTs in psbts - * :param output: Destination for resulting psbt + * :param psbts: Array of PSBTs to combine. + * :param psbts_len: Number of PSBTs in psbts. + * :param output: Destination for resulting PSBT. */ WALLY_CORE_API int wally_combine_psbts( const struct wally_psbt *psbts, @@ -549,11 +565,14 @@ WALLY_CORE_API int wally_combine_psbts( struct wally_psbt **output); /** - * Sign a PSBT using the simple signer algorithm: https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#simple-signer-algorithm + * Sign a PSBT using the simple signer algorithm. + * + * :param psbt: PSBT to sign. Directly modifies this PSBT. + * :param key: Private key to sign PSBT with. + * :param key_len: Length of key in bytes. Must be ``EC_PRIVATE_KEY_LEN``. * - * :param psbt: PSBT to sign. Directly modifies this PSBT - * :param key: Private key to sign PSBT with - * :param key_len: Length of key in bytes. Must be ``EC_PRIVATE_KEY_LEN`` + * .. note:: See https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#simple-signer-algorithm + *| for a description of the simple signer algorithm. */ WALLY_CORE_API int wally_sign_psbt( struct wally_psbt *psbt, @@ -561,17 +580,17 @@ WALLY_CORE_API int wally_sign_psbt( size_t key_len); /** - * Finalize a PSBT + * Finalize a PSBT. * - * :param psbt: PSBT to finalize. Directly modifies this PSBT + * :param psbt: PSBT to finalize. Directly modifies this PSBT. */ WALLY_CORE_API int wally_finalize_psbt( struct wally_psbt *psbt); /** - * Convert a finalized PSBT to a network transaction, i.e. extract + * Extract a network transaction from a finalized PSBT. * - * :param psbt: PSBT to extract. Directly modifies this PSBT + * :param psbt: PSBT to extract. Directly modifies this PSBT. * :param output: Resulting transaction */ WALLY_CORE_API int wally_extract_psbt( From 7c84ed1428e11ad68260346c87b6c7ce1d0a2a0c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 13:29:32 +1200 Subject: [PATCH 052/205] docs: wally_crypto doc fixes --- include/wally_crypto.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/include/wally_crypto.h b/include/wally_crypto.h index 2cca1f9ba..8b71e3e5c 100644 --- a/include/wally_crypto.h +++ b/include/wally_crypto.h @@ -483,12 +483,13 @@ WALLY_CORE_API int wally_ec_sig_to_public_key( * :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_format_bitcoin_message(const unsigned char *bytes, - size_t bytes_len, - uint32_t flags, - unsigned char *bytes_out, - size_t len, - size_t *written); +WALLY_CORE_API int wally_format_bitcoin_message( + const unsigned char *bytes, + size_t bytes_len, + uint32_t flags, + unsigned char *bytes_out, + size_t len, + size_t *written); /** * @@ -501,12 +502,13 @@ WALLY_CORE_API int wally_format_bitcoin_message(const unsigned char *bytes, * :param bytes_out: Destination for the shared secret. * :param len: The length of ``bytes_out`` in bytes. Must be ``SHA256_LEN``. */ -WALLY_CORE_API int wally_ecdh(const unsigned char *pub_key, - size_t pub_key_len, - const unsigned char *priv_key, - size_t priv_key_len, - unsigned char *bytes_out, - size_t len); +WALLY_CORE_API int wally_ecdh( + const unsigned char *pub_key, + size_t pub_key_len, + const unsigned char *priv_key, + size_t priv_key_len, + unsigned char *bytes_out, + size_t len); #ifdef __cplusplus } From df1bb2513556ec4a2f7f4aa7db058a8118e4f4b1 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 13:32:51 +1200 Subject: [PATCH 053/205] psbt: Add missing output checks --- src/psbt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 06c7ea95d..fc2fe9f7d 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2122,9 +2122,9 @@ int wally_psbt_from_base64( ssize_t decoded_len; int ret; - if (!string) { + TX_CHECK_OUTPUT; + if (!string) return WALLY_EINVAL; - } string_len = strlen(string); /* Allocate the decoded buffer */ @@ -2161,9 +2161,9 @@ int wally_psbt_to_base64( ssize_t b64_len; int ret = WALLY_OK; - if (!output || !psbt) { + TX_CHECK_OUTPUT; + if (!psbt) return WALLY_EINVAL; - } if ((ret = wally_psbt_get_length(psbt, &len)) != WALLY_OK) { return ret; From 4504a4a68b401fcb0f2c7be226bdad90386a0672 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 14:00:11 +1200 Subject: [PATCH 054/205] psbt: constify wally_extract_psbt input and fix docs --- include/wally_psbt.h | 4 ++-- src/psbt.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 43c803108..d7a88395a 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -590,11 +590,11 @@ WALLY_CORE_API int wally_finalize_psbt( /** * Extract a network transaction from a finalized PSBT. * - * :param psbt: PSBT to extract. Directly modifies this PSBT. + * :param psbt: PSBT to extract from. * :param output: Resulting transaction */ WALLY_CORE_API int wally_extract_psbt( - struct wally_psbt *psbt, + const struct wally_psbt *psbt, struct wally_tx **output); #ifdef __cplusplus diff --git a/src/psbt.c b/src/psbt.c index fc2fe9f7d..9d3f159e5 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2926,7 +2926,7 @@ int wally_finalize_psbt(struct wally_psbt *psbt) } int wally_extract_psbt( - struct wally_psbt *psbt, + const struct wally_psbt *psbt, struct wally_tx **output) { struct wally_tx *result = NULL; From 7ff892eafbc865cee71cb4ea47f90f8f8ea8e2d8 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 14:03:10 +1200 Subject: [PATCH 055/205] psbt: Add missing checks to and simplify extract_psbt --- src/psbt.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 9d3f159e5..44c8187b6 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2931,33 +2931,35 @@ int wally_extract_psbt( { struct wally_tx *result = NULL; size_t i; - int ret = WALLY_OK; + int ret; TX_CHECK_OUTPUT; - if (!psbt || !psbt->tx || psbt->num_inputs == 0 || psbt->num_outputs == 0) { + if (!psbt || !psbt->tx || !psbt->num_inputs || !psbt->num_outputs || + psbt->tx->num_inputs < psbt->num_inputs || psbt->tx->num_outputs < psbt->num_outputs) return WALLY_EINVAL; - } - wally_tx_clone(psbt->tx, 0, &result); + if ((ret = wally_tx_clone(psbt->tx, 0, &result)) != WALLY_OK) + return ret; for (i = 0; i < psbt->num_inputs; ++i) { struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_tx_input *vin = &result->inputs[i]; + if (!input->final_script_sig && !input->final_witness) { ret = WALLY_EINVAL; - goto fail; + break; } if (input->final_script_sig) { if (vin->script) { /* Our global tx shouldn't have a scriptSig */ ret = WALLY_EINVAL; - goto fail; + break; } if (!clone_bytes(&vin->script, input->final_script_sig, input->final_script_sig_len)) { ret = WALLY_ENOMEM; - goto fail; + break; } vin->script_len = input->final_script_sig_len; } @@ -2965,21 +2967,18 @@ int wally_extract_psbt( if (vin->witness) { /* Our global tx shouldn't have a witness */ ret = WALLY_EINVAL; - goto fail; + break; } if (!(vin->witness = clone_witness(input->final_witness))) { ret = WALLY_ENOMEM; - goto fail; + break; } } } - *output = result; - return ret; - -fail: - if (result) { + if (ret == WALLY_OK) + *output = result; + else wally_tx_free(result); - } return ret; } From 336e56d76676321f0385f5fa1dfead877b7d62d6 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 14:37:45 +1200 Subject: [PATCH 056/205] psbt: Fix input and output leaks, clear data when freeing --- src/psbt.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 44c8187b6..ffaa9253a 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -575,7 +575,7 @@ int wally_psbt_input_set_sighash_type( return WALLY_OK; } -int wally_psbt_input_free(struct wally_psbt_input *input) +static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) { if (input) { wally_tx_free(input->non_witness_utxo); @@ -587,10 +587,18 @@ int wally_psbt_input_free(struct wally_psbt_input *input) wally_keypath_map_free(input->keypaths); wally_partial_sigs_map_free(input->partial_sigs); wally_unknowns_map_free(input->unknowns); + wally_clear(input, sizeof(*input)); + if (free_parent) + wally_free(input); } return WALLY_OK; } +int wally_psbt_input_free(struct wally_psbt_input *input) +{ + return psbt_input_free(input, true); +} + int wally_psbt_output_init_alloc( unsigned char *redeem_script, size_t redeem_script_len, @@ -687,17 +695,25 @@ int wally_psbt_output_set_unknowns( return WALLY_OK; } -int wally_psbt_output_free(struct wally_psbt_output *output) +static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) { if (output) { clear_and_free(output->redeem_script, output->redeem_script_len); clear_and_free(output->witness_script, output->witness_script_len); wally_keypath_map_free(output->keypaths); wally_unknowns_map_free(output->unknowns); + wally_clear(output, sizeof(*output)); + if (free_parent) + wally_free(output); } return WALLY_OK; } +int wally_psbt_output_free(struct wally_psbt_output *output) +{ + return psbt_output_free(output, true); +} + int wally_psbt_init_alloc( size_t inputs_allocation_len, size_t outputs_allocation_len, @@ -739,16 +755,16 @@ int wally_psbt_free(struct wally_psbt *psbt) size_t i; if (psbt) { wally_tx_free(psbt->tx); - for (i = 0; i < psbt->num_inputs; ++i) { - wally_psbt_input_free(&psbt->inputs[i]); - } + for (i = 0; i < psbt->num_inputs; ++i) + psbt_input_free(&psbt->inputs[i], false); + wally_free(psbt->inputs); - for (i = 0; i < psbt->num_outputs; ++i) { - wally_psbt_output_free(&psbt->outputs[i]); - } + for (i = 0; i < psbt->num_outputs; ++i) + psbt_output_free(&psbt->outputs[i], false); + wally_free(psbt->outputs); wally_unknowns_map_free(psbt->unknowns); - wally_free(psbt); + clear_and_free(psbt, sizeof(*psbt)); } return WALLY_OK; } From 0b3cdf4ed8408b99212c98e59df0d670b3eb737e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:39:04 +0930 Subject: [PATCH 057/205] travis: don't explicitly list what tests in tools/travis_build.sh AFAICT, the below does the same thing, and avoids glslang having to tell me to add my test there. Signed-off-by: Rusty Russell --- tools/travis_build.sh | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/tools/travis_build.sh b/tools/travis_build.sh index 638c9e4dc..b218b3f37 100755 --- a/tools/travis_build.sh +++ b/tools/travis_build.sh @@ -1,21 +1,6 @@ #! /usr/bin/env bash -function show_err() -{ - if [ -f $1 ]; then - cat $1 - fi -} - -function show_test_err() -{ - tests="test_bech32 test_clear test_tx test_elements_tx test_blech32" - for i in $tests; do - show_err src/$i.log - done -} - -trap "show_test_err" ERR +trap "cat src/test_*.log" ERR ENABLE_SWIG_PYTHON="--enable-swig-python" ENABLE_SWIG_JAVA="--enable-swig-java" From cd6af40508856e0505d5510aa92cf129e15e9d8d Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:41:09 +0930 Subject: [PATCH 058/205] psbt: add a simple test case, by copying some of BIP 0174. Signed-off-by: Rusty Russell --- .gitignore | 1 + src/Makefile.am | 5 + src/ctest/psbts.h | 299 ++++++++++++++++++++++++++++++++++++++++++ src/ctest/test_psbt.c | 64 +++++++++ 4 files changed, 369 insertions(+) create mode 100644 src/ctest/psbts.h create mode 100644 src/ctest/test_psbt.c diff --git a/.gitignore b/.gitignore index 51e4fc112..9f999043d 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ src/test_bech32* src/test_blech32* src/test_clear* src/test_tx* +src/test_psbt* src/test_elements_tx* src/test-suite.log src/swig_java/swig_java_wrap.c diff --git a/src/Makefile.am b/src/Makefile.am index 1d13baadf..4118dbeb5 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -225,6 +225,11 @@ noinst_PROGRAMS += test_bech32 test_bech32_SOURCES = ctest/test_bech32.c test_bech32_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS) test_bech32_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@ +TESTS += test_psbt +noinst_PROGRAMS += test_psbt +test_psbt_SOURCES = ctest/test_psbt.c ccan/ccan/str/hex/hex.c +test_psbt_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS) -I$(srcdir)/ccan +test_psbt_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@ if USE_PTHREAD TESTS += test_clear noinst_PROGRAMS += test_clear diff --git a/src/ctest/psbts.h b/src/ctest/psbts.h new file mode 100644 index 000000000..51864c0eb --- /dev/null +++ b/src/ctest/psbts.h @@ -0,0 +1,299 @@ +struct psbt_test { + const char *hex; + const char *base64; +}; + +/* From BIP 174: + * + * The following are invalid PSBTs: + */ +static const struct psbt_test invalid_psbts[] = { +/* + Case: Network transaction, not PSBT format + Bytes in Hex: +*/ + { "0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300", + +/* + Base64 String: +*/ + "AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAABqRzBEAiBwsiRRI+a/R01gxbUMBD1MaRpdJDXwmjSnZiqdwlF5CgIgATKcqdrPKAvfMHQOwDkEIkIsgctFg5RXrrdvwS7dlbMBIQJlfRGNM1e44PTCzUbbezn22cONmnCry5st5dyNv+TOMf7///8C09/1BQAAAAAZdqkU0MWZA8W6woaHYOkP1SGkZlqnZSCIrADh9QUAAAAAF6kUNUXm4zuDLEcFDyTT7rk8nAOUi8eHsy4TAA=="}, + +/* + Case: PSBT missing outputs + Bytes in Hex: +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA=="}, + +/* + Case: PSBT where one input has a filled scriptSig in the unsigned tx + Bytes in Hex: + +*/ + { "70736274ff0100fd0a010200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be4000000006a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa88292feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000", +/* + Base64 String: +*/ + "cHNidP8BAP0KAQIAAAACqwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QAAAAAakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpL+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAABASAA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHhwEEFgAUhdE1N/LiZUBaNNuvqePdoB+4IwgAAAA="}, + +/* + Case: PSBT where inputs and outputs are provided but without an unsigned tx + Bytes in Hex: + +*/ + { "70736274ff000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000000", +/* + Base64 String: +*/ + "cHNidP8AAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAA=="}, + +/* + Case: PSBT with duplicate keys in an input + Bytes in Hex: + +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQA/AgAAAAH//////////////////////////////////////////wAAAAAA/////wEAAAAAAAAAAANqAQAAAAAAAAAA"}, + +/* + Case: PSBT With invalid global transaction typed key + Bytes in Hex: + +*/ + { "70736274ff020001550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8CAAFVAgAAAAEnmiMjpd+1H8RfIg+liw/BPh4zQnkqhdfjbNYzO1y8OQAAAAAA/////wGgWuoLAAAAABl2qRT/6cAGEJfMO2NvLLBGD6T8Qn0rRYisAAAAAAABASCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid input witness utxo typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac000000000002010020955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAIBACCVXuoLAAAAABepFGNFIA9o0YnhrcDfHE0W6o8UwNvrhyICA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GRjBDAiAEJLWO/6qmlOFVnqXJO7/UqJBkIkBVzfBwtncUaUQtBwIfXI6w/qZRbWC4rLM61k7eYOh4W/s6qUuZvfhhUduamgEBBCIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid pubkey length for input partial signature typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87210203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd46304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIQIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYwQwIgBCS1jv+qppThVZ6lyTu/1KiQZCJAVc3wcLZ3FGlELQcCH1yOsP6mUW1guKyzOtZO3mDoeFv7OqlLmb34YVHbmpoBAQQiACB3H9GK1FlmbdSfPVZOPbxC9MhHdONgraFoFqjtSI1WgQEFR1IhA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GIQPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvVKuIgYDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYQtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA=="}, + +/* + Case: PSBT With invalid redeemscript typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a01020400220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQIEACIAIHcf0YrUWWZt1J89Vk49vEL0yEd042CtoWgWqO1IjVaBAQVHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid witnessscript typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d568102050047522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoECBQBHUiEDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUYhA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9Uq4iBgOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RhC0prpnAAAAgAAAAIAEAACAIgYD3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg70QtKa6ZwAAAIAAAACABQAAgAAA"}, + +/* + Case: PSBT With invalid bip32 typed key + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae210603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd10b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriEGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb0QtKa6ZwAAAIAAAACABAAAgCIGA95V0eHayAXj+KWMH7+blMAvPbqv4Sf+/KSZXyb4IIO9ELSmumcAAACAAAAAgAUAAIAAAA=="}, + +/* + Case: PSBT With invalid non-witness utxo typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f0000000000020000bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAIAALsCAAAAAarXOTEBi9JfhK5AC2iEi+CdtwbqwqwYKYur7nGrZW+LAAAAAEhHMEQCIFj2/HxqM+GzFUjUgcgmwBW9MBNarULNZ3kNq2bSrSQ7AiBKHO0mBMZzW2OT5bQWkd14sA8MWUL7n3UYVvqpOBV9ugH+////AoDw+gIAAAAAF6kUD7lGNCFpa4LIM68kHHjBfdveSTSH0PIKJwEAAAAXqRQpynT4oI+BmZQoGFyXtdhS5AY/YYdlAAAAAQfaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="}, + +/* + Case: PSBT With invalid final scriptsig typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f618765000000020700da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAACBwDaAEcwRAIgdAGK1BgAl7hzMjwAFXILNoTMgSOJEEjn282bVa1nnJkCIHPTabdA4+tT3O+jOCPIBwUUylWn3ZVE8VfBZ5EyYRGMAUgwRQIhAPYQOLMI3B2oZaNIUnRvAVdyk0IIxtJEVDk82ZvfIhd3AiAFbmdaZ1ptCgK4WxTl4pB02KJam1dgvqKBb2YZEKAG6gFHUiEClYO/Oa4KYJdHrRma3dY0+mEIVZ1sXNObTCGD8auW4H8hAtq2H/SaFNtqfQKwzR+7ePxLGDErW05U2uTbovv+9TbXUq4AAQEgAMLrCwAAAAAXqRS39fr0Dj1ApaRZsds1NfK3L6kh6IcBByMiACCMI1MXN0O1ld+0oHtyuo5C43l9p06H/n2ddJfjsgKJAwEI2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="}, + +/* + Case: PSBT With invalid final script witness typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b2028903020800da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00220203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca5877110d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAggA2gQARzBEAiBi63pVYQenxz9FrEq1od3fb3B1+xJ1lpp/OD7/94S8sgIgDAXbt0cNvy8IVX3TVscyXB7TCRPpls04QJRdsSIo2l8BRzBEAiBl9FulmYtZon/+GnvtAWrx8fkNVLOqj3RQql9WolEDvQIgf3JHA60e25ZoCyhLVtT/y4j3+3Weq74IqjDym4UTg9IBR1IhAwidwQx6xttU+RMpr2FzM9s4jOrQwjH3IzedG5kDCwLcIQI63ZBPPW3PWd25BrDe4jUpt/+57VDl6GFRkmhgIh8Oc1KuACICA6mkw39ZltOqJdusa1cK8GUDlEkpQkYLNUdT7Z7spYdxENkMak8AAACAAAAAgAQAAIAAIgICf2OZdX0u/1WhNq0CxoSxg4tlVuXxtrNCgqlLa1AFEJYQ2QxqTwAAAIAAAACABQAAgAA="}, + +/* + Case: PSBT With invalid pubkey in output BIP 32 derivation paths typed key + Bytes in Hex: + +*/ + { "70736274ff01009a020000000258e87a21b56daf0c23be8e7070456c336f7cbaa5c8757924f545887bb2abdd750000000000ffffffff838d0427d0ec650a68aa46bb0b098aea4422c071b2ca78352a077959d07cea1d0100000000ffffffff0270aaf00800000000160014d85c2b71d0060b09c9886aeb815e50991dda124d00e1f5050000000016001400aea9a2e5f0f876a588df5546e8742d1d87008f00000000000100bb0200000001aad73931018bd25f84ae400b68848be09db706eac2ac18298babee71ab656f8b0000000048473044022058f6fc7c6a33e1b31548d481c826c015bd30135aad42cd67790dab66d2ad243b02204a1ced2604c6735b6393e5b41691dd78b00f0c5942fb9f751856faa938157dba01feffffff0280f0fa020000000017a9140fb9463421696b82c833af241c78c17ddbde493487d0f20a270100000017a91429ca74f8a08f81999428185c97b5d852e4063f6187650000000107da00473044022074018ad4180097b873323c0015720b3684cc8123891048e7dbcd9b55ad679c99022073d369b740e3eb53dcefa33823c8070514ca55a7dd9544f157c167913261118c01483045022100f61038b308dc1da865a34852746f015772934208c6d24454393cd99bdf2217770220056e675a675a6d0a02b85b14e5e29074d8a25a9b5760bea2816f661910a006ea01475221029583bf39ae0a609747ad199addd634fa6108559d6c5cd39b4c2183f1ab96e07f2102dab61ff49a14db6a7d02b0cd1fbb78fc4b18312b5b4e54dae4dba2fbfef536d752ae0001012000c2eb0b0000000017a914b7f5faf40e3d40a5a459b1db3535f2b72fa921e8870107232200208c2353173743b595dfb4a07b72ba8e42e3797da74e87fe7d9d7497e3b20289030108da0400473044022062eb7a556107a7c73f45ac4ab5a1dddf6f7075fb1275969a7f383efff784bcb202200c05dbb7470dbf2f08557dd356c7325c1ed30913e996cd3840945db12228da5f01473044022065f45ba5998b59a27ffe1a7bed016af1f1f90d54b3aa8f7450aa5f56a25103bd02207f724703ad1edb96680b284b56d4ffcb88f7fb759eabbe08aa30f29b851383d20147522103089dc10c7ac6db54f91329af617333db388cead0c231f723379d1b99030b02dc21023add904f3d6dcf59ddb906b0dee23529b7ffb9ed50e5e86151926860221f0e7352ae00210203a9a4c37f5996d3aa25dbac6b570af0650394492942460b354753ed9eeca58710d90c6a4f000000800000008004000080002202027f6399757d2eff55a136ad02c684b1838b6556e5f1b6b34282a94b6b5005109610d90c6a4f00000080000000800500008000", +/* + Base64 String: +*/ + "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA"}, + +/* + Case: PSBT With invalid input sighash type typed key + Bytes in Hex: + +*/ + { "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c0203000100000000010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65010125512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00", +/* + Base64 String: +*/ + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"}, + +/* + Case: PSBT With invalid output redeemScript typed key + Bytes in Hex: + +*/ + { "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c0002000016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a65010125512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d2bd57f8a8751ae00", +/* + Base64 String: +*/ + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A"}, + +/* + Case: PSBT With invalid output witnessScript typed key + Bytes in Hex: + +*/ + { "70736274ff0100730200000001301ae986e516a1ec8ac5b4bc6573d32f83b465e23ad76167d68b38e730b4dbdb0000000000ffffffff02747b01000000000017a91403aa17ae882b5d0d54b25d63104e4ffece7b9ea2876043993b0000000017a914b921b1ba6f722e4bfa83b6557a3139986a42ec8387000000000001011f00ca9a3b00000000160014d2d94b64ae08587eefc8eeb187c601e939f9037c00010016001462e9e982fff34dd8239610316b090cd2a3b747cb000100220020876bad832f1d168015ed41232a9ea65a1815d9ef13c0ef8759f64b5b2b278a6521010025512103b7ce23a01c5b4bf00a642537cdfabb315b668332867478ef51309d06d57f8a8751ae00", +/* + Base64 String: +*/ + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnQbVf4qHUa4A"}, +}; + +/* The following are valid PSBTs: + */ +static const struct psbt_test valid_psbts[] = { +/* + Case: PSBT with one P2PKH input. Outputs are empty + Bytes in Hex: + +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAAAA"}, + +/* + Case: PSBT with one P2PKH input and one P2SH-P2WPKH input. First input is signed and finalized. Outputs are empty + Bytes in Hex: + +*/ + { "70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac000000000001076a47304402204759661797c01b036b25928948686218347d89864b719e1f7fcf57d1e511658702205309eabf56aa4d8891ffd111fdf1336f3a29da866d7f8486d75546ceedaf93190121035cdc61fc7ba971c0b501a646a2a83b102cb43881217ca682dc86e2d73fa882920001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb82308000000", +/* + Base64 String: +*/ + "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEHakcwRAIgR1lmF5fAGwNrJZKJSGhiGDR9iYZLcZ4ff89X0eURZYcCIFMJ6r9Wqk2Ikf/REf3xM286KdqGbX+EhtdVRs7tr5MZASEDXNxh/HupccC1AaZGoqg7ECy0OIEhfKaC3Ibi1z+ogpIAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIAAAA"}, + +/* + Case: PSBT with one P2PKH input which has a non-final scriptSig and has a sighash type specified. Outputs are empty + Bytes in Hex: + +*/ + { "70736274ff0100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab30000000001030401000000000000", +/* + Base64 String: +*/ + "cHNidP8BAHUCAAAAASaBcTce3/KF6Tet7qSze3gADAVmy7OtZGQXE8pCFxv2AAAAAAD+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQD9pQEBAAAAAAECiaPHHqtNIOA3G7ukzGmPopXJRjr6Ljl/hTPMti+VZ+UBAAAAFxYAFL4Y0VKpsBIDna89p95PUzSe7LmF/////4b4qkOnHf8USIk6UwpyN+9rRgi7st0tAXHmOuxqSJC0AQAAABcWABT+Pp7xp0XpdNkCxDVZQ6vLNL1TU/////8CAMLrCwAAAAAZdqkUhc/xCX/Z4Ai7NK9wnGIZeziXikiIrHL++E4sAAAAF6kUM5cluiHv1irHU6m80GfWx6ajnQWHAkcwRAIgJxK+IuAnDzlPVoMR3HyppolwuAJf3TskAinwf4pfOiQCIAGLONfc0xTnNMkna9b7QPZzMlvEuqFEyADS8vAtsnZcASED0uFWdJQbrUqZY3LLh+GFbTZSYG2YVi/jnF6efkE/IQUCSDBFAiEA0SuFLYXc2WHS9fSrZgZU327tzHlMDDPOXMMJ/7X85Y0CIGczio4OFyXBl/saiK9Z9R5E5CVbIBZ8hoQDHAXR8lkqASECI7cr7vCWXRC+B3jv7NYfysb3mk6haTkzgHNEZPhPKrMAAAAAAQMEAQAAAAAAAA=="}, + +/* + Case: PSBT with one P2PKH input and one P2SH-P2WPKH input both with non-final scriptSigs. P2SH-P2WPKH input's redeemScript is available. Outputs filled. + Bytes in Hex: + +*/ + { "70736274ff0100a00200000002ab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40000000000feffffffab0949a08c5af7c49b8212f417e2f15ab3f5c33dcf153821a8139f877a5b7be40100000000feffffff02603bea0b000000001976a914768a40bbd740cbe81d988e71de2a4d5c71396b1d88ac8e240000000000001976a9146f4620b553fa095e721b9ee0efe9fa039cca459788ac00000000000100df0200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf6000000006a473044022070b2245123e6bf474d60c5b50c043d4c691a5d2435f09a34a7662a9dc251790a022001329ca9dacf280bdf30740ec0390422422c81cb45839457aeb76fc12edd95b3012102657d118d3357b8e0f4c2cd46db7b39f6d9c38d9a70abcb9b2de5dc8dbfe4ce31feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e13000001012000e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787010416001485d13537f2e265405a34dbafa9e3dda01fb8230800220202ead596687ca806043edc3de116cdf29d5e9257c196cd055cf698c8d02bf24e9910b4a6ba670000008000000080020000800022020394f62be9df19952c5587768aeb7698061ad2c4a25c894f47d8c162b4d7213d0510b4a6ba6700000080010000800200008000", +/* + Base64 String: +*/ + "cHNidP8BAKACAAAAAqsJSaCMWvfEm4IS9Bfi8Vqz9cM9zxU4IagTn4d6W3vkAAAAAAD+////qwlJoIxa98SbghL0F+LxWrP1wz3PFTghqBOfh3pbe+QBAAAAAP7///8CYDvqCwAAAAAZdqkUdopAu9dAy+gdmI5x3ipNXHE5ax2IrI4kAAAAAAAAGXapFG9GILVT+glechue4O/p+gOcykWXiKwAAAAAAAEA3wIAAAABJoFxNx7f8oXpN63upLN7eAAMBWbLs61kZBcTykIXG/YAAAAAakcwRAIgcLIkUSPmv0dNYMW1DAQ9TGkaXSQ18Jo0p2YqncJReQoCIAEynKnazygL3zB0DsA5BCJCLIHLRYOUV663b8Eu3ZWzASECZX0RjTNXuOD0ws1G23s59tnDjZpwq8ubLeXcjb/kzjH+////AtPf9QUAAAAAGXapFNDFmQPFusKGh2DpD9UhpGZap2UgiKwA4fUFAAAAABepFDVF5uM7gyxHBQ8k0+65PJwDlIvHh7MuEwAAAQEgAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4cBBBYAFIXRNTfy4mVAWjTbr6nj3aAfuCMIACICAurVlmh8qAYEPtw94RbN8p1eklfBls0FXPaYyNAr8k6ZELSmumcAAACAAAAAgAIAAIAAIgIDlPYr6d8ZlSxVh3aK63aYBhrSxKJciU9H2MFitNchPQUQtKa6ZwAAAIABAACAAgAAgAA="}, + +/* + Case: PSBT with one P2SH-P2WSH input of a 2-of-2 multisig, redeemScript, witnessScript, and keypaths are available. Contains one signature. + Bytes in Hex: + +*/ + { "70736274ff0100550200000001279a2323a5dfb51fc45f220fa58b0fc13e1e3342792a85d7e36cd6333b5cbc390000000000ffffffff01a05aea0b000000001976a914ffe9c0061097cc3b636f2cb0460fa4fc427d2b4588ac0000000000010120955eea0b0000000017a9146345200f68d189e1adc0df1c4d16ea8f14c0dbeb87220203b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4646304302200424b58effaaa694e1559ea5c93bbfd4a89064224055cdf070b6771469442d07021f5c8eb0fea6516d60b8acb33ad64ede60e8785bfb3aa94b99bdf86151db9a9a010104220020771fd18ad459666dd49f3d564e3dbc42f4c84774e360ada16816a8ed488d5681010547522103b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd462103de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd52ae220603b1341ccba7683b6af4f1238cd6e97e7167d569fac47f1e48d47541844355bd4610b4a6ba67000000800000008004000080220603de55d1e1dac805e3f8a58c1fbf9b94c02f3dbaafe127fefca4995f26f82083bd10b4a6ba670000008000000080050000800000", +/* + Base64 String: +*/ + "cHNidP8BAFUCAAAAASeaIyOl37UfxF8iD6WLD8E+HjNCeSqF1+Ns1jM7XLw5AAAAAAD/////AaBa6gsAAAAAGXapFP/pwAYQl8w7Y28ssEYPpPxCfStFiKwAAAAAAAEBIJVe6gsAAAAAF6kUY0UgD2jRieGtwN8cTRbqjxTA2+uHIgIDsTQcy6doO2r08SOM1ul+cWfVafrEfx5I1HVBhENVvUZGMEMCIAQktY7/qqaU4VWepck7v9SokGQiQFXN8HC2dxRpRC0HAh9cjrD+plFtYLisszrWTt5g6Hhb+zqpS5m9+GFR25qaAQEEIgAgdx/RitRZZm3Unz1WTj28QvTIR3TjYK2haBao7UiNVoEBBUdSIQOxNBzLp2g7avTxI4zW6X5xZ9Vp+sR/HkjUdUGEQ1W9RiED3lXR4drIBeP4pYwfv5uUwC89uq/hJ/78pJlfJvggg71SriIGA7E0HMunaDtq9PEjjNbpfnFn1Wn6xH8eSNR1QYRDVb1GELSmumcAAACAAAAAgAQAAIAiBgPeVdHh2sgF4/iljB+/m5TALz26r+En/vykmV8m+CCDvRC0prpnAAAAgAAAAIAFAACAAAA="}, + +/* + Case: PSBT with one P2WSH input of a 2-of-2 multisig. witnessScript, keypaths, and global xpubs are available. Contains no signatures. Outputs filled. + Bytes in Hex: + +*/ + { "70736274ff01005202000000019dfc6628c26c5899fe1bd3dc338665bfd55d7ada10f6220973df2d386dec12760100000000ffffffff01f03dcd1d000000001600147b3a00bfdc14d27795c2b74901d09da6ef133579000000004f01043587cf02da3fd0088000000097048b1ad0445b1ec8275517727c87b4e4ebc18a203ffa0f94c01566bd38e9000351b743887ee1d40dc32a6043724f2d6459b3b5a4d73daec8fbae0472f3bc43e20cd90c6a4fae000080000000804f01043587cf02da3fd00880000001b90452427139cd78c2cff2444be353cd58605e3e513285e528b407fae3f6173503d30a5e97c8adbc557dac2ad9a7e39c1722ebac69e668b6f2667cc1d671c83cab0cd90c6a4fae000080010000800001012b0065cd1d000000002200202c5486126c4978079a814e13715d65f36459e4d6ccaded266d0508645bafa6320105475221029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c88712103372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b52ae2206029da12cdb5b235692b91536afefe5c91c3ab9473d8e43b533836ab456299c887110d90c6a4fae0000800000008000000000220603372b34234ed7cf9c1fea5d05d441557927be9542b162eb02e1ab2ce80224c00b10d90c6a4fae0000800100008000000000002202039eff1f547a1d5f92dfa2ba7af6ac971a4bd03ba4a734b03156a256b8ad3a1ef910ede45cc500000080000000800100008000", +/* + Base64 String: +*/ + "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA"}, + +/* + Case: PSBT with unknown types in the inputs. + Bytes in Hex: + +*/ + { "70736274ff01003f0200000001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffffffff010000000000000000036a010000000000000a0f0102030405060708090f0102030405060708090a0b0c0d0e0f0000", +/* + Base64 String: +*/ + "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA="}, + +/* + Case: PSBT with `PSBT_GLOBAL_XPUB`. + Bytes in Hex: + +*/ + { "70736274ff01009d0100000002710ea76ab45c5cb6438e607e59cc037626981805ae9e0dfd9089012abb0be5350100000000ffffffff190994d6a8b3c8c82ccbcfb2fba4106aa06639b872a8d447465c0d42588d6d670000000000ffffffff0200e1f505000000001976a914b6bc2c0ee5655a843d79afedd0ccc3f7dd64340988ac605af405000000001600141188ef8e4ce0449eaac8fb141cbf5a1176e6a088000000004f010488b21e039e530cac800000003dbc8a5c9769f031b17e77fea1518603221a18fd18f2b9a54c6c8c1ac75cbc3502f230584b155d1c7f1cd45120a653c48d650b431b67c5b2c13f27d7142037c1691027569c503100008000000080000000800001011f00e1f5050000000016001433b982f91b28f160c920b4ab95e58ce50dda3a4a220203309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c47304402202d704ced830c56a909344bd742b6852dccd103e963bae92d38e75254d2bb424502202d86c437195df46c0ceda084f2a291c3da2d64070f76bf9b90b195e7ef28f77201220603309680f33c7de38ea6a47cd4ecd66f1f5a49747c6ffb8808ed09039243e3ad5c1827569c5031000080000000800000008000000000010000000001011f00e1f50500000000160014388fb944307eb77ef45197d0b0b245e079f011de220202c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b11047304402204cb1fb5f869c942e0e26100576125439179ae88dca8a9dc3ba08f7953988faa60220521f49ca791c27d70e273c9b14616985909361e25be274ea200d7e08827e514d01220602c777161f73d0b7c72b9ee7bde650293d13f095bc7656ad1f525da5fd2e10b1101827569c5031000080000000800000008000000000000000000000220202d20ca502ee289686d21815bd43a80637b0698e1fbcdbe4caed445f6c1a0a90ef1827569c50310000800000008000000080000000000400000000", +/* + Base64 String: +*/ + "cHNidP8BAJ0BAAAAAnEOp2q0XFy2Q45gflnMA3YmmBgFrp4N/ZCJASq7C+U1AQAAAAD/////GQmU1qizyMgsy8+y+6QQaqBmObhyqNRHRlwNQliNbWcAAAAAAP////8CAOH1BQAAAAAZdqkUtrwsDuVlWoQ9ea/t0MzD991kNAmIrGBa9AUAAAAAFgAUEYjvjkzgRJ6qyPsUHL9aEXbmoIgAAAAATwEEiLIeA55TDKyAAAAAPbyKXJdp8DGxfnf+oVGGAyIaGP0Y8rmlTGyMGsdcvDUC8jBYSxVdHH8c1FEgplPEjWULQxtnxbLBPyfXFCA3wWkQJ1acUDEAAIAAAACAAAAAgAABAR8A4fUFAAAAABYAFDO5gvkbKPFgySC0q5XljOUN2jpKIgIDMJaA8zx9446mpHzU7NZvH1pJdHxv+4gI7QkDkkPjrVxHMEQCIC1wTO2DDFapCTRL10K2hS3M0QPpY7rpLTjnUlTSu0JFAiAthsQ3GV30bAztoITyopHD2i1kBw92v5uQsZXn7yj3cgEiBgMwloDzPH3jjqakfNTs1m8fWkl0fG/7iAjtCQOSQ+OtXBgnVpxQMQAAgAAAAIAAAACAAAAAAAEAAAAAAQEfAOH1BQAAAAAWABQ4j7lEMH63fvRRl9CwskXgefAR3iICAsd3Fh9z0LfHK57nveZQKT0T8JW8dlatH1Jdpf0uELEQRzBEAiBMsftfhpyULg4mEAV2ElQ5F5rojcqKncO6CPeVOYj6pgIgUh9JynkcJ9cOJzybFGFphZCTYeJb4nTqIA1+CIJ+UU0BIgYCx3cWH3PQt8crnue95lApPRPwlbx2Vq0fUl2l/S4QsRAYJ1acUDEAAIAAAACAAAAAgAAAAAAAAAAAAAAiAgLSDKUC7iiWhtIYFb1DqAY3sGmOH7zb5MrtRF9sGgqQ7xgnVpxQMQAAgAAAAIAAAACAAAAAAAQAAAAA"}, +}; diff --git a/src/ctest/test_psbt.c b/src/ctest/test_psbt.c new file mode 100644 index 000000000..37f6f4733 --- /dev/null +++ b/src/ctest/test_psbt.c @@ -0,0 +1,64 @@ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "psbts.h" + +int main(void) +{ + size_t i; + + for (i = 0; i < sizeof(invalid_psbts) / sizeof(invalid_psbts[0]); i++) { + struct wally_psbt *psbt; + + if (wally_psbt_from_base64(invalid_psbts[i].base64, &psbt) != WALLY_OK) + continue; + errx(1, "Should have failed to parse psbt %s", invalid_psbts[i].base64); + } + + for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { + struct wally_psbt *psbt; + char *output; + unsigned char *bytes; + size_t len, actual_len; + + if (wally_psbt_from_base64(valid_psbts[i].base64, &psbt) != WALLY_OK) { + errx(1, "Failed to parse psbt %s", valid_psbts[i].base64); + } + if (wally_psbt_to_base64(psbt, &output) != WALLY_OK) { + errx(1, "Failed to base64 psbt %s", valid_psbts[i].base64); + } + if (strcmp(output, valid_psbts[i].base64) != 0) { + errx(1, "psbt %s turned into %s?", valid_psbts[i].base64, output); + } + free(output); + + if (wally_psbt_get_length(psbt, &len) != WALLY_OK) { + errx(1, "Failed to get pbst %s len", valid_psbts[i].base64); + } + bytes = malloc(len); + if (wally_psbt_to_bytes(psbt, bytes, len, &actual_len) != WALLY_OK) { + errx(1, "psbt %s could not to_bytes?", valid_psbts[i].base64); + } + if (len != actual_len) { + errx(1, "psbt %s to_bytes to %zu not %zu?", valid_psbts[i].base64, + actual_len, len); + } + output = malloc(hex_str_size(len)); + hex_encode(bytes, len, output, hex_str_size(len)); + if (strcmp(output, valid_psbts[i].hex) != 0) { + errx(1, "psbt[%zi] bytes %s not %s", i, output, valid_psbts[i].hex); + } + free(bytes); + free(output); + wally_psbt_free(psbt); + } + + return 0; +} From d6387934e1bff0136efb1f008754a17a66975f11 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:42:09 +0930 Subject: [PATCH 059/205] psbt: close some leaks. As revealed by: make && LD_LIBRARY_PATH=`pwd`/src/.libs valgrind --leak-check=full src/.libs/test_psbt There are more, but the next patches rework that code. Signed-off-by: Rusty Russell --- src/psbt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index ffaa9253a..5183a0671 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -282,10 +282,10 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) if (unknowns) { for (i = 0; i < unknowns->num_items; ++i) { if (unknowns->items[i].key) { - wally_clear(unknowns->items[i].key, unknowns->items[i].key_len); + clear_and_free(unknowns->items[i].key, unknowns->items[i].key_len); } if (unknowns->items[i].value) { - wally_clear(unknowns->items[i].value, unknowns->items[i].value_len); + clear_and_free(unknowns->items[i].value, unknowns->items[i].value_len); } } clear_and_free(unknowns->items, unknowns->num_items * sizeof(*unknowns->items)); From b12804e7ffc07fc3271490a0d0c699d44e331d9f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:43:09 +0930 Subject: [PATCH 060/205] psbt: improve constness. Signed-off-by: Rusty Russell --- src/psbt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psbt.c b/src/psbt.c index 5183a0671..5c90f52c6 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -15,7 +15,7 @@ const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; -static bool pubkey_is_compressed(unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { +static bool pubkey_is_compressed(const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { return pubkey[0] == 0x02 || pubkey[0] == 0x03; } From 7f2b5e9c44f0e47e91c78434cef4d0861dc8bcd7 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:27 +0930 Subject: [PATCH 061/205] pullpush: add routines for safe marshal / unmarshal. Manually checking for end of buffers is error prone: these pull & push variants are similar to those used by c-lightning. Importantly, if they fail you can still call them, meaning you can check whether it overflowed at the end of all the work. The push function also can tell you exactly how many bytes short you were. Signed-off-by: Rusty Russell --- src/Makefile.am | 1 + src/pullpush.c | 188 ++++++++++++++++++++++++++++++++++++++++++++++++ src/pullpush.h | 91 +++++++++++++++++++++++ 3 files changed, 280 insertions(+) create mode 100644 src/pullpush.c create mode 100644 src/pullpush.h diff --git a/src/Makefile.am b/src/Makefile.am index 4118dbeb5..bb32c5b5e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -185,6 +185,7 @@ libwallycore_la_SOURCES = \ mnemonic.c \ pbkdf2.c \ psbt.c \ + pullpush.c \ script.c \ scrypt.c \ sign.c \ diff --git a/src/pullpush.c b/src/pullpush.c new file mode 100644 index 000000000..0a1496c53 --- /dev/null +++ b/src/pullpush.c @@ -0,0 +1,188 @@ +#include "internal.h" +#include "script_int.h" + +#include +#include +#include +#include "pullpush.h" + +unsigned char *push_bytes(unsigned char **cursor, size_t *max, + const void *src, size_t len) +{ + if (cursor == NULL || *cursor == NULL) { + *max += len; + return NULL; + } + if (len > *max) { + if (src) + memcpy(*cursor, src, *max); + /* From now on, max records the room we *needed* */ + *max = len - *max; + *cursor = NULL; + return NULL; + } + if (src) + memcpy(*cursor, src, len); + + *cursor += len; + *max -= len; + + return *cursor - len; +} + +void pull_bytes(void *dst, size_t len, + const unsigned char **cursor, size_t *max) +{ + if (len > *max) { + memcpy(dst, *cursor, *max); + memset((char *)dst + *max, 0, len - *max); + pull_failed(cursor, max); + return; + } + memcpy(dst, *cursor, len); + *cursor += len; + *max -= len; +} + +const unsigned char *pull_skip(const unsigned char **cursor, size_t *max, + size_t len) +{ + const unsigned char *p; + + if (*cursor == NULL) { + return NULL; + } + + if (len > *max) { + pull_failed(cursor, max); + return NULL; + } + + p = *cursor; + *cursor += len; + *max -= len; + return p; +} + +void pull_failed(const unsigned char **cursor, size_t *max) +{ + *cursor = NULL; + *max = 0; +} + +void push_le64(unsigned char **cursor, size_t *max, uint64_t v) +{ + leint64_t lev = cpu_to_le64(v); + push_bytes(cursor, max, &lev, sizeof(lev)); +} + +uint64_t pull_le64(const unsigned char **cursor, size_t *max) +{ + leint64_t lev; + pull_bytes(&lev, sizeof(lev), cursor, max); + return le64_to_cpu(lev); +} + +void push_le32(unsigned char **cursor, size_t *max, uint32_t v) +{ + leint32_t lev = cpu_to_le32(v); + push_bytes(cursor, max, &lev, sizeof(lev)); +} + +uint32_t pull_le32(const unsigned char **cursor, size_t *max) +{ + leint32_t lev; + pull_bytes(&lev, sizeof(lev), cursor, max); + return le32_to_cpu(lev); +} + +void push_le16(unsigned char **cursor, size_t *max, uint16_t v) +{ + leint16_t lev = cpu_to_le16(v); + push_bytes(cursor, max, &lev, sizeof(lev)); +} + +uint16_t pull_le16(const unsigned char **cursor, size_t *max) +{ + leint16_t lev; + pull_bytes(&lev, sizeof(lev), cursor, max); + return le16_to_cpu(lev); +} + +void push_u8(unsigned char **cursor, size_t *max, uint8_t v) +{ + push_bytes(cursor, max, &v, sizeof(uint8_t)); +} + +uint8_t pull_u8(const unsigned char **cursor, size_t *max) +{ + uint8_t v; + pull_bytes(&v, sizeof(v), cursor, max); + return v; +} + +void push_varint(unsigned char **cursor, size_t *max, uint64_t v) +{ + unsigned char buf[sizeof(uint8_t) + sizeof(uint64_t)]; + size_t len = varint_to_bytes(v, buf); + + push_bytes(cursor, max, buf, len); +} + +uint64_t pull_varint(const unsigned char **cursor, size_t *max) +{ + unsigned char buf[sizeof(uint8_t) + sizeof(uint64_t)]; + uint64_t v; + + /* FIXME: Would be more efficient to opencode varint here! */ + pull_bytes(buf, 1, cursor, max); + pull_bytes(buf + 1, varint_length_from_bytes(buf) - 1, cursor, max); + varint_from_bytes(buf, &v); + + return v; +} + +void push_varbuff(unsigned char **cursor, size_t *max, + const unsigned char *bytes, size_t bytes_len) +{ + push_varint(cursor, max, bytes_len); + push_bytes(cursor, max, bytes, bytes_len); +} + +size_t pull_varlength(const unsigned char **cursor, size_t *max) +{ + uint64_t len = pull_varint(cursor, max); + + if (len > *max) { + /* Impossible length. */ + pull_failed(cursor, max); + return 0; + } + return len; +} + +void pull_subfield_start(const unsigned char *const *cursor, const size_t *max, + size_t subfield_len, + const unsigned char **subcursor, size_t *submax) +{ + if (subfield_len > *max) { + pull_failed(subcursor, submax); + } else { + *subcursor = *cursor; + *submax = subfield_len; + } +} + +void pull_subfield_end(const unsigned char **cursor, size_t *max, + const unsigned char *subcursor, size_t submax) +{ + if (subcursor == NULL) { + pull_failed(cursor, max); + } else if (*cursor != NULL) { + const unsigned char *subend = subcursor + submax; + assert(subcursor >= *cursor); + assert(subend <= *cursor + *max); + *max -= (subend - *cursor); + *cursor = subend; + } +} diff --git a/src/pullpush.h b/src/pullpush.h new file mode 100644 index 000000000..77d911f25 --- /dev/null +++ b/src/pullpush.h @@ -0,0 +1,91 @@ +#ifndef LIBWALLY_CORE_PULLPUSH_H +#define LIBWALLY_CORE_PULLPUSH_H 1 +/** + * Safely copy @len bytes from @src into @cursor. + * + * If @cursor is NULL or *@cursor is NULL, then nothing will be + * written to it (obv), but *@max will be increased @len. + * + * Otherwise, if @len > *@max, *@max bytes will be copied from @src to + * *@cursor if @src is not NULL, then *@cursor will be set to NULL and + * @max will be set to the remainder. + * + * Otherwise, @len bytes will be copied from @src to *@cursor if @src + * is not NULL, *@max decreased by @len and @cursor increased by @len. + * + * This means you can call it repeatedly, and if it fails, *@cursor will be + * NULL, and *@max will indicate how many additional bytes you need. + * + * On success, this returns *@cursor before it was updated, otherwise NULL. + */ +unsigned char *push_bytes(unsigned char **cursor, size_t *max, + const void *src, size_t len); + +/** + * Safely copy @len bytes from @cursor into @dst. + * + * If @len > *@max, *@max bytes will be copied from *@cursor, the + * remainder of @dst will be zeroed, then *@cursor will be set to NULL + * and @max will be set to 0. + * Otherwise, @len bytes will be copied from @cursor, *@max decreased + * by @len and @cursor increased by @len. + */ +void pull_bytes(void *dst, size_t len, + const unsigned char **cursor, size_t *max); + + +/** + * Return a pointer to (and skip over) some bytes. + * + * Returns NULL (and maybe calls pull_failed()) if there are not enough left. + */ +const unsigned char *pull_skip(const unsigned char **cursor, size_t *max, + size_t len); + + +/** + * Convenience function to indicate a pull failed (eg. type decode failed) + * + * Sets *cursor to NULL, *max to 0. + */ +void pull_failed(const unsigned char **cursor, size_t *max); + +/** + * Convenience functions. + */ +void push_le64(unsigned char **cursor, size_t *max, uint64_t v); +uint64_t pull_le64(const unsigned char **cursor, size_t *max); +void push_le32(unsigned char **cursor, size_t *max, uint32_t v); +uint32_t pull_le32(const unsigned char **cursor, size_t *max); +void push_le16(unsigned char **cursor, size_t *max, uint16_t v); +uint16_t pull_le16(const unsigned char **cursor, size_t *max); +void push_u8(unsigned char **cursor, size_t *max, uint8_t v); +uint8_t pull_u8(const unsigned char **cursor, size_t *max); + +void push_varint(unsigned char **cursor, size_t *max, uint64_t v); +uint64_t pull_varint(const unsigned char **cursor, size_t *max); + +void push_varbuff(unsigned char **cursor, size_t *max, + const unsigned char *bytes, size_t bytes_len); + +/* Calls pull_failed() (and returns 0) if length would exceed remaining *max */ +size_t pull_varlength(const unsigned char **cursor, size_t *max); + +/** + * Functions to parse a subfield within an area. + * + * pull_subfield_start: initializes subcursor/submax to subfield_len at + * cursor. These can then be used with pull_ methods like normal. + * + * end_subfield_pull: updates *cursor and *max to point after the subfield has + * been parsed. If *subcursor is NULL, it's equivalent to pull_failed. + */ +void pull_subfield_start(const unsigned char *const *cursor, const size_t *max, + size_t subfield_len, + const unsigned char **subcursor, size_t *submax); + +void pull_subfield_end(const unsigned char **cursor, size_t *max, + const unsigned char *subcursor, + const size_t submax); + +#endif /* LIBWALLY_CORE_PULLPUSH_H */ From a23aba69bd2f3b30ec216d9d1b971e2ace61b053 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:55 +0930 Subject: [PATCH 062/205] psbt: use push functions for converting input to bytes. This also means we return WALLY_EINVAL instead of corrupting the stack if they provide a witness output > 50 bytes. Signed-off-by: Rusty Russell --- src/psbt.c | 243 +++++++++++++++++++++++++++++------------------------ 1 file changed, 134 insertions(+), 109 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 5c90f52c6..5aae8625a 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -11,6 +11,7 @@ #include "transaction_shared.h" #include "script_int.h" #include "script.h" +#include "pullpush.h" const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; @@ -1815,164 +1816,189 @@ int wally_psbt_get_length( return WALLY_OK; } -static int psbt_input_to_bytes( - const struct wally_psbt_input *input, - unsigned char *bytes_out, size_t len, - size_t *bytes_written) +/* Literally a varbuff containing only type as a varint, then optional data */ +static void push_psbt_key( + unsigned char **cursor, size_t *max, + uint64_t type, const void *extra, size_t extra_len) +{ + push_varint(cursor, max, varint_get_length(type) + extra_len); + push_varint(cursor, max, type); + push_bytes(cursor, max, extra, extra_len); +} + +/* Common case of pushing a type whose key is a pubkey */ +static void push_psbt_key_with_pubkey( + unsigned char **cursor, size_t *max, + uint64_t type, + const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) +{ + if (pubkey_is_compressed(pubkey)) { + push_psbt_key(cursor, max, type, pubkey, EC_PUBLIC_KEY_LEN); + } else { + push_psbt_key(cursor, max, type, pubkey, + EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + } +} + +static int push_length_and_tx( + unsigned char **cursor, size_t *max, + const struct wally_tx *tx, uint32_t flags) +{ + int ret; + size_t txlen; + unsigned char *p; + + ret = wally_tx_get_length(tx, flags, &txlen); + if (ret != WALLY_OK) { + return ret; + } + + push_varint(cursor, max, txlen); + + /* FIXME: convert wally_tx to use push */ + p = push_bytes(cursor, max, NULL, txlen); + if (!p) { + /* We catch this in caller. */ + return WALLY_OK; + } + + return wally_tx_to_bytes(tx, flags, p, txlen, &txlen); +} + +static void push_witness_stack( + unsigned char **cursor, size_t *max, + const struct wally_tx_witness_stack *witness) +{ + size_t i; + + push_varint(cursor, max, witness->num_items); + for (i = 0; i < witness->num_items; ++i) { + push_varbuff(cursor, max, witness->items[i].witness, + witness->items[i].witness_len); + } +} + +static void push_keypath_item( + unsigned char **cursor, size_t *max, + uint64_t type, + const struct wally_keypath_item *item) +{ + size_t origin_len, i; + + push_psbt_key_with_pubkey(cursor, max, type, item->pubkey); + + origin_len = 4; /* Start with 4 bytes for fingerprint */ + origin_len += item->origin.path_len * sizeof(uint32_t); + push_varint(cursor, max, origin_len); + + push_bytes(cursor, max, item->origin.fingerprint, 4); + for (i = 0; i < item->origin.path_len; ++i) { + push_bytes(cursor, max, + &item->origin.path[i], sizeof(uint32_t)); + } +} + +static int push_psbt_input( + unsigned char **cursor, size_t *max, + const struct wally_psbt_input *input) { - unsigned char type, *p = bytes_out, *end = bytes_out + len; int ret; - size_t i, tx_len; + size_t i; /* Non witness utxo */ if (input->non_witness_utxo) { - type = WALLY_PSBT_IN_NON_WITNESS_UTXO; - p += varbuff_to_bytes(&type, 1, p); - ret = wally_tx_get_length(input->non_witness_utxo, WALLY_TX_FLAG_USE_WITNESS, &tx_len); + push_psbt_key(cursor, max, WALLY_PSBT_IN_NON_WITNESS_UTXO, NULL, 0); + ret = push_length_and_tx(cursor, max, + input->non_witness_utxo, + WALLY_TX_FLAG_USE_WITNESS); if (ret != WALLY_OK) { return ret; } - p += varint_to_bytes(tx_len, p); - ret = wally_tx_to_bytes(input->non_witness_utxo, WALLY_TX_FLAG_USE_WITNESS, p, end - p, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - p += tx_len; } + /* Witness utxo */ if (input->witness_utxo) { unsigned char wit_bytes[50], *w = wit_bytes; /* Witness outputs can be no larger than 50 bytes as specified in BIP 141 */ - size_t wit_len; - type = WALLY_PSBT_IN_WITNESS_UTXO; - p += varbuff_to_bytes(&type, 1, p); + size_t wit_max = sizeof(wit_bytes); - /* Serialize the output to the temp buffer; */ - w += uint64_to_le_bytes(input->witness_utxo->satoshi, w); - w += varbuff_to_bytes(input->witness_utxo->script, input->witness_utxo->script_len, w); - wit_len = w - wit_bytes; + push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_UTXO, NULL, 0); + push_le64(&w, &wit_max, input->witness_utxo->satoshi); + push_varbuff(&w, &wit_max, + input->witness_utxo->script, + input->witness_utxo->script_len); - p += varint_to_bytes(wit_len, p); - memcpy(p, wit_bytes, wit_len); - p += wit_len; + if (!w) { + return WALLY_EINVAL; + } + push_varbuff(cursor, max, wit_bytes, w - wit_bytes); } /* Partial sigs */ if (input->partial_sigs) { struct wally_partial_sigs_map *partial_sigs = input->partial_sigs; for (i = 0; i < partial_sigs->num_items; ++i) { struct wally_partial_sigs_item *item = &partial_sigs->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - p += varint_to_bytes(34, p); - *p = WALLY_PSBT_IN_PARTIAL_SIG; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_LEN); - p += EC_PUBLIC_KEY_LEN; - } else { - p += varint_to_bytes(66, p); - *p = WALLY_PSBT_IN_PARTIAL_SIG; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - p += EC_PUBLIC_KEY_UNCOMPRESSED_LEN; - } - p += varbuff_to_bytes(item->sig, item->sig_len, p); + push_psbt_key_with_pubkey(cursor, max, WALLY_PSBT_IN_PARTIAL_SIG, + item->pubkey); + push_varbuff(cursor, max, item->sig, item->sig_len); } } /* Sighash type */ if (input->sighash_type > 0) { - type = WALLY_PSBT_IN_SIGHASH_TYPE; - p += varbuff_to_bytes(&type, 1, p); - p += varint_to_bytes(sizeof(uint32_t), p); - p += uint32_to_le_bytes(input->sighash_type, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_SIGHASH_TYPE, NULL, 0); + push_varint(cursor, max, sizeof(uint32_t)); + push_le32(cursor, max, input->sighash_type); } /* Redeem script */ if (input->redeem_script) { - type = WALLY_PSBT_IN_REDEEM_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(input->redeem_script, input->redeem_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_REDEEM_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + input->redeem_script, input->redeem_script_len); } /* Witness script */ if (input->witness_script) { - type = WALLY_PSBT_IN_WITNESS_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(input->witness_script, input->witness_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + input->witness_script, input->witness_script_len); } /* Keypaths */ if (input->keypaths) { struct wally_keypath_map *keypaths = input->keypaths; for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len, j; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - p += varint_to_bytes(34, p); - *p = WALLY_PSBT_IN_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_LEN); - p += EC_PUBLIC_KEY_LEN; - } else { - p += varint_to_bytes(66, p); - *p = WALLY_PSBT_IN_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - p += EC_PUBLIC_KEY_UNCOMPRESSED_LEN; - } - - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - p += varint_to_bytes(origin_len, p); - - memcpy(p, item->origin.fingerprint, 4); - p += 4; - for (j = 0; j < item->origin.path_len; ++j) { - memcpy(p, &item->origin.path[j], sizeof(uint32_t)); - p += 4; - } + push_keypath_item(cursor, max, + WALLY_PSBT_IN_BIP32_DERIVATION, + &keypaths->items[i]); } } /* Final scriptSig */ if (input->final_script_sig) { - type = WALLY_PSBT_IN_FINAL_SCRIPTSIG; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(input->final_script_sig, input->final_script_sig_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_IN_FINAL_SCRIPTSIG, NULL, 0); + push_varbuff(cursor, max, + input->final_script_sig, input->final_script_sig_len); } /* Final scriptWitness */ if (input->final_witness) { - struct wally_tx_witness_stack *witness = input->final_witness; - size_t wit_len = varint_get_length(witness->num_items); - type = WALLY_PSBT_IN_FINAL_SCRIPTWITNESS; - p += varbuff_to_bytes(&type, 1, p); - for (i = 0; i < witness->num_items; ++i) { - const struct wally_tx_witness_item *stack; - stack = witness->items + i; - wit_len += varint_get_length(stack->witness_len); - wit_len += stack->witness_len; - } + size_t wit_len; - p += varint_to_bytes(wit_len, p); - p += varint_to_bytes(witness->num_items, p); - for (i = 0; i < witness->num_items; ++i) { - const struct wally_tx_witness_item *stack; - stack = witness->items + i; - p += varbuff_to_bytes(stack->witness, stack->witness_len, p); - } + push_psbt_key(cursor, max, WALLY_PSBT_IN_FINAL_SCRIPTWITNESS, NULL, 0); + + /* First pass simply calculates length */ + wit_len = 0; + push_witness_stack(NULL, &wit_len, input->final_witness); + + push_varint(cursor, max, wit_len); + push_witness_stack(cursor, max, input->final_witness); } /* Unknowns */ if (input->unknowns) { for (i = 0; i < input->unknowns->num_items; ++i) { struct wally_unknowns_item *unknown = &input->unknowns->items[i]; - p += varint_to_bytes(unknown->key_len, p); - memcpy(p, unknown->key, unknown->key_len); - p += unknown->key_len; - p += varint_to_bytes(unknown->value_len, p); - memcpy(p, unknown->value, unknown->value_len); - p += unknown->value_len; + push_varbuff(cursor, max, unknown->key, unknown->key_len); + push_varbuff(cursor, max, unknown->value, unknown->value_len); } } /* Separator */ - *p = WALLY_PSBT_SEPARATOR; - p++; - - *bytes_written = p - bytes_out; - + push_u8(cursor, max, WALLY_PSBT_SEPARATOR); return WALLY_OK; } @@ -2109,12 +2135,11 @@ int wally_psbt_to_bytes( /* Get lengths of each input and output */ for (i = 0; i < psbt->num_inputs; ++i) { struct wally_psbt_input *input = &psbt->inputs[i]; - size_t input_len; - ret = psbt_input_to_bytes(input, p, end - p, &input_len); + size_t max = end - p; + ret = push_psbt_input(&p, &max, input); if (ret != WALLY_OK) { return ret; } - p += input_len; } for (i = 0; i < psbt->num_outputs; ++i) { struct wally_psbt_output *output = &psbt->outputs[i]; From 8aa08b030f42730ef6a5b15dedc95ad8fabd4153 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:55 +0930 Subject: [PATCH 063/205] psbt: make output_to_bytes use push. Signed-off-by: Rusty Russell --- src/psbt.c | 68 ++++++++++++++---------------------------------------- 1 file changed, 17 insertions(+), 51 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 5aae8625a..f7d3b464b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2002,77 +2002,44 @@ static int push_psbt_input( return WALLY_OK; } -static int psbt_output_to_bytes( - const struct wally_psbt_output *output, - unsigned char *bytes_out, - size_t *bytes_written) +static int push_psbt_output( + unsigned char **cursor, size_t *max, + const struct wally_psbt_output *output) { - unsigned char type, *p = bytes_out; size_t i; /* Redeem script */ if (output->redeem_script) { - type = WALLY_PSBT_OUT_REDEEM_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(output->redeem_script, output->redeem_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_OUT_REDEEM_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + output->redeem_script, output->redeem_script_len); } /* Witness script */ if (output->witness_script) { - type = WALLY_PSBT_OUT_WITNESS_SCRIPT; - p += varbuff_to_bytes(&type, 1, p); - p += varbuff_to_bytes(output->witness_script, output->witness_script_len, p); + push_psbt_key(cursor, max, WALLY_PSBT_OUT_WITNESS_SCRIPT, NULL, 0); + push_varbuff(cursor, max, + output->witness_script, output->witness_script_len); } /* Keypaths */ if (output->keypaths) { struct wally_keypath_map *keypaths = output->keypaths; for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len, j; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - p += varint_to_bytes(34, p); - *p = WALLY_PSBT_OUT_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_LEN); - p += EC_PUBLIC_KEY_LEN; - } else { - p += varint_to_bytes(66, p); - *p = WALLY_PSBT_OUT_BIP32_DERIVATION; - p++; - memcpy(p, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - p += EC_PUBLIC_KEY_UNCOMPRESSED_LEN; - } - - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - p += varint_to_bytes(origin_len, p); - - memcpy(p, item->origin.fingerprint, 4); - p += 4; - for (j = 0; j < item->origin.path_len; ++j) { - memcpy(p, &item->origin.path[j], sizeof(uint32_t)); - p += 4; - } + push_keypath_item(cursor, max, + WALLY_PSBT_OUT_BIP32_DERIVATION, + &keypaths->items[i]); } } /* Unknowns */ if (output->unknowns) { for (i = 0; i < output->unknowns->num_items; ++i) { struct wally_unknowns_item *unknown = &output->unknowns->items[i]; - p += varint_to_bytes(unknown->key_len, p); - memcpy(p, unknown->key, unknown->key_len); - p += unknown->key_len; - p += varint_to_bytes(unknown->value_len, p); - memcpy(p, unknown->value, unknown->value_len); - p += unknown->value_len; + push_varbuff(cursor, max, unknown->key, unknown->key_len); + push_varbuff(cursor, max, unknown->value, unknown->value_len); } } /* Separator */ - *p = WALLY_PSBT_SEPARATOR; - p++; - - *bytes_written = p - bytes_out; - + push_u8(cursor, max, WALLY_PSBT_SEPARATOR); return WALLY_OK; } @@ -2143,12 +2110,11 @@ int wally_psbt_to_bytes( } for (i = 0; i < psbt->num_outputs; ++i) { struct wally_psbt_output *output = &psbt->outputs[i]; - size_t output_len; - ret = psbt_output_to_bytes(output, p, &output_len); + size_t max = end - p; + ret = push_psbt_output(&p, &max, output); if (ret != WALLY_OK) { return ret; } - p += output_len; } *bytes_written = p - bytes_out; return WALLY_OK; From 274de274f6a77f06d081ac14ebd4f9b97f4807d9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:56 +0930 Subject: [PATCH 064/205] wally_psbt: make wally_psbt_to_bytes use push itself. As a special bonus, document that it now returns bytes_written as the entire length, if the error was caused by bytes_len being insufficient. This allows the caller to avoid calling bytes_len in the common case, if they want to. Signed-off-by: Rusty Russell --- include/wally_psbt.h | 7 +++-- src/psbt.c | 65 +++++++++++++++----------------------------- 2 files changed, 27 insertions(+), 45 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index d7a88395a..beff22380 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -524,13 +524,16 @@ WALLY_CORE_API int wally_psbt_get_length( * :param psbt: the PSBT to serialize. * :param bytes_out: Bytes to create the transaction from. * :param bytes_len: Length of ``bytes`` in bytes (use `wally_psbt_get_length`). - * :param bytes_written: number of bytes written to bytes_out. + * :param written: number of bytes written to bytes_out. + * + * If @bytes_len is insufficient, this will return WALLY_EINVAL, but + * @written will be filled in the the amount which would be required. */ WALLY_CORE_API int wally_psbt_to_bytes( const struct wally_psbt *psbt, unsigned char *bytes_out, size_t bytes_len, - size_t *bytes_written); + size_t *written); /** * Create a PSBT from its serialized base64 string. diff --git a/src/psbt.c b/src/psbt.c index f7d3b464b..3aa88a2b4 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2046,77 +2046,56 @@ static int push_psbt_output( int wally_psbt_to_bytes( const struct wally_psbt *psbt, unsigned char *bytes_out, size_t len, - size_t *bytes_written) + size_t *written) { - unsigned char type, *p = bytes_out, *end = bytes_out + len; - size_t calc_len, tx_len, i; + unsigned char *cursor = bytes_out; + size_t max = len, i; int ret; - if (bytes_written) { - *bytes_written = 0; - } - - ret = wally_psbt_get_length(psbt, &calc_len); - if (ret != WALLY_OK) { - return ret; - } - if (calc_len > len) { - return WALLY_EINVAL; /* Buffer is not big enough */ - } + *written = 0; - /* Magic */ - memcpy(p, WALLY_PSBT_MAGIC, 5); - p += 5; + push_bytes(&cursor, &max, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)); /* Global tx */ - type = WALLY_PSBT_GLOBAL_UNSIGNED_TX; - p += varbuff_to_bytes(&type, 1, p); - ret = wally_tx_get_length(psbt->tx, 0, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - p += varint_to_bytes(tx_len, p); - ret = wally_tx_to_bytes(psbt->tx, 0, p, end - p, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - p += tx_len; + push_psbt_key(&cursor, &max, WALLY_PSBT_GLOBAL_UNSIGNED_TX, NULL, 0); + push_length_and_tx(&cursor, &max, psbt->tx, 0); /* Unknowns */ if (psbt->unknowns) { for (i = 0; i < psbt->unknowns->num_items; ++i) { struct wally_unknowns_item *unknown = &psbt->unknowns->items[i]; - p += varint_to_bytes(unknown->key_len, p); - memcpy(p, unknown->key, unknown->key_len); - p += unknown->key_len; - p += varint_to_bytes(unknown->value_len, p); - memcpy(p, unknown->value, unknown->value_len); - p += unknown->value_len; + push_varbuff(&cursor, &max, unknown->key, unknown->key_len); + push_varbuff(&cursor, &max, unknown->value, unknown->value_len); } } /* Separator */ - *p = WALLY_PSBT_SEPARATOR; - p++; + push_u8(&cursor, &max, WALLY_PSBT_SEPARATOR); - /* Get lengths of each input and output */ + /* Push each input and output */ for (i = 0; i < psbt->num_inputs; ++i) { struct wally_psbt_input *input = &psbt->inputs[i]; - size_t max = end - p; - ret = push_psbt_input(&p, &max, input); + ret = push_psbt_input(&cursor, &max, input); if (ret != WALLY_OK) { return ret; } } for (i = 0; i < psbt->num_outputs; ++i) { struct wally_psbt_output *output = &psbt->outputs[i]; - size_t max = end - p; - ret = push_psbt_output(&p, &max, output); + ret = push_psbt_output(&cursor, &max, output); if (ret != WALLY_OK) { return ret; } } - *bytes_written = p - bytes_out; + + if (cursor == NULL) { + /* Once cursor was NULL, max accumulates hm bytes we needed */ + *written = len + max; + return WALLY_EINVAL; + } else { + *written = len - max; + } + return WALLY_OK; } From 372b70b8ca6bf5389169020aaa59037ffd84decf Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:56 +0930 Subject: [PATCH 065/205] psbt: make psbt_input_get_length use the same code as psbt_input_to_bytes. This avoid (recently buggy!) duplication. Signed-off-by: Rusty Russell --- src/psbt.c | 217 +---------------------------------------------------- 1 file changed, 4 insertions(+), 213 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 3aa88a2b4..52c5e04ad 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1594,226 +1594,17 @@ int wally_psbt_from_bytes( return ret; } -static int psbt_input_get_length( - const struct wally_psbt_input *input, - size_t *len) -{ - int ret; - size_t out, tx_len, i; - if (!len) { - return WALLY_EINVAL; - } - - *len = 0; - out = 0; - - /* Non witness utxo */ - if (input->non_witness_utxo) { - out += 2; /* Key len and one byte type */ - ret = wally_tx_get_length(input->non_witness_utxo, WALLY_TX_FLAG_USE_WITNESS, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - out += varbuff_get_length(tx_len); - } - /* Witness utxo */ - if (input->witness_utxo) { - size_t wit_size = 0; - out += 2; /* Key len and one byte type */ - wit_size += sizeof(input->witness_utxo->satoshi); - wit_size += varbuff_get_length(input->witness_utxo->script_len); - out += varbuff_get_length(wit_size); - } - /* Partial sigs */ - if (input->partial_sigs) { - struct wally_partial_sigs_map *partial_sigs = input->partial_sigs; - for (i = 0; i < partial_sigs->num_items; ++i) { - struct wally_partial_sigs_item *item = &partial_sigs->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - out += varint_get_length(34); - out += 34; /* Compressed pubkey + 1 byte type */ - } else { - out += varint_get_length(66); - out += 66; /* Uncompressed pubkey + 1 byte type */ - } - out += varbuff_get_length(item->sig_len); - } - } - /* Sighash type */ - if (input->sighash_type > 0) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(sizeof(input->sighash_type)); - } - /* Redeem script */ - if (input->redeem_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(input->redeem_script_len); - } - /* Witness script */ - if (input->witness_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(input->witness_script_len); - } - /* Keypaths */ - if (input->keypaths) { - struct wally_keypath_map *keypaths = input->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - out += varint_get_length(34); - out += 34; /* Compressed pubkey + 1 byte type */ - } else { - out += varint_get_length(66); - out += 66; /* Uncompressed pubkey + 1 byte type */ - } - - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - out += varint_get_length(origin_len); - out += origin_len; - } - } - /* Final scriptSig */ - if (input->final_script_sig) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(input->final_script_sig_len); - } - /* Final scriptWitness */ - if (input->final_witness) { - struct wally_tx_witness_stack *witness = input->final_witness; - size_t wit_len = varint_get_length(witness->num_items); - out += 2; /* Key len and one byte type */ - out += varint_get_length(witness->num_items); - for (i = 0; i < witness->num_items; ++i) { - out += varbuff_get_length(witness->items[i].witness_len); - wit_len += varbuff_get_length(witness->items[i].witness_len); - } - out += varint_get_length(wit_len); - } - /* Unknowns */ - if (input->unknowns) { - for (i = 0; i < input->unknowns->num_items; ++i) { - struct wally_unknowns_item *unknown = &input->unknowns->items[i]; - out += varbuff_get_length(unknown->key_len); - out += varbuff_get_length(unknown->value_len); - } - } - - /* Separator */ - out += 1; - - *len = out; - return WALLY_OK; -} - -static int psbt_output_get_length( - const struct wally_psbt_output *output, - size_t *len) -{ - size_t out, i; - if (!len) { - return WALLY_EINVAL; - } - - *len = 0; - out = 0; - - /* Redeem script */ - if (output->redeem_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(output->redeem_script_len); - } - /* Witness script */ - if (output->witness_script) { - out += 2; /* Key len and one byte type */ - out += varbuff_get_length(output->witness_script_len); - } - /* Keypaths */ - if (output->keypaths) { - struct wally_keypath_map *keypaths = output->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { - size_t origin_len; - struct wally_keypath_item *item = &keypaths->items[i]; - if (pubkey_is_compressed(item->pubkey)) { - out += varint_get_length(34); - out += 34; /* Compressed pubkey + 1 byte type */ - } else { - out += varint_get_length(66); - out += 66; /* Uncompressed pubkey + 1 byte type */ - } - - origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); - out += varint_get_length(origin_len); - out += origin_len; - } - } - /* Unknowns */ - if (output->unknowns) { - for (i = 0; i < output->unknowns->num_items; ++i) { - struct wally_unknowns_item *unknown = &output->unknowns->items[i]; - out += varbuff_get_length(unknown->key_len); - out += varbuff_get_length(unknown->value_len); - } - } - - /* Separator */ - out += 1; - - *len = out; - return WALLY_OK; -} - int wally_psbt_get_length( const struct wally_psbt *psbt, size_t *written) { int ret; - size_t out, tx_len, i; - if (!written) { - return WALLY_EINVAL; - } - - *written = 0; - out = 5; /* Start with 5 byte magic */ - /* Global tx */ - out += 2; - ret = wally_tx_get_length(psbt->tx, 0, &tx_len); - if (ret != WALLY_OK) { - return ret; - } - out += varbuff_get_length(tx_len); - - /* Global unknowns */ - if (psbt->unknowns) { - for (i = 0; i < psbt->unknowns->num_items; ++i) { - struct wally_unknowns_item *unknown = &psbt->unknowns->items[i]; - out += varbuff_get_length(unknown->key_len); - out += varbuff_get_length(unknown->value_len); - } - } - - /* Separator */ - out += 1; - - /* Get lengths of each input and output */ - for (i = 0; i < psbt->num_inputs; ++i) { - struct wally_psbt_input *input = &psbt->inputs[i]; - size_t input_len; - psbt_input_get_length(input, &input_len); - out += input_len; - } - for (i = 0; i < psbt->num_outputs; ++i) { - struct wally_psbt_output *output = &psbt->outputs[i]; - size_t output_len; - psbt_output_get_length(output, &output_len); - out += output_len; + ret = wally_psbt_to_bytes(psbt, NULL, 0, written); + if (ret == WALLY_EINVAL && *written != 0) { + return WALLY_OK; } - - *written = out; - return WALLY_OK; + return ret; } /* Literally a varbuff containing only type as a varint, then optional data */ From 87293c67a59225c7ff58a9d93e5024e042f8009a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:56 +0930 Subject: [PATCH 066/205] psbt: use pull_ functions to parse input section. Signed-off-by: Rusty Russell --- src/psbt.c | 383 +++++++++++++++++++++++++++++++++-------------------- 1 file changed, 236 insertions(+), 147 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 52c5e04ad..997f9d569 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -8,6 +8,7 @@ #include #include +#include #include "transaction_shared.h" #include "script_int.h" #include "script.h" @@ -833,6 +834,126 @@ int wally_psbt_set_global_tx( return ret; } +/* Returns false if it hits a zero length "key" (i.e. separator) or EOF. + * + * Otherwise, starts the subfield (extra, extra_len), so caller should + * call pull_subfield_end(cursor, max, extra, extra_len) if this + * returns true. + */ +static bool pull_psbt_key_start( + const unsigned char **cursor, size_t *max, + uint64_t *type, + const unsigned char **extra, size_t *extra_len) +{ + size_t key_len; + + key_len = pull_varlength(cursor, max); + /* This incidentally covers the case where *cursor is NULL */ + if (key_len == 0) { + return false; + } + pull_subfield_start(cursor, max, key_len, extra, extra_len); + *type = pull_varint(cursor, max); + return true; +} + +/* clones varlength field entirely. */ +static bool clone_varlength(unsigned char **dst, + size_t *len, + const unsigned char **cursor, size_t *max) +{ + *len = pull_varlength(cursor, max); + return clone_bytes(dst, pull_skip(cursor, max, *len), *len); +} + +/* Stricter version of pull_subfield_end which insists there's nothing left. */ +static void subfield_nomore_end(const unsigned char **cursor, size_t *max, + const unsigned char *subcursor, + const size_t submax) +{ + if (submax) { + pull_failed(cursor, max); + } else { + pull_subfield_end(cursor, max, subcursor, submax); + } +} + +/* The remainder of the key is a public key, the value is a keypath */ +static int pull_keypath(const unsigned char **cursor, size_t *max, + const unsigned char *key, size_t key_len, + struct wally_keypath_map *keypaths) +{ + const unsigned char *val; + size_t i, val_max; + struct wally_keypath_item *kpitem; + + if (key_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN + && key_len != EC_PUBLIC_KEY_LEN) { + return WALLY_EINVAL; /* Size of key is unexpected */ + } + + /* Check for duplicates */ + for (i = 0; i < keypaths->num_items; ++i) { + if (memcmp(keypaths->items[i].pubkey, key, key_len) == 0) { + return WALLY_EINVAL; /* Duplicate key */ + } + } + + assert(keypaths->num_items < keypaths->items_allocation_len); + kpitem = &keypaths->items[keypaths->num_items++]; + + memcpy(kpitem->pubkey, key, key_len); + pull_subfield_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); + + /* Read the fingerprint */ + pull_bytes(kpitem->origin.fingerprint, sizeof(kpitem->origin.fingerprint), + &val, &val_max); + + /* Remainder is the path */ + kpitem->origin.path_len = val_max / sizeof(uint32_t); + kpitem->origin.path = wally_malloc(val_max); + if (kpitem->origin.path == NULL) { + return WALLY_ENOMEM; + } + for (i = 0; val_max >= sizeof(uint32_t); ++i) { + kpitem->origin.path[i] = pull_le32(&val, &val_max); + } + subfield_nomore_end(cursor, max, val, val_max); + return WALLY_OK; +} + +/* Rewind cursor to prekey, and append unknown key/value to unknowns */ +static int pull_unknown_key_value(const unsigned char **cursor, + size_t *max, + const unsigned char *pre_key, + struct wally_unknowns_map *unknowns) +{ + struct wally_unknowns_item *item; + + /* If we've already failed, it's invalid */ + if (!*cursor) { + return WALLY_EINVAL; + } + + /* We have to unwind a bit, to get entire key again. */ + *max += (*cursor - pre_key); + *cursor = pre_key; + + assert(unknowns->num_items < unknowns->items_allocation_len); + item = &unknowns->items[unknowns->num_items++]; + + if (!clone_varlength(&item->key, &item->key_len, cursor, max)) { + return WALLY_ENOMEM; + } + if (!clone_varlength(&item->value, &item->value_len, cursor, max)) { + return WALLY_ENOMEM; + } + return WALLY_OK; +} + struct psbt_input_counts { size_t num_unknowns; size_t num_keypaths; @@ -1044,19 +1165,15 @@ static int count_psbt_parts( return ret; } -static int psbt_input_from_bytes( - const unsigned char *bytes, - size_t bytes_len, +static int pull_psbt_input( + const unsigned char **cursor, + size_t *max, struct psbt_input_counts counts, - size_t *bytes_read, struct wally_psbt_input *result) { - const unsigned char *p = bytes, *end = bytes + bytes_len, *key, *value; - uint64_t key_len, value_len; - uint8_t type; - int ret = WALLY_OK; - size_t i, vl; - bool found_sep = false; + int ret; + size_t key_len; + const unsigned char *pre_key; /* Init and alloc the maps */ if (counts.num_keypaths > 0) { @@ -1076,223 +1193,191 @@ static int psbt_input_from_bytes( } /* Read key value pairs */ - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - - if (key_len == 0) { - found_sep = true; - break; - } - - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + pre_key = *cursor; + while ((key_len = pull_varlength(cursor, max)) != 0) { + const unsigned char *key, *val; + size_t val_max; - /* Pre-read the value length but don't increment for a sanity check */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) + /* Start parsing key */ + pull_subfield_start(cursor, max, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_IN_NON_WITNESS_UTXO: { if (result->non_witness_utxo) { return WALLY_EINVAL; /* We already have a non witness utxo */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Global tx key is one byte type */ } - p += varint_from_bytes(p, &value_len); - value = p; - wally_tx_from_bytes(value, value_len, 0, &result->non_witness_utxo); - p += value_len; + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + + ret = wally_tx_from_bytes(val, val_max, 0, + &result->non_witness_utxo); + if (ret != WALLY_OK) { + return ret; + } + pull_subfield_end(cursor, max, val, val_max); break; } case WALLY_PSBT_IN_WITNESS_UTXO: { - uint64_t amount = -1, script_len; - size_t script_len_len; + uint64_t amount, script_len; + const unsigned char *script; if (result->witness_utxo) { return WALLY_EINVAL; /* We already have a witness utxo */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Global tx key is one byte type */ } - p += varint_from_bytes(p, &value_len); - p += uint64_from_le_bytes(p, &amount); - script_len_len = varint_from_bytes(p, &script_len); - p += script_len_len; - ret = wally_tx_output_init_alloc(amount, p, script_len, &result->witness_utxo); + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + amount = pull_le64(&val, &val_max); + script_len = pull_varint(&val, &val_max); + script = pull_skip(&val, &val_max, script_len); + if (!script) { + return WALLY_EINVAL; + } + ret = wally_tx_output_init_alloc(amount, script, script_len, + &result->witness_utxo); if (ret != WALLY_OK) { return ret; } - p += script_len; - /* amount length (8 bytes) + script CSUint + script length = value length */ - if (8 + script_len_len + script_len != value_len) { - return WALLY_EINVAL; - } + subfield_nomore_end(cursor, max, val, val_max); break; } case WALLY_PSBT_IN_PARTIAL_SIG: { + size_t i; + struct wally_partial_sigs_item *sigitem; struct wally_partial_sigs_map *partial_sigs = result->partial_sigs; - if (key_len != 66 && key_len != 34) { + if (key_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN + && key_len != EC_PUBLIC_KEY_LEN) { return WALLY_EINVAL; /* Size of key is unexpected */ } /* Check for duplicates */ for (i = 0; i < partial_sigs->num_items; ++i) { - if (memcmp(partial_sigs->items[i].pubkey, &key[1], key_len - 1) == 0) { + if (memcmp(partial_sigs->items[i].pubkey, key, key_len) == 0) { return WALLY_EINVAL; /* Duplicate key */ } } - memcpy(partial_sigs->items[partial_sigs->num_items].pubkey, &key[1], key_len - 1); - - /* Read the signature */ - p += varint_from_bytes(p, &value_len); - clone_bytes(&partial_sigs->items[partial_sigs->num_items].sig, p, value_len); - partial_sigs->items[partial_sigs->num_items].sig_len = value_len; + sigitem = &partial_sigs->items[partial_sigs->num_items]; + memcpy(sigitem->pubkey, key, key_len); + pull_subfield_end(cursor, max, key, key_len); + if (!clone_varlength(&sigitem->sig, &sigitem->sig_len, + cursor, max)) { + return WALLY_ENOMEM; + } partial_sigs->num_items++; - p += value_len; break; } case WALLY_PSBT_IN_SIGHASH_TYPE: { if (result->sighash_type > 0) { return WALLY_EINVAL; /* Sighash already provided */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ } - p += varint_from_bytes(p, &value_len); - p += uint32_from_le_bytes(p, &result->sighash_type); + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + result->sighash_type = pull_le32(&val, &val_max); + subfield_nomore_end(cursor, max, val, val_max); break; } case WALLY_PSBT_IN_REDEEM_SCRIPT: { if (result->redeem_script_len != 0) { return WALLY_EINVAL; /* Already have a redeem script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->redeem_script, p, value_len); - result->redeem_script_len = value_len; + subfield_nomore_end(cursor, max, key, key_len); - p += value_len; + if (!clone_varlength(&result->redeem_script, + &result->redeem_script_len, + cursor, max)) { + return WALLY_ENOMEM; + } break; } case WALLY_PSBT_IN_WITNESS_SCRIPT: { if (result->witness_script_len != 0) { return WALLY_EINVAL; /* Already have a witness script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->witness_script, p, value_len); - result->witness_script_len = value_len; + subfield_nomore_end(cursor, max, key, key_len); - p += value_len; + if (!clone_varlength(&result->witness_script, + &result->witness_script_len, + cursor, max)) { + return WALLY_ENOMEM; + } break; } case WALLY_PSBT_IN_BIP32_DERIVATION: { - struct wally_keypath_map *keypaths = result->keypaths; - size_t path_len; - if (key_len != 66 && key_len != 34) { - return WALLY_EINVAL; /* Size of key is unexpected */ - } - /* Check for duplicates */ - for (i = 0; i < keypaths->num_items; ++i) { - if (memcmp(keypaths->items[i].pubkey, &key[1], key_len - 1) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } - - memcpy(keypaths->items[keypaths->num_items].pubkey, &key[1], key_len - 1); - - /* Read the path length */ - p += varint_from_bytes(p, &value_len); - if (value_len % 4 != 0 || value_len == 0) { - return WALLY_EINVAL; /* Invalid length for keypaths */ - } - path_len = (value_len / 4) - 1; - - /* Read the fingerprint */ - memcpy(keypaths->items[keypaths->num_items].origin.fingerprint, p, 4); - p += 4; - - /* Read the path itself */ - keypaths->items[keypaths->num_items].origin.path = wally_malloc(path_len * sizeof(uint32_t)); - if (!keypaths->items[keypaths->num_items].origin.path) { - return WALLY_ENOMEM; - } - for (i = 0; i < path_len; ++i) { - p += uint32_from_le_bytes(p, &keypaths->items[keypaths->num_items].origin.path[i]); + ret = pull_keypath(cursor, max, key, key_len, result->keypaths); + if (ret != WALLY_OK) { + return ret; } - keypaths->items[keypaths->num_items].origin.path_len = path_len; - - keypaths->num_items++; break; } case WALLY_PSBT_IN_FINAL_SCRIPTSIG: { if (result->final_script_sig_len != 0) { return WALLY_EINVAL; /* Already have a scriptSig */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->final_script_sig, p, value_len); - result->final_script_sig_len = value_len; + subfield_nomore_end(cursor, max, key, key_len); - p += value_len; + if (!clone_varlength(&result->final_script_sig, + &result->final_script_sig_len, + cursor, max)) { + return WALLY_ENOMEM; + } break; } case WALLY_PSBT_IN_FINAL_SCRIPTWITNESS: { uint64_t num_witnesses; + size_t i; if (result->final_witness) { return WALLY_EINVAL; /* Already have a scriptWitness */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ } - p += varint_from_bytes(p, &value_len); - p += varint_from_bytes(p, &num_witnesses); + subfield_nomore_end(cursor, max, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + num_witnesses = pull_varint(&val, &val_max); ret = wally_tx_witness_stack_init_alloc(num_witnesses, &result->final_witness); if (ret != WALLY_OK) { return ret; } for (i = 0; i < num_witnesses; ++i) { - uint64_t witness_len; - p += varint_from_bytes(p, &witness_len); - ret = wally_tx_witness_stack_set(result->final_witness, i, p, witness_len); - if (ret != WALLY_OK) + uint64_t witness_len = pull_varint(&val, &val_max); + ret = wally_tx_witness_stack_set(result->final_witness, i, + pull_skip(&val, &val_max, witness_len), + witness_len); + if (ret != WALLY_OK) { return ret; - p += witness_len; + } } + subfield_nomore_end(cursor, max, val, val_max); break; } /* Unknowns */ default: { - struct wally_unknowns_map *unknowns = result->unknowns; - clone_bytes(&unknowns->items[unknowns->num_items].key, key, key_len); - unknowns->items[unknowns->num_items].key_len = key_len; - - p += varint_from_bytes(p, &value_len); - value = p; - clone_bytes(&unknowns->items[unknowns->num_items].value, value, value_len); - unknowns->items[unknowns->num_items].value_len = value_len; - - unknowns->num_items++; - p += value_len; + ret = pull_unknown_key_value(cursor, max, pre_key, result->unknowns); + if (ret != WALLY_OK) { + return ret; + } break; } } - } + pre_key = *cursor; - if (!found_sep) { - return WALLY_EINVAL; } - *bytes_read = p - bytes; -fail: - return ret; + return WALLY_OK; } static int psbt_output_from_bytes( @@ -1549,15 +1634,19 @@ int wally_psbt_from_bytes( } /* Read inputs */ - for (i = 0; i < counts->num_inputs && p < end; ++i) { - size_t bytes_read; - - ret = psbt_input_from_bytes(p, end - p, counts->input_counts[i], &bytes_read, &result->inputs[i]); + for (i = 0; i < counts->num_inputs; ++i) { + size_t max = end - p; + ret = pull_psbt_input(&p, &max, counts->input_counts[i], + &result->inputs[i]); + /* Increment this now, might be partially initialized! */ + result->num_inputs++; if (ret != WALLY_OK) { goto fail; } - p += bytes_read; - result->num_inputs++; + if (p == NULL) { + ret = WALLY_EINVAL; + goto fail; + } } /* Make sure that the number of inputs matches the number of inputs in the transaction */ From 6c055c1ebde12b5d1c19dbdb2b8ff422df5c95b6 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:56 +0930 Subject: [PATCH 067/205] psbt: use pull_ functions to parse output section. Signed-off-by: Rusty Russell --- src/psbt.c | 144 ++++++++++++++++------------------------------------- 1 file changed, 43 insertions(+), 101 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 997f9d569..a49367cc1 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1380,19 +1380,15 @@ static int pull_psbt_input( return WALLY_OK; } -static int psbt_output_from_bytes( - const unsigned char *bytes, - size_t bytes_len, +static int pull_psbt_output( + const unsigned char **cursor, + size_t *max, struct psbt_output_counts counts, - size_t *bytes_read, struct wally_psbt_output *result) { - const unsigned char *p = bytes, *end = bytes + bytes_len, *key, *value; - uint64_t key_len, value_len; - uint8_t type; - size_t i, vl; - bool found_sep = false; - int ret = WALLY_OK; + int ret; + size_t key_len; + const unsigned char *pre_key; /* Init and alloc the maps */ if (counts.num_keypaths > 0) { @@ -1402,119 +1398,62 @@ static int psbt_output_from_bytes( wally_unknowns_map_init_alloc(counts.num_unknowns, &result->unknowns); } - /* Read key value pairs */ - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - - if (key_len == 0) { - found_sep = true; - break; - } - - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + /* Read key value */ + pre_key = *cursor; + while ((key_len = pull_varlength(cursor, max)) != 0) { + const unsigned char *key; - /* Pre-read the value length but don't increment for a sanity check */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) + /* Start parsing key */ + pull_subfield_start(cursor, max, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_OUT_REDEEM_SCRIPT: { if (result->redeem_script_len != 0) { return WALLY_EINVAL; /* Already have a redeem script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->redeem_script, p, value_len); - result->redeem_script_len = value_len; + subfield_nomore_end(cursor, max, key, key_len); - p += value_len; + if (!clone_varlength(&result->redeem_script, + &result->redeem_script_len, + cursor, max)) { + return WALLY_ENOMEM; + } break; } case WALLY_PSBT_OUT_WITNESS_SCRIPT: { if (result->witness_script_len != 0) { return WALLY_EINVAL; /* Already have a witness script */ - } else if (key_len != 1) { - return WALLY_EINVAL; /* Type is more than one byte */ } - p += varint_from_bytes(p, &value_len); - clone_bytes(&result->witness_script, p, value_len); - result->witness_script_len = value_len; + subfield_nomore_end(cursor, max, key, key_len); - p += value_len; + if (!clone_varlength(&result->witness_script, + &result->witness_script_len, + cursor, max)) { + return WALLY_ENOMEM; + } break; } case WALLY_PSBT_OUT_BIP32_DERIVATION: { - struct wally_keypath_map *keypaths = result->keypaths; - size_t path_len; - if (key_len != 66 && key_len != 34) { - return WALLY_EINVAL; /* Size of key is unexpected */ - } - /* Check for duplicates */ - for (i = 0; i < keypaths->num_items; ++i) { - if (memcmp(keypaths->items[i].pubkey, &key[1], key_len - 1) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } - - memcpy(keypaths->items[keypaths->num_items].pubkey, &key[1], key_len - 1); - - /* Read the path length */ - p += varint_from_bytes(p, &value_len); - if (value_len % 4 != 0 || value_len == 0) { - return WALLY_EINVAL; /* Invalid length for keypaths */ - } - path_len = (value_len / 4) - 1; - - /* Read the fingerprint */ - memcpy(keypaths->items[keypaths->num_items].origin.fingerprint, p, 4); - p += 4; - - /* Read the path itself */ - keypaths->items[keypaths->num_items].origin.path = wally_malloc(path_len * sizeof(uint32_t)); - if (!keypaths->items[keypaths->num_items].origin.path) { - return WALLY_ENOMEM; - } - for (i = 0; i < path_len; ++i) { - p += uint32_from_le_bytes(p, &keypaths->items[keypaths->num_items].origin.path[i]); + ret = pull_keypath(cursor, max, key, key_len, result->keypaths); + if (ret != WALLY_OK) { + return ret; } - keypaths->items[keypaths->num_items].origin.path_len = path_len; - - keypaths->num_items++; break; } /* Unknowns */ default: { - struct wally_unknowns_map *unknowns = result->unknowns; - clone_bytes(&unknowns->items[unknowns->num_items].key, key, key_len); - unknowns->items[unknowns->num_items].key_len = key_len; - - p += varint_from_bytes(p, &value_len); - value = p; - clone_bytes(&unknowns->items[unknowns->num_items].value, value, value_len); - unknowns->items[unknowns->num_items].value_len = value_len; - - unknowns->num_items++; - p += value_len; + ret = pull_unknown_key_value(cursor, max, pre_key, result->unknowns); + if (ret != WALLY_OK) { + return ret; + } break; } } + pre_key = *cursor; } - if (!found_sep) { - return WALLY_EINVAL; - } - - *bytes_read = p - bytes; -fail: - return ret; + return WALLY_OK; } int wally_psbt_from_bytes( @@ -1656,15 +1595,18 @@ int wally_psbt_from_bytes( } /* Read outputs */ - for (i = 0; i < counts->num_outputs && p < end; ++i) { - size_t bytes_read; - - ret = psbt_output_from_bytes(p, end - p, counts->output_counts[i], &bytes_read, &result->outputs[i]); + for (i = 0; i < counts->num_outputs; ++i) { + size_t max = end - p; + ret = pull_psbt_output(&p, &max, counts->output_counts[i], + &result->outputs[i]); + result->num_outputs++; if (ret != WALLY_OK) { goto fail; } - p += bytes_read; - result->num_outputs++; + if (p == NULL) { + ret = WALLY_EINVAL; + goto fail; + } } /* Make sure that the number of outputs matches the number ot outputs in the transaction */ From 155c6eb6a12eb4aacc83545ef5e1b6b9d9555597 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:56 +0930 Subject: [PATCH 068/205] psbt: convert count_psbt_parts to use pull_ code. Signed-off-by: Rusty Russell --- src/psbt.c | 118 +++++++++++++++++++---------------------------------- 1 file changed, 43 insertions(+), 75 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index a49367cc1..342f767a8 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -993,13 +993,9 @@ static int count_psbt_parts( size_t bytes_len, struct psbt_counts **output) { + int ret; + size_t i, key_len; struct psbt_counts *result; - size_t i, vl; - const unsigned char *key; - uint64_t key_len, value_len; - uint8_t type; - int ret = WALLY_OK; - const unsigned char *p = bytes, *end = bytes + bytes_len; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct psbt_counts); @@ -1009,38 +1005,34 @@ static int count_psbt_parts( result->num_outputs = 0; /* Skip the magic */ - CHECK_BUF_BOUNDS(p, (size_t)5, bytes, bytes_len) - p += 5; + pull_skip(&bytes, &bytes_len, sizeof(WALLY_PSBT_MAGIC)); /* Go through globals and count */ - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - - if (key_len == 0) { - break; - } - - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { + const unsigned char *key; - /* Read value length */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) - p += vl; + /* Start parsing key */ + pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_GLOBAL_UNSIGNED_TX: { bool expect_wit; - if (analyze_tx(p, value_len, 0, &result->num_inputs, &result->num_outputs, &expect_wit) != WALLY_OK) { + const unsigned char *val; + size_t val_max; + subfield_nomore_end(&bytes, &bytes_len, key, key_len); + + /* Value should be a tx */ + val_max = pull_varint(&bytes, &bytes_len); + val = pull_skip(&bytes, &bytes_len, val_max); + if (!val) { ret = WALLY_EINVAL; goto fail; } + ret = analyze_tx(val, val_max, 0, &result->num_inputs, &result->num_outputs, &expect_wit); + if (ret != WALLY_OK) { + goto fail; + } if ((result->input_counts = wally_malloc(result->num_inputs * sizeof(struct psbt_input_counts))) == NULL || (result->output_counts = wally_malloc(result->num_outputs * sizeof(struct psbt_output_counts))) == NULL) { ret = WALLY_ENOMEM; @@ -1051,40 +1043,27 @@ static int count_psbt_parts( /* Unknowns */ default: result->num_global_unknowns++; + pull_subfield_end(&bytes, &bytes_len, key, key_len); + /* Skip over value */ + pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); } - - /* Increment past value length */ - p += value_len; } /* Go through each input */ - for (i = 0; i < result->num_inputs && p < end; ++i) { + for (i = 0; i < result->num_inputs; ++i) { struct psbt_input_counts *input = &result->input_counts[i]; input->num_keypaths = 0; input->num_partial_sigs = 0; input->num_unknowns = 0; - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - if (key_len == 0) { - break; - } + while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { + const unsigned char *key; - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; - - /* Read value length */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) - p += vl; + /* Start parsing key */ + pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_IN_NON_WITNESS_UTXO: case WALLY_PSBT_IN_WITNESS_UTXO: case WALLY_PSBT_IN_SIGHASH_TYPE: @@ -1103,39 +1082,26 @@ static int count_psbt_parts( default: input->num_unknowns++; } - - /* Increment past value length */ - p += value_len; + pull_subfield_end(&bytes, &bytes_len, key, key_len); + /* Skip over value */ + pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); } } /* Go through each output */ - for (i = 0; i < result->num_outputs && p < end; ++i) { + for (i = 0; i < result->num_outputs; ++i) { struct psbt_output_counts *psbt_output = &result->output_counts[i]; psbt_output->num_keypaths = 0; psbt_output->num_unknowns = 0; - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - if (key_len == 0) { - break; - } + while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { + const unsigned char *key; - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; - - /* Read value length */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) - p += vl; + /* Start parsing key */ + pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_OUT_REDEEM_SCRIPT: case WALLY_PSBT_OUT_WITNESS_SCRIPT: break; @@ -1147,12 +1113,14 @@ static int count_psbt_parts( psbt_output->num_unknowns++; } - /* Increment past value length */ - p += value_len; + pull_subfield_end(&bytes, &bytes_len, key, key_len); + /* Skip over value */ + pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); } } - if (p != end) { + /* Either we ran short, or had too much? */ + if (bytes == NULL || bytes_len != 0) { ret = WALLY_EINVAL; goto fail; } From c3a424f7a8e4b2e9a6aa1feed9a411ba9b7badb4 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:56 +0930 Subject: [PATCH 069/205] psbt: convert wally_psbt_from_bytes to use pull_code. Now we pull the magic before calling count_psbt_parts(), it no longer needs to skip over it. Signed-off-by: Rusty Russell --- src/psbt.c | 112 ++++++++++++++++++----------------------------------- 1 file changed, 37 insertions(+), 75 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 342f767a8..5f6d0c2c3 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -982,12 +982,6 @@ static void free_psbt_count(struct psbt_counts *counts) } } -/* Check that the bytes already read + bytes to be read < total len */ -#define CHECK_BUF_BOUNDS(p, i, begin, tl) if ((p - begin) + i > tl) { \ - ret = WALLY_EINVAL; \ - goto fail; \ -} - static int count_psbt_parts( const unsigned char *bytes, size_t bytes_len, @@ -1004,9 +998,6 @@ static int count_psbt_parts( result->num_inputs = 0; result->num_outputs = 0; - /* Skip the magic */ - pull_skip(&bytes, &bytes_len, sizeof(WALLY_PSBT_MAGIC)); - /* Go through globals and count */ while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { const unsigned char *key; @@ -1429,27 +1420,23 @@ int wally_psbt_from_bytes( size_t bytes_len, struct wally_psbt **output) { - const unsigned char *p = bytes, *end = bytes + bytes_len, *key, *value; - uint64_t key_len, value_len; - uint8_t type; - size_t i, vl; - int ret = WALLY_OK; + const unsigned char *magic, *pre_key; + int ret; + size_t i, key_len; struct psbt_counts *counts = NULL; struct wally_psbt *result = NULL; - bool found_sep; TX_CHECK_OUTPUT; - /* Check the magic */ - if (bytes_len <= 5) { + magic = pull_skip(&bytes, &bytes_len, sizeof(WALLY_PSBT_MAGIC)); + if (!magic) { ret = WALLY_EINVAL; /* Not enough bytes */ goto fail; } - if (memcmp(p, WALLY_PSBT_MAGIC, 5) != 0 ) { + if (memcmp(magic, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)) != 0 ) { ret = WALLY_EINVAL; /* Invalid Magic */ goto fail; } - p += 5; /* Get a count of the psbt parts */ if (count_psbt_parts(bytes, bytes_len, &counts) != WALLY_OK) { @@ -1465,47 +1452,36 @@ int wally_psbt_from_bytes( *output = result; /* Read globals first */ - found_sep = false; - while (p < end) { - /* Read the key length */ - vl = varint_from_bytes(p, &key_len); - CHECK_BUF_BOUNDS(p, key_len + vl, bytes, bytes_len) - p += vl; - - if (key_len == 0) { - found_sep = true; - break; - } - - /* Read the key itself */ - key = p; - type = key[0]; - p += key_len; + pre_key = bytes; + while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { + const unsigned char *key, *val; + size_t val_max; - /* Pre-read the value length but don't increment for a sanity check */ - vl = varint_from_bytes(p, &value_len); - CHECK_BUF_BOUNDS(p, value_len + vl, bytes, bytes_len) + /* Start parsing key */ + pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); /* Process based on type */ - switch (type) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_GLOBAL_UNSIGNED_TX: { - size_t j; if (result->tx) { ret = WALLY_EINVAL; /* We already have a global tx */ goto fail; - } else if (key_len != 1) { - ret = WALLY_EINVAL; /* Global tx key is one byte type */ - goto fail; } - p += varint_from_bytes(p, &value_len); - value = p; - if ((ret = wally_tx_from_bytes(value, value_len, 0, &result->tx)) != WALLY_OK) { + subfield_nomore_end(&bytes, &bytes_len, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(&bytes, &bytes_len, + pull_varint(&bytes, &bytes_len), + &val, &val_max); + ret = wally_tx_from_bytes(val, val_max, 0, &result->tx); + if (ret != WALLY_OK) { goto fail; } - p += value_len; + pull_subfield_end(&bytes, &bytes_len, val, val_max); + /* Make sure there are no scriptSigs and scriptWitnesses */ - for (j = 0; j < result->tx->num_inputs; ++j) { - if (result->tx->inputs[j].script_len != 0 || (result->tx->inputs[j].witness && result->tx->inputs[j].witness->num_items != 0)) { + for (i = 0; i < result->tx->num_inputs; ++i) { + if (result->tx->inputs[i].script_len != 0 || (result->tx->inputs[i].witness && result->tx->inputs[i].witness->num_items != 0)) { ret = WALLY_EINVAL; /* Unsigned tx needs empty scriptSigs and scriptWtinesses */ goto fail; } @@ -1514,23 +1490,19 @@ int wally_psbt_from_bytes( } /* Unknowns */ default: { - struct wally_unknowns_map *unknowns = result->unknowns; - clone_bytes(&unknowns->items[unknowns->num_items].key, key, key_len); - unknowns->items[unknowns->num_items].key_len = key_len; - - p += varint_from_bytes(p, &value_len); - value = p; - clone_bytes(&unknowns->items[unknowns->num_items].value, value, value_len); - unknowns->items[unknowns->num_items].value_len = value_len; - - unknowns->num_items++; - p += value_len; + ret = pull_unknown_key_value(&bytes, &bytes_len, pre_key, + result->unknowns); + if (ret != WALLY_OK) { + return ret; + } break; } } + pre_key = bytes; } - if (!found_sep) { + /* We don't technically need to test here, but it's a minor optimization */ + if (!bytes) { ret = WALLY_EINVAL; /* Missing global separator */ goto fail; } @@ -1542,18 +1514,13 @@ int wally_psbt_from_bytes( /* Read inputs */ for (i = 0; i < counts->num_inputs; ++i) { - size_t max = end - p; - ret = pull_psbt_input(&p, &max, counts->input_counts[i], + ret = pull_psbt_input(&bytes, &bytes_len, counts->input_counts[i], &result->inputs[i]); /* Increment this now, might be partially initialized! */ result->num_inputs++; if (ret != WALLY_OK) { goto fail; } - if (p == NULL) { - ret = WALLY_EINVAL; - goto fail; - } } /* Make sure that the number of inputs matches the number of inputs in the transaction */ @@ -1564,21 +1531,16 @@ int wally_psbt_from_bytes( /* Read outputs */ for (i = 0; i < counts->num_outputs; ++i) { - size_t max = end - p; - ret = pull_psbt_output(&p, &max, counts->output_counts[i], + ret = pull_psbt_output(&bytes, &bytes_len, counts->output_counts[i], &result->outputs[i]); result->num_outputs++; if (ret != WALLY_OK) { goto fail; } - if (p == NULL) { - ret = WALLY_EINVAL; - goto fail; - } } - /* Make sure that the number of outputs matches the number ot outputs in the transaction */ - if (result->num_outputs != result->tx->num_outputs) { + /* If we ran out of data anywhere, fail. */ + if (bytes == NULL) { ret = WALLY_EINVAL; goto fail; } From 3430c118c28ab267f226f14f792a74c65526647a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:45:56 +0930 Subject: [PATCH 070/205] psbt: add test for marshal/unmarshal limits. This currently fails (badly). Signed-off-by: Rusty Russell --- src/Makefile.am | 5 +++ src/ctest/test_psbt_limits.c | 85 ++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 src/ctest/test_psbt_limits.c diff --git a/src/Makefile.am b/src/Makefile.am index bb32c5b5e..f2a57e586 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -231,6 +231,11 @@ noinst_PROGRAMS += test_psbt test_psbt_SOURCES = ctest/test_psbt.c ccan/ccan/str/hex/hex.c test_psbt_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS) -I$(srcdir)/ccan test_psbt_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@ +TESTS += test_psbt_limits +noinst_PROGRAMS += test_psbt_limits +test_psbt_limits_SOURCES = ctest/test_psbt_limits.c ccan/ccan/str/hex/hex.c +test_psbt_limits_CFLAGS = -I$(top_srcdir)/include $(AM_CFLAGS) -I$(srcdir)/ccan +test_psbt_limits_LDADD = $(lib_LTLIBRARIES) @CTEST_EXTRA_STATIC@ if USE_PTHREAD TESTS += test_clear noinst_PROGRAMS += test_clear diff --git a/src/ctest/test_psbt_limits.c b/src/ctest/test_psbt_limits.c new file mode 100644 index 000000000..e86c585d5 --- /dev/null +++ b/src/ctest/test_psbt_limits.c @@ -0,0 +1,85 @@ +/* This is a superset of test_psbt, but requires mmap */ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "psbts.h" + +/* Create a cliff: any access past the end will SEGV */ +static unsigned char *cliff(size_t *size) +{ + unsigned char *p; + + /* One page is enough for our tests so far */ + *size = getpagesize(); + + /* MAP_ANON isn't POSIX, but MacOS doesn't let us mmap /dev/zero */ + p = mmap(NULL, *size + getpagesize(), + PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) + err(1, "Failed to mmap anon"); + + /* Remove second page. */ + if (munmap(p + *size, getpagesize()) != 0) + err(1, "Failed to munmap /dev/zero"); + return p; +} + +static void test_psbt(const struct psbt_test *test, + unsigned char *p, size_t plen) +{ + size_t i; + + /* It can fit, otherwise adjust cliff() */ + assert(hex_data_size(strlen(test->hex)) <= plen); + + /* Unpack right next to the cliff */ + for (i = 0; i <= hex_data_size(strlen(test->hex)); i++) { + struct wally_psbt *psbt; + size_t bit; + + if (!hex_decode(test->hex, i * 2, p + plen - i, i)) + abort(); + + /* Try it raw: probably will fail. */ + if (wally_psbt_from_bytes(p + plen - i, i, &psbt) == WALLY_OK) + wally_psbt_free(psbt); + + /* Now try flipping each bit in last byte. */ + for (bit = 0; bit < 8; bit++) { + p[plen - 1] ^= (1 << bit); + if (wally_psbt_from_bytes(p + plen - i, i, &psbt) == WALLY_OK) + wally_psbt_free(psbt); + p[plen - 1] ^= (1 << bit); + } + } +} + +int main(void) +{ + size_t i; + size_t plen; + unsigned char *p = cliff(&plen); + + for (i = 0; i < sizeof(invalid_psbts) / sizeof(invalid_psbts[0]); i++) { + test_psbt(invalid_psbts + i, p, plen); + } + + for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { + test_psbt(valid_psbts + i, p, plen); + } + + return 0; +} From cd24ad82916c953e97d908bca1989305a13960ce Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 29 May 2020 10:46:42 +0930 Subject: [PATCH 071/205] psbt: add limit testing to unmarshalling as well. Signed-off-by: Rusty Russell --- src/ctest/test_psbt_limits.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/src/ctest/test_psbt_limits.c b/src/ctest/test_psbt_limits.c index e86c585d5..8648b9f10 100644 --- a/src/ctest/test_psbt_limits.c +++ b/src/ctest/test_psbt_limits.c @@ -37,8 +37,9 @@ static unsigned char *cliff(size_t *size) return p; } -static void test_psbt(const struct psbt_test *test, - unsigned char *p, size_t plen) +/* Test that we don't read past end of buffer when unmarshalling */ +static void test_psbt_read(const struct psbt_test *test, + unsigned char *p, size_t plen) { size_t i; @@ -67,6 +68,27 @@ static void test_psbt(const struct psbt_test *test, } } +/* Test that we don't write past end of buffer when marshaling */ +static void test_psbt_write(const struct psbt_test *test, + unsigned char *p, size_t plen) +{ + size_t i, written; + struct wally_psbt *psbt; + + if (wally_psbt_from_base64(test->base64, &psbt) != WALLY_OK) + abort(); + + for (i = 0;; i++) { + if (wally_psbt_to_bytes(psbt, p + plen - i, i, &written) == WALLY_OK) + break; + } + /* Should have fit exactly */ + if (written != i) + errx(1, "wally_psbt_to_bytes %s wrote %zu in %zu bytes?", + test->base64, written, i); + wally_psbt_free(psbt); +} + int main(void) { size_t i; @@ -74,11 +96,12 @@ int main(void) unsigned char *p = cliff(&plen); for (i = 0; i < sizeof(invalid_psbts) / sizeof(invalid_psbts[0]); i++) { - test_psbt(invalid_psbts + i, p, plen); + test_psbt_read(invalid_psbts + i, p, plen); } for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { - test_psbt(valid_psbts + i, p, plen); + test_psbt_read(valid_psbts + i, p, plen); + test_psbt_write(valid_psbts + i, p, plen); } return 0; From 666877cc44092380bd65bc3bc17c9e5e351fb69b Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 16:24:47 +1200 Subject: [PATCH 072/205] psbt: Delete redundant struct wally_key_origin_info --- include/wally_psbt.h | 14 ++++---------- src/psbt.c | 41 ++++++++++++++++++++--------------------- src/test/util.py | 11 ++++------- 3 files changed, 28 insertions(+), 38 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index beff22380..b4c397254 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -27,7 +27,6 @@ extern "C" { #define WALLY_PSBT_OUT_BIP32_DERIVATION 0x02 #ifdef SWIG -struct wally_key_origin_info; struct wally_keypath_map; struct wally_partial_sigs_map; struct wally_unknowns_map; @@ -36,17 +35,12 @@ struct wally_psbt_output; struct wally_psbt; #else -/** Key origin data. Contains a BIP 32 fingerprint and the derivation path */ -struct wally_key_origin_info { - unsigned char fingerprint[BIP32_KEY_FINGERPRINT_LEN]; +/** Key path, a BIP 32 path and fingerprint with associated pubkey */ +struct wally_keypath_item { uint32_t *path; size_t path_len; -}; - -/** Item in keypath map */ -struct wally_keypath_item { + unsigned char fingerprint[BIP32_KEY_FINGERPRINT_LEN]; unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; - struct wally_key_origin_info origin; }; /** A map of public keys to BIP 32 fingerprint and derivation paths */ @@ -85,7 +79,7 @@ struct wally_unknowns_map { size_t items_allocation_len; }; -/** A PSBT input map */ +/** A PSBT input */ struct wally_psbt_input { struct wally_tx *non_witness_utxo; struct wally_tx_output *witness_utxo; diff --git a/src/psbt.c b/src/psbt.c index 5f6d0c2c3..7516a6cbb 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -49,7 +49,7 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) if (keypaths) { for (i = 0; i < keypaths->num_items; ++i) { - clear_and_free(keypaths->items[i].origin.path, keypaths->items[i].origin.path_len * sizeof(*keypaths->items[i].origin.path)); + clear_and_free(keypaths->items[i].path, keypaths->items[i].path_len * sizeof(*keypaths->items[i].path)); } clear_and_free(keypaths->items, keypaths->items_allocation_len * sizeof(*keypaths->items)); clear_and_free(keypaths, sizeof(*keypaths)); @@ -68,12 +68,12 @@ static struct wally_keypath_map *clone_keypath_map(const struct wally_keypath_ma for (i = 0; i < keypaths->num_items; ++i) { memcpy(&result->items[i].pubkey, keypaths->items[i].pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - memcpy(&result->items[i].origin.fingerprint, keypaths->items[i].origin.fingerprint, 4); - if (keypaths->items[i].origin.path) { - if (!clone_bytes((unsigned char **)&result->items[i].origin.path, (unsigned char *)keypaths->items[i].origin.path, keypaths->items[i].origin.path_len * sizeof(*keypaths->items[i].origin.path))) { + memcpy(&result->items[i].fingerprint, keypaths->items[i].fingerprint, 4); + if (keypaths->items[i].path) { + if (!clone_bytes((unsigned char **)&result->items[i].path, (unsigned char *)keypaths->items[i].path, keypaths->items[i].path_len * sizeof(*keypaths->items[i].path))) { goto fail; } - result->items[i].origin.path_len = keypaths->items[i].origin.path_len; + result->items[i].path_len = keypaths->items[i].path_len; } } result->num_items = keypaths->num_items; @@ -120,12 +120,12 @@ int wally_add_new_keypath(struct wally_keypath_map *keypaths, latest = keypaths->num_items; memcpy(&keypaths->items[latest].pubkey, pubkey, pubkey_len); - memcpy(&keypaths->items[latest].origin.fingerprint, fingerprint, fingerprint_len); + memcpy(&keypaths->items[latest].fingerprint, fingerprint, fingerprint_len); if (path) { - if (!clone_bytes((unsigned char **)&keypaths->items[latest].origin.path, (unsigned char *)path, path_len * sizeof(*path))) { + if (!clone_bytes((unsigned char **)&keypaths->items[latest].path, (unsigned char *)path, path_len * sizeof(*path))) { return WALLY_ENOMEM; } - keypaths->items[latest].origin.path_len = path_len; + keypaths->items[latest].path_len = path_len; } keypaths->num_items++; @@ -136,10 +136,10 @@ static int add_keypath_item(struct wally_keypath_map *keypaths, struct wally_key { return wally_add_new_keypath(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, - item->origin.fingerprint, + item->fingerprint, BIP32_KEY_FINGERPRINT_LEN, - item->origin.path, - item->origin.path_len); + item->path, + item->path_len); } int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wally_partial_sigs_map **output) @@ -909,17 +909,17 @@ static int pull_keypath(const unsigned char **cursor, size_t *max, pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); /* Read the fingerprint */ - pull_bytes(kpitem->origin.fingerprint, sizeof(kpitem->origin.fingerprint), + pull_bytes(kpitem->fingerprint, sizeof(kpitem->fingerprint), &val, &val_max); /* Remainder is the path */ - kpitem->origin.path_len = val_max / sizeof(uint32_t); - kpitem->origin.path = wally_malloc(val_max); - if (kpitem->origin.path == NULL) { + kpitem->path_len = val_max / sizeof(uint32_t); + kpitem->path = wally_malloc(val_max); + if (kpitem->path == NULL) { return WALLY_ENOMEM; } for (i = 0; val_max >= sizeof(uint32_t); ++i) { - kpitem->origin.path[i] = pull_le32(&val, &val_max); + kpitem->path[i] = pull_le32(&val, &val_max); } subfield_nomore_end(cursor, max, val, val_max); return WALLY_OK; @@ -1640,13 +1640,12 @@ static void push_keypath_item( push_psbt_key_with_pubkey(cursor, max, type, item->pubkey); origin_len = 4; /* Start with 4 bytes for fingerprint */ - origin_len += item->origin.path_len * sizeof(uint32_t); + origin_len += item->path_len * sizeof(uint32_t); push_varint(cursor, max, origin_len); - push_bytes(cursor, max, item->origin.fingerprint, 4); - for (i = 0; i < item->origin.path_len; ++i) { - push_bytes(cursor, max, - &item->origin.path[i], sizeof(uint32_t)); + push_bytes(cursor, max, item->fingerprint, 4); + for (i = 0; i < item->path_len; ++i) { + push_bytes(cursor, max, &item->path[i], sizeof(uint32_t)); } } diff --git a/src/test/util.py b/src/test/util.py index 64f612ccd..09d4a7010 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -112,14 +112,11 @@ class wally_tx(Structure): ('num_outputs', c_ulong), ('outputs_allocation_len', c_ulong),] -class key_origin_info(Structure): - _fields_ = [('fingerprint', c_ubyte * 4), - ('items', POINTER(c_ulong)), - ('path_len', c_ulong)] - class keypath_item(Structure): - _fields_ = [('pubkey', c_ubyte * 65), - ('origin', key_origin_info)] + _fields_ = [('path', POINTER(c_ulong)), + ('path_len', c_ulong), + ('fingerprint', c_ubyte * 4), + ('pubkey', c_ubyte * 65)] class keypath_map(Structure): _fields_ = [('items', POINTER(keypath_item)), From c142302c2c08e65d3f0b612417336b6605a179c4 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 20:27:08 +1200 Subject: [PATCH 073/205] transaction: Declare vars up front --- src/transaction.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/transaction.c b/src/transaction.c index 9abd30a64..2bfe13761 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -350,10 +350,11 @@ static bool clone_input_to( #endif struct wally_tx_witness_stack *new_witness; + struct wally_tx_witness_stack *new_pegin_witness; + new_witness = src->witness ? clone_witness(src->witness) : NULL; #ifdef BUILD_ELEMENTS - struct wally_tx_witness_stack *new_pegin_witness; new_pegin_witness = src->pegin_witness ? clone_witness(src->pegin_witness) : NULL; #endif @@ -826,10 +827,10 @@ static int tx_elements_output_proof_init( const unsigned char *rangeproof, size_t rangeproof_len) { - (void) output; #ifdef BUILD_ELEMENTS unsigned char *new_surjectionproof = NULL, *new_rangeproof = NULL; #endif + (void) output; if (BYTES_INVALID(surjectionproof, surjectionproof_len) || BYTES_INVALID(rangeproof, rangeproof_len)) From ead83defe5ee73dcf2805b7d4c86e13df65a5da1 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 6 Jul 2020 22:43:40 +1200 Subject: [PATCH 074/205] docs: Add missing docs to cleanup.sh --- tools/cleanup.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/cleanup.sh b/tools/cleanup.sh index 6c3be201f..5c5b6323f 100755 --- a/tools/cleanup.sh +++ b/tools/cleanup.sh @@ -58,6 +58,6 @@ rm -f tools/build-aux/missing rm -f tools/build-aux/m4/l*.m4 rm -f tools/build-aux/test-driver rm -rf autom4te.cache/ src/secp256k1/autom4te.cache -rm -rf docs/build docs/source/address.rst docs/source/bip32.rst docs/source/bip38.rst docs/source/bip39.rst docs/source/core.rst docs/source/crypto.rst docs/source/elements.rst docs/source/script.rst docs/source/transaction.rst +rm -rf docs/build docs/source/address.rst docs/source/bip32.rst docs/source/bip38.rst docs/source/bip39.rst docs/source/core.rst docs/source/crypto.rst docs/source/elements.rst docs/source/psbt.rst docs/source/script.rst docs/source/symmetric.rst docs/source/transaction.rst rm -rf .venv exit 0 From 009516ad812f45f7151578001bb083785a8f2487 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 07:12:40 +1200 Subject: [PATCH 075/205] transaction: Expose wally_tx_get_txid We re-use the existing hex implementation as its more efficient than the PSBT one. Also expose the call through python, Java and C++. --- include/wally.hpp | 1 + include/wally_transaction.h | 14 +++++++ src/psbt.c | 33 ++-------------- src/pyexample/liquid/receive-send.py | 2 +- src/swig_java/jni_extra.java_in | 4 ++ .../src/com/blockstream/test/test_tx.java | 3 ++ src/swig_java/swig.i | 1 + src/swig_python/python_extra.py_in | 1 + src/test/test_transaction.py | 3 ++ src/test/util.py | 1 + src/transaction.c | 39 ++++++++++++++----- 11 files changed, 62 insertions(+), 40 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index ce5dc7ccc..c2e24e87e 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -444,6 +444,7 @@ WALLY_FN_P_A(bip32_key_from_base58_alloc, bip32_key_from_base58_alloc) WALLY_FN_P_A(bip39_get_languages, bip39_get_languages) WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) +WALLY_FN_P_B(tx_get_txid, wally_tx_get_txid) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) WALLY_FN_P_S(base58_get_length, wally_base58_get_length) WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 46d9ea81e..df2723f7e 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -408,6 +408,20 @@ WALLY_CORE_API int wally_tx_get_witness_count( WALLY_CORE_API int wally_tx_free(struct wally_tx *tx); #endif /* SWIG_PYTHON */ +/** + * Return the txid of a transaction. + * + * :param tx: The transaction to compute the txid of. + * :param bytes_out: Destination for the txid. + * :param len: Size of ``bytes_out`` in bytes. Must be ``WALLY_TXHASH_LEN``. + * + * .. note:: The txid is expensive to compute. + */ +WALLY_CORE_API int wally_tx_get_txid( + const struct wally_tx *tx, + unsigned char *bytes_out, + size_t len); + /** * Return the length of transaction once serialized into bytes. * diff --git a/src/psbt.c b/src/psbt.c index 7516a6cbb..65f8b65a1 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1937,33 +1937,6 @@ int wally_psbt_to_base64( return ret; } -static int get_txid( - struct wally_tx *tx, - unsigned char *txid, - size_t txid_len) -{ - unsigned char *bytes = NULL; - size_t calc, written; - int ret = WALLY_OK; - - if (!tx || !txid || txid_len != WALLY_TXHASH_LEN) { - return WALLY_EINVAL; - } - - if ((ret = wally_tx_get_length(tx, 0, &calc)) != WALLY_OK) { - return ret; - } - if ((bytes = wally_malloc(calc)) == NULL) { - return WALLY_ENOMEM; - } - if ((ret = wally_tx_to_bytes(tx, 0, bytes, calc, &written)) == WALLY_OK) { - ret = wally_sha256d(bytes, written, txid, txid_len); - } - - wally_free(bytes); - return ret; -} - static int merge_unknowns_into( struct wally_unknowns_map *dst, const struct wally_unknowns_map *src) @@ -2184,7 +2157,7 @@ int wally_combine_psbts( } /* Get info from the first psbt and use it as the template */ - if ((ret = get_txid(psbts->tx, global_txid, sizeof(global_txid))) != WALLY_OK) { + if ((ret = wally_tx_get_txid(psbts->tx, global_txid, sizeof(global_txid))) != WALLY_OK) { return ret; } @@ -2202,7 +2175,7 @@ int wally_combine_psbts( unsigned char txid[sizeof(global_txid)]; /* Compare the txids */ - if ((ret = get_txid(psbts[i].tx, txid, sizeof(txid))) != WALLY_OK) { + if ((ret = wally_tx_get_txid(psbts[i].tx, txid, sizeof(txid))) != WALLY_OK) { goto fail; } if (memcmp(global_txid, txid, sizeof(txid)) != 0) { @@ -2356,7 +2329,7 @@ int wally_sign_psbt( if (input->non_witness_utxo) { unsigned char txid[WALLY_TXHASH_LEN]; - if ((ret = get_txid(input->non_witness_utxo, txid, sizeof(txid))) != WALLY_OK) { + if ((ret = wally_tx_get_txid(input->non_witness_utxo, txid, sizeof(txid))) != WALLY_OK) { return ret; } if (memcmp((char *)txid, (char *)txin->txhash, sizeof(txid)) != 0) { diff --git a/src/pyexample/liquid/receive-send.py b/src/pyexample/liquid/receive-send.py index fc745cd6e..3f3a18514 100644 --- a/src/pyexample/liquid/receive-send.py +++ b/src/pyexample/liquid/receive-send.py @@ -207,7 +207,7 @@ # start-sign vout = 0 -prev_txid = wally.sha256d(wally.tx_to_bytes(tx, 0)) +prev_txid = wally.tx_get_txid(tx) for vin, script_pubkey in zip(vouts_in, script_pubkeys_in): wally.tx_add_elements_raw_input( diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index b80802b79..3e7149fd3 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -231,6 +231,10 @@ return _wif_is_uncompressed(wif) != 0; } + public final static byte[] tx_get_txid(final Object tx) { + return tx_get_txid(tx, null); + } + public static final byte[] tx_to_bytes(final Object tx, long flags) { final int txlength = Wally.tx_get_length(tx, flags); final byte[] buf = new byte[txlength]; diff --git a/src/swig_java/src/com/blockstream/test/test_tx.java b/src/swig_java/src/com/blockstream/test/test_tx.java index a93bd76cd..7a87ac063 100644 --- a/src/swig_java/src/com/blockstream/test/test_tx.java +++ b/src/swig_java/src/com/blockstream/test/test_tx.java @@ -31,6 +31,7 @@ public void test() { final Object tx_input_wit_null = Wally.tx_input_init(tx_get_input_txhash, 0, 4294967295L, tx_get_input_script, null); final Object tx_out = Wally.tx_output_init(100, tx_get_output_script); final byte[] tx_input_get_script = Wally.tx_input_get_script(tx_input); + final byte[] txid = Wally.tx_get_txid(tx); assert_eq(p2pkh_hex, tx_string, "hex ser/der doesn't match original"); assert_eq(p2pkh_hex, h(tx_bytes), "hex(bytes) doesn't match original"); @@ -55,6 +56,8 @@ public void test() { assert_eq(72, Wally.tx_get_input_witness(tx_wit, 0, 1).length, "witness buffer mismatch"); assert_eq(h(tx_get_output_script), h(Wally.tx_output_get_script(tx_out)), "script hex mismatch"); assert_eq(100L, Wally.tx_output_get_satoshi(tx_out), "total output mismatch"); + /* Note that the hex used here is reversed from the typical txid display order */ + assert_eq("26641caee29b3ce14d0888ad3cfdd2f73f32f0c41d3da85127639009b38f1b21", h(txid), "txid mismatch"); Wally.tx_add_input(tx, tx_input); assert_eq(2, Wally.tx_get_num_inputs(tx), "after adding number of inputs is not 2"); diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index a9fb03915..15df25e6c 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -555,6 +555,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(wally_tx_get_output_value_len); %returns_array_(wally_tx_get_signature_hash, 12, 13, SHA256_LEN); %returns_uint64(wally_tx_get_total_output_satoshi); +%returns_array_(wally_tx_get_txid, 2, 3, WALLY_TXHASH_LEN); %returns_size_t(wally_tx_get_version); %returns_size_t(wally_tx_get_vsize); %returns_size_t(wally_tx_get_weight); diff --git a/src/swig_python/python_extra.py_in b/src/swig_python/python_extra.py_in index 1262b3e72..755380d82 100644 --- a/src/swig_python/python_extra.py_in +++ b/src/swig_python/python_extra.py_in @@ -133,6 +133,7 @@ address_to_scriptpubkey = _wrap_bin(address_to_scriptpubkey, 21 + 4, resize=True tx_to_bytes = _wrap_bin(tx_to_bytes, tx_get_length, resize=True) tx_get_btc_signature_hash = _wrap_bin(tx_get_btc_signature_hash, SHA256_LEN) +tx_get_txid = _wrap_bin(tx_get_txid, WALLY_TXHASH_LEN) tx_get_signature_hash = _wrap_bin(tx_get_signature_hash, SHA256_LEN) tx_input_get_txhash = _wrap_bin(tx_input_get_txhash, WALLY_TXHASH_LEN) tx_input_get_script = _wrap_bin(tx_input_get_script, tx_input_get_script_len, resize=True) diff --git a/src/test/test_transaction.py b/src/test/test_transaction.py index f9a5e0e96..adcd6b1b5 100644 --- a/src/test/test_transaction.py +++ b/src/test/test_transaction.py @@ -59,6 +59,9 @@ def test_serialization(self): # Check the transaction can be cloned and serializes to the same hex self.assertEqual(WALLY_OK, wally_tx_clone(tx_out, 0, tx_copy)) self.assertEqual(tx_hex, utf8(self.tx_serialize_hex(tx_copy))) + # Check that the txid can be computed + txid, txid_len = make_cbuffer('00' * 32) + self.assertEqual(WALLY_OK, wally_tx_get_txid(tx_out, txid, txid_len)) def test_lengths(self): """Testing functions measuring different lengths for a tx""" diff --git a/src/test/util.py b/src/test/util.py index 09d4a7010..546645d5b 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -304,6 +304,7 @@ class wally_psbt(Structure): ('wally_tx_add_input', c_int, [POINTER(wally_tx), POINTER(wally_tx_input)]), ('wally_tx_add_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), ('wally_tx_add_elements_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_get_txid', c_int, [POINTER(wally_tx), c_void_p, c_ulong]), ('wally_tx_remove_input', c_int, [POINTER(wally_tx), c_ulong]), ('wally_tx_set_input_script', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong]), ('wally_tx_set_input_witness', c_int, [POINTER(wally_tx), c_ulong, POINTER(wally_tx_witness_stack)]), diff --git a/src/transaction.c b/src/transaction.c index 2bfe13761..cb01e4aa0 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -2152,14 +2152,21 @@ int wally_tx_to_bytes(const struct wally_tx *tx, uint32_t flags, return tx_to_bytes(tx, NULL, flags, bytes_out, len, written, is_elements); } -static int tx_to_hex(const struct wally_tx *tx, uint32_t flags, - char **output, bool is_elements) +/* Common implementation for hex conversion and txid calculation */ +static int tx_to_hex_or_txid(const struct wally_tx *tx, uint32_t flags, + char **output, + unsigned char *bytes_out, size_t len, + bool is_elements) { unsigned char buff[TX_STACK_SIZE], *buff_p = buff; size_t n, written; int ret; - if (!output) + if (output) + *output = NULL; + + if ((output && (bytes_out || len)) || + (!output && (!bytes_out || len != WALLY_TXHASH_LEN))) return WALLY_EINVAL; ret = tx_to_bytes(tx, NULL, flags, buff_p, sizeof(buff), &n, is_elements); @@ -2171,12 +2178,15 @@ static int tx_to_hex(const struct wally_tx *tx, uint32_t flags, if (n != written) ret = WALLY_ERROR; /* Length calculated incorrectly */ } - if (ret == WALLY_OK) - ret = wally_hex_from_bytes(buff_p, n, output); + if (ret == WALLY_OK) { + if (output) + ret = wally_hex_from_bytes(buff_p, n, output); + else + ret = wally_sha256d(buff_p, n, bytes_out, len); + } + wally_clear(buff_p, n); if (buff_p != buff) - clear_and_free(buff_p, n); - else - wally_clear(buff, n); + wally_free(buff_p); } return ret; } @@ -2190,7 +2200,18 @@ int wally_tx_to_hex(const struct wally_tx *tx, uint32_t flags, if (wally_tx_is_elements(tx, &is_elements) != WALLY_OK) return WALLY_EINVAL; #endif - return tx_to_hex(tx, flags, output, is_elements); + return tx_to_hex_or_txid(tx, flags, output, NULL, 0, is_elements); +} + +int wally_tx_get_txid(const struct wally_tx *tx, unsigned char *bytes_out, size_t len) +{ + size_t is_elements = 0; + +#ifdef BUILD_ELEMENTS + if (wally_tx_is_elements(tx, &is_elements) != WALLY_OK) + return WALLY_EINVAL; +#endif + return tx_to_hex_or_txid(tx, 0, NULL, bytes_out, len, is_elements); } int analyze_tx(const unsigned char *bytes, size_t bytes_len, From 05802b7d071e281cc5fee1222c43551f00e7ebd3 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 07:16:28 +1200 Subject: [PATCH 076/205] psbt: Remove unneeded casts --- src/psbt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 65f8b65a1..cf1368fed 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1952,7 +1952,7 @@ static int merge_unknowns_into( bool found = false; for (j = 0; j < dst->num_items; ++j) { if (src->items[i].key_len == dst->items[j].key_len && - memcmp((char *)dst->items[j].key, (char *)src->items[i].key, src->items[i].key_len) == 0) { + memcmp(dst->items[j].key, src->items[i].key, src->items[i].key_len) == 0) { found = true; break; } @@ -1981,7 +1981,7 @@ static int merge_keypaths_into( for (i = 0; i < src->num_items; ++i) { bool found = false; for (j = 0; j < dst->num_items; ++j) { - if (memcmp((char *)dst->items[j].pubkey, (char *)src->items[i].pubkey, 65) == 0) { + if (memcmp(dst->items[j].pubkey, src->items[i].pubkey, 65) == 0) { found = true; break; } @@ -2020,7 +2020,7 @@ static int merge_input_into( for (i = 0; i < src->partial_sigs->num_items; ++i) { bool found = false; for (j = 0; j < dst->partial_sigs->num_items; ++j) { - if (memcmp((char *)dst->partial_sigs->items[j].pubkey, (char *)src->partial_sigs->items[i].pubkey, 65) == 0) { + if (memcmp(dst->partial_sigs->items[j].pubkey, src->partial_sigs->items[i].pubkey, 65) == 0) { found = true; break; } @@ -2254,10 +2254,10 @@ int wally_sign_psbt( /* Go through each listed pubkey and see if it matches. */ for (j = 0; j < input->keypaths->num_items; ++j) { struct wally_keypath_item *item = &input->keypaths->items[j]; - if (item->pubkey[0] == 0x04 && memcmp((char *)item->pubkey, (char *)uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0) { + if (item->pubkey[0] == 0x04 && memcmp(item->pubkey, uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0) { match = true; break; - } else if (memcmp((char *)item->pubkey, (char *)pubkey, EC_PUBLIC_KEY_LEN) == 0) { + } else if (memcmp(item->pubkey, pubkey, EC_PUBLIC_KEY_LEN) == 0) { match = true; comp = true; break; @@ -2273,8 +2273,8 @@ int wally_sign_psbt( if (input->partial_sigs) { for (j = 0; j < input->partial_sigs->num_items; j++) { struct wally_partial_sigs_item *item = &input->partial_sigs->items[j]; - if (memcmp((char *)item->pubkey, (char *)uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0 - || memcmp((char *)item->pubkey, (char *)pubkey, EC_PUBLIC_KEY_LEN) == 0) { + if (memcmp(item->pubkey, uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0 || + memcmp(item->pubkey, pubkey, EC_PUBLIC_KEY_LEN) == 0) { already_signed = true; break; } @@ -2332,7 +2332,7 @@ int wally_sign_psbt( if ((ret = wally_tx_get_txid(input->non_witness_utxo, txid, sizeof(txid))) != WALLY_OK) { return ret; } - if (memcmp((char *)txid, (char *)txin->txhash, sizeof(txid)) != 0) { + if (memcmp(txid, txin->txhash, sizeof(txid)) != 0) { return WALLY_EINVAL; } @@ -2359,7 +2359,7 @@ int wally_sign_psbt( return ret; } if (scriptcode_len != WALLY_SCRIPTPUBKEY_P2WSH_LEN || - memcmp((char *)wsh, (char *)scriptcode, WALLY_SCRIPTPUBKEY_P2WSH_LEN) != 0) { + memcmp(wsh, scriptcode, WALLY_SCRIPTPUBKEY_P2WSH_LEN) != 0) { return WALLY_EINVAL; } scriptcode = input->witness_script; From 0f8e93233e4e196fda1f34b3e18748b9d40b66c3 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 07:26:16 +1200 Subject: [PATCH 077/205] docs: Update coverage report instructions --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 75f230bbb..2e966bec6 100644 --- a/README.md +++ b/README.md @@ -159,15 +159,15 @@ To generate an HTML coverage report, install `lcov` and use: ``` $ ./tools/cleanup.sh $ ./tools/autogen.sh -$ ./configure --enable-debug --enable-export-all --enable-swig-python --enable-swig-java --enable-coverage +$ ./configure --enable-debug --enable-export-all --enable-swig-python --enable-swig-java --enable-js_wrappers --enable-coverage $ make $ ./tools/coverage.sh clean $ make check $ ./tools/coverage.sh ``` -The coverage report can then be viewed at `src/lcov/index.html`. Patches to -increase the test coverage are welcome. +The coverage report can then be viewed at `./src/lcov/src/index.html`. Patches +to increase the test coverage are welcome. ## Users of libwally-core From b9c731d5257c9fd2081ce5d12d07144fd1b47a8c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 09:10:21 +1200 Subject: [PATCH 078/205] elements: Remove redundant parameter checks --- src/elements.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/elements.c b/src/elements.c index 0e4bfb23f..c48071449 100644 --- a/src/elements.c +++ b/src/elements.c @@ -534,9 +534,6 @@ int wally_asset_blinding_key_from_seed( unsigned char root[HMAC_SHA512_LEN]; int ret; - if (!bytes || !bytes_out || len != HMAC_SHA512_LEN) - return WALLY_EINVAL; - ret = wally_symmetric_key_from_seed(bytes, bytes_len, root, sizeof(root)); if (ret == WALLY_OK) { ret = wally_symmetric_key_from_parent(root, sizeof(root), 0, LABEL_STR, sizeof(LABEL_STR), From d550c9366b6c7be074f4ab644ad1cbabe1d42528 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 08:49:48 +1200 Subject: [PATCH 079/205] symmetric: Add tests --- src/Makefile.am | 1 + src/test/test_symmetric.py | 67 ++++++++++++++++++++++++++++++++++++++ src/test/util.py | 2 ++ 3 files changed, 70 insertions(+) create mode 100755 src/test/test_symmetric.py diff --git a/src/Makefile.am b/src/Makefile.am index f2a57e586..9d38d6dda 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -283,6 +283,7 @@ if RUN_PYTHON_TESTS $(AM_V_at)$(PYTHON_TEST) test/test_script.py $(AM_V_at)$(PYTHON_TEST) test/test_scrypt.py $(AM_V_at)$(PYTHON_TEST) test/test_sign.py + $(AM_V_at)$(PYTHON_TEST) test/test_symmetric.py $(AM_V_at)$(PYTHON_TEST) test/test_transaction.py $(AM_V_at)$(PYTHON_TEST) test/test_wif.py $(AM_V_at)$(PYTHON_TEST) test/test_wordlist.py diff --git a/src/test/test_symmetric.py b/src/test/test_symmetric.py new file mode 100755 index 000000000..bddf2cc20 --- /dev/null +++ b/src/test/test_symmetric.py @@ -0,0 +1,67 @@ +import unittest +from util import * + +ENTROPY_LEN_128, ENTROPY_LEN_256, ENTROPY_LEN_512 = 16, 32, 64 +HMAC_SHA512_LEN = 64 + +class SymmetricTests(unittest.TestCase): + + def test_symmetric_key(self): + seed128, seed128_len = make_cbuffer('01' * ENTROPY_LEN_128) + seed256, seed256_len = make_cbuffer('01' * ENTROPY_LEN_256) + seed512, seed512_len = make_cbuffer('01' * ENTROPY_LEN_512) + label, label_len = make_cbuffer('0f0000') + key_out, key_out_len = make_cbuffer('00' * HMAC_SHA512_LEN) + + # wally_symmetric_key_from_seed + # Invalid args + cases = [ + (None, seed128_len, key_out, key_out_len), # Null bytes + (seed128, 0, key_out, key_out_len), # 0 Length bytes + (seed128, seed128_len-1, key_out, key_out_len), # Bad bytes length + (seed128, seed128_len, None, key_out_len), # Null dest + (seed128, seed128_len, key_out, 0), # 0 length dest + (seed128, seed128_len, key_out, key_out_len+1), # Bad dest length + ] + for bytes_in, bytes_len, out, out_len in cases: + ret = wally_symmetric_key_from_seed(bytes_in, bytes_len, out, out_len) + self.assertEqual(ret, WALLY_EINVAL) + + # Valid args + for bytes_in, bytes_len in [(seed128, seed128_len), + (seed256, seed256_len), + (seed512, seed512_len)]: + ret = wally_symmetric_key_from_seed(bytes_in, bytes_len, key_out, key_out_len) + self.assertEqual(ret, WALLY_OK) + + # wally_symmetric_key_from_parent + key_in, key_len = make_cbuffer('01' * HMAC_SHA512_LEN) + # Invalid args + cases = [ + (None, key_len, 0, label, label_len, key_out, key_out_len), # Null key + (key_in, 0, 0, label, label_len, key_out, key_out_len), # 0 Length key + (key_in, key_len-1, 1, label, label_len, key_out, key_out_len), # Bad key length + (key_in, key_len, 1, label, label_len, key_out, key_out_len), # Bad version + (key_in, key_len, 0, None, label_len, key_out, key_out_len), # Null label + (key_in, key_len, 0, label, 0, key_out, key_out_len), # Bad label length + (key_in, key_len, 0, label, label_len, None, key_out_len), # Null dest + (key_in, key_len, 0, label, label_len, key_out, 0), # 0 length dest + (key_in, key_len, 0, label, label_len, key_out, key_out_len+1), # Bad dest length + ] + for bytes_in, bytes_len, ver, l, l_len, out, out_len in cases: + ret = wally_symmetric_key_from_parent(bytes_in, bytes_len, ver, l, l_len, out, out_len) + self.assertEqual(ret, WALLY_EINVAL) + + # Valid args + ret = wally_symmetric_key_from_parent(key_in, key_len, 0, label, label_len, key_out, key_out_len) + self.assertEqual(ret, WALLY_OK) + + # Check labels around length LABEL_SIZE (64) + label, label_len = make_cbuffer('0f' * 65) + for l_len in (label_len-1, label_len, label_len+1): + ret = wally_symmetric_key_from_parent(key_in, key_len, 0, label, l_len, key_out, key_out_len) + self.assertEqual(ret, WALLY_OK) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/test/util.py b/src/test/util.py index 546645d5b..ed02de55c 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -272,6 +272,8 @@ class wally_psbt(Structure): ('wally_elements_pegout_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_elements_pegin_contract_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_witness_program_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_symmetric_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_symmetric_key_from_parent', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_tx_to_hex', c_int, [POINTER(wally_tx), c_uint, c_char_p_p]), ('wally_tx_from_hex', c_int, [c_char_p, c_uint, POINTER(POINTER(wally_tx))]), ('wally_tx_to_bytes', c_int, [POINTER(wally_tx), c_uint, c_void_p, c_ulong, c_ulong_p]), From c0352cbd1ce896507bf7b931b158599353bc779f Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 09:14:56 +1200 Subject: [PATCH 080/205] symmetric: Remove SYMMETRIC_KEY_LEN from the public interface Use (HMAC_SHA512_LEN / 2) internally to reflect that the key is split: child keys are derived from the 1st half of the master while private keys are derived from the 2nd half. --- include/wally_symmetric.h | 8 ++------ src/elements.c | 2 +- src/symmetric.c | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/include/wally_symmetric.h b/include/wally_symmetric.h index 5ce1e3170..2d9e8b040 100644 --- a/include/wally_symmetric.h +++ b/include/wally_symmetric.h @@ -7,17 +7,13 @@ extern "C" { #endif -#define SYMMETRIC_KEY_LEN 32 - /** - * Create a new symmetric key from entropy. - * - * This creates a new symmetric master key. + * Create a new symmetric parent key from entropy. * * :param bytes: Entropy to use. * :param bytes_len: Size of ``bytes`` in bytes. Must be one of ``BIP32_ENTROPY_LEN_128``, *| ``BIP32_ENTROPY_LEN_256`` or ``BIP32_ENTROPY_LEN_512``. - * :param bytes_out: Destination for the resulting key. + * :param bytes_out: Destination for the resulting parent key. * :param len: Size of ``bytes_out`` in bytes. Must be ``HMAC_SHA512_LEN``. */ WALLY_CORE_API int wally_symmetric_key_from_seed( diff --git a/src/elements.c b/src/elements.c index c48071449..528ce4aac 100644 --- a/src/elements.c +++ b/src/elements.c @@ -557,7 +557,7 @@ int wally_asset_blinding_key_to_ec_private_key( if (!bytes || bytes_len != HMAC_SHA512_LEN || !script || !script_len || !bytes_out || len != EC_PRIVATE_KEY_LEN) return WALLY_EINVAL; - ret = wally_hmac_sha256(bytes + SYMMETRIC_KEY_LEN, SYMMETRIC_KEY_LEN, script, script_len, bytes_out, len); + ret = wally_hmac_sha256(bytes + HMAC_SHA512_LEN / 2, HMAC_SHA512_LEN / 2, script, script_len, bytes_out, len); if (ret == WALLY_OK) ret = wally_ec_private_key_verify(bytes_out, EC_PRIVATE_KEY_LEN); diff --git a/src/symmetric.c b/src/symmetric.c index df0a14529..934db7d04 100644 --- a/src/symmetric.c +++ b/src/symmetric.c @@ -55,7 +55,7 @@ int wally_symmetric_key_from_parent( *buff_p = version; memcpy(buff_p + 1, label, label_len); - ret = wally_hmac_sha512(bytes, SYMMETRIC_KEY_LEN, buff_p, buff_len, bytes_out, len); + ret = wally_hmac_sha512(bytes, HMAC_SHA512_LEN / 2, buff_p, buff_len, bytes_out, len); if (buff_p != buff) wally_free(buff_p); From 003160914273f6646069cc9e8f916120f2fb3410 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 16:17:55 +1200 Subject: [PATCH 081/205] transaction: Allow serialisation of partial transactions This change reverts the behaviour in a28751605a3fe7090403f530ab21ee3b1f477ab3 so that WALLY_TX_FLAG_USE_ELEMENTS can be passed without error to tx_to_hex/tx_to_bytes (where it is ignored). Also simplifies tx flag handling in general, adds some missing parameter checks and updates the tests. --- include/wally_transaction.h | 5 ++- src/swig_python/contrib/elements_tx.py | 11 ++--- src/test/test_transaction.py | 57 +++++++++++++++----------- src/transaction.c | 40 +++++++++++------- 4 files changed, 64 insertions(+), 49 deletions(-) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index df2723f7e..1ffdaeff7 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -21,8 +21,9 @@ extern "C" { #define WALLY_TXHASH_LEN 32 /** Size of a transaction hash in bytes */ -#define WALLY_TX_FLAG_USE_WITNESS 0x1 /* Encode witness data if present */ -#define WALLY_TX_FLAG_USE_ELEMENTS 0x2 /* Encode/Decode as an elements transaction */ +#define WALLY_TX_FLAG_USE_WITNESS 0x1 /* Encode witness data if present */ +#define WALLY_TX_FLAG_USE_ELEMENTS 0x2 /* Encode/Decode as an elements transaction */ +#define WALLY_TX_FLAG_ALLOW_PARTIAL 0x4 /* Allow partially complete transactions */ #define WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE 0x1 diff --git a/src/swig_python/contrib/elements_tx.py b/src/swig_python/contrib/elements_tx.py index 3a292ec4a..639981057 100644 --- a/src/swig_python/contrib/elements_tx.py +++ b/src/swig_python/contrib/elements_tx.py @@ -82,13 +82,10 @@ def test_tx(self): tx_add_elements_raw_output(tx, script, None, ct_value, None, None, None, 0) size = tx_get_length(tx, 0) vsize = tx_vsize_from_weight(tx_get_weight(tx)) - tx_hex = tx_to_hex(tx, WALLY_TX_FLAG_USE_WITNESS) - tx_bytes = tx_to_bytes(tx, WALLY_TX_FLAG_USE_WITNESS) - self.assertEqual(tx_hex, hex_from_bytes(tx_bytes)) - with self.assertRaises(ValueError): - tx_to_hex(tx, WALLY_TX_FLAG_USE_ELEMENTS) - with self.assertRaises(ValueError): - tx_to_bytes(tx, WALLY_TX_FLAG_USE_ELEMENTS) + for extra_flags in (0, WALLY_TX_FLAG_USE_ELEMENTS, WALLY_TX_FLAG_ALLOW_PARTIAL): + tx_hex = tx_to_hex(tx, WALLY_TX_FLAG_USE_WITNESS | extra_flags) + tx_bytes = tx_to_bytes(tx, WALLY_TX_FLAG_USE_WITNESS | extra_flags) + self.assertEqual(tx_hex, hex_from_bytes(tx_bytes)) def test_coinbase(self): txhash, seq, script = bytearray(b'\x00'*32), 0xffffffff, b'0000' diff --git a/src/test/test_transaction.py b/src/test/test_transaction.py index adcd6b1b5..a1b1542d4 100644 --- a/src/test/test_transaction.py +++ b/src/test/test_transaction.py @@ -14,11 +14,11 @@ class TransactionTests(unittest.TestCase): def tx_deserialize_hex(self, hex_): tx_p = pointer(wally_tx()) - self.assertEqual(WALLY_OK, wally_tx_from_hex(hex_, 0, tx_p)) + self.assertEqual(WALLY_OK, wally_tx_from_hex(hex_, 0x0, tx_p)) return tx_p[0] def tx_serialize_hex(self, tx): - ret, hex_ = wally_tx_to_hex(tx, 1) + ret, hex_ = wally_tx_to_hex(tx, 0x1) self.assertEqual(ret, WALLY_OK) return hex_ @@ -26,39 +26,46 @@ def test_serialization(self): """Testing serialization and deserialization""" tx_out = pointer(wally_tx()) tx_copy = pointer(wally_tx()) + + # Invalid arguments for args in [ + (None, 0, tx_out), # Null hex (utf8(''), 0, tx_out), # Empty hex (utf8('00'*5), 0, tx_out), # Short hex (TX_FAKE_HEX, 0, None), # Empty output - (TX_FAKE_HEX, 4, tx_out), # Unsupported flag + (TX_FAKE_HEX, 8, tx_out), # Unsupported flag (TX_WITNESS_HEX[:11]+utf8('0')+TX_WITNESS_HEX[12:], 0, tx_out), # Invalid witness flag ]: self.assertEqual(WALLY_EINVAL, wally_tx_from_hex(*args)) - # deserialization is allowed, but the opposite is not - for args in [ - (TX_FAKE_HEX[:9]+utf8('0')+TX_FAKE_HEX[92:], 0, tx_out), # No inputs - (TX_FAKE_HEX[:93]+utf8('0')+TX_FAKE_HEX[112:], 0, tx_out), # No outputs - (TX_FAKE_HEX, 2, tx_out), # Elements flag must not be set for serialization - ]: - self.assertEqual(WALLY_OK, wally_tx_from_hex(*args)) - self.assertEqual(WALLY_EINVAL, wally_tx_to_hex(args[2][0], 0)[0]) + # No-input/no-output transactions + for tx_hex in [ + TX_FAKE_HEX[:9]+utf8('0')+TX_FAKE_HEX[92:], # No inputs + TX_FAKE_HEX[:93]+utf8('0')+TX_FAKE_HEX[112:], # No outputs + ]: + self.assertEqual(WALLY_OK, wally_tx_from_hex(tx_hex, 0, tx_out)) + # Partial transactions cannot be dumped by default + self.assertEqual(WALLY_EINVAL, wally_tx_to_hex(tx_out, 0)[0]) # Check the partial transaction can be cloned self.assertEqual(WALLY_OK, wally_tx_clone(tx_out, 0, tx_copy)) - - for args in [ - (TX_HEX, 0, tx_out), - (utf8('00')+TX_HEX[2:], 0, tx_out), - (utf8('ff')+TX_FAKE_HEX[2:], 0, tx_out), - (TX_FAKE_HEX, 0, tx_out), - (TX_WITNESS_HEX, 0, tx_out), - ]: - self.assertEqual(WALLY_OK, wally_tx_from_hex(*args)) - tx_hex = utf8(self.tx_serialize_hex(args[2][0])) - self.assertEqual(args[0], tx_hex) + if tx_out.contents.num_inputs != 0: + # Partial txs with inputs can be dumped with ALLOW_PARTIAL:0x4 + ret, hex_ = wally_tx_to_hex(tx_out, 0x1|0x4) + self.assertEqual(WALLY_OK, ret) + self.assertEqual(tx_hex, utf8(hex_)) + + # Valid transactions + for tx_hex in [ TX_HEX, + utf8('00')+TX_HEX[2:], + utf8('ff')+TX_FAKE_HEX[2:], + TX_FAKE_HEX, + TX_WITNESS_HEX ]: + self.assertEqual(WALLY_OK, wally_tx_from_hex(tx_hex, 0 ,tx_out)) + hex_ = utf8(self.tx_serialize_hex(tx_out)) + self.assertEqual(tx_hex, hex_) # Check the transaction can be cloned and serializes to the same hex self.assertEqual(WALLY_OK, wally_tx_clone(tx_out, 0, tx_copy)) - self.assertEqual(tx_hex, utf8(self.tx_serialize_hex(tx_copy))) + self.assertEqual(hex_, utf8(self.tx_serialize_hex(tx_copy))) # Check that the txid can be computed txid, txid_len = make_cbuffer('00' * 32) self.assertEqual(WALLY_OK, wally_tx_get_txid(tx_out, txid, txid_len)) @@ -77,7 +84,7 @@ def test_lengths(self): vsize = (weight + 3) // 4 self.assertEqual((WALLY_OK, length), wally_tx_get_length(byref(tx), 0)) self.assertEqual((WALLY_OK, length_with_witness), wally_tx_get_length(byref(tx), 1)) - self.assertEqual((WALLY_EINVAL, 0), wally_tx_get_length(byref(tx), 2)) # Unsupported flag + self.assertEqual((WALLY_EINVAL, 0), wally_tx_get_length(byref(tx), 8)) # Unsupported flag self.assertEqual((WALLY_OK, weight), wally_tx_get_weight(byref(tx))) self.assertEqual((WALLY_OK, vsize), wally_tx_get_vsize(byref(tx))) self.assertEqual((WALLY_OK, vsize), wally_tx_vsize_from_weight(weight)) @@ -186,7 +193,7 @@ def test_get_signature_hash(self): (tx, 0, script, 0, 1, 1, 0, out, out_len), # Invalid script length (tx, 0, script, script_len, MAX_SATOSHI+1, 1, 1, out, out_len), # Invalid amount (only with segwit) (tx, 0, script, script_len, 1, 0x100, 0, out, out_len), # Invalid sighash - (tx, 0, script, script_len, 1, 1, 2, out, out_len), # Invalid flags + (tx, 0, script, script_len, 1, 1, 8, out, out_len), # Invalid flags (tx, 0, script, script_len, 1, 1, 0, None, out_len), # Empty bytes (tx, 0, script, script_len, 1, 1, 0, out, 31), # Short len ]: diff --git a/src/transaction.c b/src/transaction.c index cb01e4aa0..66874afc3 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -11,7 +11,8 @@ #include "transaction_shared.h" #include "script_int.h" -#define WALLY_TX_ALL_FLAGS (WALLY_TX_FLAG_USE_WITNESS | WALLY_TX_FLAG_USE_ELEMENTS) +#define WALLY_TX_ALL_FLAGS \ + (WALLY_TX_FLAG_USE_WITNESS | WALLY_TX_FLAG_USE_ELEMENTS | WALLY_TX_FLAG_ALLOW_PARTIAL) /* We use the maximum DER sig length (plus a byte for the sighash) so that * we overestimate the size by a byte or two per tx sig. This allows using @@ -144,6 +145,9 @@ static bool is_valid_elements_tx(const struct wally_tx *tx) { size_t i; + if (!tx->num_inputs && !tx->num_outputs) + return false; /* No inputs & no outputs, treat as non-elements tx */ + for (i = 0; i < tx->num_inputs; ++i) if (!is_valid_elements_tx_input(tx->inputs + i)) return false; @@ -1539,6 +1543,9 @@ static int tx_get_lengths(const struct wally_tx *tx, *witness_count = 0; + if (!is_valid_tx(tx)) + return WALLY_EINVAL; + if (opts) { if (flags & WALLY_TX_FLAG_USE_WITNESS) return WALLY_ERROR; /* Segwit tx hashing uses bip143 opts member */ @@ -1566,7 +1573,7 @@ static int tx_get_lengths(const struct wally_tx *tx, } } - if ((flags & ~WALLY_TX_FLAG_USE_WITNESS) || + if ((flags & ~WALLY_TX_ALL_FLAGS) || ((flags & WALLY_TX_FLAG_USE_WITNESS) && wally_tx_get_witness_count(tx, witness_count) != WALLY_OK)) return WALLY_EINVAL; @@ -1984,11 +1991,17 @@ static int tx_to_bytes(const struct wally_tx *tx, if (written) *written = 0; - if (!is_valid_tx(tx) || !tx->num_inputs || !tx->num_outputs || - (flags & ~WALLY_TX_FLAG_USE_WITNESS) || !bytes_out || !written || + if (!is_valid_tx(tx) || !tx->num_inputs || + (flags & ~WALLY_TX_ALL_FLAGS) || !bytes_out || !written || tx_get_length(tx, opts, flags, &n, is_elements) != WALLY_OK) return WALLY_EINVAL; + /* If requested, 0-output txs can be written. 0-input txs are not + * currently supported since they conflict due to segwit tx markers + * when serialized */ + if (!(flags & WALLY_TX_FLAG_ALLOW_PARTIAL) && !tx->num_outputs) + return WALLY_EINVAL; + if (opts && (flags & WALLY_TX_FLAG_USE_WITNESS)) return WALLY_ERROR; /* Segwit tx hashing is handled elsewhere */ @@ -2231,8 +2244,7 @@ int analyze_tx(const unsigned char *bytes, size_t bytes_len, if (expect_witnesses) *expect_witnesses = false; - if (!bytes || bytes_len < sizeof(uint32_t) + 2 || - (flags & ~WALLY_TX_FLAG_USE_ELEMENTS) || + if (!bytes || bytes_len < sizeof(uint32_t) + 2 || (flags & ~WALLY_TX_ALL_FLAGS) || !num_inputs || !num_outputs || !expect_witnesses) return WALLY_EINVAL; @@ -2404,12 +2416,11 @@ static int witness_stack_from_bytes(const unsigned char *bytes, struct wally_tx_ } static int tx_from_bytes(const unsigned char *bytes, size_t bytes_len, - uint32_t flags, struct wally_tx **output, - bool is_elements) + uint32_t flags, struct wally_tx **output) { const unsigned char *p = bytes; + const bool is_elements = flags & WALLY_TX_FLAG_USE_ELEMENTS; bool expect_witnesses; - uint32_t analyze_flags = flags & ~WALLY_TX_FLAG_USE_WITNESS; size_t i, j, num_inputs, num_outputs; uint64_t tmp, num_witnesses; int ret; @@ -2417,7 +2428,7 @@ static int tx_from_bytes(const unsigned char *bytes, size_t bytes_len, TX_CHECK_OUTPUT; - if (analyze_tx(bytes, bytes_len, analyze_flags, &num_inputs, &num_outputs, + if (analyze_tx(bytes, bytes_len, flags, &num_inputs, &num_outputs, &expect_witnesses) != WALLY_OK) return WALLY_EINVAL; @@ -2576,7 +2587,7 @@ static int tx_from_bytes(const unsigned char *bytes, size_t bytes_len, int wally_tx_from_bytes(const unsigned char *bytes, size_t bytes_len, uint32_t flags, struct wally_tx **output) { - return tx_from_bytes(bytes, bytes_len, flags, output, flags & WALLY_TX_FLAG_USE_ELEMENTS); + return tx_from_bytes(bytes, bytes_len, flags, output); } int wally_tx_from_hex(const char *hex, uint32_t flags, @@ -2598,8 +2609,7 @@ int wally_tx_from_hex(const char *hex, uint32_t flags, } ret = wally_hex_to_bytes(hex, buff_p, bin_len, &written); if (ret == WALLY_OK) - ret = tx_from_bytes(buff_p, bin_len, flags, output, - flags & WALLY_TX_FLAG_USE_ELEMENTS); + ret = tx_from_bytes(buff_p, bin_len, flags, output); if (buff_p != buff) clear_and_free(buff_p, bin_len); @@ -2663,7 +2673,7 @@ static int tx_get_signature_hash(const struct wally_tx *tx, if (!is_valid_tx(tx) || BYTES_INVALID(script, script_len) || BYTES_INVALID(extra, extra_len) || satoshi > WALLY_SATOSHI_MAX || (sighash & 0xffffff00) || - (flags & ~WALLY_TX_FLAG_USE_WITNESS) || !bytes_out || len < SHA256_LEN) + (flags & ~WALLY_TX_ALL_FLAGS) || !bytes_out || len < SHA256_LEN) return WALLY_EINVAL; if (extra || extra_len || extra_offset) @@ -2843,7 +2853,7 @@ int wally_tx_elements_issuance_calculate_reissuance_token(const unsigned char *e { unsigned char buff[SHA256_LEN] = { 0 }; - if ((flags & ~(WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE))) + if ((flags & ~WALLY_TX_FLAG_BLINDED_INITIAL_ISSUANCE)) return WALLY_EINVAL; /* 32-byte '1' constant for unblinded and '2' for confidential */ From ac78bdcd23366273e0ee7fe7ce74dd8699a029cf Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 16:56:47 +1200 Subject: [PATCH 082/205] elements: Remove redundant vars and simplify code --- src/transaction.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/transaction.c b/src/transaction.c index 66874afc3..187ae1fd2 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -2785,28 +2785,25 @@ int wally_tx_elements_issuance_generate_entropy(const unsigned char *txhash, unsigned char *bytes_out, size_t len) { - unsigned char buff_1[2 * SHA256_LEN], *buff_p1 = buff_1; - unsigned char buff_2[WALLY_TXHASH_LEN + sizeof(uint32_t)], *buff_p2 = buff_2; - int ret = WALLY_OK; + unsigned char buff[2 * SHA256_LEN]; + unsigned char buff_2[WALLY_TXHASH_LEN + sizeof(uint32_t)]; + int ret; if (!txhash || txhash_len != WALLY_TXHASH_LEN || !contract_hash || contract_hash_len != SHA256_LEN || !bytes_out || len != SHA256_LEN) return WALLY_EINVAL; - memcpy(buff_p2, txhash, txhash_len); - buff_p2 += txhash_len; - buff_p2 += uint32_to_le_bytes(index, buff_p2); - - if ((ret = wally_sha256d(buff_2, WALLY_TXHASH_LEN + sizeof(uint32_t), buff_p1, SHA256_LEN)) != WALLY_OK) - goto fail; + memcpy(buff_2, txhash, txhash_len); + uint32_to_le_bytes(index, buff_2 + txhash_len); - memcpy(buff_p1 + SHA256_LEN, contract_hash, contract_hash_len); + ret = wally_sha256d(buff_2, sizeof(buff_2), buff, SHA256_LEN); + if (ret == WALLY_OK) { + memcpy(buff + SHA256_LEN, contract_hash, contract_hash_len); + ret = wally_sha256_midstate(buff, sizeof(buff), bytes_out, len); + } - ret = wally_sha256_midstate(buff_p1, 2 * SHA256_LEN, bytes_out, len); -fail: - wally_clear(buff_1, sizeof(buff_1)); - wally_clear(buff_2, sizeof(buff_2)); + wally_clear_2(buff, sizeof(buff), buff_2, sizeof(buff_2)); return ret; } @@ -2817,7 +2814,7 @@ static int tx_elements_token_from_bytes(const unsigned char *entropy, unsigned char *bytes_out, size_t len) { - unsigned char buff[2 * SHA256_LEN], *buff_p = buff; + unsigned char buff[2 * SHA256_LEN]; int ret; if (!entropy || entropy_len != SHA256_LEN || @@ -2825,10 +2822,10 @@ static int tx_elements_token_from_bytes(const unsigned char *entropy, !bytes_out || len != SHA256_LEN) return WALLY_EINVAL; - memcpy(buff_p, entropy, entropy_len); - memcpy(buff_p + SHA256_LEN, bytes, bytes_len); + memcpy(buff, entropy, entropy_len); + memcpy(buff + SHA256_LEN, bytes, bytes_len); - ret = wally_sha256_midstate(buff_p, sizeof(buff), bytes_out, len); + ret = wally_sha256_midstate(buff, sizeof(buff), bytes_out, len); wally_clear(buff, sizeof(buff)); return ret; From d92caca83c262f1feb0e5a7aa5abf05587d56c9e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 17:44:59 +1200 Subject: [PATCH 083/205] psbt: Allow partial transactions --- src/psbt.c | 2 +- src/test/data/psbt.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/psbt.c b/src/psbt.c index cf1368fed..468cc2368 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1809,7 +1809,7 @@ int wally_psbt_to_bytes( /* Global tx */ push_psbt_key(&cursor, &max, WALLY_PSBT_GLOBAL_UNSIGNED_TX, NULL, 0); - push_length_and_tx(&cursor, &max, psbt->tx, 0); + push_length_and_tx(&cursor, &max, psbt->tx, WALLY_TX_FLAG_ALLOW_PARTIAL); /* Unknowns */ if (psbt->unknowns) { diff --git a/src/test/data/psbt.json b/src/test/data/psbt.json index d17719b96..cb2fe8dd2 100644 --- a/src/test/data/psbt.json +++ b/src/test/data/psbt.json @@ -43,6 +43,11 @@ { "psbt": "cHNidP8BAD8CAAAAAf//////////////////////////////////////////AAAAAAD/////AQAAAAAAAAAAA2oBAAAAAAAACg8BAgMEBQYHCAkPAQIDBAUGBwgJCgsMDQ4PAAA=", "len": 101 + }, + { + "comment": "Partial transaction (with no outputs)", + "psbt": "cHNidP8BADMCAAAAAZCmTNqA77Z44FTcG0k2D2xkazaLwfTcYgkhBHT1hFy0AAAAAAD9////AGYAAAAAAQEgQEIPAAAAAAAXqRRlVyjzbP420BqlDTI2cERp+EpVQIcBBBYAFNa5adNt/9rZhpGT9mPuSA39xzSIAA==", + "len": 121 } ], "creator" : [ From 076ccc6254e3f7bcd0af4e9096b7fa097ac01a81 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 7 Jul 2020 17:48:11 +1200 Subject: [PATCH 084/205] psbt: Avoid magic numbers --- src/psbt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 468cc2368..491e43309 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1981,7 +1981,7 @@ static int merge_keypaths_into( for (i = 0; i < src->num_items; ++i) { bool found = false; for (j = 0; j < dst->num_items; ++j) { - if (memcmp(dst->items[j].pubkey, src->items[i].pubkey, 65) == 0) { + if (memcmp(dst->items[j].pubkey, src->items[i].pubkey, sizeof(src->items[i].pubkey)) == 0) { found = true; break; } @@ -2020,7 +2020,8 @@ static int merge_input_into( for (i = 0; i < src->partial_sigs->num_items; ++i) { bool found = false; for (j = 0; j < dst->partial_sigs->num_items; ++j) { - if (memcmp(dst->partial_sigs->items[j].pubkey, src->partial_sigs->items[i].pubkey, 65) == 0) { + if (memcmp(dst->partial_sigs->items[j].pubkey, src->partial_sigs->items[i].pubkey, + sizeof(src->partial_sigs->items[i].pubkey)) == 0) { found = true; break; } From b5cde6e16a000a345dd7ffd8977872f8e0e33e4e Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 29 May 2020 13:58:49 -0400 Subject: [PATCH 085/205] Check that pointers are non-null rather than length is non-zero Byte vectors in a PSBT could have a 0 length and thus result in duplicate keys in a PSBT as length 0 is also assumed that there is no vector for that field. Instead of checking length, check that the pointer is non-null. To ensure the pointers are non-null, malloc 1 byte. The length is still stored as 0. --- src/ctest/psbts.h | 16 ++++++++++++++++ src/psbt.c | 25 ++++++++++++++++++++----- src/test/data/psbt.json | 9 ++++++++- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/src/ctest/psbts.h b/src/ctest/psbts.h index 51864c0eb..510e9f96d 100644 --- a/src/ctest/psbts.h +++ b/src/ctest/psbts.h @@ -204,6 +204,22 @@ static const struct psbt_test invalid_psbts[] = { Base64 String: */ "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnQbVf4qHUa4A"}, + +/* The following are a bunch of PSBTs with duplicate 0 length scripts */ + { "70736274ff01002a02000000000140420f000000000017a9146e91b72d5593e7d4391e2ff44e91e985c31641f08700000000000100000100016a00", + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAQAAAQABagA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff000000000000010109ffffffffffffffff000101090000cafe000000000000", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJ//////////8AAQEJAADK/gAAAAAAAA=="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff000000000000010304addedfee0103040100000000", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQMErd7f7gEDBAEAAAAA"}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff0000000000000104000104016a00", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQQAAQQBagA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff00000000000001010900e1f50500000000000105000105015100", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQUAAQUBUQA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff0000000000000107000107015100", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQcAAQcBUQA="}, + { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff00000000000001010900e1f50500000000000108010001080301015100", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQgBAAEIAwEBUQA="}, }; /* The following are valid PSBTs: diff --git a/src/psbt.c b/src/psbt.c index 491e43309..c20778f7d 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1248,7 +1248,7 @@ static int pull_psbt_input( break; } case WALLY_PSBT_IN_REDEEM_SCRIPT: { - if (result->redeem_script_len != 0) { + if (result->redeem_script) { return WALLY_EINVAL; /* Already have a redeem script */ } subfield_nomore_end(cursor, max, key, key_len); @@ -1258,10 +1258,13 @@ static int pull_psbt_input( cursor, max)) { return WALLY_ENOMEM; } + if (result->redeem_script_len == 0) { + result->redeem_script = wally_malloc(1); + } break; } case WALLY_PSBT_IN_WITNESS_SCRIPT: { - if (result->witness_script_len != 0) { + if (result->witness_script) { return WALLY_EINVAL; /* Already have a witness script */ } subfield_nomore_end(cursor, max, key, key_len); @@ -1271,6 +1274,9 @@ static int pull_psbt_input( cursor, max)) { return WALLY_ENOMEM; } + if (result->witness_script_len == 0) { + result->witness_script = wally_malloc(1); + } break; } case WALLY_PSBT_IN_BIP32_DERIVATION: { @@ -1281,7 +1287,7 @@ static int pull_psbt_input( break; } case WALLY_PSBT_IN_FINAL_SCRIPTSIG: { - if (result->final_script_sig_len != 0) { + if (result->final_script_sig) { return WALLY_EINVAL; /* Already have a scriptSig */ } subfield_nomore_end(cursor, max, key, key_len); @@ -1291,6 +1297,9 @@ static int pull_psbt_input( cursor, max)) { return WALLY_ENOMEM; } + if (result->final_script_sig_len == 0) { + result->final_script_sig = wally_malloc(1); + } break; } case WALLY_PSBT_IN_FINAL_SCRIPTWITNESS: { @@ -1368,7 +1377,7 @@ static int pull_psbt_output( /* Process based on type */ switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_OUT_REDEEM_SCRIPT: { - if (result->redeem_script_len != 0) { + if (result->redeem_script) { return WALLY_EINVAL; /* Already have a redeem script */ } subfield_nomore_end(cursor, max, key, key_len); @@ -1378,10 +1387,13 @@ static int pull_psbt_output( cursor, max)) { return WALLY_ENOMEM; } + if (result->redeem_script_len == 0) { + result->redeem_script = wally_malloc(1); + } break; } case WALLY_PSBT_OUT_WITNESS_SCRIPT: { - if (result->witness_script_len != 0) { + if (result->witness_script) { return WALLY_EINVAL; /* Already have a witness script */ } subfield_nomore_end(cursor, max, key, key_len); @@ -1391,6 +1403,9 @@ static int pull_psbt_output( cursor, max)) { return WALLY_ENOMEM; } + if (result->witness_script_len == 0) { + result->witness_script = wally_malloc(1); + } break; } case WALLY_PSBT_OUT_BIP32_DERIVATION: { diff --git a/src/test/data/psbt.json b/src/test/data/psbt.json index cb2fe8dd2..f5482c981 100644 --- a/src/test/data/psbt.json +++ b/src/test/data/psbt.json @@ -17,7 +17,14 @@ "cHNidP8BAJoCAAAAAljoeiG1ba8MI76OcHBFbDNvfLqlyHV5JPVFiHuyq911AAAAAAD/////g40EJ9DsZQpoqka7CwmK6kQiwHGyyng1Kgd5WdB86h0BAAAAAP////8CcKrwCAAAAAAWABTYXCtx0AYLCcmIauuBXlCZHdoSTQDh9QUAAAAAFgAUAK6pouXw+HaliN9VRuh0LR2HAI8AAAAAAAEAuwIAAAABqtc5MQGL0l+ErkALaISL4J23BurCrBgpi6vucatlb4sAAAAASEcwRAIgWPb8fGoz4bMVSNSByCbAFb0wE1qtQs1neQ2rZtKtJDsCIEoc7SYExnNbY5PltBaR3XiwDwxZQvufdRhW+qk4FX26Af7///8CgPD6AgAAAAAXqRQPuUY0IWlrgsgzryQceMF9295JNIfQ8gonAQAAABepFCnKdPigj4GZlCgYXJe12FLkBj9hh2UAAAABB9oARzBEAiB0AYrUGACXuHMyPAAVcgs2hMyBI4kQSOfbzZtVrWecmQIgc9Npt0Dj61Pc76M4I8gHBRTKVafdlUTxV8FnkTJhEYwBSDBFAiEA9hA4swjcHahlo0hSdG8BV3KTQgjG0kRUOTzZm98iF3cCIAVuZ1pnWm0KArhbFOXikHTYolqbV2C+ooFvZhkQoAbqAUdSIQKVg785rgpgl0etGZrd1jT6YQhVnWxc05tMIYPxq5bgfyEC2rYf9JoU22p9ArDNH7t4/EsYMStbTlTa5Nui+/71NtdSrgABASAAwusLAAAAABepFLf1+vQOPUClpFmx2zU18rcvqSHohwEHIyIAIIwjUxc3Q7WV37Sge3K6jkLjeX2nTof+fZ10l+OyAokDAQjaBABHMEQCIGLrelVhB6fHP0WsSrWh3d9vcHX7EnWWmn84Pv/3hLyyAiAMBdu3Rw2/LwhVfdNWxzJcHtMJE+mWzThAlF2xIijaXwFHMEQCIGX0W6WZi1mif/4ae+0BavHx+Q1Us6qPdFCqX1aiUQO9AiB/ckcDrR7blmgLKEtW1P/LiPf7dZ6rvgiqMPKbhROD0gFHUiEDCJ3BDHrG21T5EymvYXMz2ziM6tDCMfcjN50bmQMLAtwhAjrdkE89bc9Z3bkGsN7iNSm3/7ntUOXoYVGSaGAiHw5zUq4AIQIDqaTDf1mW06ol26xrVwrwZQOUSSlCRgs1R1PtnuylhxDZDGpPAAAAgAAAAIAEAACAACICAn9jmXV9Lv9VoTatAsaEsYOLZVbl8bazQoKpS2tQBRCWENkMak8AAACAAAAAgAUAAIAA", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", - "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A" + "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", + "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAQAAAQABagA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJ//////////8AAQEJAADK/gAAAAAAAA==", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQMErd7f7gEDBAEAAAAA", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQQAAQQBagA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQUAAQUBUQA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQcAAQcBUQA=", + "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQgBAAEIAwEBUQA=" ], "valid" : [ { From 7b6ac5c2d22f27418009eaf283141762f7d4ba3b Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 29 May 2020 14:49:41 -0400 Subject: [PATCH 086/205] Implement psbt global version type --- include/wally_psbt.h | 5 +++++ src/ctest/psbts.h | 5 +++++ src/psbt.c | 33 +++++++++++++++++++++++++++++++++ src/test/data/psbt.json | 1 + src/test/util.py | 3 ++- 5 files changed, 46 insertions(+), 1 deletion(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index b4c397254..b86cac072 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -11,6 +11,7 @@ extern "C" { #define WALLY_PSBT_SEPARATOR 0x00 #define WALLY_PSBT_GLOBAL_UNSIGNED_TX 0x00 +#define WALLY_PSBT_GLOBAL_VERSION 0xFB #define WALLY_PSBT_IN_NON_WITNESS_UTXO 0x00 #define WALLY_PSBT_IN_WITNESS_UTXO 0x01 @@ -26,6 +27,9 @@ extern "C" { #define WALLY_PSBT_OUT_WITNESS_SCRIPT 0x01 #define WALLY_PSBT_OUT_BIP32_DERIVATION 0x02 +/* PSBT Version number */ +#define WALLY_PSBT_HIGHEST_VERSION 0 + #ifdef SWIG struct wally_keypath_map; struct wally_partial_sigs_map; @@ -116,6 +120,7 @@ struct wally_psbt { size_t num_outputs; size_t outputs_allocation_len; struct wally_unknowns_map *unknowns; + uint32_t version; }; #endif /* SWIG */ diff --git a/src/ctest/psbts.h b/src/ctest/psbts.h index 510e9f96d..375223386 100644 --- a/src/ctest/psbts.h +++ b/src/ctest/psbts.h @@ -220,6 +220,11 @@ static const struct psbt_test invalid_psbts[] = { "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQcAAQcBUQA="}, { "70736274ff0100330100000001111111111111111111111111111111111111facade11111111111111111111117f00000000ffffffff00000000000001010900e1f50500000000000108010001080301015100", "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJAOH1BQAAAAAAAQgBAAEIAwEBUQA="}, + +/* Unsupported version number */ + { "70736274ff01fb04010000000100750200000001268171371edff285e937adeea4b37b78000c0566cbb3ad64641713ca42171bf60000000000feffffff02d3dff505000000001976a914d0c59903c5bac2868760e90fd521a4665aa7652088ac00e1f5050000000017a9143545e6e33b832c47050f24d3eeb93c9c03948bc787b32e1300000100fda5010100000000010289a3c71eab4d20e0371bbba4cc698fa295c9463afa2e397f8533ccb62f9567e50100000017160014be18d152a9b012039daf3da7de4f53349eecb985ffffffff86f8aa43a71dff1448893a530a7237ef6b4608bbb2dd2d0171e63aec6a4890b40100000017160014fe3e9ef1a745e974d902c4355943abcb34bd5353ffffffff0200c2eb0b000000001976a91485cff1097fd9e008bb34af709c62197b38978a4888ac72fef84e2c00000017a914339725ba21efd62ac753a9bcd067d6c7a6a39d05870247304402202712be22e0270f394f568311dc7ca9a68970b8025fdd3b240229f07f8a5f3a240220018b38d7dcd314e734c9276bd6fb40f673325bc4baa144c800d2f2f02db2765c012103d2e15674941bad4a996372cb87e1856d3652606d98562fe39c5e9e7e413f210502483045022100d12b852d85dcd961d2f5f4ab660654df6eedcc794c0c33ce5cc309ffb5fce58d022067338a8e0e1725c197fb1a88af59f51e44e4255b20167c8684031c05d1f2592a01210223b72beef0965d10be0778efecd61fcac6f79a4ea169393380734464f84f2ab300000000000000", + "cHNidP8B+wQBAAAAAQB1AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAAAA/v///wLT3/UFAAAAABl2qRTQxZkDxbrChodg6Q/VIaRmWqdlIIisAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4ezLhMAAAEA/aUBAQAAAAABAomjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAABcWABS+GNFSqbASA52vPafeT1M0nuy5hf////+G+KpDpx3/FEiJOlMKcjfva0YIu7LdLQFx5jrsakiQtAEAAAAXFgAU/j6e8adF6XTZAsQ1WUOryzS9U1P/////AgDC6wsAAAAAGXapFIXP8Ql/2eAIuzSvcJxiGXs4l4pIiKxy/vhOLAAAABepFDOXJboh79Yqx1OpvNBn1semo50FhwJHMEQCICcSviLgJw85T1aDEdx8qaaJcLgCX907JAIp8H+KXzokAiABizjX3NMU5zTJJ2vW+0D2czJbxLqhRMgA0vLwLbJ2XAEhA9LhVnSUG61KmWNyy4fhhW02UmBtmFYv45xenn5BPyEFAkgwRQIhANErhS2F3Nlh0vX0q2YGVN9u7cx5TAwzzlzDCf+1/OWNAiBnM4qODhclwZf7GoivWfUeROQlWyAWfIaEAxwF0fJZKgEhAiO3K+7wll0Qvgd47+zWH8rG95pOoWk5M4BzRGT4TyqzAAAAAAAAAA=="}, + }; /* The following are valid PSBTs: diff --git a/src/psbt.c b/src/psbt.c index c20778f7d..69cd60802 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -746,6 +746,8 @@ int wally_psbt_init_alloc( return ret != WALLY_OK ? ret : WALLY_ENOMEM; } + /* Version is always 0 */ + result->version = 0; result->inputs_allocation_len = inputs_allocation_len; result->outputs_allocation_len = outputs_allocation_len; result->tx = NULL; @@ -1031,6 +1033,11 @@ static int count_psbt_parts( } break; } + case WALLY_PSBT_GLOBAL_VERSION: + pull_subfield_end(&bytes, &bytes_len, key, key_len); + /* Skip over value */ + pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); + break; /* Unknowns */ default: result->num_global_unknowns++; @@ -1503,6 +1510,25 @@ int wally_psbt_from_bytes( } break; } + case WALLY_PSBT_GLOBAL_VERSION: { + if (result->version > 0) { + ret = WALLY_EINVAL; /* Version already provided */ + goto fail; + } + subfield_nomore_end(&bytes, &bytes_len, key, key_len); + + /* Start parsing the value field. */ + pull_subfield_start(&bytes, &bytes_len, + pull_varint(&bytes, &bytes_len), + &val, &val_max); + result->version = pull_le32(&val, &val_max); + subfield_nomore_end(&bytes, &bytes_len, val, val_max); + if (result->version > WALLY_PSBT_HIGHEST_VERSION) { + ret = WALLY_EINVAL; /* Unsupported version number */ + goto fail; + } + break; + } /* Unknowns */ default: { ret = pull_unknown_key_value(&bytes, &bytes_len, pre_key, @@ -1826,6 +1852,13 @@ int wally_psbt_to_bytes( push_psbt_key(&cursor, &max, WALLY_PSBT_GLOBAL_UNSIGNED_TX, NULL, 0); push_length_and_tx(&cursor, &max, psbt->tx, WALLY_TX_FLAG_ALLOW_PARTIAL); + /* version */ + if (psbt->version > 0) { + push_psbt_key(&cursor, &max, WALLY_PSBT_GLOBAL_VERSION, NULL, 0); + push_varint(&cursor, &max, sizeof(uint32_t)); + push_le32(&cursor, &max, psbt->version); + } + /* Unknowns */ if (psbt->unknowns) { for (i = 0; i < psbt->unknowns->num_items; ++i) { diff --git a/src/test/data/psbt.json b/src/test/data/psbt.json index f5482c981..791f4e44a 100644 --- a/src/test/data/psbt.json +++ b/src/test/data/psbt.json @@ -18,6 +18,7 @@ "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wCAwABAAAAAAEAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAgAAFgAUYunpgv/zTdgjlhAxawkM0qO3R8sAAQAiACCHa62DLx0WgBXtQSMqnqZaGBXZ7xPA74dZ9ktbKyeKZQEBJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", "cHNidP8BAHMCAAAAATAa6YblFqHsisW0vGVz0y+DtGXiOtdhZ9aLOOcwtNvbAAAAAAD/////AnR7AQAAAAAAF6kUA6oXrogrXQ1Usl1jEE5P/s57nqKHYEOZOwAAAAAXqRS5IbG6b3IuS/qDtlV6MTmYakLsg4cAAAAAAAEBHwDKmjsAAAAAFgAU0tlLZK4IWH7vyO6xh8YB6Tn5A3wAAQAWABRi6emC//NN2COWEDFrCQzSo7dHywABACIAIIdrrYMvHRaAFe1BIyqeploYFdnvE8Dvh1n2S1srJ4plIQEAJVEhA7fOI6AcW0vwCmQlN836uzFbZoMyhnR471EwnSvVf4qHUa4A", + "cHNidP8B+wQBAAAAAQB1AgAAAAEmgXE3Ht/yhek3re6ks3t4AAwFZsuzrWRkFxPKQhcb9gAAAAAA/v///wLT3/UFAAAAABl2qRTQxZkDxbrChodg6Q/VIaRmWqdlIIisAOH1BQAAAAAXqRQ1RebjO4MsRwUPJNPuuTycA5SLx4ezLhMAAAEA/aUBAQAAAAABAomjxx6rTSDgNxu7pMxpj6KVyUY6+i45f4UzzLYvlWflAQAAABcWABS+GNFSqbASA52vPafeT1M0nuy5hf////+G+KpDpx3/FEiJOlMKcjfva0YIu7LdLQFx5jrsakiQtAEAAAAXFgAU/j6e8adF6XTZAsQ1WUOryzS9U1P/////AgDC6wsAAAAAGXapFIXP8Ql/2eAIuzSvcJxiGXs4l4pIiKxy/vhOLAAAABepFDOXJboh79Yqx1OpvNBn1semo50FhwJHMEQCICcSviLgJw85T1aDEdx8qaaJcLgCX907JAIp8H+KXzokAiABizjX3NMU5zTJJ2vW+0D2czJbxLqhRMgA0vLwLbJ2XAEhA9LhVnSUG61KmWNyy4fhhW02UmBtmFYv45xenn5BPyEFAkgwRQIhANErhS2F3Nlh0vX0q2YGVN9u7cx5TAwzzlzDCf+1/OWNAiBnM4qODhclwZf7GoivWfUeROQlWyAWfIaEAxwF0fJZKgEhAiO3K+7wll0Qvgd47+zWH8rG95pOoWk5M4BzRGT4TyqzAAAAAAAAAA==", "cHNidP8BACoCAAAAAAFAQg8AAAAAABepFG6Rty1Vk+fUOR4v9E6R6YXDFkHwhwAAAAAAAQAAAQABagA=", "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQEJ//////////8AAQEJAADK/gAAAAAAAA==", "cHNidP8BADMBAAAAAREREREREREREREREREREREREfrK3hERERERERERERERfwAAAAD/////AAAAAAAAAQMErd7f7gEDBAEAAAAA", diff --git a/src/test/util.py b/src/test/util.py index ed02de55c..9509c3bee 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -175,7 +175,8 @@ class wally_psbt(Structure): ('outputs', POINTER(wally_psbt_output)), ('num_outputs', c_ulong), ('outputs_allocation_len', c_ulong), - ('unknowns', POINTER(unknowns_map))] + ('unknowns', POINTER(unknowns_map)), + ('version', c_ulong)] for f in ( ('wally_init', c_int, [c_uint]), From 2860e25ccf67a96ee75fa15c121a8404cf95a235 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 14 May 2020 19:51:03 -0400 Subject: [PATCH 087/205] Add wally_psbt_elements_input_init_alloc and elements fields setters --- include/wally_psbt.h | 189 ++++++++++++++++++++++++++++++++++++ src/psbt.c | 222 +++++++++++++++++++++++++++++++++++++++++++ src/test/util.py | 17 +++- 3 files changed, 427 insertions(+), 1 deletion(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index b86cac072..dd765d063 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -98,6 +98,23 @@ struct wally_psbt_input { struct wally_partial_sigs_map *partial_sigs; struct wally_unknowns_map *unknowns; uint32_t sighash_type; +#ifdef BUILD_ELEMENTS + uint64_t value; + bool has_value; + unsigned char *value_blinder; + size_t value_blinder_len; + unsigned char *asset; + size_t asset_len; + unsigned char *asset_blinder; + size_t asset_blinder_len; + struct wally_tx *peg_in_tx; + unsigned char *txout_proof; + size_t txout_proof_len; + unsigned char *genesis_hash; + size_t genesis_hash_len; + unsigned char *claim_script; + size_t claim_script_len; +#endif /* BUILD_ELEMENTS */ }; /** A PSBT output map */ @@ -599,6 +616,178 @@ WALLY_CORE_API int wally_extract_psbt( const struct wally_psbt *psbt, struct wally_tx **output); +#ifdef BUILD_ELEMENTS +/** + * Allocate and initialize a new elements psbt. + * + * :param inputs_allocation_len: The number of inputs to pre-allocate space for. + * :param outputs_allocation_len: The number of outputs to pre-allocate space for. + * :param global_unknowns_allocation_len: The number of global unknowns to allocate space for. + * :param output: Destination for the resulting psbt output. + */ +WALLY_CORE_API int wally_psbt_elements_init_alloc( + size_t inputs_allocation_len, + size_t outputs_allocation_len, + size_t global_unknowns_allocation_len, + struct wally_psbt **output); + +/** + * Allocate and initialize a new psbt elements input. + * + * :param non_witness_utxo: The non witness utxo for this input if it exists. + * :param witness_utxo: The witness utxo for this input if it exists. + * :param redeem_script: The redeem script for this input + * :param redeem_script_len: The length of the redeem script. + * :param witness_script: The witness script for this input + * :param witness_script_len: The length of the witness script. + * :param final_script_sig: The scriptSig for this input + * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. + * :param final_witness: The witness stack for the input, or NULL if no witness is present. + * :param keypaths: The HD keypaths for this input. + * :param partial_sigs: The partial signatures for this input. + * :param unknowns: The unknown key value pairs for this input. + * :param sighash_type: The sighash type for this input + * :param value: The value for this input + * :param value_blinder: The value blinder for ths input + * :param value_blinder_len: The length of the value_blinder. + * :param asset: The witness script for this input + * :param asset_len: The length of the witness script. + * :param asset_blinder: The witness script for this input + * :param asset_blinder__len: The length of the witness script. + * :param peg_in_tx: The witness script for this input + * :param txout_proof: The witness script for this input + * :param txout_proof_len: The length of the witness script. + * :param genesis_hash: The witness script for this input + * :param genesis_hash_len: The length of the witness script. + * :param claim_script: The witness script for this input + * :param claim_script_len: The length of the witness script. + * :param output: Destination for the resulting psbt input. + */ +WALLY_CORE_API int wally_psbt_elements_input_init_alloc( + struct wally_tx *non_witness_utxo, + struct wally_tx_output *witness_utxo, + unsigned char *redeem_script, + size_t redeem_script_len, + unsigned char *witness_script, + size_t witness_script_len, + unsigned char *final_script_sig, + size_t final_script_sig_len, + struct wally_tx_witness_stack *final_witness, + struct wally_keypath_map *keypaths, + struct wally_partial_sigs_map *partial_sigs, + struct wally_unknowns_map *unknowns, + uint32_t sighash_type, + uint64_t value, + bool has_value, + unsigned char *value_blinder, + size_t value_blinder_len, + unsigned char *asset, + size_t asset_len, + unsigned char *asset_blinder, + size_t asset_blinder_len, + struct wally_tx *peg_in_tx, + unsigned char *txout_proof, + size_t txout_proof_len, + unsigned char *genesis_hash, + size_t genesis_hash_len, + unsigned char *claim_script, + size_t claim_script_len, + struct wally_psbt_input **output); + +/** + * Set the value in an elements input + * + * :param input: The input to update. + * :param value: The value for this input + */ +WALLY_CORE_API int wally_psbt_elements_input_set_value( + struct wally_psbt_input *input, + uint64_t value); + +/** + * Set the value blinder in an elements input + * + * :param input: The input to update. + * :param value_blinder: The value blinder for this input + * :param value_blinder_len: The length of the value blinder. + */ +WALLY_CORE_API int wally_psbt_elements_input_set_value_blinder( + struct wally_psbt_input *input, + unsigned char *value_blinder, + size_t value_blinder_len); + +/** + * Set the asset in an elements input + * + * :param input: The input to update. + * :param asset: The asset for this input + * :param asset_len: The length of the asset + */ +WALLY_CORE_API int wally_psbt_elements_input_set_asset( + struct wally_psbt_input *input, + unsigned char *asset, + size_t asset_len); + +/** + * Set the asset blinder in an elements input + * + * :param input: The input to update. + * :param asset_blinder: The asset blinder for this input + * :param asset_blinder_len: The length of the asset blinder. + */ +WALLY_CORE_API int wally_psbt_elements_input_set_asset_blinder( + struct wally_psbt_input *input, + unsigned char *asset_blinder, + size_t asset_blinder_len); + +/** + * Set the peg in tx in an input + * + * :param input: The input to update. + * :param peg_in_tx: The peg in tx for this input if it exists. + */ +WALLY_CORE_API int wally_psbt_elements_input_set_peg_in_tx( + struct wally_psbt_input *input, + struct wally_tx *peg_in_tx); + +/** + * Set the txout proof in an elements input + * + * :param input: The input to update. + * :param txout_proof: The txout proof for this input + * :param txout_proof_len: The length of the txout proof. + */ +WALLY_CORE_API int wally_psbt_elements_input_set_txout_proof( + struct wally_psbt_input *input, + unsigned char *txout_proof, + size_t txout_proof_len); + +/** + * Set the genesis hash in an elements input + * + * :param input: The input to update. + * :param genesis_hash: The genesis hash for this input + * :param genesis_hash_len: The length of the genesis hash. + */ +WALLY_CORE_API int wally_psbt_elements_input_set_genesis_hash( + struct wally_psbt_input *input, + unsigned char *genesis_hash, + size_t genesis_hash_len); + +/** + * Set the claim script in an elements input + * + * :param input: The input to update. + * :param claim_script: The claim script for this input + * :param claim_script_len: The length of the claim_script. + */ +WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( + struct wally_psbt_input *input, + unsigned char *claim_script, + size_t claim_script_len); + +#endif /* BUILD_ELEMENTS */ + #ifdef __cplusplus } #endif diff --git a/src/psbt.c b/src/psbt.c index 69cd60802..a1ee28f5b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -435,6 +435,94 @@ int wally_psbt_input_init_alloc( return ret; } +#ifdef BUILD_ELEMENTS +int wally_psbt_elements_input_init_alloc( + struct wally_tx *non_witness_utxo, + struct wally_tx_output *witness_utxo, + unsigned char *redeem_script, + size_t redeem_script_len, + unsigned char *witness_script, + size_t witness_script_len, + unsigned char *final_script_sig, + size_t final_script_sig_len, + struct wally_tx_witness_stack *final_witness, + struct wally_keypath_map *keypaths, + struct wally_partial_sigs_map *partial_sigs, + struct wally_unknowns_map *unknowns, + uint32_t sighash_type, + uint64_t value, + bool has_value, + unsigned char *value_blinder, + size_t value_blinder_len, + unsigned char *asset, + size_t asset_len, + unsigned char *asset_blinder, + size_t asset_blinder_len, + struct wally_tx *peg_in_tx, + unsigned char *txout_proof, + size_t txout_proof_len, + unsigned char *genesis_hash, + size_t genesis_hash_len, + unsigned char *claim_script, + size_t claim_script_len, + struct wally_psbt_input **output) +{ + struct wally_psbt_input *result; + int ret = wally_psbt_input_init_alloc(non_witness_utxo, + witness_utxo, + redeem_script, + redeem_script_len, + witness_script, + witness_script_len, + final_script_sig, + final_script_sig_len, + final_witness, + keypaths, + partial_sigs, + unknowns, + sighash_type, + output); + if (ret != WALLY_OK) { + return ret; + } + + /* wally_psbt_input_init_alloc will allocate and initialize the input */ + result = *output; + + if (has_value && (ret = wally_psbt_elements_input_set_value(result, value)) != WALLY_OK) { + goto fail; + } + if (value_blinder && (ret = wally_psbt_elements_input_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) { + goto fail; + } + if (asset && (ret = wally_psbt_elements_input_set_asset(result, asset, asset_len)) != WALLY_OK) { + goto fail; + } + if (asset_blinder && (ret = wally_psbt_elements_input_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) { + goto fail; + } + if (peg_in_tx && (ret = wally_psbt_elements_input_set_peg_in_tx(result, peg_in_tx)) != WALLY_OK) { + goto fail; + } + if (txout_proof && (ret = wally_psbt_elements_input_set_txout_proof(result, txout_proof, txout_proof_len)) != WALLY_OK) { + goto fail; + } + if (genesis_hash && (ret = wally_psbt_elements_input_set_genesis_hash(result, genesis_hash, genesis_hash_len)) != WALLY_OK) { + goto fail; + } + if (claim_script && (ret = wally_psbt_elements_input_set_claim_script(result, claim_script, claim_script_len)) != WALLY_OK) { + goto fail; + } + + return ret; + +fail: + wally_psbt_input_free(result); + *output = NULL; + return ret; +} +#endif /* BUILD_ELEMENTS */ + int wally_psbt_input_set_non_witness_utxo( struct wally_psbt_input *input, struct wally_tx *non_witness_utxo) @@ -577,6 +665,129 @@ int wally_psbt_input_set_sighash_type( return WALLY_OK; } +#ifdef BUILD_ELEMENTS +int wally_psbt_elements_input_set_value( + struct wally_psbt_input *input, + uint64_t value) +{ + input->value = value; + input->has_value = true; + return WALLY_OK; +} + +int wally_psbt_elements_input_set_value_blinder( + struct wally_psbt_input *input, + unsigned char *value_blinder, + size_t value_blinder_len) +{ + unsigned char *result_value_blinder; + + if (!clone_bytes(&result_value_blinder, value_blinder, value_blinder_len)) { + return WALLY_ENOMEM; + } + wally_free(input->value_blinder); + input->value_blinder = value_blinder; + input->value_blinder_len = value_blinder_len; + return WALLY_OK; +} + +int wally_psbt_elements_input_set_asset( + struct wally_psbt_input *input, + unsigned char *asset, + size_t asset_len) +{ + unsigned char *result_asset; + + if (!clone_bytes(&result_asset, asset, asset_len)) { + return WALLY_ENOMEM; + } + wally_free(input->asset); + input->asset = asset; + input->asset_len = asset_len; + return WALLY_OK; +} + +int wally_psbt_elements_input_set_asset_blinder( + struct wally_psbt_input *input, + unsigned char *asset_blinder, + size_t asset_blinder_len) +{ + unsigned char *result_asset_blinder; + + if (!clone_bytes(&result_asset_blinder, asset_blinder, asset_blinder_len)) { + return WALLY_ENOMEM; + } + wally_free(input->asset_blinder); + input->asset_blinder = asset_blinder; + input->asset_blinder_len = asset_blinder_len; + return WALLY_OK; +} + +int wally_psbt_elements_input_set_peg_in_tx( + struct wally_psbt_input *input, + struct wally_tx *peg_in_tx) +{ + int ret = WALLY_OK; + struct wally_tx *result_peg_in_tx; + + if ((ret = wally_tx_clone(peg_in_tx, 0, &result_peg_in_tx)) != WALLY_OK) { + return ret; + } + wally_tx_free(input->peg_in_tx); + input->peg_in_tx = peg_in_tx; + return ret; +} + + +int wally_psbt_elements_input_set_txout_proof( + struct wally_psbt_input *input, + unsigned char *txout_proof, + size_t txout_proof_len) +{ + unsigned char *result_txout_proof; + + if (!clone_bytes(&result_txout_proof, txout_proof, txout_proof_len)) { + return WALLY_ENOMEM; + } + wally_free(input->txout_proof); + input->txout_proof = txout_proof; + input->txout_proof_len = txout_proof_len; + return WALLY_OK; +} + +int wally_psbt_elements_input_set_genesis_hash( + struct wally_psbt_input *input, + unsigned char *genesis_hash, + size_t genesis_hash_len) +{ + unsigned char *result_genesis_hash; + + if (!clone_bytes(&result_genesis_hash, genesis_hash, genesis_hash_len)) { + return WALLY_ENOMEM; + } + wally_free(input->genesis_hash); + input->genesis_hash = genesis_hash; + input->genesis_hash_len = genesis_hash_len; + return WALLY_OK; +} + +int wally_psbt_elements_input_set_claim_script( + struct wally_psbt_input *input, + unsigned char *claim_script, + size_t claim_script_len) +{ + unsigned char *result_claim_script; + + if (!clone_bytes(&result_claim_script, claim_script, claim_script_len)) { + return WALLY_ENOMEM; + } + wally_free(input->claim_script); + input->claim_script = claim_script; + input->claim_script_len = claim_script_len; + return WALLY_OK; +} +#endif /* BUILD_ELEMENTS */ + static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) { if (input) { @@ -589,6 +800,17 @@ static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) wally_keypath_map_free(input->keypaths); wally_partial_sigs_map_free(input->partial_sigs); wally_unknowns_map_free(input->unknowns); + +#ifdef BUILD_ELEMENTS + clear_and_free(input->value_blinder, input->value_blinder_len); + clear_and_free(input->asset, input->asset_len); + clear_and_free(input->asset_blinder, input->asset_blinder_len); + wally_tx_free(input->peg_in_tx); + clear_and_free(input->txout_proof, input->txout_proof_len); + clear_and_free(input->genesis_hash, input->genesis_hash_len); + clear_and_free(input->claim_script, input->claim_script_len); +#endif /* BUILD_ELEMENTS */ + wally_clear(input, sizeof(*input)); if (free_parent) wally_free(input); diff --git a/src/test/util.py b/src/test/util.py index 9509c3bee..7f94db4cc 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -157,7 +157,22 @@ class wally_psbt_input(Structure): ('keypaths', POINTER(keypath_map)), ('partial_sigs', POINTER(partial_sigs_map)), ('unknowns', POINTER(unknowns_map)), - ('sighash_type', c_ulong)] + ('sighash_type', c_ulong), + ('value', c_ulonglong), + ('has_value', c_ulong), + ('value_blinder', c_void_p), + ('value_blinder_len', c_ulong), + ('asset', c_void_p), + ('asset_len', c_ulong), + ('asset_blinder', c_void_p), + ('asset_blinder_len', c_ulong), + ('peg_in_tx', POINTER(wally_tx)), + ('txout_proof', c_void_p), + ('txout_proof_len', c_ulong), + ('genesis_hash', c_void_p), + ('genesis_hash_len', c_ulong), + ('claim_script', c_void_p), + ('claim_script_len', c_ulong)] class wally_psbt_output(Structure): _fields_ = [('redeem_script', c_void_p), From edf37aac647043d3cfce992455c3f06e56c0869a Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 11:10:50 +1200 Subject: [PATCH 088/205] psbt: Avoid bool type in public interface --- include/wally_psbt.h | 4 ++-- src/psbt.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index dd765d063..f7cad5d2b 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -100,7 +100,7 @@ struct wally_psbt_input { uint32_t sighash_type; #ifdef BUILD_ELEMENTS uint64_t value; - bool has_value; + uint32_t has_value; unsigned char *value_blinder; size_t value_blinder_len; unsigned char *asset; @@ -678,7 +678,7 @@ WALLY_CORE_API int wally_psbt_elements_input_init_alloc( struct wally_unknowns_map *unknowns, uint32_t sighash_type, uint64_t value, - bool has_value, + uint32_t has_value, unsigned char *value_blinder, size_t value_blinder_len, unsigned char *asset, diff --git a/src/psbt.c b/src/psbt.c index a1ee28f5b..885cc197b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -451,7 +451,7 @@ int wally_psbt_elements_input_init_alloc( struct wally_unknowns_map *unknowns, uint32_t sighash_type, uint64_t value, - bool has_value, + uint32_t has_value, unsigned char *value_blinder, size_t value_blinder_len, unsigned char *asset, @@ -671,7 +671,7 @@ int wally_psbt_elements_input_set_value( uint64_t value) { input->value = value; - input->has_value = true; + input->has_value = 1u; return WALLY_OK; } From 34982cb59ef11b5383388fc4adb3e2d02e08acd4 Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Thu, 14 May 2020 20:46:20 -0400 Subject: [PATCH 089/205] Add wally_psbt_elements_output_init_alloc and field setters --- include/wally_psbt.h | 163 +++++++++++++++++++++++++++++++++ src/psbt.c | 209 +++++++++++++++++++++++++++++++++++++++++++ src/test/util.py | 18 +++- 3 files changed, 389 insertions(+), 1 deletion(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index f7cad5d2b..39fbfebf3 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -125,6 +125,24 @@ struct wally_psbt_output { size_t witness_script_len; struct wally_keypath_map *keypaths; struct wally_unknowns_map *unknowns; +#ifdef BUILD_ELEMENTS + unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; + bool has_blinding_pubkey; + unsigned char *value_commitment; + size_t value_commitment_len; + unsigned char *value_blinder; + size_t value_blinder_len; + unsigned char *asset_commitment; + size_t asset_commitment_len; + unsigned char *asset_blinder; + size_t asset_blinder_len; + unsigned char *nonce_commitment; + size_t nonce_commitment_len; + unsigned char *range_proof; + size_t range_proof_len; + unsigned char *surjection_proof; + size_t surjection_proof_len; +#endif /* BUILD_ELEMENTS */ }; /** A partially signed bitcoin transaction */ @@ -786,6 +804,151 @@ WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( unsigned char *claim_script, size_t claim_script_len); +/** + * Allocate and initialize a new psbt elements output. + * + * :param redeem_script: The redeem script needed for spending this output + * :param redeem_script_len: The length of the redeem script. + * :param witness_script: The witness script needed for spending for this output + * :param witness_script_len: The length of the witness script. + * :param keypaths: The HD keypaths for the keys needed for spending this output + * :param unknowns: The unknown key value pairs for this output. + * :param blinding_pubkey: The blinding pubkey for this output + * :param value_commitment: The value commitment for this output + * :param value_commitment_len: The length of the witness script. + * :param value_blinder: The value blinder for this output + * :param value_blinder_len: The length of the value blinder. + * :param asset_commitment: The asset commitment for this output + * :param asset_commitment_len: The length of the asset commitment. + * :param asset_blinder: The asset blinder for this output + * :param asset_blinder_len: The length of the asset blinder. + * :param nonce_commitment: The nonce commitment for this output + * :param nonce_commitment_len: The length of the nonce commitment. + * :param range_proof: The range proof for this output + * :param range_proof_len: The length of the range proof. + * :param surjection_proof: The surjection proof for this output + * :param surjection_proof_len: The length of the surjection proof. + * :param output: Destination for the resulting psbt output. + */ +WALLY_CORE_API int wally_psbt_elements_output_init_alloc( + unsigned char *redeem_script, + size_t redeem_script_len, + unsigned char *witness_script, + size_t witness_script_len, + struct wally_keypath_map *keypaths, + struct wally_unknowns_map *unknowns, + unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN], + bool has_blinding_pubkey, + unsigned char *value_commitment, + size_t value_commitment_len, + unsigned char *value_blinder, + size_t value_blinder_len, + unsigned char *asset_commitment, + size_t asset_commitment_len, + unsigned char *asset_blinder, + size_t asset_blinder_len, + unsigned char *nonce_commitment, + size_t nonce_commitment_len, + unsigned char *range_proof, + size_t range_proof_len, + unsigned char *surjection_proof, + size_t surjection_proof_len, + struct wally_psbt_output **output); + +/** + * Set the blinding pubkey in an elements output + * + * :param output: The output to update. + * :param blinding_pubkey: The blinding pubkey for this output + */ +WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( + struct wally_psbt_output *output, + unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]); + +/** + * Set the value commitment in an elements output + * + * :param output: The output to update. + * :param value_commitment: The value commitment for this output + * :param value_commitment_len: The length of the value commitment. + */ +WALLY_CORE_API int wally_psbt_elements_output_set_value_commitment( + struct wally_psbt_output *output, + unsigned char *value_commitment, + size_t value_commitment_len); + +/** + * Set the value blinder in an elements output + * + * :param output: The output to update. + * :param value_blinder: The value blinder for this output + * :param value_blinder_len: The length of the value blinder. + */ +WALLY_CORE_API int wally_psbt_elements_output_set_value_blinder( + struct wally_psbt_output *output, + unsigned char *value_blinder, + size_t value_blinder_len); + +/** + * Set the asset commitment in an elements output + * + * :param output: The output to update. + * :param asset_commitment: The asset commitment for this output + * :param asset_commitment_len: The length of the asset commitment. + */ +WALLY_CORE_API int wally_psbt_elements_output_set_asset_commitment( + struct wally_psbt_output *output, + unsigned char *asset_commitment, + size_t asset_commitment_len); + +/** + * Set the asset blinder in an elements output + * + * :param output: The output to update. + * :param asset_blinder: The asset blinder for this output + * :param asset_blinder_len: The length of the asset blinder. + */ +WALLY_CORE_API int wally_psbt_elements_output_set_asset_blinder( + struct wally_psbt_output *output, + unsigned char *asset_blinder, + size_t asset_blinder_len); + +/** + * Set the nonce commitment in an elements output + * + * :param output: The output to update. + * :param nonce_commitment: The nonce commitment for this output + * :param nonce_commitment_len: The length of the nonce commitment. + */ +WALLY_CORE_API int wally_psbt_elements_output_set_nonce_commitment( + struct wally_psbt_output *output, + unsigned char *nonce_commitment, + size_t nonce_commitment_len); + +/** + * Set the range proof in an elements output + * + * :param output: The output to update. + * :param range_proof: The range_proof for this output + * :param range_proof_len: The length of the raange proof. + */ +WALLY_CORE_API int wally_psbt_elements_output_set_range_proof( + struct wally_psbt_output *output, + unsigned char *range_proof, + size_t range_proof_len); + +/** + * Set the surjection proof in an elements output + * + * :param output: The output to update. + * :param surjection_proof: The surjection proof for this output + * :param surjection_proof: The length of the surjection proof. + */ +WALLY_CORE_API int wally_psbt_elements_output_set_surjection_proof( + struct wally_psbt_output *output, + unsigned char *surjection_proof, + size_t surjection_proof_len); + #endif /* BUILD_ELEMENTS */ #ifdef __cplusplus diff --git a/src/psbt.c b/src/psbt.c index 885cc197b..02e35b929 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -859,6 +859,81 @@ int wally_psbt_output_init_alloc( return ret; } +#ifdef BUILD_ELEMENTS +int wally_psbt_elements_output_init_alloc( + unsigned char *redeem_script, + size_t redeem_script_len, + unsigned char *witness_script, + size_t witness_script_len, + struct wally_keypath_map *keypaths, + struct wally_unknowns_map *unknowns, + unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN], + bool has_blinding_pubkey, + unsigned char *value_commitment, + size_t value_commitment_len, + unsigned char *value_blinder, + size_t value_blinder_len, + unsigned char *asset_commitment, + size_t asset_commitment_len, + unsigned char *asset_blinder, + size_t asset_blinder_len, + unsigned char *nonce_commitment, + size_t nonce_commitment_len, + unsigned char *range_proof, + size_t range_proof_len, + unsigned char *surjection_proof, + size_t surjection_proof_len, + struct wally_psbt_output **output) +{ + struct wally_psbt_output *result; + int ret = wally_psbt_output_init_alloc(redeem_script, + redeem_script_len, + witness_script, + witness_script_len, + keypaths, + unknowns, + output); + if (ret != WALLY_OK) { + return ret; + } + + /* wally_psbt_output_init_alloc allocates for us */ + result = *output; + + if (has_blinding_pubkey && (ret = wally_psbt_elements_output_set_blinding_pubkey(result, blinding_pubkey)) != WALLY_OK) { + goto fail; + } + if (value_commitment && (ret = wally_psbt_elements_output_set_value_commitment(result, value_commitment, value_commitment_len)) != WALLY_OK) { + goto fail; + } + if (value_blinder && (ret = wally_psbt_elements_output_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) { + goto fail; + } + if (asset_commitment && (ret = wally_psbt_elements_output_set_asset_commitment(result, asset_commitment, asset_commitment_len)) != WALLY_OK) { + goto fail; + } + if (asset_blinder && (ret = wally_psbt_elements_output_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) { + goto fail; + } + if (nonce_commitment && (ret = wally_psbt_elements_output_set_nonce_commitment(result, nonce_commitment, nonce_commitment_len)) != WALLY_OK) { + goto fail; + } + if (range_proof && (ret = wally_psbt_elements_output_set_range_proof(result, range_proof, range_proof_len)) != WALLY_OK) { + goto fail; + } + if (surjection_proof && (ret = wally_psbt_elements_output_set_surjection_proof(result, surjection_proof, surjection_proof_len)) != WALLY_OK) { + goto fail; + } + + return ret; + +fail: + wally_psbt_output_free(result); + *output = NULL; + return ret; +} +#endif /* BUILD_ELEMENTS */ + int wally_psbt_output_set_redeem_script( struct wally_psbt_output *output, unsigned char *redeem_script, @@ -919,6 +994,129 @@ int wally_psbt_output_set_unknowns( return WALLY_OK; } +#ifdef BUILD_ELEMENTS +int wally_psbt_elements_output_set_blinding_pubkey( + struct wally_psbt_output *output, + unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) +{ + memcpy(output->blinding_pubkey, blinding_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + output->has_blinding_pubkey = true; + return WALLY_OK; +} + +int wally_psbt_elements_output_set_value_commitment( + struct wally_psbt_output *output, + unsigned char *value_commitment, + size_t value_commitment_len) +{ + unsigned char *result_value_commitment; + + if (!clone_bytes(&result_value_commitment, value_commitment, value_commitment_len)) { + return WALLY_ENOMEM; + } + wally_free(output->value_commitment); + output->value_commitment = value_commitment; + output->value_commitment_len = value_commitment_len; + return WALLY_OK; +} + +int wally_psbt_elements_output_set_value_blinder( + struct wally_psbt_output *output, + unsigned char *value_blinder, + size_t value_blinder_len) +{ + unsigned char *result_value_blinder; + + if (!clone_bytes(&result_value_blinder, value_blinder, value_blinder_len)) { + return WALLY_ENOMEM; + } + wally_free(output->value_blinder); + output->value_blinder = value_blinder; + output->value_blinder_len = value_blinder_len; + return WALLY_OK; +} + +int wally_psbt_elements_output_set_asset_commitment( + struct wally_psbt_output *output, + unsigned char *asset_commitment, + size_t asset_commitment_len) +{ + unsigned char *result_asset_commitment; + + if (!clone_bytes(&result_asset_commitment, asset_commitment, asset_commitment_len)) { + return WALLY_ENOMEM; + } + wally_free(output->asset_commitment); + output->asset_commitment = asset_commitment; + output->asset_commitment_len = asset_commitment_len; + return WALLY_OK; +} + +int wally_psbt_elements_output_set_asset_blinder( + struct wally_psbt_output *output, + unsigned char *asset_blinder, + size_t asset_blinder_len) +{ + unsigned char *result_asset_blinder; + + if (!clone_bytes(&result_asset_blinder, asset_blinder, asset_blinder_len)) { + return WALLY_ENOMEM; + } + wally_free(output->asset_blinder); + output->asset_blinder = asset_blinder; + output->asset_blinder_len = asset_blinder_len; + return WALLY_OK; +} + +int wally_psbt_elements_output_set_nonce_commitment( + struct wally_psbt_output *output, + unsigned char *nonce_commitment, + size_t nonce_commitment_len) +{ + unsigned char *result_nonce_commitment; + + if (!clone_bytes(&result_nonce_commitment, nonce_commitment, nonce_commitment_len)) { + return WALLY_ENOMEM; + } + wally_free(output->nonce_commitment); + output->nonce_commitment = nonce_commitment; + output->nonce_commitment_len = nonce_commitment_len; + return WALLY_OK; +} + +int wally_psbt_elements_output_set_range_proof( + struct wally_psbt_output *output, + unsigned char *range_proof, + size_t range_proof_len) +{ + unsigned char *result_range_proof; + + if (!clone_bytes(&result_range_proof, range_proof, range_proof_len)) { + return WALLY_ENOMEM; + } + wally_free(output->range_proof); + output->range_proof = range_proof; + output->range_proof_len = range_proof_len; + return WALLY_OK; +} + +int wally_psbt_elements_output_set_surjection_proof( + struct wally_psbt_output *output, + unsigned char *surjection_proof, + size_t surjection_proof_len) +{ + unsigned char *result_surjection_proof; + + if (!clone_bytes(&result_surjection_proof, surjection_proof, surjection_proof_len)) { + return WALLY_ENOMEM; + } + wally_free(output->surjection_proof); + output->surjection_proof = surjection_proof; + output->surjection_proof_len = surjection_proof_len; + return WALLY_OK; +} +#endif/* BUILD_ELEMENTS */ + static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) { if (output) { @@ -926,6 +1124,17 @@ static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) clear_and_free(output->witness_script, output->witness_script_len); wally_keypath_map_free(output->keypaths); wally_unknowns_map_free(output->unknowns); + +#ifdef BUILD_ELEMENTS + clear_and_free(output->value_commitment, output->value_commitment_len); + clear_and_free(output->value_blinder, output->value_blinder_len); + clear_and_free(output->asset_commitment, output->asset_commitment_len); + clear_and_free(output->asset_blinder, output->asset_blinder_len); + clear_and_free(output->nonce_commitment, output->nonce_commitment_len); + clear_and_free(output->range_proof, output->range_proof_len); + clear_and_free(output->surjection_proof, output->surjection_proof_len); +#endif /* BUILD_ELEMENTS */ + wally_clear(output, sizeof(*output)); if (free_parent) wally_free(output); diff --git a/src/test/util.py b/src/test/util.py index 7f94db4cc..837efed18 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -180,7 +180,23 @@ class wally_psbt_output(Structure): ('witness_script', c_void_p), ('witness_script_len', c_ulong), ('keypaths', POINTER(keypath_map)), - ('unknowns', POINTER(unknowns_map))] + ('unknowns', POINTER(unknowns_map)), + ('blinding_pubkey', c_ubyte * 65), + ('has_blinding_pubkey', c_ulong), + ('value_commitment', c_void_p), + ('value_commitment_len', c_ulong), + ('value_blinder', c_void_p), + ('value_blinder_len', c_ulong), + ('asset_commitment', c_void_p), + ('asset_commitment_len', c_ulong), + ('asset_blinder', c_void_p), + ('asset_blinder_len', c_ulong), + ('nonce_commitment', c_void_p), + ('nonce_commitment_len', c_ulong), + ('range_proof', c_void_p), + ('range_proof_len', c_ulong), + ('surjection_proof', c_void_p), + ('surjection_proof_len', c_ulong)] class wally_psbt(Structure): _fields_ = [('tx', POINTER(wally_tx)), From c69504a06eda986a26b54c70384e0ea33844dacf Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 15 May 2020 12:47:29 -0400 Subject: [PATCH 090/205] Have the PSBT store it's magic to distinguish between psbt and pset wally_psbt_elements_init_alloc is added to set an elements magic wally_psbt_init_alloc, wally_psbt_to_bytes, and wally_psbt_from_bytes are updated to deal with this magic instead of the hard coded magic. wally_psbt_is_elements is added. --- include/wally_psbt.h | 11 ++++++++++ src/psbt.c | 48 +++++++++++++++++++++++++++++++++++++++++++- src/test/util.py | 3 ++- 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 39fbfebf3..cacdb4a8f 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -147,6 +147,7 @@ struct wally_psbt_output { /** A partially signed bitcoin transaction */ struct wally_psbt { + unsigned char magic[5]; struct wally_tx *tx; struct wally_psbt_input *inputs; size_t num_inputs; @@ -634,6 +635,16 @@ WALLY_CORE_API int wally_extract_psbt( const struct wally_psbt *psbt, struct wally_tx **output); +/** + * Determine if a psbt is an elements psbt. + * + * :param psbt: The psbt to check. + * :param written: 1 if the transaction is an elements psbt, otherwise 0. + */ +WALLY_CORE_API int wally_psbt_is_elements( + const struct wally_psbt *psbt, + size_t *written); + #ifdef BUILD_ELEMENTS /** * Allocate and initialize a new elements psbt. diff --git a/src/psbt.c b/src/psbt.c index 02e35b929..f7caaa466 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -16,6 +16,9 @@ const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; +#ifdef BUILD_ELEMENTS +const uint8_t WALLY_ELEMENTS_PSBT_MAGIC[5] = {'p', 's', 'e', 't', 0xff}; +#endif /* BUILD_ELEMENTS */ static bool pubkey_is_compressed(const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { return pubkey[0] == 0x02 || pubkey[0] == 0x03; @@ -1179,12 +1182,29 @@ int wally_psbt_init_alloc( /* Version is always 0 */ result->version = 0; + memcpy(result->magic, WALLY_PSBT_MAGIC, 5); result->inputs_allocation_len = inputs_allocation_len; result->outputs_allocation_len = outputs_allocation_len; result->tx = NULL; return WALLY_OK; } +#ifdef BUILD_ELEMENTS +int wally_psbt_elements_init_alloc( + size_t inputs_allocation_len, + size_t outputs_allocation_len, + size_t global_unknowns_allocation_len, + struct wally_psbt **output) +{ + int ret; + + ret = wally_psbt_init_alloc(inputs_allocation_len, outputs_allocation_len, global_unknowns_allocation_len, output); + memcpy((*output)->magic, WALLY_ELEMENTS_PSBT_MAGIC, 5); + + return ret; +} +#endif /* BUILD_ELEMENTS */ + int wally_psbt_free(struct wally_psbt *psbt) { size_t i; @@ -1887,8 +1907,15 @@ int wally_psbt_from_bytes( goto fail; } if (memcmp(magic, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)) != 0 ) { +#ifdef BUILD_ELEMENTS + if (memcmp(magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(WALLY_ELEMENTS_PSBT_MAGIC)) != 0) { + ret = WALLY_EINVAL; /* Invalid Magic */ + goto fail; + } +#else ret = WALLY_EINVAL; /* Invalid Magic */ goto fail; +#endif /* BUILD_ELEMENTS */ } /* Get a count of the psbt parts */ @@ -1904,6 +1931,9 @@ int wally_psbt_from_bytes( } *output = result; + /* Set the magic */ + memcpy(result->magic, magic, 5); + /* Read globals first */ pre_key = bytes; while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { @@ -2277,7 +2307,7 @@ int wally_psbt_to_bytes( *written = 0; - push_bytes(&cursor, &max, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)); + push_bytes(&cursor, &max, psbt->magic, sizeof(psbt->magic)); /* Global tx */ push_psbt_key(&cursor, &max, WALLY_PSBT_GLOBAL_UNSIGNED_TX, NULL, 0); @@ -3172,3 +3202,19 @@ int wally_extract_psbt( wally_tx_free(result); return ret; } + +int wally_psbt_is_elements( + const struct wally_psbt *psbt, + size_t *written) +{ + if (!psbt || !written) + return WALLY_EINVAL; + + *written = 0; +#ifdef BUILD_ELEMENTS + if (memcmp(psbt->magic, WALLY_ELEMENTS_PSBT_MAGIC, 5) == 0) { + *written = 1; + } +#endif /* BUILD_ELEMENTS */ + return WALLY_OK; +} diff --git a/src/test/util.py b/src/test/util.py index 837efed18..9fd34abcf 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -199,7 +199,8 @@ class wally_psbt_output(Structure): ('surjection_proof_len', c_ulong)] class wally_psbt(Structure): - _fields_ = [('tx', POINTER(wally_tx)), + _fields_ = [('magic', c_ubyte * 5), + ('tx', POINTER(wally_tx)), ('inputs', POINTER(wally_psbt_input)), ('num_inputs', c_ulong), ('inputs_allocation_len', c_ulong), From b9914e567127a148f64dbfed85877d4da0e7d453 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 11:52:16 +1200 Subject: [PATCH 091/205] psbt: Don't pass arrays by value in the public interface SWIG can't wrap arrays by value, and this is also inconsistent with every other function call in the library. --- include/wally_psbt.h | 11 ++++++----- src/psbt.c | 22 ++++++++++++++++------ src/transaction.c | 4 ---- src/transaction_shared.h | 4 ++++ 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index cacdb4a8f..20d940e7a 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -126,8 +126,8 @@ struct wally_psbt_output { struct wally_keypath_map *keypaths; struct wally_unknowns_map *unknowns; #ifdef BUILD_ELEMENTS - unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; - bool has_blinding_pubkey; + unsigned char *blinding_pubkey; + size_t blinding_pubkey_len; unsigned char *value_commitment; size_t value_commitment_len; unsigned char *value_blinder; @@ -848,8 +848,8 @@ WALLY_CORE_API int wally_psbt_elements_output_init_alloc( size_t witness_script_len, struct wally_keypath_map *keypaths, struct wally_unknowns_map *unknowns, - unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN], - bool has_blinding_pubkey, + unsigned char *blinding_pubkey, + size_t blinding_pubkey_len, unsigned char *value_commitment, size_t value_commitment_len, unsigned char *value_blinder, @@ -874,7 +874,8 @@ WALLY_CORE_API int wally_psbt_elements_output_init_alloc( */ WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( struct wally_psbt_output *output, - unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]); + unsigned char *blinding_pubkey, + size_t blinding_pubkey_len); /** * Set the value commitment in an elements output diff --git a/src/psbt.c b/src/psbt.c index f7caaa466..956317cda 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -870,8 +870,8 @@ int wally_psbt_elements_output_init_alloc( size_t witness_script_len, struct wally_keypath_map *keypaths, struct wally_unknowns_map *unknowns, - unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN], - bool has_blinding_pubkey, + unsigned char *blinding_pubkey, + size_t blinding_pubkey_len, unsigned char *value_commitment, size_t value_commitment_len, unsigned char *value_blinder, @@ -903,7 +903,7 @@ int wally_psbt_elements_output_init_alloc( /* wally_psbt_output_init_alloc allocates for us */ result = *output; - if (has_blinding_pubkey && (ret = wally_psbt_elements_output_set_blinding_pubkey(result, blinding_pubkey)) != WALLY_OK) { + if ((ret = wally_psbt_elements_output_set_blinding_pubkey(result, blinding_pubkey, blinding_pubkey_len)) != WALLY_OK) { goto fail; } if (value_commitment && (ret = wally_psbt_elements_output_set_value_commitment(result, value_commitment, value_commitment_len)) != WALLY_OK) { @@ -1000,10 +1000,20 @@ int wally_psbt_output_set_unknowns( #ifdef BUILD_ELEMENTS int wally_psbt_elements_output_set_blinding_pubkey( struct wally_psbt_output *output, - unsigned char blinding_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) + unsigned char *blinding_pubkey, + size_t blinding_pubkey_len) { - memcpy(output->blinding_pubkey, blinding_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - output->has_blinding_pubkey = true; + unsigned char *new_blinding_pubkey = NULL; + + if (!output || BYTES_INVALID_N(blinding_pubkey, blinding_pubkey_len, EC_PUBLIC_KEY_UNCOMPRESSED_LEN)) + return WALLY_EINVAL; + + if (blinding_pubkey && !clone_bytes(&new_blinding_pubkey, blinding_pubkey, blinding_pubkey_len)) + return WALLY_ENOMEM; + + wally_free(output->blinding_pubkey); + output->blinding_pubkey = new_blinding_pubkey; + output->blinding_pubkey_len = blinding_pubkey_len; return WALLY_OK; } diff --git a/src/transaction.c b/src/transaction.c index 187ae1fd2..7a0d6dcc8 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -32,10 +32,6 @@ static const unsigned char DUMMY_SIG[EC_SIGNATURE_DER_MAX_LEN + 1]; /* +1 for si else \ wally_clear(dst, siz); -#define BYTES_VALID(p, len) ((p != NULL) == (len != 0)) -#define BYTES_INVALID(p, len) (!BYTES_VALID(p, len)) -#define BYTES_INVALID_N(p, len, siz) ((p != NULL) != (len == siz)) - #define MAX_INVALID_SATOSHI ((uint64_t) -1) /* Extra options when serializing for hashing */ diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 0eb351de0..46fa492ff 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -12,6 +12,10 @@ extern "C" { wally_clear((void *)*output, sizeof(typ)); \ result = (typ *) *output; +#define BYTES_VALID(p, len) ((p != NULL) == (len != 0)) +#define BYTES_INVALID(p, len) (!BYTES_VALID(p, len)) +#define BYTES_INVALID_N(p, len, siz) ((p != NULL) != (len == siz)) + bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len); void clear_and_free(void *p, size_t len); int analyze_tx(const unsigned char *bytes, size_t bytes_len, From 0cae12509df4ade865fd743f862819ee25e7b10a Mon Sep 17 00:00:00 2001 From: Andrew Chow Date: Fri, 29 May 2020 21:21:18 -0400 Subject: [PATCH 092/205] Implement Elements psbt de/serialization as a proprietary type --- include/wally_psbt.h | 25 +++ src/psbt.c | 482 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 507 insertions(+) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 20d940e7a..62b14470d 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -10,6 +10,9 @@ extern "C" { #define WALLY_PSBT_SEPARATOR 0x00 +/* The proprietary type is the same for all scopes */ +#define WALLY_PSBT_PROPRIETARY_TYPE 0xFC + #define WALLY_PSBT_GLOBAL_UNSIGNED_TX 0x00 #define WALLY_PSBT_GLOBAL_VERSION 0xFB @@ -23,10 +26,32 @@ extern "C" { #define WALLY_PSBT_IN_FINAL_SCRIPTSIG 0x07 #define WALLY_PSBT_IN_FINAL_SCRIPTWITNESS 0x08 +#ifdef BUILD_ELEMENTS +#define WALLY_PSBT_IN_ELEMENTS_VALUE 0x00 +#define WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER 0x01 +#define WALLY_PSBT_IN_ELEMENTS_ASSET 0x02 +#define WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER 0x03 +#define WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX 0x04 +#define WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF 0x05 +#define WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH 0x06 +#define WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT 0x07 +#endif /* BUILD ELEMENTS */ + #define WALLY_PSBT_OUT_REDEEM_SCRIPT 0x00 #define WALLY_PSBT_OUT_WITNESS_SCRIPT 0x01 #define WALLY_PSBT_OUT_BIP32_DERIVATION 0x02 +#ifdef BUILD_ELEMENTS +#define WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT 0x00 +#define WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER 0x01 +#define WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT 0x02 +#define WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER 0x03 +#define WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF 0x04 +#define WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF 0x05 +#define WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY 0x06 +#define WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT 0x07 +#endif /* BUILD ELEMENTS */ + /* PSBT Version number */ #define WALLY_PSBT_HIGHEST_VERSION 0 diff --git a/src/psbt.c b/src/psbt.c index 956317cda..359feb910 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -18,6 +18,8 @@ const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; #ifdef BUILD_ELEMENTS const uint8_t WALLY_ELEMENTS_PSBT_MAGIC[5] = {'p', 's', 'e', 't', 0xff}; +const uint8_t WALLY_ELEMENTS_ID[8] = {'e', 'l', 'e', 'm', 'e', 'n', 't', 's'}; +const size_t WALLY_ELEMENTS_ID_LEN = 8; #endif /* BUILD_ELEMENTS */ static bool pubkey_is_compressed(const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { @@ -1537,6 +1539,37 @@ static int count_psbt_parts( case WALLY_PSBT_IN_BIP32_DERIVATION: input->num_keypaths++; break; + case WALLY_PSBT_PROPRIETARY_TYPE: { +#ifdef BUILD_ELEMENTS + uint64_t id_len; + bool valid_type = false; + + id_len = pull_varlength(&key, &key_len); + if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { + pull_skip(&key, &key_len, id_len); + + switch (pull_varint(&key, &key_len)) { + case WALLY_PSBT_IN_ELEMENTS_VALUE: + case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: + case WALLY_PSBT_IN_ELEMENTS_ASSET: + case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: + case WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX: + case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: + case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: + case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: + valid_type = true; + break; + default: + valid_type = false; + } + } + if (valid_type) { + break; + } +#endif /* BUILD_ELEMENTS */ + } + /* For unknown case without elements or for unknown proprietary types */ + /* fall through */ /* Unknowns */ default: input->num_unknowns++; @@ -1567,6 +1600,37 @@ static int count_psbt_parts( case WALLY_PSBT_OUT_BIP32_DERIVATION: psbt_output->num_keypaths++; break; + case WALLY_PSBT_PROPRIETARY_TYPE: { +#ifdef BUILD_ELEMENTS + uint64_t id_len; + bool valid_type = false; + + id_len = pull_varlength(&key, &key_len); + if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { + pull_skip(&key, &key_len, id_len); + + switch (pull_varint(&key, &key_len)) { + case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: + case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: + case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: + case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: + case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: + case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: + case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: + case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: + valid_type = true; + break; + default: + valid_type = false; + } + } + if (valid_type) { + break; + } +#endif /* BUILD_ELEMENTS */ + } + /* For unknown case without elements or for unknown proprietary types */ + /* fall through */ /* Unknowns */ default: psbt_output->num_unknowns++; @@ -1800,6 +1864,169 @@ static int pull_psbt_input( subfield_nomore_end(cursor, max, val, val_max); break; } + case WALLY_PSBT_PROPRIETARY_TYPE: { +#ifdef BUILD_ELEMENTS + uint64_t id_len; + bool valid_type = false; + + id_len = pull_varlength(&key, &key_len); + if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { + size_t subkey_len; + const unsigned char *subkey; + + /* Start parsing subkey */ + pull_subfield_start(&key, &key_len, id_len, &subkey, &subkey_len); + + switch (pull_varint(&subkey, &subkey_len)) { + case WALLY_PSBT_IN_ELEMENTS_VALUE: { + valid_type = true; + if (result->has_value) { + return WALLY_EINVAL; /* Already have value */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + result->value = pull_le64(&val, &val_max); + subfield_nomore_end(cursor, max, val, val_max); + result->has_value = true; + break; + } + case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: { + valid_type = true; + if (result->value_blinder) { + return WALLY_EINVAL; /* Already have value blinding factor */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->value_blinder, + &result->value_blinder_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->value_blinder_len == 0) { + result->value_blinder = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_ASSET: { + valid_type = true; + if (result->asset) { + return WALLY_EINVAL; /* Already have asset */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->asset, + &result->asset_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->asset_len == 0) { + result->asset = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: { + valid_type = true; + if (result->asset_blinder) { + return WALLY_EINVAL; /* Already have asset blinding factor */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->asset_blinder, + &result->asset_blinder_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->asset_blinder_len == 0) { + result->asset_blinder = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX: { + valid_type = true; + if (result->peg_in_tx) { + return WALLY_EINVAL; /* Already have asset */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + + ret = wally_tx_from_bytes(val, val_max, 0, + &result->peg_in_tx); + if (ret != WALLY_OK) { + return ret; + } + pull_subfield_end(cursor, max, val, val_max); + break; + } + case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: { + valid_type = true; + if (result->txout_proof) { + return WALLY_EINVAL; /* Already have txout proof */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->txout_proof, + &result->txout_proof_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->txout_proof_len == 0) { + result->txout_proof = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: { + valid_type = true; + if (result->genesis_hash) { + return WALLY_EINVAL; /* Already have genesis hash */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->genesis_hash, + &result->genesis_hash_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->genesis_hash_len == 0) { + result->genesis_hash = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: { + valid_type = true; + if (result->claim_script) { + return WALLY_EINVAL; /* Already have asset */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->claim_script, + &result->claim_script_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->claim_script_len == 0) { + result->claim_script = wally_malloc(1); + } + break; + } + default: + valid_type = false; + } + } + if (valid_type) { + break; + } +#endif /* BUILD_ELEMENTS */ + } + /* For unknown case without elements or for unknown proprietary types */ + /* fall through */ /* Unknowns */ default: { ret = pull_unknown_key_value(cursor, max, pre_key, result->unknowns); @@ -1883,6 +2110,171 @@ static int pull_psbt_output( } break; } + case WALLY_PSBT_PROPRIETARY_TYPE: { +#ifdef BUILD_ELEMENTS + uint64_t id_len; + bool valid_type = false; + + id_len = pull_varlength(&key, &key_len); + if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { + size_t subkey_len; + const unsigned char *subkey; + + /* Start parsing subkey */ + pull_subfield_start(&key, &key_len, id_len, &subkey, &subkey_len); + + switch (pull_varint(&subkey, &subkey_len)) { + case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: { + valid_type = true; + if (result->value_commitment) { + return WALLY_EINVAL; /* Already have value commitment */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->value_commitment, + &result->value_commitment_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->value_commitment_len == 0) { + result->value_commitment = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: { + valid_type = true; + if (result->value_blinder) { + return WALLY_EINVAL; /* Already have value blinder */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->value_blinder, + &result->value_blinder_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->value_blinder_len == 0) { + result->value_blinder = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: { + valid_type = true; + if (result->asset_commitment) { + return WALLY_EINVAL; /* Already have asset commitment */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->asset_commitment, + &result->asset_commitment_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->asset_commitment_len == 0) { + result->asset_commitment = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: { + valid_type = true; + if (result->asset_blinder) { + return WALLY_EINVAL; /* Already have asset blinder */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->asset_blinder, + &result->asset_blinder_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->asset_blinder_len == 0) { + result->asset_blinder = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: { + valid_type = true; + if (result->range_proof) { + return WALLY_EINVAL; /* Already have range proof */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->range_proof, + &result->range_proof_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->range_proof_len == 0) { + result->range_proof = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: { + valid_type = true; + if (result->surjection_proof) { + return WALLY_EINVAL; /* Already have surjection proof */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->surjection_proof, + &result->surjection_proof_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->surjection_proof_len == 0) { + result->surjection_proof = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: { + valid_type = true; + if (result->blinding_pubkey) { + return WALLY_EINVAL; /* Already have blinding pubkey */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->blinding_pubkey, + &result->blinding_pubkey_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->blinding_pubkey_len == 0) { + result->blinding_pubkey = wally_malloc(1); + } else if (result->blinding_pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN && + result->blinding_pubkey_len != EC_PUBLIC_KEY_LEN) { + /* FIXME: blinding key elsewhere is assumed to be EC_PUBLIC_KEY_UNCOMPRESSED_LEN only */ + return WALLY_EINVAL; /* Size of key is unexpected */ + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: { + valid_type = true; + if (result->nonce_commitment) { + return WALLY_EINVAL; /* Already have nonce commitment */ + } + subfield_nomore_end(&key, &key_len, subkey, subkey_len); + + if (!clone_varlength(&result->nonce_commitment, + &result->nonce_commitment_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->nonce_commitment_len == 0) { + result->nonce_commitment = wally_malloc(1); + } + break; + } + default: + valid_type = false; + } + } + if (valid_type) { + break; + } +#endif /* BUILD_ELEMENTS */ + } + /* For unknown case without elements or for unknown proprietary types */ + /* fall through */ /* Unknowns */ default: { ret = pull_unknown_key_value(cursor, max, pre_key, result->unknowns); @@ -2104,6 +2496,21 @@ static void push_psbt_key_with_pubkey( } } +#ifdef BUILD_ELEMENTS +/* Common case of pushing elements proprietary type keys */ +static void push_psbt_elements_key( + unsigned char **cursor, size_t *max, + uint64_t type, const void *extra, size_t extra_len) +{ + push_varint(cursor, max, varint_get_length(WALLY_PSBT_PROPRIETARY_TYPE) + + varint_get_length(WALLY_ELEMENTS_ID_LEN) + + WALLY_ELEMENTS_ID_LEN + varint_get_length(type) + extra_len); + push_varint(cursor, max, WALLY_PSBT_PROPRIETARY_TYPE); + push_varbuff(cursor, max, WALLY_ELEMENTS_ID, WALLY_ELEMENTS_ID_LEN); + push_bytes(cursor, max, extra, extra_len); +} +#endif /* BUILD_ELEMENTS */ + static int push_length_and_tx( unsigned char **cursor, size_t *max, const struct wally_tx *tx, uint32_t flags) @@ -2251,6 +2658,47 @@ static int push_psbt_input( push_varint(cursor, max, wit_len); push_witness_stack(cursor, max, input->final_witness); } +#ifdef BUILD_ELEMENTS + /* Confidential Assets blinding data */ + if (input->has_value) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_VALUE, NULL, 0); + push_le64(cursor, max, input->value); + } + if (input->value_blinder) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER, NULL, 0); + push_varbuff(cursor, max, input->value_blinder, input->value_blinder_len); + } + if (input->asset) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_ASSET, NULL, 0); + push_varbuff(cursor, max, input->asset, input->asset_len); + } + if (input->asset_blinder) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER, NULL, 0); + push_varbuff(cursor, max, input->asset_blinder, input->asset_blinder_len); + } + /* Peg ins */ + if (input->peg_in_tx) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX, NULL, 0); + ret = push_length_and_tx(cursor, max, + input->peg_in_tx, + WALLY_TX_FLAG_USE_WITNESS); + if (ret != WALLY_OK) { + return ret; + } + } + if (input->txout_proof) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF, NULL, 0); + push_varbuff(cursor, max, input->txout_proof, input->txout_proof_len); + } + if (input->genesis_hash) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH, NULL, 0); + push_varbuff(cursor, max, input->genesis_hash, input->genesis_hash_len); + } + if (input->claim_script) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT, NULL, 0); + push_varbuff(cursor, max, input->claim_script, input->claim_script_len); + } +#endif /* BUILD_ELEMENTS */ /* Unknowns */ if (input->unknowns) { for (i = 0; i < input->unknowns->num_items; ++i) { @@ -2292,6 +2740,40 @@ static int push_psbt_output( &keypaths->items[i]); } } +#ifdef BUILD_ELEMENTS + if (output->value_commitment) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT, NULL, 0); + push_varbuff(cursor, max, output->value_commitment, output->value_commitment_len); + } + if (output->value_blinder) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER, NULL, 0); + push_varbuff(cursor, max, output->value_blinder, output->value_blinder_len); + } + if (output->asset_commitment) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT, NULL, 0); + push_varbuff(cursor, max, output->asset_commitment, output->asset_commitment_len); + } + if (output->asset_blinder) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER, NULL, 0); + push_varbuff(cursor, max, output->asset_blinder, output->asset_blinder_len); + } + if (output->range_proof) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF, NULL, 0); + push_varbuff(cursor, max, output->range_proof, output->range_proof_len); + } + if (output->surjection_proof) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF, NULL, 0); + push_varbuff(cursor, max, output->surjection_proof, output->surjection_proof_len); + } + if (output->blinding_pubkey) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY, NULL, 0); + push_varbuff(cursor, max, output->blinding_pubkey, output->blinding_pubkey_len); + } + if (output->nonce_commitment) { + push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT, NULL, 0); + push_varbuff(cursor, max, output->nonce_commitment, output->nonce_commitment_len); + } +#endif /* BUILD_ELEMENTS */ /* Unknowns */ if (output->unknowns) { for (i = 0; i < output->unknowns->num_items; ++i) { From 05a55d2a847b878d84c93f39488655c271c8269c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 12:20:55 +1200 Subject: [PATCH 093/205] psbt: Pass in correct flags for elements tx parsing Based on a patch from niftynei. --- src/psbt.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 359feb910..5b3516bbd 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1450,6 +1450,7 @@ static void free_psbt_count(struct psbt_counts *counts) static int count_psbt_parts( const unsigned char *bytes, size_t bytes_len, + uint32_t flags, struct psbt_counts **output) { int ret; @@ -1485,7 +1486,7 @@ static int count_psbt_parts( ret = WALLY_EINVAL; goto fail; } - ret = analyze_tx(val, val_max, 0, &result->num_inputs, &result->num_outputs, &expect_wit); + ret = analyze_tx(val, val_max, flags, &result->num_inputs, &result->num_outputs, &expect_wit); if (ret != WALLY_OK) { goto fail; } @@ -1660,6 +1661,7 @@ static int pull_psbt_input( const unsigned char **cursor, size_t *max, struct psbt_input_counts counts, + uint32_t flags, struct wally_psbt_input *result) { int ret; @@ -1704,8 +1706,7 @@ static int pull_psbt_input( pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); - - ret = wally_tx_from_bytes(val, val_max, 0, + ret = wally_tx_from_bytes(val, val_max, flags, &result->non_witness_utxo); if (ret != WALLY_OK) { return ret; @@ -1957,8 +1958,7 @@ static int pull_psbt_input( pull_varint(cursor, max), &val, &val_max); - ret = wally_tx_from_bytes(val, val_max, 0, - &result->peg_in_tx); + ret = wally_tx_from_bytes(val, val_max, flags, &result->peg_in_tx); if (ret != WALLY_OK) { return ret; } @@ -2300,6 +2300,7 @@ int wally_psbt_from_bytes( size_t i, key_len; struct psbt_counts *counts = NULL; struct wally_psbt *result = NULL; + uint32_t flags = 0; TX_CHECK_OUTPUT; @@ -2314,6 +2315,7 @@ int wally_psbt_from_bytes( ret = WALLY_EINVAL; /* Invalid Magic */ goto fail; } + flags |= WALLY_TX_FLAG_USE_ELEMENTS; #else ret = WALLY_EINVAL; /* Invalid Magic */ goto fail; @@ -2321,7 +2323,7 @@ int wally_psbt_from_bytes( } /* Get a count of the psbt parts */ - if (count_psbt_parts(bytes, bytes_len, &counts) != WALLY_OK) { + if (count_psbt_parts(bytes, bytes_len, flags, &counts) != WALLY_OK) { ret = WALLY_EINVAL; goto fail; } @@ -2358,7 +2360,7 @@ int wally_psbt_from_bytes( pull_subfield_start(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len), &val, &val_max); - ret = wally_tx_from_bytes(val, val_max, 0, &result->tx); + ret = wally_tx_from_bytes(val, val_max, flags, &result->tx); if (ret != WALLY_OK) { goto fail; } @@ -2419,7 +2421,7 @@ int wally_psbt_from_bytes( /* Read inputs */ for (i = 0; i < counts->num_inputs; ++i) { ret = pull_psbt_input(&bytes, &bytes_len, counts->input_counts[i], - &result->inputs[i]); + flags, &result->inputs[i]); /* Increment this now, might be partially initialized! */ result->num_inputs++; if (ret != WALLY_OK) { From 2f3aa8c53ab255e87eaca09be578e2a3c1e28b1e Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 7 Jul 2020 21:53:18 -0500 Subject: [PATCH 094/205] .gitignore: ignore ctags --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 9f999043d..2071c6e50 100644 --- a/.gitignore +++ b/.gitignore @@ -88,6 +88,9 @@ docs/source/transaction.rst docs/source/elements.rst .idea/ +# ctags +tags + # MacOS **/.DS_Store From 8351fb650e3ed96043b24ac0f108e186635425eb Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 7 Jul 2020 22:21:18 -0500 Subject: [PATCH 095/205] pset: use correct serialization for witness_utxo elementsd serializes the asset, value, nonce, and scriptpubkey for a 'witness_utxo' on the input; we were just serializing the amount + scriptpubkey, which made libwally psbt's incompatible with elementsd originated psets. --- src/psbt.c | 160 +++++++++++++++++++++++++++++++++++++++++++++++-- src/pullpush.c | 10 ++++ src/pullpush.h | 1 + 3 files changed, 167 insertions(+), 4 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 5b3516bbd..d3c1092c5 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -3,8 +3,9 @@ #include "ccan/ccan/base64/base64.h" #include "ccan/ccan/build_assert/build_assert.h" -#include +#include #include +#include #include #include @@ -1419,6 +1420,101 @@ static int pull_unknown_key_value(const unsigned char **cursor, return WALLY_OK; } +#ifdef BUILD_ELEMENTS +static size_t push_elements_bytes_size(const struct wally_tx_output *out) +{ + size_t size = 0; + size += out->asset_len == 0 ? 1 : out->asset_len; + size += out->value_len == 0 ? 1 : out->value_len; + size += out->nonce_len == 0 ? 1 : out->nonce_len; + size += out->script_len == 0 ? 1 : out->script_len + 1; + return size; +} + +static void push_elements_bytes(unsigned char **cursor, + size_t *max, + unsigned char *value, + size_t val_len) +{ + unsigned char empty = 0; + push_bytes(cursor, max, value ? value : &empty, value ? val_len : sizeof(empty)); +} + +static int pull_elements_confidential(const unsigned char **cursor, + size_t *max, + unsigned char **value, + size_t *val_len, + size_t prefixA, size_t prefixB, + size_t prefixed_size, size_t explicit_size) +{ + uint8_t type = peek_u8(cursor, max); + /*The first byte is always the 'version' + * which tells you what the value is */ + switch (type) { + /* Empty */ + case 0: + /* Pop off the type */ + pull_u8(cursor, max); + *value = NULL; + *val_len = 0; + return WALLY_OK; + /* Explicit size */ + case 1: + *value = wally_malloc(explicit_size); + pull_bytes(*value, explicit_size, cursor, max); + if (!*cursor) + return WALLY_EINVAL; + *val_len = explicit_size; + return WALLY_OK; + } + if (type == prefixA || type == prefixB) { + *value = wally_malloc(prefixed_size); + pull_bytes(*value, prefixed_size, cursor, max); + if (!*cursor) + return WALLY_EINVAL; + *val_len = prefixed_size; + return WALLY_OK; + } + return WALLY_EINVAL; +} + +/* Either returns a 33-byte commitment to a confidential value, or + * a 64-bit explicit value. */ +static int pull_confidential_value(const unsigned char **cursor, + size_t *max, + unsigned char **value, + size_t *val_len) + +{ + return pull_elements_confidential(cursor, max, value, val_len, + WALLY_TX_ASSET_CT_VALUE_PREFIX_A, WALLY_TX_ASSET_CT_VALUE_PREFIX_B, + WALLY_TX_ASSET_CT_VALUE_LEN, WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN); +} + +static int pull_confidential_asset(const unsigned char **cursor, + size_t *max, + unsigned char **asset, + size_t *asset_len) + +{ + return pull_elements_confidential(cursor, max, asset, asset_len, + WALLY_TX_ASSET_CT_ASSET_PREFIX_A, WALLY_TX_ASSET_CT_ASSET_PREFIX_B, + WALLY_TX_ASSET_CT_ASSET_LEN, WALLY_TX_ASSET_CT_ASSET_LEN); +} + +static int pull_nonce(const unsigned char **cursor, + size_t *max, + unsigned char **nonce, + size_t *nonce_len) + +{ + return pull_elements_confidential(cursor, max, nonce, nonce_len, + WALLY_TX_ASSET_CT_NONCE_PREFIX_A, WALLY_TX_ASSET_CT_NONCE_PREFIX_B, + WALLY_TX_ASSET_CT_NONCE_LEN, WALLY_TX_ASSET_CT_NONCE_LEN); +} + +#endif /* BUILD_ELEMENTS */ + struct psbt_input_counts { size_t num_unknowns; size_t num_keypaths; @@ -1721,11 +1817,42 @@ static int pull_psbt_input( return WALLY_EINVAL; /* We already have a witness utxo */ } subfield_nomore_end(cursor, max, key, key_len); - /* Start parsing the value field. */ pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); +#ifdef BUILD_ELEMENTS + if (flags & WALLY_TX_FLAG_USE_ELEMENTS) { + unsigned char *asset, *value, *nonce; + size_t asset_len, value_len, nonce_len; + if ((ret = pull_confidential_asset(&val, &val_max, &asset, &asset_len)) != WALLY_OK) { + return ret; + } + if ((ret = pull_confidential_value(&val, &val_max, &value, &value_len)) != WALLY_OK) { + return ret; + } + if ((ret = pull_nonce(&val, &val_max, &nonce, &nonce_len)) != WALLY_OK) { + return ret; + } + script_len = pull_varint(&val, &val_max); + script = pull_skip(&val, &val_max, script_len); + if (!script) { + return WALLY_EINVAL; + } + ret = wally_tx_elements_output_init_alloc(script, script_len, + asset, asset_len, + value, value_len, + nonce, nonce_len, + NULL, 0, NULL, 0, + &result->witness_utxo); + if (ret != WALLY_OK) { + return ret; + } + subfield_nomore_end(cursor, max, val, val_max); + break; + } +#endif /* BUILD_ELEMENTS */ + amount = pull_le64(&val, &val_max); script_len = pull_varint(&val, &val_max); script = pull_skip(&val, &val_max, script_len); @@ -2572,6 +2699,7 @@ static void push_keypath_item( static int push_psbt_input( unsigned char **cursor, size_t *max, + uint32_t flags, const struct wally_psbt_input *input) { int ret; @@ -2589,11 +2717,30 @@ static int push_psbt_input( } /* Witness utxo */ +#ifdef BUILD_ELEMENTS + if ((flags & WALLY_TX_FLAG_USE_ELEMENTS) && input->witness_utxo) { + struct wally_tx_output *utxo = input->witness_utxo; + size_t buf_len = push_elements_bytes_size(utxo); + unsigned char buf[buf_len], *ptr = buf; + /* Push the asset, value, nonce, then scriptpubkey */ + push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_UTXO, NULL, 0); + + push_elements_bytes(&ptr, &buf_len, utxo->asset, utxo->asset_len); + push_elements_bytes(&ptr, &buf_len, utxo->value, utxo->value_len); + push_elements_bytes(&ptr, &buf_len, utxo->nonce, utxo->nonce_len); + push_varbuff(&ptr, &buf_len, utxo->script, utxo->script_len); + + if (buf_len != 0) + return WALLY_ERROR; /* Should not happen! */ + push_varbuff(cursor, max, buf, sizeof(buf)); + } else +#endif /* BUILD_ELEMENTS */ if (input->witness_utxo) { unsigned char wit_bytes[50], *w = wit_bytes; /* Witness outputs can be no larger than 50 bytes as specified in BIP 141 */ size_t wit_max = sizeof(wit_bytes); push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_UTXO, NULL, 0); + push_le64(&w, &wit_max, input->witness_utxo->satoshi); push_varbuff(&w, &wit_max, input->witness_utxo->script, @@ -2796,11 +2943,16 @@ int wally_psbt_to_bytes( size_t *written) { unsigned char *cursor = bytes_out; - size_t max = len, i; + size_t max = len, i, is_elements; + uint32_t flags; int ret; *written = 0; + if ((ret = wally_psbt_is_elements(psbt, &is_elements)) != WALLY_OK) + return ret; + flags = is_elements ? WALLY_TX_FLAG_USE_ELEMENTS : 0; + push_bytes(&cursor, &max, psbt->magic, sizeof(psbt->magic)); /* Global tx */ @@ -2829,7 +2981,7 @@ int wally_psbt_to_bytes( /* Push each input and output */ for (i = 0; i < psbt->num_inputs; ++i) { struct wally_psbt_input *input = &psbt->inputs[i]; - ret = push_psbt_input(&cursor, &max, input); + ret = push_psbt_input(&cursor, &max, flags, input); if (ret != WALLY_OK) { return ret; } diff --git a/src/pullpush.c b/src/pullpush.c index 0a1496c53..03eb9ad34 100644 --- a/src/pullpush.c +++ b/src/pullpush.c @@ -121,6 +121,16 @@ uint8_t pull_u8(const unsigned char **cursor, size_t *max) return v; } +uint8_t peek_u8(const unsigned char **cursor, size_t *max) +{ + uint8_t v = pull_u8(cursor, max); + if (*cursor) { + *cursor -= sizeof(v); + *max += sizeof(v); + } + return v; +} + void push_varint(unsigned char **cursor, size_t *max, uint64_t v) { unsigned char buf[sizeof(uint8_t) + sizeof(uint64_t)]; diff --git a/src/pullpush.h b/src/pullpush.h index 77d911f25..3922d487b 100644 --- a/src/pullpush.h +++ b/src/pullpush.h @@ -61,6 +61,7 @@ void push_le16(unsigned char **cursor, size_t *max, uint16_t v); uint16_t pull_le16(const unsigned char **cursor, size_t *max); void push_u8(unsigned char **cursor, size_t *max, uint8_t v); uint8_t pull_u8(const unsigned char **cursor, size_t *max); +uint8_t peek_u8(const unsigned char **cursor, size_t *max); void push_varint(unsigned char **cursor, size_t *max, uint64_t v); uint64_t pull_varint(const unsigned char **cursor, size_t *max); From b40274cef8c2ff73e292085e3bf24b20744e917b Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 13:24:12 +1200 Subject: [PATCH 096/205] pset: Don't leak witness_utxo elements This doesn't actually leak right now since the input and output setters take ownership incorrectly and leak their allocated copies, but that will be fixed shortly. --- src/psbt.c | 53 ++++++++++++++++++++++++----------------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index d3c1092c5..1c349a03b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1442,47 +1442,42 @@ static void push_elements_bytes(unsigned char **cursor, static int pull_elements_confidential(const unsigned char **cursor, size_t *max, - unsigned char **value, + const unsigned char **value, size_t *val_len, size_t prefixA, size_t prefixB, size_t prefixed_size, size_t explicit_size) { - uint8_t type = peek_u8(cursor, max); - /*The first byte is always the 'version' - * which tells you what the value is */ - switch (type) { - /* Empty */ - case 0: - /* Pop off the type */ + /* First byte is always the 'version' which tells you what the value is */ + const uint8_t type = peek_u8(cursor, max); + size_t size; + + if (type == 0) { + /* Empty, Pop off the type */ pull_u8(cursor, max); *value = NULL; *val_len = 0; return WALLY_OK; - /* Explicit size */ - case 1: - *value = wally_malloc(explicit_size); - pull_bytes(*value, explicit_size, cursor, max); - if (!*cursor) - return WALLY_EINVAL; - *val_len = explicit_size; - return WALLY_OK; - } - if (type == prefixA || type == prefixB) { - *value = wally_malloc(prefixed_size); - pull_bytes(*value, prefixed_size, cursor, max); - if (!*cursor) - return WALLY_EINVAL; - *val_len = prefixed_size; - return WALLY_OK; } - return WALLY_EINVAL; + + if (type == 1) + size = explicit_size; + else if (type == prefixA || type == prefixB) + size = prefixed_size; + else + return WALLY_EINVAL; + + *value = pull_skip(cursor, max, size); + if (!*cursor) + return WALLY_EINVAL; + *val_len = size; + return WALLY_OK; } /* Either returns a 33-byte commitment to a confidential value, or * a 64-bit explicit value. */ static int pull_confidential_value(const unsigned char **cursor, size_t *max, - unsigned char **value, + const unsigned char **value, size_t *val_len) { @@ -1493,7 +1488,7 @@ static int pull_confidential_value(const unsigned char **cursor, static int pull_confidential_asset(const unsigned char **cursor, size_t *max, - unsigned char **asset, + const unsigned char **asset, size_t *asset_len) { @@ -1504,7 +1499,7 @@ static int pull_confidential_asset(const unsigned char **cursor, static int pull_nonce(const unsigned char **cursor, size_t *max, - unsigned char **nonce, + const unsigned char **nonce, size_t *nonce_len) { @@ -1823,7 +1818,7 @@ static int pull_psbt_input( &val, &val_max); #ifdef BUILD_ELEMENTS if (flags & WALLY_TX_FLAG_USE_ELEMENTS) { - unsigned char *asset, *value, *nonce; + const unsigned char *asset, *value, *nonce; size_t asset_len, value_len, nonce_len; if ((ret = pull_confidential_asset(&val, &val_max, &asset, &asset_len)) != WALLY_OK) { return ret; From 5337ca3621cb5783c3a7455ab49ec652f080aed9 Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 7 Jul 2020 22:23:36 -0500 Subject: [PATCH 097/205] pset: fixup key parsing for prefix + subtype We were pulling out a subset of the key for the subtype, which wasn't correct. What we really want to do is finish using the already pulled 'key' object, which encompasses all of the subtype info (subtypes don't have length prefixes -- this might be a bug in elementsd?) --- src/psbt.c | 50 ++++++++++++++++++++++---------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 1c349a03b..503fca055 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1994,19 +1994,16 @@ static int pull_psbt_input( id_len = pull_varlength(&key, &key_len); if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { - size_t subkey_len; - const unsigned char *subkey; + /* Skip the elements_id prefix */ + pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); - /* Start parsing subkey */ - pull_subfield_start(&key, &key_len, id_len, &subkey, &subkey_len); - - switch (pull_varint(&subkey, &subkey_len)) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_IN_ELEMENTS_VALUE: { valid_type = true; if (result->has_value) { return WALLY_EINVAL; /* Already have value */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); /* Start parsing the value field. */ pull_subfield_start(cursor, max, @@ -2022,7 +2019,7 @@ static int pull_psbt_input( if (result->value_blinder) { return WALLY_EINVAL; /* Already have value blinding factor */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->value_blinder, &result->value_blinder_len, @@ -2039,7 +2036,7 @@ static int pull_psbt_input( if (result->asset) { return WALLY_EINVAL; /* Already have asset */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->asset, &result->asset_len, @@ -2056,7 +2053,7 @@ static int pull_psbt_input( if (result->asset_blinder) { return WALLY_EINVAL; /* Already have asset blinding factor */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->asset_blinder, &result->asset_blinder_len, @@ -2073,7 +2070,7 @@ static int pull_psbt_input( if (result->peg_in_tx) { return WALLY_EINVAL; /* Already have asset */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); /* Start parsing the value field. */ pull_subfield_start(cursor, max, @@ -2092,7 +2089,7 @@ static int pull_psbt_input( if (result->txout_proof) { return WALLY_EINVAL; /* Already have txout proof */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->txout_proof, &result->txout_proof_len, @@ -2109,7 +2106,7 @@ static int pull_psbt_input( if (result->genesis_hash) { return WALLY_EINVAL; /* Already have genesis hash */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->genesis_hash, &result->genesis_hash_len, @@ -2126,7 +2123,7 @@ static int pull_psbt_input( if (result->claim_script) { return WALLY_EINVAL; /* Already have asset */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->claim_script, &result->claim_script_len, @@ -2239,19 +2236,16 @@ static int pull_psbt_output( id_len = pull_varlength(&key, &key_len); if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { - size_t subkey_len; - const unsigned char *subkey; - - /* Start parsing subkey */ - pull_subfield_start(&key, &key_len, id_len, &subkey, &subkey_len); + /* Skip the elements_id prefix */ + pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); - switch (pull_varint(&subkey, &subkey_len)) { + switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: { valid_type = true; if (result->value_commitment) { return WALLY_EINVAL; /* Already have value commitment */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->value_commitment, &result->value_commitment_len, @@ -2268,7 +2262,7 @@ static int pull_psbt_output( if (result->value_blinder) { return WALLY_EINVAL; /* Already have value blinder */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->value_blinder, &result->value_blinder_len, @@ -2285,7 +2279,7 @@ static int pull_psbt_output( if (result->asset_commitment) { return WALLY_EINVAL; /* Already have asset commitment */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->asset_commitment, &result->asset_commitment_len, @@ -2302,7 +2296,7 @@ static int pull_psbt_output( if (result->asset_blinder) { return WALLY_EINVAL; /* Already have asset blinder */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->asset_blinder, &result->asset_blinder_len, @@ -2319,7 +2313,7 @@ static int pull_psbt_output( if (result->range_proof) { return WALLY_EINVAL; /* Already have range proof */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->range_proof, &result->range_proof_len, @@ -2336,7 +2330,7 @@ static int pull_psbt_output( if (result->surjection_proof) { return WALLY_EINVAL; /* Already have surjection proof */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->surjection_proof, &result->surjection_proof_len, @@ -2353,7 +2347,7 @@ static int pull_psbt_output( if (result->blinding_pubkey) { return WALLY_EINVAL; /* Already have blinding pubkey */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->blinding_pubkey, &result->blinding_pubkey_len, @@ -2374,7 +2368,7 @@ static int pull_psbt_output( if (result->nonce_commitment) { return WALLY_EINVAL; /* Already have nonce commitment */ } - subfield_nomore_end(&key, &key_len, subkey, subkey_len); + subfield_nomore_end(cursor, max, key, key_len); if (!clone_varlength(&result->nonce_commitment, &result->nonce_commitment_len, From 8c045548c55164b2e01affc09104085e67f6dead Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 7 Jul 2020 22:25:47 -0500 Subject: [PATCH 098/205] pset: fixup serialization of proprietary elements keys We were forgetting to add the subtype for proprietary element's keys --- src/psbt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/psbt.c b/src/psbt.c index 503fca055..98a91cf4b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2625,6 +2625,7 @@ static void push_psbt_elements_key( + WALLY_ELEMENTS_ID_LEN + varint_get_length(type) + extra_len); push_varint(cursor, max, WALLY_PSBT_PROPRIETARY_TYPE); push_varbuff(cursor, max, WALLY_ELEMENTS_ID, WALLY_ELEMENTS_ID_LEN); + push_varint(cursor, max, type); push_bytes(cursor, max, extra, extra_len); } #endif /* BUILD_ELEMENTS */ From 8c4e6fc92ed0135d3c27e02a88cbfab9cb87a13b Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 7 Jul 2020 22:26:50 -0500 Subject: [PATCH 099/205] pset: include length of amount in value for WALLY_PSBT_IN_ELEMENTS_VALUEs Small oversight, omitted the length of the amount value when serializing --- src/psbt.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/psbt.c b/src/psbt.c index 98a91cf4b..85836e86b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2801,6 +2801,7 @@ static int push_psbt_input( /* Confidential Assets blinding data */ if (input->has_value) { push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_VALUE, NULL, 0); + push_varint(cursor, max, sizeof(leint64_t)); push_le64(cursor, max, input->value); } if (input->value_blinder) { From beb5ac5fce33a66a2faedd3f78e2dd3a6ea5e67b Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 7 Jul 2020 22:28:25 -0500 Subject: [PATCH 100/205] pset: add canonical pset example from elementsd An unsigned, parseable PSET that we now pass test against --- src/Makefile.am | 3 +++ src/data/pset.json | 6 ++++++ src/test/test_pset.py | 28 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 src/data/pset.json create mode 100644 src/test/test_pset.py diff --git a/src/Makefile.am b/src/Makefile.am index 9d38d6dda..e21bb60df 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -287,6 +287,9 @@ if RUN_PYTHON_TESTS $(AM_V_at)$(PYTHON_TEST) test/test_transaction.py $(AM_V_at)$(PYTHON_TEST) test/test_wif.py $(AM_V_at)$(PYTHON_TEST) test/test_wordlist.py +if BUILD_ELEMENTS + $(AM_V_at)$(PYTHON_TEST) test/test_pset.py +endif if USE_SWIG_PYTHON $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/bip32.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/mnemonic.py diff --git a/src/data/pset.json b/src/data/pset.json new file mode 100644 index 000000000..4b49da887 --- /dev/null +++ b/src/data/pset.json @@ -0,0 +1,6 @@ +{ + "valid": [{ + "pset": "cHNldP8BAOYCAAAAAAEJoA5k8iAABF66mJyk85LBsCUTVVfErOwxmexTjCBEyQAAAAAA/f///wMBXOe5Y9N/jy1Ryvu6koqqniILi7xmBXFJnANiijhRuM4BAAAAAO5rFFgAF6kUpruHAKCJvLhrCf5VkrhUvQ4+bDKHAVznuWPTf48tUcr7upKKqp4iC4u8ZgVxSZwDYoo4UbjOAQAAAAA7msoAABepFII2rTwCO4NdVWyoBFVzHVM/c1IBhwFc57lj03+PLVHK+7qSiqqeIguLvGYFcUmcA2KKOFG4zgEAAAAAAAATqAAAAAAAAAABAUMBXOe5Y9N/jy1Ryvu6koqqniILi7xmBXFJnANiijhRuM4BAAAAASoF8gAAF6kUIUgXxch89mjFY+aFBdmAk9d8GcmHAQQWABTs8/AAycufhZ2FR4uYndwqd1C7ogv8CGVsZW1lbnRzAAgA8gUqAQAAAAv8CGVsZW1lbnRzAiBc57lj03+PLVHK+7qSiqqeIguLvGYFcUmcA2KKOFG4zgABABYAFMFIn/H6YCLLR2ukTXG9evUf5T5VC/wIZWxlbWVudHMGIQMYlbtO8ZBg4wdFP1vS+d59msC7iEjmr/VATyVestonAwABABYAFJpBlksv6mEJcXOPlyskNv1O3yn+C/wIZWxlbWVudHMGIQLkIFPXDMnWVGXBPhDwpi5zMF/WmosNkQLltvC445AA2QAA", + "len": 546 + }] +} diff --git a/src/test/test_pset.py b/src/test/test_pset.py new file mode 100644 index 000000000..b86300456 --- /dev/null +++ b/src/test/test_pset.py @@ -0,0 +1,28 @@ +import json +import unittest +from util import * + +class PSETTests(unittest.TestCase): + + def test_serialization(self): + """Testing serialization and deserialization""" + + with open(root_dir + 'src/data/pset.json', 'r') as f: + d = json.load(f) + valids = d['valid'] + + for valid in valids: + psbt_out = pointer(wally_psbt()) + self.assertEqual(WALLY_OK, wally_psbt_from_base64(utf8(valid['pset']), psbt_out)) + ret, b64 = wally_psbt_to_base64(psbt_out) + self.assertEqual(WALLY_OK, ret) + self.assertEqual(valid['pset'], b64) + ret, length = wally_psbt_get_length(psbt_out) + self.assertEqual(WALLY_OK, ret) + self.assertEqual(length, valid['len']) + + +if __name__ == '__main__': + _, val = wally_is_elements_build() + if val != 0: + unittest.main() From 158a0f7dd43244d9cf35f6c61353b921f64d435e Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 2 Jul 2020 13:50:31 -0500 Subject: [PATCH 101/205] configure: wouldn't compile MAP_ANON on Ubuntu 20.04 LTS Needs the _DEFAULT_SOURCE flag? Recently upgraded to Ubuntu20.04 which can't find MAP_ANON. I traced the problem to __USE_MISC not being flagged on, for who knows why. Some digging led me to this solution. Some further patches from Joseph complete the deprecation of _BSD_SOURCE and _SVID_SOURCE for the upcoming glibc 2.20 release. The first of these patches converts _BSD_SOURCE and _SVID_SOURCE into synonyms for _DEFAULT_SOURCE. The deprecated macros remain effective, but cause compile-time warnings to be generated if they are used (unless _DEFAULT_SOURCE is also defined). The second patch (mechanically) converts all of the uses of the __USE_SVID and __USE_BSD internal macros in glibc header files into __USE_MISC. Source: https://lwn.net/Articles/590381/ --- configure.ac | 3 +++ 1 file changed, 3 insertions(+) diff --git a/configure.ac b/configure.ac index 8fb802f5c..40cca2092 100644 --- a/configure.ac +++ b/configure.ac @@ -174,6 +174,9 @@ AX_CHECK_COMPILE_FLAG([-Wpedantic], [AM_CFLAGS="-Wpedantic $AM_CFLAGS"]) AX_CHECK_COMPILE_FLAG([-Wextra], [AM_CFLAGS="-Wextra $AM_CFLAGS"]) AX_CHECK_COMPILE_FLAG([-Wall], [AM_CFLAGS="-Wall $AM_CFLAGS"]) +# Needed for Ubuntu 20.04LTS when compiling as a library +AX_CHECK_COMPILE_FLAG([-D_DEFAULT_SOURCE=1], [AM_CFLAGS="-D_DEFAULT_SOURCE=1 $AM_CFLAGS"]) + # Disable some unhelpful errors from those enabled above AX_CHECK_COMPILE_FLAG([-Wno-unused-function], [AM_CFLAGS="$AM_CFLAGS -Wno-unused-function"]) AX_CHECK_COMPILE_FLAG([-Wno-long-long], [AM_CFLAGS="$AM_CFLAGS -Wno-long-long"]) From d04bc338eb7935bb86c94cf3b843150110027ea3 Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 8 Jul 2020 15:15:26 -0500 Subject: [PATCH 102/205] transaction: expose wally_tx_output_clone Needed for the clightning things --- include/wally.hpp | 2 ++ include/wally_transaction.h | 24 +++++++++++++++++++ src/swig_java/swig.i | 2 ++ src/swig_python/swig.i | 1 + src/transaction.c | 48 +++++++++++++++++++++++++------------ 5 files changed, 62 insertions(+), 15 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index c2e24e87e..9eff4922c 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -443,6 +443,7 @@ WALLY_FN_PS_A(bip39_get_word, bip39_get_word) WALLY_FN_P_A(bip32_key_from_base58_alloc, bip32_key_from_base58_alloc) WALLY_FN_P_A(bip39_get_languages, bip39_get_languages) WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) +WALLY_FN_P_A(tx_output_clone_alloc, wally_tx_output_clone_alloc) WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) WALLY_FN_P_B(tx_get_txid, wally_tx_get_txid) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) @@ -452,6 +453,7 @@ WALLY_FN_P_S(tx_get_vsize, wally_tx_get_vsize) WALLY_FN_P_S(tx_get_weight, wally_tx_get_weight) WALLY_FN_P_S(tx_get_witness_count, wally_tx_get_witness_count) WALLY_FN_P_P(bip32_key_from_base58, bip32_key_from_base58) +WALLY_FN_P_P(tx_output_clone, wally_tx_output_clone) WALLY_FN_P_P(tx_get_total_output_satoshi, wally_tx_get_total_output_satoshi) WALLY_FN_S_S(tx_vsize_from_weight, wally_tx_vsize_from_weight) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 1ffdaeff7..0b80fb696 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -245,6 +245,30 @@ WALLY_CORE_API int wally_tx_output_init_alloc( size_t script_len, struct wally_tx_output **output); +/** + * Create a new copy of a transaction output. + * + * :param tx_output_in: The transaction output to clone. + * :param output: Destination for the resulting transaction output copy. + */ +WALLY_CORE_API int wally_tx_output_clone_alloc( + const struct wally_tx_output *tx_output_in, + struct wally_tx_output **output); + +#ifndef SWIG +/** + * Create a new copy of a transaction output in-place. + * + * :param tx_output_in: The transaction output to clone. + * :param output: Destination for the resulting transaction output copy. + * + * .. note:: ``output`` is overwritten in place, and not cleared first. + */ +WALLY_CORE_API int wally_tx_output_clone( + const struct wally_tx_output *tx_output_in, + struct wally_tx_output *output); +#endif /* SWIG */ + #ifndef SWIG_PYTHON /** * Free a transaction output allocated by `wally_tx_output_init_alloc`. diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index 15df25e6c..03cd7752a 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -607,6 +607,8 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_size_t(_tx_is_elements); %returns_void__(wally_tx_elements_output_commitment_set); %returns_void__(wally_tx_elements_output_commitment_free); +%returns_struct(wally_tx_output_clone_alloc, wally_tx_clone); +%rename("tx_output_clone") wally_tx_output_clone_alloc; %returns_void__(wally_tx_output_free); %rename("_tx_output_get_asset") wally_tx_output_get_asset; %returns_size_t(_tx_output_get_asset); diff --git a/src/swig_python/swig.i b/src/swig_python/swig.i index a01da2132..a46b82fa7 100644 --- a/src/swig_python/swig.i +++ b/src/swig_python/swig.i @@ -344,6 +344,7 @@ static void destroy_words(PyObject *obj) { (void)obj; } %rename("tx_witness_stack_init") wally_tx_witness_stack_init_alloc; %rename("tx_input_init") wally_tx_input_init_alloc; %rename("tx_output_init") wally_tx_output_init_alloc; +%rename("tx_output_clone") wally_tx_output_clone_alloc; %rename("tx_init") wally_tx_init_alloc; %rename("tx_elements_input_init") wally_tx_elements_input_init_alloc; %rename("tx_elements_output_init") wally_tx_elements_output_init_alloc; diff --git a/src/transaction.c b/src/transaction.c index 7a0d6dcc8..8a3d13e5c 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -776,16 +776,16 @@ int wally_tx_input_free(struct wally_tx_input *input) return tx_input_free(input, true); } -static bool clone_output_to(struct wally_tx_output *dst, - const struct wally_tx_output *src) +int wally_tx_output_clone(const struct wally_tx_output *src, + struct wally_tx_output *output) { unsigned char *new_script = NULL; #ifdef BUILD_ELEMENTS unsigned char *new_asset = NULL, *new_value = NULL, *new_nonce = NULL, *new_surjectionproof = NULL, *new_rangeproof = NULL; #endif - if (!dst || !src) - return false; + if (!src || !output) + return WALLY_EINVAL; #ifdef BUILD_ELEMENTS if (!clone_bytes(&new_asset, src->asset, src->asset_len) || @@ -805,19 +805,36 @@ static bool clone_output_to(struct wally_tx_output *dst, clear_and_free(new_surjectionproof, src->surjectionproof_len); clear_and_free(new_rangeproof, src->rangeproof_len); #endif - return false; + return WALLY_ENOMEM; } - memcpy(dst, src, sizeof(*src)); - dst->script = new_script; + memcpy(output, src, sizeof(*src)); + output->script = new_script; #ifdef BUILD_ELEMENTS - dst->asset = new_asset; - dst->value = new_value; - dst->nonce = new_nonce; - dst->surjectionproof = new_surjectionproof; - dst->rangeproof = new_rangeproof; + output->asset = new_asset; + output->value = new_value; + output->nonce = new_nonce; + output->surjectionproof = new_surjectionproof; + output->rangeproof = new_rangeproof; #endif - return true; + return WALLY_OK; +} + +int wally_tx_output_clone_alloc(const struct wally_tx_output *src, + struct wally_tx_output **output) +{ + struct wally_tx_output *result; + int ret; + + TX_CHECK_OUTPUT; + TX_OUTPUT_ALLOC(struct wally_tx_output); + + ret = wally_tx_output_clone(src, result); + if (ret != WALLY_OK) { + wally_free(result); + *output = NULL; + } + return ret; } static int tx_elements_output_proof_init( @@ -1359,6 +1376,7 @@ int wally_tx_remove_input(struct wally_tx *tx, size_t index) int wally_tx_add_output(struct wally_tx *tx, const struct wally_tx_output *output) { uint64_t total; + int ret; const bool is_elements = output->features & WALLY_TX_IS_ELEMENTS; if (!is_elements) { if (!is_valid_tx(tx) || !is_valid_tx_output(output) || @@ -1380,8 +1398,8 @@ int wally_tx_add_output(struct wally_tx *tx, const struct wally_tx_output *outpu tx->outputs = p; tx->outputs_allocation_len += 1; } - if (!clone_output_to(tx->outputs + tx->num_outputs, output)) - return WALLY_ENOMEM; + if ((ret = wally_tx_output_clone(output, tx->outputs + tx->num_outputs)) != WALLY_OK) + return ret; tx->num_outputs += 1; return WALLY_OK; From 21f2c1f9198473f14b57c96e41be250055c2541a Mon Sep 17 00:00:00 2001 From: niftynei Date: Wed, 8 Jul 2020 15:31:08 -0500 Subject: [PATCH 103/205] psbt: clone passed in tx_output, makes us pset compatible --- src/psbt.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 85836e86b..a89766ab9 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -548,14 +548,17 @@ int wally_psbt_input_set_witness_utxo( struct wally_psbt_input *input, struct wally_tx_output *witness_utxo) { - int ret = WALLY_OK; - struct wally_tx_output *result_witness_utxo; + int ret; + struct wally_tx_output *output; - if ((ret = wally_tx_output_init_alloc(witness_utxo->satoshi, witness_utxo->script, witness_utxo->script_len, &result_witness_utxo)) != WALLY_OK) { - return ret; + if (!input || !witness_utxo) + return WALLY_EINVAL; + + ret = wally_tx_output_clone_alloc(witness_utxo, &output); + if (ret == WALLY_OK) { + wally_tx_output_free(input->witness_utxo); + input->witness_utxo = output; } - wally_tx_output_free(input->witness_utxo); - input->witness_utxo = result_witness_utxo; return ret; } From e9e095f226f04d09817f81cc191fad464e2b3105 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 17:35:03 +1200 Subject: [PATCH 104/205] psbt: Always allow identification of elements psets --- src/psbt.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index a89766ab9..af1929d73 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -3843,18 +3843,11 @@ int wally_extract_psbt( return ret; } -int wally_psbt_is_elements( - const struct wally_psbt *psbt, - size_t *written) +int wally_psbt_is_elements(const struct wally_psbt *psbt, size_t *written) { if (!psbt || !written) return WALLY_EINVAL; - *written = 0; -#ifdef BUILD_ELEMENTS - if (memcmp(psbt->magic, WALLY_ELEMENTS_PSBT_MAGIC, 5) == 0) { - *written = 1; - } -#endif /* BUILD_ELEMENTS */ + *written = memcmp(psbt->magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(psbt->magic)) ? 0 : 1; return WALLY_OK; } From 5b83e31dc67767db906a1b3ff2ef68bec3b88ff1 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 20:48:51 +1200 Subject: [PATCH 105/205] psbt: Update docs --- include/wally_psbt.h | 239 ++++++++++++++++++++++--------------------- 1 file changed, 120 insertions(+), 119 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 62b14470d..8c39b5925 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -206,13 +206,13 @@ WALLY_CORE_API int wally_keypath_map_free( #endif /* SWIG_PYTHON */ /** - * Add an item to a keypath map + * Add an item to a keypath map. * * :param keypaths: The keypath map to add to. * :param pubkey: The pubkey to add. - * :param pubkey_len: The length of the pubkey. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. * :param fingerprint: The master key fingerprint for the pubkey. - * :param fingerprint_len: The length of the fingerprint. Must be ``BIP32_KEY_FINGERPRINT_LEN``. + * :param fingerprint_len: Length of ``fingerprint`` in bytes. Must be ``BIP32_KEY_FINGERPRINT_LEN``. * :param path: The BIP32 derivation path for the pubkey. * :param path_len: The number of items in path. */ @@ -246,13 +246,13 @@ WALLY_CORE_API int wally_partial_sigs_map_free( #endif /* SWIG_PYTHON */ /** - * Add an item to a partial sigs map + * Add an item to a partial sigs map. * * :param sigs: The partial sigs map to add to. * :param pubkey: The pubkey to add. - * :param pubkey_len: Length of the public key. Must be ``EC_PUBLIC_KEY_LEN`` or ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` + * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN`` or ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` * :param sig: The DER-encoded signature to add. - * :param sig_len: The length of sig in bytes. + * :param sig_len: Length of ``sig`` in bytes. */ WALLY_CORE_API int wally_add_new_partial_sig( struct wally_partial_sigs_map *sigs, @@ -262,7 +262,7 @@ WALLY_CORE_API int wally_add_new_partial_sig( size_t sig_len); /** - * Allocate and initialize a new unknowns map + * Allocate and initialize a new unknowns map. * * :param alloc_len: The number of items to allocate. * :param output: Destination for the new unknowns map. @@ -282,13 +282,13 @@ WALLY_CORE_API int wally_unknowns_map_free( #endif /* SWIG_PYTHON */ /** - * Add an item to an unknowns map + * Add an item to an unknowns map. * * :param unknowns: The unknowns map to add to. * :param key: The key to add. - * :param key_len: The length of the key in bytes. + * :param key_len: Length of ``key`` in bytes. * :param value: The value to add. - * :param value_len: The length of value in bytes. + * :param value_len: Length of ``value`` in bytes. */ WALLY_CORE_API int wally_add_new_unknown( struct wally_unknowns_map *unknowns, @@ -303,11 +303,11 @@ WALLY_CORE_API int wally_add_new_unknown( * :param non_witness_utxo: The non witness utxo for this input if it exists. * :param witness_utxo: The witness utxo for this input if it exists. * :param redeem_script: The redeem script for this input. - * :param redeem_script_len: The length of the redeem script. + * :param redeem_script_len: Length of ``redeem_script`` in bytes. * :param witness_script: The witness script for this input. - * :param witness_script_len: The length of the witness script. + * :param witness_script_len: Length of ``witness_script`` in bytes. * :param final_script_sig: The scriptSig for this input. - * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. + * :param final_script_sig_len: Length of ``final_script_sig`` in bytes. * :param final_witness: The witness stack for the input, or NULL if no witness is present. * :param keypaths: The HD keypaths for this input. * :param partial_sigs: The partial signatures for this input. @@ -332,7 +332,7 @@ WALLY_CORE_API int wally_psbt_input_init_alloc( struct wally_psbt_input **output); /** - * Set the non_witness_utxo in an input + * Set the non_witness_utxo in an input. * * :param input: The input to update. * :param non_witness_utxo: The non witness utxo for this input if it exists. @@ -342,7 +342,7 @@ WALLY_CORE_API int wally_psbt_input_set_non_witness_utxo( struct wally_tx *non_witness_utxo); /** - * Set the witness_utxo in an input + * Set the witness_utxo in an input. * * :param input: The input to update. * :param witness_utxo: The witness utxo for this input if it exists. @@ -352,11 +352,11 @@ WALLY_CORE_API int wally_psbt_input_set_witness_utxo( struct wally_tx_output *witness_utxo); /** - * Set the redeem_script in an input + * Set the redeem_script in an input. * * :param input: The input to update. * :param redeem_script: The redeem script for this input. - * :param redeem_script_len: The length of the redeem script. + * :param redeem_script_len: Length of ``redeem_script`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_redeem_script( struct wally_psbt_input *input, @@ -364,11 +364,11 @@ WALLY_CORE_API int wally_psbt_input_set_redeem_script( size_t redeem_script_len); /** - * Set the witness_script in an input + * Set the witness_script in an input. * * :param input: The input to update. * :param witness_script: The witness script for this input. - * :param witness_script_len: The length of the witness script. + * :param witness_script_len: Length of ``witness_script`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_witness_script( struct wally_psbt_input *input, @@ -376,11 +376,11 @@ WALLY_CORE_API int wally_psbt_input_set_witness_script( size_t witness_script_len); /** - * Set the final_script_sig in an input + * Set the final_script_sig in an input. * * :param input: The input to update. * :param final_script_sig: The scriptSig for this input. - * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. + * :param final_script_sig_len: Length of ``final_script_sig`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_final_script_sig( struct wally_psbt_input *input, @@ -388,7 +388,7 @@ WALLY_CORE_API int wally_psbt_input_set_final_script_sig( size_t final_script_sig_len); /** - * Set the final_witness in an input + * Set the final_witness in an input. * * :param input: The input to update. * :param final_witness: The witness stack for the input, or NULL if no witness is present. @@ -398,7 +398,7 @@ WALLY_CORE_API int wally_psbt_input_set_final_witness( struct wally_tx_witness_stack *final_witness); /** - * Set the keypaths in an input + * Set the keypaths in an input. * * :param input: The input to update. * :param keypaths: The HD keypaths for this input. @@ -408,7 +408,7 @@ WALLY_CORE_API int wally_psbt_input_set_keypaths( struct wally_keypath_map *keypaths); /** - * Set the partial_sigs in an input + * Set the partial_sigs in an input. * * :param input: The input to update. * :param partial_sigs: The partial signatures for this input. @@ -418,7 +418,7 @@ WALLY_CORE_API int wally_psbt_input_set_partial_sigs( struct wally_partial_sigs_map *partial_sigs); /** - * Set the partial_sigs in an input + * Set the partial_sigs in an input. * * :param input: The input to update. * :param unknowns: The unknown key value pairs for this input. @@ -428,7 +428,7 @@ WALLY_CORE_API int wally_psbt_input_set_unknowns( struct wally_unknowns_map *unknowns); /** - * Set the partial_sigs in an input + * Set the partial_sigs in an input. * * :param input: The input to update. * :param sighash_type: The sighash type for this input. @@ -451,9 +451,9 @@ WALLY_CORE_API int wally_psbt_input_free( * Allocate and initialize a new PSBT output. * * :param redeem_script: The redeem script needed for spending this output. - * :param redeem_script_len: The length of the redeem script. + * :param redeem_script_len: Length of ``redeem_script`` in bytes. * :param witness_script: The witness script needed for spending for this output. - * :param witness_script_len: The length of the witness script. + * :param witness_script_len: Length of ``witness_script`` in bytes. * :param keypaths: The HD keypaths for the keys needed for spending this output. * :param unknowns: The unknown key value pairs for this output. * :param output: Destination for the resulting PSBT output. @@ -472,7 +472,7 @@ WALLY_CORE_API int wally_psbt_output_init_alloc( * * :param output: The input to update. * :param redeem_script: The redeem script for this output. - * :param redeem_script_len: The length of the redeem script. + * :param redeem_script_len: Length of ``redeem_script`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_redeem_script( struct wally_psbt_output *output, @@ -484,7 +484,7 @@ WALLY_CORE_API int wally_psbt_output_set_redeem_script( * * :param output: The output to update. * :param witness_script: The witness script for this output. - * :param witness_script_len: The length of the witness script. + * :param witness_script_len: Length of ``witness_script`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_witness_script( struct wally_psbt_output *output, @@ -619,7 +619,7 @@ WALLY_CORE_API int wally_psbt_to_base64( * Combine the metadata from multiple PSBTs into one PSBT. * * :param psbts: Array of PSBTs to combine. - * :param psbts_len: Number of PSBTs in psbts. + * :param psbts_len: Number of PSBTs in ``psbts``. * :param output: Destination for resulting PSBT. */ WALLY_CORE_API int wally_combine_psbts( @@ -654,17 +654,17 @@ WALLY_CORE_API int wally_finalize_psbt( * Extract a network transaction from a finalized PSBT. * * :param psbt: PSBT to extract from. - * :param output: Resulting transaction + * :param output: Destination for the resulting transaction. */ WALLY_CORE_API int wally_extract_psbt( const struct wally_psbt *psbt, struct wally_tx **output); /** - * Determine if a psbt is an elements psbt. + * Determine if a PSBT is an elements PSBT. * - * :param psbt: The psbt to check. - * :param written: 1 if the transaction is an elements psbt, otherwise 0. + * :param psbt: The PSBT to check. + * :param written: 1 if the PSBT is an elements PSBT, otherwise 0. */ WALLY_CORE_API int wally_psbt_is_elements( const struct wally_psbt *psbt, @@ -672,12 +672,12 @@ WALLY_CORE_API int wally_psbt_is_elements( #ifdef BUILD_ELEMENTS /** - * Allocate and initialize a new elements psbt. + * Allocate and initialize a new elements PSBT. * * :param inputs_allocation_len: The number of inputs to pre-allocate space for. * :param outputs_allocation_len: The number of outputs to pre-allocate space for. * :param global_unknowns_allocation_len: The number of global unknowns to allocate space for. - * :param output: Destination for the resulting psbt output. + * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_elements_init_alloc( size_t inputs_allocation_len, @@ -686,16 +686,16 @@ WALLY_CORE_API int wally_psbt_elements_init_alloc( struct wally_psbt **output); /** - * Allocate and initialize a new psbt elements input. + * Allocate and initialize a new PSBT elements input. * * :param non_witness_utxo: The non witness utxo for this input if it exists. * :param witness_utxo: The witness utxo for this input if it exists. * :param redeem_script: The redeem script for this input - * :param redeem_script_len: The length of the redeem script. + * :param redeem_script_len: Length of ``redeem_script`` in bytes. * :param witness_script: The witness script for this input - * :param witness_script_len: The length of the witness script. + * :param witness_script_len: Length of ``witness_script`` in bytes. * :param final_script_sig: The scriptSig for this input - * :param final_script_sig_len: Size of ``final_script_sig`` in bytes. + * :param final_script_sig_len: Length of ``final_script_sig`` in bytes. * :param final_witness: The witness stack for the input, or NULL if no witness is present. * :param keypaths: The HD keypaths for this input. * :param partial_sigs: The partial signatures for this input. @@ -703,19 +703,19 @@ WALLY_CORE_API int wally_psbt_elements_init_alloc( * :param sighash_type: The sighash type for this input * :param value: The value for this input * :param value_blinder: The value blinder for ths input - * :param value_blinder_len: The length of the value_blinder. - * :param asset: The witness script for this input - * :param asset_len: The length of the witness script. - * :param asset_blinder: The witness script for this input - * :param asset_blinder__len: The length of the witness script. - * :param peg_in_tx: The witness script for this input - * :param txout_proof: The witness script for this input - * :param txout_proof_len: The length of the witness script. - * :param genesis_hash: The witness script for this input - * :param genesis_hash_len: The length of the witness script. - * :param claim_script: The witness script for this input - * :param claim_script_len: The length of the witness script. - * :param output: Destination for the resulting psbt input. + * :param value_blinder_len: Length of ``value_blinder`` in bytes. + * :param asset: The asset for this input. + * :param asset_len: Length of ``asset`` in bytes. + * :param asset_blinder: The asset blinder for this input. + * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. + * :param peg_in_tx: The The peg in tx for this input + * :param txout_proof: The txout proof for this input + * :param txout_proof_len: Length of ``txout_proof`` in bytes. + * :param genesis_hash: The genesis hash for this input + * :param genesis_hash_len: Length of ``genesis_hash`` in bytes. + * :param claim_script: The claim script for this input + * :param claim_script_len: Length of ``claim_script`` in bytes. + * :param output: Destination for the resulting PSBT input. */ WALLY_CORE_API int wally_psbt_elements_input_init_alloc( struct wally_tx *non_witness_utxo, @@ -749,21 +749,21 @@ WALLY_CORE_API int wally_psbt_elements_input_init_alloc( struct wally_psbt_input **output); /** - * Set the value in an elements input + * Set the value in an elements input. * * :param input: The input to update. - * :param value: The value for this input + * :param value: The value for this input. */ WALLY_CORE_API int wally_psbt_elements_input_set_value( struct wally_psbt_input *input, uint64_t value); /** - * Set the value blinder in an elements input + * Set the value blinder in an elements input. * * :param input: The input to update. - * :param value_blinder: The value blinder for this input - * :param value_blinder_len: The length of the value blinder. + * :param value_blinder: The value blinder for this input. + * :param value_blinder_len: Length of ``value_blinder`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_input_set_value_blinder( struct wally_psbt_input *input, @@ -771,11 +771,11 @@ WALLY_CORE_API int wally_psbt_elements_input_set_value_blinder( size_t value_blinder_len); /** - * Set the asset in an elements input + * Set the asset in an elements input. * * :param input: The input to update. - * :param asset: The asset for this input - * :param asset_len: The length of the asset + * :param asset: The asset for this input. + * :param asset_len: Length of ``asset`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_input_set_asset( struct wally_psbt_input *input, @@ -786,8 +786,8 @@ WALLY_CORE_API int wally_psbt_elements_input_set_asset( * Set the asset blinder in an elements input * * :param input: The input to update. - * :param asset_blinder: The asset blinder for this input - * :param asset_blinder_len: The length of the asset blinder. + * :param asset_blinder: The asset blinder for this input. + * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_input_set_asset_blinder( struct wally_psbt_input *input, @@ -795,7 +795,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_asset_blinder( size_t asset_blinder_len); /** - * Set the peg in tx in an input + * Set the peg in tx in an input. * * :param input: The input to update. * :param peg_in_tx: The peg in tx for this input if it exists. @@ -805,11 +805,11 @@ WALLY_CORE_API int wally_psbt_elements_input_set_peg_in_tx( struct wally_tx *peg_in_tx); /** - * Set the txout proof in an elements input + * Set the txout proof in an elements input. * * :param input: The input to update. - * :param txout_proof: The txout proof for this input - * :param txout_proof_len: The length of the txout proof. + * :param txout_proof: The txout proof for this input. + * :param txout_proof_len: Length of ``txout_proof`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_input_set_txout_proof( struct wally_psbt_input *input, @@ -817,11 +817,11 @@ WALLY_CORE_API int wally_psbt_elements_input_set_txout_proof( size_t txout_proof_len); /** - * Set the genesis hash in an elements input + * Set the genesis hash in an elements input. * * :param input: The input to update. - * :param genesis_hash: The genesis hash for this input - * :param genesis_hash_len: The length of the genesis hash. + * :param genesis_hash: The genesis hash for this input. + * :param genesis_hash_len: Length of ``genesis_hash`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_input_set_genesis_hash( struct wally_psbt_input *input, @@ -829,11 +829,11 @@ WALLY_CORE_API int wally_psbt_elements_input_set_genesis_hash( size_t genesis_hash_len); /** - * Set the claim script in an elements input + * Set the claim script in an elements input. * * :param input: The input to update. - * :param claim_script: The claim script for this input - * :param claim_script_len: The length of the claim_script. + * :param claim_script: The claim script for this input. + * :param claim_script_len: Length of ``claim_script`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( struct wally_psbt_input *input, @@ -841,30 +841,30 @@ WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( size_t claim_script_len); /** - * Allocate and initialize a new psbt elements output. + * Allocate and initialize a new PSBT elements output. * - * :param redeem_script: The redeem script needed for spending this output - * :param redeem_script_len: The length of the redeem script. - * :param witness_script: The witness script needed for spending for this output - * :param witness_script_len: The length of the witness script. - * :param keypaths: The HD keypaths for the keys needed for spending this output + * :param redeem_script: The redeem script needed for spending this output. + * :param redeem_script_len: Length of ``redeem_script`` in bytes. + * :param witness_script: The witness script needed for spending for this output. + * :param witness_script_len: Length of ``witness_script`` in bytes. + * :param keypaths: The HD keypaths for the keys needed for spending this output. * :param unknowns: The unknown key value pairs for this output. - * :param blinding_pubkey: The blinding pubkey for this output - * :param value_commitment: The value commitment for this output - * :param value_commitment_len: The length of the witness script. - * :param value_blinder: The value blinder for this output - * :param value_blinder_len: The length of the value blinder. - * :param asset_commitment: The asset commitment for this output - * :param asset_commitment_len: The length of the asset commitment. - * :param asset_blinder: The asset blinder for this output - * :param asset_blinder_len: The length of the asset blinder. - * :param nonce_commitment: The nonce commitment for this output - * :param nonce_commitment_len: The length of the nonce commitment. - * :param range_proof: The range proof for this output - * :param range_proof_len: The length of the range proof. - * :param surjection_proof: The surjection proof for this output - * :param surjection_proof_len: The length of the surjection proof. - * :param output: Destination for the resulting psbt output. + * :param blinding_pubkey: The blinding pubkey for this output. + * :param value_commitment: The value commitment for this output. + * :param value_commitment_len: Length of ``value_commitment`` in bytes. + * :param value_blinder: The value blinder for this output. + * :param value_blinder_len: Length of ``value_blinder`` in bytes. + * :param asset_commitment: The asset commitment for this output. + * :param asset_commitment_len: Length of ``asset_commitment`` in bytes. + * :param asset_blinder: The asset blinder for this output. + * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. + * :param nonce_commitment: The nonce commitment for this output. + * :param nonce_commitment_len: Length of ``nonce_commitment`` in bytes. + * :param range_proof: The range proof for this output. + * :param range_proof_len: Length of ``range_proof`` in bytes. + * :param surjection_proof: The surjection proof for this output. + * :param surjection_proof_len: Length of ``surjection_proof`` in bytes. + * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_elements_output_init_alloc( unsigned char *redeem_script, @@ -892,10 +892,11 @@ WALLY_CORE_API int wally_psbt_elements_output_init_alloc( struct wally_psbt_output **output); /** - * Set the blinding pubkey in an elements output + * Set the blinding pubkey in an elements output. * * :param output: The output to update. - * :param blinding_pubkey: The blinding pubkey for this output + * :param blinding_pubkey: The blinding pubkey for this output. + * :param blinding_pubkey_len: Length of ``blinding_pubkey`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( struct wally_psbt_output *output, @@ -903,11 +904,11 @@ WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( size_t blinding_pubkey_len); /** - * Set the value commitment in an elements output + * Set the value commitment in an elements output. * * :param output: The output to update. - * :param value_commitment: The value commitment for this output - * :param value_commitment_len: The length of the value commitment. + * :param value_commitment: The value commitment for this output. + * :param value_commitment_len: Length of ``value_commitment`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_value_commitment( struct wally_psbt_output *output, @@ -915,11 +916,11 @@ WALLY_CORE_API int wally_psbt_elements_output_set_value_commitment( size_t value_commitment_len); /** - * Set the value blinder in an elements output + * Set the value blinder in an elements output. * * :param output: The output to update. - * :param value_blinder: The value blinder for this output - * :param value_blinder_len: The length of the value blinder. + * :param value_blinder: The value blinder for this output. + * :param value_blinder_len: Length of ``value_blinder`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_value_blinder( struct wally_psbt_output *output, @@ -927,11 +928,11 @@ WALLY_CORE_API int wally_psbt_elements_output_set_value_blinder( size_t value_blinder_len); /** - * Set the asset commitment in an elements output + * Set the asset commitment in an elements output. * * :param output: The output to update. - * :param asset_commitment: The asset commitment for this output - * :param asset_commitment_len: The length of the asset commitment. + * :param asset_commitment: The asset commitment for this output. + * :param asset_commitment_len: Length of ``asset_commitment`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_asset_commitment( struct wally_psbt_output *output, @@ -939,11 +940,11 @@ WALLY_CORE_API int wally_psbt_elements_output_set_asset_commitment( size_t asset_commitment_len); /** - * Set the asset blinder in an elements output + * Set the asset blinder in an elements output. * * :param output: The output to update. - * :param asset_blinder: The asset blinder for this output - * :param asset_blinder_len: The length of the asset blinder. + * :param asset_blinder: The asset blinder for this output. + * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_asset_blinder( struct wally_psbt_output *output, @@ -951,11 +952,11 @@ WALLY_CORE_API int wally_psbt_elements_output_set_asset_blinder( size_t asset_blinder_len); /** - * Set the nonce commitment in an elements output + * Set the nonce commitment in an elements output. * * :param output: The output to update. - * :param nonce_commitment: The nonce commitment for this output - * :param nonce_commitment_len: The length of the nonce commitment. + * :param nonce_commitment: The nonce commitment for this output. + * :param nonce_commitment_len: Length of ``nonce_commitment`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_nonce_commitment( struct wally_psbt_output *output, @@ -963,11 +964,11 @@ WALLY_CORE_API int wally_psbt_elements_output_set_nonce_commitment( size_t nonce_commitment_len); /** - * Set the range proof in an elements output + * Set the range proof in an elements output. * * :param output: The output to update. - * :param range_proof: The range_proof for this output - * :param range_proof_len: The length of the raange proof. + * :param range_proof: The range_proof for this output. + * :param range_proof_len: Length of ``range_proof`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_range_proof( struct wally_psbt_output *output, @@ -975,11 +976,11 @@ WALLY_CORE_API int wally_psbt_elements_output_set_range_proof( size_t range_proof_len); /** - * Set the surjection proof in an elements output + * Set the surjection proof in an elements output. * * :param output: The output to update. - * :param surjection_proof: The surjection proof for this output - * :param surjection_proof: The length of the surjection proof. + * :param surjection_proof: The surjection proof for this output. + * :param surjection_proof_len: Length of ``surjection_proof`` in bytes. */ WALLY_CORE_API int wally_psbt_elements_output_set_surjection_proof( struct wally_psbt_output *output, From c182992ba0eff6abe66bf854ae49ff612103a02e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 20:49:26 +1200 Subject: [PATCH 106/205] gitignore: Ignore swp files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2071c6e50..60c756e78 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bld *.pyc +*.swp src/test/__pycache__/ *~ *.class From 161e5cc5a25ca96b21e58365e051669e7e2c78c4 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 20:53:24 +1200 Subject: [PATCH 107/205] psbt: Move test data file to the common data file location --- src/{test => }/data/psbt.json | 0 src/test/test_psbt.py | 4 +--- 2 files changed, 1 insertion(+), 3 deletions(-) rename src/{test => }/data/psbt.json (100%) diff --git a/src/test/data/psbt.json b/src/data/psbt.json similarity index 100% rename from src/test/data/psbt.json rename to src/data/psbt.json diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index a4eb72507..d855f7e84 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -1,7 +1,5 @@ import binascii -import base64 import json -import os import unittest from util import * @@ -9,7 +7,7 @@ class PSBTTests(unittest.TestCase): def test_serialization(self): """Testing serialization and deserialization""" - with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/psbt.json')) as f: + with open(root_dir + 'src/data/psbt.json', 'r') as f: d = json.load(f) invalids = d['invalid'] valids = d['valid'] From f1fa4b6e816ac932a25a3beb9b77268f188ceb83 Mon Sep 17 00:00:00 2001 From: niftynei Date: Thu, 28 May 2020 21:29:09 -0500 Subject: [PATCH 108/205] readme: add easier to skim notes for running the tests + formatter Make it easier to skim the docs to find relevant notes for running the formatter and test suite --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e966bec6..aba4b20e8 100644 --- a/README.md +++ b/README.md @@ -149,8 +149,22 @@ should format your changes using [uncrustify](https://github.com/uncrustify/uncr version 0.60 or later. The script `./tools/uncrustify` will reformat all C sources in the library as needed, with the currently chosen uncrustify options. +To reformat a single source file, use e.g.: +``` +$ ./tools/uncrustify src/transaction.c +``` + +Or to reformat all source files, pass no arguments: +``` +$ ./tools/uncrustify +``` + You should also make sure the existing tests pass and if possible write tests -covering any new functionality, following the existing style. +covering any new functionality, following the existing style. You can run the +tests via: +``` +$ make check +``` ## Generating a coverage report From 376f2324e27f2a1302539a76834ed5489e086166 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 21:09:24 +1200 Subject: [PATCH 109/205] psbt: Replace asserts with error returns --- src/psbt.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index af1929d73..b504dda80 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1,7 +1,6 @@ #include "internal.h" #include "ccan/ccan/base64/base64.h" -#include "ccan/ccan/build_assert/build_assert.h" #include #include @@ -9,7 +8,6 @@ #include #include -#include #include "transaction_shared.h" #include "script_int.h" #include "script.h" @@ -1368,7 +1366,8 @@ static int pull_keypath(const unsigned char **cursor, size_t *max, } } - assert(keypaths->num_items < keypaths->items_allocation_len); + if (keypaths->num_items >= keypaths->items_allocation_len) + return WALLY_ERROR; /* Should not happen! */ kpitem = &keypaths->items[keypaths->num_items++]; memcpy(kpitem->pubkey, key, key_len); @@ -1411,7 +1410,8 @@ static int pull_unknown_key_value(const unsigned char **cursor, *max += (*cursor - pre_key); *cursor = pre_key; - assert(unknowns->num_items < unknowns->items_allocation_len); + if (unknowns->num_items >= unknowns->items_allocation_len) + return WALLY_ERROR; /* Should not happen! */ item = &unknowns->items[unknowns->num_items++]; if (!clone_varlength(&item->key, &item->key_len, cursor, max)) { From acdc40cbd1ff8846c83b10fbd8f0417deba89cac Mon Sep 17 00:00:00 2001 From: niftynei Date: Tue, 7 Jul 2020 10:20:17 -0500 Subject: [PATCH 110/205] tests: enable non swig elements tests even when swig not enabled too many if nests meant that the build_elements tests would only run if both elements + swig_python were enabled. here we split this into two sections, where non-swig build_elements tests will run iff build_elements is flagged. --- src/Makefile.am | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index e21bb60df..cb4cbce66 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -273,7 +273,6 @@ if RUN_PYTHON_TESTS $(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_ecdh.py - $(AM_V_at)$(PYTHON_TEST) test/test_elements.py $(AM_V_at)$(PYTHON_TEST) test/test_hash.py $(AM_V_at)$(PYTHON_TEST) test/test_hex.py $(AM_V_at)$(PYTHON_TEST) test/test_hmac.py @@ -289,6 +288,10 @@ if RUN_PYTHON_TESTS $(AM_V_at)$(PYTHON_TEST) test/test_wordlist.py if BUILD_ELEMENTS $(AM_V_at)$(PYTHON_TEST) test/test_pset.py + $(AM_V_at)$(PYTHON_TEST) test/test_confidential_addr.py + $(AM_V_at)$(PYTHON_TEST) test/test_pegin.py + $(AM_V_at)$(PYTHON_TEST) test/test_pegout.py + $(AM_V_at)$(PYTHON_TEST) test/test_elements.py endif if USE_SWIG_PYTHON $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/bip32.py @@ -296,13 +299,10 @@ if USE_SWIG_PYTHON $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/sha.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/tx.py if BUILD_ELEMENTS - $(AM_V_at)$(PYTHON_TEST) test/test_confidential_addr.py - $(AM_V_at)$(PYTHON_TEST) test/test_pegin.py - $(AM_V_at)$(PYTHON_TEST) test/test_pegout.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/elements_tx.py $(AM_V_at)$(PYTHON_SWIGTEST) pyexample/liquid/receive-send.py endif -endif +endif # USE_SWIG_PYTHON endif # RUN_PYTHON_TESTS if RUN_JAVA_TESTS if BUILD_ELEMENTS From b6e292028be482e7fc58a3150478a1f245a653dd Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 21:31:26 +1200 Subject: [PATCH 111/205] psbt: Avoid magic numbers --- src/psbt.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index b504dda80..756f16dfa 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1196,7 +1196,7 @@ int wally_psbt_init_alloc( /* Version is always 0 */ result->version = 0; - memcpy(result->magic, WALLY_PSBT_MAGIC, 5); + memcpy(result->magic, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)); result->inputs_allocation_len = inputs_allocation_len; result->outputs_allocation_len = outputs_allocation_len; result->tx = NULL; @@ -1213,7 +1213,7 @@ int wally_psbt_elements_init_alloc( int ret; ret = wally_psbt_init_alloc(inputs_allocation_len, outputs_allocation_len, global_unknowns_allocation_len, output); - memcpy((*output)->magic, WALLY_ELEMENTS_PSBT_MAGIC, 5); + memcpy((*output)->magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(WALLY_ELEMENTS_PSBT_MAGIC)); return ret; } @@ -2455,7 +2455,7 @@ int wally_psbt_from_bytes( *output = result; /* Set the magic */ - memcpy(result->magic, magic, 5); + memcpy(result->magic, magic, sizeof(WALLY_PSBT_MAGIC)); /* Read globals first */ pre_key = bytes; @@ -3022,8 +3022,8 @@ int wally_psbt_from_base64( /* Decode the base64 psbt */ decoded_len = base64_decode(decoded, safe_len, string, string_len); - if (decoded_len <= 5) { /* Make sure we also have enough bytes for the magic */ - ret = WALLY_EINVAL; + if (decoded_len <= (ssize_t)sizeof(WALLY_PSBT_MAGIC)) { + ret = WALLY_EINVAL; /* Not enough bytes for the magic */ goto done; } From e46ea793c90b83595d69224cf0188b1951a524da Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 21:54:06 +1200 Subject: [PATCH 112/205] transaction: Generalise replace_script to replace_bytes --- src/transaction.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/transaction.c b/src/transaction.c index 8a3d13e5c..0988bc573 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -186,17 +186,21 @@ static void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t s return p; } -static int replace_script(const unsigned char *script, size_t script_len, - unsigned char **script_out, size_t *script_len_out) +int replace_bytes(const unsigned char *bytes, size_t bytes_len, + unsigned char **bytes_out, size_t *bytes_len_out) { - /* TODO: Avoid reallocation if new script is smaller than the existing one */ - unsigned char *new_script = NULL; - if (!clone_bytes(&new_script, script, script_len)) + unsigned char *new_bytes = NULL; + + if (BYTES_INVALID(bytes, bytes_len) || BYTES_INVALID(*bytes_out, *bytes_len_out)) + return WALLY_EINVAL; + + /* TODO: Avoid reallocation if new bytes is smaller than the existing one */ + if (!clone_bytes(&new_bytes, bytes, bytes_len)) return WALLY_ENOMEM; - clear_and_free(*script_out, *script_len_out); - *script_out = new_script; - *script_len_out = script_len; + clear_and_free(*bytes_out, *bytes_len_out); + *bytes_out = new_bytes; + *bytes_len_out = bytes_len; return WALLY_OK; } @@ -3090,9 +3094,9 @@ int wally_tx_input_set_txhash(struct wally_tx_input *input, int wally_tx_output_set_script(struct wally_tx_output *output, const unsigned char *script, size_t script_len) { - if (!is_valid_tx_output(output) || BYTES_INVALID(script, script_len)) + if (!is_valid_tx_output(output)) return WALLY_EINVAL; - return replace_script(script, script_len, &output->script, &output->script_len); + return replace_bytes(script, script_len, &output->script, &output->script_len); } int wally_tx_output_set_satoshi(struct wally_tx_output *output, uint64_t satoshi) @@ -3272,9 +3276,9 @@ int wally_tx_set_input_witness(const struct wally_tx *tx, size_t index, int wally_tx_input_set_script(struct wally_tx_input *input, const unsigned char *script, size_t script_len) { - if (!is_valid_tx_input(input) || BYTES_INVALID(script, script_len)) + if (!is_valid_tx_input(input)) return WALLY_EINVAL; - return replace_script(script, script_len, &input->script, &input->script_len); + return replace_bytes(script, script_len, &input->script, &input->script_len); } TX_SET_B(input, script) From 3d3ab8e28225dfa57fe5cd0fd972a16514c755c7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 22:19:05 +1200 Subject: [PATCH 113/205] psbt: Add helpers to simplify pubkey length checks Also remove a FIXME made redundant in the next commit. --- src/psbt.c | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 756f16dfa..9aaf2c28f 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -25,6 +25,15 @@ static bool pubkey_is_compressed(const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMP return pubkey[0] == 0x02 || pubkey[0] == 0x03; } +static bool is_valid_pubkey_len(size_t len) +{ + return len == EC_PUBLIC_KEY_UNCOMPRESSED_LEN || len == EC_PUBLIC_KEY_LEN; +} + +static bool is_valid_optional_pubkey_len(size_t len) +{ + return !len || is_valid_pubkey_len(len); +} int wally_keypath_map_init_alloc(size_t alloc_len, struct wally_keypath_map **output) { @@ -99,9 +108,8 @@ int wally_add_new_keypath(struct wally_keypath_map *keypaths, { size_t latest; - if (fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || (pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN && pubkey_len != EC_PUBLIC_KEY_LEN)) { + if (fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || !is_valid_pubkey_len(pubkey_len)) return WALLY_EINVAL; - } if (keypaths->num_items == keypaths->items_allocation_len) { struct wally_keypath_item *new_items; @@ -216,9 +224,8 @@ int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, size_t sig_len) { size_t latest; - if (pubkey_len != EC_PUBLIC_KEY_LEN && pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN) { + if (!is_valid_pubkey_len(pubkey_len)) return WALLY_EINVAL; - } if (sigs->num_items == sigs->items_allocation_len) { struct wally_partial_sigs_item *new_items; @@ -1354,10 +1361,8 @@ static int pull_keypath(const unsigned char **cursor, size_t *max, size_t i, val_max; struct wally_keypath_item *kpitem; - if (key_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN - && key_len != EC_PUBLIC_KEY_LEN) { - return WALLY_EINVAL; /* Size of key is unexpected */ - } + if (!is_valid_pubkey_len(key_len)) + return WALLY_EINVAL; /* Check for duplicates */ for (i = 0; i < keypaths->num_items; ++i) { @@ -1869,10 +1874,10 @@ static int pull_psbt_input( size_t i; struct wally_partial_sigs_item *sigitem; struct wally_partial_sigs_map *partial_sigs = result->partial_sigs; - if (key_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN - && key_len != EC_PUBLIC_KEY_LEN) { - return WALLY_EINVAL; /* Size of key is unexpected */ - } + + if (!is_valid_pubkey_len(key_len)) + return WALLY_EINVAL; + /* Check for duplicates */ for (i = 0; i < partial_sigs->num_items; ++i) { if (memcmp(partial_sigs->items[i].pubkey, key, key_len) == 0) { @@ -2357,13 +2362,10 @@ static int pull_psbt_output( cursor, max)) { return WALLY_ENOMEM; } - if (result->blinding_pubkey_len == 0) { + if (!is_valid_optional_pubkey_len(result->blinding_pubkey_len)) + return WALLY_EINVAL; + if (result->blinding_pubkey_len == 0) result->blinding_pubkey = wally_malloc(1); - } else if (result->blinding_pubkey_len != EC_PUBLIC_KEY_UNCOMPRESSED_LEN && - result->blinding_pubkey_len != EC_PUBLIC_KEY_LEN) { - /* FIXME: blinding key elsewhere is assumed to be EC_PUBLIC_KEY_UNCOMPRESSED_LEN only */ - return WALLY_EINVAL; /* Size of key is unexpected */ - } break; } case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: { From abcf7d4449170f379948f933741452c95d6356d7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 22:20:51 +1200 Subject: [PATCH 114/205] psbt: Use replace_bytes to implement elements outputs setters Each of the old impls leaked the cloned data and failed to clear the replaced data. This change also allows blinding_pubkeys to be compressed or uncompressed in line with the rest of the codes expectations. --- src/psbt.c | 201 ++++++++++++++------------------------- src/transaction_shared.h | 2 + 2 files changed, 71 insertions(+), 132 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 9aaf2c28f..c660b014f 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -948,36 +948,24 @@ int wally_psbt_elements_output_init_alloc( } #endif /* BUILD_ELEMENTS */ -int wally_psbt_output_set_redeem_script( - struct wally_psbt_output *output, - unsigned char *redeem_script, - size_t redeem_script_len) +int wally_psbt_output_set_redeem_script(struct wally_psbt_output *output, + unsigned char *redeem_script, + size_t redeem_script_len) { - unsigned char *result_redeem_script; - - if (!clone_bytes(&result_redeem_script, redeem_script, redeem_script_len)) { - return WALLY_ENOMEM; - } - wally_free(output->redeem_script); - output->redeem_script = result_redeem_script; - output->redeem_script_len = redeem_script_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(redeem_script, redeem_script_len, + &output->redeem_script, &output->redeem_script_len); } -int wally_psbt_output_set_witness_script( - struct wally_psbt_output *output, - unsigned char *witness_script, - size_t witness_script_len) +int wally_psbt_output_set_witness_script(struct wally_psbt_output *output, + unsigned char *witness_script, + size_t witness_script_len) { - unsigned char *result_witness_script; - - if (!clone_bytes(&result_witness_script, witness_script, witness_script_len)) { - return WALLY_ENOMEM; - } - wally_free(output->witness_script); - output->witness_script = result_witness_script; - output->witness_script_len = witness_script_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(witness_script, witness_script_len, + &output->witness_script, &output->witness_script_len); } int wally_psbt_output_set_keypaths( @@ -1009,135 +997,84 @@ int wally_psbt_output_set_unknowns( } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_output_set_blinding_pubkey( - struct wally_psbt_output *output, - unsigned char *blinding_pubkey, - size_t blinding_pubkey_len) +int wally_psbt_elements_output_set_blinding_pubkey(struct wally_psbt_output *output, + unsigned char *blinding_pubkey, + size_t blinding_pubkey_len) { - unsigned char *new_blinding_pubkey = NULL; - - if (!output || BYTES_INVALID_N(blinding_pubkey, blinding_pubkey_len, EC_PUBLIC_KEY_UNCOMPRESSED_LEN)) + if (!output || !is_valid_optional_pubkey_len(blinding_pubkey_len)) return WALLY_EINVAL; - - if (blinding_pubkey && !clone_bytes(&new_blinding_pubkey, blinding_pubkey, blinding_pubkey_len)) - return WALLY_ENOMEM; - - wally_free(output->blinding_pubkey); - output->blinding_pubkey = new_blinding_pubkey; - output->blinding_pubkey_len = blinding_pubkey_len; - return WALLY_OK; + return replace_bytes(blinding_pubkey, blinding_pubkey_len, + &output->blinding_pubkey, &output->blinding_pubkey_len); } -int wally_psbt_elements_output_set_value_commitment( - struct wally_psbt_output *output, - unsigned char *value_commitment, - size_t value_commitment_len) +int wally_psbt_elements_output_set_value_commitment(struct wally_psbt_output *output, + unsigned char *value_commitment, + size_t value_commitment_len) { - unsigned char *result_value_commitment; - - if (!clone_bytes(&result_value_commitment, value_commitment, value_commitment_len)) { - return WALLY_ENOMEM; - } - wally_free(output->value_commitment); - output->value_commitment = value_commitment; - output->value_commitment_len = value_commitment_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(value_commitment, value_commitment_len, + &output->value_commitment, &output->value_commitment_len); } -int wally_psbt_elements_output_set_value_blinder( - struct wally_psbt_output *output, - unsigned char *value_blinder, - size_t value_blinder_len) +int wally_psbt_elements_output_set_value_blinder(struct wally_psbt_output *output, + unsigned char *value_blinder, + size_t value_blinder_len) { - unsigned char *result_value_blinder; - - if (!clone_bytes(&result_value_blinder, value_blinder, value_blinder_len)) { - return WALLY_ENOMEM; - } - wally_free(output->value_blinder); - output->value_blinder = value_blinder; - output->value_blinder_len = value_blinder_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(value_blinder, value_blinder_len, + &output->value_blinder, &output->value_blinder_len); } -int wally_psbt_elements_output_set_asset_commitment( - struct wally_psbt_output *output, - unsigned char *asset_commitment, - size_t asset_commitment_len) +int wally_psbt_elements_output_set_asset_commitment(struct wally_psbt_output *output, + unsigned char *asset_commitment, + size_t asset_commitment_len) { - unsigned char *result_asset_commitment; - - if (!clone_bytes(&result_asset_commitment, asset_commitment, asset_commitment_len)) { - return WALLY_ENOMEM; - } - wally_free(output->asset_commitment); - output->asset_commitment = asset_commitment; - output->asset_commitment_len = asset_commitment_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(asset_commitment, asset_commitment_len, + &output->asset_commitment, &output->asset_commitment_len); } -int wally_psbt_elements_output_set_asset_blinder( - struct wally_psbt_output *output, - unsigned char *asset_blinder, - size_t asset_blinder_len) +int wally_psbt_elements_output_set_asset_blinder(struct wally_psbt_output *output, + unsigned char *asset_blinder, + size_t asset_blinder_len) { - unsigned char *result_asset_blinder; - - if (!clone_bytes(&result_asset_blinder, asset_blinder, asset_blinder_len)) { - return WALLY_ENOMEM; - } - wally_free(output->asset_blinder); - output->asset_blinder = asset_blinder; - output->asset_blinder_len = asset_blinder_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(asset_blinder, asset_blinder_len, + &output->asset_blinder, &output->asset_blinder_len); } -int wally_psbt_elements_output_set_nonce_commitment( - struct wally_psbt_output *output, - unsigned char *nonce_commitment, - size_t nonce_commitment_len) +int wally_psbt_elements_output_set_nonce_commitment(struct wally_psbt_output *output, + unsigned char *nonce_commitment, + size_t nonce_commitment_len) { - unsigned char *result_nonce_commitment; - - if (!clone_bytes(&result_nonce_commitment, nonce_commitment, nonce_commitment_len)) { - return WALLY_ENOMEM; - } - wally_free(output->nonce_commitment); - output->nonce_commitment = nonce_commitment; - output->nonce_commitment_len = nonce_commitment_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(nonce_commitment, nonce_commitment_len, + &output->nonce_commitment, &output->nonce_commitment_len); } -int wally_psbt_elements_output_set_range_proof( - struct wally_psbt_output *output, - unsigned char *range_proof, - size_t range_proof_len) +int wally_psbt_elements_output_set_range_proof(struct wally_psbt_output *output, + unsigned char *range_proof, + size_t range_proof_len) { - unsigned char *result_range_proof; - - if (!clone_bytes(&result_range_proof, range_proof, range_proof_len)) { - return WALLY_ENOMEM; - } - wally_free(output->range_proof); - output->range_proof = range_proof; - output->range_proof_len = range_proof_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(range_proof, range_proof_len, + &output->range_proof, &output->range_proof_len); } -int wally_psbt_elements_output_set_surjection_proof( - struct wally_psbt_output *output, - unsigned char *surjection_proof, - size_t surjection_proof_len) +int wally_psbt_elements_output_set_surjection_proof(struct wally_psbt_output *output, + unsigned char *surjection_proof, + size_t surjection_proof_len) { - unsigned char *result_surjection_proof; - - if (!clone_bytes(&result_surjection_proof, surjection_proof, surjection_proof_len)) { - return WALLY_ENOMEM; - } - wally_free(output->surjection_proof); - output->surjection_proof = surjection_proof; - output->surjection_proof_len = surjection_proof_len; - return WALLY_OK; + if (!output) + return WALLY_EINVAL; + return replace_bytes(surjection_proof, surjection_proof_len, + &output->surjection_proof, &output->surjection_proof_len); } #endif/* BUILD_ELEMENTS */ diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 46fa492ff..078bd0dee 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -17,6 +17,8 @@ extern "C" { #define BYTES_INVALID_N(p, len, siz) ((p != NULL) != (len == siz)) bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len); +int replace_bytes(const unsigned char *bytes, size_t bytes_len, + unsigned char **bytes_out, size_t *bytes_len_out); void clear_and_free(void *p, size_t len); int analyze_tx(const unsigned char *bytes, size_t bytes_len, uint32_t flags, size_t *num_inputs, size_t *num_outputs, From fdff995e846d1caf960ddf4c30d3a72667f10e55 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 22:52:46 +1200 Subject: [PATCH 115/205] tests: Use wally_free_string to free wally allocated string --- src/ctest/test_psbt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ctest/test_psbt.c b/src/ctest/test_psbt.c index 37f6f4733..a9ec8d0b2 100644 --- a/src/ctest/test_psbt.c +++ b/src/ctest/test_psbt.c @@ -37,7 +37,7 @@ int main(void) if (strcmp(output, valid_psbts[i].base64) != 0) { errx(1, "psbt %s turned into %s?", valid_psbts[i].base64, output); } - free(output); + wally_free_string(output); if (wally_psbt_get_length(psbt, &len) != WALLY_OK) { errx(1, "Failed to get pbst %s len", valid_psbts[i].base64); From dd35068f40f5abe1087021669906dc1f34dd0dd1 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 23:11:58 +1200 Subject: [PATCH 116/205] psbt: Fix leak in clone_unknowns_map Since the number of items wasn't updated as items were added, this code would leak if allocation failed part way through. --- src/psbt.c | 39 +++++++++++++++------------------------ 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index c660b014f..4a5944dab 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -307,34 +307,30 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) return WALLY_OK; } +static int add_unknowns_item(struct wally_unknowns_map *unknowns, struct wally_unknowns_item *item) +{ + return wally_add_new_unknown(unknowns, item->key, item->key_len, item->value, item->value_len); +} + static struct wally_unknowns_map *clone_unknowns_map(const struct wally_unknowns_map *unknowns) { struct wally_unknowns_map *result; size_t i; + int ret; - if (wally_unknowns_map_init_alloc(unknowns->items_allocation_len, &result) != WALLY_OK) { + if (!unknowns) return NULL; - } - for (i = 0; i < unknowns->num_items; ++i) { - if (unknowns->items[i].key) { - if (!clone_bytes(&result->items[i].key, unknowns->items[i].key, unknowns->items[i].key_len)) { - goto fail; - } - result->items[i].key_len = unknowns->items[i].key_len; - } - if (unknowns->items[i].value) { - if (!clone_bytes(&result->items[i].value, unknowns->items[i].value, unknowns->items[i].value_len)) { - goto fail; - } - result->items[i].value_len = unknowns->items[i].value_len; - } + ret = wally_unknowns_map_init_alloc(unknowns->items_allocation_len, &result); + + for (i = 0; ret == WALLY_OK && i < unknowns->num_items; ++i) + ret = add_unknowns_item(result, unknowns->items + i); + + if (ret != WALLY_OK) { + wally_unknowns_map_free(result); + result = NULL; } - result->num_items = unknowns->num_items; return result; -fail: - wally_unknowns_map_free(result); - return NULL; } int wally_add_new_unknown(struct wally_unknowns_map *unknowns, @@ -382,11 +378,6 @@ int wally_add_new_unknown(struct wally_unknowns_map *unknowns, return WALLY_OK; } -static int add_unknowns_item(struct wally_unknowns_map *unknowns, struct wally_unknowns_item *item) -{ - return wally_add_new_unknown(unknowns, item->key, item->key_len, item->value, item->value_len); -} - int wally_psbt_input_init_alloc( struct wally_tx *non_witness_utxo, struct wally_tx_output *witness_utxo, From 8ed09e5aaa491f374c29590020b7e9ee05714f79 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 23:37:52 +1200 Subject: [PATCH 117/205] psbt: share code to set the unknown map member in inputs and outputs Adds parameter checking and allow setting a null map also. --- src/psbt.c | 41 +++++++++++++++++++---------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 4a5944dab..787577c17 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -333,6 +333,19 @@ static struct wally_unknowns_map *clone_unknowns_map(const struct wally_unknowns return result; } +static int replace_unknowns(const struct wally_unknowns_map *src, + struct wally_unknowns_map **dst) +{ + struct wally_unknowns_map *new_unknowns = NULL; + + if (src && !(new_unknowns = clone_unknowns_map(src))) + return WALLY_ENOMEM; + + wally_unknowns_map_free(*dst); + *dst = new_unknowns; + return WALLY_OK; +} + int wally_add_new_unknown(struct wally_unknowns_map *unknowns, unsigned char *key, size_t key_len, @@ -648,18 +661,10 @@ int wally_psbt_input_set_partial_sigs( return WALLY_OK; } -int wally_psbt_input_set_unknowns( - struct wally_psbt_input *input, - struct wally_unknowns_map *unknowns) +int wally_psbt_input_set_unknowns(struct wally_psbt_input *input, + struct wally_unknowns_map *unknowns) { - struct wally_unknowns_map *result_unknowns; - - if (!(result_unknowns = clone_unknowns_map(unknowns))) { - return WALLY_ENOMEM; - } - wally_unknowns_map_free(input->unknowns); - input->unknowns = result_unknowns; - return WALLY_OK; + return input ? replace_unknowns(unknowns, &input->unknowns) : WALLY_EINVAL; } int wally_psbt_input_set_sighash_type( @@ -973,18 +978,10 @@ int wally_psbt_output_set_keypaths( return WALLY_OK; } -int wally_psbt_output_set_unknowns( - struct wally_psbt_output *output, - struct wally_unknowns_map *unknowns) +int wally_psbt_output_set_unknowns(struct wally_psbt_output *output, + struct wally_unknowns_map *unknowns) { - struct wally_unknowns_map *result_unknowns; - - if (!(result_unknowns = clone_unknowns_map(unknowns))) { - return WALLY_ENOMEM; - } - wally_unknowns_map_free(output->unknowns); - output->unknowns = result_unknowns; - return WALLY_OK; + return output ? replace_unknowns(unknowns, &output->unknowns) : WALLY_EINVAL; } #ifdef BUILD_ELEMENTS From 5b835cfeaadb2a60fd15a7b97500012579577612 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 9 Jul 2020 23:41:42 +1200 Subject: [PATCH 118/205] psbt: remove redundant checks before clear_and_free --- src/psbt.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 787577c17..679aacf3d 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -180,11 +180,8 @@ int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs) size_t i; if (sigs) { - for (i = 0; i < sigs->num_items; ++i) { - if (sigs->items[i].sig) { - clear_and_free(sigs->items[i].sig, sigs->items[i].sig_len); - } - } + for (i = 0; i < sigs->num_items; ++i) + clear_and_free(sigs->items[i].sig, sigs->items[i].sig_len); clear_and_free(sigs->items, sigs->items_allocation_len * sizeof(*sigs->items)); clear_and_free(sigs, sizeof(*sigs)); } @@ -294,12 +291,8 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) if (unknowns) { for (i = 0; i < unknowns->num_items; ++i) { - if (unknowns->items[i].key) { - clear_and_free(unknowns->items[i].key, unknowns->items[i].key_len); - } - if (unknowns->items[i].value) { - clear_and_free(unknowns->items[i].value, unknowns->items[i].value_len); - } + clear_and_free(unknowns->items[i].key, unknowns->items[i].key_len); + clear_and_free(unknowns->items[i].value, unknowns->items[i].value_len); } clear_and_free(unknowns->items, unknowns->num_items * sizeof(*unknowns->items)); clear_and_free(unknowns, sizeof(*unknowns)); From bdd087b372837e0714a96ebbcc23bddb0f33a029 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 00:01:37 +1200 Subject: [PATCH 119/205] psbt: Use replace_bytes to implement elements inputs setters As per 88b4d3210a6a3fd2b4697f0bfe0b14cb791750c0 but for inputs. --- src/psbt.c | 171 ++++++++++++++++++----------------------------------- 1 file changed, 58 insertions(+), 113 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 679aacf3d..0ba3bdd01 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -564,52 +564,34 @@ int wally_psbt_input_set_witness_utxo( return ret; } -int wally_psbt_input_set_redeem_script( - struct wally_psbt_input *input, - unsigned char *redeem_script, - size_t redeem_script_len) +int wally_psbt_input_set_redeem_script(struct wally_psbt_input *input, + unsigned char *redeem_script, + size_t redeem_script_len) { - unsigned char *result_redeem_script; - - if (!clone_bytes(&result_redeem_script, redeem_script, redeem_script_len)) { - return WALLY_ENOMEM; - } - wally_free(input->redeem_script); - input->redeem_script = result_redeem_script; - input->redeem_script_len = redeem_script_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(redeem_script, redeem_script_len, + &input->redeem_script, &input->redeem_script_len); } -int wally_psbt_input_set_witness_script( - struct wally_psbt_input *input, - unsigned char *witness_script, - size_t witness_script_len) +int wally_psbt_input_set_witness_script(struct wally_psbt_input *input, + unsigned char *witness_script, + size_t witness_script_len) { - unsigned char *result_witness_script; - - if (!clone_bytes(&result_witness_script, witness_script, witness_script_len)) { - return WALLY_ENOMEM; - } - wally_free(input->witness_script); - input->witness_script = result_witness_script; - input->witness_script_len = witness_script_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(witness_script, witness_script_len, + &input->witness_script, &input->witness_script_len); } -int wally_psbt_input_set_final_script_sig( - struct wally_psbt_input *input, - unsigned char *final_script_sig, - size_t final_script_sig_len) +int wally_psbt_input_set_final_script_sig(struct wally_psbt_input *input, + unsigned char *final_script_sig, + size_t final_script_sig_len) { - unsigned char *result_final_script_sig; - - if (!clone_bytes(&result_final_script_sig, final_script_sig, final_script_sig_len)) { - return WALLY_ENOMEM; - } - wally_free(input->final_script_sig); - input->final_script_sig = result_final_script_sig; - input->final_script_sig_len = final_script_sig_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(final_script_sig, final_script_sig_len, + &input->final_script_sig, &input->final_script_sig_len); } int wally_psbt_input_set_final_witness( @@ -678,52 +660,32 @@ int wally_psbt_elements_input_set_value( return WALLY_OK; } -int wally_psbt_elements_input_set_value_blinder( - struct wally_psbt_input *input, - unsigned char *value_blinder, - size_t value_blinder_len) +int wally_psbt_elements_input_set_value_blinder(struct wally_psbt_input *input, + unsigned char *value_blinder, + size_t value_blinder_len) { - unsigned char *result_value_blinder; - - if (!clone_bytes(&result_value_blinder, value_blinder, value_blinder_len)) { - return WALLY_ENOMEM; - } - wally_free(input->value_blinder); - input->value_blinder = value_blinder; - input->value_blinder_len = value_blinder_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(value_blinder, value_blinder_len, + &input->value_blinder, &input->value_blinder_len); } -int wally_psbt_elements_input_set_asset( - struct wally_psbt_input *input, - unsigned char *asset, - size_t asset_len) +int wally_psbt_elements_input_set_asset(struct wally_psbt_input *input, + unsigned char *asset, size_t asset_len) { - unsigned char *result_asset; - - if (!clone_bytes(&result_asset, asset, asset_len)) { - return WALLY_ENOMEM; - } - wally_free(input->asset); - input->asset = asset; - input->asset_len = asset_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(asset, asset_len, &input->asset, &input->asset_len); } -int wally_psbt_elements_input_set_asset_blinder( - struct wally_psbt_input *input, - unsigned char *asset_blinder, - size_t asset_blinder_len) +int wally_psbt_elements_input_set_asset_blinder(struct wally_psbt_input *input, + unsigned char *asset_blinder, + size_t asset_blinder_len) { - unsigned char *result_asset_blinder; - - if (!clone_bytes(&result_asset_blinder, asset_blinder, asset_blinder_len)) { - return WALLY_ENOMEM; - } - wally_free(input->asset_blinder); - input->asset_blinder = asset_blinder; - input->asset_blinder_len = asset_blinder_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(asset_blinder, asset_blinder_len, + &input->asset_blinder, &input->asset_blinder_len); } int wally_psbt_elements_input_set_peg_in_tx( @@ -747,47 +709,30 @@ int wally_psbt_elements_input_set_txout_proof( unsigned char *txout_proof, size_t txout_proof_len) { - unsigned char *result_txout_proof; - - if (!clone_bytes(&result_txout_proof, txout_proof, txout_proof_len)) { - return WALLY_ENOMEM; - } - wally_free(input->txout_proof); - input->txout_proof = txout_proof; - input->txout_proof_len = txout_proof_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(txout_proof, txout_proof_len, + &input->txout_proof, &input->txout_proof_len); } -int wally_psbt_elements_input_set_genesis_hash( - struct wally_psbt_input *input, - unsigned char *genesis_hash, - size_t genesis_hash_len) +int wally_psbt_elements_input_set_genesis_hash(struct wally_psbt_input *input, + unsigned char *genesis_hash, + size_t genesis_hash_len) { - unsigned char *result_genesis_hash; - - if (!clone_bytes(&result_genesis_hash, genesis_hash, genesis_hash_len)) { - return WALLY_ENOMEM; - } - wally_free(input->genesis_hash); - input->genesis_hash = genesis_hash; - input->genesis_hash_len = genesis_hash_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(genesis_hash, genesis_hash_len, + &input->genesis_hash, &input->genesis_hash_len); } -int wally_psbt_elements_input_set_claim_script( - struct wally_psbt_input *input, - unsigned char *claim_script, - size_t claim_script_len) +int wally_psbt_elements_input_set_claim_script(struct wally_psbt_input *input, + unsigned char *claim_script, + size_t claim_script_len) { - unsigned char *result_claim_script; - - if (!clone_bytes(&result_claim_script, claim_script, claim_script_len)) { - return WALLY_ENOMEM; - } - wally_free(input->claim_script); - input->claim_script = claim_script; - input->claim_script_len = claim_script_len; - return WALLY_OK; + if (!input) + return WALLY_EINVAL; + return replace_bytes(claim_script, claim_script_len, + &input->claim_script, &input->claim_script_len); } #endif /* BUILD_ELEMENTS */ From 6bd19a8c8b1a5b33ce36e4297e8692f9355556d3 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 00:30:21 +1200 Subject: [PATCH 120/205] psbt: merge replace_unknowns with clone_unknowns_map --- src/psbt.c | 37 +++++++++++++------------------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 0ba3bdd01..3046a94c0 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -305,38 +305,27 @@ static int add_unknowns_item(struct wally_unknowns_map *unknowns, struct wally_u return wally_add_new_unknown(unknowns, item->key, item->key_len, item->value, item->value_len); } -static struct wally_unknowns_map *clone_unknowns_map(const struct wally_unknowns_map *unknowns) +static int replace_unknowns(const struct wally_unknowns_map *src, + struct wally_unknowns_map **dst) { - struct wally_unknowns_map *result; + struct wally_unknowns_map *result = NULL; size_t i; - int ret; - - if (!unknowns) - return NULL; + int ret = WALLY_OK; - ret = wally_unknowns_map_init_alloc(unknowns->items_allocation_len, &result); + if (src) { + ret = wally_unknowns_map_init_alloc(src->items_allocation_len, &result); - for (i = 0; ret == WALLY_OK && i < unknowns->num_items; ++i) - ret = add_unknowns_item(result, unknowns->items + i); + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_unknowns_item(result, src->items + i); + } if (ret != WALLY_OK) { wally_unknowns_map_free(result); - result = NULL; + } else { + wally_unknowns_map_free(*dst); + *dst = result; } - return result; -} - -static int replace_unknowns(const struct wally_unknowns_map *src, - struct wally_unknowns_map **dst) -{ - struct wally_unknowns_map *new_unknowns = NULL; - - if (src && !(new_unknowns = clone_unknowns_map(src))) - return WALLY_ENOMEM; - - wally_unknowns_map_free(*dst); - *dst = new_unknowns; - return WALLY_OK; + return ret; } int wally_add_new_unknown(struct wally_unknowns_map *unknowns, From a722cbd5e5ec102d18563b6c1b2a9ccfd08313a7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 00:41:05 +1200 Subject: [PATCH 121/205] psbt: Share keypath setting code like the updated unknowns code Again, this fixes a leak in the error case. --- src/psbt.c | 80 +++++++++++++++++++----------------------------------- 1 file changed, 28 insertions(+), 52 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 3046a94c0..730017c73 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -70,32 +70,34 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) return WALLY_OK; } -static struct wally_keypath_map *clone_keypath_map(const struct wally_keypath_map *keypaths) +static int add_keypath_item(struct wally_keypath_map *keypaths, struct wally_keypath_item *item) { - struct wally_keypath_map *result; + return wally_add_new_keypath(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, + item->fingerprint, BIP32_KEY_FINGERPRINT_LEN, + item->path, item->path_len); +} + +static int replace_keypaths(const struct wally_keypath_map *src, + struct wally_keypath_map **dst) +{ + struct wally_keypath_map *result = NULL; size_t i; + int ret = WALLY_OK; - if (wally_keypath_map_init_alloc(keypaths->items_allocation_len, &result) != WALLY_OK) { - return NULL; - } + if (src) { + ret = wally_keypath_map_init_alloc(src->items_allocation_len, &result); - for (i = 0; i < keypaths->num_items; ++i) { - memcpy(&result->items[i].pubkey, keypaths->items[i].pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - memcpy(&result->items[i].fingerprint, keypaths->items[i].fingerprint, 4); - if (keypaths->items[i].path) { - if (!clone_bytes((unsigned char **)&result->items[i].path, (unsigned char *)keypaths->items[i].path, keypaths->items[i].path_len * sizeof(*keypaths->items[i].path))) { - goto fail; - } - result->items[i].path_len = keypaths->items[i].path_len; - } + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_keypath_item(result, src->items + i); } - result->num_items = keypaths->num_items; - return result; - -fail: - wally_keypath_map_free(result); - return NULL; + if (ret != WALLY_OK) { + wally_keypath_map_free(result); + } else { + wally_keypath_map_free(*dst); + *dst = result; + } + return ret; } int wally_add_new_keypath(struct wally_keypath_map *keypaths, @@ -144,16 +146,6 @@ int wally_add_new_keypath(struct wally_keypath_map *keypaths, return WALLY_OK; } -static int add_keypath_item(struct wally_keypath_map *keypaths, struct wally_keypath_item *item) -{ - return wally_add_new_keypath(keypaths, item->pubkey, - EC_PUBLIC_KEY_UNCOMPRESSED_LEN, - item->fingerprint, - BIP32_KEY_FINGERPRINT_LEN, - item->path, - item->path_len); -} - int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wally_partial_sigs_map **output) { struct wally_partial_sigs_map *result; @@ -597,18 +589,10 @@ int wally_psbt_input_set_final_witness( return WALLY_OK; } -int wally_psbt_input_set_keypaths( - struct wally_psbt_input *input, - struct wally_keypath_map *keypaths) +int wally_psbt_input_set_keypaths(struct wally_psbt_input *input, + struct wally_keypath_map *keypaths) { - struct wally_keypath_map *result_keypaths; - - if (!(result_keypaths = clone_keypath_map(keypaths))) { - return WALLY_ENOMEM; - } - wally_keypath_map_free(input->keypaths); - input->keypaths = result_keypaths; - return WALLY_OK; + return input ? replace_keypaths(keypaths, &input->keypaths) : WALLY_EINVAL; } int wally_psbt_input_set_partial_sigs( @@ -891,18 +875,10 @@ int wally_psbt_output_set_witness_script(struct wally_psbt_output *output, &output->witness_script, &output->witness_script_len); } -int wally_psbt_output_set_keypaths( - struct wally_psbt_output *output, - struct wally_keypath_map *keypaths) +int wally_psbt_output_set_keypaths(struct wally_psbt_output *output, + struct wally_keypath_map *keypaths) { - struct wally_keypath_map *result_keypaths; - - if (!(result_keypaths = clone_keypath_map(keypaths))) { - return WALLY_ENOMEM; - } - wally_keypath_map_free(output->keypaths); - output->keypaths = result_keypaths; - return WALLY_OK; + return output ? replace_keypaths(keypaths, &output->keypaths) : WALLY_EINVAL; } int wally_psbt_output_set_unknowns(struct wally_psbt_output *output, From 33d28073f4f20dbe8f9cd25f78773f44576cf2ec Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 00:51:07 +1200 Subject: [PATCH 122/205] psbt: Don't leak peg_in_tx when setting it on inputs --- src/psbt.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 730017c73..0ca2b8c86 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -661,22 +661,22 @@ int wally_psbt_elements_input_set_asset_blinder(struct wally_psbt_input *input, &input->asset_blinder, &input->asset_blinder_len); } -int wally_psbt_elements_input_set_peg_in_tx( - struct wally_psbt_input *input, - struct wally_tx *peg_in_tx) +int wally_psbt_elements_input_set_peg_in_tx(struct wally_psbt_input *input, + struct wally_tx *peg_in_tx) { int ret = WALLY_OK; - struct wally_tx *result_peg_in_tx; + struct wally_tx *new_tx; - if ((ret = wally_tx_clone(peg_in_tx, 0, &result_peg_in_tx)) != WALLY_OK) { - return ret; + if (!input) + return WALLY_EINVAL; + + if ((ret = wally_tx_clone(peg_in_tx, 0, &new_tx)) == WALLY_OK) { + wally_tx_free(input->peg_in_tx); + input->peg_in_tx = new_tx; } - wally_tx_free(input->peg_in_tx); - input->peg_in_tx = peg_in_tx; return ret; } - int wally_psbt_elements_input_set_txout_proof( struct wally_psbt_input *input, unsigned char *txout_proof, From 2f42da22f4fbc2c850ac079d308b1f17095a55dd Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 01:03:20 +1200 Subject: [PATCH 123/205] psbt: Share partial sigs setting code like the updated unknowns code As before, this fixes a leak in the error case. --- src/psbt.c | 61 +++++++++++++++++++++--------------------------------- 1 file changed, 24 insertions(+), 37 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 0ca2b8c86..380a5fb37 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -180,30 +180,33 @@ int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs) return WALLY_OK; } -static struct wally_partial_sigs_map *clone_partial_sigs_map(const struct wally_partial_sigs_map *sigs) +static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, struct wally_partial_sigs_item *item) { - struct wally_partial_sigs_map *result; + return wally_add_new_partial_sig(sigs, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, + item->sig, item->sig_len); +} + +static int replace_partial_sigs(const struct wally_partial_sigs_map *src, + struct wally_partial_sigs_map **dst) +{ + struct wally_partial_sigs_map *result = NULL; size_t i; + int ret = WALLY_OK; - if (wally_partial_sigs_map_init_alloc(sigs->items_allocation_len, &result) != WALLY_OK) { - return NULL; - } + if (src) { + ret = wally_partial_sigs_map_init_alloc(src->items_allocation_len, &result); - for (i = 0; i < sigs->num_items; ++i) { - memcpy(&result->items[i].pubkey, sigs->items[i].pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - if (sigs->items[i].sig) { - if (!clone_bytes(&result->items[i].sig, sigs->items[i].sig, sigs->items[i].sig_len)) { - goto fail; - } - result->items[i].sig_len = sigs->items[i].sig_len; - } + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_partial_sig_item(result, src->items + i); } - result->num_items = sigs->num_items; - return result; -fail: - wally_partial_sigs_map_free(result); - return NULL; + if (ret != WALLY_OK) { + wally_partial_sigs_map_free(result); + } else { + wally_partial_sigs_map_free(*dst); + *dst = result; + } + return ret; } int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, @@ -248,14 +251,6 @@ int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, return WALLY_OK; } -static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, struct wally_partial_sigs_item *item) -{ - return wally_add_new_partial_sig(sigs, item->pubkey, - EC_PUBLIC_KEY_UNCOMPRESSED_LEN, - item->sig, - item->sig_len); -} - int wally_unknowns_map_init_alloc(size_t alloc_len, struct wally_unknowns_map **output) { struct wally_unknowns_map *result; @@ -595,18 +590,10 @@ int wally_psbt_input_set_keypaths(struct wally_psbt_input *input, return input ? replace_keypaths(keypaths, &input->keypaths) : WALLY_EINVAL; } -int wally_psbt_input_set_partial_sigs( - struct wally_psbt_input *input, - struct wally_partial_sigs_map *partial_sigs) +int wally_psbt_input_set_partial_sigs(struct wally_psbt_input *input, + struct wally_partial_sigs_map *partial_sigs) { - struct wally_partial_sigs_map *result_partial_sigs; - - if (!(result_partial_sigs = clone_partial_sigs_map(partial_sigs))) { - return WALLY_ENOMEM; - } - wally_partial_sigs_map_free(input->partial_sigs); - input->partial_sigs = result_partial_sigs; - return WALLY_OK; + return input ? replace_partial_sigs(partial_sigs, &input->partial_sigs) : WALLY_EINVAL; } int wally_psbt_input_set_unknowns(struct wally_psbt_input *input, From 679c8760d2bb448fb1dec0ef0d767b363a29bc93 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 01:09:51 +1200 Subject: [PATCH 124/205] psbt: psbt_input_set_final_witness: Add checks, allow NULL witness --- src/psbt.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 380a5fb37..955a170cf 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -570,17 +570,19 @@ int wally_psbt_input_set_final_script_sig(struct wally_psbt_input *input, &input->final_script_sig, &input->final_script_sig_len); } -int wally_psbt_input_set_final_witness( - struct wally_psbt_input *input, - struct wally_tx_witness_stack *final_witness) +int wally_psbt_input_set_final_witness(struct wally_psbt_input *input, + struct wally_tx_witness_stack *final_witness) { - struct wally_tx_witness_stack *result_final_witness; + struct wally_tx_witness_stack *new_witness = NULL; + + if (!input) + return WALLY_EINVAL; - if (!(result_final_witness = clone_witness(final_witness))) { + if (final_witness && !(new_witness = clone_witness(final_witness))) return WALLY_ENOMEM; - } + wally_tx_witness_stack_free(input->final_witness); - input->final_witness = result_final_witness; + input->final_witness = new_witness; return WALLY_OK; } From 5ce62ddb2b4472b9f9426b415b84674c1976a4be Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 01:14:14 +1200 Subject: [PATCH 125/205] psbt: psbt_input_set_non_witness_utxo: Add input check --- src/psbt.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 955a170cf..247d16363 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -507,18 +507,19 @@ int wally_psbt_elements_input_init_alloc( } #endif /* BUILD_ELEMENTS */ -int wally_psbt_input_set_non_witness_utxo( - struct wally_psbt_input *input, - struct wally_tx *non_witness_utxo) +int wally_psbt_input_set_non_witness_utxo(struct wally_psbt_input *input, + struct wally_tx *non_witness_utxo) { int ret = WALLY_OK; - struct wally_tx *result_non_witness_utxo; + struct wally_tx *new_tx; - if ((ret = wally_tx_clone(non_witness_utxo, 0, &result_non_witness_utxo)) != WALLY_OK) { - return ret; + if (!input) + return WALLY_EINVAL; + + if ((ret = wally_tx_clone(non_witness_utxo, 0, &new_tx)) == WALLY_OK) { + wally_tx_free(input->non_witness_utxo); + input->non_witness_utxo = new_tx; } - wally_tx_free(input->non_witness_utxo); - input->non_witness_utxo = result_non_witness_utxo; return ret; } From 422f452e0bff0d9ecfd1e821dfcc137843ea928c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 08:51:52 +1200 Subject: [PATCH 126/205] psbt: Share code to grow array members --- src/psbt.c | 82 +++++++++++++++------------------------- src/transaction.c | 2 +- src/transaction_shared.h | 1 + 3 files changed, 33 insertions(+), 52 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 247d16363..d4aa7eeba 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -100,6 +100,22 @@ static int replace_keypaths(const struct wally_keypath_map *src, return ret; } +static int array_grow(void **src, size_t num_items, size_t *allocation_len, size_t item_size) +{ + if (num_items == *allocation_len) { + /* Array is full, allocate more space */ + const size_t n = (*allocation_len == 0 ? 1 : *allocation_len) * 2; + void *p = realloc_array(*src, *allocation_len, n, item_size); + if (!p) + return WALLY_ENOMEM; + /* Free and replace the old array with the new enlarged copy */ + clear_and_free(*src, num_items * item_size); + *src = p; + *allocation_len = n; + } + return WALLY_OK; +} + int wally_add_new_keypath(struct wally_keypath_map *keypaths, unsigned char *pubkey, size_t pubkey_len, @@ -109,27 +125,15 @@ int wally_add_new_keypath(struct wally_keypath_map *keypaths, size_t path_len) { size_t latest; + int ret; if (fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || !is_valid_pubkey_len(pubkey_len)) return WALLY_EINVAL; - if (keypaths->num_items == keypaths->items_allocation_len) { - struct wally_keypath_item *new_items; - size_t new_alloc_len = 1; - if (keypaths->items_allocation_len != 0) { - new_alloc_len = keypaths->items_allocation_len * 2; - } - new_items = wally_malloc(new_alloc_len * sizeof(struct wally_keypath_item)); - if (!new_items) { - return WALLY_ENOMEM; - } - wally_bzero(new_items, new_alloc_len * sizeof(*new_items)); - memcpy(new_items, keypaths->items, keypaths->items_allocation_len * sizeof(*keypaths->items)); - - clear_and_free(keypaths->items, keypaths->items_allocation_len * sizeof(*keypaths->items)); - keypaths->items = new_items; - keypaths->items_allocation_len = new_alloc_len; - } + ret = array_grow((void *)&keypaths->items, keypaths->num_items, + &keypaths->items_allocation_len, sizeof(struct wally_keypath_item)); + if (ret != WALLY_OK) + return ret; latest = keypaths->num_items; @@ -216,26 +220,15 @@ int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, size_t sig_len) { size_t latest; + int ret; + if (!is_valid_pubkey_len(pubkey_len)) return WALLY_EINVAL; - if (sigs->num_items == sigs->items_allocation_len) { - struct wally_partial_sigs_item *new_items; - size_t new_alloc_len = 1; - if (sigs->items_allocation_len != 0) { - new_alloc_len = sigs->items_allocation_len * 2; - } - new_items = wally_malloc(new_alloc_len * sizeof(struct wally_partial_sigs_item)); - if (!new_items) { - return WALLY_ENOMEM; - } - wally_bzero(new_items, new_alloc_len * sizeof(*new_items)); - memcpy(new_items, sigs->items, sigs->items_allocation_len * sizeof(*sigs->items)); - - clear_and_free(sigs->items, sigs->items_allocation_len * sizeof(*sigs->items)); - sigs->items = new_items; - sigs->items_allocation_len = new_alloc_len; - } + ret = array_grow((void *)&sigs->items, sigs->num_items, + &sigs->items_allocation_len, sizeof(struct wally_partial_sigs_item)); + if (ret != WALLY_OK) + return ret; latest = sigs->num_items; @@ -323,23 +316,10 @@ int wally_add_new_unknown(struct wally_unknowns_map *unknowns, { size_t latest; - if (unknowns->num_items == unknowns->items_allocation_len) { - struct wally_unknowns_item *new_items; - size_t new_alloc_len = 1; - if (unknowns->items_allocation_len != 0) { - new_alloc_len = unknowns->items_allocation_len * 2; - } - new_items = wally_malloc(new_alloc_len * sizeof(struct wally_unknowns_item)); - if (!new_items) { - return WALLY_ENOMEM; - } - wally_bzero(new_items, new_alloc_len * sizeof(*new_items)); - memcpy(new_items, unknowns->items, unknowns->items_allocation_len * sizeof(*unknowns->items)); - - clear_and_free(unknowns->items, unknowns->items_allocation_len * sizeof(*unknowns->items)); - unknowns->items = new_items; - unknowns->items_allocation_len = new_alloc_len; - } + int ret = array_grow((void *)&unknowns->items, unknowns->num_items, + &unknowns->items_allocation_len, sizeof(struct wally_unknowns_item)); + if (ret != WALLY_OK) + return ret; latest = unknowns->num_items; diff --git a/src/transaction.c b/src/transaction.c index 0988bc573..c7b1449c8 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -175,7 +175,7 @@ void clear_and_free(void *p, size_t len) } } -static void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size) +void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size) { unsigned char *p = wally_malloc(new_n * size); if (!p) diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 078bd0dee..ff4dc7227 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -20,6 +20,7 @@ bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len); int replace_bytes(const unsigned char *bytes, size_t bytes_len, unsigned char **bytes_out, size_t *bytes_len_out); void clear_and_free(void *p, size_t len); +void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size); int analyze_tx(const unsigned char *bytes, size_t bytes_len, uint32_t flags, size_t *num_inputs, size_t *num_outputs, bool *expect_witnesses); From f8f931020a991c82039f3b06b715fe7c3533e495 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 09:20:25 +1200 Subject: [PATCH 127/205] psbt: add_new_keypath: Check parameters, clear on failure --- src/psbt.c | 37 ++++++++++++++++--------------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index d4aa7eeba..0948a4c7d 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -117,37 +117,32 @@ static int array_grow(void **src, size_t num_items, size_t *allocation_len, size } int wally_add_new_keypath(struct wally_keypath_map *keypaths, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *fingerprint, - size_t fingerprint_len, - uint32_t *path, - size_t path_len) + unsigned char *pubkey, size_t pubkey_len, + unsigned char *fingerprint, size_t fingerprint_len, + uint32_t *path, size_t path_len) { - size_t latest; int ret; - if (fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || !is_valid_pubkey_len(pubkey_len)) + if (!keypaths || !pubkey || !is_valid_pubkey_len(pubkey_len) || + !fingerprint || fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || + BYTES_INVALID(path, path_len)) return WALLY_EINVAL; ret = array_grow((void *)&keypaths->items, keypaths->num_items, &keypaths->items_allocation_len, sizeof(struct wally_keypath_item)); - if (ret != WALLY_OK) - return ret; - - latest = keypaths->num_items; + if (ret == WALLY_OK) { + struct wally_keypath_item *new_item = keypaths->items + keypaths->num_items; - memcpy(&keypaths->items[latest].pubkey, pubkey, pubkey_len); - memcpy(&keypaths->items[latest].fingerprint, fingerprint, fingerprint_len); - if (path) { - if (!clone_bytes((unsigned char **)&keypaths->items[latest].path, (unsigned char *)path, path_len * sizeof(*path))) { - return WALLY_ENOMEM; + if (path) { + if (!clone_bytes((unsigned char **)&new_item->path, (unsigned char *)path, path_len * sizeof(*path))) + return WALLY_ENOMEM; + new_item->path_len = path_len; } - keypaths->items[latest].path_len = path_len; + memcpy(new_item->pubkey, pubkey, pubkey_len); + memcpy(new_item->fingerprint, fingerprint, fingerprint_len); + keypaths->num_items++; } - keypaths->num_items++; - - return WALLY_OK; + return ret; } int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wally_partial_sigs_map **output) From 8950a6ac44a1f1218456aec4194a0fc940f76e48 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 09:35:19 +1200 Subject: [PATCH 128/205] psbt: add_new_partial_sig: Check parameters, clear on failure, fix compressed pubkeys Previously this code would read off the end of pubkey if a compressed pubkey was passed. --- src/psbt.c | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 0948a4c7d..569aa09d9 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -209,34 +209,27 @@ static int replace_partial_sigs(const struct wally_partial_sigs_map *src, } int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, - unsigned char *pubkey, - size_t pubkey_len, - unsigned char *sig, - size_t sig_len) + unsigned char *pubkey, size_t pubkey_len, + unsigned char *sig, size_t sig_len) { - size_t latest; int ret; - if (!is_valid_pubkey_len(pubkey_len)) + if (!sigs || !pubkey || !is_valid_pubkey_len(pubkey_len) || + BYTES_INVALID(sig, sig_len)) return WALLY_EINVAL; ret = array_grow((void *)&sigs->items, sigs->num_items, &sigs->items_allocation_len, sizeof(struct wally_partial_sigs_item)); - if (ret != WALLY_OK) - return ret; - - latest = sigs->num_items; + if (ret == WALLY_OK) { + struct wally_partial_sigs_item *new_item = sigs->items + sigs->num_items; - memcpy(&sigs->items[latest].pubkey, pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - if (sig) { - if (!clone_bytes(&sigs->items[latest].sig, sig, sig_len)) { + if (sig && !clone_bytes(&new_item->sig, sig, sig_len)) return WALLY_ENOMEM; - } - sigs->items[latest].sig_len = sig_len; + new_item->sig_len = sig_len; + memcpy(&new_item->pubkey, pubkey, pubkey_len); + sigs->num_items++; } - sigs->num_items++; - - return WALLY_OK; + return ret; } int wally_unknowns_map_init_alloc(size_t alloc_len, struct wally_unknowns_map **output) From 4991ee1fde636ba1d95bf85184a4a640f0287fa2 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 10:43:43 +1200 Subject: [PATCH 129/205] psbt: add_new_unknown: Check parameters, don't leak on failure --- src/psbt.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 569aa09d9..905762069 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -297,35 +297,31 @@ static int replace_unknowns(const struct wally_unknowns_map *src, } int wally_add_new_unknown(struct wally_unknowns_map *unknowns, - unsigned char *key, - size_t key_len, - unsigned char *value, - size_t value_len) + unsigned char *key, size_t key_len, + unsigned char *value, size_t value_len) { - size_t latest; + int ret; - int ret = array_grow((void *)&unknowns->items, unknowns->num_items, - &unknowns->items_allocation_len, sizeof(struct wally_unknowns_item)); - if (ret != WALLY_OK) - return ret; + if (!unknowns || !key || BYTES_INVALID(key, key_len) || BYTES_INVALID(value, value_len)) + return WALLY_EINVAL; - latest = unknowns->num_items; + ret = array_grow((void *)&unknowns->items, unknowns->num_items, + &unknowns->items_allocation_len, sizeof(struct wally_unknowns_item)); + if (ret == WALLY_OK) { + struct wally_unknowns_item *new_item = unknowns->items + unknowns->num_items; - if (key) { - if (!clone_bytes(&unknowns->items[latest].key, key, key_len)) { + if (!clone_bytes(&new_item->key, key, key_len)) return WALLY_ENOMEM; - } - unknowns->items[latest].key_len = key_len; - } - if (value) { - if (!clone_bytes(&unknowns->items[latest].value, value, value_len)) { + if (value && !clone_bytes(&new_item->value, value, value_len)) { + clear_and_free(new_item->key, key_len); + new_item->key = NULL; return WALLY_ENOMEM; } - unknowns->items[latest].value_len = value_len; + new_item->key_len = key_len; + new_item->value_len = value_len; + unknowns->num_items++; } - unknowns->num_items++; - - return WALLY_OK; + return ret; } int wally_psbt_input_init_alloc( From 12ba10e651287c1607025602fe06ae9c4f514a33 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 12:33:22 +1200 Subject: [PATCH 130/205] psbt: Rename some psbt functions to follow library standards --- CHANGES.md | 9 +++++++++ include/wally_psbt.h | 14 +++++++------- src/psbt.c | 32 ++++++++++++++++---------------- src/test/test_psbt.py | 10 +++++----- src/test/util.py | 8 ++++---- 5 files changed, 41 insertions(+), 32 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index a674b07f4..49c10edfc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,15 @@ - FINGERPRINT_LEN was renamed to BIP32_KEY_FINGERPRINT_LEN for consistency - You should change any references in your source when upgrading. +- The following PSBT functions have been renamed for consistency: + - wally_add_new_keypath -> wally_keypath_map_add + - wally_add_new_partial_sig -> wally_partial_sigs_map_add + - wally_add_new_unknown -> wally_unknowns_map_add + - wally_extract_psbt -> wally_psbt_extract + - wally_finalize_psbt -> wally_psbt_finalize + - wally_sign_psbt -> wally_psbt_sign + - wally_combine_psbts -> wally_psbt_combine + ## Version 0.7.8 - Python 2 wheels are now deprecated. Users should move to Python 3 as soon as possible. diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 8c39b5925..bbfcf566a 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -216,7 +216,7 @@ WALLY_CORE_API int wally_keypath_map_free( * :param path: The BIP32 derivation path for the pubkey. * :param path_len: The number of items in path. */ -WALLY_CORE_API int wally_add_new_keypath( +WALLY_CORE_API int wally_keypath_map_add( struct wally_keypath_map *keypaths, unsigned char *pubkey, size_t pubkey_len, @@ -254,7 +254,7 @@ WALLY_CORE_API int wally_partial_sigs_map_free( * :param sig: The DER-encoded signature to add. * :param sig_len: Length of ``sig`` in bytes. */ -WALLY_CORE_API int wally_add_new_partial_sig( +WALLY_CORE_API int wally_partial_sigs_map_add( struct wally_partial_sigs_map *sigs, unsigned char *pubkey, size_t pubkey_len, @@ -290,7 +290,7 @@ WALLY_CORE_API int wally_unknowns_map_free( * :param value: The value to add. * :param value_len: Length of ``value`` in bytes. */ -WALLY_CORE_API int wally_add_new_unknown( +WALLY_CORE_API int wally_unknowns_map_add( struct wally_unknowns_map *unknowns, unsigned char *key, size_t key_len, @@ -622,7 +622,7 @@ WALLY_CORE_API int wally_psbt_to_base64( * :param psbts_len: Number of PSBTs in ``psbts``. * :param output: Destination for resulting PSBT. */ -WALLY_CORE_API int wally_combine_psbts( +WALLY_CORE_API int wally_psbt_combine( const struct wally_psbt *psbts, size_t psbts_len, struct wally_psbt **output); @@ -637,7 +637,7 @@ WALLY_CORE_API int wally_combine_psbts( * .. note:: See https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#simple-signer-algorithm *| for a description of the simple signer algorithm. */ -WALLY_CORE_API int wally_sign_psbt( +WALLY_CORE_API int wally_psbt_sign( struct wally_psbt *psbt, const unsigned char *key, size_t key_len); @@ -647,7 +647,7 @@ WALLY_CORE_API int wally_sign_psbt( * * :param psbt: PSBT to finalize. Directly modifies this PSBT. */ -WALLY_CORE_API int wally_finalize_psbt( +WALLY_CORE_API int wally_psbt_finalize( struct wally_psbt *psbt); /** @@ -656,7 +656,7 @@ WALLY_CORE_API int wally_finalize_psbt( * :param psbt: PSBT to extract from. * :param output: Destination for the resulting transaction. */ -WALLY_CORE_API int wally_extract_psbt( +WALLY_CORE_API int wally_psbt_extract( const struct wally_psbt *psbt, struct wally_tx **output); diff --git a/src/psbt.c b/src/psbt.c index 905762069..8450d7f89 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -72,7 +72,7 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) static int add_keypath_item(struct wally_keypath_map *keypaths, struct wally_keypath_item *item) { - return wally_add_new_keypath(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, + return wally_keypath_map_add(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, item->fingerprint, BIP32_KEY_FINGERPRINT_LEN, item->path, item->path_len); } @@ -116,7 +116,7 @@ static int array_grow(void **src, size_t num_items, size_t *allocation_len, size return WALLY_OK; } -int wally_add_new_keypath(struct wally_keypath_map *keypaths, +int wally_keypath_map_add(struct wally_keypath_map *keypaths, unsigned char *pubkey, size_t pubkey_len, unsigned char *fingerprint, size_t fingerprint_len, uint32_t *path, size_t path_len) @@ -181,8 +181,8 @@ int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs) static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, struct wally_partial_sigs_item *item) { - return wally_add_new_partial_sig(sigs, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, - item->sig, item->sig_len); + return wally_partial_sigs_map_add(sigs, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, + item->sig, item->sig_len); } static int replace_partial_sigs(const struct wally_partial_sigs_map *src, @@ -208,9 +208,9 @@ static int replace_partial_sigs(const struct wally_partial_sigs_map *src, return ret; } -int wally_add_new_partial_sig(struct wally_partial_sigs_map *sigs, - unsigned char *pubkey, size_t pubkey_len, - unsigned char *sig, size_t sig_len) +int wally_partial_sigs_map_add(struct wally_partial_sigs_map *sigs, + unsigned char *pubkey, size_t pubkey_len, + unsigned char *sig, size_t sig_len) { int ret; @@ -270,7 +270,7 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) static int add_unknowns_item(struct wally_unknowns_map *unknowns, struct wally_unknowns_item *item) { - return wally_add_new_unknown(unknowns, item->key, item->key_len, item->value, item->value_len); + return wally_unknowns_map_add(unknowns, item->key, item->key_len, item->value, item->value_len); } static int replace_unknowns(const struct wally_unknowns_map *src, @@ -296,9 +296,9 @@ static int replace_unknowns(const struct wally_unknowns_map *src, return ret; } -int wally_add_new_unknown(struct wally_unknowns_map *unknowns, - unsigned char *key, size_t key_len, - unsigned char *value, size_t value_len) +int wally_unknowns_map_add(struct wally_unknowns_map *unknowns, + unsigned char *key, size_t key_len, + unsigned char *value, size_t value_len) { int ret; @@ -3074,7 +3074,7 @@ static int merge_output_into( return WALLY_OK; } -int wally_combine_psbts( +int wally_psbt_combine( const struct wally_psbt *psbts, size_t psbts_len, struct wally_psbt **output) @@ -3150,7 +3150,7 @@ int wally_combine_psbts( return ret; } -int wally_sign_psbt( +int wally_psbt_sign( struct wally_psbt *psbt, const unsigned char *key, size_t key_len) @@ -3329,7 +3329,7 @@ int wally_sign_psbt( return ret; } } - if ((ret = wally_add_new_partial_sig(input->partial_sigs, comp ? pubkey : uncomp_pubkey, comp ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN, der_sig, der_sig_len)) != WALLY_OK) { + if ((ret = wally_partial_sigs_map_add(input->partial_sigs, comp ? pubkey : uncomp_pubkey, comp ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN, der_sig, der_sig_len)) != WALLY_OK) { return ret; } } @@ -3337,7 +3337,7 @@ int wally_sign_psbt( return WALLY_OK; } -int wally_finalize_psbt(struct wally_psbt *psbt) +int wally_psbt_finalize(struct wally_psbt *psbt) { size_t i; int ret; @@ -3569,7 +3569,7 @@ int wally_finalize_psbt(struct wally_psbt *psbt) return WALLY_OK; } -int wally_extract_psbt( +int wally_psbt_extract( const struct wally_psbt *psbt, struct wally_tx **output) { diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index d855f7e84..a0a1a34b1 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -64,7 +64,7 @@ def test_serialization(self): self.assertEqual(WALLY_OK, wally_psbt_from_base64(comb.encode('utf-8'), psbt)) to_combine.append(psbt.contents) combined = pointer(wally_psbt()) - self.assertEqual(WALLY_OK, wally_combine_psbts((wally_psbt * len(to_combine))(*to_combine), len(to_combine), combined)) + self.assertEqual(WALLY_OK, wally_psbt_combine((wally_psbt * len(to_combine))(*to_combine), len(to_combine), combined)) ret, comb_ser = wally_psbt_to_base64(combined) self.assertEqual(combiner['result'], comb_ser) @@ -74,7 +74,7 @@ def test_serialization(self): for priv in signer['privkeys']: buf, buf_len = make_cbuffer('00'*32) self.assertEqual(WALLY_OK, wally_wif_to_bytes(priv.encode('utf-8'), 0xEF, 0, buf, buf_len)) - self.assertEqual(WALLY_OK, wally_sign_psbt(psbt, buf, buf_len)) + self.assertEqual(WALLY_OK, wally_psbt_sign(psbt, buf, buf_len)) ret, reser = wally_psbt_to_base64(psbt) self.assertEqual(WALLY_OK, ret) @@ -89,12 +89,12 @@ def test_serialization(self): for priv in inval_signer['privkeys']: buf, buf_len = make_cbuffer('00'*32) self.assertEqual(WALLY_OK, wally_wif_to_bytes(priv.encode('utf-8'), 0xEF, 0, buf, buf_len)) - self.assertEqual(WALLY_EINVAL, wally_sign_psbt(psbt, buf, buf_len)) + self.assertEqual(WALLY_EINVAL, wally_psbt_sign(psbt, buf, buf_len)) for finalizer in finalizers: psbt = pointer(wally_psbt()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(finalizer['finalize'].encode('utf-8'), psbt)) - self.assertEqual(WALLY_OK, wally_finalize_psbt(psbt)) + self.assertEqual(WALLY_OK, wally_psbt_finalize(psbt)) ret, reser = wally_psbt_to_base64(psbt) self.assertEqual(WALLY_OK, ret) self.assertEqual(finalizer['result'], reser) @@ -103,7 +103,7 @@ def test_serialization(self): psbt = pointer(wally_psbt()) tx = pointer(wally_tx()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(extractor['extract'].encode('utf-8'), psbt)) - self.assertEqual(WALLY_OK, wally_extract_psbt(psbt, tx)) + self.assertEqual(WALLY_OK, wally_psbt_extract(psbt, tx)) ret, reser = wally_tx_to_hex(tx, 1) self.assertEqual(WALLY_OK, ret) self.assertEqual(extractor['result'], reser) diff --git a/src/test/util.py b/src/test/util.py index 9fd34abcf..2ce17c7d5 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -361,10 +361,10 @@ class wally_psbt(Structure): ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_char_p_p]), ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), - ('wally_combine_psbts', c_int, [POINTER(wally_psbt), c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_sign_psbt', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), - ('wally_finalize_psbt', c_int, [POINTER(wally_psbt)]), - ('wally_extract_psbt', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]) + ('wally_psbt_combine', c_int, [POINTER(wally_psbt), c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), + ('wally_psbt_finalize', c_int, [POINTER(wally_psbt)]), + ('wally_psbt_extract', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]) ): def bind_fn(name, res, args): From 1375e0972aede497e49d524709e0cc42bff96c86 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 13:27:57 +1200 Subject: [PATCH 131/205] psbt: final input/output review updates --- src/psbt.c | 281 +++++++++++++++++++---------------------------------- 1 file changed, 102 insertions(+), 179 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 8450d7f89..616de038c 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -324,58 +324,43 @@ int wally_unknowns_map_add(struct wally_unknowns_map *unknowns, return ret; } -int wally_psbt_input_init_alloc( - struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - unsigned char *final_script_sig, - size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, - struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - struct wally_psbt_input **output) +int wally_psbt_input_init_alloc(struct wally_tx *non_witness_utxo, + struct wally_tx_output *witness_utxo, + unsigned char *redeem_script, size_t redeem_script_len, + unsigned char *witness_script, size_t witness_script_len, + unsigned char *final_script_sig, size_t final_script_sig_len, + struct wally_tx_witness_stack *final_witness, + struct wally_keypath_map *keypaths, + struct wally_partial_sigs_map *partial_sigs, + struct wally_unknowns_map *unknowns, + uint32_t sighash_type, + struct wally_psbt_input **output) { struct wally_psbt_input *result; - int ret = WALLY_OK; + int ret; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_psbt_input); - if (non_witness_utxo && (ret = wally_psbt_input_set_non_witness_utxo(result, non_witness_utxo)) != WALLY_OK) { + if (non_witness_utxo && (ret = wally_psbt_input_set_non_witness_utxo(result, non_witness_utxo)) != WALLY_OK) goto fail; - } - if (witness_utxo && (ret = wally_psbt_input_set_witness_utxo(result, witness_utxo)) != WALLY_OK) { + if (witness_utxo && (ret = wally_psbt_input_set_witness_utxo(result, witness_utxo)) != WALLY_OK) goto fail; - } - if (redeem_script && (ret = wally_psbt_input_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) { + if (redeem_script && (ret = wally_psbt_input_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) goto fail; - } - if (witness_script && (ret = wally_psbt_input_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) { + if (witness_script && (ret = wally_psbt_input_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) goto fail; - } - if (final_script_sig && (ret = wally_psbt_input_set_final_script_sig(result, final_script_sig, final_script_sig_len)) != WALLY_OK) { + if (final_script_sig && (ret = wally_psbt_input_set_final_script_sig(result, final_script_sig, final_script_sig_len)) != WALLY_OK) goto fail; - } - if (final_witness && (ret = wally_psbt_input_set_final_witness(result, final_witness)) != WALLY_OK) { + if (final_witness && (ret = wally_psbt_input_set_final_witness(result, final_witness)) != WALLY_OK) goto fail; - } - if (keypaths && (ret = wally_psbt_input_set_keypaths(result, keypaths)) != WALLY_OK) { + if (keypaths && (ret = wally_psbt_input_set_keypaths(result, keypaths)) != WALLY_OK) goto fail; - } - if (partial_sigs && (ret = wally_psbt_input_set_partial_sigs(result, partial_sigs)) != WALLY_OK) { + if (partial_sigs && (ret = wally_psbt_input_set_partial_sigs(result, partial_sigs)) != WALLY_OK) goto fail; - } - if (unknowns && (ret = wally_psbt_input_set_unknowns(result, unknowns)) != WALLY_OK) { + if (unknowns && (ret = wally_psbt_input_set_unknowns(result, unknowns)) != WALLY_OK) goto fail; - } - ret = wally_psbt_input_set_sighash_type(result, sighash_type); - - return ret; + return wally_psbt_input_set_sighash_type(result, sighash_type); fail: wally_psbt_input_free(result); @@ -384,85 +369,58 @@ int wally_psbt_input_init_alloc( } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_input_init_alloc( - struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - unsigned char *final_script_sig, - size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, - struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - uint64_t value, - uint32_t has_value, - unsigned char *value_blinder, - size_t value_blinder_len, - unsigned char *asset, - size_t asset_len, - unsigned char *asset_blinder, - size_t asset_blinder_len, - struct wally_tx *peg_in_tx, - unsigned char *txout_proof, - size_t txout_proof_len, - unsigned char *genesis_hash, - size_t genesis_hash_len, - unsigned char *claim_script, - size_t claim_script_len, - struct wally_psbt_input **output) +int wally_psbt_elements_input_init_alloc(struct wally_tx *non_witness_utxo, + struct wally_tx_output *witness_utxo, + unsigned char *redeem_script, size_t redeem_script_len, + unsigned char *witness_script, size_t witness_script_len, + unsigned char *final_script_sig, size_t final_script_sig_len, + struct wally_tx_witness_stack *final_witness, + struct wally_keypath_map *keypaths, + struct wally_partial_sigs_map *partial_sigs, + struct wally_unknowns_map *unknowns, + uint32_t sighash_type, + uint64_t value, uint32_t has_value, + unsigned char *value_blinder, size_t value_blinder_len, + unsigned char *asset, size_t asset_len, + unsigned char *asset_blinder, size_t asset_blinder_len, + struct wally_tx *peg_in_tx, + unsigned char *txout_proof, size_t txout_proof_len, + unsigned char *genesis_hash, size_t genesis_hash_len, + unsigned char *claim_script, size_t claim_script_len, + struct wally_psbt_input **output) { struct wally_psbt_input *result; - int ret = wally_psbt_input_init_alloc(non_witness_utxo, - witness_utxo, - redeem_script, - redeem_script_len, - witness_script, - witness_script_len, - final_script_sig, - final_script_sig_len, - final_witness, - keypaths, - partial_sigs, - unknowns, + int ret = wally_psbt_input_init_alloc(non_witness_utxo, witness_utxo, + redeem_script, redeem_script_len, + witness_script, witness_script_len, + final_script_sig, final_script_sig_len, + final_witness, keypaths, + partial_sigs, unknowns, sighash_type, output); - if (ret != WALLY_OK) { + if (ret != WALLY_OK) return ret; - } - /* wally_psbt_input_init_alloc will allocate and initialize the input */ result = *output; - if (has_value && (ret = wally_psbt_elements_input_set_value(result, value)) != WALLY_OK) { + if (has_value && (ret = wally_psbt_elements_input_set_value(result, value)) != WALLY_OK) goto fail; - } - if (value_blinder && (ret = wally_psbt_elements_input_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) { + if (value_blinder && (ret = wally_psbt_elements_input_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) goto fail; - } - if (asset && (ret = wally_psbt_elements_input_set_asset(result, asset, asset_len)) != WALLY_OK) { + if (asset && (ret = wally_psbt_elements_input_set_asset(result, asset, asset_len)) != WALLY_OK) goto fail; - } - if (asset_blinder && (ret = wally_psbt_elements_input_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) { + if (asset_blinder && (ret = wally_psbt_elements_input_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) goto fail; - } - if (peg_in_tx && (ret = wally_psbt_elements_input_set_peg_in_tx(result, peg_in_tx)) != WALLY_OK) { + if (peg_in_tx && (ret = wally_psbt_elements_input_set_peg_in_tx(result, peg_in_tx)) != WALLY_OK) goto fail; - } - if (txout_proof && (ret = wally_psbt_elements_input_set_txout_proof(result, txout_proof, txout_proof_len)) != WALLY_OK) { + if (txout_proof && (ret = wally_psbt_elements_input_set_txout_proof(result, txout_proof, txout_proof_len)) != WALLY_OK) goto fail; - } - if (genesis_hash && (ret = wally_psbt_elements_input_set_genesis_hash(result, genesis_hash, genesis_hash_len)) != WALLY_OK) { + if (genesis_hash && (ret = wally_psbt_elements_input_set_genesis_hash(result, genesis_hash, genesis_hash_len)) != WALLY_OK) goto fail; - } - if (claim_script && (ret = wally_psbt_elements_input_set_claim_script(result, claim_script, claim_script_len)) != WALLY_OK) { + if (claim_script && (ret = wally_psbt_elements_input_set_claim_script(result, claim_script, claim_script_len)) != WALLY_OK) goto fail; - } - return ret; + return WALLY_OK; fail: wally_psbt_input_free(result); @@ -487,14 +445,13 @@ int wally_psbt_input_set_non_witness_utxo(struct wally_psbt_input *input, return ret; } -int wally_psbt_input_set_witness_utxo( - struct wally_psbt_input *input, - struct wally_tx_output *witness_utxo) +int wally_psbt_input_set_witness_utxo(struct wally_psbt_input *input, + struct wally_tx_output *witness_utxo) { int ret; struct wally_tx_output *output; - if (!input || !witness_utxo) + if (!input) return WALLY_EINVAL; ret = wally_tx_output_clone_alloc(witness_utxo, &output); @@ -569,18 +526,16 @@ int wally_psbt_input_set_unknowns(struct wally_psbt_input *input, return input ? replace_unknowns(unknowns, &input->unknowns) : WALLY_EINVAL; } -int wally_psbt_input_set_sighash_type( - struct wally_psbt_input *input, - uint32_t sighash_type) +int wally_psbt_input_set_sighash_type(struct wally_psbt_input *input, uint32_t sighash_type) { + if (!input) + return WALLY_EINVAL; input->sighash_type = sighash_type; return WALLY_OK; } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_input_set_value( - struct wally_psbt_input *input, - uint64_t value) +int wally_psbt_elements_input_set_value(struct wally_psbt_input *input, uint64_t value) { input->value = value; input->has_value = 1u; @@ -631,10 +586,9 @@ int wally_psbt_elements_input_set_peg_in_tx(struct wally_psbt_input *input, return ret; } -int wally_psbt_elements_input_set_txout_proof( - struct wally_psbt_input *input, - unsigned char *txout_proof, - size_t txout_proof_len) +int wally_psbt_elements_input_set_txout_proof(struct wally_psbt_input *input, + unsigned char *txout_proof, + size_t txout_proof_len) { if (!input) return WALLY_EINVAL; @@ -698,14 +652,11 @@ int wally_psbt_input_free(struct wally_psbt_input *input) return psbt_input_free(input, true); } -int wally_psbt_output_init_alloc( - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, - struct wally_psbt_output **output) +int wally_psbt_output_init_alloc(unsigned char *redeem_script, size_t redeem_script_len, + unsigned char *witness_script, size_t witness_script_len, + struct wally_keypath_map *keypaths, + struct wally_unknowns_map *unknowns, + struct wally_psbt_output **output) { struct wally_psbt_output *result; int ret = WALLY_OK; @@ -713,20 +664,16 @@ int wally_psbt_output_init_alloc( TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_psbt_output); - if (redeem_script && (ret = wally_psbt_output_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) { + if (redeem_script && (ret = wally_psbt_output_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) goto fail; - } - if (witness_script && (ret = wally_psbt_output_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) { + if (witness_script && (ret = wally_psbt_output_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) goto fail; - } - if (keypaths && (ret = wally_psbt_output_set_keypaths(result, keypaths)) != WALLY_OK) { + if (keypaths && (ret = wally_psbt_output_set_keypaths(result, keypaths)) != WALLY_OK) goto fail; - } - if (unknowns && (ret = wally_psbt_output_set_unknowns(result, unknowns)) != WALLY_OK) { + if (unknowns && (ret = wally_psbt_output_set_unknowns(result, unknowns)) != WALLY_OK) goto fail; - } - return ret; + return WALLY_OK; fail: wally_psbt_output_free(result); @@ -735,70 +682,46 @@ int wally_psbt_output_init_alloc( } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_output_init_alloc( - unsigned char *redeem_script, - size_t redeem_script_len, - unsigned char *witness_script, - size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, - unsigned char *blinding_pubkey, - size_t blinding_pubkey_len, - unsigned char *value_commitment, - size_t value_commitment_len, - unsigned char *value_blinder, - size_t value_blinder_len, - unsigned char *asset_commitment, - size_t asset_commitment_len, - unsigned char *asset_blinder, - size_t asset_blinder_len, - unsigned char *nonce_commitment, - size_t nonce_commitment_len, - unsigned char *range_proof, - size_t range_proof_len, - unsigned char *surjection_proof, - size_t surjection_proof_len, - struct wally_psbt_output **output) +int wally_psbt_elements_output_init_alloc(unsigned char *redeem_script, size_t redeem_script_len, + unsigned char *witness_script, size_t witness_script_len, + struct wally_keypath_map *keypaths, + struct wally_unknowns_map *unknowns, + unsigned char *blinding_pubkey, size_t blinding_pubkey_len, + unsigned char *value_commitment, size_t value_commitment_len, + unsigned char *value_blinder, size_t value_blinder_len, + unsigned char *asset_commitment, size_t asset_commitment_len, + unsigned char *asset_blinder, size_t asset_blinder_len, + unsigned char *nonce_commitment, size_t nonce_commitment_len, + unsigned char *range_proof, size_t range_proof_len, + unsigned char *surjection_proof, size_t surjection_proof_len, + struct wally_psbt_output **output) { struct wally_psbt_output *result; - int ret = wally_psbt_output_init_alloc(redeem_script, - redeem_script_len, - witness_script, - witness_script_len, - keypaths, - unknowns, - output); - if (ret != WALLY_OK) { + int ret = wally_psbt_output_init_alloc(redeem_script, redeem_script_len, + witness_script, witness_script_len, + keypaths, unknowns, output); + if (ret != WALLY_OK) return ret; - } /* wally_psbt_output_init_alloc allocates for us */ result = *output; - if ((ret = wally_psbt_elements_output_set_blinding_pubkey(result, blinding_pubkey, blinding_pubkey_len)) != WALLY_OK) { + if ((ret = wally_psbt_elements_output_set_blinding_pubkey(result, blinding_pubkey, blinding_pubkey_len)) != WALLY_OK) goto fail; - } - if (value_commitment && (ret = wally_psbt_elements_output_set_value_commitment(result, value_commitment, value_commitment_len)) != WALLY_OK) { + if (value_commitment && (ret = wally_psbt_elements_output_set_value_commitment(result, value_commitment, value_commitment_len)) != WALLY_OK) goto fail; - } - if (value_blinder && (ret = wally_psbt_elements_output_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) { + if (value_blinder && (ret = wally_psbt_elements_output_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) goto fail; - } - if (asset_commitment && (ret = wally_psbt_elements_output_set_asset_commitment(result, asset_commitment, asset_commitment_len)) != WALLY_OK) { + if (asset_commitment && (ret = wally_psbt_elements_output_set_asset_commitment(result, asset_commitment, asset_commitment_len)) != WALLY_OK) goto fail; - } - if (asset_blinder && (ret = wally_psbt_elements_output_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) { + if (asset_blinder && (ret = wally_psbt_elements_output_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) goto fail; - } - if (nonce_commitment && (ret = wally_psbt_elements_output_set_nonce_commitment(result, nonce_commitment, nonce_commitment_len)) != WALLY_OK) { + if (nonce_commitment && (ret = wally_psbt_elements_output_set_nonce_commitment(result, nonce_commitment, nonce_commitment_len)) != WALLY_OK) goto fail; - } - if (range_proof && (ret = wally_psbt_elements_output_set_range_proof(result, range_proof, range_proof_len)) != WALLY_OK) { + if (range_proof && (ret = wally_psbt_elements_output_set_range_proof(result, range_proof, range_proof_len)) != WALLY_OK) goto fail; - } - if (surjection_proof && (ret = wally_psbt_elements_output_set_surjection_proof(result, surjection_proof, surjection_proof_len)) != WALLY_OK) { + if (surjection_proof && (ret = wally_psbt_elements_output_set_surjection_proof(result, surjection_proof, surjection_proof_len)) != WALLY_OK) goto fail; - } return ret; From d59b4a95bb4726a3a70b2f32ec4a0e5c8998163d Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 15:01:55 +1200 Subject: [PATCH 132/205] psbt: Only copy magic if psbt allocation succeeds --- src/psbt.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 616de038c..2e31bac3c 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -922,10 +922,11 @@ int wally_psbt_elements_init_alloc( size_t global_unknowns_allocation_len, struct wally_psbt **output) { - int ret; - - ret = wally_psbt_init_alloc(inputs_allocation_len, outputs_allocation_len, global_unknowns_allocation_len, output); - memcpy((*output)->magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(WALLY_ELEMENTS_PSBT_MAGIC)); + int ret = wally_psbt_init_alloc(inputs_allocation_len, + outputs_allocation_len, + global_unknowns_allocation_len, output); + if (ret == WALLY_OK) + memcpy((*output)->magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(WALLY_ELEMENTS_PSBT_MAGIC)); return ret; } From dfd5097fdde6c1a11bb2c16bbc3a1d7c8633f8e7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 17:27:31 +1200 Subject: [PATCH 133/205] internal: Implement an internal calloc to simplify code --- src/internal.c | 7 +++++++ src/internal.h | 2 ++ src/psbt.c | 15 +++++---------- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/internal.c b/src/internal.c index 76e75eb05..5578441a1 100644 --- a/src/internal.c +++ b/src/internal.c @@ -231,6 +231,13 @@ void *wally_malloc(size_t size) return _ops.malloc_fn(size); } +void *wally_calloc(size_t size) +{ + void *p = _ops.malloc_fn(size); + (void) wally_bzero(p, size); + return p; +} + void wally_free(void *ptr) { _ops.free_fn(ptr); diff --git a/src/internal.h b/src/internal.h index d501f8a60..d98db082e 100644 --- a/src/internal.h +++ b/src/internal.h @@ -40,10 +40,12 @@ void wally_clear_6(void *p, size_t len, void *p2, size_t len2, const struct wally_operations *wally_ops(void); void *wally_malloc(size_t size); +void *wally_calloc(size_t size); void wally_free(void *ptr); char *wally_strdup(const char *str); #define malloc(size) __use_wally_malloc_internally__ +#define calloc(size) __use_wally_calloc_internally__ #define free(ptr) __use_wally_free_internally__ #ifdef strdup #undef strdup diff --git a/src/psbt.c b/src/psbt.c index 2e31bac3c..d56da1dd1 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -888,16 +888,11 @@ int wally_psbt_init_alloc( TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_psbt); - if (inputs_allocation_len) { - result->inputs = wally_malloc(inputs_allocation_len * sizeof(struct wally_psbt_input)); - if (result->inputs) - wally_bzero(result->inputs, inputs_allocation_len * sizeof(*result->inputs)); - } - if (outputs_allocation_len) { - result->outputs = wally_malloc(outputs_allocation_len * sizeof(struct wally_psbt_output)); - if (result->outputs) - wally_bzero(result->outputs, outputs_allocation_len * sizeof(*result->outputs)); - } + if (inputs_allocation_len) + result->inputs = wally_calloc(inputs_allocation_len * sizeof(struct wally_psbt_input)); + if (outputs_allocation_len) + result->outputs = wally_calloc(outputs_allocation_len * sizeof(struct wally_psbt_output)); + ret = wally_unknowns_map_init_alloc(global_unknowns_allocation_len, &result->unknowns); if (ret != WALLY_OK || From 1d615a6b8f005238c1310e690971e06ac33fb55f Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 10 Jul 2020 18:42:28 +1200 Subject: [PATCH 134/205] psbt: set_global_tx: Don't leak inputs if output allocation fails --- include/wally_psbt.h | 1 - src/psbt.c | 83 ++++++++++++++++++-------------------------- 2 files changed, 34 insertions(+), 50 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index bbfcf566a..22438ecb0 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -547,7 +547,6 @@ WALLY_CORE_API int wally_psbt_free( /** * Set the global transaction for a PSBT. - * Also initializes all of the wally_psbt_input and wally_psbt_outputs necessary. * * :param psbt: The PSBT to set the transaction for. * :param tx: The transaction to set. diff --git a/src/psbt.c b/src/psbt.c index d56da1dd1..a2daf8b0a 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -946,67 +946,52 @@ int wally_psbt_free(struct wally_psbt *psbt) return WALLY_OK; } -int wally_psbt_set_global_tx( - struct wally_psbt *psbt, - struct wally_tx *tx) +int wally_psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx) { + struct wally_tx *new_tx; + struct wally_psbt_input *new_inputs = NULL; + struct wally_psbt_output *new_outputs = NULL; size_t i; - int ret = WALLY_OK; + int ret; - /* Needs a psbt that is completely empty, i.e. no tx, no inputs, and no outputs. */ - if (!tx || !psbt || psbt->tx || psbt->num_inputs != 0 || psbt->num_outputs != 0) { - return WALLY_EINVAL; - } + if (!psbt || psbt->tx || psbt->num_inputs || psbt->num_outputs || !tx) + return WALLY_EINVAL; /* PSBT must be completely empty */ - /* tx cannot have any scriptSigs or witnesses */ - for (i = 0; i < tx->num_inputs; ++i) { - if (tx->inputs[i].script || tx->inputs[i].witness) { - return WALLY_EINVAL; - } - } + for (i = 0; i < tx->num_inputs; ++i) + if (tx->inputs[i].script || tx->inputs[i].witness) + return WALLY_EINVAL; /* tx mustn't have scriptSigs or witnesses */ - if ((ret = wally_tx_clone(tx, 0, &psbt->tx)) != WALLY_OK) { - goto fail; + if ((ret = wally_tx_clone(tx, 0, &new_tx)) != WALLY_OK) + return ret; + + if (psbt->inputs_allocation_len < tx->num_inputs) + new_inputs = wally_calloc(tx->num_inputs * sizeof(struct wally_psbt_input)); + + if (psbt->outputs_allocation_len < tx->num_outputs) + new_outputs = wally_calloc(tx->num_outputs * sizeof(struct wally_psbt_output)); + + if ((psbt->inputs_allocation_len < tx->num_inputs && !new_inputs) || + (psbt->outputs_allocation_len < tx->num_outputs && !new_outputs)) { + wally_free(new_inputs); + wally_free(new_outputs); + wally_tx_free(new_tx); + return WALLY_ENOMEM; } - if (psbt->inputs_allocation_len < tx->num_inputs) { - if (psbt->inputs) { - wally_free(psbt->inputs); - } - psbt->inputs_allocation_len = 0; - psbt->inputs = wally_malloc(tx->num_inputs * sizeof(struct wally_psbt_input)); - if (!psbt->inputs) { - ret = WALLY_ENOMEM; - goto fail; - } + if (new_inputs) { + wally_free(psbt->inputs); + psbt->inputs = new_inputs; psbt->inputs_allocation_len = tx->num_inputs; } - wally_bzero(psbt->inputs, psbt->inputs_allocation_len * sizeof(*psbt->inputs)); - psbt->num_inputs = tx->num_inputs; - - if (psbt->outputs_allocation_len < tx->num_outputs) { - if (psbt->outputs) { - wally_free(psbt->outputs); - } - psbt->outputs_allocation_len = 0; - psbt->outputs = wally_malloc(tx->num_outputs * sizeof(struct wally_psbt_output)); - if (!psbt->outputs) { - ret = WALLY_ENOMEM; - goto fail; - } + if (new_outputs) { + wally_free(psbt->outputs); + psbt->outputs = new_outputs; psbt->outputs_allocation_len = tx->num_outputs; } - wally_bzero(psbt->outputs, psbt->outputs_allocation_len * sizeof(*psbt->outputs)); + psbt->tx = new_tx; + psbt->num_inputs = tx->num_inputs; psbt->num_outputs = tx->num_outputs; - - return ret; - -fail: - if (psbt->tx) { - wally_tx_free(psbt->tx); - psbt->tx = NULL; - } - return ret; + return WALLY_OK; } /* Returns false if it hits a zero length "key" (i.e. separator) or EOF. From 7d8ac1bb0a47c58096b58fa6ca19804fdc037a18 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sat, 11 Jul 2020 00:09:28 +1200 Subject: [PATCH 135/205] psbt: Remove redundant pre-iteration of data when deserializing Instead, have the various elements allocated and added on demand using the existing functions. This is substantially simpler and allows us to remove redundant checks during parsing that the add/set functions already perform. As part of this change, some parameter constification was required. Also, wally_psbt_set_global_tx is updated to not create empty/invalid inputs and outputs. --- include/wally_psbt.h | 14 +- src/psbt.c | 518 +++++++++--------------------------------- src/test/test_psbt.py | 5 + 3 files changed, 124 insertions(+), 413 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 22438ecb0..75978e0f9 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -218,11 +218,11 @@ WALLY_CORE_API int wally_keypath_map_free( */ WALLY_CORE_API int wally_keypath_map_add( struct wally_keypath_map *keypaths, - unsigned char *pubkey, + const unsigned char *pubkey, size_t pubkey_len, - unsigned char *fingerprint, + const unsigned char *fingerprint, size_t fingerprint_len, - uint32_t *path, + const uint32_t *path, size_t path_len); /** @@ -256,9 +256,9 @@ WALLY_CORE_API int wally_partial_sigs_map_free( */ WALLY_CORE_API int wally_partial_sigs_map_add( struct wally_partial_sigs_map *sigs, - unsigned char *pubkey, + const unsigned char *pubkey, size_t pubkey_len, - unsigned char *sig, + const unsigned char *sig, size_t sig_len); /** @@ -292,9 +292,9 @@ WALLY_CORE_API int wally_unknowns_map_free( */ WALLY_CORE_API int wally_unknowns_map_add( struct wally_unknowns_map *unknowns, - unsigned char *key, + const unsigned char *key, size_t key_len, - unsigned char *value, + const unsigned char *value, size_t value_len); /** diff --git a/src/psbt.c b/src/psbt.c index a2daf8b0a..31ae034a3 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -70,7 +70,7 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) return WALLY_OK; } -static int add_keypath_item(struct wally_keypath_map *keypaths, struct wally_keypath_item *item) +static int add_keypath_item(struct wally_keypath_map *keypaths, const struct wally_keypath_item *item) { return wally_keypath_map_add(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, item->fingerprint, BIP32_KEY_FINGERPRINT_LEN, @@ -117,9 +117,9 @@ static int array_grow(void **src, size_t num_items, size_t *allocation_len, size } int wally_keypath_map_add(struct wally_keypath_map *keypaths, - unsigned char *pubkey, size_t pubkey_len, - unsigned char *fingerprint, size_t fingerprint_len, - uint32_t *path, size_t path_len) + const unsigned char *pubkey, size_t pubkey_len, + const unsigned char *fingerprint, size_t fingerprint_len, + const uint32_t *path, size_t path_len) { int ret; @@ -179,7 +179,7 @@ int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs) return WALLY_OK; } -static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, struct wally_partial_sigs_item *item) +static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, const struct wally_partial_sigs_item *item) { return wally_partial_sigs_map_add(sigs, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, item->sig, item->sig_len); @@ -209,8 +209,8 @@ static int replace_partial_sigs(const struct wally_partial_sigs_map *src, } int wally_partial_sigs_map_add(struct wally_partial_sigs_map *sigs, - unsigned char *pubkey, size_t pubkey_len, - unsigned char *sig, size_t sig_len) + const unsigned char *pubkey, size_t pubkey_len, + const unsigned char *sig, size_t sig_len) { int ret; @@ -268,7 +268,7 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) return WALLY_OK; } -static int add_unknowns_item(struct wally_unknowns_map *unknowns, struct wally_unknowns_item *item) +static int add_unknowns_item(struct wally_unknowns_map *unknowns, const struct wally_unknowns_item *item) { return wally_unknowns_map_add(unknowns, item->key, item->key_len, item->value, item->value_len); } @@ -297,8 +297,8 @@ static int replace_unknowns(const struct wally_unknowns_map *src, } int wally_unknowns_map_add(struct wally_unknowns_map *unknowns, - unsigned char *key, size_t key_len, - unsigned char *value, size_t value_len) + const unsigned char *key, size_t key_len, + const unsigned char *value, size_t value_len) { int ret; @@ -989,8 +989,6 @@ int wally_psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx) psbt->outputs_allocation_len = tx->num_outputs; } psbt->tx = new_tx; - psbt->num_inputs = tx->num_inputs; - psbt->num_outputs = tx->num_outputs; return WALLY_OK; } @@ -1041,77 +1039,107 @@ static void subfield_nomore_end(const unsigned char **cursor, size_t *max, /* The remainder of the key is a public key, the value is a keypath */ static int pull_keypath(const unsigned char **cursor, size_t *max, const unsigned char *key, size_t key_len, - struct wally_keypath_map *keypaths) + struct wally_keypath_map **keypaths) { const unsigned char *val; size_t i, val_max; - struct wally_keypath_item *kpitem; + const unsigned char *fingerprint; + int ret; if (!is_valid_pubkey_len(key_len)) return WALLY_EINVAL; + if (!*keypaths && wally_keypath_map_init_alloc(1, keypaths) != WALLY_OK) + return WALLY_ENOMEM; + /* Check for duplicates */ - for (i = 0; i < keypaths->num_items; ++i) { - if (memcmp(keypaths->items[i].pubkey, key, key_len) == 0) { + for (i = 0; i < (*keypaths)->num_items; ++i) { + if (memcmp((*keypaths)->items[i].pubkey, key, key_len) == 0) { return WALLY_EINVAL; /* Duplicate key */ } } - if (keypaths->num_items >= keypaths->items_allocation_len) - return WALLY_ERROR; /* Should not happen! */ - kpitem = &keypaths->items[keypaths->num_items++]; - - memcpy(kpitem->pubkey, key, key_len); pull_subfield_end(cursor, max, key, key_len); /* Start parsing the value field. */ pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); /* Read the fingerprint */ - pull_bytes(kpitem->fingerprint, sizeof(kpitem->fingerprint), - &val, &val_max); + fingerprint = pull_skip(&val, &val_max, sizeof(BIP32_KEY_FINGERPRINT_LEN)); - /* Remainder is the path */ - kpitem->path_len = val_max / sizeof(uint32_t); - kpitem->path = wally_malloc(val_max); - if (kpitem->path == NULL) { - return WALLY_ENOMEM; + ret = wally_keypath_map_add(*keypaths, key, key_len, + fingerprint, BIP32_KEY_FINGERPRINT_LEN, NULL, 0); + if (ret == WALLY_OK) { + /* Remainder is the path */ + struct wally_keypath_item *kpitem; + kpitem = (*keypaths)->items + (*keypaths)->num_items - 1; + if ((kpitem->path = wally_malloc(val_max)) == NULL) + return WALLY_ENOMEM; + + kpitem->path_len = val_max / sizeof(uint32_t); + for (i = 0; val_max >= sizeof(uint32_t); ++i) { + kpitem->path[i] = pull_le32(&val, &val_max); + } + subfield_nomore_end(cursor, max, val, val_max); } - for (i = 0; val_max >= sizeof(uint32_t); ++i) { - kpitem->path[i] = pull_le32(&val, &val_max); + return ret; +} + +/* The remainder of the key is a public key, the value is a signature */ +static int pull_partial_sig(const unsigned char **cursor, size_t *max, + const unsigned char *key, size_t key_len, + struct wally_partial_sigs_map **partial_sigs) +{ + const unsigned char *val; + size_t val_len, i; + + if (!is_valid_pubkey_len(key_len)) + return WALLY_EINVAL; + + if (!*partial_sigs && wally_partial_sigs_map_init_alloc(1, partial_sigs) != WALLY_OK) + return WALLY_ENOMEM; + + /* Check for duplicates */ + for (i = 0; i < (*partial_sigs)->num_items; ++i) { + if (memcmp((*partial_sigs)->items[i].pubkey, key, key_len) == 0) { + return WALLY_EINVAL; /* Duplicate key */ + } } - subfield_nomore_end(cursor, max, val, val_max); - return WALLY_OK; + + pull_subfield_end(cursor, max, key, key_len); + + val_len = pull_varlength(cursor, max); + val = pull_skip(cursor, max, val_len); + + return wally_partial_sigs_map_add(*partial_sigs, key, key_len, val, val_len); } /* Rewind cursor to prekey, and append unknown key/value to unknowns */ static int pull_unknown_key_value(const unsigned char **cursor, size_t *max, const unsigned char *pre_key, - struct wally_unknowns_map *unknowns) + struct wally_unknowns_map **unknowns) { - struct wally_unknowns_item *item; + const unsigned char *key, *val; + size_t key_len, val_len; /* If we've already failed, it's invalid */ - if (!*cursor) { + if (!*cursor) return WALLY_EINVAL; - } + + if (!*unknowns && wally_unknowns_map_init_alloc(1, unknowns) != WALLY_OK) + return WALLY_ENOMEM; /* We have to unwind a bit, to get entire key again. */ *max += (*cursor - pre_key); *cursor = pre_key; - if (unknowns->num_items >= unknowns->items_allocation_len) - return WALLY_ERROR; /* Should not happen! */ - item = &unknowns->items[unknowns->num_items++]; + key_len = pull_varlength(cursor, max); + key = pull_skip(cursor, max, key_len); + val_len = pull_varlength(cursor, max); + val = pull_skip(cursor, max, val_len); - if (!clone_varlength(&item->key, &item->key_len, cursor, max)) { - return WALLY_ENOMEM; - } - if (!clone_varlength(&item->value, &item->value_len, cursor, max)) { - return WALLY_ENOMEM; - } - return WALLY_OK; + return wally_unknowns_map_add(*unknowns, key, key_len, val, val_len); } #ifdef BUILD_ELEMENTS @@ -1204,248 +1232,9 @@ static int pull_nonce(const unsigned char **cursor, #endif /* BUILD_ELEMENTS */ -struct psbt_input_counts { - size_t num_unknowns; - size_t num_keypaths; - size_t num_partial_sigs; -}; - -struct psbt_output_counts { - size_t num_unknowns; - size_t num_keypaths; -}; - -struct psbt_counts { - size_t num_global_unknowns; - struct psbt_input_counts *input_counts; - size_t num_inputs; - struct psbt_output_counts *output_counts; - size_t num_outputs; -}; - -static void free_psbt_count(struct psbt_counts *counts) -{ - if (counts) { - clear_and_free(counts->input_counts, counts->num_inputs * sizeof(*counts->input_counts)); - clear_and_free(counts->output_counts, counts->num_outputs * sizeof(*counts->output_counts)); - clear_and_free(counts, sizeof(*counts)); - } -} - -static int count_psbt_parts( - const unsigned char *bytes, - size_t bytes_len, - uint32_t flags, - struct psbt_counts **output) -{ - int ret; - size_t i, key_len; - struct psbt_counts *result; - - TX_CHECK_OUTPUT; - TX_OUTPUT_ALLOC(struct psbt_counts); - - result->num_global_unknowns = 0; - result->num_inputs = 0; - result->num_outputs = 0; - - /* Go through globals and count */ - while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { - const unsigned char *key; - - /* Start parsing key */ - pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); - - /* Process based on type */ - switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_GLOBAL_UNSIGNED_TX: { - bool expect_wit; - const unsigned char *val; - size_t val_max; - subfield_nomore_end(&bytes, &bytes_len, key, key_len); - - /* Value should be a tx */ - val_max = pull_varint(&bytes, &bytes_len); - val = pull_skip(&bytes, &bytes_len, val_max); - if (!val) { - ret = WALLY_EINVAL; - goto fail; - } - ret = analyze_tx(val, val_max, flags, &result->num_inputs, &result->num_outputs, &expect_wit); - if (ret != WALLY_OK) { - goto fail; - } - if ((result->input_counts = wally_malloc(result->num_inputs * sizeof(struct psbt_input_counts))) == NULL || - (result->output_counts = wally_malloc(result->num_outputs * sizeof(struct psbt_output_counts))) == NULL) { - ret = WALLY_ENOMEM; - goto fail; - } - break; - } - case WALLY_PSBT_GLOBAL_VERSION: - pull_subfield_end(&bytes, &bytes_len, key, key_len); - /* Skip over value */ - pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); - break; - /* Unknowns */ - default: - result->num_global_unknowns++; - pull_subfield_end(&bytes, &bytes_len, key, key_len); - /* Skip over value */ - pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); - } - } - - /* Go through each input */ - for (i = 0; i < result->num_inputs; ++i) { - struct psbt_input_counts *input = &result->input_counts[i]; - input->num_keypaths = 0; - input->num_partial_sigs = 0; - input->num_unknowns = 0; - - while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { - const unsigned char *key; - - /* Start parsing key */ - pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); - - /* Process based on type */ - switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_IN_NON_WITNESS_UTXO: - case WALLY_PSBT_IN_WITNESS_UTXO: - case WALLY_PSBT_IN_SIGHASH_TYPE: - case WALLY_PSBT_IN_REDEEM_SCRIPT: - case WALLY_PSBT_IN_WITNESS_SCRIPT: - case WALLY_PSBT_IN_FINAL_SCRIPTSIG: - case WALLY_PSBT_IN_FINAL_SCRIPTWITNESS: - break; - case WALLY_PSBT_IN_PARTIAL_SIG: - input->num_partial_sigs++; - break; - case WALLY_PSBT_IN_BIP32_DERIVATION: - input->num_keypaths++; - break; - case WALLY_PSBT_PROPRIETARY_TYPE: { -#ifdef BUILD_ELEMENTS - uint64_t id_len; - bool valid_type = false; - - id_len = pull_varlength(&key, &key_len); - if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { - pull_skip(&key, &key_len, id_len); - - switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_IN_ELEMENTS_VALUE: - case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: - case WALLY_PSBT_IN_ELEMENTS_ASSET: - case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: - case WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX: - case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: - case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: - case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: - valid_type = true; - break; - default: - valid_type = false; - } - } - if (valid_type) { - break; - } -#endif /* BUILD_ELEMENTS */ - } - /* For unknown case without elements or for unknown proprietary types */ - /* fall through */ - /* Unknowns */ - default: - input->num_unknowns++; - } - pull_subfield_end(&bytes, &bytes_len, key, key_len); - /* Skip over value */ - pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); - } - } - - /* Go through each output */ - for (i = 0; i < result->num_outputs; ++i) { - struct psbt_output_counts *psbt_output = &result->output_counts[i]; - psbt_output->num_keypaths = 0; - psbt_output->num_unknowns = 0; - - while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { - const unsigned char *key; - - /* Start parsing key */ - pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); - - /* Process based on type */ - switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_OUT_REDEEM_SCRIPT: - case WALLY_PSBT_OUT_WITNESS_SCRIPT: - break; - case WALLY_PSBT_OUT_BIP32_DERIVATION: - psbt_output->num_keypaths++; - break; - case WALLY_PSBT_PROPRIETARY_TYPE: { -#ifdef BUILD_ELEMENTS - uint64_t id_len; - bool valid_type = false; - - id_len = pull_varlength(&key, &key_len); - if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { - pull_skip(&key, &key_len, id_len); - - switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: - case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: - case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: - case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: - case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: - case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: - case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: - case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: - valid_type = true; - break; - default: - valid_type = false; - } - } - if (valid_type) { - break; - } -#endif /* BUILD_ELEMENTS */ - } - /* For unknown case without elements or for unknown proprietary types */ - /* fall through */ - /* Unknowns */ - default: - psbt_output->num_unknowns++; - } - - pull_subfield_end(&bytes, &bytes_len, key, key_len); - /* Skip over value */ - pull_skip(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len)); - } - } - - /* Either we ran short, or had too much? */ - if (bytes == NULL || bytes_len != 0) { - ret = WALLY_EINVAL; - goto fail; - } - - return WALLY_OK; - -fail: - free_psbt_count(result); - *output = NULL; - return ret; -} - static int pull_psbt_input( const unsigned char **cursor, size_t *max, - struct psbt_input_counts counts, uint32_t flags, struct wally_psbt_input *result) { @@ -1453,23 +1242,6 @@ static int pull_psbt_input( size_t key_len; const unsigned char *pre_key; - /* Init and alloc the maps */ - if (counts.num_keypaths > 0) { - if ((ret = wally_keypath_map_init_alloc(counts.num_keypaths, &result->keypaths)) != WALLY_OK) { - return ret; - } - } - if (counts.num_partial_sigs > 0) { - if ((ret = wally_partial_sigs_map_init_alloc(counts.num_partial_sigs, &result->partial_sigs)) != WALLY_OK) { - return ret; - } - } - if (counts.num_unknowns > 0) { - if ((ret = wally_unknowns_map_init_alloc(counts.num_unknowns, &result->unknowns)) != WALLY_OK) { - return ret; - } - } - /* Read key value pairs */ pre_key = *cursor; while ((key_len = pull_varlength(cursor, max)) != 0) { @@ -1557,29 +1329,9 @@ static int pull_psbt_input( break; } case WALLY_PSBT_IN_PARTIAL_SIG: { - size_t i; - struct wally_partial_sigs_item *sigitem; - struct wally_partial_sigs_map *partial_sigs = result->partial_sigs; - - if (!is_valid_pubkey_len(key_len)) - return WALLY_EINVAL; - - /* Check for duplicates */ - for (i = 0; i < partial_sigs->num_items; ++i) { - if (memcmp(partial_sigs->items[i].pubkey, key, key_len) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } - - sigitem = &partial_sigs->items[partial_sigs->num_items]; - memcpy(sigitem->pubkey, key, key_len); - pull_subfield_end(cursor, max, key, key_len); - - if (!clone_varlength(&sigitem->sig, &sigitem->sig_len, - cursor, max)) { - return WALLY_ENOMEM; - } - partial_sigs->num_items++; + ret = pull_partial_sig(cursor, max, key, key_len, &result->partial_sigs); + if (ret != WALLY_OK) + return ret; break; } case WALLY_PSBT_IN_SIGHASH_TYPE: { @@ -1629,10 +1381,9 @@ static int pull_psbt_input( break; } case WALLY_PSBT_IN_BIP32_DERIVATION: { - ret = pull_keypath(cursor, max, key, key_len, result->keypaths); - if (ret != WALLY_OK) { + ret = pull_keypath(cursor, max, key, key_len, &result->keypaths); + if (ret != WALLY_OK) return ret; - } break; } case WALLY_PSBT_IN_FINAL_SCRIPTSIG: { @@ -1842,10 +1593,9 @@ static int pull_psbt_input( /* fall through */ /* Unknowns */ default: { - ret = pull_unknown_key_value(cursor, max, pre_key, result->unknowns); - if (ret != WALLY_OK) { + ret = pull_unknown_key_value(cursor, max, pre_key, &result->unknowns); + if (ret != WALLY_OK) return ret; - } break; } } @@ -1859,21 +1609,12 @@ static int pull_psbt_input( static int pull_psbt_output( const unsigned char **cursor, size_t *max, - struct psbt_output_counts counts, struct wally_psbt_output *result) { int ret; size_t key_len; const unsigned char *pre_key; - /* Init and alloc the maps */ - if (counts.num_keypaths > 0) { - wally_keypath_map_init_alloc(counts.num_keypaths, &result->keypaths); - } - if (counts.num_unknowns > 0) { - wally_unknowns_map_init_alloc(counts.num_unknowns, &result->unknowns); - } - /* Read key value */ pre_key = *cursor; while ((key_len = pull_varlength(cursor, max)) != 0) { @@ -1917,10 +1658,9 @@ static int pull_psbt_output( break; } case WALLY_PSBT_OUT_BIP32_DERIVATION: { - ret = pull_keypath(cursor, max, key, key_len, result->keypaths); - if (ret != WALLY_OK) { + ret = pull_keypath(cursor, max, key, key_len, &result->keypaths); + if (ret != WALLY_OK) return ret; - } break; } case WALLY_PSBT_PROPRIETARY_TYPE: { @@ -2084,10 +1824,9 @@ static int pull_psbt_output( /* fall through */ /* Unknowns */ default: { - ret = pull_unknown_key_value(cursor, max, pre_key, result->unknowns); - if (ret != WALLY_OK) { + ret = pull_unknown_key_value(cursor, max, pre_key, &result->unknowns); + if (ret != WALLY_OK) return ret; - } break; } } @@ -2105,7 +1844,6 @@ int wally_psbt_from_bytes( const unsigned char *magic, *pre_key; int ret; size_t i, key_len; - struct psbt_counts *counts = NULL; struct wally_psbt *result = NULL; uint32_t flags = 0; @@ -2129,18 +1867,10 @@ int wally_psbt_from_bytes( #endif /* BUILD_ELEMENTS */ } - /* Get a count of the psbt parts */ - if (count_psbt_parts(bytes, bytes_len, flags, &counts) != WALLY_OK) { - ret = WALLY_EINVAL; - goto fail; - } - /* Make the wally_psbt */ - ret = wally_psbt_init_alloc(counts->num_inputs, counts->num_outputs, counts->num_global_unknowns, &result); - if (ret != WALLY_OK) { + ret = wally_psbt_init_alloc(0, 0, 8, &result); + if (ret != WALLY_OK) goto fail; - } - *output = result; /* Set the magic */ memcpy(result->magic, magic, sizeof(WALLY_PSBT_MAGIC)); @@ -2157,29 +1887,22 @@ int wally_psbt_from_bytes( /* Process based on type */ switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_GLOBAL_UNSIGNED_TX: { - if (result->tx) { - ret = WALLY_EINVAL; /* We already have a global tx */ - goto fail; - } + struct wally_tx *tx; + subfield_nomore_end(&bytes, &bytes_len, key, key_len); /* Start parsing the value field. */ pull_subfield_start(&bytes, &bytes_len, pull_varint(&bytes, &bytes_len), &val, &val_max); - ret = wally_tx_from_bytes(val, val_max, flags, &result->tx); - if (ret != WALLY_OK) { - goto fail; + ret = wally_tx_from_bytes(val, val_max, flags, &tx); + if (ret == WALLY_OK) { + ret = wally_psbt_set_global_tx(result, tx); + wally_tx_free(tx); } + if (ret != WALLY_OK) + goto fail; pull_subfield_end(&bytes, &bytes_len, val, val_max); - - /* Make sure there are no scriptSigs and scriptWitnesses */ - for (i = 0; i < result->tx->num_inputs; ++i) { - if (result->tx->inputs[i].script_len != 0 || (result->tx->inputs[i].witness && result->tx->inputs[i].witness->num_items != 0)) { - ret = WALLY_EINVAL; /* Unsigned tx needs empty scriptSigs and scriptWtinesses */ - goto fail; - } - } break; } case WALLY_PSBT_GLOBAL_VERSION: { @@ -2203,11 +1926,9 @@ int wally_psbt_from_bytes( } /* Unknowns */ default: { - ret = pull_unknown_key_value(&bytes, &bytes_len, pre_key, - result->unknowns); - if (ret != WALLY_OK) { - return ret; - } + ret = pull_unknown_key_value(&bytes, &bytes_len, pre_key, &result->unknowns); + if (ret != WALLY_OK) + goto fail; break; } } @@ -2226,45 +1947,32 @@ int wally_psbt_from_bytes( } /* Read inputs */ - for (i = 0; i < counts->num_inputs; ++i) { - ret = pull_psbt_input(&bytes, &bytes_len, counts->input_counts[i], - flags, &result->inputs[i]); - /* Increment this now, might be partially initialized! */ - result->num_inputs++; - if (ret != WALLY_OK) { + for (i = 0; i < result->tx->num_inputs; ++i) { + ret = pull_psbt_input(&bytes, &bytes_len, flags, &result->inputs[i]); + result->num_inputs = i + 1; /* Free this input if we fail */ + if (ret != WALLY_OK) goto fail; - } - } - - /* Make sure that the number of inputs matches the number of inputs in the transaction */ - if (result->num_inputs != result->tx->num_inputs) { - ret = WALLY_EINVAL; - goto fail; } /* Read outputs */ - for (i = 0; i < counts->num_outputs; ++i) { - ret = pull_psbt_output(&bytes, &bytes_len, counts->output_counts[i], - &result->outputs[i]); - result->num_outputs++; - if (ret != WALLY_OK) { + for (i = 0; i < result->tx->num_outputs; ++i) { + ret = pull_psbt_output(&bytes, &bytes_len, &result->outputs[i]); + result->num_outputs = i + 1; /* Free this output if we fail */ + if (ret != WALLY_OK) goto fail; - } } /* If we ran out of data anywhere, fail. */ - if (bytes == NULL) { + if (!bytes) { ret = WALLY_EINVAL; goto fail; } - free_psbt_count(counts); + *output = result; return WALLY_OK; fail: - free_psbt_count(counts); wally_psbt_free(result); - *output = NULL; return ret; } @@ -2462,11 +2170,10 @@ static int push_psbt_input( } /* Keypaths */ if (input->keypaths) { - struct wally_keypath_map *keypaths = input->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { + for (i = 0; i < input->keypaths->num_items; ++i) { push_keypath_item(cursor, max, WALLY_PSBT_IN_BIP32_DERIVATION, - &keypaths->items[i]); + &input->keypaths->items[i]); } } /* Final scriptSig */ @@ -2564,11 +2271,10 @@ static int push_psbt_output( } /* Keypaths */ if (output->keypaths) { - struct wally_keypath_map *keypaths = output->keypaths; - for (i = 0; i < keypaths->num_items; ++i) { + for (i = 0; i < output->keypaths->num_items; ++i) { push_keypath_item(cursor, max, WALLY_PSBT_OUT_BIP32_DERIVATION, - &keypaths->items[i]); + &output->keypaths->items[i]); } } #ifdef BUILD_ELEMENTS diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index a0a1a34b1..1da19272d 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -53,6 +53,11 @@ def test_serialization(self): self.assertEqual(WALLY_OK, wally_tx_add_output(tx, output)) self.assertEqual(WALLY_OK, wally_psbt_set_global_tx(psbt, tx)) + # wally_psbt_set_global_tx() reserves space for but does not add + # PSBT input and output values. Set the count here to use the + # empty reserved ones for this test. + psbt.contents.num_inputs = psbt.contents.tx.contents.num_inputs + psbt.contents.num_outputs = psbt.contents.tx.contents.num_outputs ret, ser = wally_psbt_to_base64(psbt) self.assertEqual(WALLY_OK, ret) self.assertEqual(creator['result'], ser) From 14ec80b3641c8e47c99d15f135ca1603f12d39df Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sat, 11 Jul 2020 00:37:35 +1200 Subject: [PATCH 136/205] psbt: optimise to avoid cloning the parsed global tx --- src/psbt.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 31ae034a3..3e77b8472 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -946,9 +946,9 @@ int wally_psbt_free(struct wally_psbt *psbt) return WALLY_OK; } -int wally_psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx) +static int psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx, bool do_clone) { - struct wally_tx *new_tx; + struct wally_tx *new_tx = NULL; struct wally_psbt_input *new_inputs = NULL; struct wally_psbt_output *new_outputs = NULL; size_t i; @@ -961,7 +961,7 @@ int wally_psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx) if (tx->inputs[i].script || tx->inputs[i].witness) return WALLY_EINVAL; /* tx mustn't have scriptSigs or witnesses */ - if ((ret = wally_tx_clone(tx, 0, &new_tx)) != WALLY_OK) + if (do_clone && (ret = wally_tx_clone(tx, 0, &new_tx)) != WALLY_OK) return ret; if (psbt->inputs_allocation_len < tx->num_inputs) @@ -988,10 +988,15 @@ int wally_psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx) psbt->outputs = new_outputs; psbt->outputs_allocation_len = tx->num_outputs; } - psbt->tx = new_tx; + psbt->tx = do_clone ? new_tx : tx; return WALLY_OK; } +int wally_psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx) +{ + return psbt_set_global_tx(psbt, tx, true); +} + /* Returns false if it hits a zero length "key" (i.e. separator) or EOF. * * Otherwise, starts the subfield (extra, extra_len), so caller should @@ -1897,8 +1902,9 @@ int wally_psbt_from_bytes( &val, &val_max); ret = wally_tx_from_bytes(val, val_max, flags, &tx); if (ret == WALLY_OK) { - ret = wally_psbt_set_global_tx(result, tx); - wally_tx_free(tx); + ret = psbt_set_global_tx(result, tx, false); + if (ret != WALLY_OK) + wally_tx_free(tx); } if (ret != WALLY_OK) goto fail; From 842e0f296677bb9833611d68d762456e1cf39b9e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sat, 11 Jul 2020 23:08:44 +1200 Subject: [PATCH 137/205] psbt: psbt_to_bytes: Follow the library convention for too short buffers The convention is to return WALLY_OK and put the required length in *written. The caller must check that the returned amount fits within the buffer they supplied. The SWIG generated wrappers will throw an exception on any return result except WALLY_OK. This and other library conventions will be documented shortly. --- CHANGES.md | 3 ++ src/ctest/test_psbt_limits.c | 20 ++++++++----- src/psbt.c | 58 +++++++++++++++--------------------- 3 files changed, 39 insertions(+), 42 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 49c10edfc..569f0af3d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,9 @@ ## Version 0.7.9 +- psbt_to_bytes no longer returns WALLY_EINVAL if the supplied buffer is too + short. Please see the function documentation for details. + - FINGERPRINT_LEN was renamed to BIP32_KEY_FINGERPRINT_LEN for consistency - You should change any references in your source when upgrading. diff --git a/src/ctest/test_psbt_limits.c b/src/ctest/test_psbt_limits.c index 8648b9f10..2a812feae 100644 --- a/src/ctest/test_psbt_limits.c +++ b/src/ctest/test_psbt_limits.c @@ -72,20 +72,24 @@ static void test_psbt_read(const struct psbt_test *test, static void test_psbt_write(const struct psbt_test *test, unsigned char *p, size_t plen) { - size_t i, written; + size_t i, psbt_len, written; struct wally_psbt *psbt; if (wally_psbt_from_base64(test->base64, &psbt) != WALLY_OK) abort(); - for (i = 0;; i++) { - if (wally_psbt_to_bytes(psbt, p + plen - i, i, &written) == WALLY_OK) - break; + if (wally_psbt_get_length(psbt, &psbt_len) != WALLY_OK) + abort(); + + for (i = 0; i <= psbt_len; i++) { + /* A too short buffer should return OK and the required length */ + if (wally_psbt_to_bytes(psbt, p + plen - i, i, &written) != WALLY_OK) { + errx(1, "wally_psbt_to_bytes should have suceeded"); + } + if (written != psbt_len) + errx(1, "wally_psbt_to_bytes %s wrote %zu in %zu bytes?", + test->base64, written, i); } - /* Should have fit exactly */ - if (written != i) - errx(1, "wally_psbt_to_bytes %s wrote %zu in %zu bytes?", - test->base64, written, i); wally_psbt_free(psbt); } diff --git a/src/psbt.c b/src/psbt.c index 3e77b8472..9dbc08d9e 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1982,17 +1982,9 @@ int wally_psbt_from_bytes( return ret; } -int wally_psbt_get_length( - const struct wally_psbt *psbt, - size_t *written) +int wally_psbt_get_length(const struct wally_psbt *psbt, size_t *written) { - int ret; - - ret = wally_psbt_to_bytes(psbt, NULL, 0, written); - if (ret == WALLY_EINVAL && *written != 0) { - return WALLY_OK; - } - return ret; + return wally_psbt_to_bytes(psbt, NULL, 0, written); } /* Literally a varbuff containing only type as a varint, then optional data */ @@ -2331,22 +2323,25 @@ static int push_psbt_output( return WALLY_OK; } -int wally_psbt_to_bytes( - const struct wally_psbt *psbt, - unsigned char *bytes_out, size_t len, - size_t *written) +int wally_psbt_to_bytes(const struct wally_psbt *psbt, + unsigned char *bytes_out, size_t len, + size_t *written) { unsigned char *cursor = bytes_out; size_t max = len, i, is_elements; uint32_t flags; int ret; - *written = 0; + if (written) + *written = 0; + + if (!written) + return WALLY_EINVAL; if ((ret = wally_psbt_is_elements(psbt, &is_elements)) != WALLY_OK) return ret; - flags = is_elements ? WALLY_TX_FLAG_USE_ELEMENTS : 0; + flags = is_elements ? WALLY_TX_FLAG_USE_ELEMENTS : 0; push_bytes(&cursor, &max, psbt->magic, sizeof(psbt->magic)); /* Global tx */ @@ -2391,7 +2386,6 @@ int wally_psbt_to_bytes( if (cursor == NULL) { /* Once cursor was NULL, max accumulates hm bytes we needed */ *written = len + max; - return WALLY_EINVAL; } else { *written = len - max; } @@ -2437,29 +2431,29 @@ int wally_psbt_from_base64( return ret; } -int wally_psbt_to_base64( - struct wally_psbt *psbt, - char **output) +int wally_psbt_to_base64(struct wally_psbt *psbt, char **output) { unsigned char *buff; char *result = NULL; - size_t len, written, b64_safe_len; - ssize_t b64_len; + size_t len, written, b64_safe_len = 0; int ret = WALLY_OK; TX_CHECK_OUTPUT; if (!psbt) return WALLY_EINVAL; - if ((ret = wally_psbt_get_length(psbt, &len)) != WALLY_OK) { + if ((ret = wally_psbt_get_length(psbt, &len)) != WALLY_OK) return ret; - } - if ((buff = wally_malloc(len)) == NULL) { + + if ((buff = wally_malloc(len)) == NULL) return WALLY_ENOMEM; - } /* Get psbt bytes */ - if ((ret = wally_psbt_to_bytes(psbt, buff, len, &written)) != WALLY_OK) { + if ((ret = wally_psbt_to_bytes(psbt, buff, len, &written)) != WALLY_OK) + goto done; + + if (written != len) { + ret = WALLY_ERROR; /* Length calculated incorrectly */ goto done; } @@ -2469,7 +2463,7 @@ int wally_psbt_to_base64( ret = WALLY_ENOMEM; goto done; } - if ((b64_len = base64_encode(result, b64_safe_len, (char *)buff, written)) <= 0) { + if (base64_encode(result, b64_safe_len, (char *)buff, written) <= 0) { ret = WALLY_EINVAL; goto done; } @@ -2477,12 +2471,8 @@ int wally_psbt_to_base64( result = NULL; done: - if (result) { - clear_and_free(result, b64_safe_len); - } - if (buff) { - clear_and_free(buff, len); - } + clear_and_free(result, b64_safe_len); + clear_and_free(buff, len); return ret; } From a5e7f4774e408ff111a0deb7ad1c048fb5bda2d8 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 00:58:10 +1200 Subject: [PATCH 138/205] docs: Add docs for return codes and variable output buffers There is plenty more to be documented, but this at least documents the most common user confusion regarding variable length output buffers and how they are handled. --- docs/source/conf.py | 8 ++++--- docs/source/conventions.rst | 45 +++++++++++++++++++++++++++++++++++++ docs/source/index.rst | 1 + 3 files changed, 51 insertions(+), 3 deletions(-) create mode 100644 docs/source/conventions.rst diff --git a/docs/source/conf.py b/docs/source/conf.py index 7249033c8..ad95d5641 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -13,12 +13,14 @@ def output_func(docs, func): func = func[:-1].replace('WALLY_CORE_API','').strip() func = func.replace(',',', ').replace(' ', ' ') ret = ['.. c:function:: ' + func, ''] - seen_param = False + is_variable_buffer_ret = 'unsigned char *bytes_out, size_t len, size_t *written' in func for l in docs: ret.extend(get_doc_lines(l)) if is_normal_ret: - ret.append(' :return: WALLY_OK or an error code.') # FIXME: Link - ret.append(' :rtype: int') + if is_variable_buffer_ret: + ret.append(' :return: See :ref:`variable-length-output-buffers`') + else: + ret.append(' :return: See :ref:`error-codes`') ret.append('') ret.append('') return ret diff --git a/docs/source/conventions.rst b/docs/source/conventions.rst new file mode 100644 index 000000000..8572d7ee2 --- /dev/null +++ b/docs/source/conventions.rst @@ -0,0 +1,45 @@ +Library Conventions +=================== + +.. _error-codes: + +Error Codes +----------- + +The following values can be returned by library functions: + +================ ============================================= +Code Meaning +================ ============================================= +``WALLY_OK`` The function completed without error. + See :ref:`variable-length-output-buffers` if + applicable for the function. +``WALLY_ERROR`` An internal or unexpected error happened in + the library. In some cases this code may + indicate a specific error condition which + will be documented with the function. +``WALLY_EINVAL`` One or more parameters passed to the function + is not valid. For example, a required buffer + value is NULL or of the wrong length. +``WALLY_ENOMEM`` The function required memory allocation but + no memory could be allocated from the O/S. +================ ============================================= + + +.. _variable-length-output-buffers: + +Variable Length Output Buffers +------------------------------ + +Some functions write output that can vary in length to user supplied buffers. +In these cases, the number of written bytes is placed in the ``written`` +output parameter when the function completes. + +If the user supplied buffer is of insufficient size, these functions will +still return ``WALLY_OK``, but will place the required size in the ``written`` +output parameter. + +Callers must check not only that the function succeeds, but also that the +number of bytes written is less than or equal to the supplied buffer size. +If the buffer is too small, it should be resized to the returned size and the +call retried. diff --git a/docs/source/index.rst b/docs/source/index.rst index 4fb0697d2..37590e050 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -21,6 +21,7 @@ libwally-core documentation :maxdepth: 2 :caption: Developer Guides + Library Conventions Liquid Indices and tables From 854df83b8cedb97aabac70ada6732c73a2527c28 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 01:01:07 +1200 Subject: [PATCH 139/205] psbt: Standardise param name in order to correct doc generation --- include/wally_psbt.h | 11 ++++------- src/psbt.c | 34 ++++++++++++++++------------------ 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 75978e0f9..ab419eeb7 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -559,12 +559,12 @@ WALLY_CORE_API int wally_psbt_set_global_tx( * Create a PSBT from its serialized bytes. * * :param bytes: Bytes to create the PSBT from. - * :param bytes_len: Length of ``bytes`` in bytes. + * :param len: Length of ``bytes`` in bytes. * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_from_bytes( const unsigned char *bytes, - size_t bytes_len, + size_t len, struct wally_psbt **output); /** @@ -582,16 +582,13 @@ WALLY_CORE_API int wally_psbt_get_length( * * :param psbt: the PSBT to serialize. * :param bytes_out: Bytes to create the transaction from. - * :param bytes_len: Length of ``bytes`` in bytes (use `wally_psbt_get_length`). + * :param len: Length of ``bytes`` in bytes (use `wally_psbt_get_length`). * :param written: number of bytes written to bytes_out. - * - * If @bytes_len is insufficient, this will return WALLY_EINVAL, but - * @written will be filled in the the amount which would be required. */ WALLY_CORE_API int wally_psbt_to_bytes( const struct wally_psbt *psbt, unsigned char *bytes_out, - size_t bytes_len, + size_t len, size_t *written); /** diff --git a/src/psbt.c b/src/psbt.c index 9dbc08d9e..e3703e036 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1841,10 +1841,8 @@ static int pull_psbt_output( return WALLY_OK; } -int wally_psbt_from_bytes( - const unsigned char *bytes, - size_t bytes_len, - struct wally_psbt **output) +int wally_psbt_from_bytes(const unsigned char *bytes, size_t len, + struct wally_psbt **output) { const unsigned char *magic, *pre_key; int ret; @@ -1854,7 +1852,7 @@ int wally_psbt_from_bytes( TX_CHECK_OUTPUT; - magic = pull_skip(&bytes, &bytes_len, sizeof(WALLY_PSBT_MAGIC)); + magic = pull_skip(&bytes, &len, sizeof(WALLY_PSBT_MAGIC)); if (!magic) { ret = WALLY_EINVAL; /* Not enough bytes */ goto fail; @@ -1882,23 +1880,23 @@ int wally_psbt_from_bytes( /* Read globals first */ pre_key = bytes; - while ((key_len = pull_varlength(&bytes, &bytes_len)) != 0) { + while ((key_len = pull_varlength(&bytes, &len)) != 0) { const unsigned char *key, *val; size_t val_max; /* Start parsing key */ - pull_subfield_start(&bytes, &bytes_len, key_len, &key, &key_len); + pull_subfield_start(&bytes, &len, key_len, &key, &key_len); /* Process based on type */ switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_GLOBAL_UNSIGNED_TX: { struct wally_tx *tx; - subfield_nomore_end(&bytes, &bytes_len, key, key_len); + subfield_nomore_end(&bytes, &len, key, key_len); /* Start parsing the value field. */ - pull_subfield_start(&bytes, &bytes_len, - pull_varint(&bytes, &bytes_len), + pull_subfield_start(&bytes, &len, + pull_varint(&bytes, &len), &val, &val_max); ret = wally_tx_from_bytes(val, val_max, flags, &tx); if (ret == WALLY_OK) { @@ -1908,7 +1906,7 @@ int wally_psbt_from_bytes( } if (ret != WALLY_OK) goto fail; - pull_subfield_end(&bytes, &bytes_len, val, val_max); + pull_subfield_end(&bytes, &len, val, val_max); break; } case WALLY_PSBT_GLOBAL_VERSION: { @@ -1916,14 +1914,14 @@ int wally_psbt_from_bytes( ret = WALLY_EINVAL; /* Version already provided */ goto fail; } - subfield_nomore_end(&bytes, &bytes_len, key, key_len); + subfield_nomore_end(&bytes, &len, key, key_len); /* Start parsing the value field. */ - pull_subfield_start(&bytes, &bytes_len, - pull_varint(&bytes, &bytes_len), + pull_subfield_start(&bytes, &len, + pull_varint(&bytes, &len), &val, &val_max); result->version = pull_le32(&val, &val_max); - subfield_nomore_end(&bytes, &bytes_len, val, val_max); + subfield_nomore_end(&bytes, &len, val, val_max); if (result->version > WALLY_PSBT_HIGHEST_VERSION) { ret = WALLY_EINVAL; /* Unsupported version number */ goto fail; @@ -1932,7 +1930,7 @@ int wally_psbt_from_bytes( } /* Unknowns */ default: { - ret = pull_unknown_key_value(&bytes, &bytes_len, pre_key, &result->unknowns); + ret = pull_unknown_key_value(&bytes, &len, pre_key, &result->unknowns); if (ret != WALLY_OK) goto fail; break; @@ -1954,7 +1952,7 @@ int wally_psbt_from_bytes( /* Read inputs */ for (i = 0; i < result->tx->num_inputs; ++i) { - ret = pull_psbt_input(&bytes, &bytes_len, flags, &result->inputs[i]); + ret = pull_psbt_input(&bytes, &len, flags, &result->inputs[i]); result->num_inputs = i + 1; /* Free this input if we fail */ if (ret != WALLY_OK) goto fail; @@ -1962,7 +1960,7 @@ int wally_psbt_from_bytes( /* Read outputs */ for (i = 0; i < result->tx->num_outputs; ++i) { - ret = pull_psbt_output(&bytes, &bytes_len, &result->outputs[i]); + ret = pull_psbt_output(&bytes, &len, &result->outputs[i]); result->num_outputs = i + 1; /* Free this output if we fail */ if (ret != WALLY_OK) goto fail; From 423d9d67c2bd7dbb0ec9b4935e9aece03dd3e93e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 01:23:39 +1200 Subject: [PATCH 140/205] psbt: fix warnings building without elements support --- src/psbt.c | 10 ++++++---- src/transaction.c | 3 +-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index e3703e036..1f07bde8c 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -13,12 +13,12 @@ #include "script.h" #include "pullpush.h" -const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; +static const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; +static const uint8_t WALLY_ELEMENTS_PSBT_MAGIC[5] = {'p', 's', 'e', 't', 0xff}; #ifdef BUILD_ELEMENTS -const uint8_t WALLY_ELEMENTS_PSBT_MAGIC[5] = {'p', 's', 'e', 't', 0xff}; -const uint8_t WALLY_ELEMENTS_ID[8] = {'e', 'l', 'e', 'm', 'e', 'n', 't', 's'}; -const size_t WALLY_ELEMENTS_ID_LEN = 8; +static const uint8_t WALLY_ELEMENTS_ID[8] = {'e', 'l', 'e', 'm', 'e', 'n', 't', 's'}; +static const size_t WALLY_ELEMENTS_ID_LEN = 8; #endif /* BUILD_ELEMENTS */ static bool pubkey_is_compressed(const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { @@ -2090,6 +2090,8 @@ static int push_psbt_input( int ret; size_t i; + (void)flags; + /* Non witness utxo */ if (input->non_witness_utxo) { push_psbt_key(cursor, max, WALLY_PSBT_IN_NON_WITNESS_UTXO, NULL, 0); diff --git a/src/transaction.c b/src/transaction.c index c7b1449c8..271a16754 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -351,10 +351,9 @@ static bool clone_input_to( #ifdef BUILD_ELEMENTS unsigned char *new_issuance_amount = NULL, *new_inflation_keys = NULL, *new_issuance_amount_rangeproof = NULL, *new_inflation_keys_rangeproof = NULL; + struct wally_tx_witness_stack *new_pegin_witness; #endif - struct wally_tx_witness_stack *new_witness; - struct wally_tx_witness_stack *new_pegin_witness; new_witness = src->witness ? clone_witness(src->witness) : NULL; From 7a7916fbd1c706b3b30d724d83443ffe5deb9ee5 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 09:22:03 +1200 Subject: [PATCH 141/205] Java: use consistent method prologues --- src/swig_java/jni_extra.java_in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/swig_java/jni_extra.java_in b/src/swig_java/jni_extra.java_in index 3e7149fd3..a3d18522e 100644 --- a/src/swig_java/jni_extra.java_in +++ b/src/swig_java/jni_extra.java_in @@ -190,19 +190,19 @@ return ret; } - public static final byte[] scriptpubkey_p2pkh_from_bytes(byte[] bytes, long flags) { + public final static byte[] scriptpubkey_p2pkh_from_bytes(byte[] bytes, long flags) { final byte[] buf = new byte[WALLY_SCRIPTPUBKEY_P2PKH_LEN]; final int len = scriptpubkey_p2pkh_from_bytes(bytes, flags, buf); return checkBuffer(buf, len); } - public static final byte[] scriptpubkey_p2sh_from_bytes(byte[] bytes, long flags) { + public final static byte[] scriptpubkey_p2sh_from_bytes(byte[] bytes, long flags) { final byte[] buf = new byte[WALLY_SCRIPTPUBKEY_P2SH_LEN]; final int len = scriptpubkey_p2sh_from_bytes(bytes, flags, buf); return checkBuffer(buf, len); } - public static final byte[] scriptpubkey_multisig_from_bytes(byte[] bytes, long threshold, long flags, int num_sigs) { + public final static byte[] scriptpubkey_multisig_from_bytes(byte[] bytes, long threshold, long flags, int num_sigs) { final int required_len = 3 + num_sigs * (Wally.EC_PUBLIC_KEY_LEN + 1); final byte[] buf = new byte[required_len]; final int len = scriptpubkey_multisig_from_bytes(bytes, threshold, flags, buf); @@ -221,7 +221,7 @@ return ret; } - public static final byte[] addr_segwit_to_bytes(String jarg1, String jarg2, long jarg3) { + public final static byte[] addr_segwit_to_bytes(String jarg1, String jarg2, long jarg3) { final byte[] buf = new byte[32 + 2]; /* Largest v0 witness script possible */ final int len = addr_segwit_to_bytes(jarg1, jarg2, jarg3, buf); return trimBuffer(buf, len); From e383d75d5f8b1162f47a0a837e53a5be39699e6c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 09:37:06 +1200 Subject: [PATCH 142/205] psbt: Clear decoded base64 data after unserialising --- src/psbt.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 1f07bde8c..b55e5d8d5 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2393,9 +2393,7 @@ int wally_psbt_to_bytes(const struct wally_psbt *psbt, return WALLY_OK; } -int wally_psbt_from_base64( - const char *string, - struct wally_psbt **output) +int wally_psbt_from_base64(const char *string, struct wally_psbt **output) { char *decoded; size_t safe_len, string_len; @@ -2425,9 +2423,7 @@ int wally_psbt_from_base64( ret = wally_psbt_from_bytes((unsigned char *)decoded, decoded_len, output); done: - if (decoded) { - wally_free(decoded); - } + clear_and_free(decoded, safe_len); return ret; } From f1f70d95fca6b7571135f25718b1879bc33dd575 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 09:40:53 +1200 Subject: [PATCH 143/205] psbt: Clean up test, use wally for hex conversion --- src/ctest/test_psbt.c | 54 ++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/ctest/test_psbt.c b/src/ctest/test_psbt.c index a9ec8d0b2..0b6f17364 100644 --- a/src/ctest/test_psbt.c +++ b/src/ctest/test_psbt.c @@ -4,9 +4,7 @@ #include #include #include -#include #include -#include #include "psbts.h" @@ -23,40 +21,44 @@ int main(void) } for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { + const char* base64_in = valid_psbts[i].base64; struct wally_psbt *psbt; char *output; unsigned char *bytes; - size_t len, actual_len; + size_t len, written; + + if (wally_psbt_from_base64(base64_in, &psbt) != WALLY_OK) + errx(1, "Failed to parse psbt %s", base64_in); + + if (wally_psbt_to_base64(psbt, &output) != WALLY_OK) + errx(1, "Failed to base64 psbt %s", base64_in); + + if (strcmp(output, base64_in) != 0) + errx(1, "psbt %s turned into %s?", base64_in, output); - if (wally_psbt_from_base64(valid_psbts[i].base64, &psbt) != WALLY_OK) { - errx(1, "Failed to parse psbt %s", valid_psbts[i].base64); - } - if (wally_psbt_to_base64(psbt, &output) != WALLY_OK) { - errx(1, "Failed to base64 psbt %s", valid_psbts[i].base64); - } - if (strcmp(output, valid_psbts[i].base64) != 0) { - errx(1, "psbt %s turned into %s?", valid_psbts[i].base64, output); - } wally_free_string(output); - if (wally_psbt_get_length(psbt, &len) != WALLY_OK) { - errx(1, "Failed to get pbst %s len", valid_psbts[i].base64); - } + if (wally_psbt_get_length(psbt, &len) != WALLY_OK) + errx(1, "Failed to get psbt %s len", base64_in); + bytes = malloc(len); - if (wally_psbt_to_bytes(psbt, bytes, len, &actual_len) != WALLY_OK) { - errx(1, "psbt %s could not to_bytes?", valid_psbts[i].base64); - } - if (len != actual_len) { - errx(1, "psbt %s to_bytes to %zu not %zu?", valid_psbts[i].base64, - actual_len, len); + if (wally_psbt_to_bytes(psbt, bytes, len, &written) != WALLY_OK) + errx(1, "psbt %s could not to_bytes?", base64_in); + + if (len != written) { + errx(1, "psbt %s to_bytes to %zu not %zu?", base64_in, + written, len); } - output = malloc(hex_str_size(len)); - hex_encode(bytes, len, output, hex_str_size(len)); - if (strcmp(output, valid_psbts[i].hex) != 0) { + + if (wally_hex_from_bytes(bytes, len, &output) != WALLY_OK) + errx(1, "Failed to convert psbt bytes to hex"); + + if (strcmp(output, valid_psbts[i].hex) != 0) errx(1, "psbt[%zi] bytes %s not %s", i, output, valid_psbts[i].hex); - } + + wally_free_string(output); + free(bytes); - free(output); wally_psbt_free(psbt); } From 78409c7cf3b2019725dc1849f202a7dd7300c7b9 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 16:13:03 +1200 Subject: [PATCH 144/205] psbt: constify psbt function parameters --- include/wally_psbt.h | 142 ++++++++++++++++++++--------------------- src/ctest/test_psbt.c | 2 +- src/psbt.c | 144 +++++++++++++++++++++--------------------- 3 files changed, 144 insertions(+), 144 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index ab419eeb7..1e4964a16 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -316,18 +316,18 @@ WALLY_CORE_API int wally_unknowns_map_add( * :param output: Destination for the resulting PSBT input. */ WALLY_CORE_API int wally_psbt_input_init_alloc( - struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, + const struct wally_tx *non_witness_utxo, + const struct wally_tx_output *witness_utxo, + const unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len, - unsigned char *final_script_sig, + const unsigned char *final_script_sig, size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, - struct wally_unknowns_map *unknowns, + const struct wally_tx_witness_stack *final_witness, + const struct wally_keypath_map *keypaths, + const struct wally_partial_sigs_map *partial_sigs, + const struct wally_unknowns_map *unknowns, uint32_t sighash_type, struct wally_psbt_input **output); @@ -339,7 +339,7 @@ WALLY_CORE_API int wally_psbt_input_init_alloc( */ WALLY_CORE_API int wally_psbt_input_set_non_witness_utxo( struct wally_psbt_input *input, - struct wally_tx *non_witness_utxo); + const struct wally_tx *non_witness_utxo); /** * Set the witness_utxo in an input. @@ -349,7 +349,7 @@ WALLY_CORE_API int wally_psbt_input_set_non_witness_utxo( */ WALLY_CORE_API int wally_psbt_input_set_witness_utxo( struct wally_psbt_input *input, - struct wally_tx_output *witness_utxo); + const struct wally_tx_output *witness_utxo); /** * Set the redeem_script in an input. @@ -360,7 +360,7 @@ WALLY_CORE_API int wally_psbt_input_set_witness_utxo( */ WALLY_CORE_API int wally_psbt_input_set_redeem_script( struct wally_psbt_input *input, - unsigned char *redeem_script, + const unsigned char *redeem_script, size_t redeem_script_len); /** @@ -372,7 +372,7 @@ WALLY_CORE_API int wally_psbt_input_set_redeem_script( */ WALLY_CORE_API int wally_psbt_input_set_witness_script( struct wally_psbt_input *input, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len); /** @@ -384,7 +384,7 @@ WALLY_CORE_API int wally_psbt_input_set_witness_script( */ WALLY_CORE_API int wally_psbt_input_set_final_script_sig( struct wally_psbt_input *input, - unsigned char *final_script_sig, + const unsigned char *final_script_sig, size_t final_script_sig_len); /** @@ -395,7 +395,7 @@ WALLY_CORE_API int wally_psbt_input_set_final_script_sig( */ WALLY_CORE_API int wally_psbt_input_set_final_witness( struct wally_psbt_input *input, - struct wally_tx_witness_stack *final_witness); + const struct wally_tx_witness_stack *final_witness); /** * Set the keypaths in an input. @@ -405,7 +405,7 @@ WALLY_CORE_API int wally_psbt_input_set_final_witness( */ WALLY_CORE_API int wally_psbt_input_set_keypaths( struct wally_psbt_input *input, - struct wally_keypath_map *keypaths); + const struct wally_keypath_map *keypaths); /** * Set the partial_sigs in an input. @@ -415,7 +415,7 @@ WALLY_CORE_API int wally_psbt_input_set_keypaths( */ WALLY_CORE_API int wally_psbt_input_set_partial_sigs( struct wally_psbt_input *input, - struct wally_partial_sigs_map *partial_sigs); + const struct wally_partial_sigs_map *partial_sigs); /** * Set the partial_sigs in an input. @@ -425,7 +425,7 @@ WALLY_CORE_API int wally_psbt_input_set_partial_sigs( */ WALLY_CORE_API int wally_psbt_input_set_unknowns( struct wally_psbt_input *input, - struct wally_unknowns_map *unknowns); + const struct wally_unknowns_map *unknowns); /** * Set the partial_sigs in an input. @@ -459,12 +459,12 @@ WALLY_CORE_API int wally_psbt_input_free( * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_output_init_alloc( - unsigned char *redeem_script, + const unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, + const struct wally_keypath_map *keypaths, + const struct wally_unknowns_map *unknowns, struct wally_psbt_output **output); /** @@ -476,7 +476,7 @@ WALLY_CORE_API int wally_psbt_output_init_alloc( */ WALLY_CORE_API int wally_psbt_output_set_redeem_script( struct wally_psbt_output *output, - unsigned char *redeem_script, + const unsigned char *redeem_script, size_t redeem_script_len); /** @@ -488,7 +488,7 @@ WALLY_CORE_API int wally_psbt_output_set_redeem_script( */ WALLY_CORE_API int wally_psbt_output_set_witness_script( struct wally_psbt_output *output, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len); /** @@ -499,7 +499,7 @@ WALLY_CORE_API int wally_psbt_output_set_witness_script( */ WALLY_CORE_API int wally_psbt_output_set_keypaths( struct wally_psbt_output *output, - struct wally_keypath_map *keypaths); + const struct wally_keypath_map *keypaths); /** * Set the partial_sigs in an output. @@ -509,7 +509,7 @@ WALLY_CORE_API int wally_psbt_output_set_keypaths( */ WALLY_CORE_API int wally_psbt_output_set_unknowns( struct wally_psbt_output *output, - struct wally_unknowns_map *unknowns); + const struct wally_unknowns_map *unknowns); #ifndef SWIG_PYTHON /** @@ -553,7 +553,7 @@ WALLY_CORE_API int wally_psbt_free( */ WALLY_CORE_API int wally_psbt_set_global_tx( struct wally_psbt *psbt, - struct wally_tx *tx); + const struct wally_tx *tx); /** * Create a PSBT from its serialized bytes. @@ -608,7 +608,7 @@ WALLY_CORE_API int wally_psbt_from_base64( * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_to_base64( - struct wally_psbt *psbt, + const struct wally_psbt *psbt, char **output); /** @@ -714,33 +714,33 @@ WALLY_CORE_API int wally_psbt_elements_init_alloc( * :param output: Destination for the resulting PSBT input. */ WALLY_CORE_API int wally_psbt_elements_input_init_alloc( - struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, + const struct wally_tx *non_witness_utxo, + const struct wally_tx_output *witness_utxo, + const unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len, - unsigned char *final_script_sig, + const unsigned char *final_script_sig, size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, - struct wally_unknowns_map *unknowns, + const struct wally_tx_witness_stack *final_witness, + const struct wally_keypath_map *keypaths, + const struct wally_partial_sigs_map *partial_sigs, + const struct wally_unknowns_map *unknowns, uint32_t sighash_type, uint64_t value, uint32_t has_value, - unsigned char *value_blinder, + const unsigned char *value_blinder, size_t value_blinder_len, - unsigned char *asset, + const unsigned char *asset, size_t asset_len, - unsigned char *asset_blinder, + const unsigned char *asset_blinder, size_t asset_blinder_len, - struct wally_tx *peg_in_tx, - unsigned char *txout_proof, + const struct wally_tx *peg_in_tx, + const unsigned char *txout_proof, size_t txout_proof_len, - unsigned char *genesis_hash, + const unsigned char *genesis_hash, size_t genesis_hash_len, - unsigned char *claim_script, + const unsigned char *claim_script, size_t claim_script_len, struct wally_psbt_input **output); @@ -763,7 +763,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_value( */ WALLY_CORE_API int wally_psbt_elements_input_set_value_blinder( struct wally_psbt_input *input, - unsigned char *value_blinder, + const unsigned char *value_blinder, size_t value_blinder_len); /** @@ -775,7 +775,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_value_blinder( */ WALLY_CORE_API int wally_psbt_elements_input_set_asset( struct wally_psbt_input *input, - unsigned char *asset, + const unsigned char *asset, size_t asset_len); /** @@ -787,7 +787,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_asset( */ WALLY_CORE_API int wally_psbt_elements_input_set_asset_blinder( struct wally_psbt_input *input, - unsigned char *asset_blinder, + const unsigned char *asset_blinder, size_t asset_blinder_len); /** @@ -798,7 +798,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_asset_blinder( */ WALLY_CORE_API int wally_psbt_elements_input_set_peg_in_tx( struct wally_psbt_input *input, - struct wally_tx *peg_in_tx); + const struct wally_tx *peg_in_tx); /** * Set the txout proof in an elements input. @@ -809,7 +809,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_peg_in_tx( */ WALLY_CORE_API int wally_psbt_elements_input_set_txout_proof( struct wally_psbt_input *input, - unsigned char *txout_proof, + const unsigned char *txout_proof, size_t txout_proof_len); /** @@ -821,7 +821,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_txout_proof( */ WALLY_CORE_API int wally_psbt_elements_input_set_genesis_hash( struct wally_psbt_input *input, - unsigned char *genesis_hash, + const unsigned char *genesis_hash, size_t genesis_hash_len); /** @@ -833,7 +833,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_genesis_hash( */ WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( struct wally_psbt_input *input, - unsigned char *claim_script, + const unsigned char *claim_script, size_t claim_script_len); /** @@ -863,27 +863,27 @@ WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_elements_output_init_alloc( - unsigned char *redeem_script, + const unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, - unsigned char *blinding_pubkey, + const struct wally_keypath_map *keypaths, + const struct wally_unknowns_map *unknowns, + const unsigned char *blinding_pubkey, size_t blinding_pubkey_len, - unsigned char *value_commitment, + const unsigned char *value_commitment, size_t value_commitment_len, - unsigned char *value_blinder, + const unsigned char *value_blinder, size_t value_blinder_len, - unsigned char *asset_commitment, + const unsigned char *asset_commitment, size_t asset_commitment_len, - unsigned char *asset_blinder, + const unsigned char *asset_blinder, size_t asset_blinder_len, - unsigned char *nonce_commitment, + const unsigned char *nonce_commitment, size_t nonce_commitment_len, - unsigned char *range_proof, + const unsigned char *range_proof, size_t range_proof_len, - unsigned char *surjection_proof, + const unsigned char *surjection_proof, size_t surjection_proof_len, struct wally_psbt_output **output); @@ -896,7 +896,7 @@ WALLY_CORE_API int wally_psbt_elements_output_init_alloc( */ WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( struct wally_psbt_output *output, - unsigned char *blinding_pubkey, + const unsigned char *blinding_pubkey, size_t blinding_pubkey_len); /** @@ -908,7 +908,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( */ WALLY_CORE_API int wally_psbt_elements_output_set_value_commitment( struct wally_psbt_output *output, - unsigned char *value_commitment, + const unsigned char *value_commitment, size_t value_commitment_len); /** @@ -920,7 +920,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_value_commitment( */ WALLY_CORE_API int wally_psbt_elements_output_set_value_blinder( struct wally_psbt_output *output, - unsigned char *value_blinder, + const unsigned char *value_blinder, size_t value_blinder_len); /** @@ -932,7 +932,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_value_blinder( */ WALLY_CORE_API int wally_psbt_elements_output_set_asset_commitment( struct wally_psbt_output *output, - unsigned char *asset_commitment, + const unsigned char *asset_commitment, size_t asset_commitment_len); /** @@ -944,7 +944,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_asset_commitment( */ WALLY_CORE_API int wally_psbt_elements_output_set_asset_blinder( struct wally_psbt_output *output, - unsigned char *asset_blinder, + const unsigned char *asset_blinder, size_t asset_blinder_len); /** @@ -956,7 +956,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_asset_blinder( */ WALLY_CORE_API int wally_psbt_elements_output_set_nonce_commitment( struct wally_psbt_output *output, - unsigned char *nonce_commitment, + const unsigned char *nonce_commitment, size_t nonce_commitment_len); /** @@ -968,7 +968,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_nonce_commitment( */ WALLY_CORE_API int wally_psbt_elements_output_set_range_proof( struct wally_psbt_output *output, - unsigned char *range_proof, + const unsigned char *range_proof, size_t range_proof_len); /** @@ -980,7 +980,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_range_proof( */ WALLY_CORE_API int wally_psbt_elements_output_set_surjection_proof( struct wally_psbt_output *output, - unsigned char *surjection_proof, + const unsigned char *surjection_proof, size_t surjection_proof_len); #endif /* BUILD_ELEMENTS */ diff --git a/src/ctest/test_psbt.c b/src/ctest/test_psbt.c index 0b6f17364..f3a237523 100644 --- a/src/ctest/test_psbt.c +++ b/src/ctest/test_psbt.c @@ -21,7 +21,7 @@ int main(void) } for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { - const char* base64_in = valid_psbts[i].base64; + const char *base64_in = valid_psbts[i].base64; struct wally_psbt *psbt; char *output; unsigned char *bytes; diff --git a/src/psbt.c b/src/psbt.c index b55e5d8d5..a4b9d0145 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -324,15 +324,15 @@ int wally_unknowns_map_add(struct wally_unknowns_map *unknowns, return ret; } -int wally_psbt_input_init_alloc(struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, size_t witness_script_len, - unsigned char *final_script_sig, size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, - struct wally_unknowns_map *unknowns, +int wally_psbt_input_init_alloc(const struct wally_tx *non_witness_utxo, + const struct wally_tx_output *witness_utxo, + const unsigned char *redeem_script, size_t redeem_script_len, + const unsigned char *witness_script, size_t witness_script_len, + const unsigned char *final_script_sig, size_t final_script_sig_len, + const struct wally_tx_witness_stack *final_witness, + const struct wally_keypath_map *keypaths, + const struct wally_partial_sigs_map *partial_sigs, + const struct wally_unknowns_map *unknowns, uint32_t sighash_type, struct wally_psbt_input **output) { @@ -369,24 +369,24 @@ int wally_psbt_input_init_alloc(struct wally_tx *non_witness_utxo, } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_input_init_alloc(struct wally_tx *non_witness_utxo, - struct wally_tx_output *witness_utxo, - unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, size_t witness_script_len, - unsigned char *final_script_sig, size_t final_script_sig_len, - struct wally_tx_witness_stack *final_witness, - struct wally_keypath_map *keypaths, - struct wally_partial_sigs_map *partial_sigs, - struct wally_unknowns_map *unknowns, +int wally_psbt_elements_input_init_alloc(const struct wally_tx *non_witness_utxo, + const struct wally_tx_output *witness_utxo, + const unsigned char *redeem_script, size_t redeem_script_len, + const unsigned char *witness_script, size_t witness_script_len, + const unsigned char *final_script_sig, size_t final_script_sig_len, + const struct wally_tx_witness_stack *final_witness, + const struct wally_keypath_map *keypaths, + const struct wally_partial_sigs_map *partial_sigs, + const struct wally_unknowns_map *unknowns, uint32_t sighash_type, uint64_t value, uint32_t has_value, - unsigned char *value_blinder, size_t value_blinder_len, - unsigned char *asset, size_t asset_len, - unsigned char *asset_blinder, size_t asset_blinder_len, - struct wally_tx *peg_in_tx, - unsigned char *txout_proof, size_t txout_proof_len, - unsigned char *genesis_hash, size_t genesis_hash_len, - unsigned char *claim_script, size_t claim_script_len, + const unsigned char *value_blinder, size_t value_blinder_len, + const unsigned char *asset, size_t asset_len, + const unsigned char *asset_blinder, size_t asset_blinder_len, + const struct wally_tx *peg_in_tx, + const unsigned char *txout_proof, size_t txout_proof_len, + const unsigned char *genesis_hash, size_t genesis_hash_len, + const unsigned char *claim_script, size_t claim_script_len, struct wally_psbt_input **output) { struct wally_psbt_input *result; @@ -430,7 +430,7 @@ int wally_psbt_elements_input_init_alloc(struct wally_tx *non_witness_utxo, #endif /* BUILD_ELEMENTS */ int wally_psbt_input_set_non_witness_utxo(struct wally_psbt_input *input, - struct wally_tx *non_witness_utxo) + const struct wally_tx *non_witness_utxo) { int ret = WALLY_OK; struct wally_tx *new_tx; @@ -446,7 +446,7 @@ int wally_psbt_input_set_non_witness_utxo(struct wally_psbt_input *input, } int wally_psbt_input_set_witness_utxo(struct wally_psbt_input *input, - struct wally_tx_output *witness_utxo) + const struct wally_tx_output *witness_utxo) { int ret; struct wally_tx_output *output; @@ -463,7 +463,7 @@ int wally_psbt_input_set_witness_utxo(struct wally_psbt_input *input, } int wally_psbt_input_set_redeem_script(struct wally_psbt_input *input, - unsigned char *redeem_script, + const unsigned char *redeem_script, size_t redeem_script_len) { if (!input) @@ -473,7 +473,7 @@ int wally_psbt_input_set_redeem_script(struct wally_psbt_input *input, } int wally_psbt_input_set_witness_script(struct wally_psbt_input *input, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len) { if (!input) @@ -483,7 +483,7 @@ int wally_psbt_input_set_witness_script(struct wally_psbt_input *input, } int wally_psbt_input_set_final_script_sig(struct wally_psbt_input *input, - unsigned char *final_script_sig, + const unsigned char *final_script_sig, size_t final_script_sig_len) { if (!input) @@ -493,7 +493,7 @@ int wally_psbt_input_set_final_script_sig(struct wally_psbt_input *input, } int wally_psbt_input_set_final_witness(struct wally_psbt_input *input, - struct wally_tx_witness_stack *final_witness) + const struct wally_tx_witness_stack *final_witness) { struct wally_tx_witness_stack *new_witness = NULL; @@ -509,19 +509,19 @@ int wally_psbt_input_set_final_witness(struct wally_psbt_input *input, } int wally_psbt_input_set_keypaths(struct wally_psbt_input *input, - struct wally_keypath_map *keypaths) + const struct wally_keypath_map *keypaths) { return input ? replace_keypaths(keypaths, &input->keypaths) : WALLY_EINVAL; } int wally_psbt_input_set_partial_sigs(struct wally_psbt_input *input, - struct wally_partial_sigs_map *partial_sigs) + const struct wally_partial_sigs_map *partial_sigs) { return input ? replace_partial_sigs(partial_sigs, &input->partial_sigs) : WALLY_EINVAL; } int wally_psbt_input_set_unknowns(struct wally_psbt_input *input, - struct wally_unknowns_map *unknowns) + const struct wally_unknowns_map *unknowns) { return input ? replace_unknowns(unknowns, &input->unknowns) : WALLY_EINVAL; } @@ -543,7 +543,7 @@ int wally_psbt_elements_input_set_value(struct wally_psbt_input *input, uint64_t } int wally_psbt_elements_input_set_value_blinder(struct wally_psbt_input *input, - unsigned char *value_blinder, + const unsigned char *value_blinder, size_t value_blinder_len) { if (!input) @@ -553,7 +553,7 @@ int wally_psbt_elements_input_set_value_blinder(struct wally_psbt_input *input, } int wally_psbt_elements_input_set_asset(struct wally_psbt_input *input, - unsigned char *asset, size_t asset_len) + const unsigned char *asset, size_t asset_len) { if (!input) return WALLY_EINVAL; @@ -561,7 +561,7 @@ int wally_psbt_elements_input_set_asset(struct wally_psbt_input *input, } int wally_psbt_elements_input_set_asset_blinder(struct wally_psbt_input *input, - unsigned char *asset_blinder, + const unsigned char *asset_blinder, size_t asset_blinder_len) { if (!input) @@ -571,7 +571,7 @@ int wally_psbt_elements_input_set_asset_blinder(struct wally_psbt_input *input, } int wally_psbt_elements_input_set_peg_in_tx(struct wally_psbt_input *input, - struct wally_tx *peg_in_tx) + const struct wally_tx *peg_in_tx) { int ret = WALLY_OK; struct wally_tx *new_tx; @@ -587,7 +587,7 @@ int wally_psbt_elements_input_set_peg_in_tx(struct wally_psbt_input *input, } int wally_psbt_elements_input_set_txout_proof(struct wally_psbt_input *input, - unsigned char *txout_proof, + const unsigned char *txout_proof, size_t txout_proof_len) { if (!input) @@ -597,7 +597,7 @@ int wally_psbt_elements_input_set_txout_proof(struct wally_psbt_input *input, } int wally_psbt_elements_input_set_genesis_hash(struct wally_psbt_input *input, - unsigned char *genesis_hash, + const unsigned char *genesis_hash, size_t genesis_hash_len) { if (!input) @@ -607,7 +607,7 @@ int wally_psbt_elements_input_set_genesis_hash(struct wally_psbt_input *input, } int wally_psbt_elements_input_set_claim_script(struct wally_psbt_input *input, - unsigned char *claim_script, + const unsigned char *claim_script, size_t claim_script_len) { if (!input) @@ -652,10 +652,10 @@ int wally_psbt_input_free(struct wally_psbt_input *input) return psbt_input_free(input, true); } -int wally_psbt_output_init_alloc(unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, +int wally_psbt_output_init_alloc(const unsigned char *redeem_script, size_t redeem_script_len, + const unsigned char *witness_script, size_t witness_script_len, + const struct wally_keypath_map *keypaths, + const struct wally_unknowns_map *unknowns, struct wally_psbt_output **output) { struct wally_psbt_output *result; @@ -682,18 +682,18 @@ int wally_psbt_output_init_alloc(unsigned char *redeem_script, size_t redeem_scr } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_output_init_alloc(unsigned char *redeem_script, size_t redeem_script_len, - unsigned char *witness_script, size_t witness_script_len, - struct wally_keypath_map *keypaths, - struct wally_unknowns_map *unknowns, - unsigned char *blinding_pubkey, size_t blinding_pubkey_len, - unsigned char *value_commitment, size_t value_commitment_len, - unsigned char *value_blinder, size_t value_blinder_len, - unsigned char *asset_commitment, size_t asset_commitment_len, - unsigned char *asset_blinder, size_t asset_blinder_len, - unsigned char *nonce_commitment, size_t nonce_commitment_len, - unsigned char *range_proof, size_t range_proof_len, - unsigned char *surjection_proof, size_t surjection_proof_len, +int wally_psbt_elements_output_init_alloc(const unsigned char *redeem_script, size_t redeem_script_len, + const unsigned char *witness_script, size_t witness_script_len, + const struct wally_keypath_map *keypaths, + const struct wally_unknowns_map *unknowns, + const unsigned char *blinding_pubkey, size_t blinding_pubkey_len, + const unsigned char *value_commitment, size_t value_commitment_len, + const unsigned char *value_blinder, size_t value_blinder_len, + const unsigned char *asset_commitment, size_t asset_commitment_len, + const unsigned char *asset_blinder, size_t asset_blinder_len, + const unsigned char *nonce_commitment, size_t nonce_commitment_len, + const unsigned char *range_proof, size_t range_proof_len, + const unsigned char *surjection_proof, size_t surjection_proof_len, struct wally_psbt_output **output) { struct wally_psbt_output *result; @@ -733,7 +733,7 @@ int wally_psbt_elements_output_init_alloc(unsigned char *redeem_script, size_t r #endif /* BUILD_ELEMENTS */ int wally_psbt_output_set_redeem_script(struct wally_psbt_output *output, - unsigned char *redeem_script, + const unsigned char *redeem_script, size_t redeem_script_len) { if (!output) @@ -743,7 +743,7 @@ int wally_psbt_output_set_redeem_script(struct wally_psbt_output *output, } int wally_psbt_output_set_witness_script(struct wally_psbt_output *output, - unsigned char *witness_script, + const unsigned char *witness_script, size_t witness_script_len) { if (!output) @@ -753,20 +753,20 @@ int wally_psbt_output_set_witness_script(struct wally_psbt_output *output, } int wally_psbt_output_set_keypaths(struct wally_psbt_output *output, - struct wally_keypath_map *keypaths) + const struct wally_keypath_map *keypaths) { return output ? replace_keypaths(keypaths, &output->keypaths) : WALLY_EINVAL; } int wally_psbt_output_set_unknowns(struct wally_psbt_output *output, - struct wally_unknowns_map *unknowns) + const struct wally_unknowns_map *unknowns) { return output ? replace_unknowns(unknowns, &output->unknowns) : WALLY_EINVAL; } #ifdef BUILD_ELEMENTS int wally_psbt_elements_output_set_blinding_pubkey(struct wally_psbt_output *output, - unsigned char *blinding_pubkey, + const unsigned char *blinding_pubkey, size_t blinding_pubkey_len) { if (!output || !is_valid_optional_pubkey_len(blinding_pubkey_len)) @@ -776,7 +776,7 @@ int wally_psbt_elements_output_set_blinding_pubkey(struct wally_psbt_output *out } int wally_psbt_elements_output_set_value_commitment(struct wally_psbt_output *output, - unsigned char *value_commitment, + const unsigned char *value_commitment, size_t value_commitment_len) { if (!output) @@ -786,7 +786,7 @@ int wally_psbt_elements_output_set_value_commitment(struct wally_psbt_output *ou } int wally_psbt_elements_output_set_value_blinder(struct wally_psbt_output *output, - unsigned char *value_blinder, + const unsigned char *value_blinder, size_t value_blinder_len) { if (!output) @@ -796,7 +796,7 @@ int wally_psbt_elements_output_set_value_blinder(struct wally_psbt_output *outpu } int wally_psbt_elements_output_set_asset_commitment(struct wally_psbt_output *output, - unsigned char *asset_commitment, + const unsigned char *asset_commitment, size_t asset_commitment_len) { if (!output) @@ -806,7 +806,7 @@ int wally_psbt_elements_output_set_asset_commitment(struct wally_psbt_output *ou } int wally_psbt_elements_output_set_asset_blinder(struct wally_psbt_output *output, - unsigned char *asset_blinder, + const unsigned char *asset_blinder, size_t asset_blinder_len) { if (!output) @@ -816,7 +816,7 @@ int wally_psbt_elements_output_set_asset_blinder(struct wally_psbt_output *outpu } int wally_psbt_elements_output_set_nonce_commitment(struct wally_psbt_output *output, - unsigned char *nonce_commitment, + const unsigned char *nonce_commitment, size_t nonce_commitment_len) { if (!output) @@ -826,7 +826,7 @@ int wally_psbt_elements_output_set_nonce_commitment(struct wally_psbt_output *ou } int wally_psbt_elements_output_set_range_proof(struct wally_psbt_output *output, - unsigned char *range_proof, + const unsigned char *range_proof, size_t range_proof_len) { if (!output) @@ -836,7 +836,7 @@ int wally_psbt_elements_output_set_range_proof(struct wally_psbt_output *output, } int wally_psbt_elements_output_set_surjection_proof(struct wally_psbt_output *output, - unsigned char *surjection_proof, + const unsigned char *surjection_proof, size_t surjection_proof_len) { if (!output) @@ -992,9 +992,9 @@ static int psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx, bool return WALLY_OK; } -int wally_psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx) +int wally_psbt_set_global_tx(struct wally_psbt *psbt, const struct wally_tx *tx) { - return psbt_set_global_tx(psbt, tx, true); + return psbt_set_global_tx(psbt, (struct wally_tx *)tx, true); } /* Returns false if it hits a zero length "key" (i.e. separator) or EOF. @@ -2427,7 +2427,7 @@ int wally_psbt_from_base64(const char *string, struct wally_psbt **output) return ret; } -int wally_psbt_to_base64(struct wally_psbt *psbt, char **output) +int wally_psbt_to_base64(const struct wally_psbt *psbt, char **output) { unsigned char *buff; char *result = NULL; From 44fee6c62c2788c9a53d65f5e80e5df7619ad9d5 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Sun, 12 Jul 2020 21:10:56 +1200 Subject: [PATCH 145/205] psbt: Don't use C++ stdlib types for parameter names --- include/wally_psbt.h | 6 +++--- src/psbt.c | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 1e4964a16..41bfdca6c 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -594,18 +594,18 @@ WALLY_CORE_API int wally_psbt_to_bytes( /** * Create a PSBT from its serialized base64 string. * - * :param string: Base64 string to create the PSBT from. + * :param base64: Base64 string to create the PSBT from. * :param output: Destination for the resulting PSBT. */ WALLY_CORE_API int wally_psbt_from_base64( - const char *string, + const char *base64, struct wally_psbt **output); /** * Serialize a PSBT to a base64 string. * * :param psbt: the PSBT to serialize. - * :param output: Destination for the resulting PSBT. + * :param output: Destination for the resulting serialized PSBT. */ WALLY_CORE_API int wally_psbt_to_base64( const struct wally_psbt *psbt, diff --git a/src/psbt.c b/src/psbt.c index a4b9d0145..6c5911022 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2393,27 +2393,27 @@ int wally_psbt_to_bytes(const struct wally_psbt *psbt, return WALLY_OK; } -int wally_psbt_from_base64(const char *string, struct wally_psbt **output) +int wally_psbt_from_base64(const char *base64, struct wally_psbt **output) { char *decoded; - size_t safe_len, string_len; + size_t safe_len, base64_len; ssize_t decoded_len; int ret; TX_CHECK_OUTPUT; - if (!string) + if (!base64) return WALLY_EINVAL; - string_len = strlen(string); + base64_len = strlen(base64); /* Allocate the decoded buffer */ - safe_len = base64_decoded_length(string_len); + safe_len = base64_decoded_length(base64_len); if ((decoded = wally_malloc(safe_len)) == NULL) { ret = WALLY_ENOMEM; goto done; } /* Decode the base64 psbt */ - decoded_len = base64_decode(decoded, safe_len, string, string_len); + decoded_len = base64_decode(decoded, safe_len, base64, base64_len); if (decoded_len <= (ssize_t)sizeof(WALLY_PSBT_MAGIC)) { ret = WALLY_EINVAL; /* Not enough bytes for the magic */ goto done; From 5f1b62b066001092353f69a1f7748aabc0eb40de Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 00:03:23 +1200 Subject: [PATCH 146/205] psbt: Use the same parameter names as other calls for consistency --- include/wally_psbt.h | 12 ++++++------ src/psbt.c | 30 +++++++++++++++--------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 41bfdca6c..008b4819b 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -188,11 +188,11 @@ struct wally_psbt { /** * Allocate and initialize a new keypath map. * - * :param alloc_len: The number of items to allocate. + * :param allocation_len: The number of items to allocate. * :param output: Destination for the new keypath map. */ WALLY_CORE_API int wally_keypath_map_init_alloc( - size_t alloc_len, + size_t allocation_len, struct wally_keypath_map **output); #ifndef SWIG_PYTHON @@ -228,11 +228,11 @@ WALLY_CORE_API int wally_keypath_map_add( /** * Allocate and initialize a new partial sigs map. * - * :param alloc_len: The number of items to allocate. + * :param allocation_len: The number of items to allocate. * :param output: Destination for the new partial sigs map. */ WALLY_CORE_API int wally_partial_sigs_map_init_alloc( - size_t alloc_len, + size_t allocation_len, struct wally_partial_sigs_map **output); #ifndef SWIG_PYTHON @@ -264,11 +264,11 @@ WALLY_CORE_API int wally_partial_sigs_map_add( /** * Allocate and initialize a new unknowns map. * - * :param alloc_len: The number of items to allocate. + * :param allocation_len: The number of items to allocate. * :param output: Destination for the new unknowns map. */ WALLY_CORE_API int wally_unknowns_map_init_alloc( - size_t alloc_len, + size_t allocation_len, struct wally_unknowns_map **output); #ifndef SWIG_PYTHON diff --git a/src/psbt.c b/src/psbt.c index 6c5911022..9559e4a85 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -35,23 +35,23 @@ static bool is_valid_optional_pubkey_len(size_t len) return !len || is_valid_pubkey_len(len); } -int wally_keypath_map_init_alloc(size_t alloc_len, struct wally_keypath_map **output) +int wally_keypath_map_init_alloc(size_t allocation_len, struct wally_keypath_map **output) { struct wally_keypath_map *result; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_keypath_map); - if (alloc_len) { - result->items = wally_malloc(alloc_len * sizeof(*result->items)); + if (allocation_len) { + result->items = wally_malloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, alloc_len * sizeof(*result->items)); + wally_clear(result->items, allocation_len * sizeof(*result->items)); } - result->items_allocation_len = alloc_len; + result->items_allocation_len = allocation_len; result->num_items = 0; return WALLY_OK; } @@ -145,23 +145,23 @@ int wally_keypath_map_add(struct wally_keypath_map *keypaths, return ret; } -int wally_partial_sigs_map_init_alloc(size_t alloc_len, struct wally_partial_sigs_map **output) +int wally_partial_sigs_map_init_alloc(size_t allocation_len, struct wally_partial_sigs_map **output) { struct wally_partial_sigs_map *result; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_partial_sigs_map); - if (alloc_len) { - result->items = wally_malloc(alloc_len * sizeof(*result->items)); + if (allocation_len) { + result->items = wally_malloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, alloc_len * sizeof(*result->items)); + wally_clear(result->items, allocation_len * sizeof(*result->items)); } - result->items_allocation_len = alloc_len; + result->items_allocation_len = allocation_len; result->num_items = 0; return WALLY_OK; } @@ -232,23 +232,23 @@ int wally_partial_sigs_map_add(struct wally_partial_sigs_map *sigs, return ret; } -int wally_unknowns_map_init_alloc(size_t alloc_len, struct wally_unknowns_map **output) +int wally_unknowns_map_init_alloc(size_t allocation_len, struct wally_unknowns_map **output) { struct wally_unknowns_map *result; TX_CHECK_OUTPUT; TX_OUTPUT_ALLOC(struct wally_unknowns_map); - if (alloc_len) { - result->items = wally_malloc(alloc_len * sizeof(*result->items)); + if (allocation_len) { + result->items = wally_malloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, alloc_len * sizeof(*result->items)); + wally_clear(result->items, allocation_len * sizeof(*result->items)); } - result->items_allocation_len = alloc_len; + result->items_allocation_len = allocation_len; result->num_items = 0; return WALLY_OK; } From bbcc4f85c9f5aea409432cf8fd3bc684541e2fde Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 11:14:40 +1200 Subject: [PATCH 147/205] psbt: Expose functions to C++ --- include/wally.hpp | 120 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 108 insertions(+), 12 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 9eff4922c..e1f133316 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -57,6 +58,14 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(i321, out); \ } +#define WALLY_FN_S_A(F, N) template inline int F(size_t s1, O * *out) { \ + return ::N(s1, out); \ +} + +#define WALLY_FN_SSS_A(F, N) template inline int F(size_t s1, size_t s2, size_t s3, O * *out) { \ + return ::N(s1, s2, s3, out); \ +} + #define WALLY_FN_6_B(F, N) template inline int F(uint64_t i641, O & out) { \ return ::N(i641, WALLYO(out)); \ } @@ -180,6 +189,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i321); \ } +#define WALLY_FN_P6(F, N) template inline int F(const P1 &p1, uint64_t i641) { \ + return ::N(WALLYP(p1), i641); \ +} + #define WALLY_FN_P33(F, N) template inline int F(const P1 &p1, uint32_t i321, uint32_t i322) { \ return ::N(WALLYP(p1), i321, i322); \ } @@ -242,6 +255,14 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), WALLYB(i1)); \ } +#define WALLY_FN_PBB(F, N) template \ + inline int F(const P1 &p1, const I1 &i1, const I2 &i2) { return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2)); } + +#define WALLY_FN_PBBB(F, N) template \ + inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const I3 &i3) { \ + return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYB(i3)); \ +} + #define WALLY_FN_PBBBBB(F, N) template \ inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5) { \ return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5)); \ @@ -284,6 +305,11 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), WALLYB(i1), out); \ } +#define WALLY_FN_PBBPP_A(F, N) template \ + inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const P2 &p2, const P3 &p3, O * *out) { \ + return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYP(p2), WALLYP(p3), out); \ +} + #define WALLY_FN_PP(F, N) template inline int F(const P1 &p1, const P2 &p2) { \ return ::N(WALLYP(p1), WALLYP(p2)); \ } @@ -294,6 +320,12 @@ template <> inline auto get_p(const std::nullptr_t& p) { return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ } +#define WALLY_FN_PPBBBPPPP3_A(F, N) template \ + inline int F(const P1 &p1, const P2 &p2, const I1 &i1, const I2 &i2, const I3 &i3, \ + const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, uint32_t i321, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYP(p3), WALLYP(p4), WALLYP(p5), WALLYP(p6), i321, out); \ +} + #define WALLY_FN_PP_BS(F, N) template inline int F(const P1 &p1, const P2 &p2, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), WALLYP(p2), WALLYO(out), written ? written : &n); \ @@ -347,6 +379,10 @@ WALLY_FN_3(cleanup, wally_cleanup) WALLY_FN_333_BBBBBA(bip32_key_init_alloc, bip32_key_init_alloc) WALLY_FN_33SS_A(tx_init_alloc, wally_tx_init_alloc) WALLY_FN_3_A(tx_witness_stack_init_alloc, wally_tx_witness_stack_init_alloc) +WALLY_FN_S_A(keypath_map_init_alloc, wally_keypath_map_init_alloc) +WALLY_FN_S_A(partial_sigs_map_init_alloc, wally_partial_sigs_map_init_alloc) +WALLY_FN_S_A(unknowns_map_init_alloc, wally_unknowns_map_init_alloc) +WALLY_FN_SSS_A(psbt_init_alloc, wally_psbt_init_alloc) WALLY_FN_6B_A(tx_output_init_alloc, wally_tx_output_init_alloc) WALLY_FN_B(ec_private_key_verify, wally_ec_private_key_verify) WALLY_FN_B(ec_public_key_verify, wally_ec_public_key_verify) @@ -383,6 +419,7 @@ WALLY_FN_BP3_A(addr_segwit_from_bytes, wally_addr_segwit_from_bytes) WALLY_FN_BB_BS(scriptsig_p2pkh_from_der, wally_scriptsig_p2pkh_from_der) WALLY_FN_B_A(bip32_key_unserialize_alloc, bip32_key_unserialize_alloc) WALLY_FN_B_A(hex_from_bytes, wally_hex_from_bytes) +WALLY_FN_B_A(psbt_from_bytes, wally_psbt_from_bytes) WALLY_FN_B_B(ec_public_key_decompress, wally_ec_public_key_decompress) WALLY_FN_B_B(ec_public_key_from_private_key, wally_ec_public_key_from_private_key) WALLY_FN_B_B(ec_sig_from_der, wally_ec_sig_from_der) @@ -399,11 +436,18 @@ WALLY_FN_BB33_B(pbkdf2_hmac_sha512, wally_pbkdf2_hmac_sha512) WALLY_FN_P(bip32_key_free, bip32_key_free) WALLY_FN_P(bip32_key_strip_private_key, bip32_key_strip_private_key) WALLY_FN_P(get_operations, wally_get_operations) +WALLY_FN_P(keypath_map_free, wally_keypath_map_free) +WALLY_FN_P(partial_sigs_map_free, wally_partial_sigs_map_free) +WALLY_FN_P(psbt_free, wally_psbt_free) +WALLY_FN_P(psbt_input_free, wally_psbt_input_free) +WALLY_FN_P(psbt_output_free, wally_psbt_output_free) WALLY_FN_P(set_operations, wally_set_operations) WALLY_FN_P(tx_free, wally_tx_free) WALLY_FN_P(tx_input_free, wally_tx_input_free) WALLY_FN_P(tx_output_free, wally_tx_output_free) WALLY_FN_P(tx_witness_stack_free, wally_tx_witness_stack_free) +WALLY_FN_P(unknowns_map_free, wally_unknowns_map_free) +WALLY_FN_P3(psbt_input_set_sighash_type, wally_psbt_input_set_sighash_type) WALLY_FN_P3(tx_witness_stack_add_dummy, wally_tx_witness_stack_add_dummy) WALLY_FN_P3(tx_witness_stack_set_dummy, wally_tx_witness_stack_set_dummy) WALLY_FN_P33_P(bip32_key_from_parent, bip32_key_from_parent) @@ -423,16 +467,28 @@ WALLY_FN_P3_S(tx_get_length, wally_tx_get_length) WALLY_FN_P33_A(scriptpubkey_to_address, wally_scriptpubkey_to_address) WALLY_FN_P33_A(wif_to_address, wally_wif_to_address) WALLY_FN_P6B3(tx_add_raw_output, wally_tx_add_raw_output) +WALLY_FN_PB(psbt_input_set_redeem_script, wally_psbt_input_set_redeem_script) +WALLY_FN_PB(psbt_input_set_witness_script, wally_psbt_input_set_witness_script) +WALLY_FN_PB(psbt_input_set_final_script_sig, wally_psbt_input_set_final_script_sig) +WALLY_FN_PB(psbt_output_set_redeem_script, wally_psbt_output_set_redeem_script) +WALLY_FN_PB(psbt_output_set_witness_script, wally_psbt_output_set_witness_script) +WALLY_FN_PB(psbt_sign, wally_psbt_sign) WALLY_FN_PB(tx_witness_stack_add, wally_tx_witness_stack_add) WALLY_FN_PB33BP3(tx_add_raw_input, wally_tx_add_raw_input) +WALLY_FN_PBB(partial_sigs_map_add, wally_partial_sigs_map_add) +WALLY_FN_PBB(unknowns_map_add, wally_unknowns_map_add) +WALLY_FN_PBBB(keypath_map_add, wally_keypath_map_add) +WALLY_FN_PBBPP_A(psbt_output_init_alloc, wally_psbt_output_init_alloc) WALLY_FN_PB3_A(bip32_key_from_parent_path_alloc, bip32_key_from_parent_path_alloc) WALLY_FN_PB3_B(bip38_to_private_key, bip38_to_private_key) WALLY_FN_PB3_P(bip32_key_from_parent_path, bip32_key_from_parent_path) WALLY_FN_PB_A(bip39_mnemonic_from_bytes, bip39_mnemonic_from_bytes) +WALLY_FN_PB_A(psbt_combine, wally_psbt_combine) WALLY_FN_PP(bip39_mnemonic_validate, bip39_mnemonic_validate) WALLY_FN_PP(tx_add_input, wally_tx_add_input) WALLY_FN_PP(tx_add_output, wally_tx_add_output) WALLY_FN_PP3_BS(addr_segwit_to_bytes, wally_addr_segwit_to_bytes) +WALLY_FN_PPBBBPPPP3_A(psbt_input_init_alloc, wally_psbt_input_init_alloc) WALLY_FN_PP_BS(bip39_mnemonic_to_bytes, bip39_mnemonic_to_bytes) WALLY_FN_PP_BS(bip39_mnemonic_to_seed, bip39_mnemonic_to_seed) WALLY_FN_PS(tx_remove_input, wally_tx_remove_input) @@ -443,18 +499,34 @@ WALLY_FN_PS_A(bip39_get_word, bip39_get_word) WALLY_FN_P_A(bip32_key_from_base58_alloc, bip32_key_from_base58_alloc) WALLY_FN_P_A(bip39_get_languages, bip39_get_languages) WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) +WALLY_FN_P_A(psbt_extract, wally_psbt_extract) +WALLY_FN_P_A(psbt_from_base64, wally_psbt_from_base64) +WALLY_FN_P_A(psbt_to_base64, wally_psbt_to_base64) WALLY_FN_P_A(tx_output_clone_alloc, wally_tx_output_clone_alloc) WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) WALLY_FN_P_B(tx_get_txid, wally_tx_get_txid) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) +WALLY_FN_P_BS(psbt_to_bytes, wally_psbt_to_bytes) WALLY_FN_P_S(base58_get_length, wally_base58_get_length) -WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) +WALLY_FN_P_S(psbt_get_length, wally_psbt_get_length) +WALLY_FN_P_S(psbt_is_elements, wally_psbt_is_elements) WALLY_FN_P_S(tx_get_vsize, wally_tx_get_vsize) WALLY_FN_P_S(tx_get_weight, wally_tx_get_weight) WALLY_FN_P_S(tx_get_witness_count, wally_tx_get_witness_count) +WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) WALLY_FN_P_P(bip32_key_from_base58, bip32_key_from_base58) -WALLY_FN_P_P(tx_output_clone, wally_tx_output_clone) +WALLY_FN_P_P(psbt_input_set_final_witness, wally_psbt_input_set_final_witness) +WALLY_FN_P_P(psbt_input_set_keypaths, wally_psbt_input_set_keypaths) +WALLY_FN_P_P(psbt_input_set_non_witness_utxo, wally_psbt_input_set_non_witness_utxo) +WALLY_FN_P_P(psbt_input_set_partial_sigs, wally_psbt_input_set_partial_sigs) +WALLY_FN_P_P(psbt_input_set_unknowns, wally_psbt_input_set_unknowns) +WALLY_FN_P_P(psbt_input_set_witness_utxo, wally_psbt_input_set_witness_utxo) +WALLY_FN_P_P(psbt_output_set_keypaths, wally_psbt_output_set_keypaths) +WALLY_FN_P_P(psbt_output_set_unknowns, wally_psbt_output_set_unknowns) +WALLY_FN_P_P(psbt_set_global_tx, wally_psbt_set_global_tx) WALLY_FN_P_P(tx_get_total_output_satoshi, wally_tx_get_total_output_satoshi) +WALLY_FN_P_P(tx_output_clone, wally_tx_output_clone) + WALLY_FN_S_S(tx_vsize_from_weight, wally_tx_vsize_from_weight) inline struct secp256k1_context_struct *get_secp_context() { @@ -481,22 +553,46 @@ inline bool is_elements_build() } #ifdef BUILD_ELEMENTS -WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) -WALLY_FN_P(tx_elements_input_issuance_free, wally_tx_elements_input_issuance_free) -WALLY_FN_B33BPBBBBBB_A(tx_elements_input_init_alloc, wally_tx_elements_input_init_alloc) -WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_commitment_set) -WALLY_FN_P(tx_elements_output_commitment_free, wally_tx_elements_output_commitment_free) WALLY_FN_6BBBBBB_A(tx_elements_output_init_alloc, wally_tx_elements_output_init_alloc) -WALLY_FN_PB33BPBBBBBB3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) -WALLY_FN_P6BBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) -WALLY_FN_P_S(tx_is_elements, wally_tx_is_elements) WALLY_FN_6_B(tx_confidential_value_from_satoshi, wally_tx_confidential_value_from_satoshi) -WALLY_FN_P6BB33_B(tx_get_elements_signature_hash, wally_tx_get_elements_signature_hash) +WALLY_FN_B33BPBBBBBB_A(tx_elements_input_init_alloc, wally_tx_elements_input_init_alloc) WALLY_FN_B3B_B(tx_elements_issuance_generate_entropy, wally_tx_elements_issuance_generate_entropy) -WALLY_FN_B_B(tx_elements_issuance_calculate_asset, wally_tx_elements_issuance_calculate_asset) WALLY_FN_B3_B(tx_elements_issuance_calculate_reissuance_token, wally_tx_elements_issuance_calculate_reissuance_token) +WALLY_FN_B_B(tx_elements_issuance_calculate_asset, wally_tx_elements_issuance_calculate_asset) +WALLY_FN_P(psbt_finalize, wally_psbt_finalize) +WALLY_FN_P(tx_elements_input_issuance_free, wally_tx_elements_input_issuance_free) +WALLY_FN_P(tx_elements_output_commitment_free, wally_tx_elements_output_commitment_free) +WALLY_FN_P6BB33_B(tx_get_elements_signature_hash, wally_tx_get_elements_signature_hash) +WALLY_FN_P6BBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) +WALLY_FN_PB33BPBBBBBB3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) +WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_commitment_set) +WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) +WALLY_FN_P_S(tx_is_elements, wally_tx_is_elements) +WALLY_FN_P_P(psbt_elements_input_set_peg_in_tx, wally_psbt_elements_input_set_peg_in_tx) +WALLY_FN_PB(psbt_elements_input_set_value_blinder, wally_psbt_elements_input_set_value_blinder) +WALLY_FN_PB(psbt_elements_input_set_asset, wally_psbt_elements_input_set_asset) +WALLY_FN_PB(psbt_elements_input_set_asset_blinder, wally_psbt_elements_input_set_asset_blinder) +WALLY_FN_PB(psbt_elements_input_set_txout_proof, wally_psbt_elements_input_set_txout_proof) +WALLY_FN_PB(psbt_elements_input_set_genesis_hash, wally_psbt_elements_input_set_genesis_hash) +WALLY_FN_PB(psbt_elements_input_set_claim_script, wally_psbt_elements_input_set_claim_script) +WALLY_FN_PB(psbt_elements_output_set_blinding_pubkey, wally_psbt_elements_output_set_blinding_pubkey) +WALLY_FN_PB(psbt_elements_output_set_value_commitment, wally_psbt_elements_output_set_value_commitment) +WALLY_FN_PB(psbt_elements_output_set_value_blinder, wally_psbt_elements_output_set_value_blinder) +WALLY_FN_PB(psbt_elements_output_set_asset_commitment, wally_psbt_elements_output_set_asset_commitment) +WALLY_FN_PB(psbt_elements_output_set_asset_blinder, wally_psbt_elements_output_set_asset_blinder) +WALLY_FN_PB(psbt_elements_output_set_nonce_commitment, wally_psbt_elements_output_set_nonce_commitment) +WALLY_FN_PB(psbt_elements_output_set_range_proof, wally_psbt_elements_output_set_range_proof) +WALLY_FN_PB(psbt_elements_output_set_surjection_proof, wally_psbt_elements_output_set_surjection_proof) +WALLY_FN_P6(psbt_elements_input_set_value, wally_psbt_elements_input_set_value) +WALLY_FN_SSS_A(psbt_elements_init_alloc, wally_psbt_elements_init_alloc) +#if 0 +// TODO: Perhaps these functions should be simplified, 19 i& 12 parameters seems a bit much +(psbt_elements_input_init_alloc, wally_psbt_elements_input_init_alloc) +(psbt_elements_output_init_alloc, wally_psbt_elements_output_init_alloc) +#endif #endif /* BUILD_ELEMENTS */ +#undef WALLYP #undef WALLYB #undef WALLYO From ef20e844531bc157aa5cf0b4588e2dc910adcd4a Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 11:37:18 +1200 Subject: [PATCH 148/205] psbt: Add flags to serialisation calls for future use --- CHANGES.md | 2 ++ include/wally.hpp | 6 +++--- include/wally_psbt.h | 6 ++++++ src/ctest/test_psbt.c | 6 +++--- src/ctest/test_psbt_limits.c | 4 ++-- src/psbt.c | 20 ++++++++++---------- src/test/test_psbt.py | 12 ++++++------ src/test/test_pset.py | 4 ++-- src/test/util.py | 6 +++--- 9 files changed, 37 insertions(+), 29 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 569f0af3d..9f1183f4f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ ## Version 0.7.9 +- psbt_to_bytes, psbt_get_length and psbt_to_base64 now take a flags argument. + - psbt_to_bytes no longer returns WALLY_EINVAL if the supplied buffer is too short. Please see the function documentation for details. diff --git a/include/wally.hpp b/include/wally.hpp index e1f133316..190264dd4 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -455,14 +455,17 @@ WALLY_FN_P3B(tx_witness_stack_set, wally_tx_witness_stack_set) WALLY_FN_P3B633_B(tx_get_btc_signature_hash, wally_tx_get_btc_signature_hash) WALLY_FN_P3BB36333_B(tx_get_signature_hash, wally_tx_get_signature_hash) WALLY_FN_P3_A(bip32_key_to_base58, bip32_key_to_base58) +WALLY_FN_P3_A(psbt_to_base64, wally_psbt_to_base64) WALLY_FN_P3_A(tx_clone, wally_tx_clone) WALLY_FN_P3_A(tx_from_hex, wally_tx_from_hex) WALLY_FN_P3_A(tx_to_hex, wally_tx_to_hex) WALLY_FN_P3_B(bip32_key_serialize, bip32_key_serialize) WALLY_FN_P3_B(wif_to_bytes, wally_wif_to_bytes) WALLY_FN_P3_BS(base58_to_bytes, wally_base58_to_bytes) +WALLY_FN_P3_BS(psbt_to_bytes, wally_psbt_to_bytes) WALLY_FN_P3_BS(tx_to_bytes, wally_tx_to_bytes) WALLY_FN_P3_BS(wif_to_public_key, wally_wif_to_public_key) +WALLY_FN_P3_S(psbt_get_length, wally_psbt_get_length) WALLY_FN_P3_S(tx_get_length, wally_tx_get_length) WALLY_FN_P33_A(scriptpubkey_to_address, wally_scriptpubkey_to_address) WALLY_FN_P33_A(wif_to_address, wally_wif_to_address) @@ -501,14 +504,11 @@ WALLY_FN_P_A(bip39_get_languages, bip39_get_languages) WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) WALLY_FN_P_A(psbt_extract, wally_psbt_extract) WALLY_FN_P_A(psbt_from_base64, wally_psbt_from_base64) -WALLY_FN_P_A(psbt_to_base64, wally_psbt_to_base64) WALLY_FN_P_A(tx_output_clone_alloc, wally_tx_output_clone_alloc) WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) WALLY_FN_P_B(tx_get_txid, wally_tx_get_txid) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) -WALLY_FN_P_BS(psbt_to_bytes, wally_psbt_to_bytes) WALLY_FN_P_S(base58_get_length, wally_base58_get_length) -WALLY_FN_P_S(psbt_get_length, wally_psbt_get_length) WALLY_FN_P_S(psbt_is_elements, wally_psbt_is_elements) WALLY_FN_P_S(tx_get_vsize, wally_tx_get_vsize) WALLY_FN_P_S(tx_get_weight, wally_tx_get_weight) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 008b4819b..bcaa2c8b8 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -571,22 +571,26 @@ WALLY_CORE_API int wally_psbt_from_bytes( * Get the length of a PSBT when serialized to bytes. * * :param psbt: the PSBT. + * :param flags: Flags controlling length determination. Must be 0. * :param written: Destination for the length in bytes when serialized. */ WALLY_CORE_API int wally_psbt_get_length( const struct wally_psbt *psbt, + uint32_t flags, size_t *written); /** * Serialize a PSBT to bytes. * * :param psbt: the PSBT to serialize. + * :param flags: Flags controlling serialization. Must be 0. * :param bytes_out: Bytes to create the transaction from. * :param len: Length of ``bytes`` in bytes (use `wally_psbt_get_length`). * :param written: number of bytes written to bytes_out. */ WALLY_CORE_API int wally_psbt_to_bytes( const struct wally_psbt *psbt, + uint32_t flags, unsigned char *bytes_out, size_t len, size_t *written); @@ -605,10 +609,12 @@ WALLY_CORE_API int wally_psbt_from_base64( * Serialize a PSBT to a base64 string. * * :param psbt: the PSBT to serialize. + * :param flags: Flags controlling serialization. Must be 0. * :param output: Destination for the resulting serialized PSBT. */ WALLY_CORE_API int wally_psbt_to_base64( const struct wally_psbt *psbt, + uint32_t flags, char **output); /** diff --git a/src/ctest/test_psbt.c b/src/ctest/test_psbt.c index f3a237523..8bac62ddb 100644 --- a/src/ctest/test_psbt.c +++ b/src/ctest/test_psbt.c @@ -30,7 +30,7 @@ int main(void) if (wally_psbt_from_base64(base64_in, &psbt) != WALLY_OK) errx(1, "Failed to parse psbt %s", base64_in); - if (wally_psbt_to_base64(psbt, &output) != WALLY_OK) + if (wally_psbt_to_base64(psbt, 0, &output) != WALLY_OK) errx(1, "Failed to base64 psbt %s", base64_in); if (strcmp(output, base64_in) != 0) @@ -38,11 +38,11 @@ int main(void) wally_free_string(output); - if (wally_psbt_get_length(psbt, &len) != WALLY_OK) + if (wally_psbt_get_length(psbt, 0, &len) != WALLY_OK) errx(1, "Failed to get psbt %s len", base64_in); bytes = malloc(len); - if (wally_psbt_to_bytes(psbt, bytes, len, &written) != WALLY_OK) + if (wally_psbt_to_bytes(psbt, 0, bytes, len, &written) != WALLY_OK) errx(1, "psbt %s could not to_bytes?", base64_in); if (len != written) { diff --git a/src/ctest/test_psbt_limits.c b/src/ctest/test_psbt_limits.c index 2a812feae..a73cfe560 100644 --- a/src/ctest/test_psbt_limits.c +++ b/src/ctest/test_psbt_limits.c @@ -78,12 +78,12 @@ static void test_psbt_write(const struct psbt_test *test, if (wally_psbt_from_base64(test->base64, &psbt) != WALLY_OK) abort(); - if (wally_psbt_get_length(psbt, &psbt_len) != WALLY_OK) + if (wally_psbt_get_length(psbt, 0, &psbt_len) != WALLY_OK) abort(); for (i = 0; i <= psbt_len; i++) { /* A too short buffer should return OK and the required length */ - if (wally_psbt_to_bytes(psbt, p + plen - i, i, &written) != WALLY_OK) { + if (wally_psbt_to_bytes(psbt, 0, p + plen - i, i, &written) != WALLY_OK) { errx(1, "wally_psbt_to_bytes should have suceeded"); } if (written != psbt_len) diff --git a/src/psbt.c b/src/psbt.c index 9559e4a85..a18dae438 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1980,9 +1980,9 @@ int wally_psbt_from_bytes(const unsigned char *bytes, size_t len, return ret; } -int wally_psbt_get_length(const struct wally_psbt *psbt, size_t *written) +int wally_psbt_get_length(const struct wally_psbt *psbt, uint32_t flags, size_t *written) { - return wally_psbt_to_bytes(psbt, NULL, 0, written); + return wally_psbt_to_bytes(psbt, flags, NULL, 0, written); } /* Literally a varbuff containing only type as a varint, then optional data */ @@ -2323,25 +2323,25 @@ static int push_psbt_output( return WALLY_OK; } -int wally_psbt_to_bytes(const struct wally_psbt *psbt, +int wally_psbt_to_bytes(const struct wally_psbt *psbt, uint32_t flags, unsigned char *bytes_out, size_t len, size_t *written) { unsigned char *cursor = bytes_out; size_t max = len, i, is_elements; - uint32_t flags; + uint32_t tx_flags; int ret; if (written) *written = 0; - if (!written) + if (flags != 0 || !written) return WALLY_EINVAL; if ((ret = wally_psbt_is_elements(psbt, &is_elements)) != WALLY_OK) return ret; - flags = is_elements ? WALLY_TX_FLAG_USE_ELEMENTS : 0; + tx_flags = is_elements ? WALLY_TX_FLAG_USE_ELEMENTS : 0; push_bytes(&cursor, &max, psbt->magic, sizeof(psbt->magic)); /* Global tx */ @@ -2370,7 +2370,7 @@ int wally_psbt_to_bytes(const struct wally_psbt *psbt, /* Push each input and output */ for (i = 0; i < psbt->num_inputs; ++i) { struct wally_psbt_input *input = &psbt->inputs[i]; - ret = push_psbt_input(&cursor, &max, flags, input); + ret = push_psbt_input(&cursor, &max, tx_flags, input); if (ret != WALLY_OK) { return ret; } @@ -2427,7 +2427,7 @@ int wally_psbt_from_base64(const char *base64, struct wally_psbt **output) return ret; } -int wally_psbt_to_base64(const struct wally_psbt *psbt, char **output) +int wally_psbt_to_base64(const struct wally_psbt *psbt, uint32_t flags, char **output) { unsigned char *buff; char *result = NULL; @@ -2438,14 +2438,14 @@ int wally_psbt_to_base64(const struct wally_psbt *psbt, char **output) if (!psbt) return WALLY_EINVAL; - if ((ret = wally_psbt_get_length(psbt, &len)) != WALLY_OK) + if ((ret = wally_psbt_get_length(psbt, flags, &len)) != WALLY_OK) return ret; if ((buff = wally_malloc(len)) == NULL) return WALLY_ENOMEM; /* Get psbt bytes */ - if ((ret = wally_psbt_to_bytes(psbt, buff, len, &written)) != WALLY_OK) + if ((ret = wally_psbt_to_bytes(psbt, flags, buff, len, &written)) != WALLY_OK) goto done; if (written != len) { diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index 1da19272d..3ed1316b2 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -24,10 +24,10 @@ def test_serialization(self): for valid in valids: psbt = pointer(wally_psbt()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(valid['psbt'].encode('utf-8'), psbt)) - ret, reser = wally_psbt_to_base64(psbt) + ret, reser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(valid['psbt'], reser) - ret, length = wally_psbt_get_length(psbt) + ret, length = wally_psbt_get_length(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(length, valid['len']) @@ -58,7 +58,7 @@ def test_serialization(self): # empty reserved ones for this test. psbt.contents.num_inputs = psbt.contents.tx.contents.num_inputs psbt.contents.num_outputs = psbt.contents.tx.contents.num_outputs - ret, ser = wally_psbt_to_base64(psbt) + ret, ser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(creator['result'], ser) @@ -70,7 +70,7 @@ def test_serialization(self): to_combine.append(psbt.contents) combined = pointer(wally_psbt()) self.assertEqual(WALLY_OK, wally_psbt_combine((wally_psbt * len(to_combine))(*to_combine), len(to_combine), combined)) - ret, comb_ser = wally_psbt_to_base64(combined) + ret, comb_ser = wally_psbt_to_base64(combined, 0) self.assertEqual(combiner['result'], comb_ser) for signer in signers: @@ -81,7 +81,7 @@ def test_serialization(self): self.assertEqual(WALLY_OK, wally_wif_to_bytes(priv.encode('utf-8'), 0xEF, 0, buf, buf_len)) self.assertEqual(WALLY_OK, wally_psbt_sign(psbt, buf, buf_len)) - ret, reser = wally_psbt_to_base64(psbt) + ret, reser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) # Check that we can *demarshal* the signed PSBT (some bugs only appear here) self.assertEqual(WALLY_OK, wally_psbt_from_base64(reser, psbt)) @@ -100,7 +100,7 @@ def test_serialization(self): psbt = pointer(wally_psbt()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(finalizer['finalize'].encode('utf-8'), psbt)) self.assertEqual(WALLY_OK, wally_psbt_finalize(psbt)) - ret, reser = wally_psbt_to_base64(psbt) + ret, reser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(finalizer['result'], reser) diff --git a/src/test/test_pset.py b/src/test/test_pset.py index b86300456..ed54d6569 100644 --- a/src/test/test_pset.py +++ b/src/test/test_pset.py @@ -14,10 +14,10 @@ def test_serialization(self): for valid in valids: psbt_out = pointer(wally_psbt()) self.assertEqual(WALLY_OK, wally_psbt_from_base64(utf8(valid['pset']), psbt_out)) - ret, b64 = wally_psbt_to_base64(psbt_out) + ret, b64 = wally_psbt_to_base64(psbt_out, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(valid['pset'], b64) - ret, length = wally_psbt_get_length(psbt_out) + ret, length = wally_psbt_get_length(psbt_out, 0) self.assertEqual(WALLY_OK, ret) self.assertEqual(length, valid['len']) diff --git a/src/test/util.py b/src/test/util.py index 2ce17c7d5..4ea434fde 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -356,10 +356,10 @@ class wally_psbt(Structure): ('wally_psbt_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_free', c_int, [POINTER(wally_psbt)]), ('wally_psbt_from_bytes', c_int, [c_void_p, c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_to_bytes', c_int, [POINTER(wally_psbt), c_void_p, c_ulong, c_ulong_p]), - ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_ulong_p]), + ('wally_psbt_to_bytes', c_int, [POINTER(wally_psbt), c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_uint, c_ulong_p]), ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_char_p_p]), + ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_uint32, c_char_p_p]), ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), ('wally_psbt_combine', c_int, [POINTER(wally_psbt), c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), From f7303ef69d98d0c439622bc802dae2da0852a163 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 13:29:31 +1200 Subject: [PATCH 149/205] pset: quick hack to create elements tx hash for signing based on a patch from niftynei. --- src/psbt.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index a18dae438..514972d54 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2752,19 +2752,20 @@ int wally_psbt_combine( return ret; } -int wally_psbt_sign( - struct wally_psbt *psbt, - const unsigned char *key, - size_t key_len) +int wally_psbt_sign(struct wally_psbt *psbt, + const unsigned char *key, size_t key_len) { unsigned char pubkey[EC_PUBLIC_KEY_LEN], uncomp_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN], sig[EC_SIGNATURE_LEN], der_sig[EC_SIGNATURE_DER_MAX_LEN + 1]; - size_t i, j, der_sig_len; + size_t i, j, der_sig_len, is_elements; int ret; if (!psbt || !psbt->tx || !key || key_len != EC_PRIVATE_KEY_LEN) { return WALLY_EINVAL; } + if ((ret = wally_psbt_is_elements(psbt, &is_elements)) != WALLY_OK) + return ret; + /* Get the pubkey */ if ((ret = wally_ec_public_key_from_private_key(key, key_len, pubkey, EC_PUBLIC_KEY_LEN)) != WALLY_OK) { return ret; @@ -2905,7 +2906,15 @@ int wally_psbt_sign( continue; } - if ((ret = wally_tx_get_btc_signature_hash(psbt->tx, i, scriptcode, scriptcode_len, input->witness_utxo->satoshi, sighash_type, WALLY_TX_FLAG_USE_WITNESS, sighash, SHA256_LEN)) != WALLY_OK) { + if (is_elements) { +#ifdef BUILD_ELEMENTS + if ((ret = wally_tx_get_elements_signature_hash(psbt->tx, i, scriptcode, scriptcode_len, input->witness_utxo->value, input->witness_utxo->value_len, sighash_type, WALLY_TX_FLAG_USE_WITNESS, sighash, SHA256_LEN)) != WALLY_OK) { + return ret; + } +#else + return WALLY_ERROR; +#endif /* BUILD_ELEMENTS */ + } else if ((ret = wally_tx_get_btc_signature_hash(psbt->tx, i, scriptcode, scriptcode_len, input->witness_utxo->satoshi, sighash_type, WALLY_TX_FLAG_USE_WITNESS, sighash, SHA256_LEN)) != WALLY_OK) { return ret; } } From 55ca566f4264a17314ce325862c182fa756a78f7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 21:19:29 +1200 Subject: [PATCH 150/205] psbt: Add find functions for psbt map types --- include/wally.hpp | 7 ++++ include/wally_psbt.h | 54 +++++++++++++++++++++++++--- src/psbt.c | 86 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 143 insertions(+), 4 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 190264dd4..a64e08a1e 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -305,6 +305,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), WALLYB(i1), out); \ } +#define WALLY_FN_PB_S(F, N) template inline int F(const P1 &p1, const I1 &i1, size_t * written) { \ + return ::N(WALLYP(p1), WALLYB(i1), written); \ +} + #define WALLY_FN_PBBPP_A(F, N) template \ inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const P2 &p2, const P3 &p3, O * *out) { \ return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYP(p2), WALLYP(p3), out); \ @@ -487,6 +491,9 @@ WALLY_FN_PB3_B(bip38_to_private_key, bip38_to_private_key) WALLY_FN_PB3_P(bip32_key_from_parent_path, bip32_key_from_parent_path) WALLY_FN_PB_A(bip39_mnemonic_from_bytes, bip39_mnemonic_from_bytes) WALLY_FN_PB_A(psbt_combine, wally_psbt_combine) +WALLY_FN_PB_S(keypath_map_find, wally_keypath_map_find) +WALLY_FN_PB_S(partial_sigs_map_find, wally_partial_sigs_map_find) +WALLY_FN_PB_S(unknowns_map_find, wally_unknowns_map_find) WALLY_FN_PP(bip39_mnemonic_validate, bip39_mnemonic_validate) WALLY_FN_PP(tx_add_input, wally_tx_add_input) WALLY_FN_PP(tx_add_output, wally_tx_add_output) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index bcaa2c8b8..95b54896e 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -64,7 +64,7 @@ struct wally_psbt_output; struct wally_psbt; #else -/** Key path, a BIP 32 path and fingerprint with associated pubkey */ +/** A BIP 32 path and fingerprint with associated public key */ struct wally_keypath_item { uint32_t *path; size_t path_len; @@ -79,14 +79,14 @@ struct wally_keypath_map { size_t items_allocation_len; }; -/** Item in partial signatures map */ +/** A signature with associated public key */ struct wally_partial_sigs_item { unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; unsigned char *sig; size_t sig_len; }; -/** A map of public key's to signatures */ +/** A map of public keys to signatures */ struct wally_partial_sigs_map { struct wally_partial_sigs_item *items; size_t num_items; @@ -101,7 +101,7 @@ struct wally_unknowns_item { size_t value_len; }; -/** Unknown items map */ +/** A map of unknown key,value pairs */ struct wally_unknowns_map { struct wally_unknowns_item *items; size_t num_items; @@ -205,6 +205,22 @@ WALLY_CORE_API int wally_keypath_map_free( struct wally_keypath_map *keypaths); #endif /* SWIG_PYTHON */ + +/** + * Find an item in a keypath map. + * + * :param keypaths: The keypath map to find ``pubkey`` in. + * :param pubkey: The pubkey to find. + * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param written: On success, set to zero if the item is not found, otherwise + *| the index of the item plus one. + */ +WALLY_CORE_API int wally_keypath_map_find( + const struct wally_keypath_map *keypaths, + const unsigned char *pubkey, + size_t pubkey_len, + size_t *written); + /** * Add an item to a keypath map. * @@ -245,6 +261,21 @@ WALLY_CORE_API int wally_partial_sigs_map_free( struct wally_partial_sigs_map *sigs); #endif /* SWIG_PYTHON */ +/** + * Find an item in a partial sigs map. + * + * :param sigs: The partial sigs map to find ``pubkey`` in. + * :param pubkey: The pubkey to find. + * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param written: On success, set to zero if the item is not found, otherwise + *| the index of the item plus one. + */ +WALLY_CORE_API int wally_partial_sigs_map_find( + const struct wally_partial_sigs_map *sigs, + const unsigned char *pubkey, + size_t pubkey_len, + size_t *written); + /** * Add an item to a partial sigs map. * @@ -281,6 +312,21 @@ WALLY_CORE_API int wally_unknowns_map_free( struct wally_unknowns_map *unknowns); #endif /* SWIG_PYTHON */ +/** + * Find an item in an unknowns map. + * + * :param unknowns: The unknowns map to find ``key`` in. + * :param key: The key to find. + * :param key_len: Length of ``key`` in bytes. + * :param written: On success, set to zero if the item is not found, otherwise + *| the index of the item plus one. + */ +WALLY_CORE_API int wally_unknowns_map_find( + const struct wally_unknowns_map *unknowns, + const unsigned char *key, + size_t key_len, + size_t *written); + /** * Add an item to an unknowns map. * diff --git a/src/psbt.c b/src/psbt.c index 514972d54..17453a43a 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -25,6 +25,13 @@ static bool pubkey_is_compressed(const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMP return pubkey[0] == 0x02 || pubkey[0] == 0x03; } +static size_t get_pubkey_len(const unsigned char *pubkey, size_t pubkey_len) +{ + if (!pubkey_len) + return 0; + return pubkey_is_compressed(pubkey) ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN; +} + static bool is_valid_pubkey_len(size_t len) { return len == EC_PUBLIC_KEY_UNCOMPRESSED_LEN || len == EC_PUBLIC_KEY_LEN; @@ -35,6 +42,14 @@ static bool is_valid_optional_pubkey_len(size_t len) return !len || is_valid_pubkey_len(len); } +static bool is_equal_pubkey(const unsigned char *l, size_t l_len, const unsigned char *r, size_t r_len) +{ + if (!l || !r) + return l == r; /* Equal if both NULL only */ + + return l_len == r_len && memcmp(l, r, l_len) == 0; +} + int wally_keypath_map_init_alloc(size_t allocation_len, struct wally_keypath_map **output) { struct wally_keypath_map *result; @@ -70,6 +85,30 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) return WALLY_OK; } +int wally_keypath_map_find(const struct wally_keypath_map *keypaths, + const unsigned char *pubkey, size_t pubkey_len, + size_t *written) +{ + size_t i; + + if (written) + *written = 0; + + if (!keypaths || !pubkey || !is_valid_pubkey_len(pubkey_len) || !written) + return WALLY_EINVAL; + + for (i = 0; i < keypaths->num_items; ++i) { + const struct wally_keypath_item *item = &keypaths->items[i]; + + if (is_equal_pubkey(pubkey, pubkey_len, + item->pubkey, get_pubkey_len(item->pubkey, sizeof(item->pubkey)))) { + *written = i + 1; /* Found */ + break; + } + } + return WALLY_OK; +} + static int add_keypath_item(struct wally_keypath_map *keypaths, const struct wally_keypath_item *item) { return wally_keypath_map_add(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, @@ -179,6 +218,30 @@ int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs) return WALLY_OK; } +int wally_partial_sigs_map_find(const struct wally_partial_sigs_map *partial_sigs, + const unsigned char *pubkey, size_t pubkey_len, + size_t *written) +{ + size_t i; + + if (written) + *written = 0; + + if (!partial_sigs || !pubkey || !is_valid_pubkey_len(pubkey_len) || !written) + return WALLY_EINVAL; + + for (i = 0; i < partial_sigs->num_items; ++i) { + const struct wally_partial_sigs_item *item = &partial_sigs->items[i]; + + if (is_equal_pubkey(pubkey, pubkey_len, + item->pubkey, get_pubkey_len(item->pubkey, sizeof(item->pubkey)))) { + *written = i + 1; /* Found */ + break; + } + } + return WALLY_OK; +} + static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, const struct wally_partial_sigs_item *item) { return wally_partial_sigs_map_add(sigs, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, @@ -268,6 +331,29 @@ int wally_unknowns_map_free(struct wally_unknowns_map *unknowns) return WALLY_OK; } +int wally_unknowns_map_find(const struct wally_unknowns_map *unknowns, + const unsigned char *key, size_t key_len, + size_t *written) +{ + size_t i; + + if (written) + *written = 0; + + if (!unknowns || !key || BYTES_INVALID(key, key_len) || !written) + return WALLY_EINVAL; + + for (i = 0; i < unknowns->num_items; ++i) { + const struct wally_unknowns_item *item = &unknowns->items[i]; + + if (key_len == item->key_len && memcmp(key, item->key, key_len) == 0) { + *written = i + 1; /* Found */ + break; + } + } + return WALLY_OK; +} + static int add_unknowns_item(struct wally_unknowns_map *unknowns, const struct wally_unknowns_item *item) { return wally_unknowns_map_add(unknowns, item->key, item->key_len, item->value, item->value_len); From ae8328384c4e2454610daaf4cfbfa96f443ce70f Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 21:31:47 +1200 Subject: [PATCH 151/205] psbt: ignore duplicate keys when adding to maps Regarding handling duplicated keys, BIP 174 states: Keys within each scope should never be duplicated; all keys in the format are unique. PSBTs containing duplicate keys are invalid. However implementors will still need to handle events where keys are duplicated when combining transactions with duplicated fields. In this event, the software may choose whichever value it wishes. If the caller wishes to return an error when adding duplicate keys, they should use the find functions to check for duplicates before adding values. --- src/psbt.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/psbt.c b/src/psbt.c index 17453a43a..958f74ca4 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -160,6 +160,7 @@ int wally_keypath_map_add(struct wally_keypath_map *keypaths, const unsigned char *fingerprint, size_t fingerprint_len, const uint32_t *path, size_t path_len) { + size_t is_found; int ret; if (!keypaths || !pubkey || !is_valid_pubkey_len(pubkey_len) || @@ -167,6 +168,10 @@ int wally_keypath_map_add(struct wally_keypath_map *keypaths, BYTES_INVALID(path, path_len)) return WALLY_EINVAL; + ret = wally_keypath_map_find(keypaths, pubkey, pubkey_len, &is_found); + if (ret != WALLY_OK || is_found) + return ret; /* Return WALLY_OK and do nothing if already present */ + ret = array_grow((void *)&keypaths->items, keypaths->num_items, &keypaths->items_allocation_len, sizeof(struct wally_keypath_item)); if (ret == WALLY_OK) { @@ -275,12 +280,17 @@ int wally_partial_sigs_map_add(struct wally_partial_sigs_map *sigs, const unsigned char *pubkey, size_t pubkey_len, const unsigned char *sig, size_t sig_len) { + size_t is_found; int ret; if (!sigs || !pubkey || !is_valid_pubkey_len(pubkey_len) || BYTES_INVALID(sig, sig_len)) return WALLY_EINVAL; + ret = wally_partial_sigs_map_find(sigs, pubkey, pubkey_len, &is_found); + if (ret != WALLY_OK || is_found) + return ret; /* Return WALLY_OK and do nothing if already present */ + ret = array_grow((void *)&sigs->items, sigs->num_items, &sigs->items_allocation_len, sizeof(struct wally_partial_sigs_item)); if (ret == WALLY_OK) { @@ -386,11 +396,16 @@ int wally_unknowns_map_add(struct wally_unknowns_map *unknowns, const unsigned char *key, size_t key_len, const unsigned char *value, size_t value_len) { + size_t is_found; int ret; if (!unknowns || !key || BYTES_INVALID(key, key_len) || BYTES_INVALID(value, value_len)) return WALLY_EINVAL; + ret = wally_unknowns_map_find(unknowns, key, key_len, &is_found); + if (ret != WALLY_OK || is_found) + return ret; /* Return WALLY_OK and do nothing if already present */ + ret = array_grow((void *)&unknowns->items, unknowns->num_items, &unknowns->items_allocation_len, sizeof(struct wally_unknowns_item)); if (ret == WALLY_OK) { From 49b702784056c68ed5e008b8575e2f68226dde14 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 21:55:41 +1200 Subject: [PATCH 152/205] psbt: Use find to prevent dupes when reading, add unknowns check --- src/psbt.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 958f74ca4..8a50b0356 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1148,22 +1148,21 @@ static int pull_keypath(const unsigned char **cursor, size_t *max, struct wally_keypath_map **keypaths) { const unsigned char *val; - size_t i, val_max; + size_t i, val_max, is_found; const unsigned char *fingerprint; int ret; if (!is_valid_pubkey_len(key_len)) return WALLY_EINVAL; - if (!*keypaths && wally_keypath_map_init_alloc(1, keypaths) != WALLY_OK) - return WALLY_ENOMEM; + if (!*keypaths && (ret = wally_keypath_map_init_alloc(1, keypaths)) != WALLY_OK) + return ret; - /* Check for duplicates */ - for (i = 0; i < (*keypaths)->num_items; ++i) { - if (memcmp((*keypaths)->items[i].pubkey, key, key_len) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } + ret = wally_keypath_map_find(*keypaths, key, key_len, &is_found); + if (ret == WALLY_OK && is_found) + ret = WALLY_EINVAL; /* Duplicates are invalid */ + if (ret != WALLY_OK) + return ret; pull_subfield_end(cursor, max, key, key_len); @@ -1197,7 +1196,8 @@ static int pull_partial_sig(const unsigned char **cursor, size_t *max, struct wally_partial_sigs_map **partial_sigs) { const unsigned char *val; - size_t val_len, i; + size_t val_len, is_found; + int ret; if (!is_valid_pubkey_len(key_len)) return WALLY_EINVAL; @@ -1205,12 +1205,11 @@ static int pull_partial_sig(const unsigned char **cursor, size_t *max, if (!*partial_sigs && wally_partial_sigs_map_init_alloc(1, partial_sigs) != WALLY_OK) return WALLY_ENOMEM; - /* Check for duplicates */ - for (i = 0; i < (*partial_sigs)->num_items; ++i) { - if (memcmp((*partial_sigs)->items[i].pubkey, key, key_len) == 0) { - return WALLY_EINVAL; /* Duplicate key */ - } - } + ret = wally_partial_sigs_map_find(*partial_sigs, key, key_len, &is_found); + if (ret == WALLY_OK && is_found) + ret = WALLY_EINVAL; /* Duplicates are invalid */ + if (ret != WALLY_OK) + return ret; pull_subfield_end(cursor, max, key, key_len); @@ -1227,7 +1226,8 @@ static int pull_unknown_key_value(const unsigned char **cursor, struct wally_unknowns_map **unknowns) { const unsigned char *key, *val; - size_t key_len, val_len; + size_t key_len, val_len, is_found; + int ret; /* If we've already failed, it's invalid */ if (!*cursor) @@ -1245,6 +1245,12 @@ static int pull_unknown_key_value(const unsigned char **cursor, val_len = pull_varlength(cursor, max); val = pull_skip(cursor, max, val_len); + ret = wally_unknowns_map_find(*unknowns, key, key_len, &is_found); + if (ret == WALLY_OK && is_found) + ret = WALLY_EINVAL; /* Duplicates are invalid */ + if (ret != WALLY_OK) + return ret; + return wally_unknowns_map_add(*unknowns, key, key_len, val, val_len); } From 4933da159f9f7e79cd80c273ea349780f864e8d7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 22:27:28 +1200 Subject: [PATCH 153/205] psbt: Use find to check for existing input signature when signing --- src/psbt.c | 36 +++++++++++++++++------------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 8a50b0356..8f7ebef93 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2862,7 +2862,9 @@ int wally_psbt_combine( int wally_psbt_sign(struct wally_psbt *psbt, const unsigned char *key, size_t key_len) { - unsigned char pubkey[EC_PUBLIC_KEY_LEN], uncomp_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN], sig[EC_SIGNATURE_LEN], der_sig[EC_SIGNATURE_DER_MAX_LEN + 1]; + unsigned char pubkey[EC_PUBLIC_KEY_LEN], full_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; + unsigned char sig[EC_SIGNATURE_LEN], der_sig[EC_SIGNATURE_DER_MAX_LEN + 1]; + const size_t pubkey_len = sizeof(pubkey), full_pubkey_len = sizeof(full_pubkey); size_t i, j, der_sig_len, is_elements; int ret; @@ -2874,10 +2876,10 @@ int wally_psbt_sign(struct wally_psbt *psbt, return ret; /* Get the pubkey */ - if ((ret = wally_ec_public_key_from_private_key(key, key_len, pubkey, EC_PUBLIC_KEY_LEN)) != WALLY_OK) { + if ((ret = wally_ec_public_key_from_private_key(key, key_len, pubkey, pubkey_len)) != WALLY_OK) { return ret; } - if ((ret = wally_ec_public_key_decompress(pubkey, EC_PUBLIC_KEY_LEN, uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN)) != WALLY_OK) { + if ((ret = wally_ec_public_key_decompress(pubkey, pubkey_len, full_pubkey, full_pubkey_len)) != WALLY_OK) { return ret; } @@ -2887,7 +2889,7 @@ int wally_psbt_sign(struct wally_psbt *psbt, struct wally_tx_input *txin = &psbt->tx->inputs[i]; unsigned char sighash[SHA256_LEN], *scriptcode, wpkh_sc[WALLY_SCRIPTPUBKEY_P2PKH_LEN]; size_t scriptcode_len; - bool match = false, comp = false, already_signed = false; + bool match = false, comp = false; uint32_t sighash_type = WALLY_SIGHASH_ALL; if (!input->keypaths) { @@ -2898,10 +2900,10 @@ int wally_psbt_sign(struct wally_psbt *psbt, /* Go through each listed pubkey and see if it matches. */ for (j = 0; j < input->keypaths->num_items; ++j) { struct wally_keypath_item *item = &input->keypaths->items[j]; - if (item->pubkey[0] == 0x04 && memcmp(item->pubkey, uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0) { + if (item->pubkey[0] == 0x04 && memcmp(item->pubkey, full_pubkey, full_pubkey_len) == 0) { match = true; break; - } else if (memcmp(item->pubkey, pubkey, EC_PUBLIC_KEY_LEN) == 0) { + } else if (memcmp(item->pubkey, pubkey, pubkey_len) == 0) { match = true; comp = true; break; @@ -2915,19 +2917,15 @@ int wally_psbt_sign(struct wally_psbt *psbt, /* Make sure we don't already have a sig for this input ?! */ if (input->partial_sigs) { - for (j = 0; j < input->partial_sigs->num_items; j++) { - struct wally_partial_sigs_item *item = &input->partial_sigs->items[j]; - if (memcmp(item->pubkey, uncomp_pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN) == 0 || - memcmp(item->pubkey, pubkey, EC_PUBLIC_KEY_LEN) == 0) { - already_signed = true; - break; - } - } - } + size_t is_found; + ret = wally_partial_sigs_map_find(input->partial_sigs, full_pubkey, full_pubkey_len, &is_found); + if (ret == WALLY_OK && !is_found) + ret = wally_partial_sigs_map_find(input->partial_sigs, pubkey, pubkey_len, &is_found); + if (ret != WALLY_OK) + return ret; - /* We've already got a partial sig for this pubkey on this input */ - if (already_signed) { - continue; + if (is_found) + continue; /* Already got a partial sig for this pubkey on this input */ } /* Sighash type */ @@ -3047,7 +3045,7 @@ int wally_psbt_sign(struct wally_psbt *psbt, return ret; } } - if ((ret = wally_partial_sigs_map_add(input->partial_sigs, comp ? pubkey : uncomp_pubkey, comp ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN, der_sig, der_sig_len)) != WALLY_OK) { + if ((ret = wally_partial_sigs_map_add(input->partial_sigs, comp ? pubkey : full_pubkey, comp ? pubkey_len : full_pubkey_len, der_sig, der_sig_len)) != WALLY_OK) { return ret; } } From 339a9705e7c4a6c8b7ebbf1d5ef54a719e32a420 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 13 Jul 2020 23:12:59 +1200 Subject: [PATCH 154/205] psbt: Use find to match keypaths when signing Also clean up the signing code a little --- src/psbt.c | 60 +++++++++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 35 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 8f7ebef93..7f9f40a01 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2865,7 +2865,7 @@ int wally_psbt_sign(struct wally_psbt *psbt, unsigned char pubkey[EC_PUBLIC_KEY_LEN], full_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; unsigned char sig[EC_SIGNATURE_LEN], der_sig[EC_SIGNATURE_DER_MAX_LEN + 1]; const size_t pubkey_len = sizeof(pubkey), full_pubkey_len = sizeof(full_pubkey); - size_t i, j, der_sig_len, is_elements; + size_t i, der_sig_len, is_elements; int ret; if (!psbt || !psbt->tx || !key || key_len != EC_PRIVATE_KEY_LEN) { @@ -2888,32 +2888,23 @@ int wally_psbt_sign(struct wally_psbt *psbt, struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_tx_input *txin = &psbt->tx->inputs[i]; unsigned char sighash[SHA256_LEN], *scriptcode, wpkh_sc[WALLY_SCRIPTPUBKEY_P2PKH_LEN]; - size_t scriptcode_len; - bool match = false, comp = false; - uint32_t sighash_type = WALLY_SIGHASH_ALL; - - if (!input->keypaths) { - /* Can't do anything without the keypaths */ - continue; + size_t keypath_index = 0, scriptcode_len; + bool is_compressed; + uint32_t sighash_type; + + /* See if this input has a keypath matching the pubkey of the private key supplied */ + if (input->keypaths) { + ret = wally_keypath_map_find(input->keypaths, full_pubkey, full_pubkey_len, &keypath_index); + if (ret == WALLY_OK && !keypath_index) + ret = wally_keypath_map_find(input->keypaths, pubkey, pubkey_len, &keypath_index); + if (ret != WALLY_OK) + return ret; } - /* Go through each listed pubkey and see if it matches. */ - for (j = 0; j < input->keypaths->num_items; ++j) { - struct wally_keypath_item *item = &input->keypaths->items[j]; - if (item->pubkey[0] == 0x04 && memcmp(item->pubkey, full_pubkey, full_pubkey_len) == 0) { - match = true; - break; - } else if (memcmp(item->pubkey, pubkey, pubkey_len) == 0) { - match = true; - comp = true; - break; - } - } + if (!keypath_index) + continue; /* Didn't find a keypath matching this pubkey: skip it */ - /* Did not find pubkey, skip */ - if (!match) { - continue; - } + is_compressed = pubkey_is_compressed(input->keypaths->items[keypath_index - 1].pubkey); /* Make sure we don't already have a sig for this input ?! */ if (input->partial_sigs) { @@ -2928,10 +2919,7 @@ int wally_psbt_sign(struct wally_psbt *psbt, continue; /* Already got a partial sig for this pubkey on this input */ } - /* Sighash type */ - if (input->sighash_type > 0) { - sighash_type = input->sighash_type; - } + sighash_type = input->sighash_type ? input->sighash_type : WALLY_SIGHASH_ALL; /* Get scriptcode and sighash */ if (input->redeem_script) { @@ -3040,14 +3028,16 @@ int wally_psbt_sign(struct wally_psbt *psbt, der_sig_len++; /* Copy the DER sig into the psbt */ - if (!input->partial_sigs) { - if ((ret = wally_partial_sigs_map_init_alloc(1, &input->partial_sigs)) != WALLY_OK) { - return ret; - } - } - if ((ret = wally_partial_sigs_map_add(input->partial_sigs, comp ? pubkey : full_pubkey, comp ? pubkey_len : full_pubkey_len, der_sig, der_sig_len)) != WALLY_OK) { + if (!input->partial_sigs && + (ret = wally_partial_sigs_map_init_alloc(1, &input->partial_sigs)) != WALLY_OK) + return ret; + + ret = wally_partial_sigs_map_add(input->partial_sigs, + is_compressed ? pubkey : full_pubkey, + is_compressed ? pubkey_len : full_pubkey_len, + der_sig, der_sig_len); + if (ret != WALLY_OK) return ret; - } } return WALLY_OK; From 5f71525856981b605114250674d0e007ed1e5110 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 00:57:23 +1200 Subject: [PATCH 155/205] psbt: Change psbt_combine to just combine two psbts together. There is no way to create an array of psbts using the current wally interface - since only wally_psbt_init_alloc() is exposed, you'd have be doing something nasty like using memcpy to copy structs into an array etc (which the ctypes python test was actually doing). Instead of this nastyness, just let the caller loop through their inputs and merge them in one by one. The code for this is significantly cleaner too. --- CHANGES.md | 2 ++ include/wally.hpp | 2 +- include/wally_psbt.h | 12 +++---- src/psbt.c | 83 +++++++++++-------------------------------- src/test/test_psbt.py | 18 +++++----- src/test/util.py | 2 +- 6 files changed, 38 insertions(+), 81 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9f1183f4f..28be6db26 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ ## Version 0.7.9 +- psbt_combine has been changed to only combine one PSBT into another. + - psbt_to_bytes, psbt_get_length and psbt_to_base64 now take a flags argument. - psbt_to_bytes no longer returns WALLY_EINVAL if the supplied buffer is too diff --git a/include/wally.hpp b/include/wally.hpp index a64e08a1e..795150630 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -490,11 +490,11 @@ WALLY_FN_PB3_A(bip32_key_from_parent_path_alloc, bip32_key_from_parent_path_allo WALLY_FN_PB3_B(bip38_to_private_key, bip38_to_private_key) WALLY_FN_PB3_P(bip32_key_from_parent_path, bip32_key_from_parent_path) WALLY_FN_PB_A(bip39_mnemonic_from_bytes, bip39_mnemonic_from_bytes) -WALLY_FN_PB_A(psbt_combine, wally_psbt_combine) WALLY_FN_PB_S(keypath_map_find, wally_keypath_map_find) WALLY_FN_PB_S(partial_sigs_map_find, wally_partial_sigs_map_find) WALLY_FN_PB_S(unknowns_map_find, wally_unknowns_map_find) WALLY_FN_PP(bip39_mnemonic_validate, bip39_mnemonic_validate) +WALLY_FN_PP(psbt_combine, wally_psbt_combine) WALLY_FN_PP(tx_add_input, wally_tx_add_input) WALLY_FN_PP(tx_add_output, wally_tx_add_output) WALLY_FN_PP3_BS(addr_segwit_to_bytes, wally_addr_segwit_to_bytes) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 95b54896e..6eefc7de0 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -664,16 +664,14 @@ WALLY_CORE_API int wally_psbt_to_base64( char **output); /** - * Combine the metadata from multiple PSBTs into one PSBT. + * Combine the metadata from a source PSBT into another PSBT. * - * :param psbts: Array of PSBTs to combine. - * :param psbts_len: Number of PSBTs in ``psbts``. - * :param output: Destination for resulting PSBT. + * :param psbt: the PSBT to combine into. + * :param source: the PSBT to copy data from. */ WALLY_CORE_API int wally_psbt_combine( - const struct wally_psbt *psbts, - size_t psbts_len, - struct wally_psbt **output); + struct wally_psbt *psbt, + const struct wally_psbt *src); /** * Sign a PSBT using the simple signer algorithm. diff --git a/src/psbt.c b/src/psbt.c index 7f9f40a01..fac53b338 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2783,79 +2783,36 @@ static int merge_output_into( return WALLY_OK; } -int wally_psbt_combine( - const struct wally_psbt *psbts, - size_t psbts_len, - struct wally_psbt **output) +int wally_psbt_combine(struct wally_psbt *psbt, const struct wally_psbt *src) { - struct wally_psbt *result; - unsigned char global_txid[WALLY_TXHASH_LEN]; - size_t i, j; - int ret = WALLY_OK; - - TX_CHECK_OUTPUT; + unsigned char txid[WALLY_TXHASH_LEN], src_txid[WALLY_TXHASH_LEN]; + size_t i; + int ret; - if (!psbts) { + if (!psbt || !psbt->tx || !src || !src->tx) return WALLY_EINVAL; - } - - /* Get info from the first psbt and use it as the template */ - if ((ret = wally_tx_get_txid(psbts->tx, global_txid, sizeof(global_txid))) != WALLY_OK) { - return ret; - } - - if ((ret = wally_psbt_init_alloc(psbts[0].inputs_allocation_len, psbts[0].outputs_allocation_len, psbts[0].unknowns->items_allocation_len, &result)) != WALLY_OK) { - return ret; - } - if ((ret = wally_tx_clone(psbts[0].tx, 0, &result->tx)) != WALLY_OK) { - goto fail; - } - result->num_inputs = psbts[0].num_inputs; - result->num_outputs = psbts[0].num_outputs; - - for (i = 0; i < psbts_len; ++i) { - unsigned char txid[sizeof(global_txid)]; + ret = wally_tx_get_txid(psbt->tx, txid, sizeof(txid)); + if (ret == WALLY_OK) + ret = wally_tx_get_txid(src->tx, src_txid, sizeof(src_txid)); - /* Compare the txids */ - if ((ret = wally_tx_get_txid(psbts[i].tx, txid, sizeof(txid))) != WALLY_OK) { - goto fail; - } - if (memcmp(global_txid, txid, sizeof(txid)) != 0) { - ret = WALLY_EINVAL; - goto fail; - } + if (ret == WALLY_OK && memcmp(txid, src_txid, sizeof(txid)) != 0) + ret = WALLY_EINVAL; /* Transactions don't match */ - /* Now start merging */ - for (j = 0; j < result->num_inputs; ++j) { - if ((ret = merge_input_into(&result->inputs[j], &psbts[i].inputs[j])) != WALLY_OK) { - goto fail; - } - } - for (j = 0; j < result->num_outputs; ++j) { - if ((ret = merge_output_into(&result->outputs[j], &psbts[i].outputs[j])) != WALLY_OK) { - goto fail; - } - } + for (i = 0; ret == WALLY_OK && i < psbt->num_inputs; ++i) + ret = merge_input_into(&psbt->inputs[i], &src->inputs[i]); - if (psbts[i].unknowns) { - if (!result->unknowns) { - if ((ret = wally_unknowns_map_init_alloc(psbts[i].unknowns->items_allocation_len, &result->unknowns)) != WALLY_OK) { - goto fail; - } - } + for (i = 0; ret == WALLY_OK && i < psbt->num_outputs; ++i) + ret = merge_output_into(&psbt->outputs[i], &src->outputs[i]); - if ((ret = merge_unknowns_into(result->unknowns, psbts[i].unknowns)) != WALLY_OK) { - goto fail; - } - } + if (ret == WALLY_OK && src->unknowns) { + if (!psbt->unknowns) + ret = wally_unknowns_map_init_alloc(src->unknowns->items_allocation_len, + &psbt->unknowns); + if (ret == WALLY_OK) + ret = merge_unknowns_into(psbt->unknowns, src->unknowns); } - *output = result; - return WALLY_OK; - -fail: - wally_psbt_free(result); return ret; } diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index 3ed1316b2..4ea1f4223 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -63,15 +63,15 @@ def test_serialization(self): self.assertEqual(creator['result'], ser) for combiner in combiners: - to_combine = [] - for comb in combiner['combine']: - psbt = pointer(wally_psbt()) - self.assertEqual(WALLY_OK, wally_psbt_from_base64(comb.encode('utf-8'), psbt)) - to_combine.append(psbt.contents) - combined = pointer(wally_psbt()) - self.assertEqual(WALLY_OK, wally_psbt_combine((wally_psbt * len(to_combine))(*to_combine), len(to_combine), combined)) - ret, comb_ser = wally_psbt_to_base64(combined, 0) - self.assertEqual(combiner['result'], comb_ser) + psbt = pointer(wally_psbt()) + self.assertEqual(WALLY_OK, wally_psbt_from_base64(combiner['combine'][0].encode('utf-8'), psbt)) + for src_b64 in combiner['combine'][1:]: + src = pointer(wally_psbt()) + self.assertEqual(WALLY_OK, wally_psbt_from_base64(src_b64.encode('utf-8'), src)) + self.assertEqual(WALLY_OK, wally_psbt_combine(psbt, src)) + self.assertEqual(WALLY_OK, wally_psbt_free(src)) + ret, psbt_b64 = wally_psbt_to_base64(psbt, 0) + self.assertEqual(combiner['result'], psbt_b64) for signer in signers: psbt = pointer(wally_psbt()) diff --git a/src/test/util.py b/src/test/util.py index 4ea434fde..7072a66e0 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -361,7 +361,7 @@ class wally_psbt(Structure): ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_uint32, c_char_p_p]), ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), - ('wally_psbt_combine', c_int, [POINTER(wally_psbt), c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), ('wally_psbt_finalize', c_int, [POINTER(wally_psbt)]), ('wally_psbt_extract', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]) From f538834078d5772a0d210077cbb0c2d4a4eaf971 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 01:17:43 +1200 Subject: [PATCH 156/205] psbt: Remove duplicated code around merging unknown maps In particular, there is no need to search for duplicates now that the add code follows the BIP semantics. --- src/psbt.c | 70 +++++++++++++++--------------------------------------- 1 file changed, 19 insertions(+), 51 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index fac53b338..fc8b40139 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2579,33 +2579,24 @@ int wally_psbt_to_base64(const struct wally_psbt *psbt, uint32_t flags, char **o return ret; } -static int merge_unknowns_into( - struct wally_unknowns_map *dst, - const struct wally_unknowns_map *src) +static int combine_unknowns(struct wally_unknowns_map **dst, + const struct wally_unknowns_map *src) { int ret = WALLY_OK; - size_t i, j; + size_t i; - if (!src || !dst) { + if (!dst) return WALLY_EINVAL; - } - for (i = 0; i < src->num_items; ++i) { - bool found = false; - for (j = 0; j < dst->num_items; ++j) { - if (src->items[i].key_len == dst->items[j].key_len && - memcmp(dst->items[j].key, src->items[i].key, src->items[i].key_len) == 0) { - found = true; - break; - } - } - if (found) { - continue; - } - if ((ret = add_unknowns_item(dst, &src->items[i])) != WALLY_OK) { - return ret; - } - } + if (!src) + return WALLY_OK; /* No-op */ + + if (!*dst) + ret = wally_unknowns_map_init_alloc(src->items_allocation_len, dst); + + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_unknowns_item(*dst, &src->items[i]); + return ret; } @@ -2689,17 +2680,8 @@ static int merge_input_into( } } - if (src->unknowns) { - if (!dst->unknowns) { - if ((ret = wally_unknowns_map_init_alloc(src->unknowns->items_allocation_len, &dst->unknowns)) != WALLY_OK) { - return ret; - } - } - - if ((ret = merge_unknowns_into(dst->unknowns, src->unknowns)) != WALLY_OK) { - return ret; - } - } + if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) + return ret; if (dst->redeem_script_len == 0 && src->redeem_script_len > 0) { if (!clone_bytes(&dst->redeem_script, src->redeem_script, src->redeem_script_len)) { @@ -2754,17 +2736,8 @@ static int merge_output_into( } } - if (src->unknowns) { - if (!dst->unknowns) { - if ((ret = wally_unknowns_map_init_alloc(src->unknowns->items_allocation_len, &dst->unknowns)) != WALLY_OK) { - return ret; - } - } - - if ((ret = merge_unknowns_into(dst->unknowns, src->unknowns)) != WALLY_OK) { - return ret; - } - } + if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) + return ret; if (dst->redeem_script_len == 0 && src->redeem_script_len > 0) { if (!clone_bytes(&dst->redeem_script, src->redeem_script, src->redeem_script_len)) { @@ -2805,13 +2778,8 @@ int wally_psbt_combine(struct wally_psbt *psbt, const struct wally_psbt *src) for (i = 0; ret == WALLY_OK && i < psbt->num_outputs; ++i) ret = merge_output_into(&psbt->outputs[i], &src->outputs[i]); - if (ret == WALLY_OK && src->unknowns) { - if (!psbt->unknowns) - ret = wally_unknowns_map_init_alloc(src->unknowns->items_allocation_len, - &psbt->unknowns); - if (ret == WALLY_OK) - ret = merge_unknowns_into(psbt->unknowns, src->unknowns); - } + if (ret == WALLY_OK) + ret = combine_unknowns(&psbt->unknowns, src->unknowns); return ret; } From c52d034a61db6296a5d3e5941f9f76842a3015f4 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 01:58:08 +1200 Subject: [PATCH 157/205] psbt: Remove duplicated code around merging keypath maps --- src/psbt.c | 67 ++++++++++++++++-------------------------------------- 1 file changed, 20 insertions(+), 47 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index fc8b40139..8e8efdf4d 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2600,32 +2600,24 @@ static int combine_unknowns(struct wally_unknowns_map **dst, return ret; } -static int merge_keypaths_into( - struct wally_keypath_map *dst, - const struct wally_keypath_map *src) +static int combine_keypath(struct wally_keypath_map **dst, + const struct wally_keypath_map *src) { int ret = WALLY_OK; - size_t i, j; + size_t i; - if (!src || !dst) { + if (!dst) return WALLY_EINVAL; - } - for (i = 0; i < src->num_items; ++i) { - bool found = false; - for (j = 0; j < dst->num_items; ++j) { - if (memcmp(dst->items[j].pubkey, src->items[i].pubkey, sizeof(src->items[i].pubkey)) == 0) { - found = true; - break; - } - } - if (found) { - continue; - } - if ((ret = add_keypath_item(dst, &src->items[i])) != WALLY_OK) { - return ret; - } - } + if (!src) + return WALLY_OK; /* No-op */ + + if (!*dst) + ret = wally_keypath_map_init_alloc(src->items_allocation_len, dst); + + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_keypath_item(*dst, &src->items[i]); + return ret; } @@ -2668,17 +2660,8 @@ static int merge_input_into( } } - if (src->keypaths) { - if (!dst->keypaths) { - if ((ret = wally_keypath_map_init_alloc(src->keypaths->items_allocation_len, &dst->keypaths)) != WALLY_OK) { - return ret; - } - } - - if ((ret = merge_keypaths_into(dst->keypaths, src->keypaths)) != WALLY_OK) { - return ret; - } - } + if ((ret = combine_keypath(&dst->keypaths, src->keypaths)) != WALLY_OK) + return ret; if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) return ret; @@ -2718,23 +2701,13 @@ static int merge_input_into( return WALLY_OK; } -static int merge_output_into( - struct wally_psbt_output *dst, - const struct wally_psbt_output *src) +static int merge_output_into(struct wally_psbt_output *dst, + const struct wally_psbt_output *src) { - int ret = WALLY_OK; - - if (src->keypaths) { - if (!dst->keypaths) { - if ((ret = wally_keypath_map_init_alloc(src->keypaths->items_allocation_len, &dst->keypaths)) != WALLY_OK) { - return ret; - } - } + int ret; - if ((ret = merge_keypaths_into(dst->keypaths, src->keypaths)) != WALLY_OK) { - return ret; - } - } + if ((ret = combine_keypath(&dst->keypaths, src->keypaths)) != WALLY_OK) + return ret; if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) return ret; From de0b08ee7906b0c58722bf84de06a84f0bb1070d Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 01:56:07 +1200 Subject: [PATCH 158/205] psbt: Add pubkeys with the correct length --- src/psbt.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 8e8efdf4d..9c83fb7df 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -111,7 +111,8 @@ int wally_keypath_map_find(const struct wally_keypath_map *keypaths, static int add_keypath_item(struct wally_keypath_map *keypaths, const struct wally_keypath_item *item) { - return wally_keypath_map_add(keypaths, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, + const size_t pubkey_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + return wally_keypath_map_add(keypaths, item->pubkey, pubkey_len, item->fingerprint, BIP32_KEY_FINGERPRINT_LEN, item->path, item->path_len); } @@ -249,7 +250,8 @@ int wally_partial_sigs_map_find(const struct wally_partial_sigs_map *partial_sig static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, const struct wally_partial_sigs_item *item) { - return wally_partial_sigs_map_add(sigs, item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN, + const size_t pubkey_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + return wally_partial_sigs_map_add(sigs, item->pubkey, pubkey_len, item->sig, item->sig_len); } From 58f381c932e63414ef26b27058ed1e12dc6894cb Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 01:58:45 +1200 Subject: [PATCH 159/205] psbt: simplify push_psbt_key_with_pubkey --- src/psbt.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 9c83fb7df..da060a02c 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2110,12 +2110,8 @@ static void push_psbt_key_with_pubkey( uint64_t type, const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { - if (pubkey_is_compressed(pubkey)) { - push_psbt_key(cursor, max, type, pubkey, EC_PUBLIC_KEY_LEN); - } else { - push_psbt_key(cursor, max, type, pubkey, - EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - } + const size_t pubkey_len = get_pubkey_len(pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + push_psbt_key(cursor, max, type, pubkey, pubkey_len); } #ifdef BUILD_ELEMENTS From cbd800b9142737f279dcaccad69f62ca0577d923 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 10:42:00 +1200 Subject: [PATCH 160/205] psbt: Add elements support for psbt_combine, clean up Also fix sighash combining to only overwrite if no sighash is given in the destination PSBT. --- src/psbt.c | 184 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 104 insertions(+), 80 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index da060a02c..12d92624f 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2619,113 +2619,137 @@ static int combine_keypath(struct wally_keypath_map **dst, return ret; } -static int merge_input_into( - struct wally_psbt_input *dst, - const struct wally_psbt_input *src) +static int combine_partial_sigs(struct wally_partial_sigs_map **dst, + const struct wally_partial_sigs_map *src) { int ret = WALLY_OK; - size_t i, j; + size_t i; - if (!dst->non_witness_utxo && src->non_witness_utxo && (ret = wally_tx_clone(src->non_witness_utxo, 0, &dst->non_witness_utxo)) != WALLY_OK) { - return ret; - } - if (!dst->witness_utxo && src->witness_utxo && (ret = wally_tx_output_init_alloc(src->witness_utxo->satoshi, src->witness_utxo->script, src->witness_utxo->script_len, &dst->witness_utxo)) != WALLY_OK) { - return ret; - } + if (!dst) + return WALLY_EINVAL; - if (src->partial_sigs) { - if (!dst->partial_sigs) { - if ((ret = wally_partial_sigs_map_init_alloc(src->partial_sigs->items_allocation_len, &dst->partial_sigs)) != WALLY_OK) { - return ret; - } - } + if (!src) + return WALLY_OK; /* No-op */ - for (i = 0; i < src->partial_sigs->num_items; ++i) { - bool found = false; - for (j = 0; j < dst->partial_sigs->num_items; ++j) { - if (memcmp(dst->partial_sigs->items[j].pubkey, src->partial_sigs->items[i].pubkey, - sizeof(src->partial_sigs->items[i].pubkey)) == 0) { - found = true; - break; - } - } - if (found) { - continue; - } - if ((ret = add_partial_sig_item(dst->partial_sigs, &src->partial_sigs->items[i])) != WALLY_OK) { - return ret; - } - } - } + if (!*dst) + ret = wally_partial_sigs_map_init_alloc(src->items_allocation_len, dst); - if ((ret = combine_keypath(&dst->keypaths, src->keypaths)) != WALLY_OK) - return ret; + for (i = 0; ret == WALLY_OK && i < src->num_items; ++i) + ret = add_partial_sig_item(*dst, &src->items[i]); - if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) - return ret; + return ret; +} - if (dst->redeem_script_len == 0 && src->redeem_script_len > 0) { - if (!clone_bytes(&dst->redeem_script, src->redeem_script, src->redeem_script_len)) { - return WALLY_ENOMEM; - } - dst->redeem_script_len = src->redeem_script_len; - } +#define COMBINE_BYTES(typ, member) \ + if (!dst->member && src->member && \ + (ret = wally_psbt_ ## typ ## _set_ ## member(dst, src->member, src->member ## _len)) != WALLY_OK) \ + return ret - if (dst->witness_script_len == 0 && src->witness_script_len > 0) { - if (!clone_bytes(&dst->witness_script, src->witness_script, src->witness_script_len)) { - return WALLY_ENOMEM; - } - dst->witness_script_len = src->witness_script_len; - } +#define COMBINE_ELEMENTS_BYTES(typ, member) \ + if (!dst->member && src->member && \ + (ret = wally_psbt_elements_ ## typ ## _set_ ## member(dst, src->member, src->member ## _len)) != WALLY_OK) \ + return ret - if (dst->final_script_sig_len == 0 && src->final_script_sig_len > 0) { - if (!clone_bytes(&dst->final_script_sig, src->final_script_sig, src->final_script_sig_len)) { - return WALLY_ENOMEM; - } - dst->final_script_sig_len = src->final_script_sig_len; - } +static int combine_txs(struct wally_tx **dst, struct wally_tx *src) +{ + if (!dst) + return WALLY_EINVAL; - if (!dst->final_witness && src->final_witness) { - dst->final_witness = clone_witness(src->final_witness); - if (!dst->final_witness) { - return WALLY_ENOMEM; - } + if (!*dst && src) + return wally_tx_clone(src, 0, dst); + + return WALLY_OK; +} + +static int combine_inputs(struct wally_psbt_input *dst, + const struct wally_psbt_input *src) +{ + int ret; + + if ((ret = combine_txs(&dst->non_witness_utxo, src->non_witness_utxo)) != WALLY_OK) + return ret; + + if (!dst->witness_utxo && src->witness_utxo) { + const struct wally_tx_output *src_utxo = src->witness_utxo; +#ifdef BUILD_ELEMENTS + ret = wally_tx_elements_output_init_alloc( + src_utxo->script, src_utxo->script_len, + src_utxo->asset, src_utxo->asset_len, + src_utxo->value, src_utxo->value_len, + src_utxo->nonce, src_utxo->nonce_len, + src_utxo->surjectionproof, src_utxo->surjectionproof_len, + src_utxo->rangeproof, src_utxo->rangeproof_len, +#else + ret = wally_tx_output_init_alloc( + src_utxo->satoshi, + src_utxo->script, + src_utxo->script_len, +#endif + &dst->witness_utxo); + if (ret != WALLY_OK) + return ret; } - if (src->sighash_type > dst->sighash_type) { + COMBINE_BYTES(input, redeem_script); + COMBINE_BYTES(input, witness_script); + COMBINE_BYTES(input, final_script_sig); + + if (!dst->final_witness && src->final_witness && + (ret = wally_psbt_input_set_final_witness(dst, src->final_witness)) != WALLY_OK) + return ret; + if ((ret = combine_keypath(&dst->keypaths, src->keypaths)) != WALLY_OK) + return ret; + if ((ret = combine_partial_sigs(&dst->partial_sigs, src->partial_sigs)) != WALLY_OK) + return ret; + if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) + return ret; + if (!dst->sighash_type && src->sighash_type) dst->sighash_type = src->sighash_type; - } +#ifdef BUILD_ELEMENTS + if (!dst->has_value && src->has_value) { + dst->value = src->value; + dst->has_value = true; + } + COMBINE_ELEMENTS_BYTES(input, value_blinder); + COMBINE_ELEMENTS_BYTES(input, asset); + COMBINE_ELEMENTS_BYTES(input, asset_blinder); + if ((ret = combine_txs(&dst->peg_in_tx, src->peg_in_tx)) != WALLY_OK) + return ret; + COMBINE_ELEMENTS_BYTES(input, txout_proof); + COMBINE_ELEMENTS_BYTES(input, genesis_hash); + COMBINE_ELEMENTS_BYTES(input, claim_script); +#endif return WALLY_OK; } -static int merge_output_into(struct wally_psbt_output *dst, - const struct wally_psbt_output *src) +static int combine_outputs(struct wally_psbt_output *dst, + const struct wally_psbt_output *src) { int ret; if ((ret = combine_keypath(&dst->keypaths, src->keypaths)) != WALLY_OK) return ret; - if ((ret = combine_unknowns(&dst->unknowns, src->unknowns)) != WALLY_OK) return ret; - if (dst->redeem_script_len == 0 && src->redeem_script_len > 0) { - if (!clone_bytes(&dst->redeem_script, src->redeem_script, src->redeem_script_len)) { - return WALLY_ENOMEM; - } - dst->redeem_script_len = src->redeem_script_len; - } - - if (dst->witness_script_len == 0 && src->witness_script_len > 0) { - if (!clone_bytes(&dst->witness_script, src->witness_script, src->witness_script_len)) { - return WALLY_ENOMEM; - } - dst->witness_script_len = src->witness_script_len; - } + COMBINE_BYTES(output, redeem_script); + COMBINE_BYTES(output, witness_script); +#ifdef BUILD_ELEMENTS + COMBINE_ELEMENTS_BYTES(output, blinding_pubkey); + COMBINE_ELEMENTS_BYTES(output, value_commitment); + COMBINE_ELEMENTS_BYTES(output, value_blinder); + COMBINE_ELEMENTS_BYTES(output, asset_commitment); + COMBINE_ELEMENTS_BYTES(output, asset_blinder); + COMBINE_ELEMENTS_BYTES(output, nonce_commitment); + COMBINE_ELEMENTS_BYTES(output, range_proof); + COMBINE_ELEMENTS_BYTES(output, surjection_proof); +#endif return WALLY_OK; } +#undef COMBINE_BYTES +#undef COMBINE_ELEMENTS_BYTES int wally_psbt_combine(struct wally_psbt *psbt, const struct wally_psbt *src) { @@ -2744,10 +2768,10 @@ int wally_psbt_combine(struct wally_psbt *psbt, const struct wally_psbt *src) ret = WALLY_EINVAL; /* Transactions don't match */ for (i = 0; ret == WALLY_OK && i < psbt->num_inputs; ++i) - ret = merge_input_into(&psbt->inputs[i], &src->inputs[i]); + ret = combine_inputs(&psbt->inputs[i], &src->inputs[i]); for (i = 0; ret == WALLY_OK && i < psbt->num_outputs; ++i) - ret = merge_output_into(&psbt->outputs[i], &src->outputs[i]); + ret = combine_outputs(&psbt->outputs[i], &src->outputs[i]); if (ret == WALLY_OK) ret = combine_unknowns(&psbt->unknowns, src->unknowns); From 15277960ee135e54860308c301aef689086876aa Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 11:50:29 +1200 Subject: [PATCH 161/205] psbt: Allow clearing value and struct members of psbt inputs/outputs --- include/wally.hpp | 1 + include/wally_psbt.h | 8 ++++++++ src/psbt.c | 46 ++++++++++++++++++++++++++++---------------- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 795150630..5c1a7845b 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -566,6 +566,7 @@ WALLY_FN_B33BPBBBBBB_A(tx_elements_input_init_alloc, wally_tx_elements_input_ini WALLY_FN_B3B_B(tx_elements_issuance_generate_entropy, wally_tx_elements_issuance_generate_entropy) WALLY_FN_B3_B(tx_elements_issuance_calculate_reissuance_token, wally_tx_elements_issuance_calculate_reissuance_token) WALLY_FN_B_B(tx_elements_issuance_calculate_asset, wally_tx_elements_issuance_calculate_asset) +WALLY_FN_P(psbt_elements_input_clear_value, wally_psbt_elements_input_clear_value) WALLY_FN_P(psbt_finalize, wally_psbt_finalize) WALLY_FN_P(tx_elements_input_issuance_free, wally_tx_elements_input_issuance_free) WALLY_FN_P(tx_elements_output_commitment_free, wally_tx_elements_output_commitment_free) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 6eefc7de0..e070295f9 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -804,6 +804,14 @@ WALLY_CORE_API int wally_psbt_elements_input_set_value( struct wally_psbt_input *input, uint64_t value); +/** + * Clear the value in an elements input. + * + * :param input: The input to update. + */ +WALLY_CORE_API int wally_psbt_elements_input_clear_value( + struct wally_psbt_input *input); + /** * Set the value blinder in an elements input. * diff --git a/src/psbt.c b/src/psbt.c index 12d92624f..66edd10ee 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -536,32 +536,35 @@ int wally_psbt_input_set_non_witness_utxo(struct wally_psbt_input *input, const struct wally_tx *non_witness_utxo) { int ret = WALLY_OK; - struct wally_tx *new_tx; + struct wally_tx *new_tx = NULL; if (!input) return WALLY_EINVAL; - if ((ret = wally_tx_clone(non_witness_utxo, 0, &new_tx)) == WALLY_OK) { - wally_tx_free(input->non_witness_utxo); - input->non_witness_utxo = new_tx; - } + if (non_witness_utxo && + (ret = wally_tx_clone(non_witness_utxo, 0, &new_tx)) != WALLY_OK) + return ret; + + wally_tx_free(input->non_witness_utxo); + input->non_witness_utxo = new_tx; return ret; } int wally_psbt_input_set_witness_utxo(struct wally_psbt_input *input, const struct wally_tx_output *witness_utxo) { - int ret; - struct wally_tx_output *output; + int ret = WALLY_OK; + struct wally_tx_output *new_output = NULL; if (!input) return WALLY_EINVAL; - ret = wally_tx_output_clone_alloc(witness_utxo, &output); - if (ret == WALLY_OK) { - wally_tx_output_free(input->witness_utxo); - input->witness_utxo = output; - } + if (witness_utxo && + (ret = wally_tx_output_clone_alloc(witness_utxo, &new_output) != WALLY_OK)) + return ret; + + wally_tx_output_free(input->witness_utxo); + input->witness_utxo = new_output; return ret; } @@ -645,6 +648,13 @@ int wally_psbt_elements_input_set_value(struct wally_psbt_input *input, uint64_t return WALLY_OK; } +int wally_psbt_elements_input_clear_value(struct wally_psbt_input *input) +{ + input->value = 0; + input->has_value = 0; + return WALLY_OK; +} + int wally_psbt_elements_input_set_value_blinder(struct wally_psbt_input *input, const unsigned char *value_blinder, size_t value_blinder_len) @@ -677,15 +687,17 @@ int wally_psbt_elements_input_set_peg_in_tx(struct wally_psbt_input *input, const struct wally_tx *peg_in_tx) { int ret = WALLY_OK; - struct wally_tx *new_tx; + struct wally_tx *new_tx = NULL; if (!input) return WALLY_EINVAL; - if ((ret = wally_tx_clone(peg_in_tx, 0, &new_tx)) == WALLY_OK) { - wally_tx_free(input->peg_in_tx); - input->peg_in_tx = new_tx; - } + if (peg_in_tx && + (ret = wally_tx_clone(peg_in_tx, 0, &new_tx)) != WALLY_OK) + return ret; + + wally_tx_free(input->peg_in_tx); + input->peg_in_tx = new_tx; return ret; } From 5b723cad1703cb2d98ea91c96afec4b97163d732 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 12:04:46 +1200 Subject: [PATCH 162/205] Revert "elements: don't fail silently if the buffer is too small" This reverts commit 211df9d9496172608b6d9ce47704552d256b2005. The previous behaviour is what is intended as per the newly updated docs. --- src/script.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/script.c b/src/script.c index f731b4036..4f93d42c3 100644 --- a/src/script.c +++ b/src/script.c @@ -891,9 +891,6 @@ int wally_elements_pegout_script_size(size_t parent_genesis_blockhash_len, size_t whitelist_proof_len, size_t *written) { - if (!written) - return WALLY_EINVAL; - *written = 1 + parent_genesis_blockhash_len + calc_push_opcode_size(parent_genesis_blockhash_len) + mainchain_script_len + calc_push_opcode_size(mainchain_script_len) @@ -916,6 +913,8 @@ int wally_elements_pegout_script_from_bytes(const unsigned char *parent_genesis_ size_t *written) { #define pegout_script_push(bytes, bytes_len) \ + if (len < bytes_written) \ + return WALLY_OK; \ bytes_out += bytes_written; \ len -= bytes_written; \ if ((ret = wally_script_push_from_bytes(bytes, bytes_len, 0, bytes_out, len, &bytes_written)) != WALLY_OK) \ @@ -924,18 +923,14 @@ int wally_elements_pegout_script_from_bytes(const unsigned char *parent_genesis_ *written += bytes_written; size_t bytes_written = 1; /* OP_RETURN */ - size_t required_size; int ret; if (written) *written = 0; - if ((ret = wally_elements_pegout_script_size(parent_genesis_blockhash_len, mainchain_script_len, sub_pubkey_len, whitelist_proof_len, &required_size)) != WALLY_OK) - return ret; - if (!parent_genesis_blockhash || parent_genesis_blockhash_len != 32 || !mainchain_script || !mainchain_script_len || !sub_pubkey || sub_pubkey_len != EC_PUBLIC_KEY_LEN || - !whitelist_proof || !whitelist_proof_len || flags || !bytes_out || len < required_size) + !whitelist_proof || !whitelist_proof_len || flags || !bytes_out || !len) return WALLY_EINVAL; *bytes_out = OP_RETURN; From fe3ac1d5a72538c84c6fdedda0dd13cecef26174 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 13:22:17 +1200 Subject: [PATCH 163/205] elements: Document elements_pegout_script_from_bytes change --- CHANGES.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 28be6db26..f0d04dc93 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,9 @@ ## Version 0.7.9 +- elements_pegout_script_from_bytes now follows the library convention for + too-short buffers. See the generated API documentation for details. + - psbt_combine has been changed to only combine one PSBT into another. - psbt_to_bytes, psbt_get_length and psbt_to_base64 now take a flags argument. From 2a26b055efec038a871b1bc895d4582664ca7026 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 14 Jul 2020 13:20:25 +1200 Subject: [PATCH 164/205] elements: asset_pak_whitelistproof: Update and use correct return semantics --- CHANGES.md | 9 ++-- src/elements.c | 57 +++++++++++++++--------- src/swig_java/jni_elements_extra.java_in | 4 +- 3 files changed, 43 insertions(+), 27 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index f0d04dc93..d4b5c500d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,16 +2,15 @@ ## Version 0.7.9 -- elements_pegout_script_from_bytes now follows the library convention for - too-short buffers. See the generated API documentation for details. +- elements_pegout_script_from_bytes, asset_pak_whitelistproof and + psbt_to_bytes now follow the library convention for too-short buffers + instead of returning WALLY_EINVAL. See the generated API documentation + section "Variable Length Output Buffers" for details. - psbt_combine has been changed to only combine one PSBT into another. - psbt_to_bytes, psbt_get_length and psbt_to_base64 now take a flags argument. -- psbt_to_bytes no longer returns WALLY_EINVAL if the supplied buffer is too - short. Please see the function documentation for details. - - FINGERPRINT_LEN was renamed to BIP32_KEY_FINGERPRINT_LEN for consistency - You should change any references in your source when upgrading. diff --git a/src/elements.c b/src/elements.c index 528ce4aac..96af319d7 100644 --- a/src/elements.c +++ b/src/elements.c @@ -592,43 +592,60 @@ int wally_asset_pak_whitelistproof( size_t len, size_t *written) { + const secp256k1_context *ctx = secp_ctx(); secp256k1_pubkey online_secp_keys[SECP256K1_WHITELIST_MAX_N_KEYS]; secp256k1_pubkey offline_secp_keys[SECP256K1_WHITELIST_MAX_N_KEYS]; - const secp256k1_context *ctx = secp_ctx(); secp256k1_pubkey pubkey; secp256k1_whitelist_signature sig; const size_t num_keys = offline_keys_len / EC_PUBLIC_KEY_LEN; - size_t expected_sig_size = (1 + 32 * (1 + num_keys)); + size_t sig_size = (1 + 32 * (1 + num_keys)); size_t i; + int ret; + + if (written) + *written = 0; - if (!online_keys || online_keys_len != offline_keys_len || !offline_keys || !offline_keys_len || - offline_keys_len % EC_PUBLIC_KEY_LEN || key_index >= num_keys || num_keys > SECP256K1_WHITELIST_MAX_N_KEYS || + if (!ctx) + return WALLY_ENOMEM; + + if (!online_keys || online_keys_len != offline_keys_len || + !offline_keys || !offline_keys_len || + offline_keys_len % EC_PUBLIC_KEY_LEN || key_index >= num_keys || + num_keys > SECP256K1_WHITELIST_MAX_N_KEYS || !sub_pubkey || sub_pubkey_len != EC_PUBLIC_KEY_LEN || !online_priv_key || online_priv_key_len != EC_PRIVATE_KEY_LEN || !summed_key || summed_key_len != EC_PRIVATE_KEY_LEN || !pubkey_parse(ctx, &pubkey, sub_pubkey, sub_pubkey_len) || - len < expected_sig_size || !written) + !bytes_out || !len || !written) return WALLY_EINVAL; + if (len < sig_size) { + *written = sig_size; + return WALLY_OK; /* Tell the caller the required size */ + } + for (i = 0; i < num_keys; ++i) { if (!pubkey_parse(ctx, &online_secp_keys[i], online_keys + i * EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_LEN) || - !pubkey_parse(ctx, &offline_secp_keys[i], offline_keys + i * EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_LEN)) - return WALLY_ERROR; + !pubkey_parse(ctx, &offline_secp_keys[i], offline_keys + i * EC_PUBLIC_KEY_LEN, EC_PUBLIC_KEY_LEN)) { + ret = WALLY_EINVAL; + goto fail; + } } - if (!secp256k1_whitelist_sign(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, - &pubkey, online_priv_key, summed_key, key_index, NULL, NULL)) - return WALLY_ERROR; - - if (!secp256k1_whitelist_verify(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, &pubkey)) - return WALLY_ERROR; - - if (!secp256k1_whitelist_signature_serialize(ctx, bytes_out, &expected_sig_size, &sig)) - return WALLY_ERROR; - - *written = expected_sig_size; - - return WALLY_OK; + if (secp256k1_whitelist_sign(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, + &pubkey, online_priv_key, summed_key, key_index, NULL, NULL) && + secp256k1_whitelist_verify(ctx, &sig, online_secp_keys, offline_secp_keys, num_keys, &pubkey) && + secp256k1_whitelist_signature_serialize(ctx, bytes_out, &sig_size, &sig)) { + ret = WALLY_OK; + *written = sig_size; + } else + ret = WALLY_ERROR; + +fail: + wally_clear_3(online_secp_keys, sizeof(online_secp_keys), + offline_secp_keys, (sizeof(offline_secp_keys)), + &pubkey, sizeof(pubkey)); + return ret; } #endif /* BUILD_ELEMENTS */ diff --git a/src/swig_java/jni_elements_extra.java_in b/src/swig_java/jni_elements_extra.java_in index 462d8e16c..abac435a1 100644 --- a/src/swig_java/jni_elements_extra.java_in +++ b/src/swig_java/jni_elements_extra.java_in @@ -128,8 +128,8 @@ public final static byte[] asset_pak_whitelistproof(byte[] on_keys, byte[] off_keys, long idx, byte[] sub_pubkey, byte[] priv_key, byte[] summed_key) { final int required_len = asset_pak_whitelistproof_size(off_keys.length / Wally.EC_PUBLIC_KEY_LEN); final byte[] buf = new byte[required_len]; - asset_pak_whitelistproof(on_keys, off_keys, idx, sub_pubkey, priv_key, summed_key, buf); - return buf; + final int len = asset_pak_whitelistproof(on_keys, off_keys, idx, sub_pubkey, priv_key, summed_key, buf); + return checkBuffer(buf, len); } public final static byte[] elements_pegout_script_from_bytes(byte[] bh, byte[] mcs, byte[] pk, byte[] whl, long flags) { From da87f5cdd5fb07849ecd1b0ad2be89d32fafc595 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 7 Dec 2018 22:57:15 +1300 Subject: [PATCH 165/205] Add security issue reporting information --- README.md | 2 +- SECURITY.md | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 SECURITY.md diff --git a/README.md b/README.md index aba4b20e8..042d306d1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Read the API documentation at https://wally.readthedocs.io. Note that library interfaces may change slightly while the library design matures. Please see the [CHANGES](./CHANGES.md) file to determine if the API has changed when upgrading. -Please report bugs and submit patches to https://github.com/ElementsProject/libwally-core. +Please report bugs and submit patches to [Our github repository](https://github.com/ElementsProject/libwally-core). If you wish to report a security issue, please read [Our security reporting guidelines](./SECURITY.md). [![Build Status](https://travis-ci.org/ElementsProject/libwally-core.svg?branch=master)](https://travis-ci.org/ElementsProject/libwally-core) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..071e4adf5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,326 @@ +# Security + +The maintainers of libwally take security very seriously and are committed to addressing any disclosed security vulnerabilities quickly and carefully. If you find a security vulnerability, please report it to us following the steps described here. + +## Reporting a Vulnerability + +Privately and confidentially send us a description of the vulnerability that you have discovered using an encrypted and authenticated channel. PGP encrypted email is preferred. Our contact information is given below. + +In your report, please include as much information as you can, including: + +* a description of the vulnerability and how it could be exploited +* its potential impact (e.g. privacy leak, denial of service, theft of funds) +* steps or code for reproducing it +* a proposed patch for remedying it + +Also, provide us with a secure means to contact you with any follow up questions we might have. + +## Considerations + +Please take care not to violate the privacy of users in your report. For example, stack traces or exploit scripts sent to us should never contain private keys or personally identifiable information. + +Give us at least one week to investigate the vulnerability you found and up to 90 days to fix it. Also, please give us reasonable advanced notice if at any point you intend to disclose the vulnerability to anyone else. + +In general, please investigate and report bugs in a way that makes a reasonable, good faith effort not to be disruptive or harmful to us, this software's users, or the users of dependent projects. + +We will take care to inform the maintainers of dependent projects. + +## How to Contact Us + +### Primary Contact + +Jon Griffiths +jgriffiths@blockstream.com + +Please use the following PGP key for communication: + + +``` +Email: Jon Griffiths +Fingerprint: 129EE55E90E6E7BB5ED3530DFD9FCBA3C53CED20 + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFcpb6cBEACshfpRfpq1su/TdjBphD1kBeyJbU5FhsX3LbOmyWERcvqH8ES8 +tKd0oVrt8pGj1R+GLrmT/bKA0qizsKzB46ErkCFqTrZIJc7c/dXB/N3ZqwRLi6zH +kfA9llqEd1fHCjFpNAGE9KFHqdVq2MGw0tCqRmOX+2ny0PqEe8mluCZV5drsDq4M +DDUVQPGP8JG0Z0J03jyOCHWz5D7E7vGazl5RhMZu2109xEM26vevUd1y8QLsjWLS +vyFjNKEgNGkxQnJ3JL5JLnlduiZQS8lM2KIpZw8G8sxtE4iuc/FQLWy6F9Mb23mg +eL9OYxVhY9/QS0EUS48/lqc2oxGHnDCn1U5jUK9ihMwLupgY8glCqXtHf0jqVDjV +QThqHVdxRqYuvlgaRSDf7YKgV8QOG0/j2o0u0Ums7zfA+yvtO0rgqKpb7SgQU3cx +y+JX1Ko8Aoa/KQEv44LuRLwBZ7B3WmBcitv/YHtdYFyYADCMwKaojG5Rh7sxgwgp +3788Rm81EpqjNlj1IoFBQ4UU7aRgcXnngUTSY3JTZ8XEmvH6Q1i51L7nfXcg1Nkz +E1Fuz4NGedh2iwHmGLUxkSqUgyavvmZ+OxiVr/lxIEKKEbR+nuE5yP6dk3Uv8RjA +/l+Ak1Tu6EWvCYFMPb4asOtKu2Z09gpXabeyMC17hsHsAfmqEkSKdgZzcQARAQAB +tClKb24gR3JpZmZpdGhzIDxqb25fcF9ncmlmZml0aHNAeWFob28uY29tPokCPQQT +AQIAJwIbAwUJAeEzgAIeAQIXgAUCVylwhwULCQgHAwUVCgkICwUWAgMBAAAKCRD9 +n8ujxTztII8qD/4zlQ6q5lwBHkyO2ZiDkh33kKllUg2DdbYG7or6W8GAxWs7Naap +SRjKzsh6j2emP1SWTKi/wRSiqk7xO7FLD29OTuIMYTox6QPm/hTLw5GqQ8z84lJ0 +cIn+l3ntxW10l062nsp/bfVIt6vg06RbQtppdp16Ki6EhYLojsZ5F8K9+55wc055 +OBll4QNGy/jcdyfYtjrddTadnqjjBEub8sx5cCqfSQiqAY/rIAa5DqMcvf6DS56L +0uLpcIDNn9knc3STQUTKlide1tYOSEUYsE705FGlrY0tJzvt2lHKq8xfaj4mOHx0 +k9Ji5HiSrTM+PBcYZ/mdQgw3JTLaOyPCpw8zIUJKudkqiBYAVUJjQfHHq7YsmMUg +dqQmjG5Mu99+YYNRhMoCGcrFdsbtrpS4F/vf/WSYstzw8NXIcroFB/68IYWqaeSM +sGVXpV7wKmeNSnaz1xBrdVhD+2m9Kyg9fttfPHLyN3iQipoFDGyBGeL5Iej+Nn4K +MR6fT1lxQilLBrtTv6rdWMIPDbiey0nUSRC6IkFlPB8R+fFdUx9gNSARzkZrl7lr +s0yuEV+6BWfxPwcYlNSfJJEovOVvbogvlx2NTVzXCXd6o4sdH6CKPTeAoIHPUJ+8 +zLQAq8C6bWa/AyfDZzymFraiiwA6SDb3yWUpQPQFyqGPTC5cm/pD/IOJvIkCPgQT +AQIAKAUCVylvpwIbAwUJAeEzgAYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQ +/Z/Lo8U87SCaSg//am7TvXy1SX13kCHrzeU933z1d81MMFHI47mvBYb1OzYROM5z +SVD/82XI6kYbzPAf74Tc2BlaeEKP5pfoSjGT5x97o14tx3HuYG5LVjVpgCxI1yuP +XzyLRU9JWJBMkeWC8obZd/4P0iFELylLC570LuKsMx1G00Luxsy2xXXSCOhdJY9f +598qehqACTKCXYLMUspGqgC/nJDCUAzi+mXqybdhTh9Dd5sFL0OIL+/NIDlT4/HE +KOBK1lVBUQiH5TJLhaaRijXlUTYntBba5uu0j/PUNYJ+FKVp/YNcA7QPJQOpVxjX +RaNgN+65UswA5SQmbr+k5pXmBhIFW9Q0pW6C5c4bLrH9p7jneJJQJlOevf3WGnjm +9Qkubmz9COwzmBMMqixNoHtElsjAwWs/o1W6va+qcTwkrGfyQMMS8pZEc0WWAaO5 +0MrOyhc3Bz+MV5/lWeV10zR8SHGjXQSoE/zlKi7rKtZr9jLg3A3JabH54LmTbbHT +ARK4GWYXMqrCAzN+Fn2AQvOoU3xA3HEatKDxoPd9tGRmr8if/jEkjlJ336E/oPq7 +hxEX42qKyqbW6WED937eSuKIZoMGusdp0S778NOa9E+KyizARAUui50PAeL15K9G +h+0VRx4VxWyFk8Ra/bVs9CmDUciMmV2wx87LAU+30ak2K2M29Vkhlm8/zB+JAj4E +EwECACgCGwMGCwkIBwMCBhUIAgkKCwQWAgMBAh4BAheABQJZCv4qBQkDwsHuAAoJ +EP2fy6PFPO0gBGIP/3zw8WZRURPQfQ0hC8UQc96uaPU7IBQrMXDBj+y8XBNLCFJX +UhT3rS1wlN5foCt0DxkgLIAU73GUJ0Q7qG0Vcap7YWSpcw6y6Ih7vxVRzAqe8nfC +IznSK28uhJgVErelNLOYLqiV3nO5oHOSVLL95JwvexPw/zIkbSQwr7mX/Rica8iG +qEGXqRgjasgLz0BhR7OozzgdXHmVcwtQ2x9t5ySso/doj+RrSTdCbSw+5l8fZOC/ +HEIdOWrjkL5r84EmZHfb1sbk0CAPZeX1lnaXSitYenb5Yl90ejSOjGwqV4F+/ZoA +LspvU1SeDiASQaFaK/gxuVeGVduYcbXriD06iGsMzX6BkathV/hPd2naneT4T85K +SgjUs9Mby9/gy84uNDDsH3PSBlYJCH+GuVkafiwD9GZc8sr5KJtCIFA/ZCJk0omJ +Mdod8QaWKwCpiJO4ynnliiBnXKMHABYQBR4B68fz2RduQ94tnGEdbyJbakPQ1viL +7Gr0hkau6Rn/p8qzH7ZG5zI1N6e1TUTwiRsDJK82N/R6hHj2ovf6oDp2oa5/0E1g +AlzstP4b2BmVnyEivc72smRbPwqN4kyoc6xUQsH7nWmXdw05uHW583et9Aa8R9My +65ubRnk6TWkwcUycJZMzPI9UJCIPj8vDHw8+6esVR+iaf60YYdzRPIZ7nQjjiQI+ +BBMBAgAoAhsDBgsJCAcDAgYVCAIJCgsEFgIDAQIeAQIXgAUCWu+aGwUJBadd8QAK +CRD9n8ujxTztIMOkD/49LKpwugFKAMtAN8tg5JmOmvFvzUgHKNaI1QLDw/7CB1E8 +3+zSTEge9MQme7pBeHbf8wHqRIOEQJuygmYcsXNdDhe2cDbuKKhBRnTiYyzZojSH +7Q/+21N4e0zIsizFCEwDFmIJa3YFGmVH28Cql2AtopW4yv9ZR4D/Fe9DF3um9llg +rZEOyIysJuj56rGUuRs1779xs+taVV74n3Vt6CY+zE0nbZayzac1G9SmowKeJjnY +aLoaxthpac4ysBDBfJaIj3ddU1exXiOJJYrOQ43h2iRmcpVRZ6QOtGRIsixLc/Sx +8x2ML4iHtY1V37oFCLa8PZs35Q/Jtbj/CRmM/WpmnCNR3e8rHGwHdJiV6oLChbE2 +BQuhQdxPSDPGJ2Z6CBpycWtCl2cH4INdbvjQyqyhRyWugqUSYkhzVe0q3VA5sJMj +otHeSSsBV8PeakjV3hQ7idH4DFwExKrJOm2Miif/MKJSOx14lWPeshHOIivwB3M/ +mt1hVHp512GuNdNNPWx3F3kPZbk2n03WL6rNb5EgA+6py7pEDOZgy9BmzAkTz3cN +0cySdqESS7oPpWfWDjYYJo4KndKdfmgWCf3y4HbCW01tjgSC4hk8sqmLOEhQ+s1h +vTB9U9jFtszCyNOrzsDqEDpgu8PFWGdOr+Fg5bQtLvf40dlu8JaFmllDpCALHYkC +MwQQAQgAHRYhBBM+rBeUNvFKXPG3lIYP64BOZpMgBQJboUJGAAoJEIYP64BOZpMg +0CMP/iNHXbGqGH0N7+BjwV4HrQxQ5+G4LEVu0EIq0Ut6n5I0ie5sAhOj/AKATLTx +CpQiAkuNb3VVXmmVgKAV76ClKzIr5/n0j+Iy+Pgjy817swVt56edeBZxv76pduaP +wUnfDxV0+SQpzBR7WavZ9v5cQFj0YI/vAlCeOSEDbqbZuu01f6WzhBNAk4VBV09q +T7/HgUCeRF4GpPF+jUMjM5bsH+9Xizf9CKLixw++KvcMiyzMFfruWSLm7m1lyAws +rItz1HKWvbrs59IRVs59QkmwD6e/LaZ+mycco95RarRvG/sgPEBIhUfdoevgWTIy +WRgUgY1YWEtOSpDHEnnwG/qPgqakrYUsPD3N42szqisLOxD9qWSGJnQJpcbbeAEO +byaMN7fVFAZ0AszDvUKiDb3ZEUI/DWl3P2+Rs4a0lXXAeL2itdikunZshvDyuzk+ +LV0BMNMfz232spxqZTYjUFGM19KA2nRqlmL2RX+vz8066EZpf7V84g2Ai+3jVlUJ +K/sBcFblwwpXcvpBqumeiWD01GI/DT9yU98Qm41uPk/5J+/NKAXzaOofEAlxPCN0 +R6U4nrTwslELdahh1QGVLUZA2wasLmwpXrs6/7lI3HQ3Y9A2zonsfwVCTHpIYJn0 +wT287lsehVjkqiK/Q/ectsgfy1qK51kYcdqLpcf0we4qIOaQiQIcBBABCgAGBQJb +p5nLAAoJEKJtbZ/giO1YFSkQAKh84zOXp63A3WhAqpMODwIOc3bHhfgD2emJAwBA +cvJ0jF6gQeQceWtoW3Fy0ivA/LQCX6cemriyJNOUHXAiilzcXQH/1VuUatD6K6X7 +eCbbilah0EMrUG/PLcvf8KlicazKwUpv9lLAdE5horUaq56QcGzWxL9OQkHJKpTp +aHo3Y4eEiXiAJr18t6OGuP3sqvPqOe7RuS9gHGyfVRb9cg8k1T9f4WdCNyoyAsbd +I2I7LtTln2xY/DDU9ynzOkwpxXCrxYmE3zMcPCTe5xITQ3JkprWIGDKFrxomYx4M +8DF9gtDLzOzA+7gHNbzsJzA2mUpvoA3ajz/GHNZUdh0yIeGmZKQbaA1uONUZTlxx +dRdoNTXl2AQ8NbD7VThxIj3ib8v4q6NpohPrzYZ+PmtUdd+stFWxkafB44LgjfbR +WO/JE4zVwrfykDRoMGwL4nCgcssyuCSDdtYaKgIiiUqZNyDakzcMMI6TMT/VfjXk +vjZYTOtXGsFJQRg9L9AEtVIsOB/IkChPL1AyzdQjK15jlQTo0qw7sr0zysFMyNML +rr49Sjcv0+cO3MHyT7Fi7gvHLVy6Lh6cvDtjaNUgYfrslimQdqUS7W7piEOKlADY +eUD8YFxmtHSkqmkdYW/ULYOlkp2nzjlfOG0GGfvibz1opIF9aSZH6on7eox/DS+i +DjVJiQIzBBABCAAdFiEEDXrynMkm7zNZa1t+hkxNCRC0MNcFAluskTIACgkQhkxN +CRC0MNfdxw/+KxfOpVzONnv62CBFG+XuzJ0yWNFuVvEJGwcFVKBozlpw5I6SDxtv +fL+BbRkuXMKI9vrXbvC8QKkOfz2zVTiDPYwXqnq6YeN+Tp5WKfsNWxDXLfTLS8nS +mPektqH5oWSCCqrGIYjGRBQ2vC4c0vjMHLRmXHMjuB7brC8XMYTIA3DhbN9wG3+F +dkTTjKIDrMfdn4gGOEmAiYYQuwjnnOAG9WIOfmsIuda5+taIId7mamV3N45rjn+k +uYJ9p0TsRoOM1gKyrrwFPSY1z354Vq9hcwOoCgNklATlEx+MkNG5jNmeXH0aH4HW +QqoryrJH+5+KNKKjkBe2vg6JXDDICAF6L/TtYhLxLrfz9G+ZIrU2x7O0xB8XXORY +X0fskhMqf0HdbJDfmHDWUmsG07FGCG9ppt/DC5QQYjnH+znSfug1/1IN9fo5FIDe +LgMjaa7CdvmVpdwTqZHuE9EcFqp2WjusmcPWW9npd5vHYpL7WxFzOyqQ1Gtjphmo +CkoWHKP1NpBZ106QHoUvmyfGQgz1GTfvzpH+YU/9rPbidJOIe3LkHXCFg5Txox5m +kf+85FFi5myCuxoRFIUu8oP2XMwPtLc1Bnt3bdKJmP+J+WcSmYLDdoBfzROL0M2i +6YAC4Grd6Jt2d5vMaCzqYFK00gvYQON6543YLGS6tTHPiOo5LIrXi1SJAhwEEAEC +AAYFAluk8hEACgkQAAI0BZy1BxUScBAAq4EiTtzbO91FN2vOHq1TIxObnw/GA5xt +Z7y7uKV9ZlrboyJ/L9WUT3JNRWPejhTeXIAz404Zqu0wsf1SJ6G6Dk1fN/xzpkOi +SoG4TsY3aw2JiuNzqd3GF6DipD5LMyoldlEsJAj2Xq43XnD0ZClT431jkj2EP03X +37xw/8LyFPdqovoGtr/a4ZVQBcJbuHxJdYZ4orDKSfnwEj4Mb9b29pEza22HKs3d +thc3aTMTOH9K2a/3X4aN1li7KfFwHgW+L7BFkbd9APpfgAb1VwcZLZnDYrEiIxzj +iagJqPH1PfGDNGju+K42Mtb/T3f7BnwyTuOhRNfOxIzGofpjYDkl5GhSGk5HSPxg +hXZvpCEn5pTDpqI/yzbw2j+njiLnTZvjsTMaOccw6i1b0V6K4fMOXDdc0LbE5rBS +37/izR4DHSRwCP4eVpz1OWkyx3FhjXNVCAW2xRUheOP+REjwFbZGWyiNTl9AtDki +85BVNdvqVKk2GhxK5MC/0A3k0qowy6FIEJcpwdf1wCbH3VQ0iOGCLI5baHOP7/WZ +AlyyfZhrGVlN2lqI9t9Rs8VPlig7we/HK0flxAiV/Rx0wvTgWEOXgaoio4DFhMdh ++Wf3eQU2R20C2BZEvdtzh77HaG+GRTbRYwZpiUsrMsIni8/Zb51HunAVNf0t60Se +i6Ry+XufyQGJATMEEAEKAB0WIQR0gJCTeNVE6mttzrdTWxKYC7ik0wUCW6HPZAAK +CRBTWxKYC7ik00sEB/0d7YWDsv1xSr9emZBwVkLaTHhwSrD4hbvYkO3CzQ4td/HS +0jlraIzI7uZJrA0KXELSMGfa8I7h8khMCl6Es6xeJs46uv/Bk/9ccLqvfwMSGD7r +uURMYPXaQqba/oYCHXhIlwjDqm/J8lgdJOfxUmml26qG23UO/g6hxSpsMcoNZ+qx +Vnl1Xp9poGKo2CwPfIGgJcc6wDU26OlWQluuux0ErtYa1o6DdmJikRnYxLxamo0J +mbL+YWeOC1CZd0M3bIjK2y1nrtnFglAuC5XuZYCGMNDnQO0lJNrQS3OezD7nNXJ7 +xZZso9G8KbK4i4Ube7KHMND3mHLCzaYyyKLItmoNiQIzBBABCAAdFiEEjMl02c/Q +NNzu0hOwKlfgphDX8ZwFAlug8mcACgkQKlfgphDX8ZwjQg//bfCvWSSq/XSNTdYc +tSysVaVHICm4BdOkMh6Gtb/1TJ4fE9mHnfza2h3zgQF3ayOk4JC0O/Ybfsm8HFXN +c7RBh+IQJ1DclXkhH+e1dXyPFuMR5SWR1dL4PMvyHfT2iUe7Ibud+EUDFWFA1CC9 +L/fEWfW3+mCizFI8IgoHObL6U0+4xATICacuTyNFtK90IWNcA/DuPm7x467qY1f7 +PmEfrPhXVrGkqy1kAswZz+pKly3S/FOpeqN+o5B/tA+X25v0R4XUPYsp3LToDJX3 +x6iPq0vrDQFkHG3SXdGBgR/ipy3bObSOguE6iDg12ZxNQbmXB0ggHjurVv6/9Twy +wN6UDD9iNs0JDXQ4fXbHs5qYChhxzGeU6dNGzqk0PC6j/ubFyb1zWqLTToa0FZuh +HS1Z2A6amiw7VAXXobjZ34N0lr9qnu/BrOqE7dMnvK/CX6T9mM5bGPf8zKvI8j29 +OTtS9BGq0LDjGkTuquLUzDodvZHeVinJ2IKLAmrrM5dhhDjDRamIpXIcUrG0akhS +exMP/2XLLNpz4Oa51AWf7nswc39s+Y3mFeO2qYdEDHXRvBESbZid/W7olVFbABnV +N/NGkDJmCZL3vRojnVBX7vv+7WHICsR50nApov6Yh3VO1XKooVdgpIOremGMlxR6 +xJ6PNW3YuUa8kPCM+EwafBSdF/eJAj4EEwECACgCGwMGCwkIBwMCBhUIAgkKCwQW +AgMBAh4BAheABQJfAiUnBQkJuej1AAoJEP2fy6PFPO0gN1cP/2jTMkl04rRf0JgD +IuyUAC5ZDYxjd0qnTtMLE1bJxOdAh5a450PdQWQFjqyRWlfpQlznxrO1O0H/x1/D +5ZNgLU7FlXYmuGj86NfIIiUxH+MbkjiQ7VUgNt04PRqt4GpWWn9O14Xxz09JSVA4 +19lC8FVt9M2JzUEi/hAte9GsXr0FHo1hDBZeXpGvZi8RbnbkEv+PXHiAWlpPEKeu +w6h9qej1r3DrYYPOmnYGc5R1MygDQe4Wag3owx3QOTx9pHV4TCaUtLNL04lzDgjB +cSjQNskzovi8AAnpMjU9Igvly+eD+vZ5019K42UJAkD3QM5u9xt8tkztPn3/GZgM +NpGrubWph5aEYx0XI/+ywBj52VfVrHf07htS+o+aj1EJDdB1TsXcPK/ecu/pF0z1 +xfEmKYhYdBPHIfymocFW316kOl5kGryuZC2sEDUFveihadC4C80XYPLycIelQ5vt +3lJp5CbdbZNGSEpW7tiB1sjKDAO1+j6O9mqG9opo35iTGlLkJYNRZQmzIytAvLKg +YNt9h9+/tzEZxpyLtPddXiVzieCTpf5lf9JWrAHfE9pf+/nHy9TU3KlQ+5JFq9Jp +ZYtXmnjz4sXsU/SzZc8ZgVfa81ZB9ZPpWeTytgmIvZ8IB0dg9J78VQLsomgNDGXR +rQNLeK0S9XuwzBEdHW4D1NXGapQRuQINBFcpb6cBEADHIXZN1ns7lR1sG/+WxnMJ +u5EB38/t16Rd/f+KmNKk+iyHdHxHALERoIP7P0BUhm259szYbMM6VJp7Rm2fUN/7 +BbtTdoCdignuna4bENX3RI9lCTXU3QbXo4JT9EcnoIhwosV1XxBASqAdc5Yosn7R +uQP/yXKjQz6Auce95NGRPKzgSGkgWRA7mzzRkxCQ5QIL2CmTi4KsXyJWCKLPst3u +xJpW2vucouRdBQoQ1a1gX76RFKIYaKLrbJ6tVzUYrve2LHCs8Q4mNVy/LrxKNHtv +9muilTYEyOdXf1R7zHgTH7QW2xoS5Bjt0iaOx6wdSc4xwx4uQMuIHyveT8uagahY +W7g7xd0tIi3yja1qDdkvU4zp975/Q/Ls+qW2/4CahlukOj8LX/teiLuaFaHlDYqI +Hv22URBaIQuK+L/f3Ogi+hLbSCWSu4zLYvAWZ2Bl2amfDrC3t46gT9u8uNDhlt9Y +4H10s5kON4nXVwgRRPllRc2IYqK6i0JHvF9xE5OvnYDPRblV54WQjJmAkmrEl4Up +kd5SVqVoNf99MzvWrjiId3oZKUb3bfv+tfMCupjr6ELOg9dOQrXHB1qfrrs2q4s4 +ltF3+D5jpqhz09UZW/HEpbdEwvqS0Bb1W7oq5jd/LwL/hhmPVey65k4VfDuZF7gX +Mf7o5/pgbQgIaeRRWJnjBwARAQABiQIlBBgBAgAPAhsMBQJa75o7BQkFp14PAAoJ +EP2fy6PFPO0gjQQQAIgM+dTJlwnZBmgSDgnYOKAV8IKc4JWf0jlmQ/7Nkqpyujb4 +oMYDkvLNkKhs0QsiaCowz2IY96RksEUEZRim2L8sXYi17RYxsu6l0Cb54YBpQXZw +gOUPxIJmT4vdoP0cEf6ryo3G7BQ+XqpKOyORRd22/Oplu5DQLzEJZIu+YEptobBY +pUFqM8C9hFviCJW0juDDSdrJjiUnP9sqPXfbXpRZ3GbgUatlFeOOFFqS++rRP5fH +JngxFHqWKd1f4SOP/5ECtb1POGBPT9WT0YLuis6Oqo4yTvk/Oyn3mVNPiSlBkXML +GDUj3L/1rrADtj7HKPkHssR9cWq0MoUwaucSAvJEvdd0WPqG+7tIcO3SvZpkpIhu +L55vW1i9Iog+Vy60VsdgbM0QB1TC2OwRomWCYy9OrPbNk9Uk0oOuvrmc3ni7HpcT +TDm/+ocvtJ35OPwqdA47oxq1lY3dvRrB/6n4XT028PI+Axpga0/4w+oxN9ZESgTk +S0Jf9fuSKCXNWgcWkegKYr4ExEvJMKbx5O8DYJgQbvtmx7XUL/oUrYbpYWlhYx3x +/EvlWIE38p3us/0o8cYjh+gsxAtaBPmsW2KDsu205AMSsjUoF8jnY0eaMTvORQcW +LDc1js0jGKX1KoNRxySa4IwUrN+BSbtIonPw27Uch6NIu9+1CwUkagFOAimUuQIN +BFcpcKEBEADO3laIO69lLMz5yv+71c8cfr1Xjw99ax6JRw5+S+63/EooZzMQAnVu +79e9EDqL4w5qudCTnb5DWARnPY9pSbMvuP6vvNJYmLeiGT4R7pzlxw7oNDfoTknI +XmEOjVSHFg0YFSU0pxv0F35adC5m2YcxEEGOXNNxFZ9m/H8XDA0DsA2hqlxhcKCn +qQ8/aH6gkAUdXfpW+dXac7h6MazsErsMaPssPAvmlMNglOEvRoCtvI6+PB4rCsJL +eBaCj3pu+DaJRSyJyTt2TKKoYVxW6SlRIWn4ysii/P7XMjM4fNUJJOvLBwdEDkJj +eKNiGsz5ahAWrfVQ7aTuvp0h2g3LyY2tYhDeLGY4Tm13eVi58s3oNLcXdgsfMTgE +udA0OwvEdR5Kfgth0thBZUjsUH5xML8t/FpLmKniUE4VdnkatSSZAe+5xqmkn7V3 +ZJm1XkhUHFdETVc/xgTF7spccPjzMDkrFqGKmoC9n9ZJDX7K4BhIxMHG6SnLbXVd +4D+9ErRePchem9Q+yo6bBzw8X9nxBeju4pBkpmr3eCF33Atn+bN0ncp2G8BW2h73 +aWuXXqMhkCSko4UB3sviuCL9aXkAaqvk5WRBAhsZhEgO7ZEsTz0NTf6BxZJ+l1B/ +fNFAL+0awLpDOWsI4Fj4DO/6EXdmwRAmRBsSzv/WvfbJBzRBKZdoZQARAQABiQRE +BBgBAgAPAhsCBQJa75pVBQkFp10xAinBXSAEGQECAAYFAlcpcKEACgkQ9xwiw9sf +cidUWxAAqBuhLpGsfE761pLeO3DLEtUKt/YXFNiS62MSOO3hQYduZihq45Lvc6oI +eFvPGZq3ewHJ/YKI3BeCYJqB3yYWDzd2XQySozMMT1CsJF5AbnQ+VYmICGOQDgVU +LP1YOt5zuYK1MKCwG2sh/1pOJAbZA7Oj8BOU8hz90r7+F/65HMDku6QZnglpb1WT +v3+U/TQcuarYdPd/gqUJogwLfvSRhFcSXav/qpcCHvJqO7iuz+8cGIoply87YKz0 +WsipQl8wO5fFpk+T2LIc7vWfs56CIRh4+xI/TJAySwpX7Vm2D1AZtN/myYXrVt2J +N+GyAzUZXU42kOpkIR5ojagSohxdQcX+C821vk0izHxivqkm+Rue/TqdrnYSyoRQ +earNG3ErPRnF3GP3m82IsZEGwM3I2ev8hpQ5wtehXv3VGnfpeqonrVecvMsNrFvl +Zw8OsLKbct3DQug1rIacgb3tXz9oO+VSY8c0vNuaY8gPqyXuoWWht+djgnvueTom +TbaBCIySnzj2qlCkfrMkWOZG7ONhl+HWSRekIWiYirsWhTxEPgNSebXvBdDYhn5Y +a2Cu4glJDhO4ptFX59pKDyDltwFXgc9IfZfkVrVMVx6IwhjrXILZvul01LDeyVOw +8Dcy+epUpJ1012qUb9Capzrq8kXEsb4FdBqOpZ9e3MOWlQONlGgJEP2fy6PFPO0g +TV4P/RY9pjtEMYCQ4i2qPdDXFpaIFv8f0UlAegN9bF32uSWXHLksuo6J+/40vYDt +qPzBO1JQUovKb4Xgn9muN+YDT0u7RyItEQSYczEOjf1ygd354bjvefhfarMboupl +5h1zKR/S9hCQMA6CyyN83ucSPGzuJXaTro5a1IIL8aFJGyRU0wlFmW8csa6w3rtO +u13jSh+XRSXrcGL4/IpTrSVbvqRVF6ptyiLnOPJ1tf2DMUCz7Z3UFm2sXd29seL2 +Fq3KwEWbLeMlGlRRVbdUJkVtQqhcG3H1pWTcPbO2nWdNEIsV+DovvaaHp7yg12ok +/8+GY8fwEnfb90+w1Pox5iUlBX47NdYsuX8QEON3fbt2+rTKE2hElIpGOBOjQwF9 +Q3r7/tJ8wHJS4TBFzuNOmgLNG1jVuasYEB5NdXQgrYd0ADnAsGHq+L/5tsoA8B/y +OWdlXLdRZGdThgIrJLBy0HCes0vf7BU67wXWOpUzTYVMphStomafGnqMkTjhUUAQ +6KOPGVWBXGhTqNQEWhlHr9Ro+9We0ULbeWt3Ldcnfr9erap8q474jvTW3cbbqAT/ +7qS44dDnO07gu76L/UntHgRUM5p+AwIcbwduMDGOZxMK0rNlc3GQm7KDdlJGewAr +HXv4f5B0kS3W42HJYVfByu0jHyyM3Q36LW6hchdGRpKHHlDFiQREBBgBAgAPAhsC +BQJfAiWrBQkJueiFAinBXSAEGQECAAYFAlcpcKEACgkQ9xwiw9sfcidUWxAAqBuh +LpGsfE761pLeO3DLEtUKt/YXFNiS62MSOO3hQYduZihq45Lvc6oIeFvPGZq3ewHJ +/YKI3BeCYJqB3yYWDzd2XQySozMMT1CsJF5AbnQ+VYmICGOQDgVULP1YOt5zuYK1 +MKCwG2sh/1pOJAbZA7Oj8BOU8hz90r7+F/65HMDku6QZnglpb1WTv3+U/TQcuarY +dPd/gqUJogwLfvSRhFcSXav/qpcCHvJqO7iuz+8cGIoply87YKz0WsipQl8wO5fF +pk+T2LIc7vWfs56CIRh4+xI/TJAySwpX7Vm2D1AZtN/myYXrVt2JN+GyAzUZXU42 +kOpkIR5ojagSohxdQcX+C821vk0izHxivqkm+Rue/TqdrnYSyoRQearNG3ErPRnF +3GP3m82IsZEGwM3I2ev8hpQ5wtehXv3VGnfpeqonrVecvMsNrFvlZw8OsLKbct3D +Qug1rIacgb3tXz9oO+VSY8c0vNuaY8gPqyXuoWWht+djgnvueTomTbaBCIySnzj2 +qlCkfrMkWOZG7ONhl+HWSRekIWiYirsWhTxEPgNSebXvBdDYhn5Ya2Cu4glJDhO4 +ptFX59pKDyDltwFXgc9IfZfkVrVMVx6IwhjrXILZvul01LDeyVOw8Dcy+epUpJ10 +12qUb9Capzrq8kXEsb4FdBqOpZ9e3MOWlQONlGgJEP2fy6PFPO0g6OUP/i7NGgKx +8BcqGwxLnD/0yWAxFIR4hhqyEFMhu3at1x3RAS+Wbp2VVtVBKXEjHF8FU4uumAtV +jnDX7znLNRxU3V5V3D0ISxMtvbqhW1mCMyrbc0o2fwd53klT2E8vE9B+VV6XUYzk +Viqj0YOcQ7mTDbNufPrapdRtT5g/05lC98MBSjzGVv11h9t8dTMcmPBgMMwzdYEJ +tdHHJzfjmvqApYe6mP3NvCO9j8qukVX3nQjxx/5y2E17CyASwU8iLpB1mjPcTKFZ +xQVdg61m7ftwptIdasQaY7msqaW9C44ULMdxMq8E25ebMT1W8pGzLjO5xXI6v1o5 +h9hRNJEjPVpODgcBz8V+VZaiyfbF5/Rq/SUhHXLdxLS4ZvdWxoWj3NtbItg42OtG +qOU8CFh6pZQp3j2bvkQMdTQ587QByTE3cev+1RAjrjGNqIpSyAhDrFICP6Wz4EkX +OO43P0SZry7u5/lQRSo9w3r0j29MmGSZrVxgG3WRuzXh7e7Ii8uSETjqtmIXu9xO +9HokXbIcVmqD+eF2hdtx1FpSTvV3iefOn7XVVcyWGQHDfOXtbfyE5McZkX1YZ9gf +vS/3t/c23hqM2rFNVBs+yKfZIGEa7w+WedspQ4RR9PuTJP1El1aPCVheMIKxJHgz +24DIbd7BgGqHkwKf6fItseIGXWNWMFtLhObb +=GEF6 +-----END PGP PUBLIC KEY BLOCK----- +``` + +## Escalation + +If there is no response from the authors within 3 days, please escalate your vulnerability report by emailing security@blockstream.com using this PGP key: + + +``` +-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQINBFv/XdQBEAC2iS1uQij2AJSnvQZxScnqf6v0db63QDbS6GjH5PndQ8cF0szv +YJYCFBigkzj4BkKxbJJlnfPW6Jl3SfzCGDvBW3IYuB3S10InDqJFYcM1ZemWCGAs +HA48NDfB4AIBIFH09H4dUE/J6yAdhX/+Qa/bjOhiwrCFVE2pVtMN8aTFnaLzxCP+ +fWZUaPrPv84B7uxEdLM77wIhsN+16FAr1qS42NfKDDolBAs//Bmv5fkNC7lzAVCf +MA/QEcNlAvButPrNyZU3t25maUv5hhKUDdJ2G/iACf8tVgp+ygmD8NHQMLPSaFqa +O5wy77Fd5OyX3Gii/E8MtPEsePViwecwJqc/3UXBx7zTRou2gxLikVFTnJb+Jit9 +F2kcljhCjHGxsuhf4Zr6zu+RTHHDgdBmpt4t1HA2jft/40r+uWQjL/rNP+01HgZj +4OLHkSI5VfJsXRn1EqOGpBIzR56f0GaxA0jluQMfkE9PTMxg5+YbrGgdot3l7pQ3 ++mqMu3aim2EYZZHTsMCRt4j4pRn5g4BZan+w7STfA7rIMJu/MjP3G4s+IFMPVRki +QLwktZSD+x2M9iIsOD4YVheMKtU6WRroFeCkXzIzLYwCuZ4ym/JFJMH+Keuyo254 +5hcymw+ivmPP+xuuoP1npQioRH4RKpfDgskABv8+t5rteV4BtUIWL33A/wARAQAB +tDlCbG9ja3N0cmVhbSBTZWN1cml0eSBSZXBvcnRpbmcgPHNlY3VyaXR5QGJsb2Nr +c3RyZWFtLmNvbT6JAk4EEwEKADgWIQQRdlQtqY5x4TNyLvdKyMyIaESi1gUCW/9d +1AIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRBKyMyIaESi1lcQD/9HZmtP +XhKtwC92zTsT5Xqt/K4ckaiJRaUlHeFtfkHpTdXIUFIJjZ1w1JJAWLtRf58MY45U +5DAOOYQptoXiy4USZkIMH1uBtFSAvyCUXH5cDWK1347G5rUg6Ry8Cxe+wzXOlxfr +f/9Vs28z+awfIrvk50sj4QW+mMlS69VwuHUl5CJ+BtcqQWQO85ummQxQq8rMw7rD +AwkftqiMKz+YLw5/xECyiXDDdQr66kdkglbQGgiciS7HNo0SQ2XqTNcGZkRA3lmv +HYCchZpgr9qxfnLjgVddJB+iNTwFZ7AQ7ZBlYWvu5UIMweuEz+yB7WGbQZLOsRZ8 +OaIPmZ150VX0sQYeXYhoFrraNW6obFqsSklnQbsfw6KsCaFvYhNZgHf177YlrAzq +puR53H1sOjOQq8pnbjyf4XLhAGMC65LydWtkQK77m46kOBZad9UGg2WKg/SY+3pF +WWdP7vlsR7oJyElEQfUwBsT16K/6kenyagQ6CzqnF/X+W7P1STndpBJp4lD0RfaD +v6UyqxPYhUuQ24jP5jm8+RtS+OGB00czY2cVSDgjYVuU80WsW+Qt0XtLKeoVYdCb +TaKgreicqbz0Afr9hbPIieW2wbQnYlRPjprTVhhGsxlaUb7Kcz7fapliJrKBFgy5 +odUljZ+iSompuiYtFhVYA8e6sx0pRUGOopnkGLkCDQRb/13UARAA3WAlRv6DofgG +xu+L2ePZb1OCQTkn4Eq+24veGibPvlqFJivF1ebctUtxiKVsz0dXtWcAYk7Rh2I/ +xsEGxIzhjr5VLVOdldM5AgJna6WPvOA4sPXjdy47R71NfEQfg9Svv93mmkpbJsL3 +NuHxvpoeO4A9JrFfwn7WJevXOiUWdKJ+nn0ZPwjYle6i27OfIojyVmZVQEiHC/Il +LxQEYaNDalAorjnn0b7X7S3Z8pMAb8HqD0RTXXed9LPgbasARyND2I2xy1txUDPI +Qcq6tIbryGYlegEHuvsE31zRPoNjnXkwABb6qBkUUiZMbRJCYOQXSo7Z2tasKHIJ +I/FnIj8dmT/IXDb9KiWr8wziGLdgnZx3QZGt5P0LIMFKrfXMNJO7EmO1QMbgZFgk +JPhJ0o61PvMaVLMQVoxD6K7bKOzI2t4LTA0l5RxuMcadu8G13YzgVXX44Cac1qUn +xriMzk62HXdSeZozcO/IRN7Kdw2bB++5EVYTQN1EEhIymXVUrBg2pXvLSXalg+kp +0BhLVHcbTI51mKz8GY9NUShFI7ZEzxzzltcEA+F5TLrPMgT+tx+QvjDdGWIhWycI +KW53hjKiGolhpG9Kqo9ogtCO2a3r6JspO0z+54/EF5rS2LI13pqk0qNgoYMYqChe +XU8BJdZ9siCooQ+3o+Y/9TkQWSAwnWkAEQEAAYkCNgQYAQoAIBYhBBF2VC2pjnHh +M3Iu90rIzIhoRKLWBQJb/13UAhsMAAoJEErIzIhoRKLWGhoP/jFfwRrda1RNR6OY +NHOIa4x4PtjDuYwDYgI5X2NQXlglyOTWouKjY1eu7LRoQSS5blD7BA9GHhYRDBL/ +0NQo/EQn3JFoitGWs07Bry0A4DTOz0H7wRqVXtN+Ck13QdEemq+suLE+PcbRJ4Ei +ANoNVgSRGqYO683oXEzGgzF+FXXPbcRTNHwvV8LgmUioe2cgHX3Q2PC3gUTmnNkq +IhWirlT5cQVSLS2IzsP903uq8VtHl7lXLkS6Ba3CmwLoHYfhurGQNR6Av2WPgL2D +oY8NOxPdz9QxBUzUVObiMm3UfD/eTF73NAmNJRDqYzpY/l54ZyxLFjlfXRpwKrx/ +islwezx+2fzns5u4xwdywVHzvgsmbXMIDdNTaTS8BDaKbAopLmbmuTnnTbJXWFbb +mQ2/GHcB0mKuXDkzt+7JMQ0NHtrGC3qvEtnTXZGXr3uIhFDkJSOoaH68dqq5++pz +GtT+aiv3L120r0pSSyTgbPsrqSlWgXEuJ4uzt3j69J0Qek0YrL0EDxHdnGPW4+fv +AZiq1RFG8MHOy0Obahed5uqlzXCNtroHdgSQeR+6IkODSsEd+hVdXJs/hjcWLNG5 +VNztar/H4BSwlhKbgvFivOzhj8x5TNoqMM95G8Ew/5idiT/YQgsA6lcwsEZ78t9O +lTHPj4G8vH5F/zIFb+uQNSlKzuH+ +=8mAH +-----END PGP PUBLIC KEY BLOCK----- +``` + +## Acknowledgement + +Your help in maintaining and improving the security of this software is deeply appreciated. When the vulnerability you have reported is patched here and in downstream dependencies, we will publicly disclose it. Let us know if you would like to remain anonymous or would like to be acknowledged. We would be happy to acknowledge your contributions to closing the vulnerability you found in the release notes, source code and/or documentation in this repository. From e109ac33ebbc42f479cb61c16d9cd2dd6db21bea Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 15 Jul 2020 09:31:24 +1200 Subject: [PATCH 166/205] elements: make wally_is_elements_build take a size_t output Part of cleanup around auto-generating CFFI wrappers. --- CHANGES.md | 2 ++ include/wally.hpp | 2 +- include/wally_core.h | 4 ++-- src/internal.c | 8 ++++---- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index d4b5c500d..58f06eabc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -2,6 +2,8 @@ ## Version 0.7.9 +- wally_is_elements_build now takes a size_t output instead of uin64_t. + - elements_pegout_script_from_bytes, asset_pak_whitelistproof and psbt_to_bytes now follow the library convention for too-short buffers instead of returning WALLY_EINVAL. See the generated API documentation diff --git a/include/wally.hpp b/include/wally.hpp index 5c1a7845b..4c72ca4b1 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -554,7 +554,7 @@ template inline int clear(O& out) { inline bool is_elements_build() { - uint64_t ret = 0; + size_t ret; ::wally_is_elements_build(&ret); return ret != 0; } diff --git a/include/wally_core.h b/include/wally_core.h index 6dbb9e9d9..e31d01dc3 100644 --- a/include/wally_core.h +++ b/include/wally_core.h @@ -241,9 +241,9 @@ WALLY_CORE_API int wally_set_operations( /** * Determine if the library was built with elements support. * - * :param value_out: 1 if the library supports elements, otherwise 0. + * :param written: 1 if the library supports elements, otherwise 0. */ -WALLY_CORE_API int wally_is_elements_build(uint64_t *value_out); +WALLY_CORE_API int wally_is_elements_build(size_t *written); #ifdef __cplusplus } diff --git a/src/internal.c b/src/internal.c index 5578441a1..0b1747ff2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -278,14 +278,14 @@ int wally_set_operations(const struct wally_operations *ops) return WALLY_OK; } -int wally_is_elements_build(uint64_t *value_out) +int wally_is_elements_build(size_t *written) { - if (!value_out) + if (!written) return WALLY_EINVAL; #ifdef BUILD_ELEMENTS - *value_out = 1; + *written = 1; #else - *value_out = 0; + *written = 0; #endif return WALLY_OK; } From e372dc73a7871a7df684a7ececc1c17b1ce7e43d Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 15 Jul 2020 09:32:56 +1200 Subject: [PATCH 167/205] docs: Document asset_unblind_with_nonce --- include/wally_elements.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/wally_elements.h b/include/wally_elements.h index 172b5142b..5dbc503c4 100644 --- a/include/wally_elements.h +++ b/include/wally_elements.h @@ -209,6 +209,27 @@ WALLY_CORE_API int wally_asset_surjectionproof( size_t len, size_t *written); +/** + * Unblind a confidential transaction output. + * + * :param nonce_hash: SHA-256 hash of the generated nonce. + * :param nonce_hash_len: Length of ``nonce_hash``. Must be ``SHA256_LEN``. + * :param proof: Rangeproof from :c:func:`wally_tx_get_output_rangeproof`. + * :param proof_len: Length of ``proof``. + * :param commitment: Value commitment from :c:func:`wally_tx_get_output_value`. + * :param commitment_len: Length of ``commitment``. + * :param extra: Script pubkey from :c:func:`wally_tx_get_output_script`. + * :param extra_len: Length of ``extra``. + * :param generator: Asset generator from :c:func:`wally_tx_get_output_asset`. + * :param generator_len: Length of ``generator``. Must be ``ASSET_GENERATOR_LEN``. + * :param asset_out: Buffer to receive unblinded asset id. + * :param asset_out_len: Length of ``asset_out``. Must be ``ASSET_TAG_LEN``. + * :param abf_out: Buffer to receive asset blinding factor. + * :param abf_out_len: Length of ``abf_out``. Must be ``BLINDING_FACTOR_LEN``. + * :param vbf_out: Buffer to receive asset blinding factor. + * :param vbf_out_len: Length of ``vbf_out``. Must be ``BLINDING_FACTOR_LEN``. + * :param value_out: Destination for unblinded transaction output value. + */ WALLY_CORE_API int wally_asset_unblind_with_nonce( const unsigned char *nonce_hash, size_t nonce_hash_len, From 22abab9f0a7dc0a31cd7c4f4f577242652f8d9e5 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 15 Jul 2020 09:38:19 +1200 Subject: [PATCH 168/205] python: Add a script to auto-generate the CFFI function list This fixes a number of incorrect entries and adds the remaining 70+ calls that were missing from the list. --- docs/source/conf.py | 6 ++++++ tools/build_python_cffi.sh | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100755 tools/build_python_cffi.sh diff --git a/docs/source/conf.py b/docs/source/conf.py index ad95d5641..42ed6f6c5 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -3,6 +3,9 @@ # libwally-core documentation build configuration file SCANNING, DOCS, FUNC = 1, 2, 3 +from os import getenv +DUMP_FUNCS = getenv("WALLY_DOC_DUMP_FUNCS") is not None + def get_doc_lines(l): if l.startswith('.. '): return [' ' + l, ''] @@ -12,6 +15,9 @@ def output_func(docs, func): is_normal_ret = 'WALLY_CORE_API int' in func func = func[:-1].replace('WALLY_CORE_API','').strip() func = func.replace(',',', ').replace(' ', ' ') + if DUMP_FUNCS: + # Dump function definitions if requested + print ('%s' % func) ret = ['.. c:function:: ' + func, ''] is_variable_buffer_ret = 'unsigned char *bytes_out, size_t len, size_t *written' in func for l in docs: diff --git a/tools/build_python_cffi.sh b/tools/build_python_cffi.sh new file mode 100755 index 000000000..bb9da9106 --- /dev/null +++ b/tools/build_python_cffi.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Generate the CFFI function list used in src/tests/util.py +# Run to print the updated list and update util.py as needed. +# Only generates entries for documented functions, and requires +# that the user has sphinx documentation tool installed (package +# sphinx-doc on debian). + +# FIXME: 'int' is used only by wally_asset_rangeproof/wally_asset_rangeproof_with_nonce + +# This expression just replaces the various argument types with their +# CFFI type. struct 'words' is special cases as it is an opaque type +# and no struct definition is exposed to library users. +WALLY_DOC_DUMP_FUNCS="1" sphinx-build -b html -a -c docs/source docs/source docs/build/html 2>&1 | \ + grep '^int ' | \ + sed -e "s/(/',c_int,[/g" \ + -e "s/^int / ('/g" \ + -e 's/, /,/g' -e 's/const //g' | \ + perl -pe 's/int .*?[,)]/c_int,/g' | \ + perl -pe 's/size_t \*.*?[,)]/c_ulong_p,/g' | \ + perl -pe 's/size_t .*?[,)]/c_ulong,/g' | \ + perl -pe 's/uint32_t \*.*?[,)]/c_uint_p,/g' | \ + perl -pe 's/uint32_t .*?[,)]/c_uint,/g' | \ + perl -pe 's/uint64_t \*.*?,/POINTER(c_uint64),/g' | \ + perl -pe 's/uint64_t \*.*?\)/c_uint64_p,/g' | \ + perl -pe 's/uint64_t .*?[,)]/c_uint64,/g' | \ + perl -pe 's/unsigned char \*.*?[,)]/c_void_p,/g' | \ + perl -pe 's/char \*\*.*?[,)]/c_char_p_p,/g' | \ + perl -pe 's/char \*.*?[,)]/c_char_p,/g' | \ + perl -pe 's/void \*.*?[,)]/c_void_p,/g' | \ + perl -pe 's/struct ([a-z0-9_]*?) \*\*(.*?)[,)]/POINTER(POINTER(\1)),/g' | \ + perl -pe 's/struct ([a-z0-9_]*?) \*(.*?)[,)]/POINTER(\1),/g' | \ + sed -e 's/POINTER(words)/c_void_p/g' \ + -e 's/,/, /g' \ + -e 's/, $/]),/g' | sort + From 57eddc55df0bff9e3dc7e90da35ff1d575ebd942 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 15 Jul 2020 09:41:08 +1200 Subject: [PATCH 169/205] python: Update the CFFI test wrapper Now exposes every available function with correct types. Additionally, we add auto-return semantics for uin64_t output functions. --- src/test/util.py | 356 ++++++++++++++++++++++++++++++----------------- 1 file changed, 230 insertions(+), 126 deletions(-) diff --git a/src/test/util.py b/src/test/util.py index 7072a66e0..6f7a7c52f 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -27,7 +27,7 @@ _bzero_fn_t = CFUNCTYPE(c_void_p, c_ulong) _ec_nonce_fn_t = CFUNCTYPE(c_int, c_void_p, c_void_p, c_void_p, c_void_p, c_void_p, c_uint) -class operations(Structure): +class wally_operations(Structure): _fields_ = [('malloc_fn', _malloc_fn_t), ('free_fn', _free_fn_t), ('bzero_fn', _bzero_fn_t), @@ -53,6 +53,9 @@ class c_char_p_p_class(object): class c_ulong_p_class(object): pass c_ulong_p = c_ulong_p_class() +class c_uint64_p_class(object): + pass +c_uint64_p = c_uint64_p_class() # ctypes is missing this for some reason c_uint_p = POINTER(c_uint) @@ -87,7 +90,7 @@ class wally_tx_input(Structure): ('pegin_witness', POINTER(wally_tx_witness_stack))] class wally_tx_output(Structure): - _fields_ = [('satoshi', c_ulonglong), + _fields_ = [('satoshi', c_uint64), ('script', c_void_p), ('script_len', c_ulong), ('features', c_ubyte), @@ -112,35 +115,35 @@ class wally_tx(Structure): ('num_outputs', c_ulong), ('outputs_allocation_len', c_ulong),] -class keypath_item(Structure): +class wally_keypath_item(Structure): _fields_ = [('path', POINTER(c_ulong)), ('path_len', c_ulong), ('fingerprint', c_ubyte * 4), ('pubkey', c_ubyte * 65)] -class keypath_map(Structure): - _fields_ = [('items', POINTER(keypath_item)), +class wally_keypath_map(Structure): + _fields_ = [('items', POINTER(wally_keypath_item)), ('num_items', c_ulong), ('items_allocation_len', c_ulong)] -class partial_sigs_item(Structure): +class wally_partial_sigs_item(Structure): _fields_ = [('pubkey', c_ubyte * 65), ('sig', c_void_p), ('sig_len', c_ulong)] -class partial_sigs_map(Structure): - _fields_ = [('items', POINTER(partial_sigs_item)), +class wally_partial_sigs_map(Structure): + _fields_ = [('items', POINTER(wally_partial_sigs_item)), ('num_items', c_ulong), ('items_allocation_len', c_ulong)] -class unknowns_item(Structure): +class wally_unknowns_item(Structure): _fields_ = [('key', c_void_p), ('key_len', c_ulong), ('value', c_void_p), ('value_len', c_ulong)] -class unknowns_map(Structure): - _fields_ = [('items', POINTER(unknowns_item)), +class wally_unknowns_map(Structure): + _fields_ = [('items', POINTER(wally_unknowns_item)), ('num_items', c_ulong), ('items_allocation_len', c_ulong)] @@ -154,11 +157,11 @@ class wally_psbt_input(Structure): ('final_script_sig', c_void_p), ('final_script_sig_len', c_ulong), ('final_witness', POINTER(wally_tx_witness_stack)), - ('keypaths', POINTER(keypath_map)), - ('partial_sigs', POINTER(partial_sigs_map)), - ('unknowns', POINTER(unknowns_map)), + ('keypaths', POINTER(wally_keypath_map)), + ('partial_sigs', POINTER(wally_partial_sigs_map)), + ('unknowns', POINTER(wally_unknowns_map)), ('sighash_type', c_ulong), - ('value', c_ulonglong), + ('value', c_uint64), ('has_value', c_ulong), ('value_blinder', c_void_p), ('value_blinder_len', c_ulong), @@ -179,8 +182,8 @@ class wally_psbt_output(Structure): ('redeem_script_len', c_ulong), ('witness_script', c_void_p), ('witness_script_len', c_ulong), - ('keypaths', POINTER(keypath_map)), - ('unknowns', POINTER(unknowns_map)), + ('keypaths', POINTER(wally_keypath_map)), + ('unknowns', POINTER(wally_unknowns_map)), ('blinding_pubkey', c_ubyte * 65), ('has_blinding_pubkey', c_ulong), ('value_commitment', c_void_p), @@ -207,164 +210,252 @@ class wally_psbt(Structure): ('outputs', POINTER(wally_psbt_output)), ('num_outputs', c_ulong), ('outputs_allocation_len', c_ulong), - ('unknowns', POINTER(unknowns_map)), + ('unknowns', POINTER(wally_unknowns_map)), ('version', c_ulong)] for f in ( - ('wally_init', c_int, [c_uint]), - ('wally_cleanup', c_int, [c_uint]), - ('wally_is_elements_build', c_int, [c_ulong_p]), - ('wordlist_init', c_void_p, [c_char_p]), - ('wordlist_lookup_word', c_ulong, [c_void_p, c_char_p]), - ('wordlist_lookup_index', c_char_p, [c_void_p, c_ulong]), - ('wordlist_free', None, [c_void_p]), + # Internal functions ('mnemonic_from_bytes', c_char_p, [c_void_p, c_void_p, c_ulong]), ('mnemonic_to_bytes', c_int, [c_void_p, c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('wally_base58_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), - ('wally_base58_get_length', c_int, [c_char_p, c_ulong_p]), - ('wally_base58_to_bytes', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wordlist_free', None, [c_void_p]), + ('wordlist_init', c_void_p, [c_char_p]), + ('wordlist_lookup_index', c_char_p, [c_void_p, c_ulong]), + ('wordlist_lookup_word', c_ulong, [c_void_p, c_char_p]), + # Exported functions ('bip32_key_free', c_int, [POINTER(ext_key)]), + ('bip32_key_from_base58_alloc', c_int, [c_char_p, POINTER(POINTER(ext_key))]), + ('bip32_key_from_base58', c_int, [c_char_p, POINTER(ext_key)]), + ('bip32_key_from_parent_alloc', c_int, [POINTER(ext_key), c_uint, c_uint, POINTER(POINTER(ext_key))]), + ('bip32_key_from_parent', c_int, [POINTER(ext_key), c_uint, c_uint, POINTER(ext_key)]), + ('bip32_key_from_parent_path_alloc', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(POINTER(ext_key))]), + ('bip32_key_from_parent_path', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), + ('bip32_key_from_seed_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, POINTER(POINTER(ext_key))]), ('bip32_key_from_seed', c_int, [c_void_p, c_ulong, c_uint, c_uint, POINTER(ext_key)]), + ('bip32_key_get_fingerprint', c_int, [POINTER(ext_key), c_void_p, c_ulong]), + ('bip32_key_init_alloc', c_int, [c_uint, c_uint, c_uint, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(ext_key))]), ('bip32_key_serialize', c_int, [POINTER(ext_key), c_uint, c_void_p, c_ulong]), - ('bip32_key_unserialize', c_int, [c_void_p, c_uint, POINTER(ext_key)]), - ('bip32_key_from_parent', c_int, [c_void_p, c_uint, c_uint, POINTER(ext_key)]), - ('bip32_key_from_parent_path', c_int, [c_void_p, c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), - ('bip32_key_with_tweak_from_parent_path', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), - ('bip32_key_to_base58', c_int, [POINTER(ext_key), c_uint, c_char_p_p]), - ('bip32_key_from_base58', c_int, [c_char_p, POINTER(ext_key)]), - ('bip32_key_from_base58_alloc', c_int, [c_char_p, POINTER(POINTER(ext_key))]), ('bip32_key_strip_private_key', c_int, [POINTER(ext_key)]), - ('bip32_key_get_fingerprint', c_int, [POINTER(ext_key), c_void_p, c_ulong]), - ('bip38_raw_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('bip32_key_to_base58', c_int, [POINTER(ext_key), c_uint, c_char_p_p]), + ('bip32_key_unserialize_alloc', c_int, [c_void_p, c_ulong, POINTER(POINTER(ext_key))]), + ('bip32_key_unserialize', c_int, [c_void_p, c_ulong, POINTER(ext_key)]), + ('bip32_key_with_tweak_from_parent_path_alloc', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(POINTER(ext_key))]), + ('bip32_key_with_tweak_from_parent_path', c_int, [POINTER(ext_key), c_uint_p, c_ulong, c_uint, POINTER(ext_key)]), ('bip38_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_char_p_p]), - ('bip38_to_private_key', c_int, [c_char_p, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('bip38_raw_to_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('bip38_raw_get_flags', c_int, [c_void_p, c_ulong, c_ulong_p]), ('bip38_get_flags', c_int, [c_char_p, c_ulong_p]), + ('bip38_raw_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('bip38_raw_get_flags', c_int, [c_void_p, c_ulong, c_ulong_p]), + ('bip38_raw_to_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('bip38_to_private_key', c_int, [c_char_p, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), ('bip39_get_languages', c_int, [c_char_p_p]), - ('bip39_get_wordlist', c_int, [c_char_p, POINTER(c_void_p)]), ('bip39_get_word', c_int, [c_void_p, c_ulong, c_char_p_p]), + ('bip39_get_wordlist', c_int, [c_char_p, POINTER(c_void_p)]), ('bip39_mnemonic_from_bytes', c_int, [c_void_p, c_void_p, c_ulong, c_char_p_p]), ('bip39_mnemonic_to_bytes', c_int, [c_void_p, c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('bip39_mnemonic_validate', c_int, [c_void_p, c_char_p]), ('bip39_mnemonic_to_seed', c_int, [c_char_p, c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('wally_addr_segwit_from_bytes', c_int, [c_void_p, c_ulong, c_char_p, c_uint, c_char_p_p]), - ('wally_addr_segwit_to_bytes', c_int, [c_void_p, c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('bip39_mnemonic_validate', c_int, [c_void_p, c_char_p]), ('wally_address_to_scriptpubkey', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_to_address', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), + ('wally_addr_segwit_from_bytes', c_int, [c_void_p, c_ulong, c_char_p, c_uint, c_char_p_p]), + ('wally_addr_segwit_to_bytes', c_int, [c_char_p, c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_aes_cbc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_aes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('wally_asset_blinding_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_blinding_key_to_ec_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_final_vbf', c_int, [POINTER(c_uint64), c_ulong, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_generator_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_asset_pak_whitelistproof', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), + ('wally_asset_pak_whitelistproof_size', c_int, [c_ulong, c_ulong_p]), + ('wally_asset_rangeproof', c_int, [c_uint64, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint64, c_int, c_int, c_void_p, c_ulong, c_ulong_p]), + ('wally_asset_surjectionproof', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), + ('wally_asset_surjectionproof_size', c_int, [c_ulong, c_ulong_p]), + ('wally_asset_unblind', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint64_p]), + ('wally_asset_unblind_with_nonce', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint64_p]), + ('wally_asset_value_commitment', c_int, [c_uint64, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_base58_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), + ('wally_base58_get_length', c_int, [c_char_p, c_ulong_p]), + ('wally_base58_to_bytes', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_bip32_key_to_address', c_int, [POINTER(ext_key), c_uint, c_uint, c_char_p_p]), ('wally_bip32_key_to_addr_segwit', c_int, [POINTER(ext_key), c_char_p, c_uint, c_char_p_p]), + ('wally_bzero', c_int, [c_void_p, c_ulong]), + ('wally_cleanup', c_int, [c_uint]), ('wally_confidential_addr_from_addr', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_char_p_p]), + ('wally_confidential_addr_from_addr_segwit', c_int, [c_char_p, c_char_p, c_char_p, c_void_p, c_ulong, c_char_p_p]), + ('wally_confidential_addr_segwit_to_ec_public_key', c_int, [c_char_p, c_char_p, c_void_p, c_ulong]), ('wally_confidential_addr_to_addr', c_int, [c_char_p, c_uint, c_char_p_p]), + ('wally_confidential_addr_to_addr_segwit', c_int, [c_char_p, c_char_p, c_char_p, c_char_p_p]), ('wally_confidential_addr_to_ec_public_key', c_int, [c_char_p, c_uint, c_void_p, c_ulong]), - ('wally_asset_blinding_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_asset_blinding_key_to_ec_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_asset_unblind', c_int, [c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_asset_unblind_with_nonce', c_int, [c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_char_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_asset_pak_whitelistproof', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_sha256d', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_hash160', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_hex_from_bytes', c_int, [c_void_p, c_ulong, c_char_p_p]), - ('wally_hex_to_bytes', c_int, [c_char_p, c_void_p, c_ulong, c_ulong_p]), - ('wally_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), - ('wally_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), - ('wally_aes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('wally_aes_cbc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_pbkdf2_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_ulong, c_void_p, c_ulong]), - ('wally_pbkdf2_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_ulong, c_void_p, c_ulong]), - ('wally_scrypt', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_uint, c_void_p, c_ulong]), - ('wally_secp_randomize', c_int, [c_void_p, c_ulong]), + ('wally_ecdh', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_private_key_verify', c_int, [c_void_p, c_ulong]), - ('wally_ec_public_key_verify', c_int, [c_void_p, c_ulong]), ('wally_ec_public_key_decompress', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_ec_public_key_negate', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_public_key_from_private_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_ec_public_key_negate', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_ec_public_key_verify', c_int, [c_void_p, c_ulong]), ('wally_ec_sig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), ('wally_ec_sig_from_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_sig_normalize', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_sig_to_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), - ('wally_ec_sig_to_public_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), + ('wally_ec_sig_to_public_key', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_ec_sig_verify', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), - ('wally_ecdh', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p]), - ('wally_get_operations', c_int, [POINTER(operations)]), - ('wally_set_operations', c_int, [POINTER(operations)]), + ('wally_elements_pegin_contract_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_elements_pegout_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_elements_pegout_script_size', c_int, [c_ulong, c_ulong, c_ulong, c_ulong, c_ulong_p]), ('wally_format_bitcoin_message', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_free_string', c_int, [c_char_p]), + ('wally_get_operations', c_int, [POINTER(wally_operations)]), + ('wally_hash160', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_hex_from_bytes', c_int, [c_void_p, c_ulong, c_char_p_p]), + ('wally_hex_to_bytes', c_int, [c_char_p, c_void_p, c_ulong, c_ulong_p]), + ('wally_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_init', c_int, [c_uint]), + ('wally_is_elements_build', c_int, [c_ulong_p]), + ('wally_keypath_map_add', c_int, [POINTER(wally_keypath_map), c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong]), + ('wally_keypath_map_find', c_int, [POINTER(wally_keypath_map), c_void_p, c_ulong, c_ulong_p]), + ('wally_keypath_map_free', c_int, [POINTER(wally_keypath_map)]), + ('wally_keypath_map_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_keypath_map))]), + ('wally_partial_sigs_map_add', c_int, [POINTER(wally_partial_sigs_map), c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_partial_sigs_map_find', c_int, [POINTER(wally_partial_sigs_map), c_void_p, c_ulong, c_ulong_p]), + ('wally_partial_sigs_map_free', c_int, [POINTER(wally_partial_sigs_map)]), + ('wally_partial_sigs_map_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_partial_sigs_map))]), + ('wally_pbkdf2_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_pbkdf2_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), + ('wally_psbt_elements_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_elements_input_clear_value', c_int, [POINTER(wally_psbt_input)]), + ('wally_psbt_elements_input_init_alloc', c_int, [POINTER(wally_tx), POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(wally_keypath_map), POINTER(wally_partial_sigs_map), POINTER(wally_unknowns_map), c_uint, c_uint64, c_uint, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_psbt_input))]), + ('wally_psbt_elements_input_set_asset_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_elements_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_elements_input_set_claim_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_elements_input_set_genesis_hash', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_elements_input_set_peg_in_tx', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), + ('wally_psbt_elements_input_set_txout_proof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_elements_input_set_value_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_elements_input_set_value', c_int, [POINTER(wally_psbt_input), c_uint64]), + ('wally_psbt_elements_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_keypath_map), POINTER(wally_unknowns_map), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_psbt_output))]), + ('wally_psbt_elements_output_set_asset_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_elements_output_set_asset_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_elements_output_set_blinding_pubkey', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_elements_output_set_nonce_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_elements_output_set_range_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_elements_output_set_surjection_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_elements_output_set_value_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_elements_output_set_value_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_extract', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]), + ('wally_psbt_finalize', c_int, [POINTER(wally_psbt)]), + ('wally_psbt_free', c_int, [POINTER(wally_psbt)]), + ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_from_bytes', c_int, [c_void_p, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_uint, c_ulong_p]), + ('wally_psbt_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_input_free', c_int, [POINTER(wally_psbt_input)]), + ('wally_psbt_input_init_alloc', c_int, [POINTER(wally_tx), POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(wally_keypath_map), POINTER(wally_partial_sigs_map), POINTER(wally_unknowns_map), c_uint, POINTER(POINTER(wally_psbt_input))]), + ('wally_psbt_input_set_final_script_sig', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_final_witness', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx_witness_stack)]), + ('wally_psbt_input_set_keypaths', c_int, [POINTER(wally_psbt_input), POINTER(wally_keypath_map)]), + ('wally_psbt_input_set_non_witness_utxo', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), + ('wally_psbt_input_set_partial_sigs', c_int, [POINTER(wally_psbt_input), POINTER(wally_partial_sigs_map)]), + ('wally_psbt_input_set_redeem_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_sighash_type', c_int, [POINTER(wally_psbt_input), c_uint]), + ('wally_psbt_input_set_unknowns', c_int, [POINTER(wally_psbt_input), POINTER(wally_unknowns_map)]), + ('wally_psbt_input_set_witness_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_witness_utxo', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx_output)]), + ('wally_psbt_is_elements', c_int, [POINTER(wally_psbt), c_ulong_p]), + ('wally_psbt_output_free', c_int, [POINTER(wally_psbt_output)]), + ('wally_psbt_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_keypath_map), POINTER(wally_unknowns_map), POINTER(POINTER(wally_psbt_output))]), + ('wally_psbt_output_set_keypaths', c_int, [POINTER(wally_psbt_output), POINTER(wally_keypath_map)]), + ('wally_psbt_output_set_redeem_script', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_unknowns', c_int, [POINTER(wally_psbt_output), POINTER(wally_unknowns_map)]), + ('wally_psbt_output_set_witness_script', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), + ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), + ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_uint, c_char_p_p]), + ('wally_psbt_to_bytes', c_int, [POINTER(wally_psbt), c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_csv_2of2_then_1_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_csv_2of3_then_2_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_get_type', c_int, [c_void_p, c_ulong, c_ulong_p]), - ('wally_script_push_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_op_return_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_p2pkh_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_p2sh_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_csv_2of2_then_1_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptpubkey_csv_2of3_then_2_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptpubkey_to_address', c_int, [c_void_p, c_ulong, c_uint, c_char_p_p]), + ('wally_script_push_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_scriptsig_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptsig_p2pkh_from_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptsig_p2pkh_from_sig', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_scriptsig_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_elements_pegout_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_elements_pegin_contract_script_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_witness_program_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_symmetric_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_scrypt', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_secp_randomize', c_int, [c_void_p, c_ulong]), + ('wally_set_operations', c_int, [POINTER(wally_operations)]), + ('wally_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_sha256d', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_sha256_midstate', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), ('wally_symmetric_key_from_parent', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_void_p, c_ulong]), - ('wally_tx_to_hex', c_int, [POINTER(wally_tx), c_uint, c_char_p_p]), - ('wally_tx_from_hex', c_int, [c_char_p, c_uint, POINTER(POINTER(wally_tx))]), - ('wally_tx_to_bytes', c_int, [POINTER(wally_tx), c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_tx_from_bytes', c_int, [c_void_p, c_ulong, c_uint, POINTER(POINTER(wally_tx))]), - ('wally_tx_init_alloc', c_int, [c_uint, c_uint, c_ulong, c_ulong, POINTER(POINTER(wally_tx))]), + ('wally_symmetric_key_from_seed', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_add_elements_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_add_elements_raw_output', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint]), + ('wally_tx_add_input', c_int, [POINTER(wally_tx), POINTER(wally_tx_input)]), + ('wally_tx_add_output', c_int, [POINTER(wally_tx), POINTER(wally_tx_output)]), + ('wally_tx_add_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_add_raw_output', c_int, [POINTER(wally_tx), c_uint64, c_void_p, c_ulong, c_uint]), ('wally_tx_clone', c_int, [POINTER(wally_tx), c_uint, POINTER(POINTER(wally_tx))]), + ('wally_tx_confidential_value_from_satoshi', c_int, [c_uint64, c_void_p, c_ulong]), + ('wally_tx_confidential_value_to_satoshi', c_int, [c_void_p, c_ulong, c_uint64_p]), + ('wally_tx_elements_input_init_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_input))]), + ('wally_tx_elements_input_is_pegin', c_int, [POINTER(wally_tx_input), c_ulong_p]), + ('wally_tx_elements_input_issuance_free', c_int, [POINTER(wally_tx_input)]), + ('wally_tx_elements_input_issuance_set', c_int, [POINTER(wally_tx_input), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_issuance_calculate_asset', c_int, [c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_issuance_calculate_reissuance_token', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong]), + ('wally_tx_elements_issuance_generate_entropy', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_output_commitment_free', c_int, [POINTER(wally_tx_output)]), + ('wally_tx_elements_output_commitment_set', c_int, [POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_tx_elements_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_tx_output))]), ('wally_tx_free', c_int, [POINTER(wally_tx)]), + ('wally_tx_from_bytes', c_int, [c_void_p, c_ulong, c_uint, POINTER(POINTER(wally_tx))]), + ('wally_tx_from_hex', c_int, [c_char_p, c_uint, POINTER(POINTER(wally_tx))]), + ('wally_tx_get_btc_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_uint64, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_tx_get_elements_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), ('wally_tx_get_length', c_int, [POINTER(wally_tx), c_uint, c_ulong_p]), + ('wally_tx_get_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint64, c_uint, c_uint, c_uint, c_void_p, c_ulong]), + ('wally_tx_get_total_output_satoshi', c_int, [POINTER(wally_tx), c_uint64_p]), + ('wally_tx_get_txid', c_int, [POINTER(wally_tx), c_void_p, c_ulong]), ('wally_tx_get_vsize', c_int, [POINTER(wally_tx), c_ulong_p]), ('wally_tx_get_weight', c_int, [POINTER(wally_tx), c_ulong_p]), - ('wally_tx_vsize_from_weight', c_int, [c_ulong, c_ulong_p]), - ('wally_tx_get_total_output_satoshi', c_int, [POINTER(wally_tx), POINTER(c_ulonglong)]), ('wally_tx_get_witness_count', c_int, [POINTER(wally_tx), c_ulong_p]), - ('wally_tx_get_btc_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_ulonglong, c_uint, c_uint, c_void_p, c_ulong]), - ('wally_tx_get_elements_signature_hash', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), - ('wally_tx_witness_stack_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_tx_witness_stack))]), - ('wally_tx_witness_stack_free', c_int, [POINTER(wally_tx_witness_stack)]), - ('wally_tx_witness_stack_add', c_int, [POINTER(wally_tx_witness_stack), c_void_p, c_ulong]), - ('wally_tx_witness_stack_add_dummy', c_int, [POINTER(wally_tx_witness_stack), c_uint]), - ('wally_tx_witness_stack_set', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_void_p, c_ulong]), - ('wally_tx_witness_stack_set_dummy', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_uint]), - ('wally_tx_output_init_alloc', c_int, [c_ulonglong, c_void_p, c_ulong, POINTER(POINTER(wally_tx_output))]), - ('wally_tx_output_free', c_int, [POINTER(wally_tx_output)]), - ('wally_tx_add_output', c_int, [POINTER(wally_tx), POINTER(wally_tx_output)]), - ('wally_tx_add_raw_output', c_int, [POINTER(wally_tx), c_ulonglong, c_void_p, c_ulong, c_uint]), - ('wally_tx_add_elements_raw_output', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_uint]), - ('wally_tx_remove_output', c_int, [POINTER(wally_tx), c_ulong]), - ('wally_tx_input_init_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_input))]), + ('wally_tx_init_alloc', c_int, [c_uint, c_uint, c_ulong, c_ulong, POINTER(POINTER(wally_tx))]), ('wally_tx_input_free', c_int, [POINTER(wally_tx_input)]), - ('wally_tx_add_input', c_int, [POINTER(wally_tx), POINTER(wally_tx_input)]), - ('wally_tx_add_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), - ('wally_tx_add_elements_raw_input', c_int, [POINTER(wally_tx), c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), c_uint]), - ('wally_tx_get_txid', c_int, [POINTER(wally_tx), c_void_p, c_ulong]), + ('wally_tx_input_init_alloc', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_input))]), + ('wally_tx_is_coinbase', c_int, [POINTER(wally_tx), c_ulong_p]), + ('wally_tx_is_elements', c_int, [POINTER(wally_tx), c_ulong_p]), + ('wally_tx_output_clone_alloc', c_int, [POINTER(wally_tx_output), POINTER(POINTER(wally_tx_output))]), + ('wally_tx_output_clone', c_int, [POINTER(wally_tx_output), POINTER(wally_tx_output)]), + ('wally_tx_output_free', c_int, [POINTER(wally_tx_output)]), + ('wally_tx_output_init_alloc', c_int, [c_uint64, c_void_p, c_ulong, POINTER(POINTER(wally_tx_output))]), ('wally_tx_remove_input', c_int, [POINTER(wally_tx), c_ulong]), + ('wally_tx_remove_output', c_int, [POINTER(wally_tx), c_ulong]), ('wally_tx_set_input_script', c_int, [POINTER(wally_tx), c_ulong, c_void_p, c_ulong]), ('wally_tx_set_input_witness', c_int, [POINTER(wally_tx), c_ulong, POINTER(wally_tx_witness_stack)]), - ('wally_tx_confidential_value_from_satoshi', c_int, [c_ulonglong, c_void_p, c_ulong]), + ('wally_tx_to_bytes', c_int, [POINTER(wally_tx), c_uint, c_void_p, c_ulong, c_ulong_p]), + ('wally_tx_to_hex', c_int, [POINTER(wally_tx), c_uint, c_char_p_p]), + ('wally_tx_vsize_from_weight', c_int, [c_ulong, c_ulong_p]), + ('wally_tx_witness_stack_add', c_int, [POINTER(wally_tx_witness_stack), c_void_p, c_ulong]), + ('wally_tx_witness_stack_add_dummy', c_int, [POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_witness_stack_free', c_int, [POINTER(wally_tx_witness_stack)]), + ('wally_tx_witness_stack_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_tx_witness_stack_set', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_void_p, c_ulong]), + ('wally_tx_witness_stack_set_dummy', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_uint]), + ('wally_unknowns_map_add', c_int, [POINTER(wally_unknowns_map), c_void_p, c_ulong, c_void_p, c_ulong]), + ('wally_unknowns_map_find', c_int, [POINTER(wally_unknowns_map), c_void_p, c_ulong, c_ulong_p]), + ('wally_unknowns_map_free', c_int, [POINTER(wally_unknowns_map)]), + ('wally_unknowns_map_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_unknowns_map))]), ('wally_wif_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_char_p_p]), + ('wally_wif_is_uncompressed', c_int, [c_char_p, c_ulong_p]), ('wally_wif_to_address', c_int, [c_char_p, c_uint, c_uint, c_char_p_p]), ('wally_wif_to_bytes', c_int, [c_char_p, c_uint, c_uint, c_void_p, c_ulong]), ('wally_wif_to_public_key', c_int, [c_char_p, c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_wif_is_uncompressed', c_int, [c_char_p, c_ulong_p]), - ('wally_psbt_input_init_alloc', c_int, [POINTER(wally_tx), POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(keypath_map), POINTER(partial_sigs_map), POINTER(unknowns_map), c_ulong, POINTER(POINTER(wally_psbt_input))]), - ('wally_psbt_input_free', c_int, [POINTER(wally_psbt_input)]), - ('wally_psbt_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(keypath_map), POINTER(unknowns_map), c_ulong, POINTER(POINTER(wally_psbt_output))]), - ('wally_psbt_output_free', c_int, [POINTER(wally_psbt_output)]), - ('wally_psbt_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_free', c_int, [POINTER(wally_psbt)]), - ('wally_psbt_from_bytes', c_int, [c_void_p, c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_to_bytes', c_int, [POINTER(wally_psbt), c_uint, c_void_p, c_ulong, c_ulong_p]), - ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_uint, c_ulong_p]), - ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_uint32, c_char_p_p]), - ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), - ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), - ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), - ('wally_psbt_finalize', c_int, [POINTER(wally_psbt)]), - ('wally_psbt_extract', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]) + ('wally_witness_multisig_from_bytes', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint_p, c_ulong, c_uint, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_witness_p2wpkh_from_der', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_witness_p2wpkh_from_sig', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, POINTER(POINTER(wally_tx_witness_stack))]), + ('wally_witness_program_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_void_p, c_ulong, c_ulong_p]), ): def bind_fn(name, res, args): @@ -373,7 +464,8 @@ def bind_fn(name, res, args): fn.restype, fn.argtypes = res, args return fn except AttributeError: - # Internal function and 'configure --enable-export-all' not used + # Internal function and 'configure --enable-export-all' not used, + # or an Elements function and Elements support not enabled. return None def in_string_fn_wrapper(fn, pos, *args): @@ -398,22 +490,34 @@ def int_fn_wrapper(fn, *args): ret = fn(*new_args) return [p.value, (ret, p.value)][fn.restype is not None] + def int64_fn_wrapper(fn, *args): + p = c_uint64() + new_args = [a for a in args] + [byref(p)] + ret = fn(*new_args) + return [p.value, (ret, p.value)][fn.restype is not None] + name, restype, argtypes = f is_str_fn = len(argtypes) and type(argtypes[-1]) is c_char_p_p_class is_int_fn = len(argtypes) and type(argtypes[-1]) is c_ulong_p_class + is_int64_fn = len(argtypes) and type(argtypes[-1]) is c_uint64_p_class in_str_pos = [i for (i, t) in enumerate(argtypes) if t == c_char_p] if is_str_fn: argtypes[-1] = POINTER(c_char_p) elif is_int_fn: argtypes[-1] = POINTER(c_ulong) + elif is_int64_fn: + argtypes[-1] = POINTER(c_uint64) fn = bind_fn(name, restype, argtypes) def mkstr(f): return lambda *args: string_fn_wrapper(f, *args) def mkint(f): return lambda *args: int_fn_wrapper(f, *args) + def mkint64(f): return lambda *args: int64_fn_wrapper(f, *args) def mkinstr(f, pos): return lambda *args: in_string_fn_wrapper(f, pos, *args) if is_str_fn: fn = mkstr(fn) elif is_int_fn: fn = mkint(fn) + elif is_int64_fn: + fn = mkint64(fn) if len(in_str_pos) > 0 and fn: for pos in in_str_pos: fn = mkinstr(fn, pos) @@ -444,8 +548,8 @@ def make_cbuffer(hex_in): assert wally_secp_randomize(urandom(32), 32) == WALLY_OK, 'Random init failed' -_original_ops = operations() -_new_ops = operations() +_original_ops = wally_operations() +_new_ops = wally_operations() for ops in (_original_ops, _new_ops): assert wally_get_operations(byref(ops)) == WALLY_OK From 92bfd309255c0e256f86665456133ec6e51e983a Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 16 Jul 2020 23:55:43 +1200 Subject: [PATCH 170/205] script: Fix multisig limit for scriptpubkeys/scriptsigs to 15, update tests Thanks to benma for the report. --- include/wally_script.h | 2 ++ src/script.c | 10 ++++----- src/test/test_script.py | 45 ++++++++++++++++++++++++----------------- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/include/wally_script.h b/include/wally_script.h index f94e83faa..3b102a19d 100644 --- a/include/wally_script.h +++ b/include/wally_script.h @@ -333,6 +333,8 @@ WALLY_CORE_API int wally_scriptpubkey_p2sh_from_bytes( * :param bytes_out: Destination for the resulting scriptPubkey. * :param len: The length of ``bytes_out`` in bytes. * :param written: Destination for the number of bytes written to ``bytes_out``. + * + * .. note:: A maximum of 15 keys are allowed to be passed. */ WALLY_CORE_API int wally_scriptpubkey_multisig_from_bytes( const unsigned char *bytes, diff --git a/src/script.c b/src/script.c index 4f93d42c3..8beaa36b4 100644 --- a/src/script.c +++ b/src/script.c @@ -553,13 +553,13 @@ int wally_scriptpubkey_multisig_from_bytes( size_t n_pubkeys = bytes_len / EC_PUBLIC_KEY_LEN; size_t script_len = 3 + (n_pubkeys * (EC_PUBLIC_KEY_LEN + 1)); size_t i; - unsigned char pubkey_bytes[16 * EC_PUBLIC_KEY_LEN]; + unsigned char pubkey_bytes[15 * EC_PUBLIC_KEY_LEN]; if (written) *written = 0; if (!bytes || !bytes_len || bytes_len % EC_PUBLIC_KEY_LEN || - n_pubkeys < 1 || n_pubkeys > 16 || threshold < 1 || threshold > 16 || + n_pubkeys < 1 || n_pubkeys > 15 || threshold < 1 || threshold > 15 || threshold > n_pubkeys || (flags & ~WALLY_SCRIPT_MULTISIG_SORTED) || !bytes_out || !written) return WALLY_EINVAL; @@ -594,8 +594,8 @@ int wally_scriptsig_multisig_from_bytes( unsigned char *bytes_out, size_t len, size_t *written) { #define MAX_DER (EC_SIGNATURE_DER_MAX_LEN + 1) - unsigned char der_buff[16 * MAX_DER], *p = bytes_out; - size_t der_len[16]; + unsigned char der_buff[15 * MAX_DER], *p = bytes_out; + size_t der_len[15]; size_t i, required = 0, n_sigs = bytes_len / EC_SIGNATURE_LEN; int ret = WALLY_OK; @@ -603,7 +603,7 @@ int wally_scriptsig_multisig_from_bytes( *written = 0; if (!script || !script_len || !bytes || !bytes_len || bytes_len % EC_SIGNATURE_LEN || - n_sigs < 1 || n_sigs > 16 || !sighash || sighash_len != n_sigs || + n_sigs < 1 || n_sigs > 15 || !sighash || sighash_len != n_sigs || flags || !bytes_out || !written) return WALLY_EINVAL; diff --git a/src/test/test_script.py b/src/test/test_script.py index ed3e73513..c9cc9849b 100755 --- a/src/test/test_script.py +++ b/src/test/test_script.py @@ -6,7 +6,7 @@ SCRIPT_TYPE_P2SH = 0x4 SCRIPT_TYPE_MULTISIG = 0x20 -WALLY_SCRIPT_MULTISIG_SORTED = 0x8 +SCRIPT_MULTISIG_SORTED = 0x8 SCRIPT_HASH160 = 0x1 SCRIPT_SHA256 = 0x2 @@ -24,10 +24,11 @@ SH, SH_LEN = make_cbuffer('11' * 20) # Fake script hash MPK_2, MPK_2_LEN = make_cbuffer('11' * 33 * 2) # Fake multiple (2) pubkeys MPK_3, MPK_3_LEN = make_cbuffer('11' * 33 * 3) # Fake multiple (3) pubkeys -MPK_3_SORTED, MPK_3_SORTED_LEN = make_cbuffer('01'*33 + '10'*33 + '11'*33) # Fake multiple (3) sorted pubkeys -MPK_3_SORTED_REVERSE, MPK_3_SORTED_LEN = make_cbuffer('11'*33 + '10'*33 + '01'*33) # Fake multiple (3) sorted pubkeys, in reverse order -MPK_3_SORTED_KEY_PUSH = '21'+'01'*33 + '21'+'10'*33 + '21'+'11'*33 -MPK_17, MPK_17_LEN = make_cbuffer('11' * 33 * 17) # Fake multiple (17) pubkeys +SPK, SPK_LEN = make_cbuffer('01'*33 + '10'*33 + '11'*33) # Fake multiple (3) sorted pubkeys +RPK, _ = make_cbuffer('11'*33 + '10'*33 + '01'*33) # Fake multiple (3) sorted pubkeys, in reverse order +SPK_KEY_PUSH = '21'+'01'*33 + '21'+'10'*33 + '21'+'11'*33 +MPK_15, MPK_15_LEN = make_cbuffer('11' * 33 * 15) # Fake multiple (15) pubkeys +MPK_16, MPK_16_LEN = make_cbuffer('11' * 33 * 16) # Fake multiple (16) pubkeys SIG, SIG_LEN = make_cbuffer('11' * 64) # Fake signature SIG_LARGE, SIG_LARGE_LEN = make_cbuffer('ff' * 64) # Fake out of range signature @@ -142,7 +143,7 @@ def test_scriptpubkey_multisig_from_bytes(self): (MPK_2, 0, 1, 0, out, out_len), # Empty bytes (MPK_2, MPK_2_LEN+1, 1, 0, out, out_len), # Unsupported bytes len (SH, SH_LEN, 1, 0, out, out_len), # Too few pubkeys - (MPK_17, MPK_17_LEN, 1, 0, out, out_len), # Too many pubkeys + (MPK_16, MPK_16_LEN, 1, 0, out, out_len), # Too many pubkeys (MPK_2, MPK_2_LEN, 0, 0, out, out_len), # Too low threshold (MPK_2, MPK_2_LEN, 17, 0, out, out_len), # Too high threshold (MPK_2, MPK_2_LEN, 3, 0, out, out_len), # Inconsistent threshold @@ -154,28 +155,34 @@ def test_scriptpubkey_multisig_from_bytes(self): self.assertEqual(ret, (WALLY_EINVAL, 0)) # Valid cases - out, out_len = make_cbuffer('00' * 33 * 4) + out, out_len = make_cbuffer('00' * 33 * 16) valid_args = [ - [(MPK_2, MPK_2_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*2+'52ae'], # 1of2 - [(MPK_2, MPK_2_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*2+'52ae'], # 2of2 - [(MPK_3, MPK_3_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*3+'53ae'], # 1of3 - [(MPK_3, MPK_3_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*3+'53ae'], # 2of3 - [(MPK_3, MPK_3_LEN, 3, 0, out, out_len), '53'+('21'+'11'*33)*3+'53ae'], # 3of3 - [(MPK_3_SORTED, MPK_3_SORTED_LEN, 1, 0, out, out_len), '51'+ MPK_3_SORTED_KEY_PUSH + '53ae'], # 1of3 sorted - [(MPK_3_SORTED, MPK_3_SORTED_LEN, 1, WALLY_SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ MPK_3_SORTED_KEY_PUSH + '53ae'], # 1of3 sorted (WALLY_SCRIPT_MULTISIG_SORTED should have no effect) - [(MPK_3_SORTED_REVERSE, MPK_3_SORTED_LEN, 1, WALLY_SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ MPK_3_SORTED_KEY_PUSH + '53ae'], # 1of3 sorted reverse (BIP67) + [(MPK_2, MPK_2_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*2+'52ae'], # 1of2 + [(MPK_2, MPK_2_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*2+'52ae'], # 2of2 + [(MPK_3, MPK_3_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*3+'53ae'], # 1of3 + [(MPK_3, MPK_3_LEN, 2, 0, out, out_len), '52'+('21'+'11'*33)*3+'53ae'], # 2of3 + [(MPK_3, MPK_3_LEN, 3, 0, out, out_len), '53'+('21'+'11'*33)*3+'53ae'], # 3of3 + [(MPK_15, MPK_15_LEN, 1, 0, out, out_len), '51'+('21'+'11'*33)*15+'5fae'], # 1of15 + [(MPK_15, MPK_15_LEN, 15, 0, out, out_len), '5f'+('21'+'11'*33)*15+'5fae'], # 15of15 + # 1of3 sorted + [(SPK, SPK_LEN, 1, 0, out, out_len), '51'+ SPK_KEY_PUSH + '53ae'], + # 1of3 sorted (SCRIPT_MULTISIG_SORTED should have no effect) + [(SPK, SPK_LEN, 1, SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ SPK_KEY_PUSH + '53ae'], + # 1of3 sorted reverse (BIP67) + [(RPK, SPK_LEN, 1, SCRIPT_MULTISIG_SORTED, out, out_len), '51'+ SPK_KEY_PUSH + '53ae'], ] for args, exp_script in valid_args: - script_len = 3 + (args[1] // 33 * (33 + 1)) + (pubkeys, pubkeys_len, threshold, flags, out, out_len) = args + script_len = 3 + (pubkeys_len // 33 * (33 + 1)) ret = wally_scriptpubkey_multisig_from_bytes(*args) self.assertEqual(ret, (WALLY_OK, script_len)) - self.assertEqual(args[4][:script_len], unhexlify(exp_script)) + self.assertEqual(out[:script_len], unhexlify(exp_script)) # Check the script is identified by scriptpubkey_get_type ret = wally_scriptpubkey_get_type(out, script_len) self.assertEqual(ret, (WALLY_OK, SCRIPT_TYPE_MULTISIG)) # Check a too-short output buffer short_out, short_out_len = make_cbuffer('00' * (script_len - 1)) - short_args = (args[0], args[1], args[2], args[3], short_out, short_out_len) + short_args = (pubkeys, pubkeys_len, threshold, flags, short_out, short_out_len) ret = wally_scriptpubkey_multisig_from_bytes(*short_args) self.assertEqual(ret, (WALLY_OK, script_len)) @@ -311,7 +318,7 @@ def c_sighash(s): (RS_1of2, RS_1of2_LEN, None, SIG_LEN, c_sighash([0x01]), 1, 0, out, out_len), # Null bytes (RS_1of2, RS_1of2_LEN, SIG, 0, c_sighash([0x01]), 1, 0, out, out_len), # Empty bytes or too few sigs (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN+1, c_sighash([0x01]), 1, 0, out, out_len), # Unsupported bytes len - (RS_1of2, RS_1of2_LEN, SIG, 17, c_sighash([0x01]), 1, 0, out, out_len), # Too many sigs + (RS_1of2, RS_1of2_LEN, SIG, 16, c_sighash([0x01]), 1, 0, out, out_len), # Too many sigs (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN, None, 1, 0, out, out_len), # Null sighash (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN, c_sighash([0x01]), 2, 0, out, out_len), # Inconsistent sighash length (RS_1of2, RS_1of2_LEN, SIG, SIG_LEN, c_sighash([0x01]), 1, 1, out, out_len), # Unsupported flags From 213ef332516432881eb587edaa67d33b434357f7 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 17 Jul 2020 00:33:14 +1200 Subject: [PATCH 171/205] psbt: check script length as well as script when deserialising This covers the case where script_len is 0, pull_skip reading 0 bytes will succeed returning a non-NULL pointer (tx_output_init would then fail but this is clearer for the maintainer I feel). --- src/psbt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 66edd10ee..8e02c402e 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1423,7 +1423,7 @@ static int pull_psbt_input( } script_len = pull_varint(&val, &val_max); script = pull_skip(&val, &val_max, script_len); - if (!script) { + if (!script || !script_len) { return WALLY_EINVAL; } ret = wally_tx_elements_output_init_alloc(script, script_len, @@ -1443,7 +1443,7 @@ static int pull_psbt_input( amount = pull_le64(&val, &val_max); script_len = pull_varint(&val, &val_max); script = pull_skip(&val, &val_max, script_len); - if (!script) { + if (!script || !script_len) { return WALLY_EINVAL; } ret = wally_tx_output_init_alloc(amount, script, script_len, From fcbfc65c3f13a02bf7f4dcff0dc847e736efa603 Mon Sep 17 00:00:00 2001 From: k-matsuzawa Date: Tue, 10 Mar 2020 17:30:50 +0900 Subject: [PATCH 172/205] fix: mnemonic_w memory leak. and wordlist init/free memory leak. --- src/mnemonic.c | 10 ++++++---- src/wordlist.c | 7 ++++--- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/mnemonic.c b/src/mnemonic.c index 06f5f908a..0679315c8 100644 --- a/src/mnemonic.c +++ b/src/mnemonic.c @@ -62,18 +62,20 @@ char *mnemonic_from_bytes(const struct words *w, const unsigned char *bytes, siz int mnemonic_to_bytes(const struct words *w, const char *mnemonic, unsigned char *bytes_out, size_t len, size_t *written) { - struct words *mnemonic_w = wordlist_init(mnemonic); + struct words *mnemonic_w = NULL; size_t i; if (written) *written = 0; - if (!mnemonic_w) - return WALLY_ENOMEM; - if (!w || !bytes_out || !len) return WALLY_EINVAL; + mnemonic_w = wordlist_init(mnemonic); + + if (!mnemonic_w) + return WALLY_ENOMEM; + if ((mnemonic_w->len * w->bits + 7u) / 8u > len) goto cleanup; /* Return the length we would have written */ diff --git a/src/wordlist.c b/src/wordlist.c index fb1481931..5752ef385 100644 --- a/src/wordlist.c +++ b/src/wordlist.c @@ -20,6 +20,7 @@ static struct words *wordlist_alloc(const char *words, size_t len) { struct words *w = wally_malloc(sizeof(struct words)); if (w) { + wally_clear(w, sizeof(*w)); w->str = wally_strdup(words); if (w->str) { w->str_len = strlen(w->str); @@ -29,7 +30,6 @@ static struct words *wordlist_alloc(const char *words, size_t len) if (w->indices) return w; } - w->str_len = 0; wordlist_free(w); } return NULL; @@ -92,9 +92,10 @@ const char *wordlist_lookup_index(const struct words *w, size_t idx) void wordlist_free(struct words *w) { - if (w && w->str_len) { + if (w) { if (w->str) { - wally_clear((void *)w->str, w->str_len); + if (w->str_len) + wally_clear((void *)w->str, w->str_len); wally_free((void *)w->str); } if (w->indices) From d922969cc6baef37e67416676a9040918c1bc775 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 09:52:50 +1200 Subject: [PATCH 173/205] pullpush: Address review nit --- src/pullpush.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pullpush.h b/src/pullpush.h index 3922d487b..2d5146fa6 100644 --- a/src/pullpush.h +++ b/src/pullpush.h @@ -78,7 +78,7 @@ size_t pull_varlength(const unsigned char **cursor, size_t *max); * pull_subfield_start: initializes subcursor/submax to subfield_len at * cursor. These can then be used with pull_ methods like normal. * - * end_subfield_pull: updates *cursor and *max to point after the subfield has + * pull_subfield_end: updates *cursor and *max to point after the subfield has * been parsed. If *subcursor is NULL, it's equivalent to pull_failed. */ void pull_subfield_start(const unsigned char *const *cursor, const size_t *max, From d8461a1f08ae729add200bca5187a6955cf9b7d6 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 17 Jul 2020 11:08:28 +1200 Subject: [PATCH 174/205] c++: Update wally.hpp with missing/incorrect functions --- include/wally.hpp | 330 +++++++++++++++++++++++++++++++++------------- 1 file changed, 240 insertions(+), 90 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 4c72ca4b1..1329730fa 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -12,6 +12,7 @@ #include #include #include +#include #include /* These wrappers allow passing containers such as std::vector, std::array, @@ -46,7 +47,7 @@ template <> inline auto get_p(const std::nullptr_t& p) { #define WALLY_FN_3(F, N) inline int F(uint32_t i321) { return ::N(i321); } -#define WALLY_FN_333_BBBBBA(F, N) template inline int F(uint32_t i321, uint32_t i322, uint32_t i323, const I1 &i1, const I2 &i2, const I3 &i3, const I4 &i4, const I5 &i5, O * *out) { \ +#define WALLY_FN_333BBBBB_A(F, N) template inline int F(uint32_t i321, uint32_t i322, uint32_t i323, const I1 &i1, const I2 &i2, const I3 &i3, const I4 &i4, const I5 &i5, O * *out) { \ return ::N(i321, i322, i323, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), out); \ } @@ -54,10 +55,6 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(i321, i322, s1, s2, out); \ } -#define WALLY_FN_3_A(F, N) template inline int F(uint32_t i321, O * *out) { \ - return ::N(i321, out); \ -} - #define WALLY_FN_S_A(F, N) template inline int F(size_t s1, O * *out) { \ return ::N(s1, out); \ } @@ -66,6 +63,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(s1, s2, s3, out); \ } +#define WALLY_FN_SSSS_S(F, N) inline int F(size_t s1, size_t s2, size_t s3, size_t s4, size_t * written = 0) { \ + return ::N(s1, s2, s3, s4, written); \ +} + #define WALLY_FN_6_B(F, N) template inline int F(uint64_t i641, O & out) { \ return ::N(i641, WALLYO(out)); \ } @@ -74,9 +75,38 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(i641, WALLYB(i1), out); \ } -#define WALLY_FN_6BBBBBB_A(F, N) template \ - inline int F(uint64_t i641, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, O * *out) { \ - return ::N(i641, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), out); \ +#define WALLY_FN_BBBBBB_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), out); \ +} + +#define WALLY_FN_BBPPBBBBBBBB_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const P1& p1, const P2& p2, const I3 &i3, const I4& i4, \ + const I5 &i5, const I6 &i6, const I7 &i7, const I8& i8, const I9 &i9, const I10 &i10, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYP(p1), WALLYP(p2), WALLYB(i3), WALLYB(i4), \ + WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), WALLYB(i9), WALLYB(i10), out); \ +} + +#define WALLY_FN_PPBBBPPPP363BBBPBBB_A(F, N) \ + template \ + inline int F(const P1& p1, const P2& p2, const I1 &i1, const I2 &i2, const I3 &i3, const P3& p3, \ + const P4& p4, const P5& p5, const P6& p6, uint32_t i321, uint64_t i641, uint32_t i322, \ + const I4& i4, \ const I5 &i5, const I6 &i6, const P7& p7, const I7 &i7, const I8& i8, const I9 &i9, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYP(p3), \ + WALLYP(p4), WALLYP(p5), WALLYP(p6), i321, i641, i322, WALLYB(i4), WALLYB(i5), \ + WALLYB(i6), WALLYP(p7), WALLYB(i7), WALLYB(i8), WALLYB(i9), out); \ +} + +#define WALLY_FN_BB_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), out); \ +} + +#define WALLY_FN_BBB3_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3 &i3, uint32_t i321, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), i321, out); \ } #define WALLY_FN_B(F, N) template inline int F(const I &i1) { return ::N(WALLYB(i1)); } @@ -125,6 +155,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), WALLYB(i2), i321, out); \ } +#define WALLY_FN_BB3B(F, N) template inline int F(const I1 &i1, const I2 &i2, uint32_t i321, const I3 &i3) { \ + return ::N(WALLYB(i1), WALLYB(i2), i321, WALLYB(i3)); \ +} + #define WALLY_FN_BB3_B(F, N) template inline int F(const I1 &i1, const I2 &i2, uint32_t i321, O & out) { \ return ::N(WALLYB(i1), WALLYB(i2), i321, WALLYO(out)); \ } @@ -141,6 +175,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ } +#define WALLY_FN_6BB_B(F, N) template inline int F(uint64_t i641, const I1 &i1, const I2 &i2, O & out) { \ + return ::N(i641, WALLYB(i1), WALLYB(i2), WALLYO(out)); \ +} + #define WALLY_FN_BB_B(F, N) template inline int F(const I1 &i1, const I2 &i2, O & out) { \ return ::N(WALLYB(i1), WALLYB(i2), WALLYO(out)); \ } @@ -163,6 +201,14 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), WALLYO(out)); \ } +#define WALLY_FN_B_6(F, N) template inline int F(const I &i1, uint64_t *out) { \ + return ::N(WALLYB(i1), out); \ +} + +#define WALLY_FN_BSBB_B(F, N) template inline int F(const I1 &i1, size_t s1, const I2& i2, const I3& i3, O & out) { \ + return ::N(WALLYB(i1), s1, WALLYB(i2), WALLYB(i3), WALLYO(out)); \ +} + #define WALLY_FN_B_BS(F, N) template inline int F(const I &i1, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYB(i1), WALLYO(out), written ? written : &n); \ @@ -189,6 +235,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i321); \ } +#define WALLY_FN_PS3(F, N) template inline int F(const P1 &p1, size_t s1, uint32_t i321) { \ + return ::N(WALLYP(p1), s1, i321); \ +} + #define WALLY_FN_P6(F, N) template inline int F(const P1 &p1, uint64_t i641) { \ return ::N(WALLYP(p1), i641); \ } @@ -201,18 +251,18 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i321, i322, out); \ } -#define WALLY_FN_P3B(F, N) template inline int F(const P1 &p1, uint32_t i321, const I1 &i1, O & out) { \ - return ::N(WALLYP(p1), i321, WALLYB(i1), WALLYO(out)); \ +#define WALLY_FN_P3B_A(F, N) template inline int F(const P1 &p1, uint32_t i321, const I1 &i1, O * * out) { \ + return ::N(WALLYP(p1), i321, WALLYB(i1), out); \ } -#define WALLY_FN_P3B633_B(F, N) template inline int F(const P1 &p1, uint32_t i321, const I1 &i1, uint64_t i641, uint32_t i322, uint32_t i323, O & out) { \ - return ::N(WALLYP(p1), i321, WALLYB(i1), i641, i322, i323, WALLYO(out)); \ +#define WALLY_FN_PSB633_B(F, N) template inline int F(const P1 &p1, size_t s1, const I1 &i1, uint64_t i641, uint32_t i321, uint32_t i322, O & out) { \ + return ::N(WALLYP(p1), s1, WALLYB(i1), i641, i321, i322, WALLYO(out)); \ } -#define WALLY_FN_P3BB36333_B(F, N) \ +#define WALLY_FN_PSBB36333_B(F, N) \ template \ - inline int F(const P1 &p1, uint32_t i321, const I1 &i1, const I2 &i2, uint32_t i322, uint64_t i641, uint32_t i323, uint32_t i324, uint32_t i325, O & out) { \ - return ::N(WALLYP(p1), i321, WALLYB(i1), WALLYB(i2), i322, i641, i323, i324, i325, WALLYO(out)); \ + inline int F(const P1 &p1, size_t s1, const I1 &i1, const I2 &i2, uint32_t i321, uint64_t i641, uint32_t i322, uint32_t i323, uint32_t i324, O & out) { \ + return ::N(WALLYP(p1), s1, WALLYB(i1), WALLYB(i2), i321, i641, i322, i323, i324, WALLYO(out)); \ } #define WALLY_FN_P3_A(F, N) template inline int F(const P1 &p1, uint32_t i321, O * *out) { \ @@ -223,6 +273,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i321, WALLYO(out)); \ } +#define WALLY_FN_P33_B(F, N) template inline int F(const P1 &p1, uint32_t i321, uint32_t i322, O & out) { \ + return ::N(WALLYP(p1), i321, i322, WALLYO(out)); \ +} + #define WALLY_FN_P3_BS(F, N) template inline int F(const P1 &p1, uint32_t i321, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), i321, WALLYO(out), written ? written : &n); \ @@ -241,14 +295,14 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), i641, WALLYB(i1), i321); \ } -#define WALLY_FN_P6BB33_B(F, N) template \ - inline int F(const P1 &p1, uint64_t i641, const I1 &i1, const I2 &i2, uint32_t i321, uint32_t i322, O & out) { \ - return ::N(WALLYP(p1), i641, WALLYB(i1), WALLYB(i2), i321, i322, WALLYO(out)); \ +#define WALLY_FN_PSBB33_B(F, N) template \ + inline int F(const P1 &p1, size_t s1, const I1 &i1, const I2 &i2, uint32_t i321, uint32_t i322, O & out) { \ + return ::N(WALLYP(p1), s1, WALLYB(i1), WALLYB(i2), i321, i322, WALLYO(out)); \ } -#define WALLY_FN_P6BBBBBB3(F, N) template \ - inline int F(const P1 &p1, uint64_t i641, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, uint32_t i321) { \ - return ::N(WALLYP(p1), i641, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), i321); \ +#define WALLY_FN_PBBBBBB3(F, N) template \ + inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, uint32_t i321) { \ + return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), i321); \ } #define WALLY_FN_PB(F, N) template inline int F(const P1 &p1, const I1 &i1) { \ @@ -283,10 +337,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), i321, i322, WALLYB(i2), WALLYP(p1), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), out); \ } -#define WALLY_FN_PB33BPBBBBBB3(F, N) template \ +#define WALLY_FN_PB33BPBBBBBBP3(F, N) template \ inline int F(const P1 &p1, const I1 &i1, uint32_t i321, uint32_t i322, const I2 &i2, const P2 &p2, \ - const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, const I7& i7, const I8& i8, uint32_t i323) { \ - return ::N(WALLYP(p1), WALLYB(i1), i321, i322, WALLYB(i2), WALLYP(p2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), i323); \ + const I3 &i3, const I4& i4, const I5 &i5, const I6 &i6, const I7& i7, const I8& i8, const P3& p3, uint32_t i323) { \ + return ::N(WALLYP(p1), WALLYB(i1), i321, i322, WALLYB(i2), WALLYP(p2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), WALLYP(p3), i323); \ } #define WALLY_FN_PB3_A(F, N) template inline int F(const P1 &p1, const I1 &i1, uint32_t i321, O * *out) { \ @@ -309,27 +363,82 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), WALLYB(i1), written); \ } -#define WALLY_FN_PBBPP_A(F, N) template \ - inline int F(const P1 &p1, const I1 &i1, const I2 &i2, const P2 &p2, const P3 &p3, O * *out) { \ - return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2), WALLYP(p2), WALLYP(p3), out); \ +#define WALLY_FN_BBPP_A(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const P2 &p2, const P3 &p3, O * *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYP(p2), WALLYP(p3), out); \ } #define WALLY_FN_PP(F, N) template inline int F(const P1 &p1, const P2 &p2) { \ return ::N(WALLYP(p1), WALLYP(p2)); \ } +#define WALLY_FN_PPP_A(F, N) template inline int F(const P1 &p1, const P2 &p2, const P3& p3, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYP(p3), out); \ +} + +#define WALLY_FN_PP3_A(F, N) template inline int F(const P1 &p1, const P2 &p2, uint32_t i321, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), i321, out); \ +} + +#define WALLY_FN_PPPB_A(F, N) template \ + inline int F(const P1 &p1, const P2 &p2, const P3& p3, const I1& i1, O * *out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYP(p3), WALLYB(i1), out); \ +} + #define WALLY_FN_PP3_BS(F, N) template inline int F(const P1 &p1, const P2 &p2, uint32_t i321, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), WALLYP(p2), i321, WALLYO(out), written ? written : &n); \ return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ } +#define WALLY_FN_BBSBBB_BS(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, size_t s1, const I3& i3, const I4& i4, const I5& i5, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(WALLYB(i1), WALLYB(i2), s1, WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_BBBB3_BS(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3& i3, const I4& i4, uint32_t i321, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), i321, WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_BBBBBBB_BS(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, const I3& i3, const I4& i4, const I5& i5, const I6& i6, const I7& i7, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_6BBBBBBBB6II_BS(F, N) template \ + inline int F(uint64_t i641, const I1 &i1, const I2 &i2, const I3& i3, const I4& i4, const I5& i5, const I6& i6, const I7& i7, const I8& i8, uint64_t i642, int i321, int i322, O & out, size_t * written = 0) { \ + size_t n; \ + int ret = ::N(i641, WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), i642, i321, i322, WALLYO(out), written ? written : &n); \ + return written || ret != WALLY_OK ? ret : n == static_cast(out.size()) ? WALLY_OK : WALLY_EINVAL; \ +} + +#define WALLY_FN_BBBBB_BBB6(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, size_t s1, const I3& i3, const I4& i4, const I5& i5, O1& out1, O2& out2, O3& out3, uint64_t *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYO(out1), WALLYO(out2), WALLYO(out3), out); \ +} + +#define WALLY_FN_BBBBBB_BBB6(F, N) template \ + inline int F(const I1 &i1, const I2 &i2, size_t s1, const I3& i3, const I4& i4, const I5& i5, const I6& i6, O1& out1, O2& out2, O3& out3, uint64_t *out) { \ + return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYO(out1), WALLYO(out2), WALLYO(out3), out); \ +} + #define WALLY_FN_PPBBBPPPP3_A(F, N) template \ inline int F(const P1 &p1, const P2 &p2, const I1 &i1, const I2 &i2, const I3 &i3, \ const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, uint32_t i321, O * *out) { \ return ::N(WALLYP(p1), WALLYP(p2), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYP(p3), WALLYP(p4), WALLYP(p5), WALLYP(p6), i321, out); \ } +#define WALLY_FN_PP_B(F, N) template inline int F(const P1 &p1, const P2 &p2, O & out) { \ + return ::N(WALLYP(p1), WALLYP(p2), WALLYO(out)); \ +} + #define WALLY_FN_PP_BS(F, N) template inline int F(const P1 &p1, const P2 &p2, O & out, size_t * written = 0) { \ size_t n; \ int ret = ::N(WALLYP(p1), WALLYP(p2), WALLYO(out), written ? written : &n); \ @@ -352,6 +461,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), s1, out); \ } +#define WALLY_FN__A(F, N) template inline int F(O **out) { return ::N(out); } + +#define WALLY_FN__S(F, N) inline int F(size_t *written) { return ::N(written); } + #define WALLY_FN_P_A(F, N) template inline int F(const P1 &p1, O * *out) { \ return ::N(WALLYP(p1), out); \ } @@ -370,73 +483,79 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), written); \ } -#define WALLY_FN_P_P(F, N) template inline int F(const P1 &p1, O * written) { \ - return ::N(WALLYP(p1), written); \ +#define WALLY_FN_P_P(F, N) template inline int F(const P1 &p1, O * out) { \ + return ::N(WALLYP(p1), out); \ } #define WALLY_FN_S_S(F, N) inline int F(size_t s1, size_t * written) { \ return ::N(s1, written); \ } -WALLY_FN_3(init, wally_init) WALLY_FN_3(cleanup, wally_cleanup) -WALLY_FN_333_BBBBBA(bip32_key_init_alloc, bip32_key_init_alloc) +WALLY_FN_3(init, wally_init) +WALLY_FN_333BBBBB_A(bip32_key_init_alloc, bip32_key_init_alloc) WALLY_FN_33SS_A(tx_init_alloc, wally_tx_init_alloc) -WALLY_FN_3_A(tx_witness_stack_init_alloc, wally_tx_witness_stack_init_alloc) -WALLY_FN_S_A(keypath_map_init_alloc, wally_keypath_map_init_alloc) -WALLY_FN_S_A(partial_sigs_map_init_alloc, wally_partial_sigs_map_init_alloc) -WALLY_FN_S_A(unknowns_map_init_alloc, wally_unknowns_map_init_alloc) -WALLY_FN_SSS_A(psbt_init_alloc, wally_psbt_init_alloc) WALLY_FN_6B_A(tx_output_init_alloc, wally_tx_output_init_alloc) WALLY_FN_B(ec_private_key_verify, wally_ec_private_key_verify) WALLY_FN_B(ec_public_key_verify, wally_ec_public_key_verify) WALLY_FN_B(secp_randomize, wally_secp_randomize) WALLY_FN_B33BP_A(tx_input_init_alloc, wally_tx_input_init_alloc) -WALLY_FN_B33_A(bip32_key_from_parent_alloc, bip32_key_from_parent_alloc) WALLY_FN_B33_A(bip32_key_from_seed_alloc, bip32_key_from_seed_alloc) WALLY_FN_B33_A(wif_from_bytes, wally_wif_from_bytes) WALLY_FN_B33_BS(scriptpubkey_csv_2of2_then_1_from_bytes, wally_scriptpubkey_csv_2of2_then_1_from_bytes) WALLY_FN_B33_BS(scriptpubkey_csv_2of3_then_2_from_bytes, wally_scriptpubkey_csv_2of3_then_2_from_bytes) WALLY_FN_B33_BS(scriptpubkey_multisig_from_bytes, wally_scriptpubkey_multisig_from_bytes) WALLY_FN_B33_P(bip32_key_from_seed, bip32_key_from_seed) +WALLY_FN_B3B_B(symmetric_key_from_parent, wally_symmetric_key_from_parent) WALLY_FN_B3_A(base58_from_bytes, wally_base58_from_bytes) +WALLY_FN_B3_A(scriptpubkey_to_address, wally_scriptpubkey_to_address) WALLY_FN_B3_A(tx_from_bytes, wally_tx_from_bytes) WALLY_FN_B3_BS(format_bitcoin_message, wally_format_bitcoin_message) WALLY_FN_B3_BS(script_push_from_bytes, wally_script_push_from_bytes) +WALLY_FN_B3_BS(scriptpubkey_op_return_from_bytes, wally_scriptpubkey_op_return_from_bytes) WALLY_FN_B3_BS(scriptpubkey_p2pkh_from_bytes, wally_scriptpubkey_p2pkh_from_bytes) WALLY_FN_B3_BS(scriptpubkey_p2sh_from_bytes, wally_scriptpubkey_p2sh_from_bytes) WALLY_FN_B3_BS(witness_program_from_bytes, wally_witness_program_from_bytes) WALLY_FN_BB333_B(scrypt, wally_scrypt) +WALLY_FN_BB33_B(pbkdf2_hmac_sha256, wally_pbkdf2_hmac_sha256) +WALLY_FN_BB33_B(pbkdf2_hmac_sha512, wally_pbkdf2_hmac_sha512) +WALLY_FN_BB3B(ec_sig_verify, wally_ec_sig_verify) WALLY_FN_BB3_A(bip38_from_private_key, bip38_from_private_key) +WALLY_FN_BB3_A(witness_p2wpkh_from_sig, wally_witness_p2wpkh_from_sig) WALLY_FN_BB3_B(aes, wally_aes) WALLY_FN_BB3_B(bip38_raw_from_private_key, bip38_raw_from_private_key) WALLY_FN_BB3_B(bip38_raw_to_private_key, bip38_raw_to_private_key) WALLY_FN_BB3_B(ec_sig_from_bytes, wally_ec_sig_from_bytes) -WALLY_FN_BB3_B(ec_sig_verify, wally_ec_sig_verify) WALLY_FN_BB3_BS(scriptsig_p2pkh_from_sig, wally_scriptsig_p2pkh_from_sig) +WALLY_FN_BBB3_A(witness_multisig_from_bytes, wally_witness_multisig_from_bytes) WALLY_FN_BBB3_BS(aes_cbc, wally_aes_cbc) WALLY_FN_BBB3_BS(scriptsig_multisig_from_bytes, wally_scriptsig_multisig_from_bytes) +WALLY_FN_BBPP_A(psbt_output_init_alloc, wally_psbt_output_init_alloc) +WALLY_FN_BB_A(witness_p2wpkh_from_der, wally_witness_p2wpkh_from_der) +WALLY_FN_BB_B(ec_sig_to_public_key, wally_ec_sig_to_public_key) +WALLY_FN_BB_B(ecdh, wally_ecdh) WALLY_FN_BB_B(hmac_sha256, wally_hmac_sha256) WALLY_FN_BB_B(hmac_sha512, wally_hmac_sha512) -WALLY_FN_BB_B(ecdh, wally_ecdh) -WALLY_FN_BP3_A(addr_segwit_from_bytes, wally_addr_segwit_from_bytes) WALLY_FN_BB_BS(scriptsig_p2pkh_from_der, wally_scriptsig_p2pkh_from_der) +WALLY_FN_BP3_A(addr_segwit_from_bytes, wally_addr_segwit_from_bytes) WALLY_FN_B_A(bip32_key_unserialize_alloc, bip32_key_unserialize_alloc) WALLY_FN_B_A(hex_from_bytes, wally_hex_from_bytes) WALLY_FN_B_A(psbt_from_bytes, wally_psbt_from_bytes) WALLY_FN_B_B(ec_public_key_decompress, wally_ec_public_key_decompress) WALLY_FN_B_B(ec_public_key_from_private_key, wally_ec_public_key_from_private_key) +WALLY_FN_B_B(ec_public_key_negate, wally_ec_public_key_negate) WALLY_FN_B_B(ec_sig_from_der, wally_ec_sig_from_der) WALLY_FN_B_B(ec_sig_normalize, wally_ec_sig_normalize) WALLY_FN_B_B(hash160, wally_hash160) WALLY_FN_B_B(sha256, wally_sha256) +WALLY_FN_B_B(sha256_midstate, wally_sha256_midstate) WALLY_FN_B_B(sha256d, wally_sha256d) WALLY_FN_B_B(sha512, wally_sha512) +WALLY_FN_B_B(symmetric_key_from_seed, wally_symmetric_key_from_seed) WALLY_FN_B_BS(ec_sig_to_der, wally_ec_sig_to_der) WALLY_FN_B_P(bip32_key_unserialize, bip32_key_unserialize) +WALLY_FN_B_S(bip38_raw_get_flags, bip38_raw_get_flags) WALLY_FN_B_S(scriptpubkey_get_type, wally_scriptpubkey_get_type) -WALLY_FN_BB33_B(pbkdf2_hmac_sha256, wally_pbkdf2_hmac_sha256) -WALLY_FN_BB33_B(pbkdf2_hmac_sha512, wally_pbkdf2_hmac_sha512) WALLY_FN_P(bip32_key_free, bip32_key_free) WALLY_FN_P(bip32_key_strip_private_key, bip32_key_strip_private_key) WALLY_FN_P(get_operations, wally_get_operations) @@ -453,61 +572,71 @@ WALLY_FN_P(tx_witness_stack_free, wally_tx_witness_stack_free) WALLY_FN_P(unknowns_map_free, wally_unknowns_map_free) WALLY_FN_P3(psbt_input_set_sighash_type, wally_psbt_input_set_sighash_type) WALLY_FN_P3(tx_witness_stack_add_dummy, wally_tx_witness_stack_add_dummy) -WALLY_FN_P3(tx_witness_stack_set_dummy, wally_tx_witness_stack_set_dummy) +WALLY_FN_P33_A(bip32_key_from_parent_alloc, bip32_key_from_parent_alloc) +WALLY_FN_P33_A(bip32_key_to_address, wally_bip32_key_to_address) +WALLY_FN_P33_A(wif_to_address, wally_wif_to_address) +WALLY_FN_P33_B(wif_to_bytes, wally_wif_to_bytes) WALLY_FN_P33_P(bip32_key_from_parent, bip32_key_from_parent) -WALLY_FN_P3B(tx_witness_stack_set, wally_tx_witness_stack_set) -WALLY_FN_P3B633_B(tx_get_btc_signature_hash, wally_tx_get_btc_signature_hash) -WALLY_FN_P3BB36333_B(tx_get_signature_hash, wally_tx_get_signature_hash) WALLY_FN_P3_A(bip32_key_to_base58, bip32_key_to_base58) WALLY_FN_P3_A(psbt_to_base64, wally_psbt_to_base64) WALLY_FN_P3_A(tx_clone, wally_tx_clone) WALLY_FN_P3_A(tx_from_hex, wally_tx_from_hex) WALLY_FN_P3_A(tx_to_hex, wally_tx_to_hex) WALLY_FN_P3_B(bip32_key_serialize, bip32_key_serialize) -WALLY_FN_P3_B(wif_to_bytes, wally_wif_to_bytes) +WALLY_FN_P3_BS(address_to_scriptpubkey, wally_address_to_scriptpubkey) WALLY_FN_P3_BS(base58_to_bytes, wally_base58_to_bytes) WALLY_FN_P3_BS(psbt_to_bytes, wally_psbt_to_bytes) WALLY_FN_P3_BS(tx_to_bytes, wally_tx_to_bytes) WALLY_FN_P3_BS(wif_to_public_key, wally_wif_to_public_key) WALLY_FN_P3_S(psbt_get_length, wally_psbt_get_length) WALLY_FN_P3_S(tx_get_length, wally_tx_get_length) -WALLY_FN_P33_A(scriptpubkey_to_address, wally_scriptpubkey_to_address) -WALLY_FN_P33_A(wif_to_address, wally_wif_to_address) WALLY_FN_P6B3(tx_add_raw_output, wally_tx_add_raw_output) +WALLY_FN_PB(psbt_input_set_final_script_sig, wally_psbt_input_set_final_script_sig) WALLY_FN_PB(psbt_input_set_redeem_script, wally_psbt_input_set_redeem_script) WALLY_FN_PB(psbt_input_set_witness_script, wally_psbt_input_set_witness_script) -WALLY_FN_PB(psbt_input_set_final_script_sig, wally_psbt_input_set_final_script_sig) WALLY_FN_PB(psbt_output_set_redeem_script, wally_psbt_output_set_redeem_script) WALLY_FN_PB(psbt_output_set_witness_script, wally_psbt_output_set_witness_script) WALLY_FN_PB(psbt_sign, wally_psbt_sign) WALLY_FN_PB(tx_witness_stack_add, wally_tx_witness_stack_add) WALLY_FN_PB33BP3(tx_add_raw_input, wally_tx_add_raw_input) -WALLY_FN_PBB(partial_sigs_map_add, wally_partial_sigs_map_add) -WALLY_FN_PBB(unknowns_map_add, wally_unknowns_map_add) -WALLY_FN_PBBB(keypath_map_add, wally_keypath_map_add) -WALLY_FN_PBBPP_A(psbt_output_init_alloc, wally_psbt_output_init_alloc) WALLY_FN_PB3_A(bip32_key_from_parent_path_alloc, bip32_key_from_parent_path_alloc) WALLY_FN_PB3_B(bip38_to_private_key, bip38_to_private_key) WALLY_FN_PB3_P(bip32_key_from_parent_path, bip32_key_from_parent_path) +WALLY_FN_PBB(partial_sigs_map_add, wally_partial_sigs_map_add) +WALLY_FN_PBB(unknowns_map_add, wally_unknowns_map_add) +WALLY_FN_PBBB(keypath_map_add, wally_keypath_map_add) WALLY_FN_PB_A(bip39_mnemonic_from_bytes, bip39_mnemonic_from_bytes) WALLY_FN_PB_S(keypath_map_find, wally_keypath_map_find) WALLY_FN_PB_S(partial_sigs_map_find, wally_partial_sigs_map_find) WALLY_FN_PB_S(unknowns_map_find, wally_unknowns_map_find) WALLY_FN_PP(bip39_mnemonic_validate, bip39_mnemonic_validate) WALLY_FN_PP(psbt_combine, wally_psbt_combine) +WALLY_FN_PP(psbt_input_set_final_witness, wally_psbt_input_set_final_witness) +WALLY_FN_PP(psbt_input_set_keypaths, wally_psbt_input_set_keypaths) +WALLY_FN_PP(psbt_input_set_non_witness_utxo, wally_psbt_input_set_non_witness_utxo) +WALLY_FN_PP(psbt_input_set_partial_sigs, wally_psbt_input_set_partial_sigs) +WALLY_FN_PP(psbt_input_set_unknowns, wally_psbt_input_set_unknowns) +WALLY_FN_PP(psbt_input_set_witness_utxo, wally_psbt_input_set_witness_utxo) +WALLY_FN_PP(psbt_output_set_keypaths, wally_psbt_output_set_keypaths) +WALLY_FN_PP(psbt_output_set_unknowns, wally_psbt_output_set_unknowns) +WALLY_FN_PP(psbt_set_global_tx, wally_psbt_set_global_tx) WALLY_FN_PP(tx_add_input, wally_tx_add_input) WALLY_FN_PP(tx_add_output, wally_tx_add_output) +WALLY_FN_PP3_A(bip32_key_to_addr_segwit, wally_bip32_key_to_addr_segwit) WALLY_FN_PP3_BS(addr_segwit_to_bytes, wally_addr_segwit_to_bytes) WALLY_FN_PPBBBPPPP3_A(psbt_input_init_alloc, wally_psbt_input_init_alloc) WALLY_FN_PP_BS(bip39_mnemonic_to_bytes, bip39_mnemonic_to_bytes) WALLY_FN_PP_BS(bip39_mnemonic_to_seed, bip39_mnemonic_to_seed) WALLY_FN_PS(tx_remove_input, wally_tx_remove_input) WALLY_FN_PS(tx_remove_output, wally_tx_remove_output) +WALLY_FN_PS3(tx_witness_stack_set_dummy, wally_tx_witness_stack_set_dummy) WALLY_FN_PSB(tx_set_input_script, wally_tx_set_input_script) +WALLY_FN_PSB(tx_witness_stack_set, wally_tx_witness_stack_set) +WALLY_FN_PSB633_B(tx_get_btc_signature_hash, wally_tx_get_btc_signature_hash) +WALLY_FN_PSBB36333_B(tx_get_signature_hash, wally_tx_get_signature_hash) WALLY_FN_PSP(tx_set_input_witness, wally_tx_set_input_witness) WALLY_FN_PS_A(bip39_get_word, bip39_get_word) WALLY_FN_P_A(bip32_key_from_base58_alloc, bip32_key_from_base58_alloc) -WALLY_FN_P_A(bip39_get_languages, bip39_get_languages) WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) WALLY_FN_P_A(psbt_extract, wally_psbt_extract) WALLY_FN_P_A(psbt_from_base64, wally_psbt_from_base64) @@ -515,26 +644,24 @@ WALLY_FN_P_A(tx_output_clone_alloc, wally_tx_output_clone_alloc) WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) WALLY_FN_P_B(tx_get_txid, wally_tx_get_txid) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) +WALLY_FN_P_P(bip32_key_from_base58, bip32_key_from_base58) +WALLY_FN_P_P(tx_get_total_output_satoshi, wally_tx_get_total_output_satoshi) +WALLY_FN_P_P(tx_output_clone, wally_tx_output_clone) WALLY_FN_P_S(base58_get_length, wally_base58_get_length) +WALLY_FN_P_S(bip38_get_flags, bip38_get_flags) WALLY_FN_P_S(psbt_is_elements, wally_psbt_is_elements) WALLY_FN_P_S(tx_get_vsize, wally_tx_get_vsize) WALLY_FN_P_S(tx_get_weight, wally_tx_get_weight) WALLY_FN_P_S(tx_get_witness_count, wally_tx_get_witness_count) +WALLY_FN_P_S(tx_is_coinbase, wally_tx_is_coinbase) WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) -WALLY_FN_P_P(bip32_key_from_base58, bip32_key_from_base58) -WALLY_FN_P_P(psbt_input_set_final_witness, wally_psbt_input_set_final_witness) -WALLY_FN_P_P(psbt_input_set_keypaths, wally_psbt_input_set_keypaths) -WALLY_FN_P_P(psbt_input_set_non_witness_utxo, wally_psbt_input_set_non_witness_utxo) -WALLY_FN_P_P(psbt_input_set_partial_sigs, wally_psbt_input_set_partial_sigs) -WALLY_FN_P_P(psbt_input_set_unknowns, wally_psbt_input_set_unknowns) -WALLY_FN_P_P(psbt_input_set_witness_utxo, wally_psbt_input_set_witness_utxo) -WALLY_FN_P_P(psbt_output_set_keypaths, wally_psbt_output_set_keypaths) -WALLY_FN_P_P(psbt_output_set_unknowns, wally_psbt_output_set_unknowns) -WALLY_FN_P_P(psbt_set_global_tx, wally_psbt_set_global_tx) -WALLY_FN_P_P(tx_get_total_output_satoshi, wally_tx_get_total_output_satoshi) -WALLY_FN_P_P(tx_output_clone, wally_tx_output_clone) - +WALLY_FN_SSS_A(psbt_init_alloc, wally_psbt_init_alloc) +WALLY_FN_S_A(keypath_map_init_alloc, wally_keypath_map_init_alloc) +WALLY_FN_S_A(partial_sigs_map_init_alloc, wally_partial_sigs_map_init_alloc) +WALLY_FN_S_A(tx_witness_stack_init_alloc, wally_tx_witness_stack_init_alloc) +WALLY_FN_S_A(unknowns_map_init_alloc, wally_unknowns_map_init_alloc) WALLY_FN_S_S(tx_vsize_from_weight, wally_tx_vsize_from_weight) +WALLY_FN__A(bip39_get_languages, bip39_get_languages) inline struct secp256k1_context_struct *get_secp_context() { return ::wally_get_secp_context(); @@ -560,44 +687,67 @@ inline bool is_elements_build() } #ifdef BUILD_ELEMENTS -WALLY_FN_6BBBBBB_A(tx_elements_output_init_alloc, wally_tx_elements_output_init_alloc) +WALLY_FN_6BBBBBBBB6II_BS(asset_rangeproof, wally_asset_rangeproof) +WALLY_FN_6BB_B(asset_value_commitment, wally_asset_value_commitment) WALLY_FN_6_B(tx_confidential_value_from_satoshi, wally_tx_confidential_value_from_satoshi) -WALLY_FN_B33BPBBBBBB_A(tx_elements_input_init_alloc, wally_tx_elements_input_init_alloc) +WALLY_FN_B33BPBBBBBBP_A(tx_elements_input_init_alloc, wally_tx_elements_input_init_alloc) WALLY_FN_B3B_B(tx_elements_issuance_generate_entropy, wally_tx_elements_issuance_generate_entropy) WALLY_FN_B3_B(tx_elements_issuance_calculate_reissuance_token, wally_tx_elements_issuance_calculate_reissuance_token) +WALLY_FN_BB3_BS(elements_pegin_contract_script_from_bytes, wally_elements_pegin_contract_script_from_bytes) +WALLY_FN_BBBB3_BS(elements_pegout_script_from_bytes, wally_elements_pegout_script_from_bytes) +WALLY_FN_BBBBBBB_BS(asset_surjectionproof, wally_asset_surjectionproof) +WALLY_FN_BBBBBB_A(tx_elements_output_init_alloc, wally_tx_elements_output_init_alloc) +WALLY_FN_BBBBBB_BBB6(asset_unblind, wally_asset_unblind) +WALLY_FN_BBBBB_BBB6(asset_unblind_with_nonce, wally_asset_unblind_with_nonce) +WALLY_FN_BBPPBBBBBBBB_A(psbt_elements_output_init_alloc, wally_psbt_elements_output_init_alloc) +WALLY_FN_BBSBBB_BS(asset_pak_whitelistproof, wally_asset_pak_whitelistproof) +WALLY_FN_BB_B(asset_blinding_key_to_ec_private_key, wally_asset_blinding_key_to_ec_private_key) +WALLY_FN_BB_B(asset_generator_from_bytes, wally_asset_generator_from_bytes) +WALLY_FN_BSBB_B(asset_final_vbf, wally_asset_final_vbf) +WALLY_FN_B_6(tx_confidential_value_to_satoshi, wally_tx_confidential_value_to_satoshi) +WALLY_FN_B_B(asset_blinding_key_from_seed, wally_asset_blinding_key_from_seed) WALLY_FN_B_B(tx_elements_issuance_calculate_asset, wally_tx_elements_issuance_calculate_asset) WALLY_FN_P(psbt_elements_input_clear_value, wally_psbt_elements_input_clear_value) WALLY_FN_P(psbt_finalize, wally_psbt_finalize) WALLY_FN_P(tx_elements_input_issuance_free, wally_tx_elements_input_issuance_free) WALLY_FN_P(tx_elements_output_commitment_free, wally_tx_elements_output_commitment_free) -WALLY_FN_P6BB33_B(tx_get_elements_signature_hash, wally_tx_get_elements_signature_hash) -WALLY_FN_P6BBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) -WALLY_FN_PB33BPBBBBBB3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) -WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_commitment_set) -WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) -WALLY_FN_P_S(tx_is_elements, wally_tx_is_elements) -WALLY_FN_P_P(psbt_elements_input_set_peg_in_tx, wally_psbt_elements_input_set_peg_in_tx) -WALLY_FN_PB(psbt_elements_input_set_value_blinder, wally_psbt_elements_input_set_value_blinder) +WALLY_FN_P3B_A(confidential_addr_from_addr, wally_confidential_addr_from_addr) +WALLY_FN_P3_A(confidential_addr_to_addr, wally_confidential_addr_to_addr) +WALLY_FN_P3_B(confidential_addr_to_ec_public_key, wally_confidential_addr_to_ec_public_key) +WALLY_FN_P6(psbt_elements_input_set_value, wally_psbt_elements_input_set_value) WALLY_FN_PB(psbt_elements_input_set_asset, wally_psbt_elements_input_set_asset) WALLY_FN_PB(psbt_elements_input_set_asset_blinder, wally_psbt_elements_input_set_asset_blinder) -WALLY_FN_PB(psbt_elements_input_set_txout_proof, wally_psbt_elements_input_set_txout_proof) -WALLY_FN_PB(psbt_elements_input_set_genesis_hash, wally_psbt_elements_input_set_genesis_hash) WALLY_FN_PB(psbt_elements_input_set_claim_script, wally_psbt_elements_input_set_claim_script) -WALLY_FN_PB(psbt_elements_output_set_blinding_pubkey, wally_psbt_elements_output_set_blinding_pubkey) -WALLY_FN_PB(psbt_elements_output_set_value_commitment, wally_psbt_elements_output_set_value_commitment) -WALLY_FN_PB(psbt_elements_output_set_value_blinder, wally_psbt_elements_output_set_value_blinder) -WALLY_FN_PB(psbt_elements_output_set_asset_commitment, wally_psbt_elements_output_set_asset_commitment) +WALLY_FN_PB(psbt_elements_input_set_genesis_hash, wally_psbt_elements_input_set_genesis_hash) +WALLY_FN_PB(psbt_elements_input_set_txout_proof, wally_psbt_elements_input_set_txout_proof) +WALLY_FN_PB(psbt_elements_input_set_value_blinder, wally_psbt_elements_input_set_value_blinder) WALLY_FN_PB(psbt_elements_output_set_asset_blinder, wally_psbt_elements_output_set_asset_blinder) +WALLY_FN_PB(psbt_elements_output_set_asset_commitment, wally_psbt_elements_output_set_asset_commitment) +WALLY_FN_PB(psbt_elements_output_set_blinding_pubkey, wally_psbt_elements_output_set_blinding_pubkey) WALLY_FN_PB(psbt_elements_output_set_nonce_commitment, wally_psbt_elements_output_set_nonce_commitment) WALLY_FN_PB(psbt_elements_output_set_range_proof, wally_psbt_elements_output_set_range_proof) WALLY_FN_PB(psbt_elements_output_set_surjection_proof, wally_psbt_elements_output_set_surjection_proof) -WALLY_FN_P6(psbt_elements_input_set_value, wally_psbt_elements_input_set_value) +WALLY_FN_PB(psbt_elements_output_set_value_blinder, wally_psbt_elements_output_set_value_blinder) +WALLY_FN_PB(psbt_elements_output_set_value_commitment, wally_psbt_elements_output_set_value_commitment) +WALLY_FN_PB33BPBBBBBB3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) +WALLY_FN_PB33BPBBBBBBP3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) +WALLY_FN_PB3P(bip32_key_with_tweak_from_parent_path, bip32_key_with_tweak_from_parent_path) +WALLY_FN_PB3_A(bip32_key_with_tweak_from_parent_path_alloc, bip32_key_with_tweak_from_parent_path_alloc) +WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_commitment_set) +WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) +WALLY_FN_PBBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) +WALLY_FN_PP(psbt_elements_input_set_peg_in_tx, wally_psbt_elements_input_set_peg_in_tx) +WALLY_FN_PPBBBPPPP363BBBPBBB_A(psbt_elements_input_init_alloc, wally_psbt_elements_input_init_alloc) +WALLY_FN_PPPB_A(confidential_addr_from_addr_segwit, wally_confidential_addr_from_addr_segwit) +WALLY_FN_PPP_A(confidential_addr_to_addr_segwit, wally_confidential_addr_to_addr_segwit) +WALLY_FN_PP_B(confidential_addr_segwit_to_ec_public_key, wally_confidential_addr_segwit_to_ec_public_key) +WALLY_FN_PSBB33_B(tx_get_elements_signature_hash, wally_tx_get_elements_signature_hash) +WALLY_FN_P_S(tx_elements_input_is_pegin, wally_tx_elements_input_is_pegin) +WALLY_FN_P_S(tx_is_elements, wally_tx_is_elements) +WALLY_FN_SSSS_S(elements_pegout_script_size, wally_elements_pegout_script_size) WALLY_FN_SSS_A(psbt_elements_init_alloc, wally_psbt_elements_init_alloc) -#if 0 -// TODO: Perhaps these functions should be simplified, 19 i& 12 parameters seems a bit much -(psbt_elements_input_init_alloc, wally_psbt_elements_input_init_alloc) -(psbt_elements_output_init_alloc, wally_psbt_elements_output_init_alloc) -#endif +WALLY_FN_S_S(asset_pak_whitelistproof_size, wally_asset_pak_whitelistproof_size) +WALLY_FN_S_S(asset_surjectionproof_size, wally_asset_surjectionproof_size) #endif /* BUILD_ELEMENTS */ #undef WALLYP From 2cc28c17acbf2241ef4832193654d3c924c0511e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 14:45:29 +1200 Subject: [PATCH 175/205] script: Update function layout to match others --- include/wally_script.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/wally_script.h b/include/wally_script.h index 3b102a19d..0ba227133 100644 --- a/include/wally_script.h +++ b/include/wally_script.h @@ -299,8 +299,12 @@ WALLY_CORE_API int wally_witness_p2wpkh_from_der( * :param written: Destination for the number of bytes written to ``bytes_out``. */ WALLY_CORE_API int wally_scriptpubkey_op_return_from_bytes( - const unsigned char *bytes, size_t bytes_len, - uint32_t flags, unsigned char *bytes_out, size_t len, size_t *written); + const unsigned char *bytes, + size_t bytes_len, + uint32_t flags, + unsigned char *bytes_out, + size_t len, + size_t *written); /** * Create a P2SH scriptPubkey. From 0325ab9e7e68935f4414036090082369e5bea30d Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 15:28:31 +1200 Subject: [PATCH 176/205] pullpush: remove unused LE16 functions --- src/pullpush.c | 13 ------------- src/pullpush.h | 2 -- 2 files changed, 15 deletions(-) diff --git a/src/pullpush.c b/src/pullpush.c index 03eb9ad34..6721f4da6 100644 --- a/src/pullpush.c +++ b/src/pullpush.c @@ -96,19 +96,6 @@ uint32_t pull_le32(const unsigned char **cursor, size_t *max) return le32_to_cpu(lev); } -void push_le16(unsigned char **cursor, size_t *max, uint16_t v) -{ - leint16_t lev = cpu_to_le16(v); - push_bytes(cursor, max, &lev, sizeof(lev)); -} - -uint16_t pull_le16(const unsigned char **cursor, size_t *max) -{ - leint16_t lev; - pull_bytes(&lev, sizeof(lev), cursor, max); - return le16_to_cpu(lev); -} - void push_u8(unsigned char **cursor, size_t *max, uint8_t v) { push_bytes(cursor, max, &v, sizeof(uint8_t)); diff --git a/src/pullpush.h b/src/pullpush.h index 2d5146fa6..73cd6f2a5 100644 --- a/src/pullpush.h +++ b/src/pullpush.h @@ -57,8 +57,6 @@ void push_le64(unsigned char **cursor, size_t *max, uint64_t v); uint64_t pull_le64(const unsigned char **cursor, size_t *max); void push_le32(unsigned char **cursor, size_t *max, uint32_t v); uint32_t pull_le32(const unsigned char **cursor, size_t *max); -void push_le16(unsigned char **cursor, size_t *max, uint16_t v); -uint16_t pull_le16(const unsigned char **cursor, size_t *max); void push_u8(unsigned char **cursor, size_t *max, uint8_t v); uint8_t pull_u8(const unsigned char **cursor, size_t *max); uint8_t peek_u8(const unsigned char **cursor, size_t *max); From a37ef060127c0da8ef9f6d4a5ac3182524fbd582 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 15:54:14 +1200 Subject: [PATCH 177/205] tests: Remove internal header from elements C test --- src/ctest/test_elements_tx.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ctest/test_elements_tx.c b/src/ctest/test_elements_tx.c index f7fbbbb35..122d0c9ce 100644 --- a/src/ctest/test_elements_tx.c +++ b/src/ctest/test_elements_tx.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include From 2d9b761135557bcf9303b2f8b0057a4e0e4bd645 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 16:06:18 +1200 Subject: [PATCH 178/205] psbt: create empty inputs and outputs when setting the global tx We revert to this behaviour since we will have to offer indexed getters and setters to support python and java anyway, so lets let the caller set the tx and then update the resulting PSBT inputs and outputs in place. --- include/wally_psbt.h | 4 ++++ src/psbt.c | 4 ++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index e070295f9..4d598ce07 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -596,6 +596,10 @@ WALLY_CORE_API int wally_psbt_free( * * :param psbt: The PSBT to set the transaction for. * :param tx: The transaction to set. + * + * The global transaction can only be set on a newly created PSBT. After this + * call completes the PSBT will have empty inputs and outputs for each input + * and output in the transaction ``tx`` given. */ WALLY_CORE_API int wally_psbt_set_global_tx( struct wally_psbt *psbt, diff --git a/src/psbt.c b/src/psbt.c index 8e02c402e..344975d62 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1103,6 +1103,8 @@ static int psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx, bool psbt->outputs = new_outputs; psbt->outputs_allocation_len = tx->num_outputs; } + psbt->num_inputs = tx->num_inputs; + psbt->num_outputs = tx->num_outputs; psbt->tx = do_clone ? new_tx : tx; return WALLY_OK; } @@ -2074,7 +2076,6 @@ int wally_psbt_from_bytes(const unsigned char *bytes, size_t len, /* Read inputs */ for (i = 0; i < result->tx->num_inputs; ++i) { ret = pull_psbt_input(&bytes, &len, flags, &result->inputs[i]); - result->num_inputs = i + 1; /* Free this input if we fail */ if (ret != WALLY_OK) goto fail; } @@ -2082,7 +2083,6 @@ int wally_psbt_from_bytes(const unsigned char *bytes, size_t len, /* Read outputs */ for (i = 0; i < result->tx->num_outputs; ++i) { ret = pull_psbt_output(&bytes, &len, &result->outputs[i]); - result->num_outputs = i + 1; /* Free this output if we fail */ if (ret != WALLY_OK) goto fail; } From cab172e22c1669d8f9a697f50fe06430606bbc5e Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 16:15:06 +1200 Subject: [PATCH 179/205] transaction: Don't expose analyse_tx now that psbt doesnt need it --- src/transaction.c | 6 +++--- src/transaction_shared.h | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/transaction.c b/src/transaction.c index 271a16754..37ed89294 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -2244,9 +2244,9 @@ int wally_tx_get_txid(const struct wally_tx *tx, unsigned char *bytes_out, size_ return tx_to_hex_or_txid(tx, 0, NULL, bytes_out, len, is_elements); } -int analyze_tx(const unsigned char *bytes, size_t bytes_len, - uint32_t flags, size_t *num_inputs, size_t *num_outputs, - bool *expect_witnesses) +static int analyze_tx(const unsigned char *bytes, size_t bytes_len, + uint32_t flags, size_t *num_inputs, size_t *num_outputs, + bool *expect_witnesses) { const unsigned char *p = bytes, *end = bytes + bytes_len; uint64_t v, num_witnesses; diff --git a/src/transaction_shared.h b/src/transaction_shared.h index ff4dc7227..6d1626975 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -21,9 +21,6 @@ int replace_bytes(const unsigned char *bytes, size_t bytes_len, unsigned char **bytes_out, size_t *bytes_len_out); void clear_and_free(void *p, size_t len); void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size); -int analyze_tx(const unsigned char *bytes, size_t bytes_len, - uint32_t flags, size_t *num_inputs, size_t *num_outputs, - bool *expect_witnesses); struct wally_tx_witness_stack *clone_witness( const struct wally_tx_witness_stack *stack); From 5c9d80576083bd6ced4f872bd12625309a4a87c5 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 16:44:22 +1200 Subject: [PATCH 180/205] transaction: Make clear_and_free available and use it internally --- src/bip32.c | 3 +-- src/bip39.c | 3 +-- src/elements.c | 7 +++---- src/internal.c | 8 ++++++++ src/internal.h | 3 ++- src/script.c | 16 +++++++++------- src/swig_java/swig.i | 8 -------- src/symmetric.c | 1 + src/transaction.c | 8 -------- src/transaction_shared.h | 1 - src/wordlist.c | 3 +-- 11 files changed, 26 insertions(+), 35 deletions(-) diff --git a/src/bip32.c b/src/bip32.c index 5c144ef13..1e1efae1b 100644 --- a/src/bip32.c +++ b/src/bip32.c @@ -104,8 +104,7 @@ int bip32_key_free(const struct ext_key *hdkey) { if (!hdkey) return WALLY_EINVAL; - wally_clear((void *)hdkey, sizeof(*hdkey)); - wally_free((void *)hdkey); + clear_and_free((void *)hdkey, sizeof(*hdkey)); return WALLY_OK; } diff --git a/src/bip39.c b/src/bip39.c index 0eb1038b5..65b39a02a 100644 --- a/src/bip39.c +++ b/src/bip39.c @@ -232,8 +232,7 @@ int bip39_mnemonic_to_seed(const char *mnemonic, const char *passphrase, if (!ret && written) *written = BIP39_SEED_LEN_512; /* Succeeded */ - wally_clear(salt, salt_len); - wally_free(salt); + clear_and_free(salt, salt_len); return ret; } diff --git a/src/elements.c b/src/elements.c index 96af319d7..4025a5f7b 100644 --- a/src/elements.c +++ b/src/elements.c @@ -122,8 +122,8 @@ int wally_asset_final_vbf(const uint64_t *values, size_t values_len, size_t num_ ret = WALLY_OK; cleanup: - wally_free(abf_p); - wally_free(vbf_p); + clear_and_free(abf_p, values_len * sizeof(unsigned char *)); + clear_and_free(vbf_p, values_len * sizeof(unsigned char *)); return ret; } @@ -423,8 +423,7 @@ int wally_asset_surjectionproof(const unsigned char *output_asset, size_t output cleanup: wally_clear_2(&gen, sizeof(gen), &proof, sizeof(proof)); if (generators) - wally_clear(generators, num_inputs * sizeof(secp256k1_generator)); - wally_free(generators); + clear_and_free(generators, num_inputs * sizeof(secp256k1_generator)); return ret; } diff --git a/src/internal.c b/src/internal.c index 0b1747ff2..8e8458d13 100644 --- a/src/internal.c +++ b/src/internal.c @@ -335,6 +335,14 @@ void wally_clear_6(void *p, size_t len, void *p2, size_t len2, _ops.bzero_fn(p6, len6); } +void clear_and_free(void *p, size_t len) +{ + if (p) { + wally_clear(p, len); + wally_free(p); + } +} + static bool wally_init_done = false; int wally_init(uint32_t flags) diff --git a/src/internal.h b/src/internal.h index d98db082e..92a99b562 100644 --- a/src/internal.h +++ b/src/internal.h @@ -36,6 +36,8 @@ void wally_clear_6(void *p, size_t len, void *p2, size_t len2, void *p3, size_t len3, void *p4, size_t len4, void *p5, size_t len5, void *p6, size_t len6); +void clear_and_free(void *p, size_t len); + /* Fetch our internal operations function pointers */ const struct wally_operations *wally_ops(void); @@ -53,4 +55,3 @@ char *wally_strdup(const char *str); #define strdup(ptr) __use_wally_strdup_internally__ #endif /* LIBWALLY_INTERNAL_H */ - diff --git a/src/script.c b/src/script.c index 8beaa36b4..10eb20ee2 100644 --- a/src/script.c +++ b/src/script.c @@ -1137,19 +1137,21 @@ int wally_witness_multisig_from_bytes( int ret = WALLY_OK; size_t script_sig_len, n_sigs, buf_len; - if (!script || !script_len || !bytes || !bytes_len || !sighash || !sighash_len || !witness || !script_is_op_n(script[0], false, &n_sigs)) { + if (!script || !script_len || !bytes || !bytes_len || !sighash || !sighash_len || + !witness || !script_is_op_n(script[0], false, &n_sigs)) return WALLY_EINVAL; - } buf_len = n_sigs * (EC_SIGNATURE_DER_MAX_LEN + 2) + script_len; - if (!(script_sig = wally_malloc(buf_len))) { + if (!(script_sig = wally_malloc(buf_len))) return WALLY_ENOMEM; - } - if ((ret = wally_scriptsig_multisig_from_bytes(script, script_len, bytes, bytes_len, sighash, sighash_len, flags, script_sig, buf_len, &script_sig_len)) == WALLY_OK) { + ret = wally_scriptsig_multisig_from_bytes(script, script_len, + bytes, bytes_len, + sighash, sighash_len, flags, + script_sig, buf_len, &script_sig_len); + if (ret == WALLY_OK) ret = scriptsig_to_witness(script_sig, script_sig_len, witness); - } - wally_free(script_sig); + clear_and_free(script_sig, script_sig_len); return ret; } diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index 03cd7752a..cfcba20c4 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -94,14 +94,6 @@ static unsigned char* malloc_or_throw(JNIEnv *jenv, size_t len) { return p; } -static void clear_and_free(void *p, size_t len) -{ - if (p) { - wally_bzero(p, len); - wally_free(p); - } -} - static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) { jbyteArray ret = (*jenv)->NewByteArray(jenv, len); if (ret) diff --git a/src/symmetric.c b/src/symmetric.c index 934db7d04..169f573ba 100644 --- a/src/symmetric.c +++ b/src/symmetric.c @@ -57,6 +57,7 @@ int wally_symmetric_key_from_parent( ret = wally_hmac_sha512(bytes, HMAC_SHA512_LEN / 2, buff_p, buff_len, bytes_out, len); + wally_clear(buff_p, buff_len); if (buff_p != buff) wally_free(buff_p); diff --git a/src/transaction.c b/src/transaction.c index 37ed89294..17cdf5b6f 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -167,14 +167,6 @@ bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len) return *dst != NULL; } -void clear_and_free(void *p, size_t len) -{ - if (p) { - wally_clear(p, len); - wally_free(p); - } -} - void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size) { unsigned char *p = wally_malloc(new_n * size); diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 6d1626975..2764fe3e1 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -19,7 +19,6 @@ extern "C" { bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len); int replace_bytes(const unsigned char *bytes, size_t bytes_len, unsigned char **bytes_out, size_t *bytes_len_out); -void clear_and_free(void *p, size_t len); void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size); struct wally_tx_witness_stack *clone_witness( const struct wally_tx_witness_stack *stack); diff --git a/src/wordlist.c b/src/wordlist.c index 5752ef385..b24211bb0 100644 --- a/src/wordlist.c +++ b/src/wordlist.c @@ -100,7 +100,6 @@ void wordlist_free(struct words *w) } if (w->indices) wally_free((void *)w->indices); /* No need to clear */ - wally_clear(w, sizeof(*w)); - wally_free(w); + clear_and_free(w, sizeof(*w)); } } From af29018b749fa00ac09a533bc12ad5b58cfb4145 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 18:13:01 +1200 Subject: [PATCH 181/205] transaction: Expose tx_witness_stack_clone --- include/wally.hpp | 1 + include/wally_transaction.h | 10 +++++++ src/psbt.c | 10 +++---- src/swig_java/swig.i | 1 + src/swig_python/contrib/tx.py | 4 +++ src/swig_python/swig.i | 1 + src/test/util.py | 1 + src/transaction.c | 52 ++++++++++++++++++++--------------- src/transaction_shared.h | 2 -- 9 files changed, 53 insertions(+), 29 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 1329730fa..1a9c8c396 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -641,6 +641,7 @@ WALLY_FN_P_A(bip39_get_wordlist, bip39_get_wordlist) WALLY_FN_P_A(psbt_extract, wally_psbt_extract) WALLY_FN_P_A(psbt_from_base64, wally_psbt_from_base64) WALLY_FN_P_A(tx_output_clone_alloc, wally_tx_output_clone_alloc) +WALLY_FN_P_A(tx_witness_stack_clone_alloc, wally_tx_witness_stack_clone_alloc) WALLY_FN_P_B(bip32_key_get_fingerprint, bip32_key_get_fingerprint) WALLY_FN_P_B(tx_get_txid, wally_tx_get_txid) WALLY_FN_P_BS(hex_to_bytes, wally_hex_to_bytes) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 0b80fb696..6ae133571 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -141,6 +141,16 @@ WALLY_CORE_API int wally_tx_witness_stack_init_alloc( size_t allocation_len, struct wally_tx_witness_stack **output); +/** + * Create a copy of a witness stack. + * + * :param stack: The witness stack to copy. + * :param output: Destination for the resulting copy. + */ +WALLY_CORE_API int wally_tx_witness_stack_clone_alloc( + const struct wally_tx_witness_stack *stack, + struct wally_tx_witness_stack **output); + /** * Add a witness to a witness stack. * diff --git a/src/psbt.c b/src/psbt.c index 344975d62..92d2e479a 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -606,7 +606,8 @@ int wally_psbt_input_set_final_witness(struct wally_psbt_input *input, if (!input) return WALLY_EINVAL; - if (final_witness && !(new_witness = clone_witness(final_witness))) + if (final_witness && + (wally_tx_witness_stack_clone_alloc(final_witness, &new_witness) != WALLY_OK)) return WALLY_ENOMEM; wally_tx_witness_stack_free(input->final_witness); @@ -3225,7 +3226,7 @@ int wally_psbt_extract( return ret; for (i = 0; i < psbt->num_inputs; ++i) { - struct wally_psbt_input *input = &psbt->inputs[i]; + const struct wally_psbt_input *input = &psbt->inputs[i]; struct wally_tx_input *vin = &result->inputs[i]; if (!input->final_script_sig && !input->final_witness) { @@ -3251,10 +3252,9 @@ int wally_psbt_extract( ret = WALLY_EINVAL; break; } - if (!(vin->witness = clone_witness(input->final_witness))) { - ret = WALLY_ENOMEM; + ret = wally_tx_witness_stack_clone_alloc(input->final_witness, &vin->witness); + if (ret != WALLY_OK) break; - } } } diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index cfcba20c4..7d8ae5ee2 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -658,6 +658,7 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %returns_void__(wally_tx_witness_stack_free); %returns_struct(wally_tx_witness_stack_init_alloc, wally_tx_witness_stack); %rename("tx_witness_stack_init") wally_tx_witness_stack_init_alloc; +%returns_struct(wally_tx_witness_stack_clone_alloc, wally_tx_witness_stack); %returns_void__(wally_tx_witness_stack_set); %returns_void__(wally_tx_witness_stack_set_dummy); %returns_string(wally_wif_from_bytes); diff --git a/src/swig_python/contrib/tx.py b/src/swig_python/contrib/tx.py index eeeb570ea..28dcfc7bf 100644 --- a/src/swig_python/contrib/tx.py +++ b/src/swig_python/contrib/tx.py @@ -17,6 +17,10 @@ def test_tx_witness(self): witness = tx_witness_stack_init(0) tx_witness_stack_set(witness, 0, witness_script) + with self.assertRaises(ValueError): + tx_witness_stack_clone(None) + cloned = tx_witness_stack_clone(witness) + def test_tx_input(self): # Test invalid inputs txhash, seq, script, witness_script = b'0' * 32, 0xffffffff, b'0000', b'000000' diff --git a/src/swig_python/swig.i b/src/swig_python/swig.i index a46b82fa7..4daa71a01 100644 --- a/src/swig_python/swig.i +++ b/src/swig_python/swig.i @@ -345,6 +345,7 @@ static void destroy_words(PyObject *obj) { (void)obj; } %rename("tx_input_init") wally_tx_input_init_alloc; %rename("tx_output_init") wally_tx_output_init_alloc; %rename("tx_output_clone") wally_tx_output_clone_alloc; +%rename("tx_witness_stack_clone") wally_tx_witness_stack_clone_alloc; %rename("tx_init") wally_tx_init_alloc; %rename("tx_elements_input_init") wally_tx_elements_input_init_alloc; %rename("tx_elements_output_init") wally_tx_elements_output_init_alloc; diff --git a/src/test/util.py b/src/test/util.py index 6f7a7c52f..37eac5ee0 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -439,6 +439,7 @@ class wally_psbt(Structure): ('wally_tx_vsize_from_weight', c_int, [c_ulong, c_ulong_p]), ('wally_tx_witness_stack_add', c_int, [POINTER(wally_tx_witness_stack), c_void_p, c_ulong]), ('wally_tx_witness_stack_add_dummy', c_int, [POINTER(wally_tx_witness_stack), c_uint]), + ('wally_tx_witness_stack_clone_alloc', c_int, [POINTER(wally_tx_witness_stack), POINTER(POINTER(wally_tx_witness_stack))]), ('wally_tx_witness_stack_free', c_int, [POINTER(wally_tx_witness_stack)]), ('wally_tx_witness_stack_init_alloc', c_int, [c_ulong, POINTER(POINTER(wally_tx_witness_stack))]), ('wally_tx_witness_stack_set', c_int, [POINTER(wally_tx_witness_stack), c_ulong, c_void_p, c_ulong]), diff --git a/src/transaction.c b/src/transaction.c index 17cdf5b6f..95a1c4c03 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -197,25 +197,28 @@ int replace_bytes(const unsigned char *bytes, size_t bytes_len, } -struct wally_tx_witness_stack *clone_witness( - const struct wally_tx_witness_stack *stack) +int wally_tx_witness_stack_clone_alloc(const struct wally_tx_witness_stack *stack, + struct wally_tx_witness_stack **output) { struct wally_tx_witness_stack *result; size_t i; int ret; - ret = wally_tx_witness_stack_init_alloc(stack->items_allocation_len, &result); + TX_CHECK_OUTPUT; + if (!stack) + return WALLY_EINVAL; - if (ret == WALLY_OK) { - for (i = 0; i < stack->num_items && ret == WALLY_OK; ++i) { - ret = wally_tx_witness_stack_set(result, i, - stack->items[i].witness, - stack->items[i].witness_len); - if (ret != WALLY_OK) - wally_tx_witness_stack_free(result); - } + ret = wally_tx_witness_stack_init_alloc(stack->items_allocation_len, &result); + for (i = 0; ret == WALLY_OK && i < stack->num_items; ++i) { + ret = wally_tx_witness_stack_set(result, i, + stack->items[i].witness, + stack->items[i].witness_len); } - return ret == WALLY_OK ? result : NULL; + if (ret == WALLY_OK) + *output = result; + else + wally_tx_witness_stack_free(result); + return ret; } int wally_tx_witness_stack_init_alloc(size_t allocation_len, @@ -343,14 +346,16 @@ static bool clone_input_to( #ifdef BUILD_ELEMENTS unsigned char *new_issuance_amount = NULL, *new_inflation_keys = NULL, *new_issuance_amount_rangeproof = NULL, *new_inflation_keys_rangeproof = NULL; - struct wally_tx_witness_stack *new_pegin_witness; + struct wally_tx_witness_stack *new_pegin_witness = NULL; #endif - struct wally_tx_witness_stack *new_witness; + struct wally_tx_witness_stack *new_witness = NULL; - new_witness = src->witness ? clone_witness(src->witness) : NULL; + if (src->witness) + wally_tx_witness_stack_clone_alloc(src->witness, &new_witness); #ifdef BUILD_ELEMENTS - new_pegin_witness = src->pegin_witness ? clone_witness(src->pegin_witness) : NULL; + if (src->pegin_witness) + wally_tx_witness_stack_clone_alloc(src->pegin_witness, &new_pegin_witness); #endif if (!clone_bytes(&new_script, src->script, src->script_len) || @@ -582,7 +587,7 @@ static int tx_elements_input_init( struct wally_tx_witness_stack *new_witness = NULL; struct wally_tx_witness_stack *new_pegin_witness = NULL; unsigned char *new_script = NULL; - int ret, old_features; + int ret = WALLY_OK, old_features; if (!txhash || txhash_len != WALLY_TXHASH_LEN || BYTES_INVALID(script, script_len) || !output) @@ -590,11 +595,13 @@ static int tx_elements_input_init( old_features = output->features; - if ((witness && !(new_witness = clone_witness(witness))) || - (pegin_witness && !(new_pegin_witness = clone_witness(pegin_witness))) || - !clone_bytes(&new_script, script, script_len)) + if (witness) + ret = wally_tx_witness_stack_clone_alloc(witness, &new_witness); + if (ret == WALLY_OK && pegin_witness) + ret = wally_tx_witness_stack_clone_alloc(pegin_witness, &new_pegin_witness); + if (ret == WALLY_OK && !clone_bytes(&new_script, script, script_len)) ret = WALLY_ENOMEM; - else { + if (ret == WALLY_OK) { output->features = 0; ret = tx_elements_input_issuance_init(output, nonce, @@ -3249,7 +3256,8 @@ int wally_tx_input_set_witness(struct wally_tx_input *input, if (!is_valid_tx_input(input) || (stack && !is_valid_witness_stack(stack))) return WALLY_EINVAL; - if (stack && (new_witness = clone_witness(stack)) == NULL) + if (stack && + wally_tx_witness_stack_clone_alloc(stack, &new_witness) != WALLY_OK) return WALLY_ENOMEM; tx_witness_stack_free(input->witness, true); diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 2764fe3e1..136ea08fd 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -20,8 +20,6 @@ bool clone_bytes(unsigned char **dst, const unsigned char *src, size_t len); int replace_bytes(const unsigned char *bytes, size_t bytes_len, unsigned char **bytes_out, size_t *bytes_len_out); void *realloc_array(const void *src, size_t old_n, size_t new_n, size_t size); -struct wally_tx_witness_stack *clone_witness( - const struct wally_tx_witness_stack *stack); #ifdef __cplusplus } From d10846b703f15b559497c48cb85a0e2ef10cf164 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 18:31:56 +1200 Subject: [PATCH 182/205] general: Use wally_calloc in more places to simplify code --- src/bip32.c | 5 ++--- src/psbt.c | 9 +++------ src/transaction.c | 3 +-- src/transaction_shared.h | 3 +-- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/bip32.c b/src/bip32.c index 1e1efae1b..0169e60f5 100644 --- a/src/bip32.c +++ b/src/bip32.c @@ -162,10 +162,9 @@ int bip32_key_from_seed(const unsigned char *bytes, size_t bytes_len, #define ALLOC_KEY() \ if (!output) \ return WALLY_EINVAL; \ - *output = wally_malloc(sizeof(struct ext_key)); \ + *output = wally_calloc(sizeof(struct ext_key)); \ if (!*output) \ - return WALLY_ENOMEM; \ - wally_clear((void *)*output, sizeof(struct ext_key)) + return WALLY_ENOMEM int bip32_key_from_seed_alloc(const unsigned char *bytes, size_t bytes_len, uint32_t version, uint32_t flags, diff --git a/src/psbt.c b/src/psbt.c index 92d2e479a..a56fcf3c6 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -58,13 +58,12 @@ int wally_keypath_map_init_alloc(size_t allocation_len, struct wally_keypath_map TX_OUTPUT_ALLOC(struct wally_keypath_map); if (allocation_len) { - result->items = wally_malloc(allocation_len * sizeof(*result->items)); + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, allocation_len * sizeof(*result->items)); } result->items_allocation_len = allocation_len; result->num_items = 0; @@ -198,13 +197,12 @@ int wally_partial_sigs_map_init_alloc(size_t allocation_len, struct wally_partia TX_OUTPUT_ALLOC(struct wally_partial_sigs_map); if (allocation_len) { - result->items = wally_malloc(allocation_len * sizeof(*result->items)); + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, allocation_len * sizeof(*result->items)); } result->items_allocation_len = allocation_len; result->num_items = 0; @@ -315,13 +313,12 @@ int wally_unknowns_map_init_alloc(size_t allocation_len, struct wally_unknowns_m TX_OUTPUT_ALLOC(struct wally_unknowns_map); if (allocation_len) { - result->items = wally_malloc(allocation_len * sizeof(*result->items)); + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, allocation_len * sizeof(*result->items)); } result->items_allocation_len = allocation_len; result->num_items = 0; diff --git a/src/transaction.c b/src/transaction.c index 95a1c4c03..23a416f99 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -230,13 +230,12 @@ int wally_tx_witness_stack_init_alloc(size_t allocation_len, TX_OUTPUT_ALLOC(struct wally_tx_witness_stack); if (allocation_len) { - result->items = wally_malloc(allocation_len * sizeof(*result->items)); + result->items = wally_calloc(allocation_len * sizeof(*result->items)); if (!result->items) { wally_free(result); *output = NULL; return WALLY_ENOMEM; } - wally_clear(result->items, allocation_len * sizeof(*result->items)); } result->items_allocation_len = allocation_len; result->num_items = 0; diff --git a/src/transaction_shared.h b/src/transaction_shared.h index 136ea08fd..4b90f5f15 100644 --- a/src/transaction_shared.h +++ b/src/transaction_shared.h @@ -7,9 +7,8 @@ extern "C" { #define TX_CHECK_OUTPUT if (!output) return WALLY_EINVAL; else *output = NULL #define TX_OUTPUT_ALLOC(typ) \ - *output = wally_malloc(sizeof(typ)); \ + *output = wally_calloc(sizeof(typ)); \ if (!*output) return WALLY_ENOMEM; \ - wally_clear((void *)*output, sizeof(typ)); \ result = (typ *) *output; #define BYTES_VALID(p, len) ((p != NULL) == (len != 0)) From e1aa1939540b174dc913ffb554226201dcb09723 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 22:14:36 +1200 Subject: [PATCH 183/205] psbt: Initial SWIG python wrapper implementation --- src/Makefile.am | 2 ++ src/bip39.c | 2 +- src/psbt.c | 25 ++++++++++++++++++++++ src/psbt_int.h | 36 ++++++++++++++++++++++++++++++++ src/swig_python/contrib/psbt.py | 27 ++++++++++++++++++++++++ src/swig_python/swig.i | 8 +++++++ src/transaction_int.h | 2 +- src/wordlist.c | 2 +- src/wrap_js/src/combined.c | 2 ++ src/wrap_js/src/combined_ccan2.c | 1 + 10 files changed, 104 insertions(+), 3 deletions(-) create mode 100644 src/psbt_int.h create mode 100644 src/swig_python/contrib/psbt.py diff --git a/src/Makefile.am b/src/Makefile.am index cb4cbce66..bec495c38 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -296,7 +296,9 @@ endif if USE_SWIG_PYTHON $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/bip32.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 + $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/signmessage.py $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/tx.py if BUILD_ELEMENTS $(AM_V_at)$(PYTHON_SWIGTEST) swig_python/contrib/elements_tx.py diff --git a/src/bip39.c b/src/bip39.c index 65b39a02a..427774303 100644 --- a/src/bip39.c +++ b/src/bip39.c @@ -203,7 +203,7 @@ int bip39_mnemonic_to_seed(const char *mnemonic, const char *passphrase, unsigned char *bytes_out, size_t len, size_t *written) { - const size_t bip9_cost = 2048u; + const uint32_t bip9_cost = 2048u; const char *prefix = "mnemonic"; const size_t prefix_len = strlen(prefix); const size_t passphrase_len = passphrase ? strlen(passphrase) : 0; diff --git a/src/psbt.c b/src/psbt.c index a56fcf3c6..c520f84db 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -9,6 +9,7 @@ #include #include #include "transaction_shared.h" +#include "psbt_int.h" #include "script_int.h" #include "script.h" #include "pullpush.h" @@ -1059,6 +1060,30 @@ int wally_psbt_free(struct wally_psbt *psbt) return WALLY_OK; } +int wally_psbt_get_global_tx_alloc(const struct wally_psbt *psbt, struct wally_tx **output) +{ + TX_CHECK_OUTPUT; + if (!psbt) + return WALLY_EINVAL; + if (!psbt->tx) + return WALLY_OK; /* Return a NULL tx if not present */ + return wally_tx_clone(psbt->tx, 0, output); +} + +#define PSBT_GET(name) \ + int wally_psbt_get_ ## name(const struct wally_psbt *psbt, size_t *written) { \ + if (written) \ + *written = 0; \ + if (!psbt || !written) \ + return WALLY_EINVAL; \ + *written = psbt->name; \ + return WALLY_OK; \ + } + +PSBT_GET(version) +PSBT_GET(num_inputs) +PSBT_GET(num_outputs) + static int psbt_set_global_tx(struct wally_psbt *psbt, struct wally_tx *tx, bool do_clone) { struct wally_tx *new_tx = NULL; diff --git a/src/psbt_int.h b/src/psbt_int.h new file mode 100644 index 000000000..7e3c3510e --- /dev/null +++ b/src/psbt_int.h @@ -0,0 +1,36 @@ +#ifndef LIBWALLY_CORE_PSBT_INT_H +#define LIBWALLY_CORE_PSBT_INT_H 1 + +#if defined(SWIG) || defined (SWIG_JAVA_BUILD) || defined (SWIG_PYTHON_BUILD) || defined(SWIG_JAVASCRIPT_BUILD) + +#ifdef __cplusplus +extern "C" { +#endif + +/* PSBT */ + +WALLY_CORE_API int wally_psbt_get_global_tx_alloc(const struct wally_psbt *psbt, struct wally_tx **output); +WALLY_CORE_API int wally_psbt_get_version(const struct wally_psbt *psbt, size_t *written); +WALLY_CORE_API int wally_psbt_get_num_inputs(const struct wally_psbt *psbt, size_t *written); +WALLY_CORE_API int wally_psbt_get_num_outputs(const struct wally_psbt *psbt, size_t *written); + +/* Inputs */ + +#ifdef BUILD_ELEMENTS +#endif /* BUILD_ELEMENTS */ + +/* Outputs */ + +#ifdef BUILD_ELEMENTS +#endif /* BUILD_ELEMENTS */ + +#ifdef BUILD_ELEMENTS +#endif /* BUILD_ELEMENTS */ + +#ifdef __cplusplus +} +#endif + +#endif /* SWIG/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD/SWIG_JAVASCRIPT_BUILD */ + +#endif /* LIBWALLY_CORE_PSBT_INT_H */ diff --git a/src/swig_python/contrib/psbt.py b/src/swig_python/contrib/psbt.py new file mode 100644 index 000000000..321303e4e --- /dev/null +++ b/src/swig_python/contrib/psbt.py @@ -0,0 +1,27 @@ +"""Tests for PSBT wrappers""" +import unittest +from wallycore import * + +SAMPLE = "cHNidP8BAFICAAAAAZ38ZijCbFiZ/hvT3DOGZb/VXXraEPYiCXPfLTht7BJ2AQAAAAD/////AfA9zR0AAAAAFgAUezoAv9wU0neVwrdJAdCdpu8TNXkAAAAATwEENYfPAto/0AiAAAAAlwSLGtBEWx7IJ1UXcnyHtOTrwYogP/oPlMAVZr046QADUbdDiH7h1A3DKmBDck8tZFmztaTXPa7I+64EcvO8Q+IM2QxqT64AAIAAAACATwEENYfPAto/0AiAAAABuQRSQnE5zXjCz/JES+NTzVhgXj5RMoXlKLQH+uP2FzUD0wpel8itvFV9rCrZp+OcFyLrrGnmaLbyZnzB1nHIPKsM2QxqT64AAIABAACAAAEBKwBlzR0AAAAAIgAgLFSGEmxJeAeagU4TcV1l82RZ5NbMre0mbQUIZFuvpjIBBUdSIQKdoSzbWyNWkrkVNq/v5ckcOrlHPY5DtTODarRWKZyIcSEDNys0I07Xz5wf6l0F1EFVeSe+lUKxYusC4ass6AIkwAtSriIGAp2hLNtbI1aSuRU2r+/lyRw6uUc9jkO1M4NqtFYpnIhxENkMak+uAACAAAAAgAAAAAAiBgM3KzQjTtfPnB/qXQXUQVV5J76VQrFi6wLhqyzoAiTACxDZDGpPrgAAgAEAAIAAAAAAACICA57/H1R6HV+S36K6evaslxpL0DukpzSwMVaiVritOh75EO3kXMUAAACAAAAAgAEAAIAA" + + +class PSBTTests(unittest.TestCase): + + def test_psbt(self): + psbt = psbt_from_base64(SAMPLE) + + self.assertIsNotNone(psbt_get_global_tx(psbt)) + + self.assertEqual(psbt_get_version(psbt), 0) + self.assertEqual(psbt_get_num_inputs(psbt), 1) + self.assertEqual(psbt_get_num_outputs(psbt), 1) + + self.assertEqual(psbt_to_base64(psbt, 0), SAMPLE) + + # Combining with ourselves shouldn't change the PSBT + psbt_combine(psbt, psbt) + self.assertEqual(psbt_to_base64(psbt, 0), SAMPLE) + + +if __name__ == '__main__': + unittest.main() diff --git a/src/swig_python/swig.i b/src/swig_python/swig.i index 4daa71a01..c3f1e9234 100644 --- a/src/swig_python/swig.i +++ b/src/swig_python/swig.i @@ -28,6 +28,8 @@ del swig_import_helper #include "../include/wally_bip38.h" #include "../include/wally_bip39.h" #include "../include/wally_crypto.h" +#include "../include/wally_psbt.h" +#include "psbt_int.h" #include "../include/wally_script.h" #include "../include/wally_symmetric.h" #include "../include/wally_transaction.h" @@ -83,6 +85,7 @@ static bool ulonglong_cast(PyObject *item, unsigned long long *val) if (p) fn(p); } capsule_dtor(ext_key, bip32_key_free) +capsule_dtor(wally_psbt, wally_psbt_free) capsule_dtor(wally_tx, wally_tx_free) capsule_dtor(wally_tx_input, wally_tx_input_free) capsule_dtor(wally_tx_output, wally_tx_output_free) @@ -329,6 +332,7 @@ static void destroy_words(PyObject *obj) { (void)obj; } %py_opaque_struct(words); %py_opaque_struct(ext_key); +%py_opaque_struct(wally_psbt); %py_opaque_struct(wally_tx_witness_stack); %py_opaque_struct(wally_tx_input); %py_opaque_struct(wally_tx_output); @@ -346,6 +350,8 @@ static void destroy_words(PyObject *obj) { (void)obj; } %rename("tx_output_init") wally_tx_output_init_alloc; %rename("tx_output_clone") wally_tx_output_clone_alloc; %rename("tx_witness_stack_clone") wally_tx_witness_stack_clone_alloc; +%rename("psbt_init") wally_psbt_init_alloc; +%rename("psbt_get_global_tx") wally_psbt_get_global_tx_alloc; %rename("tx_init") wally_tx_init_alloc; %rename("tx_elements_input_init") wally_tx_elements_input_init_alloc; %rename("tx_elements_output_init") wally_tx_elements_output_init_alloc; @@ -359,6 +365,8 @@ static void destroy_words(PyObject *obj) { (void)obj; } %include "../include/wally_bip39.h" %include "../include/wally_crypto.h" %include "../include/wally_script.h" +%include "../include/wally_psbt.h" +%include "psbt_int.h" %include "../include/wally_symmetric.h" %include "../include/wally_transaction.h" %include "transaction_int.h" diff --git a/src/transaction_int.h b/src/transaction_int.h index 07aaf738b..f58452d9c 100644 --- a/src/transaction_int.h +++ b/src/transaction_int.h @@ -136,6 +136,6 @@ WALLY_CORE_API int wally_tx_set_output_rangeproof(const struct wally_tx *tx_in, } #endif -#endif /* SWIG_JAVA_BUILD/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD */ +#endif /* SWIG/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD/SWIG_JAVASCRIPT_BUILD */ #endif /* LIBWALLY_CORE_TRANSACTION_INT_H */ diff --git a/src/wordlist.c b/src/wordlist.c index b24211bb0..6c45dbae0 100644 --- a/src/wordlist.c +++ b/src/wordlist.c @@ -7,7 +7,7 @@ static int bstrcmp(const void *l, const void *r) } /* https://graphics.stanford.edu/~seander/bithacks.html#IntegerLogObvious */ -static int get_bits(size_t n) +static size_t get_bits(size_t n) { size_t bits = 0; while (n >>= 1) diff --git a/src/wrap_js/src/combined.c b/src/wrap_js/src/combined.c index 27e8db552..9b8bcf0db 100644 --- a/src/wrap_js/src/combined.c +++ b/src/wrap_js/src/combined.c @@ -14,6 +14,8 @@ #include "hmac.c" #include "mnemonic.c" #include "pbkdf2.c" +#include "pullpush.c" +#include "psbt.c" #include "script.c" #include "scrypt.c" #include "sign.c" diff --git a/src/wrap_js/src/combined_ccan2.c b/src/wrap_js/src/combined_ccan2.c index fbf19b50b..e74d46429 100644 --- a/src/wrap_js/src/combined_ccan2.c +++ b/src/wrap_js/src/combined_ccan2.c @@ -1,2 +1,3 @@ #include "internal.h" #include "ccan/ccan/crypto/ripemd160/ripemd160.c" +#include "src/ccan/ccan/base64/base64.c" From c9ac89e65157ba78d3fd5ea882d74211b6a9b117 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 22:48:12 +1200 Subject: [PATCH 184/205] psbt: Add combining to psbt ctest for valgrind checking --- src/ctest/test_psbt.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/ctest/test_psbt.c b/src/ctest/test_psbt.c index 8bac62ddb..0cfdd9f9f 100644 --- a/src/ctest/test_psbt.c +++ b/src/ctest/test_psbt.c @@ -22,7 +22,7 @@ int main(void) for (i = 0; i < sizeof(valid_psbts) / sizeof(valid_psbts[0]); i++) { const char *base64_in = valid_psbts[i].base64; - struct wally_psbt *psbt; + struct wally_psbt *psbt, *psbt_clone; char *output; unsigned char *bytes; size_t len, written; @@ -57,8 +57,15 @@ int main(void) errx(1, "psbt[%zi] bytes %s not %s", i, output, valid_psbts[i].hex); wally_free_string(output); - free(bytes); + + if (wally_psbt_from_base64(base64_in, &psbt_clone) != WALLY_OK) + errx(1, "Failed to parse psbt clone %s", base64_in); + + if (wally_psbt_combine(psbt_clone, psbt) != WALLY_OK) + errx(1, "Failed to combine psbts %s", base64_in); + + wally_psbt_free(psbt_clone); wally_psbt_free(psbt); } From 942c009b76307683906ad0a8559f7c648a22bb2c Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 23:54:44 +1200 Subject: [PATCH 185/205] psbt: remove unused pull_psbt_key_start function --- src/psbt.c | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index c520f84db..779a677da 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1137,29 +1137,6 @@ int wally_psbt_set_global_tx(struct wally_psbt *psbt, const struct wally_tx *tx) return psbt_set_global_tx(psbt, (struct wally_tx *)tx, true); } -/* Returns false if it hits a zero length "key" (i.e. separator) or EOF. - * - * Otherwise, starts the subfield (extra, extra_len), so caller should - * call pull_subfield_end(cursor, max, extra, extra_len) if this - * returns true. - */ -static bool pull_psbt_key_start( - const unsigned char **cursor, size_t *max, - uint64_t *type, - const unsigned char **extra, size_t *extra_len) -{ - size_t key_len; - - key_len = pull_varlength(cursor, max); - /* This incidentally covers the case where *cursor is NULL */ - if (key_len == 0) { - return false; - } - pull_subfield_start(cursor, max, key_len, extra, extra_len); - *type = pull_varint(cursor, max); - return true; -} - /* clones varlength field entirely. */ static bool clone_varlength(unsigned char **dst, size_t *len, From 1abd2a0495cb440bae8dfeb67563d6b113bfd613 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Mon, 20 Jul 2020 23:56:08 +1200 Subject: [PATCH 186/205] tests: fix clang warning --- src/ctest/test_clear.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ctest/test_clear.c b/src/ctest/test_clear.c index e2598ed5a..fc11c0bc8 100644 --- a/src/ctest/test_clear.c +++ b/src/ctest/test_clear.c @@ -86,7 +86,7 @@ static bool in_stack(const char *caller, const void *search, size_t len) for (i = 0; i < PTHREAD_STACK_MIN - len - 1; ++i) if (!memcmp(gstack + i, search, len)) { if (caller) { - printf("Found %s secret at stack position %ld and base %p\n", caller, (long)i, gstack); + printf("Found %s secret at stack position %ld and base %p\n", caller, (long)i, (void *)gstack); dump_mem(search, len); } return true; /* Found */ From 71ffd971c3ddf03c41ab8ea32d17c576cc0dd8a0 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 21 Jul 2020 10:09:16 +1200 Subject: [PATCH 187/205] psbt: Windows build fixes --- src/psbt.c | 25 +++++++++++++++++-------- src/pullpush.h | 3 +-- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 779a677da..46a6641c5 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2224,19 +2224,28 @@ static int push_psbt_input( #ifdef BUILD_ELEMENTS if ((flags & WALLY_TX_FLAG_USE_ELEMENTS) && input->witness_utxo) { struct wally_tx_output *utxo = input->witness_utxo; - size_t buf_len = push_elements_bytes_size(utxo); - unsigned char buf[buf_len], *ptr = buf; + const size_t buff_len = push_elements_bytes_size(utxo); + size_t remaining = buff_len; + unsigned char buff[1024], *buff_p = buff, *ptr; + + if (buff_len > sizeof(buff) && !(buff_p = wally_malloc(buff_len))) + return WALLY_ENOMEM; + ptr = buff_p; + /* Push the asset, value, nonce, then scriptpubkey */ push_psbt_key(cursor, max, WALLY_PSBT_IN_WITNESS_UTXO, NULL, 0); - push_elements_bytes(&ptr, &buf_len, utxo->asset, utxo->asset_len); - push_elements_bytes(&ptr, &buf_len, utxo->value, utxo->value_len); - push_elements_bytes(&ptr, &buf_len, utxo->nonce, utxo->nonce_len); - push_varbuff(&ptr, &buf_len, utxo->script, utxo->script_len); + push_elements_bytes(&ptr, &remaining, utxo->asset, utxo->asset_len); + push_elements_bytes(&ptr, &remaining, utxo->value, utxo->value_len); + push_elements_bytes(&ptr, &remaining, utxo->nonce, utxo->nonce_len); + push_varbuff(&ptr, &remaining, utxo->script, utxo->script_len); - if (buf_len != 0) + if (!remaining) + push_varbuff(cursor, max, buff_p, buff_len); + if (buff_p != buff) + clear_and_free(buff_p, buff_len); + if (remaining) return WALLY_ERROR; /* Should not happen! */ - push_varbuff(cursor, max, buf, sizeof(buf)); } else #endif /* BUILD_ELEMENTS */ if (input->witness_utxo) { diff --git a/src/pullpush.h b/src/pullpush.h index 73cd6f2a5..e811bb9b3 100644 --- a/src/pullpush.h +++ b/src/pullpush.h @@ -84,7 +84,6 @@ void pull_subfield_start(const unsigned char *const *cursor, const size_t *max, const unsigned char **subcursor, size_t *submax); void pull_subfield_end(const unsigned char **cursor, size_t *max, - const unsigned char *subcursor, - const size_t submax); + const unsigned char *subcursor, size_t submax); #endif /* LIBWALLY_CORE_PULLPUSH_H */ From 384947faaa06fb03daf8323e8bc49b364c20d38b Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 21 Jul 2020 22:46:16 +1200 Subject: [PATCH 188/205] psbt: Add non-elements swig setters, with tests Exposes the types used by the setters and renames some things so the existing SWIG pattern matches work for types. --- include/wally_psbt.h | 44 +++++++------- src/psbt.c | 102 +++++++++++++++++++++++++------- src/psbt_int.h | 16 ++++- src/swig_python/contrib/psbt.py | 62 +++++++++++++++++++ src/swig_python/swig.i | 38 ++++++++---- 5 files changed, 203 insertions(+), 59 deletions(-) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 4d598ce07..824b425b1 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -209,37 +209,37 @@ WALLY_CORE_API int wally_keypath_map_free( /** * Find an item in a keypath map. * - * :param keypaths: The keypath map to find ``pubkey`` in. - * :param pubkey: The pubkey to find. - * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param keypaths: The keypath map to find ``pub_key`` in. + * :param pub_key: The pubkey to find. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. * :param written: On success, set to zero if the item is not found, otherwise *| the index of the item plus one. */ WALLY_CORE_API int wally_keypath_map_find( const struct wally_keypath_map *keypaths, - const unsigned char *pubkey, - size_t pubkey_len, + const unsigned char *pub_key, + size_t pub_key_len, size_t *written); /** * Add an item to a keypath map. * * :param keypaths: The keypath map to add to. - * :param pubkey: The pubkey to add. - * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param pub_key: The pubkey to add. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. * :param fingerprint: The master key fingerprint for the pubkey. * :param fingerprint_len: Length of ``fingerprint`` in bytes. Must be ``BIP32_KEY_FINGERPRINT_LEN``. - * :param path: The BIP32 derivation path for the pubkey. - * :param path_len: The number of items in path. + * :param child_path: The BIP32 derivation path for the pubkey. + * :param child_path_len: The number of items in ``child_path``. */ WALLY_CORE_API int wally_keypath_map_add( struct wally_keypath_map *keypaths, - const unsigned char *pubkey, - size_t pubkey_len, + const unsigned char *pub_key, + size_t pub_key_len, const unsigned char *fingerprint, size_t fingerprint_len, - const uint32_t *path, - size_t path_len); + const uint32_t *child_path, + size_t child_path_len); /** * Allocate and initialize a new partial sigs map. @@ -264,31 +264,31 @@ WALLY_CORE_API int wally_partial_sigs_map_free( /** * Find an item in a partial sigs map. * - * :param sigs: The partial sigs map to find ``pubkey`` in. - * :param pubkey: The pubkey to find. - * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. + * :param sigs: The partial sigs map to find ``pub_key`` in. + * :param pub_key: The pubkey to find. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` or ``EC_PUBLIC_KEY_LEN``. * :param written: On success, set to zero if the item is not found, otherwise *| the index of the item plus one. */ WALLY_CORE_API int wally_partial_sigs_map_find( const struct wally_partial_sigs_map *sigs, - const unsigned char *pubkey, - size_t pubkey_len, + const unsigned char *pub_key, + size_t pub_key_len, size_t *written); /** * Add an item to a partial sigs map. * * :param sigs: The partial sigs map to add to. - * :param pubkey: The pubkey to add. - * :param pubkey_len: Length of ``pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN`` or ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` + * :param pub_key: The pubkey to add. + * :param pub_key_len: Length of ``pub_key`` in bytes. Must be ``EC_PUBLIC_KEY_LEN`` or ``EC_PUBLIC_KEY_UNCOMPRESSED_LEN`` * :param sig: The DER-encoded signature to add. * :param sig_len: Length of ``sig`` in bytes. */ WALLY_CORE_API int wally_partial_sigs_map_add( struct wally_partial_sigs_map *sigs, - const unsigned char *pubkey, - size_t pubkey_len, + const unsigned char *pub_key, + size_t pub_key_len, const unsigned char *sig, size_t sig_len); diff --git a/src/psbt.c b/src/psbt.c index 46a6641c5..ae1050a18 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -22,15 +22,15 @@ static const uint8_t WALLY_ELEMENTS_ID[8] = {'e', 'l', 'e', 'm', 'e', 'n', 't', static const size_t WALLY_ELEMENTS_ID_LEN = 8; #endif /* BUILD_ELEMENTS */ -static bool pubkey_is_compressed(const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { - return pubkey[0] == 0x02 || pubkey[0] == 0x03; +static bool pubkey_is_compressed(const unsigned char pub_key[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) { + return pub_key[0] == 0x02 || pub_key[0] == 0x03; } -static size_t get_pubkey_len(const unsigned char *pubkey, size_t pubkey_len) +static size_t get_pubkey_len(const unsigned char *pub_key, size_t pub_key_len) { - if (!pubkey_len) + if (!pub_key_len) return 0; - return pubkey_is_compressed(pubkey) ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN; + return pubkey_is_compressed(pub_key) ? EC_PUBLIC_KEY_LEN : EC_PUBLIC_KEY_UNCOMPRESSED_LEN; } static bool is_valid_pubkey_len(size_t len) @@ -86,7 +86,7 @@ int wally_keypath_map_free(struct wally_keypath_map *keypaths) } int wally_keypath_map_find(const struct wally_keypath_map *keypaths, - const unsigned char *pubkey, size_t pubkey_len, + const unsigned char *pub_key, size_t pub_key_len, size_t *written) { size_t i; @@ -94,13 +94,13 @@ int wally_keypath_map_find(const struct wally_keypath_map *keypaths, if (written) *written = 0; - if (!keypaths || !pubkey || !is_valid_pubkey_len(pubkey_len) || !written) + if (!keypaths || !pub_key || !is_valid_pubkey_len(pub_key_len) || !written) return WALLY_EINVAL; for (i = 0; i < keypaths->num_items; ++i) { const struct wally_keypath_item *item = &keypaths->items[i]; - if (is_equal_pubkey(pubkey, pubkey_len, + if (is_equal_pubkey(pub_key, pub_key_len, item->pubkey, get_pubkey_len(item->pubkey, sizeof(item->pubkey)))) { *written = i + 1; /* Found */ break; @@ -111,8 +111,8 @@ int wally_keypath_map_find(const struct wally_keypath_map *keypaths, static int add_keypath_item(struct wally_keypath_map *keypaths, const struct wally_keypath_item *item) { - const size_t pubkey_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - return wally_keypath_map_add(keypaths, item->pubkey, pubkey_len, + const size_t pub_key_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + return wally_keypath_map_add(keypaths, item->pubkey, pub_key_len, item->fingerprint, BIP32_KEY_FINGERPRINT_LEN, item->path, item->path_len); } @@ -157,19 +157,19 @@ static int array_grow(void **src, size_t num_items, size_t *allocation_len, size } int wally_keypath_map_add(struct wally_keypath_map *keypaths, - const unsigned char *pubkey, size_t pubkey_len, + const unsigned char *pub_key, size_t pub_key_len, const unsigned char *fingerprint, size_t fingerprint_len, const uint32_t *path, size_t path_len) { size_t is_found; int ret; - if (!keypaths || !pubkey || !is_valid_pubkey_len(pubkey_len) || + if (!keypaths || !pub_key || !is_valid_pubkey_len(pub_key_len) || !fingerprint || fingerprint_len != BIP32_KEY_FINGERPRINT_LEN || BYTES_INVALID(path, path_len)) return WALLY_EINVAL; - ret = wally_keypath_map_find(keypaths, pubkey, pubkey_len, &is_found); + ret = wally_keypath_map_find(keypaths, pub_key, pub_key_len, &is_found); if (ret != WALLY_OK || is_found) return ret; /* Return WALLY_OK and do nothing if already present */ @@ -183,7 +183,7 @@ int wally_keypath_map_add(struct wally_keypath_map *keypaths, return WALLY_ENOMEM; new_item->path_len = path_len; } - memcpy(new_item->pubkey, pubkey, pubkey_len); + memcpy(new_item->pubkey, pub_key, pub_key_len); memcpy(new_item->fingerprint, fingerprint, fingerprint_len); keypaths->num_items++; } @@ -224,7 +224,7 @@ int wally_partial_sigs_map_free(struct wally_partial_sigs_map *sigs) } int wally_partial_sigs_map_find(const struct wally_partial_sigs_map *partial_sigs, - const unsigned char *pubkey, size_t pubkey_len, + const unsigned char *pub_key, size_t pub_key_len, size_t *written) { size_t i; @@ -232,13 +232,13 @@ int wally_partial_sigs_map_find(const struct wally_partial_sigs_map *partial_sig if (written) *written = 0; - if (!partial_sigs || !pubkey || !is_valid_pubkey_len(pubkey_len) || !written) + if (!partial_sigs || !pub_key || !is_valid_pubkey_len(pub_key_len) || !written) return WALLY_EINVAL; for (i = 0; i < partial_sigs->num_items; ++i) { const struct wally_partial_sigs_item *item = &partial_sigs->items[i]; - if (is_equal_pubkey(pubkey, pubkey_len, + if (is_equal_pubkey(pub_key, pub_key_len, item->pubkey, get_pubkey_len(item->pubkey, sizeof(item->pubkey)))) { *written = i + 1; /* Found */ break; @@ -249,8 +249,8 @@ int wally_partial_sigs_map_find(const struct wally_partial_sigs_map *partial_sig static int add_partial_sig_item(struct wally_partial_sigs_map *sigs, const struct wally_partial_sigs_item *item) { - const size_t pubkey_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - return wally_partial_sigs_map_add(sigs, item->pubkey, pubkey_len, + const size_t pub_key_len = get_pubkey_len(item->pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); + return wally_partial_sigs_map_add(sigs, item->pubkey, pub_key_len, item->sig, item->sig_len); } @@ -278,17 +278,17 @@ static int replace_partial_sigs(const struct wally_partial_sigs_map *src, } int wally_partial_sigs_map_add(struct wally_partial_sigs_map *sigs, - const unsigned char *pubkey, size_t pubkey_len, + const unsigned char *pub_key, size_t pub_key_len, const unsigned char *sig, size_t sig_len) { size_t is_found; int ret; - if (!sigs || !pubkey || !is_valid_pubkey_len(pubkey_len) || + if (!sigs || !pub_key || !is_valid_pubkey_len(pub_key_len) || BYTES_INVALID(sig, sig_len)) return WALLY_EINVAL; - ret = wally_partial_sigs_map_find(sigs, pubkey, pubkey_len, &is_found); + ret = wally_partial_sigs_map_find(sigs, pub_key, pub_key_len, &is_found); if (ret != WALLY_OK || is_found) return ret; /* Return WALLY_OK and do nothing if already present */ @@ -300,7 +300,7 @@ int wally_partial_sigs_map_add(struct wally_partial_sigs_map *sigs, if (sig && !clone_bytes(&new_item->sig, sig, sig_len)) return WALLY_ENOMEM; new_item->sig_len = sig_len; - memcpy(&new_item->pubkey, pubkey, pubkey_len); + memcpy(&new_item->pubkey, pub_key, pub_key_len); sigs->num_items++; } return ret; @@ -3281,3 +3281,59 @@ int wally_psbt_is_elements(const struct wally_psbt *psbt, size_t *written) *written = memcmp(psbt->magic, WALLY_ELEMENTS_PSBT_MAGIC, sizeof(psbt->magic)) ? 0 : 1; return WALLY_OK; } + +#if defined(SWIG) || defined (SWIG_JAVA_BUILD) || defined (SWIG_PYTHON_BUILD) || defined (SWIG_JAVASCRIPT_BUILD) + +static struct wally_psbt_input *psbt_get_input(const struct wally_psbt *psbt, size_t index) +{ + return psbt && index < psbt->num_inputs ? &psbt->inputs[index] : NULL; +} + +static struct wally_psbt_output *psbt_get_output(const struct wally_psbt *psbt, size_t index) +{ + return psbt && index < psbt->num_outputs ? &psbt->outputs[index] : NULL; +} + +/* Set a binary buffer value on an input/output */ +#define PSBT_SET_B(typ, name) \ + int wally_psbt_set_ ## typ ## _ ## name(struct wally_psbt *psbt, size_t index, \ + const unsigned char *name, size_t name ## _len) { \ + return wally_psbt_ ## typ ## _set_ ## name(psbt_get_ ## typ(psbt, index), name, name ## _len); \ + } + +/* Set an integer value on an input/output */ +#define PSBT_SET_I(typ, name, inttyp) \ + int wally_psbt_set_ ## typ ## _ ## name(struct wally_psbt *psbt, size_t index, \ + inttyp v) { \ + struct wally_psbt_ ## typ *p = psbt_get_ ## typ(psbt, index); \ + if (!p) \ + return WALLY_EINVAL; \ + p->name = v; \ + return WALLY_OK; \ + } + +/* Set a struct on an input/output */ +#define PSBT_SET_S(typ, name, structtyp) \ + int wally_psbt_set_ ## typ ## _ ## name(struct wally_psbt *psbt, size_t index, \ + const struct structtyp *p) { \ + return wally_psbt_ ## typ ## _set_ ## name(psbt_get_ ## typ(psbt, index), p); \ + } + + +PSBT_SET_S(input, non_witness_utxo, wally_tx) +PSBT_SET_S(input, witness_utxo, wally_tx_output) +PSBT_SET_B(input, redeem_script) +PSBT_SET_B(input, witness_script) +PSBT_SET_B(input, final_script_sig) +PSBT_SET_S(input, final_witness, wally_tx_witness_stack) +PSBT_SET_S(input, keypaths, wally_keypath_map) +PSBT_SET_S(input, partial_sigs, wally_partial_sigs_map) +PSBT_SET_S(input, unknowns, wally_unknowns_map) +PSBT_SET_I(input, sighash_type, uint32_t) + +PSBT_SET_B(output, redeem_script) +PSBT_SET_B(output, witness_script) +PSBT_SET_S(output, keypaths, wally_keypath_map) +PSBT_SET_S(output, unknowns, wally_unknowns_map) + +#endif /* SWIG/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD/SWIG_JAVASCRIPT_BUILD */ diff --git a/src/psbt_int.h b/src/psbt_int.h index 7e3c3510e..474786870 100644 --- a/src/psbt_int.h +++ b/src/psbt_int.h @@ -15,12 +15,26 @@ WALLY_CORE_API int wally_psbt_get_num_inputs(const struct wally_psbt *psbt, size WALLY_CORE_API int wally_psbt_get_num_outputs(const struct wally_psbt *psbt, size_t *written); /* Inputs */ - +WALLY_CORE_API int wally_psbt_set_input_non_witness_utxo(struct wally_psbt *psbt, size_t index, const struct wally_tx *non_witness_utxo); +WALLY_CORE_API int wally_psbt_set_input_witness_utxo(struct wally_psbt *psbt, size_t index, const struct wally_tx_output *witness_utxo); +WALLY_CORE_API int wally_psbt_set_input_redeem_script(struct wally_psbt *psbt, size_t index, const unsigned char *redeem_script, size_t redeem_script_len); +WALLY_CORE_API int wally_psbt_set_input_witness_script(struct wally_psbt *psbt, size_t index, const unsigned char *witness_script, size_t witness_script_len); +WALLY_CORE_API int wally_psbt_set_input_final_script_sig(struct wally_psbt *psbt, size_t index, const unsigned char *final_script_sig, size_t final_script_sig_len); +WALLY_CORE_API int wally_psbt_set_input_final_witness(struct wally_psbt *psbt, size_t index, const struct wally_tx_witness_stack *final_witness); +WALLY_CORE_API int wally_psbt_set_input_keypaths(struct wally_psbt *psbt, size_t index, const struct wally_keypath_map *keypaths); +WALLY_CORE_API int wally_psbt_set_input_partial_sigs(struct wally_psbt *psbt, size_t index, const struct wally_partial_sigs_map *partial_sigs); +WALLY_CORE_API int wally_psbt_set_input_unknowns(struct wally_psbt *psbt, size_t index, const struct wally_unknowns_map *unknowns); +WALLY_CORE_API int wally_psbt_set_input_sighash_type(struct wally_psbt *psbt, size_t index, uint32_t sighash_type); #ifdef BUILD_ELEMENTS #endif /* BUILD_ELEMENTS */ /* Outputs */ +WALLY_CORE_API int wally_psbt_set_output_redeem_script(struct wally_psbt *psbt, size_t index, const unsigned char *redeem_script, size_t redeem_script_len); +WALLY_CORE_API int wally_psbt_set_output_witness_script(struct wally_psbt *psbt, size_t index, const unsigned char *witness_script, size_t witness_script_len); +WALLY_CORE_API int wally_psbt_set_output_keypaths(struct wally_psbt *psbt, size_t index, const struct wally_keypath_map *keypaths); +WALLY_CORE_API int wally_psbt_set_output_unknowns(struct wally_psbt *psbt, size_t index, const struct wally_unknowns_map *unknowns); + #ifdef BUILD_ELEMENTS #endif /* BUILD_ELEMENTS */ diff --git a/src/swig_python/contrib/psbt.py b/src/swig_python/contrib/psbt.py index 321303e4e..50ba6d7c6 100644 --- a/src/swig_python/contrib/psbt.py +++ b/src/swig_python/contrib/psbt.py @@ -7,6 +7,15 @@ class PSBTTests(unittest.TestCase): + def _try_set(self, fn, psbt, valid_value, null_value=None): + fn(psbt, 0, valid_value) # Set + fn(psbt, 0, null_value) # Un-set + with self.assertRaises(ValueError): + fn(None, 0, valid_value) # Null PSBT + with self.assertRaises(ValueError): + fn(psbt, 1, valid_value) # Invalid index + + def test_psbt(self): psbt = psbt_from_base64(SAMPLE) @@ -16,12 +25,65 @@ def test_psbt(self): self.assertEqual(psbt_get_num_inputs(psbt), 1) self.assertEqual(psbt_get_num_outputs(psbt), 1) + # Conversion to base64 should round trip self.assertEqual(psbt_to_base64(psbt, 0), SAMPLE) # Combining with ourselves shouldn't change the PSBT psbt_combine(psbt, psbt) self.assertEqual(psbt_to_base64(psbt, 0), SAMPLE) + # Test setters + dummy_tx = psbt_get_global_tx(psbt) + self.assertIsNotNone(dummy_tx) + + dummy_txout = tx_output_init(1234567, bytearray(b'\x00' * 33)) + + dummy_witness = tx_witness_stack_init(5) + self.assertIsNotNone(dummy_witness) + + dummy_bytes = bytearray(b'\x00' * 32) + dummy_pubkey = bytearray(b'\x02'* EC_PUBLIC_KEY_LEN) + dummy_fingerprint = bytearray(b'\x00' * BIP32_KEY_FINGERPRINT_LEN) + dummy_path = [1234, 1234, 1234] + dummy_sig = bytearray(b'\x00' * 72) + + dummy_keypaths = keypath_map_init(0) + self.assertIsNotNone(dummy_keypaths) + keypath_map_add(dummy_keypaths, dummy_pubkey, dummy_fingerprint, dummy_path) + self.assertEqual(keypath_map_find(dummy_keypaths, dummy_pubkey), 1) + + dummy_partial_sigs = partial_sigs_map_init(0) + self.assertIsNotNone(dummy_partial_sigs) + partial_sigs_map_add(dummy_partial_sigs, dummy_pubkey, dummy_sig) + self.assertEqual(partial_sigs_map_find(dummy_partial_sigs, dummy_pubkey), 1) + + dummy_unknowns = unknowns_map_init(1) + self.assertIsNotNone(dummy_unknowns) + unknowns_map_add(dummy_unknowns, dummy_pubkey, dummy_fingerprint) + self.assertEqual(unknowns_map_find(dummy_unknowns, dummy_pubkey), 1) + + # + # Inputs + # + self._try_set(psbt_set_input_non_witness_utxo, psbt, dummy_tx) + self._try_set(psbt_set_input_witness_utxo, psbt, dummy_txout) + self._try_set(psbt_set_input_final_witness, psbt, dummy_witness) + self._try_set(psbt_set_input_keypaths, psbt, dummy_keypaths) + self._try_set(psbt_set_input_partial_sigs, psbt, dummy_partial_sigs) + self._try_set(psbt_set_input_unknowns, psbt, dummy_unknowns) + self._try_set(psbt_set_input_sighash_type, psbt, 0xff, 0x0) + self._try_set(psbt_set_input_redeem_script, psbt, dummy_bytes) + self._try_set(psbt_set_input_witness_script, psbt, dummy_bytes) + self._try_set(psbt_set_input_final_script_sig, psbt, dummy_bytes) + + # + # Outputs + # + self._try_set(psbt_set_output_redeem_script, psbt, dummy_bytes) + self._try_set(psbt_set_output_witness_script, psbt, dummy_bytes) + self._try_set(psbt_set_output_keypaths, psbt, dummy_keypaths) + self._try_set(psbt_set_output_unknowns, psbt, dummy_unknowns) + if __name__ == '__main__': unittest.main() diff --git a/src/swig_python/swig.i b/src/swig_python/swig.i index c3f1e9234..5270e05d5 100644 --- a/src/swig_python/swig.i +++ b/src/swig_python/swig.i @@ -85,11 +85,14 @@ static bool ulonglong_cast(PyObject *item, unsigned long long *val) if (p) fn(p); } capsule_dtor(ext_key, bip32_key_free) +capsule_dtor(wally_keypath_map, wally_keypath_map_free) +capsule_dtor(wally_partial_sigs_map, wally_partial_sigs_map_free) capsule_dtor(wally_psbt, wally_psbt_free) capsule_dtor(wally_tx, wally_tx_free) capsule_dtor(wally_tx_input, wally_tx_input_free) capsule_dtor(wally_tx_output, wally_tx_output_free) capsule_dtor(wally_tx_witness_stack, wally_tx_witness_stack_free) +capsule_dtor(wally_unknowns_map, wally_unknowns_map_free) static void destroy_words(PyObject *obj) { (void)obj; } #define MAX_LOCAL_STACK 256u @@ -239,7 +242,10 @@ static void destroy_words(PyObject *obj) { (void)obj; } %pybuffer_nonnull_binary(const unsigned char *parent_genesis_blockhash, size_t parent_genesis_blockhash_len); %pybuffer_nonnull_binary(const unsigned char *mainchain_script, size_t mainchain_script_len); %pybuffer_nonnull_binary(const unsigned char *whitelist_proof, size_t whitelist_proof_len); -%pybuffer_nonnull_binary(const unsigned char *redeem_script, size_t redeem_script_len); +%pybuffer_nullable_binary(const unsigned char *redeem_script, size_t redeem_script_len); +%pybuffer_nullable_binary(const unsigned char *witness_script, size_t witness_script_len); +%pybuffer_nullable_binary(const unsigned char *final_script_sig, size_t final_script_sig_len); +%pybuffer_nullable_binary(const unsigned char *fingerprint, size_t fingerprint_len); /* Output buffers */ %pybuffer_output_binary(unsigned char *asset_out, size_t asset_out_len); @@ -330,31 +336,37 @@ static void destroy_words(PyObject *obj) { (void)obj; } %py_int_array(uint32_t, 0xffull, sighash, sighash_len) %py_int_array(uint64_t, 0xffffffffffffffffull, values, values_len) -%py_opaque_struct(words); %py_opaque_struct(ext_key); +%py_opaque_struct(wally_keypath_map) +%py_opaque_struct(wally_partial_sigs_map) %py_opaque_struct(wally_psbt); -%py_opaque_struct(wally_tx_witness_stack); +%py_opaque_struct(wally_tx); %py_opaque_struct(wally_tx_input); %py_opaque_struct(wally_tx_output); -%py_opaque_struct(wally_tx); +%py_opaque_struct(wally_tx_witness_stack); +%py_opaque_struct(wally_unknowns_map) +%py_opaque_struct(words); +%rename("bip32_key_from_base58") bip32_key_from_base58_alloc; %rename("bip32_key_from_parent") bip32_key_from_parent_alloc; %rename("bip32_key_from_parent_path") bip32_key_from_parent_path_alloc; -%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; %rename("bip32_key_from_seed") bip32_key_from_seed_alloc; %rename("bip32_key_init") bip32_key_init_alloc; -%rename("bip32_key_from_base58") bip32_key_from_base58_alloc; %rename("bip32_key_unserialize") bip32_key_unserialize_alloc; -%rename("tx_witness_stack_init") wally_tx_witness_stack_init_alloc; -%rename("tx_input_init") wally_tx_input_init_alloc; -%rename("tx_output_init") wally_tx_output_init_alloc; -%rename("tx_output_clone") wally_tx_output_clone_alloc; -%rename("tx_witness_stack_clone") wally_tx_witness_stack_clone_alloc; -%rename("psbt_init") wally_psbt_init_alloc; +%rename("bip32_key_with_tweak_from_parent_path") bip32_key_with_tweak_from_parent_path_alloc; +%rename("keypath_map_init") wally_keypath_map_init_alloc; +%rename("partial_sigs_map_init") wally_partial_sigs_map_init_alloc; %rename("psbt_get_global_tx") wally_psbt_get_global_tx_alloc; -%rename("tx_init") wally_tx_init_alloc; +%rename("psbt_init") wally_psbt_init_alloc; %rename("tx_elements_input_init") wally_tx_elements_input_init_alloc; %rename("tx_elements_output_init") wally_tx_elements_output_init_alloc; +%rename("tx_init") wally_tx_init_alloc; +%rename("tx_input_init") wally_tx_input_init_alloc; +%rename("tx_output_clone") wally_tx_output_clone_alloc; +%rename("tx_output_init") wally_tx_output_init_alloc; +%rename("tx_witness_stack_clone") wally_tx_witness_stack_clone_alloc; +%rename("tx_witness_stack_init") wally_tx_witness_stack_init_alloc; +%rename("unknowns_map_init") wally_unknowns_map_init_alloc; %rename("%(regex:/^wally_(.+)/\\1/)s", %$isfunction) ""; %include "../include/wally_core.h" From 204419a8801a4e994a4bf88a1e59ede7176fc1cc Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Tue, 21 Jul 2020 22:51:03 +1200 Subject: [PATCH 189/205] symmetric: Add missing symmetric header to install list --- src/Makefile.am | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Makefile.am b/src/Makefile.am index bec495c38..9e0e6da46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -16,6 +16,7 @@ include_HEADERS += $(top_srcdir)/include/wally_crypto.h include_HEADERS += $(top_srcdir)/include/wally_elements.h include_HEADERS += $(top_srcdir)/include/wally_psbt.h include_HEADERS += $(top_srcdir)/include/wally_script.h +include_HEADERS += $(top_srcdir)/include/wally_symmetric.h include_HEADERS += $(top_srcdir)/include/wally_transaction.h pkgconfigdir = $(libdir)/pkgconfig From 467165b87d4f337b5fa0228e143643354adad414 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 22 Jul 2020 08:55:00 +1200 Subject: [PATCH 190/205] psbt: Remove input and output allocation and free functions There were no calls that take these functions so removing them should not cause any issues. Modifying the PSBTs transaction inputs and outputs will be added, which like psbt_set_global_tx() will update the PSBT to reflect the tx status. Otherwise for all other operations the caller will only need to set values within the existing PSBT inputs and outputs. This will save a lot of boilerplate and wrapping code from being required, and fits with e.g. c-lightnings view of how PSBTs will be manipulated. --- CHANGES.md | 4 + include/wally.hpp | 36 -------- include/wally_psbt.h | 188 ----------------------------------------- src/psbt.c | 195 ------------------------------------------- src/test/util.py | 6 -- 5 files changed, 4 insertions(+), 425 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 58f06eabc..9a8ae3aec 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,10 @@ instead of returning WALLY_EINVAL. See the generated API documentation section "Variable Length Output Buffers" for details. +- psbt_input_init_alloc, psbt_input_free, psbt_output_init_alloc, psbt_output_free, + and their elements counterparts psbt_elements_input_init_alloc and + psbt_elements_output_init_alloc have been removed. + - psbt_combine has been changed to only combine one PSBT into another. - psbt_to_bytes, psbt_get_length and psbt_to_base64 now take a flags argument. diff --git a/include/wally.hpp b/include/wally.hpp index 1a9c8c396..3a027e2fc 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -80,25 +80,6 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), out); \ } -#define WALLY_FN_BBPPBBBBBBBB_A(F, N) template \ - inline int F(const I1 &i1, const I2 &i2, const P1& p1, const P2& p2, const I3 &i3, const I4& i4, \ - const I5 &i5, const I6 &i6, const I7 &i7, const I8& i8, const I9 &i9, const I10 &i10, O * *out) { \ - return ::N(WALLYB(i1), WALLYB(i2), WALLYP(p1), WALLYP(p2), WALLYB(i3), WALLYB(i4), \ - WALLYB(i5), WALLYB(i6), WALLYB(i7), WALLYB(i8), WALLYB(i9), WALLYB(i10), out); \ -} - -#define WALLY_FN_PPBBBPPPP363BBBPBBB_A(F, N) \ - template \ - inline int F(const P1& p1, const P2& p2, const I1 &i1, const I2 &i2, const I3 &i3, const P3& p3, \ - const P4& p4, const P5& p5, const P6& p6, uint32_t i321, uint64_t i641, uint32_t i322, \ - const I4& i4, \ const I5 &i5, const I6 &i6, const P7& p7, const I7 &i7, const I8& i8, const I9 &i9, O * *out) { \ - return ::N(WALLYP(p1), WALLYP(p2), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYP(p3), \ - WALLYP(p4), WALLYP(p5), WALLYP(p6), i321, i641, i322, WALLYB(i4), WALLYB(i5), \ - WALLYB(i6), WALLYP(p7), WALLYB(i7), WALLYB(i8), WALLYB(i9), out); \ -} - #define WALLY_FN_BB_A(F, N) template \ inline int F(const I1 &i1, const I2 &i2, O * *out) { \ return ::N(WALLYB(i1), WALLYB(i2), out); \ @@ -363,11 +344,6 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), WALLYB(i1), written); \ } -#define WALLY_FN_BBPP_A(F, N) template \ - inline int F(const I1 &i1, const I2 &i2, const P2 &p2, const P3 &p3, O * *out) { \ - return ::N(WALLYB(i1), WALLYB(i2), WALLYP(p2), WALLYP(p3), out); \ -} - #define WALLY_FN_PP(F, N) template inline int F(const P1 &p1, const P2 &p2) { \ return ::N(WALLYP(p1), WALLYP(p2)); \ } @@ -429,12 +405,6 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYB(i4), WALLYB(i5), WALLYB(i6), WALLYO(out1), WALLYO(out2), WALLYO(out3), out); \ } -#define WALLY_FN_PPBBBPPPP3_A(F, N) template \ - inline int F(const P1 &p1, const P2 &p2, const I1 &i1, const I2 &i2, const I3 &i3, \ - const P3 &p3, const P4 &p4, const P5 &p5, const P6 &p6, uint32_t i321, O * *out) { \ - return ::N(WALLYP(p1), WALLYP(p2), WALLYB(i1), WALLYB(i2), WALLYB(i3), WALLYP(p3), WALLYP(p4), WALLYP(p5), WALLYP(p6), i321, out); \ -} - #define WALLY_FN_PP_B(F, N) template inline int F(const P1 &p1, const P2 &p2, O & out) { \ return ::N(WALLYP(p1), WALLYP(p2), WALLYO(out)); \ } @@ -530,7 +500,6 @@ WALLY_FN_BB3_BS(scriptsig_p2pkh_from_sig, wally_scriptsig_p2pkh_from_sig) WALLY_FN_BBB3_A(witness_multisig_from_bytes, wally_witness_multisig_from_bytes) WALLY_FN_BBB3_BS(aes_cbc, wally_aes_cbc) WALLY_FN_BBB3_BS(scriptsig_multisig_from_bytes, wally_scriptsig_multisig_from_bytes) -WALLY_FN_BBPP_A(psbt_output_init_alloc, wally_psbt_output_init_alloc) WALLY_FN_BB_A(witness_p2wpkh_from_der, wally_witness_p2wpkh_from_der) WALLY_FN_BB_B(ec_sig_to_public_key, wally_ec_sig_to_public_key) WALLY_FN_BB_B(ecdh, wally_ecdh) @@ -562,8 +531,6 @@ WALLY_FN_P(get_operations, wally_get_operations) WALLY_FN_P(keypath_map_free, wally_keypath_map_free) WALLY_FN_P(partial_sigs_map_free, wally_partial_sigs_map_free) WALLY_FN_P(psbt_free, wally_psbt_free) -WALLY_FN_P(psbt_input_free, wally_psbt_input_free) -WALLY_FN_P(psbt_output_free, wally_psbt_output_free) WALLY_FN_P(set_operations, wally_set_operations) WALLY_FN_P(tx_free, wally_tx_free) WALLY_FN_P(tx_input_free, wally_tx_input_free) @@ -624,7 +591,6 @@ WALLY_FN_PP(tx_add_input, wally_tx_add_input) WALLY_FN_PP(tx_add_output, wally_tx_add_output) WALLY_FN_PP3_A(bip32_key_to_addr_segwit, wally_bip32_key_to_addr_segwit) WALLY_FN_PP3_BS(addr_segwit_to_bytes, wally_addr_segwit_to_bytes) -WALLY_FN_PPBBBPPPP3_A(psbt_input_init_alloc, wally_psbt_input_init_alloc) WALLY_FN_PP_BS(bip39_mnemonic_to_bytes, bip39_mnemonic_to_bytes) WALLY_FN_PP_BS(bip39_mnemonic_to_seed, bip39_mnemonic_to_seed) WALLY_FN_PS(tx_remove_input, wally_tx_remove_input) @@ -700,7 +666,6 @@ WALLY_FN_BBBBBBB_BS(asset_surjectionproof, wally_asset_surjectionproof) WALLY_FN_BBBBBB_A(tx_elements_output_init_alloc, wally_tx_elements_output_init_alloc) WALLY_FN_BBBBBB_BBB6(asset_unblind, wally_asset_unblind) WALLY_FN_BBBBB_BBB6(asset_unblind_with_nonce, wally_asset_unblind_with_nonce) -WALLY_FN_BBPPBBBBBBBB_A(psbt_elements_output_init_alloc, wally_psbt_elements_output_init_alloc) WALLY_FN_BBSBBB_BS(asset_pak_whitelistproof, wally_asset_pak_whitelistproof) WALLY_FN_BB_B(asset_blinding_key_to_ec_private_key, wally_asset_blinding_key_to_ec_private_key) WALLY_FN_BB_B(asset_generator_from_bytes, wally_asset_generator_from_bytes) @@ -738,7 +703,6 @@ WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_comm WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) WALLY_FN_PBBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) WALLY_FN_PP(psbt_elements_input_set_peg_in_tx, wally_psbt_elements_input_set_peg_in_tx) -WALLY_FN_PPBBBPPPP363BBBPBBB_A(psbt_elements_input_init_alloc, wally_psbt_elements_input_init_alloc) WALLY_FN_PPPB_A(confidential_addr_from_addr_segwit, wally_confidential_addr_from_addr_segwit) WALLY_FN_PPP_A(confidential_addr_to_addr_segwit, wally_confidential_addr_to_addr_segwit) WALLY_FN_PP_B(confidential_addr_segwit_to_ec_public_key, wally_confidential_addr_segwit_to_ec_public_key) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 824b425b1..573767fa1 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -343,40 +343,6 @@ WALLY_CORE_API int wally_unknowns_map_add( const unsigned char *value, size_t value_len); -/** - * Allocate and initialize a new PSBT input. - * - * :param non_witness_utxo: The non witness utxo for this input if it exists. - * :param witness_utxo: The witness utxo for this input if it exists. - * :param redeem_script: The redeem script for this input. - * :param redeem_script_len: Length of ``redeem_script`` in bytes. - * :param witness_script: The witness script for this input. - * :param witness_script_len: Length of ``witness_script`` in bytes. - * :param final_script_sig: The scriptSig for this input. - * :param final_script_sig_len: Length of ``final_script_sig`` in bytes. - * :param final_witness: The witness stack for the input, or NULL if no witness is present. - * :param keypaths: The HD keypaths for this input. - * :param partial_sigs: The partial signatures for this input. - * :param unknowns: The unknown key value pairs for this input. - * :param sighash_type: The sighash type for this input. - * :param output: Destination for the resulting PSBT input. - */ -WALLY_CORE_API int wally_psbt_input_init_alloc( - const struct wally_tx *non_witness_utxo, - const struct wally_tx_output *witness_utxo, - const unsigned char *redeem_script, - size_t redeem_script_len, - const unsigned char *witness_script, - size_t witness_script_len, - const unsigned char *final_script_sig, - size_t final_script_sig_len, - const struct wally_tx_witness_stack *final_witness, - const struct wally_keypath_map *keypaths, - const struct wally_partial_sigs_map *partial_sigs, - const struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - struct wally_psbt_input **output); - /** * Set the non_witness_utxo in an input. * @@ -483,36 +449,6 @@ WALLY_CORE_API int wally_psbt_input_set_sighash_type( struct wally_psbt_input *input, uint32_t sighash_type); -#ifndef SWIG_PYTHON -/** - * Free a PSBT input allocated by `wally_psbt_input_init_alloc`. - * - * :param input: The PSBT input to free. - */ -WALLY_CORE_API int wally_psbt_input_free( - struct wally_psbt_input *input); -#endif /* SWIG_PYTHON */ - -/** - * Allocate and initialize a new PSBT output. - * - * :param redeem_script: The redeem script needed for spending this output. - * :param redeem_script_len: Length of ``redeem_script`` in bytes. - * :param witness_script: The witness script needed for spending for this output. - * :param witness_script_len: Length of ``witness_script`` in bytes. - * :param keypaths: The HD keypaths for the keys needed for spending this output. - * :param unknowns: The unknown key value pairs for this output. - * :param output: Destination for the resulting PSBT output. - */ -WALLY_CORE_API int wally_psbt_output_init_alloc( - const unsigned char *redeem_script, - size_t redeem_script_len, - const unsigned char *witness_script, - size_t witness_script_len, - const struct wally_keypath_map *keypaths, - const struct wally_unknowns_map *unknowns, - struct wally_psbt_output **output); - /** * Set the redeem_script in an output. * @@ -557,16 +493,6 @@ WALLY_CORE_API int wally_psbt_output_set_unknowns( struct wally_psbt_output *output, const struct wally_unknowns_map *unknowns); -#ifndef SWIG_PYTHON -/** - * Free a PSBT output allocated by `wally_psbt_output_init_alloc`. - * - * :param output: The PSBT output to free. - */ -WALLY_CORE_API int wally_psbt_output_free( - struct wally_psbt_output *output); -#endif /* SWIG_PYTHON */ - /** * Allocate and initialize a new PSBT. * @@ -735,69 +661,6 @@ WALLY_CORE_API int wally_psbt_elements_init_alloc( size_t global_unknowns_allocation_len, struct wally_psbt **output); -/** - * Allocate and initialize a new PSBT elements input. - * - * :param non_witness_utxo: The non witness utxo for this input if it exists. - * :param witness_utxo: The witness utxo for this input if it exists. - * :param redeem_script: The redeem script for this input - * :param redeem_script_len: Length of ``redeem_script`` in bytes. - * :param witness_script: The witness script for this input - * :param witness_script_len: Length of ``witness_script`` in bytes. - * :param final_script_sig: The scriptSig for this input - * :param final_script_sig_len: Length of ``final_script_sig`` in bytes. - * :param final_witness: The witness stack for the input, or NULL if no witness is present. - * :param keypaths: The HD keypaths for this input. - * :param partial_sigs: The partial signatures for this input. - * :param unknowns: The unknown key value pairs for this input. - * :param sighash_type: The sighash type for this input - * :param value: The value for this input - * :param value_blinder: The value blinder for ths input - * :param value_blinder_len: Length of ``value_blinder`` in bytes. - * :param asset: The asset for this input. - * :param asset_len: Length of ``asset`` in bytes. - * :param asset_blinder: The asset blinder for this input. - * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. - * :param peg_in_tx: The The peg in tx for this input - * :param txout_proof: The txout proof for this input - * :param txout_proof_len: Length of ``txout_proof`` in bytes. - * :param genesis_hash: The genesis hash for this input - * :param genesis_hash_len: Length of ``genesis_hash`` in bytes. - * :param claim_script: The claim script for this input - * :param claim_script_len: Length of ``claim_script`` in bytes. - * :param output: Destination for the resulting PSBT input. - */ -WALLY_CORE_API int wally_psbt_elements_input_init_alloc( - const struct wally_tx *non_witness_utxo, - const struct wally_tx_output *witness_utxo, - const unsigned char *redeem_script, - size_t redeem_script_len, - const unsigned char *witness_script, - size_t witness_script_len, - const unsigned char *final_script_sig, - size_t final_script_sig_len, - const struct wally_tx_witness_stack *final_witness, - const struct wally_keypath_map *keypaths, - const struct wally_partial_sigs_map *partial_sigs, - const struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - uint64_t value, - uint32_t has_value, - const unsigned char *value_blinder, - size_t value_blinder_len, - const unsigned char *asset, - size_t asset_len, - const unsigned char *asset_blinder, - size_t asset_blinder_len, - const struct wally_tx *peg_in_tx, - const unsigned char *txout_proof, - size_t txout_proof_len, - const unsigned char *genesis_hash, - size_t genesis_hash_len, - const unsigned char *claim_script, - size_t claim_script_len, - struct wally_psbt_input **output); - /** * Set the value in an elements input. * @@ -898,57 +761,6 @@ WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( const unsigned char *claim_script, size_t claim_script_len); -/** - * Allocate and initialize a new PSBT elements output. - * - * :param redeem_script: The redeem script needed for spending this output. - * :param redeem_script_len: Length of ``redeem_script`` in bytes. - * :param witness_script: The witness script needed for spending for this output. - * :param witness_script_len: Length of ``witness_script`` in bytes. - * :param keypaths: The HD keypaths for the keys needed for spending this output. - * :param unknowns: The unknown key value pairs for this output. - * :param blinding_pubkey: The blinding pubkey for this output. - * :param value_commitment: The value commitment for this output. - * :param value_commitment_len: Length of ``value_commitment`` in bytes. - * :param value_blinder: The value blinder for this output. - * :param value_blinder_len: Length of ``value_blinder`` in bytes. - * :param asset_commitment: The asset commitment for this output. - * :param asset_commitment_len: Length of ``asset_commitment`` in bytes. - * :param asset_blinder: The asset blinder for this output. - * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. - * :param nonce_commitment: The nonce commitment for this output. - * :param nonce_commitment_len: Length of ``nonce_commitment`` in bytes. - * :param range_proof: The range proof for this output. - * :param range_proof_len: Length of ``range_proof`` in bytes. - * :param surjection_proof: The surjection proof for this output. - * :param surjection_proof_len: Length of ``surjection_proof`` in bytes. - * :param output: Destination for the resulting PSBT output. - */ -WALLY_CORE_API int wally_psbt_elements_output_init_alloc( - const unsigned char *redeem_script, - size_t redeem_script_len, - const unsigned char *witness_script, - size_t witness_script_len, - const struct wally_keypath_map *keypaths, - const struct wally_unknowns_map *unknowns, - const unsigned char *blinding_pubkey, - size_t blinding_pubkey_len, - const unsigned char *value_commitment, - size_t value_commitment_len, - const unsigned char *value_blinder, - size_t value_blinder_len, - const unsigned char *asset_commitment, - size_t asset_commitment_len, - const unsigned char *asset_blinder, - size_t asset_blinder_len, - const unsigned char *nonce_commitment, - size_t nonce_commitment_len, - const unsigned char *range_proof, - size_t range_proof_len, - const unsigned char *surjection_proof, - size_t surjection_proof_len, - struct wally_psbt_output **output); - /** * Set the blinding pubkey in an elements output. * diff --git a/src/psbt.c b/src/psbt.c index ae1050a18..98a32741b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -425,111 +425,6 @@ int wally_unknowns_map_add(struct wally_unknowns_map *unknowns, return ret; } -int wally_psbt_input_init_alloc(const struct wally_tx *non_witness_utxo, - const struct wally_tx_output *witness_utxo, - const unsigned char *redeem_script, size_t redeem_script_len, - const unsigned char *witness_script, size_t witness_script_len, - const unsigned char *final_script_sig, size_t final_script_sig_len, - const struct wally_tx_witness_stack *final_witness, - const struct wally_keypath_map *keypaths, - const struct wally_partial_sigs_map *partial_sigs, - const struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - struct wally_psbt_input **output) -{ - struct wally_psbt_input *result; - int ret; - - TX_CHECK_OUTPUT; - TX_OUTPUT_ALLOC(struct wally_psbt_input); - - if (non_witness_utxo && (ret = wally_psbt_input_set_non_witness_utxo(result, non_witness_utxo)) != WALLY_OK) - goto fail; - if (witness_utxo && (ret = wally_psbt_input_set_witness_utxo(result, witness_utxo)) != WALLY_OK) - goto fail; - if (redeem_script && (ret = wally_psbt_input_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) - goto fail; - if (witness_script && (ret = wally_psbt_input_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) - goto fail; - if (final_script_sig && (ret = wally_psbt_input_set_final_script_sig(result, final_script_sig, final_script_sig_len)) != WALLY_OK) - goto fail; - if (final_witness && (ret = wally_psbt_input_set_final_witness(result, final_witness)) != WALLY_OK) - goto fail; - if (keypaths && (ret = wally_psbt_input_set_keypaths(result, keypaths)) != WALLY_OK) - goto fail; - if (partial_sigs && (ret = wally_psbt_input_set_partial_sigs(result, partial_sigs)) != WALLY_OK) - goto fail; - if (unknowns && (ret = wally_psbt_input_set_unknowns(result, unknowns)) != WALLY_OK) - goto fail; - return wally_psbt_input_set_sighash_type(result, sighash_type); - -fail: - wally_psbt_input_free(result); - *output = NULL; - return ret; -} - -#ifdef BUILD_ELEMENTS -int wally_psbt_elements_input_init_alloc(const struct wally_tx *non_witness_utxo, - const struct wally_tx_output *witness_utxo, - const unsigned char *redeem_script, size_t redeem_script_len, - const unsigned char *witness_script, size_t witness_script_len, - const unsigned char *final_script_sig, size_t final_script_sig_len, - const struct wally_tx_witness_stack *final_witness, - const struct wally_keypath_map *keypaths, - const struct wally_partial_sigs_map *partial_sigs, - const struct wally_unknowns_map *unknowns, - uint32_t sighash_type, - uint64_t value, uint32_t has_value, - const unsigned char *value_blinder, size_t value_blinder_len, - const unsigned char *asset, size_t asset_len, - const unsigned char *asset_blinder, size_t asset_blinder_len, - const struct wally_tx *peg_in_tx, - const unsigned char *txout_proof, size_t txout_proof_len, - const unsigned char *genesis_hash, size_t genesis_hash_len, - const unsigned char *claim_script, size_t claim_script_len, - struct wally_psbt_input **output) -{ - struct wally_psbt_input *result; - int ret = wally_psbt_input_init_alloc(non_witness_utxo, witness_utxo, - redeem_script, redeem_script_len, - witness_script, witness_script_len, - final_script_sig, final_script_sig_len, - final_witness, keypaths, - partial_sigs, unknowns, - sighash_type, - output); - if (ret != WALLY_OK) - return ret; - - result = *output; - - if (has_value && (ret = wally_psbt_elements_input_set_value(result, value)) != WALLY_OK) - goto fail; - if (value_blinder && (ret = wally_psbt_elements_input_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) - goto fail; - if (asset && (ret = wally_psbt_elements_input_set_asset(result, asset, asset_len)) != WALLY_OK) - goto fail; - if (asset_blinder && (ret = wally_psbt_elements_input_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) - goto fail; - if (peg_in_tx && (ret = wally_psbt_elements_input_set_peg_in_tx(result, peg_in_tx)) != WALLY_OK) - goto fail; - if (txout_proof && (ret = wally_psbt_elements_input_set_txout_proof(result, txout_proof, txout_proof_len)) != WALLY_OK) - goto fail; - if (genesis_hash && (ret = wally_psbt_elements_input_set_genesis_hash(result, genesis_hash, genesis_hash_len)) != WALLY_OK) - goto fail; - if (claim_script && (ret = wally_psbt_elements_input_set_claim_script(result, claim_script, claim_script_len)) != WALLY_OK) - goto fail; - - return WALLY_OK; - -fail: - wally_psbt_input_free(result); - *output = NULL; - return ret; -} -#endif /* BUILD_ELEMENTS */ - int wally_psbt_input_set_non_witness_utxo(struct wally_psbt_input *input, const struct wally_tx *non_witness_utxo) { @@ -761,91 +656,6 @@ static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) return WALLY_OK; } -int wally_psbt_input_free(struct wally_psbt_input *input) -{ - return psbt_input_free(input, true); -} - -int wally_psbt_output_init_alloc(const unsigned char *redeem_script, size_t redeem_script_len, - const unsigned char *witness_script, size_t witness_script_len, - const struct wally_keypath_map *keypaths, - const struct wally_unknowns_map *unknowns, - struct wally_psbt_output **output) -{ - struct wally_psbt_output *result; - int ret = WALLY_OK; - - TX_CHECK_OUTPUT; - TX_OUTPUT_ALLOC(struct wally_psbt_output); - - if (redeem_script && (ret = wally_psbt_output_set_redeem_script(result, redeem_script, redeem_script_len)) != WALLY_OK) - goto fail; - if (witness_script && (ret = wally_psbt_output_set_witness_script(result, witness_script, witness_script_len)) != WALLY_OK) - goto fail; - if (keypaths && (ret = wally_psbt_output_set_keypaths(result, keypaths)) != WALLY_OK) - goto fail; - if (unknowns && (ret = wally_psbt_output_set_unknowns(result, unknowns)) != WALLY_OK) - goto fail; - - return WALLY_OK; - -fail: - wally_psbt_output_free(result); - *output = NULL; - return ret; -} - -#ifdef BUILD_ELEMENTS -int wally_psbt_elements_output_init_alloc(const unsigned char *redeem_script, size_t redeem_script_len, - const unsigned char *witness_script, size_t witness_script_len, - const struct wally_keypath_map *keypaths, - const struct wally_unknowns_map *unknowns, - const unsigned char *blinding_pubkey, size_t blinding_pubkey_len, - const unsigned char *value_commitment, size_t value_commitment_len, - const unsigned char *value_blinder, size_t value_blinder_len, - const unsigned char *asset_commitment, size_t asset_commitment_len, - const unsigned char *asset_blinder, size_t asset_blinder_len, - const unsigned char *nonce_commitment, size_t nonce_commitment_len, - const unsigned char *range_proof, size_t range_proof_len, - const unsigned char *surjection_proof, size_t surjection_proof_len, - struct wally_psbt_output **output) -{ - struct wally_psbt_output *result; - int ret = wally_psbt_output_init_alloc(redeem_script, redeem_script_len, - witness_script, witness_script_len, - keypaths, unknowns, output); - if (ret != WALLY_OK) - return ret; - - /* wally_psbt_output_init_alloc allocates for us */ - result = *output; - - if ((ret = wally_psbt_elements_output_set_blinding_pubkey(result, blinding_pubkey, blinding_pubkey_len)) != WALLY_OK) - goto fail; - if (value_commitment && (ret = wally_psbt_elements_output_set_value_commitment(result, value_commitment, value_commitment_len)) != WALLY_OK) - goto fail; - if (value_blinder && (ret = wally_psbt_elements_output_set_value_blinder(result, value_blinder, value_blinder_len)) != WALLY_OK) - goto fail; - if (asset_commitment && (ret = wally_psbt_elements_output_set_asset_commitment(result, asset_commitment, asset_commitment_len)) != WALLY_OK) - goto fail; - if (asset_blinder && (ret = wally_psbt_elements_output_set_asset_blinder(result, asset_blinder, asset_blinder_len)) != WALLY_OK) - goto fail; - if (nonce_commitment && (ret = wally_psbt_elements_output_set_nonce_commitment(result, nonce_commitment, nonce_commitment_len)) != WALLY_OK) - goto fail; - if (range_proof && (ret = wally_psbt_elements_output_set_range_proof(result, range_proof, range_proof_len)) != WALLY_OK) - goto fail; - if (surjection_proof && (ret = wally_psbt_elements_output_set_surjection_proof(result, surjection_proof, surjection_proof_len)) != WALLY_OK) - goto fail; - - return ret; - -fail: - wally_psbt_output_free(result); - *output = NULL; - return ret; -} -#endif /* BUILD_ELEMENTS */ - int wally_psbt_output_set_redeem_script(struct wally_psbt_output *output, const unsigned char *redeem_script, size_t redeem_script_len) @@ -985,11 +795,6 @@ static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) return WALLY_OK; } -int wally_psbt_output_free(struct wally_psbt_output *output) -{ - return psbt_output_free(output, true); -} - int wally_psbt_init_alloc( size_t inputs_allocation_len, size_t outputs_allocation_len, diff --git a/src/test/util.py b/src/test/util.py index 37eac5ee0..3e61a6e4f 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -321,7 +321,6 @@ class wally_psbt(Structure): ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), ('wally_psbt_elements_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_elements_input_clear_value', c_int, [POINTER(wally_psbt_input)]), - ('wally_psbt_elements_input_init_alloc', c_int, [POINTER(wally_tx), POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(wally_keypath_map), POINTER(wally_partial_sigs_map), POINTER(wally_unknowns_map), c_uint, c_uint64, c_uint, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_psbt_input))]), ('wally_psbt_elements_input_set_asset_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_elements_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_elements_input_set_claim_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), @@ -330,7 +329,6 @@ class wally_psbt(Structure): ('wally_psbt_elements_input_set_txout_proof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_elements_input_set_value_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_elements_input_set_value', c_int, [POINTER(wally_psbt_input), c_uint64]), - ('wally_psbt_elements_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_keypath_map), POINTER(wally_unknowns_map), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(POINTER(wally_psbt_output))]), ('wally_psbt_elements_output_set_asset_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_elements_output_set_asset_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_elements_output_set_blinding_pubkey', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), @@ -346,8 +344,6 @@ class wally_psbt(Structure): ('wally_psbt_from_bytes', c_int, [c_void_p, c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_uint, c_ulong_p]), ('wally_psbt_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_input_free', c_int, [POINTER(wally_psbt_input)]), - ('wally_psbt_input_init_alloc', c_int, [POINTER(wally_tx), POINTER(wally_tx_output), c_void_p, c_ulong, c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_tx_witness_stack), POINTER(wally_keypath_map), POINTER(wally_partial_sigs_map), POINTER(wally_unknowns_map), c_uint, POINTER(POINTER(wally_psbt_input))]), ('wally_psbt_input_set_final_script_sig', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_final_witness', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx_witness_stack)]), ('wally_psbt_input_set_keypaths', c_int, [POINTER(wally_psbt_input), POINTER(wally_keypath_map)]), @@ -359,8 +355,6 @@ class wally_psbt(Structure): ('wally_psbt_input_set_witness_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_witness_utxo', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx_output)]), ('wally_psbt_is_elements', c_int, [POINTER(wally_psbt), c_ulong_p]), - ('wally_psbt_output_free', c_int, [POINTER(wally_psbt_output)]), - ('wally_psbt_output_init_alloc', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, POINTER(wally_keypath_map), POINTER(wally_unknowns_map), POINTER(POINTER(wally_psbt_output))]), ('wally_psbt_output_set_keypaths', c_int, [POINTER(wally_psbt_output), POINTER(wally_keypath_map)]), ('wally_psbt_output_set_redeem_script', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_output_set_unknowns', c_int, [POINTER(wally_psbt_output), POINTER(wally_unknowns_map)]), From ee4f030dffe5be9c73b8d9dc411a8f19c211a5da Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 22 Jul 2020 10:52:33 +1200 Subject: [PATCH 191/205] psbt: Don't expose psbt input/output direct setters to SWIG SWIG wrappers should use the indexed setters exposed through swig_int.h to set values through the psbt, since they can't get pointers to the input and output items. --- include/wally_psbt.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 573767fa1..d20173f6e 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -343,6 +343,7 @@ WALLY_CORE_API int wally_unknowns_map_add( const unsigned char *value, size_t value_len); +#ifndef SWIG /** * Set the non_witness_utxo in an input. * @@ -492,6 +493,7 @@ WALLY_CORE_API int wally_psbt_output_set_keypaths( WALLY_CORE_API int wally_psbt_output_set_unknowns( struct wally_psbt_output *output, const struct wally_unknowns_map *unknowns); +#endif /* SWIG */ /** * Allocate and initialize a new PSBT. @@ -661,6 +663,7 @@ WALLY_CORE_API int wally_psbt_elements_init_alloc( size_t global_unknowns_allocation_len, struct wally_psbt **output); +#ifndef SWIG /** * Set the value in an elements input. * @@ -856,6 +859,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_surjection_proof( struct wally_psbt_output *output, const unsigned char *surjection_proof, size_t surjection_proof_len); +#endif /* SWIG */ #endif /* BUILD_ELEMENTS */ From d1ebc724c82710d91092fb9cf47ba425d2c9e85b Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 22 Jul 2020 21:12:21 +1200 Subject: [PATCH 192/205] psbt: push pubkey keys directly This will be even cleaner once pubkey is converted to a ptr + length from its current array form. --- src/psbt.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 98a32741b..3b20fc444 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1921,16 +1921,6 @@ static void push_psbt_key( push_bytes(cursor, max, extra, extra_len); } -/* Common case of pushing a type whose key is a pubkey */ -static void push_psbt_key_with_pubkey( - unsigned char **cursor, size_t *max, - uint64_t type, - const unsigned char pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]) -{ - const size_t pubkey_len = get_pubkey_len(pubkey, EC_PUBLIC_KEY_UNCOMPRESSED_LEN); - push_psbt_key(cursor, max, type, pubkey, pubkey_len); -} - #ifdef BUILD_ELEMENTS /* Common case of pushing elements proprietary type keys */ static void push_psbt_elements_key( @@ -1992,7 +1982,8 @@ static void push_keypath_item( { size_t origin_len, i; - push_psbt_key_with_pubkey(cursor, max, type, item->pubkey); + push_psbt_key(cursor, max, type, item->pubkey, + get_pubkey_len(item->pubkey, sizeof(item->pubkey))); origin_len = 4; /* Start with 4 bytes for fingerprint */ origin_len += item->path_len * sizeof(uint32_t); @@ -2073,10 +2064,11 @@ static int push_psbt_input( if (input->partial_sigs) { struct wally_partial_sigs_map *partial_sigs = input->partial_sigs; for (i = 0; i < partial_sigs->num_items; ++i) { - struct wally_partial_sigs_item *item = &partial_sigs->items[i]; - push_psbt_key_with_pubkey(cursor, max, WALLY_PSBT_IN_PARTIAL_SIG, - item->pubkey); - push_varbuff(cursor, max, item->sig, item->sig_len); + const struct wally_partial_sigs_item *p = &partial_sigs->items[i]; + + push_psbt_key(cursor, max, WALLY_PSBT_IN_PARTIAL_SIG, + p->pubkey, get_pubkey_len(p->pubkey, sizeof(p->pubkey))); + push_varbuff(cursor, max, p->sig, p->sig_len); } } /* Sighash type */ From c1ea199c988febf03495f41733faf35c386b24e3 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 22 Jul 2020 21:14:10 +1200 Subject: [PATCH 193/205] psbt: Add a FIXME for adding validation to getters/setters --- src/psbt.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/psbt.c b/src/psbt.c index 3b20fc444..293536ee0 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -14,6 +14,11 @@ #include "script.h" #include "pullpush.h" +/* FIXME: In input getters and setters, as well as in pubkey keyed maps, + * Check the validity of the values being set (e.g. the length is correct + * for the type, the pubkey is valid etc etc) + */ + static const uint8_t WALLY_PSBT_MAGIC[5] = {'p', 's', 'b', 't', 0xff}; static const uint8_t WALLY_ELEMENTS_PSBT_MAGIC[5] = {'p', 's', 'e', 't', 0xff}; From d74863e07f681d653dc9e9fd86c399ff20a5a9de Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 22 Jul 2020 22:34:47 +1200 Subject: [PATCH 194/205] psbt: Take the version in psbt_init_alloc for future compatibility --- CHANGES.md | 3 +++ include/wally.hpp | 8 ++++---- include/wally_psbt.h | 4 ++++ src/psbt.c | 19 ++++++++++--------- src/test/test_psbt.py | 2 +- src/test/util.py | 4 ++-- 6 files changed, 24 insertions(+), 16 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 9a8ae3aec..ec90ae858 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,6 +9,9 @@ instead of returning WALLY_EINVAL. See the generated API documentation section "Variable Length Output Buffers" for details. +- psbt_init_alloc and psbt_elements_init_alloc now take a version number + as their first argument which must be 0. + - psbt_input_init_alloc, psbt_input_free, psbt_output_init_alloc, psbt_output_free, and their elements counterparts psbt_elements_input_init_alloc and psbt_elements_output_init_alloc have been removed. diff --git a/include/wally.hpp b/include/wally.hpp index 3a027e2fc..81644b18c 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -59,8 +59,8 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(s1, out); \ } -#define WALLY_FN_SSS_A(F, N) template inline int F(size_t s1, size_t s2, size_t s3, O * *out) { \ - return ::N(s1, s2, s3, out); \ +#define WALLY_FN_3SSS_A(F, N) template inline int F(uint32_t i321, size_t s1, size_t s2, size_t s3, O * *out) { \ + return ::N(i321, s1, s2, s3, out); \ } #define WALLY_FN_SSSS_S(F, N) inline int F(size_t s1, size_t s2, size_t s3, size_t s4, size_t * written = 0) { \ @@ -465,6 +465,7 @@ WALLY_FN_3(cleanup, wally_cleanup) WALLY_FN_3(init, wally_init) WALLY_FN_333BBBBB_A(bip32_key_init_alloc, bip32_key_init_alloc) WALLY_FN_33SS_A(tx_init_alloc, wally_tx_init_alloc) +WALLY_FN_3SSS_A(psbt_init_alloc, wally_psbt_init_alloc) WALLY_FN_6B_A(tx_output_init_alloc, wally_tx_output_init_alloc) WALLY_FN_B(ec_private_key_verify, wally_ec_private_key_verify) WALLY_FN_B(ec_public_key_verify, wally_ec_public_key_verify) @@ -622,7 +623,6 @@ WALLY_FN_P_S(tx_get_weight, wally_tx_get_weight) WALLY_FN_P_S(tx_get_witness_count, wally_tx_get_witness_count) WALLY_FN_P_S(tx_is_coinbase, wally_tx_is_coinbase) WALLY_FN_P_S(wif_is_uncompressed, wally_wif_is_uncompressed) -WALLY_FN_SSS_A(psbt_init_alloc, wally_psbt_init_alloc) WALLY_FN_S_A(keypath_map_init_alloc, wally_keypath_map_init_alloc) WALLY_FN_S_A(partial_sigs_map_init_alloc, wally_partial_sigs_map_init_alloc) WALLY_FN_S_A(tx_witness_stack_init_alloc, wally_tx_witness_stack_init_alloc) @@ -654,6 +654,7 @@ inline bool is_elements_build() } #ifdef BUILD_ELEMENTS +WALLY_FN_3SSS_A(psbt_elements_init_alloc, wally_psbt_elements_init_alloc) WALLY_FN_6BBBBBBBB6II_BS(asset_rangeproof, wally_asset_rangeproof) WALLY_FN_6BB_B(asset_value_commitment, wally_asset_value_commitment) WALLY_FN_6_B(tx_confidential_value_from_satoshi, wally_tx_confidential_value_from_satoshi) @@ -710,7 +711,6 @@ WALLY_FN_PSBB33_B(tx_get_elements_signature_hash, wally_tx_get_elements_signatur WALLY_FN_P_S(tx_elements_input_is_pegin, wally_tx_elements_input_is_pegin) WALLY_FN_P_S(tx_is_elements, wally_tx_is_elements) WALLY_FN_SSSS_S(elements_pegout_script_size, wally_elements_pegout_script_size) -WALLY_FN_SSS_A(psbt_elements_init_alloc, wally_psbt_elements_init_alloc) WALLY_FN_S_S(asset_pak_whitelistproof_size, wally_asset_pak_whitelistproof_size) WALLY_FN_S_S(asset_surjectionproof_size, wally_asset_surjectionproof_size) #endif /* BUILD_ELEMENTS */ diff --git a/include/wally_psbt.h b/include/wally_psbt.h index d20173f6e..a365da356 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -498,12 +498,14 @@ WALLY_CORE_API int wally_psbt_output_set_unknowns( /** * Allocate and initialize a new PSBT. * + * :param version: The version of the PSBT. Must be 0. * :param inputs_allocation_len: The number of inputs to pre-allocate space for. * :param outputs_allocation_len: The number of outputs to pre-allocate space for. * :param global_unknowns_allocation_len: The number of global unknowns to allocate space for. * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_init_alloc( + uint32_t version, size_t inputs_allocation_len, size_t outputs_allocation_len, size_t global_unknowns_allocation_len, @@ -652,12 +654,14 @@ WALLY_CORE_API int wally_psbt_is_elements( /** * Allocate and initialize a new elements PSBT. * + * :param version: The version of the PSBT. Must be 0. * :param inputs_allocation_len: The number of inputs to pre-allocate space for. * :param outputs_allocation_len: The number of outputs to pre-allocate space for. * :param global_unknowns_allocation_len: The number of global unknowns to allocate space for. * :param output: Destination for the resulting PSBT output. */ WALLY_CORE_API int wally_psbt_elements_init_alloc( + uint32_t version, size_t inputs_allocation_len, size_t outputs_allocation_len, size_t global_unknowns_allocation_len, diff --git a/src/psbt.c b/src/psbt.c index 293536ee0..3e8bf0628 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -800,16 +800,17 @@ static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) return WALLY_OK; } -int wally_psbt_init_alloc( - size_t inputs_allocation_len, - size_t outputs_allocation_len, - size_t global_unknowns_allocation_len, - struct wally_psbt **output) +int wally_psbt_init_alloc(uint32_t version, size_t inputs_allocation_len, + size_t outputs_allocation_len, + size_t global_unknowns_allocation_len, + struct wally_psbt **output) { struct wally_psbt *result; int ret; TX_CHECK_OUTPUT; + if (version) + return WALLY_EINVAL; /* Only version 0 is specified/supported */ TX_OUTPUT_ALLOC(struct wally_psbt); if (inputs_allocation_len) @@ -825,8 +826,7 @@ int wally_psbt_init_alloc( return ret != WALLY_OK ? ret : WALLY_ENOMEM; } - /* Version is always 0 */ - result->version = 0; + result->version = version; memcpy(result->magic, WALLY_PSBT_MAGIC, sizeof(WALLY_PSBT_MAGIC)); result->inputs_allocation_len = inputs_allocation_len; result->outputs_allocation_len = outputs_allocation_len; @@ -836,12 +836,13 @@ int wally_psbt_init_alloc( #ifdef BUILD_ELEMENTS int wally_psbt_elements_init_alloc( + uint32_t version, size_t inputs_allocation_len, size_t outputs_allocation_len, size_t global_unknowns_allocation_len, struct wally_psbt **output) { - int ret = wally_psbt_init_alloc(inputs_allocation_len, + int ret = wally_psbt_init_alloc(version, inputs_allocation_len, outputs_allocation_len, global_unknowns_allocation_len, output); if (ret == WALLY_OK) @@ -1804,7 +1805,7 @@ int wally_psbt_from_bytes(const unsigned char *bytes, size_t len, } /* Make the wally_psbt */ - ret = wally_psbt_init_alloc(0, 0, 8, &result); + ret = wally_psbt_init_alloc(0, 0, 0, 8, &result); if (ret != WALLY_OK) goto fail; diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index 4ea1f4223..def925902 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -33,7 +33,7 @@ def test_serialization(self): for creator in creators: psbt = pointer(wally_psbt()) - self.assertEqual(WALLY_OK, wally_psbt_init_alloc(2, 2, 0, psbt)) + self.assertEqual(WALLY_OK, wally_psbt_init_alloc(0, 2, 2, 0, psbt)) tx = pointer(wally_tx()) self.assertEqual(WALLY_OK, wally_tx_init_alloc(2, 0, 2, 2, tx)) diff --git a/src/test/util.py b/src/test/util.py index 3e61a6e4f..5027d7a64 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -319,7 +319,7 @@ class wally_psbt(Structure): ('wally_pbkdf2_hmac_sha256', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), ('wally_pbkdf2_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), - ('wally_psbt_elements_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_elements_init_alloc', c_int, [c_uint, c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_elements_input_clear_value', c_int, [POINTER(wally_psbt_input)]), ('wally_psbt_elements_input_set_asset_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_elements_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), @@ -343,7 +343,7 @@ class wally_psbt(Structure): ('wally_psbt_from_base64', c_int, [c_char_p, POINTER(POINTER(wally_psbt))]), ('wally_psbt_from_bytes', c_int, [c_void_p, c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_get_length', c_int, [POINTER(wally_psbt), c_uint, c_ulong_p]), - ('wally_psbt_init_alloc', c_int, [c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), + ('wally_psbt_init_alloc', c_int, [c_uint, c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_input_set_final_script_sig', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_final_witness', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx_witness_stack)]), ('wally_psbt_input_set_keypaths', c_int, [POINTER(wally_psbt_input), POINTER(wally_keypath_map)]), From 36ed6c8b1ae001fa9b4f72bb3c4289775a4b6173 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Wed, 22 Jul 2020 22:37:31 +1200 Subject: [PATCH 195/205] psbt: use BIP32_KEY_FINGERPRINT_LEN per review --- src/psbt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 3e8bf0628..c5c94058b 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1991,11 +1991,11 @@ static void push_keypath_item( push_psbt_key(cursor, max, type, item->pubkey, get_pubkey_len(item->pubkey, sizeof(item->pubkey))); - origin_len = 4; /* Start with 4 bytes for fingerprint */ + origin_len = BIP32_KEY_FINGERPRINT_LEN; origin_len += item->path_len * sizeof(uint32_t); push_varint(cursor, max, origin_len); - push_bytes(cursor, max, item->fingerprint, 4); + push_bytes(cursor, max, item->fingerprint, sizeof(item->fingerprint)); for (i = 0; i < item->path_len; ++i) { push_bytes(cursor, max, &item->path[i], sizeof(uint32_t)); } From b9b18977d6332ab977b88282e775dd4795b830a9 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 23 Jul 2020 00:37:38 +1200 Subject: [PATCH 196/205] psbt: rename elements input/output getters/setters These should have followed the model of the transaction code; when Elements support is compiled in, inputs and outputs *are* Elements inputs and outputs and elements members can be set like any other members. --- include/wally.hpp | 34 ++++++------ include/wally_psbt.h | 42 +++++++------- src/psbt.c | 128 +++++++++++++++++++++---------------------- src/test/util.py | 34 ++++++------ 4 files changed, 116 insertions(+), 122 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 81644b18c..a0fc382a5 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -674,28 +674,28 @@ WALLY_FN_BSBB_B(asset_final_vbf, wally_asset_final_vbf) WALLY_FN_B_6(tx_confidential_value_to_satoshi, wally_tx_confidential_value_to_satoshi) WALLY_FN_B_B(asset_blinding_key_from_seed, wally_asset_blinding_key_from_seed) WALLY_FN_B_B(tx_elements_issuance_calculate_asset, wally_tx_elements_issuance_calculate_asset) -WALLY_FN_P(psbt_elements_input_clear_value, wally_psbt_elements_input_clear_value) +WALLY_FN_P(psbt_input_clear_value, wally_psbt_input_clear_value) WALLY_FN_P(psbt_finalize, wally_psbt_finalize) WALLY_FN_P(tx_elements_input_issuance_free, wally_tx_elements_input_issuance_free) WALLY_FN_P(tx_elements_output_commitment_free, wally_tx_elements_output_commitment_free) WALLY_FN_P3B_A(confidential_addr_from_addr, wally_confidential_addr_from_addr) WALLY_FN_P3_A(confidential_addr_to_addr, wally_confidential_addr_to_addr) WALLY_FN_P3_B(confidential_addr_to_ec_public_key, wally_confidential_addr_to_ec_public_key) -WALLY_FN_P6(psbt_elements_input_set_value, wally_psbt_elements_input_set_value) -WALLY_FN_PB(psbt_elements_input_set_asset, wally_psbt_elements_input_set_asset) -WALLY_FN_PB(psbt_elements_input_set_asset_blinder, wally_psbt_elements_input_set_asset_blinder) -WALLY_FN_PB(psbt_elements_input_set_claim_script, wally_psbt_elements_input_set_claim_script) -WALLY_FN_PB(psbt_elements_input_set_genesis_hash, wally_psbt_elements_input_set_genesis_hash) -WALLY_FN_PB(psbt_elements_input_set_txout_proof, wally_psbt_elements_input_set_txout_proof) -WALLY_FN_PB(psbt_elements_input_set_value_blinder, wally_psbt_elements_input_set_value_blinder) -WALLY_FN_PB(psbt_elements_output_set_asset_blinder, wally_psbt_elements_output_set_asset_blinder) -WALLY_FN_PB(psbt_elements_output_set_asset_commitment, wally_psbt_elements_output_set_asset_commitment) -WALLY_FN_PB(psbt_elements_output_set_blinding_pubkey, wally_psbt_elements_output_set_blinding_pubkey) -WALLY_FN_PB(psbt_elements_output_set_nonce_commitment, wally_psbt_elements_output_set_nonce_commitment) -WALLY_FN_PB(psbt_elements_output_set_range_proof, wally_psbt_elements_output_set_range_proof) -WALLY_FN_PB(psbt_elements_output_set_surjection_proof, wally_psbt_elements_output_set_surjection_proof) -WALLY_FN_PB(psbt_elements_output_set_value_blinder, wally_psbt_elements_output_set_value_blinder) -WALLY_FN_PB(psbt_elements_output_set_value_commitment, wally_psbt_elements_output_set_value_commitment) +WALLY_FN_P6(psbt_input_set_value, wally_psbt_input_set_value) +WALLY_FN_PB(psbt_input_set_asset, wally_psbt_input_set_asset) +WALLY_FN_PB(psbt_input_set_asset_blinder, wally_psbt_input_set_asset_blinder) +WALLY_FN_PB(psbt_input_set_claim_script, wally_psbt_input_set_claim_script) +WALLY_FN_PB(psbt_input_set_genesis_hash, wally_psbt_input_set_genesis_hash) +WALLY_FN_PB(psbt_input_set_txout_proof, wally_psbt_input_set_txout_proof) +WALLY_FN_PB(psbt_input_set_value_blinder, wally_psbt_input_set_value_blinder) +WALLY_FN_PB(psbt_output_set_asset_blinder, wally_psbt_output_set_asset_blinder) +WALLY_FN_PB(psbt_output_set_asset_commitment, wally_psbt_output_set_asset_commitment) +WALLY_FN_PB(psbt_output_set_blinding_pubkey, wally_psbt_output_set_blinding_pubkey) +WALLY_FN_PB(psbt_output_set_nonce_commitment, wally_psbt_output_set_nonce_commitment) +WALLY_FN_PB(psbt_output_set_range_proof, wally_psbt_output_set_range_proof) +WALLY_FN_PB(psbt_output_set_surjection_proof, wally_psbt_output_set_surjection_proof) +WALLY_FN_PB(psbt_output_set_value_blinder, wally_psbt_output_set_value_blinder) +WALLY_FN_PB(psbt_output_set_value_commitment, wally_psbt_output_set_value_commitment) WALLY_FN_PB33BPBBBBBB3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) WALLY_FN_PB33BPBBBBBBP3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) WALLY_FN_PB3P(bip32_key_with_tweak_from_parent_path, bip32_key_with_tweak_from_parent_path) @@ -703,7 +703,7 @@ WALLY_FN_PB3_A(bip32_key_with_tweak_from_parent_path_alloc, bip32_key_with_tweak WALLY_FN_PBBBBB(tx_elements_output_commitment_set, wally_tx_elements_output_commitment_set) WALLY_FN_PBBBBBB(tx_elements_input_issuance_set, wally_tx_elements_input_issuance_set) WALLY_FN_PBBBBBB3(tx_add_elements_raw_output, wally_tx_add_elements_raw_output) -WALLY_FN_PP(psbt_elements_input_set_peg_in_tx, wally_psbt_elements_input_set_peg_in_tx) +WALLY_FN_PP(psbt_input_set_peg_in_tx, wally_psbt_input_set_peg_in_tx) WALLY_FN_PPPB_A(confidential_addr_from_addr_segwit, wally_confidential_addr_from_addr_segwit) WALLY_FN_PPP_A(confidential_addr_to_addr_segwit, wally_confidential_addr_to_addr_segwit) WALLY_FN_PP_B(confidential_addr_segwit_to_ec_public_key, wally_confidential_addr_segwit_to_ec_public_key) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index a365da356..22df0e5d9 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -674,7 +674,7 @@ WALLY_CORE_API int wally_psbt_elements_init_alloc( * :param input: The input to update. * :param value: The value for this input. */ -WALLY_CORE_API int wally_psbt_elements_input_set_value( +WALLY_CORE_API int wally_psbt_input_set_value( struct wally_psbt_input *input, uint64_t value); @@ -683,7 +683,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_value( * * :param input: The input to update. */ -WALLY_CORE_API int wally_psbt_elements_input_clear_value( +WALLY_CORE_API int wally_psbt_input_clear_value( struct wally_psbt_input *input); /** @@ -693,7 +693,7 @@ WALLY_CORE_API int wally_psbt_elements_input_clear_value( * :param value_blinder: The value blinder for this input. * :param value_blinder_len: Length of ``value_blinder`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_input_set_value_blinder( +WALLY_CORE_API int wally_psbt_input_set_value_blinder( struct wally_psbt_input *input, const unsigned char *value_blinder, size_t value_blinder_len); @@ -705,7 +705,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_value_blinder( * :param asset: The asset for this input. * :param asset_len: Length of ``asset`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_input_set_asset( +WALLY_CORE_API int wally_psbt_input_set_asset( struct wally_psbt_input *input, const unsigned char *asset, size_t asset_len); @@ -717,7 +717,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_asset( * :param asset_blinder: The asset blinder for this input. * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_input_set_asset_blinder( +WALLY_CORE_API int wally_psbt_input_set_asset_blinder( struct wally_psbt_input *input, const unsigned char *asset_blinder, size_t asset_blinder_len); @@ -728,7 +728,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_asset_blinder( * :param input: The input to update. * :param peg_in_tx: The peg in tx for this input if it exists. */ -WALLY_CORE_API int wally_psbt_elements_input_set_peg_in_tx( +WALLY_CORE_API int wally_psbt_input_set_peg_in_tx( struct wally_psbt_input *input, const struct wally_tx *peg_in_tx); @@ -739,7 +739,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_peg_in_tx( * :param txout_proof: The txout proof for this input. * :param txout_proof_len: Length of ``txout_proof`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_input_set_txout_proof( +WALLY_CORE_API int wally_psbt_input_set_txout_proof( struct wally_psbt_input *input, const unsigned char *txout_proof, size_t txout_proof_len); @@ -751,7 +751,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_txout_proof( * :param genesis_hash: The genesis hash for this input. * :param genesis_hash_len: Length of ``genesis_hash`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_input_set_genesis_hash( +WALLY_CORE_API int wally_psbt_input_set_genesis_hash( struct wally_psbt_input *input, const unsigned char *genesis_hash, size_t genesis_hash_len); @@ -763,7 +763,7 @@ WALLY_CORE_API int wally_psbt_elements_input_set_genesis_hash( * :param claim_script: The claim script for this input. * :param claim_script_len: Length of ``claim_script`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( +WALLY_CORE_API int wally_psbt_input_set_claim_script( struct wally_psbt_input *input, const unsigned char *claim_script, size_t claim_script_len); @@ -772,13 +772,13 @@ WALLY_CORE_API int wally_psbt_elements_input_set_claim_script( * Set the blinding pubkey in an elements output. * * :param output: The output to update. - * :param blinding_pubkey: The blinding pubkey for this output. - * :param blinding_pubkey_len: Length of ``blinding_pubkey`` in bytes. + * :param pub_key: The blinding pubkey for this output. + * :param pub_key_len: Length of ``pub_key`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( +WALLY_CORE_API int wally_psbt_output_set_blinding_pubkey( struct wally_psbt_output *output, - const unsigned char *blinding_pubkey, - size_t blinding_pubkey_len); + const unsigned char *pub_key, + size_t pub_key_len); /** * Set the value commitment in an elements output. @@ -787,7 +787,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_blinding_pubkey( * :param value_commitment: The value commitment for this output. * :param value_commitment_len: Length of ``value_commitment`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_value_commitment( +WALLY_CORE_API int wally_psbt_output_set_value_commitment( struct wally_psbt_output *output, const unsigned char *value_commitment, size_t value_commitment_len); @@ -799,7 +799,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_value_commitment( * :param value_blinder: The value blinder for this output. * :param value_blinder_len: Length of ``value_blinder`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_value_blinder( +WALLY_CORE_API int wally_psbt_output_set_value_blinder( struct wally_psbt_output *output, const unsigned char *value_blinder, size_t value_blinder_len); @@ -811,7 +811,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_value_blinder( * :param asset_commitment: The asset commitment for this output. * :param asset_commitment_len: Length of ``asset_commitment`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_asset_commitment( +WALLY_CORE_API int wally_psbt_output_set_asset_commitment( struct wally_psbt_output *output, const unsigned char *asset_commitment, size_t asset_commitment_len); @@ -823,7 +823,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_asset_commitment( * :param asset_blinder: The asset blinder for this output. * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_asset_blinder( +WALLY_CORE_API int wally_psbt_output_set_asset_blinder( struct wally_psbt_output *output, const unsigned char *asset_blinder, size_t asset_blinder_len); @@ -835,7 +835,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_asset_blinder( * :param nonce_commitment: The nonce commitment for this output. * :param nonce_commitment_len: Length of ``nonce_commitment`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_nonce_commitment( +WALLY_CORE_API int wally_psbt_output_set_nonce_commitment( struct wally_psbt_output *output, const unsigned char *nonce_commitment, size_t nonce_commitment_len); @@ -847,7 +847,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_nonce_commitment( * :param range_proof: The range_proof for this output. * :param range_proof_len: Length of ``range_proof`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_range_proof( +WALLY_CORE_API int wally_psbt_output_set_range_proof( struct wally_psbt_output *output, const unsigned char *range_proof, size_t range_proof_len); @@ -859,7 +859,7 @@ WALLY_CORE_API int wally_psbt_elements_output_set_range_proof( * :param surjection_proof: The surjection proof for this output. * :param surjection_proof_len: Length of ``surjection_proof`` in bytes. */ -WALLY_CORE_API int wally_psbt_elements_output_set_surjection_proof( +WALLY_CORE_API int wally_psbt_output_set_surjection_proof( struct wally_psbt_output *output, const unsigned char *surjection_proof, size_t surjection_proof_len); diff --git a/src/psbt.c b/src/psbt.c index c5c94058b..17cc614ba 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -540,23 +540,23 @@ int wally_psbt_input_set_sighash_type(struct wally_psbt_input *input, uint32_t s } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_input_set_value(struct wally_psbt_input *input, uint64_t value) +int wally_psbt_input_set_value(struct wally_psbt_input *input, uint64_t value) { input->value = value; input->has_value = 1u; return WALLY_OK; } -int wally_psbt_elements_input_clear_value(struct wally_psbt_input *input) +int wally_psbt_input_clear_value(struct wally_psbt_input *input) { input->value = 0; input->has_value = 0; return WALLY_OK; } -int wally_psbt_elements_input_set_value_blinder(struct wally_psbt_input *input, - const unsigned char *value_blinder, - size_t value_blinder_len) +int wally_psbt_input_set_value_blinder(struct wally_psbt_input *input, + const unsigned char *value_blinder, + size_t value_blinder_len) { if (!input) return WALLY_EINVAL; @@ -564,17 +564,17 @@ int wally_psbt_elements_input_set_value_blinder(struct wally_psbt_input *input, &input->value_blinder, &input->value_blinder_len); } -int wally_psbt_elements_input_set_asset(struct wally_psbt_input *input, - const unsigned char *asset, size_t asset_len) +int wally_psbt_input_set_asset(struct wally_psbt_input *input, + const unsigned char *asset, size_t asset_len) { if (!input) return WALLY_EINVAL; return replace_bytes(asset, asset_len, &input->asset, &input->asset_len); } -int wally_psbt_elements_input_set_asset_blinder(struct wally_psbt_input *input, - const unsigned char *asset_blinder, - size_t asset_blinder_len) +int wally_psbt_input_set_asset_blinder(struct wally_psbt_input *input, + const unsigned char *asset_blinder, + size_t asset_blinder_len) { if (!input) return WALLY_EINVAL; @@ -582,8 +582,8 @@ int wally_psbt_elements_input_set_asset_blinder(struct wally_psbt_input *input, &input->asset_blinder, &input->asset_blinder_len); } -int wally_psbt_elements_input_set_peg_in_tx(struct wally_psbt_input *input, - const struct wally_tx *peg_in_tx) +int wally_psbt_input_set_peg_in_tx(struct wally_psbt_input *input, + const struct wally_tx *peg_in_tx) { int ret = WALLY_OK; struct wally_tx *new_tx = NULL; @@ -600,9 +600,9 @@ int wally_psbt_elements_input_set_peg_in_tx(struct wally_psbt_input *input, return ret; } -int wally_psbt_elements_input_set_txout_proof(struct wally_psbt_input *input, - const unsigned char *txout_proof, - size_t txout_proof_len) +int wally_psbt_input_set_txout_proof(struct wally_psbt_input *input, + const unsigned char *txout_proof, + size_t txout_proof_len) { if (!input) return WALLY_EINVAL; @@ -610,9 +610,9 @@ int wally_psbt_elements_input_set_txout_proof(struct wally_psbt_input *input, &input->txout_proof, &input->txout_proof_len); } -int wally_psbt_elements_input_set_genesis_hash(struct wally_psbt_input *input, - const unsigned char *genesis_hash, - size_t genesis_hash_len) +int wally_psbt_input_set_genesis_hash(struct wally_psbt_input *input, + const unsigned char *genesis_hash, + size_t genesis_hash_len) { if (!input) return WALLY_EINVAL; @@ -620,9 +620,9 @@ int wally_psbt_elements_input_set_genesis_hash(struct wally_psbt_input *input, &input->genesis_hash, &input->genesis_hash_len); } -int wally_psbt_elements_input_set_claim_script(struct wally_psbt_input *input, - const unsigned char *claim_script, - size_t claim_script_len) +int wally_psbt_input_set_claim_script(struct wally_psbt_input *input, + const unsigned char *claim_script, + size_t claim_script_len) { if (!input) return WALLY_EINVAL; @@ -694,19 +694,19 @@ int wally_psbt_output_set_unknowns(struct wally_psbt_output *output, } #ifdef BUILD_ELEMENTS -int wally_psbt_elements_output_set_blinding_pubkey(struct wally_psbt_output *output, - const unsigned char *blinding_pubkey, - size_t blinding_pubkey_len) +int wally_psbt_output_set_blinding_pubkey(struct wally_psbt_output *output, + const unsigned char *pub_key, + size_t pub_key_len) { - if (!output || !is_valid_optional_pubkey_len(blinding_pubkey_len)) + if (!output || !is_valid_optional_pubkey_len(pub_key_len)) return WALLY_EINVAL; - return replace_bytes(blinding_pubkey, blinding_pubkey_len, + return replace_bytes(pub_key, pub_key_len, &output->blinding_pubkey, &output->blinding_pubkey_len); } -int wally_psbt_elements_output_set_value_commitment(struct wally_psbt_output *output, - const unsigned char *value_commitment, - size_t value_commitment_len) +int wally_psbt_output_set_value_commitment(struct wally_psbt_output *output, + const unsigned char *value_commitment, + size_t value_commitment_len) { if (!output) return WALLY_EINVAL; @@ -714,9 +714,9 @@ int wally_psbt_elements_output_set_value_commitment(struct wally_psbt_output *ou &output->value_commitment, &output->value_commitment_len); } -int wally_psbt_elements_output_set_value_blinder(struct wally_psbt_output *output, - const unsigned char *value_blinder, - size_t value_blinder_len) +int wally_psbt_output_set_value_blinder(struct wally_psbt_output *output, + const unsigned char *value_blinder, + size_t value_blinder_len) { if (!output) return WALLY_EINVAL; @@ -724,9 +724,9 @@ int wally_psbt_elements_output_set_value_blinder(struct wally_psbt_output *outpu &output->value_blinder, &output->value_blinder_len); } -int wally_psbt_elements_output_set_asset_commitment(struct wally_psbt_output *output, - const unsigned char *asset_commitment, - size_t asset_commitment_len) +int wally_psbt_output_set_asset_commitment(struct wally_psbt_output *output, + const unsigned char *asset_commitment, + size_t asset_commitment_len) { if (!output) return WALLY_EINVAL; @@ -734,9 +734,9 @@ int wally_psbt_elements_output_set_asset_commitment(struct wally_psbt_output *ou &output->asset_commitment, &output->asset_commitment_len); } -int wally_psbt_elements_output_set_asset_blinder(struct wally_psbt_output *output, - const unsigned char *asset_blinder, - size_t asset_blinder_len) +int wally_psbt_output_set_asset_blinder(struct wally_psbt_output *output, + const unsigned char *asset_blinder, + size_t asset_blinder_len) { if (!output) return WALLY_EINVAL; @@ -744,9 +744,9 @@ int wally_psbt_elements_output_set_asset_blinder(struct wally_psbt_output *outpu &output->asset_blinder, &output->asset_blinder_len); } -int wally_psbt_elements_output_set_nonce_commitment(struct wally_psbt_output *output, - const unsigned char *nonce_commitment, - size_t nonce_commitment_len) +int wally_psbt_output_set_nonce_commitment(struct wally_psbt_output *output, + const unsigned char *nonce_commitment, + size_t nonce_commitment_len) { if (!output) return WALLY_EINVAL; @@ -754,9 +754,9 @@ int wally_psbt_elements_output_set_nonce_commitment(struct wally_psbt_output *ou &output->nonce_commitment, &output->nonce_commitment_len); } -int wally_psbt_elements_output_set_range_proof(struct wally_psbt_output *output, - const unsigned char *range_proof, - size_t range_proof_len) +int wally_psbt_output_set_range_proof(struct wally_psbt_output *output, + const unsigned char *range_proof, + size_t range_proof_len) { if (!output) return WALLY_EINVAL; @@ -764,9 +764,9 @@ int wally_psbt_elements_output_set_range_proof(struct wally_psbt_output *output, &output->range_proof, &output->range_proof_len); } -int wally_psbt_elements_output_set_surjection_proof(struct wally_psbt_output *output, - const unsigned char *surjection_proof, - size_t surjection_proof_len) +int wally_psbt_output_set_surjection_proof(struct wally_psbt_output *output, + const unsigned char *surjection_proof, + size_t surjection_proof_len) { if (!output) return WALLY_EINVAL; @@ -2469,11 +2469,6 @@ static int combine_partial_sigs(struct wally_partial_sigs_map **dst, (ret = wally_psbt_ ## typ ## _set_ ## member(dst, src->member, src->member ## _len)) != WALLY_OK) \ return ret -#define COMBINE_ELEMENTS_BYTES(typ, member) \ - if (!dst->member && src->member && \ - (ret = wally_psbt_elements_ ## typ ## _set_ ## member(dst, src->member, src->member ## _len)) != WALLY_OK) \ - return ret - static int combine_txs(struct wally_tx **dst, struct wally_tx *src) { if (!dst) @@ -2535,14 +2530,14 @@ static int combine_inputs(struct wally_psbt_input *dst, dst->value = src->value; dst->has_value = true; } - COMBINE_ELEMENTS_BYTES(input, value_blinder); - COMBINE_ELEMENTS_BYTES(input, asset); - COMBINE_ELEMENTS_BYTES(input, asset_blinder); + COMBINE_BYTES(input, value_blinder); + COMBINE_BYTES(input, asset); + COMBINE_BYTES(input, asset_blinder); if ((ret = combine_txs(&dst->peg_in_tx, src->peg_in_tx)) != WALLY_OK) return ret; - COMBINE_ELEMENTS_BYTES(input, txout_proof); - COMBINE_ELEMENTS_BYTES(input, genesis_hash); - COMBINE_ELEMENTS_BYTES(input, claim_script); + COMBINE_BYTES(input, txout_proof); + COMBINE_BYTES(input, genesis_hash); + COMBINE_BYTES(input, claim_script); #endif return WALLY_OK; } @@ -2561,19 +2556,18 @@ static int combine_outputs(struct wally_psbt_output *dst, COMBINE_BYTES(output, witness_script); #ifdef BUILD_ELEMENTS - COMBINE_ELEMENTS_BYTES(output, blinding_pubkey); - COMBINE_ELEMENTS_BYTES(output, value_commitment); - COMBINE_ELEMENTS_BYTES(output, value_blinder); - COMBINE_ELEMENTS_BYTES(output, asset_commitment); - COMBINE_ELEMENTS_BYTES(output, asset_blinder); - COMBINE_ELEMENTS_BYTES(output, nonce_commitment); - COMBINE_ELEMENTS_BYTES(output, range_proof); - COMBINE_ELEMENTS_BYTES(output, surjection_proof); + COMBINE_BYTES(output, blinding_pubkey); + COMBINE_BYTES(output, value_commitment); + COMBINE_BYTES(output, value_blinder); + COMBINE_BYTES(output, asset_commitment); + COMBINE_BYTES(output, asset_blinder); + COMBINE_BYTES(output, nonce_commitment); + COMBINE_BYTES(output, range_proof); + COMBINE_BYTES(output, surjection_proof); #endif return WALLY_OK; } #undef COMBINE_BYTES -#undef COMBINE_ELEMENTS_BYTES int wally_psbt_combine(struct wally_psbt *psbt, const struct wally_psbt *src) { diff --git a/src/test/util.py b/src/test/util.py index 5027d7a64..f72f61483 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -320,23 +320,23 @@ class wally_psbt(Structure): ('wally_pbkdf2_hmac_sha512', c_int, [c_void_p, c_ulong, c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong]), ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), ('wally_psbt_elements_init_alloc', c_int, [c_uint, c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), - ('wally_psbt_elements_input_clear_value', c_int, [POINTER(wally_psbt_input)]), - ('wally_psbt_elements_input_set_asset_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_elements_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_elements_input_set_claim_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_elements_input_set_genesis_hash', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_elements_input_set_peg_in_tx', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), - ('wally_psbt_elements_input_set_txout_proof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_elements_input_set_value_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_elements_input_set_value', c_int, [POINTER(wally_psbt_input), c_uint64]), - ('wally_psbt_elements_output_set_asset_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_elements_output_set_asset_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_elements_output_set_blinding_pubkey', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_elements_output_set_nonce_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_elements_output_set_range_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_elements_output_set_surjection_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_elements_output_set_value_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_elements_output_set_value_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_input_clear_value', c_int, [POINTER(wally_psbt_input)]), + ('wally_psbt_input_set_asset_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_claim_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_genesis_hash', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_peg_in_tx', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), + ('wally_psbt_input_set_txout_proof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_value_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_value', c_int, [POINTER(wally_psbt_input), c_uint64]), + ('wally_psbt_output_set_asset_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_asset_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_blinding_pubkey', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_nonce_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_range_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_surjection_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_value_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_value_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_extract', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]), ('wally_psbt_finalize', c_int, [POINTER(wally_psbt)]), ('wally_psbt_free', c_int, [POINTER(wally_psbt)]), From 1b616660718aa02d72769999d7a69b65d9dec2a9 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 23 Jul 2020 00:42:59 +1200 Subject: [PATCH 197/205] psbt: Update CHANGES.md to a simpler message for the next release The previous interface was unusable: no users should be affected, so we just note that the new interface is final to fulfill the contract we have w.r.t. updating CHANGES.md for API changes. --- CHANGES.md | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index ec90ae858..d8db54e31 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -9,28 +9,11 @@ instead of returning WALLY_EINVAL. See the generated API documentation section "Variable Length Output Buffers" for details. -- psbt_init_alloc and psbt_elements_init_alloc now take a version number - as their first argument which must be 0. - -- psbt_input_init_alloc, psbt_input_free, psbt_output_init_alloc, psbt_output_free, - and their elements counterparts psbt_elements_input_init_alloc and - psbt_elements_output_init_alloc have been removed. - -- psbt_combine has been changed to only combine one PSBT into another. - -- psbt_to_bytes, psbt_get_length and psbt_to_base64 now take a flags argument. - - FINGERPRINT_LEN was renamed to BIP32_KEY_FINGERPRINT_LEN for consistency - You should change any references in your source when upgrading. -- The following PSBT functions have been renamed for consistency: - - wally_add_new_keypath -> wally_keypath_map_add - - wally_add_new_partial_sig -> wally_partial_sigs_map_add - - wally_add_new_unknown -> wally_unknowns_map_add - - wally_extract_psbt -> wally_psbt_extract - - wally_finalize_psbt -> wally_psbt_finalize - - wally_sign_psbt -> wally_psbt_sign - - wally_combine_psbts -> wally_psbt_combine +- Almost all functions comprising the PSBT interface have changed name, + arguments, semantics or all three. Users can consider the new interface final. ## Version 0.7.8 From 6a9b30918905365ebfac9545d6216793dd9e26e6 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 23 Jul 2020 08:08:28 +1200 Subject: [PATCH 198/205] transaction: update docs for allowed value lengths --- include/wally_transaction.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/wally_transaction.h b/include/wally_transaction.h index 6ae133571..4bfa0f3cd 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -747,7 +747,7 @@ WALLY_CORE_API int wally_tx_elements_input_is_pegin( * :param asset: The commitment to a possibly blinded asset. * :param asset_len: Size of ``asset`` in bytes. Must be ``WALLY_TX_ASSET_CT_ASSET_LEN``. * :param value: The commitment to a possibly blinded value. - * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN``. + * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN`` or ``WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN``. * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. * :param surjectionproof: surjection proof. @@ -786,7 +786,7 @@ WALLY_CORE_API int wally_tx_elements_output_commitment_free( * :param asset: The asset tag of the output. * :param asset_len: Size of ``asset`` in bytes. Must be ``WALLY_TX_ASSET_CT_ASSET_LEN``. * :param value: The commitment to a possibly blinded value. - * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN``. + * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN`` or ``WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN``. * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. * :param surjectionproof: The surjection proof. @@ -869,7 +869,7 @@ WALLY_CORE_API int wally_tx_add_elements_raw_input( * :param asset: The asset tag of the output. * :param asset_len: Size of ``asset`` in bytes. Must be ``WALLY_TX_ASSET_CT_ASSET_LEN``. * :param value: The commitment to a possibly blinded value. - * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN``. + * :param value_len: Size of ``value`` in bytes. Must be ``WALLY_TX_ASSET_CT_VALUE_LEN`` or ``WALLY_TX_ASSET_CT_VALUE_UNBLIND_LEN``. * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. * :param surjectionproof: The surjection proof. From 87e45e0c570561f391c8f375512e2fb36032befd Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 23 Jul 2020 08:10:27 +1200 Subject: [PATCH 199/205] elements: use the correct constant for blinding factor lengths The incorrect constant has the same size so this isn't an API change; it just makes the code a little clearer. --- include/wally_elements.h | 2 +- src/elements.c | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/wally_elements.h b/include/wally_elements.h index 5dbc503c4..8d67f2c9a 100644 --- a/include/wally_elements.h +++ b/include/wally_elements.h @@ -25,7 +25,7 @@ extern "C" { * :param asset: Asset Tag to create a blinding generator for. * :param asset_len: Length of ``asset`` in bytes. Must be ``ASSET_TAG_LEN``. * :param abf: Asset Blinding Factor (Random entropy to blind with). - * :param abf_len: Length of ``abf`` in bytes. Must be ``ASSET_TAG_LEN``. + * :param abf_len: Length of ``abf`` in bytes. Must be ``BLINDING_FACTOR_LEN``. * :param bytes_out: Destination for the resulting Asset Generator. * :param len: The length of ``bytes_out`` in bytes. Must be ``ASSET_GENERATOR_LEN``. */ diff --git a/src/elements.c b/src/elements.c index 4025a5f7b..e14a86799 100644 --- a/src/elements.c +++ b/src/elements.c @@ -69,7 +69,7 @@ int wally_asset_generator_from_bytes(const unsigned char *asset, size_t asset_le if (!ctx) return WALLY_ENOMEM; - if (!asset || asset_len != ASSET_TAG_LEN || !abf || abf_len != ASSET_TAG_LEN || + if (!asset || asset_len != ASSET_TAG_LEN || !abf || abf_len != BLINDING_FACTOR_LEN || !bytes_out || len != ASSET_GENERATOR_LEN) return WALLY_EINVAL; @@ -96,8 +96,8 @@ int wally_asset_final_vbf(const uint64_t *values, size_t values_len, size_t num_ if (!values || values_len < 2u || num_inputs >= values_len || - !abf || abf_len != (values_len * ASSET_TAG_LEN) || - !vbf || vbf_len != ((values_len - 1) * ASSET_TAG_LEN) || + !abf || abf_len != (values_len * BLINDING_FACTOR_LEN) || + !vbf || vbf_len != ((values_len - 1) * BLINDING_FACTOR_LEN) || !bytes_out || len != ASSET_TAG_LEN) return WALLY_EINVAL; @@ -110,8 +110,8 @@ int wally_asset_final_vbf(const uint64_t *values, size_t values_len, size_t num_ } for (i = 0; i < values_len; i++) { - abf_p[i] = abf + i * ASSET_TAG_LEN; - vbf_p[i] = vbf + i * ASSET_TAG_LEN; + abf_p[i] = abf + i * BLINDING_FACTOR_LEN; + vbf_p[i] = vbf + i * BLINDING_FACTOR_LEN; } vbf_p[values_len - 1] = bytes_out; wally_clear(bytes_out, len); @@ -177,8 +177,8 @@ int wally_asset_rangeproof_with_nonce(uint64_t value, if (!nonce_hash || nonce_hash_len != SHA256_LEN || !asset || asset_len != ASSET_TAG_LEN || - !abf || abf_len != ASSET_TAG_LEN || - !vbf || vbf_len != ASSET_TAG_LEN || + !abf || abf_len != BLINDING_FACTOR_LEN || + !vbf || vbf_len != BLINDING_FACTOR_LEN || !bytes_out || len < ASSET_RANGEPROOF_MAX_LEN || !written || get_commitment(ctx, commitment, commitment_len, &commit) != WALLY_OK || /* FIXME: Is there an upper size limit on the extra commitment? */ @@ -276,8 +276,8 @@ int wally_asset_unblind_with_nonce(const unsigned char *nonce_hash, size_t nonce (extra_len && !extra) || get_generator(ctx, generator, generator_len, &gen) != WALLY_OK || !asset_out || asset_out_len != ASSET_TAG_LEN || - !abf_out || abf_out_len != ASSET_TAG_LEN || - !vbf_out || vbf_out_len != ASSET_TAG_LEN || !value_out) + !abf_out || abf_out_len != BLINDING_FACTOR_LEN || + !vbf_out || vbf_out_len != BLINDING_FACTOR_LEN || !value_out) goto cleanup; /* Extract the value blinding factor, value and message from the rangeproof */ @@ -374,11 +374,11 @@ int wally_asset_surjectionproof(const unsigned char *output_asset, size_t output return WALLY_ENOMEM; if (!output_asset || output_asset_len != ASSET_TAG_LEN || - !output_abf || output_abf_len != ASSET_TAG_LEN || + !output_abf || output_abf_len != BLINDING_FACTOR_LEN || get_generator(ctx, output_generator, output_generator_len, &gen) != WALLY_OK || !bytes || bytes_len != 32u || !asset || !num_inputs || (asset_len % ASSET_TAG_LEN != 0) || - !abf || abf_len != num_inputs * ASSET_TAG_LEN || + !abf || abf_len != num_inputs * BLINDING_FACTOR_LEN || !generator || generator_len != num_inputs * ASSET_GENERATOR_LEN || !bytes_out || len != SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(num_inputs, num_used) || !written) @@ -410,7 +410,7 @@ int wally_asset_surjectionproof(const unsigned char *output_asset, size_t output if (!secp256k1_surjectionproof_generate(ctx, &proof, generators, num_inputs, &gen, actual_index, - abf + actual_index * ASSET_TAG_LEN, + abf + actual_index * BLINDING_FACTOR_LEN, output_abf)) { ret = WALLY_ERROR; /* Caller must retry with different entropy/outputs */ goto cleanup; From 24e4db98385b6d2857a169b79d65a90147c498ce Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 23 Jul 2020 08:49:45 +1200 Subject: [PATCH 200/205] psbt: Expose output setters to python, with tests This required changes to paramater names to match the transaction fields, and includes documentation fixes and length checks for the setter functions. --- include/wally.hpp | 14 +- include/wally_elements.h | 2 +- include/wally_psbt.h | 124 +++++++++--------- src/psbt.c | 224 ++++++++++++++++---------------- src/psbt_int.h | 11 +- src/swig_python/contrib/psbt.py | 13 ++ src/swig_python/swig.i | 6 +- src/test/util.py | 42 +++--- 8 files changed, 228 insertions(+), 208 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index a0fc382a5..0b5995125 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -683,18 +683,18 @@ WALLY_FN_P3_A(confidential_addr_to_addr, wally_confidential_addr_to_addr) WALLY_FN_P3_B(confidential_addr_to_ec_public_key, wally_confidential_addr_to_ec_public_key) WALLY_FN_P6(psbt_input_set_value, wally_psbt_input_set_value) WALLY_FN_PB(psbt_input_set_asset, wally_psbt_input_set_asset) -WALLY_FN_PB(psbt_input_set_asset_blinder, wally_psbt_input_set_asset_blinder) +WALLY_FN_PB(psbt_input_set_abf, wally_psbt_input_set_abf) WALLY_FN_PB(psbt_input_set_claim_script, wally_psbt_input_set_claim_script) WALLY_FN_PB(psbt_input_set_genesis_hash, wally_psbt_input_set_genesis_hash) WALLY_FN_PB(psbt_input_set_txout_proof, wally_psbt_input_set_txout_proof) -WALLY_FN_PB(psbt_input_set_value_blinder, wally_psbt_input_set_value_blinder) -WALLY_FN_PB(psbt_output_set_asset_blinder, wally_psbt_output_set_asset_blinder) +WALLY_FN_PB(psbt_input_set_vbf, wally_psbt_input_set_vbf) +WALLY_FN_PB(psbt_output_set_abf, wally_psbt_output_set_abf) WALLY_FN_PB(psbt_output_set_asset_commitment, wally_psbt_output_set_asset_commitment) WALLY_FN_PB(psbt_output_set_blinding_pubkey, wally_psbt_output_set_blinding_pubkey) -WALLY_FN_PB(psbt_output_set_nonce_commitment, wally_psbt_output_set_nonce_commitment) -WALLY_FN_PB(psbt_output_set_range_proof, wally_psbt_output_set_range_proof) -WALLY_FN_PB(psbt_output_set_surjection_proof, wally_psbt_output_set_surjection_proof) -WALLY_FN_PB(psbt_output_set_value_blinder, wally_psbt_output_set_value_blinder) +WALLY_FN_PB(psbt_output_set_nonce, wally_psbt_output_set_nonce) +WALLY_FN_PB(psbt_output_set_rangeproof, wally_psbt_output_set_rangeproof) +WALLY_FN_PB(psbt_output_set_surjectionproof, wally_psbt_output_set_surjectionproof) +WALLY_FN_PB(psbt_output_set_vbf, wally_psbt_output_set_vbf) WALLY_FN_PB(psbt_output_set_value_commitment, wally_psbt_output_set_value_commitment) WALLY_FN_PB33BPBBBBBB3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) WALLY_FN_PB33BPBBBBBBP3(tx_add_elements_raw_input, wally_tx_add_elements_raw_input) diff --git a/include/wally_elements.h b/include/wally_elements.h index 8d67f2c9a..bf1674e3f 100644 --- a/include/wally_elements.h +++ b/include/wally_elements.h @@ -72,7 +72,7 @@ WALLY_CORE_API int wally_asset_final_vbf( * :param generator: Asset generator from `wally_asset_generator_from_bytes`. * :param generator_len: Length of ``generator``. Must be ``ASSET_GENERATOR_LEN``. * :param bytes_out: Buffer to receive value commitment. - * :param len: Length of ``bytes_out``. Must be ``ASSET_GENERATOR_LEN``. + * :param len: Length of ``bytes_out``. Must be ``ASSET_COMMITMENT_LEN``. */ WALLY_CORE_API int wally_asset_value_commitment( uint64_t value, diff --git a/include/wally_psbt.h b/include/wally_psbt.h index 22df0e5d9..fe1c86666 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -126,12 +126,12 @@ struct wally_psbt_input { #ifdef BUILD_ELEMENTS uint64_t value; uint32_t has_value; - unsigned char *value_blinder; - size_t value_blinder_len; + unsigned char *vbf; + size_t vbf_len; unsigned char *asset; size_t asset_len; - unsigned char *asset_blinder; - size_t asset_blinder_len; + unsigned char *abf; + size_t abf_len; struct wally_tx *peg_in_tx; unsigned char *txout_proof; size_t txout_proof_len; @@ -142,7 +142,7 @@ struct wally_psbt_input { #endif /* BUILD_ELEMENTS */ }; -/** A PSBT output map */ +/** A PSBT output */ struct wally_psbt_output { unsigned char *redeem_script; size_t redeem_script_len; @@ -155,18 +155,18 @@ struct wally_psbt_output { size_t blinding_pubkey_len; unsigned char *value_commitment; size_t value_commitment_len; - unsigned char *value_blinder; - size_t value_blinder_len; + unsigned char *vbf; + size_t vbf_len; unsigned char *asset_commitment; size_t asset_commitment_len; - unsigned char *asset_blinder; - size_t asset_blinder_len; - unsigned char *nonce_commitment; - size_t nonce_commitment_len; - unsigned char *range_proof; - size_t range_proof_len; - unsigned char *surjection_proof; - size_t surjection_proof_len; + unsigned char *abf; + size_t abf_len; + unsigned char *nonce; + size_t nonce_len; + unsigned char *rangeproof; + size_t rangeproof_len; + unsigned char *surjectionproof; + size_t surjectionproof_len; #endif /* BUILD_ELEMENTS */ }; @@ -687,16 +687,16 @@ WALLY_CORE_API int wally_psbt_input_clear_value( struct wally_psbt_input *input); /** - * Set the value blinder in an elements input. + * Set the value blinding factor in an elements input. * * :param input: The input to update. - * :param value_blinder: The value blinder for this input. - * :param value_blinder_len: Length of ``value_blinder`` in bytes. + * :param vbf: The value blinding factor. + * :param vbf_len: Length of ``vbf``. Must be ``BLINDING_FACTOR_LEN``. */ -WALLY_CORE_API int wally_psbt_input_set_value_blinder( +WALLY_CORE_API int wally_psbt_input_set_vbf( struct wally_psbt_input *input, - const unsigned char *value_blinder, - size_t value_blinder_len); + const unsigned char *vbf, + size_t vbf_len); /** * Set the asset in an elements input. @@ -711,16 +711,16 @@ WALLY_CORE_API int wally_psbt_input_set_asset( size_t asset_len); /** - * Set the asset blinder in an elements input + * Set the asset blinding factor in an elements input * * :param input: The input to update. - * :param asset_blinder: The asset blinder for this input. - * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. + * :param abf: The asset blinding factor. + * :param abf_len: Length of ``abf`` in bytes. Must be ``BLINDING_FACTOR_LEN``. */ -WALLY_CORE_API int wally_psbt_input_set_asset_blinder( +WALLY_CORE_API int wally_psbt_input_set_abf( struct wally_psbt_input *input, - const unsigned char *asset_blinder, - size_t asset_blinder_len); + const unsigned char *abf, + size_t abf_len); /** * Set the peg in tx in an input. @@ -784,85 +784,85 @@ WALLY_CORE_API int wally_psbt_output_set_blinding_pubkey( * Set the value commitment in an elements output. * * :param output: The output to update. - * :param value_commitment: The value commitment for this output. - * :param value_commitment_len: Length of ``value_commitment`` in bytes. + * :param commitment: The value commitment for this output. + * :param commitment_len: Length of ``commitment`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_value_commitment( struct wally_psbt_output *output, - const unsigned char *value_commitment, - size_t value_commitment_len); + const unsigned char *commitment, + size_t commitment_len); /** - * Set the value blinder in an elements output. + * Set the value blinding factor in an elements output. * * :param output: The output to update. - * :param value_blinder: The value blinder for this output. - * :param value_blinder_len: Length of ``value_blinder`` in bytes. + * :param vbf: The value blinding factor. + * :param vbf_len: Length of ``vbf``. Must be ``BLINDING_FACTOR_LEN``. */ -WALLY_CORE_API int wally_psbt_output_set_value_blinder( +WALLY_CORE_API int wally_psbt_output_set_vbf( struct wally_psbt_output *output, - const unsigned char *value_blinder, - size_t value_blinder_len); + const unsigned char *vbf, + size_t vbf_len); /** * Set the asset commitment in an elements output. * * :param output: The output to update. - * :param asset_commitment: The asset commitment for this output. - * :param asset_commitment_len: Length of ``asset_commitment`` in bytes. + * :param commitment: The asset commitment for this output. + * :param commitment_len: Length of ``commitment`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_asset_commitment( struct wally_psbt_output *output, - const unsigned char *asset_commitment, - size_t asset_commitment_len); + const unsigned char *commitment, + size_t commitment_len); /** - * Set the asset blinder in an elements output. + * Set the asset blinding factor in an elements output. * * :param output: The output to update. - * :param asset_blinder: The asset blinder for this output. - * :param asset_blinder_len: Length of ``asset_blinder`` in bytes. + * :param abf: The asset blinding factor. + * :param abf_len: Length of ``abf`` in bytes. Must be ``BLINDING_FACTOR_LEN``. */ -WALLY_CORE_API int wally_psbt_output_set_asset_blinder( +WALLY_CORE_API int wally_psbt_output_set_abf( struct wally_psbt_output *output, - const unsigned char *asset_blinder, - size_t asset_blinder_len); + const unsigned char *abf, + size_t abf_len); /** * Set the nonce commitment in an elements output. * * :param output: The output to update. - * :param nonce_commitment: The nonce commitment for this output. - * :param nonce_commitment_len: Length of ``nonce_commitment`` in bytes. + * :param nonce: The commitment used to create the nonce (with the blinding key) for the range proof. + * :param nonce_len: Size of ``nonce`` in bytes. Must be ``WALLY_TX_ASSET_CT_NONCE_LEN``. */ -WALLY_CORE_API int wally_psbt_output_set_nonce_commitment( +WALLY_CORE_API int wally_psbt_output_set_nonce( struct wally_psbt_output *output, - const unsigned char *nonce_commitment, - size_t nonce_commitment_len); + const unsigned char *nonce, + size_t nonce_len); /** * Set the range proof in an elements output. * * :param output: The output to update. - * :param range_proof: The range_proof for this output. - * :param range_proof_len: Length of ``range_proof`` in bytes. + * :param rangeproof: The rangeproof for this output. + * :param rangeproof_len: Length of ``rangeproof`` in bytes. */ -WALLY_CORE_API int wally_psbt_output_set_range_proof( +WALLY_CORE_API int wally_psbt_output_set_rangeproof( struct wally_psbt_output *output, - const unsigned char *range_proof, - size_t range_proof_len); + const unsigned char *rangeproof, + size_t rangeproof_len); /** * Set the surjection proof in an elements output. * * :param output: The output to update. - * :param surjection_proof: The surjection proof for this output. - * :param surjection_proof_len: Length of ``surjection_proof`` in bytes. + * :param surjectionproof: The surjection proof for this output. + * :param surjectionproof_len: Length of ``surjectionproof`` in bytes. */ -WALLY_CORE_API int wally_psbt_output_set_surjection_proof( +WALLY_CORE_API int wally_psbt_output_set_surjectionproof( struct wally_psbt_output *output, - const unsigned char *surjection_proof, - size_t surjection_proof_len); + const unsigned char *surjectionproof, + size_t surjectionproof_len); #endif /* SWIG */ #endif /* BUILD_ELEMENTS */ diff --git a/src/psbt.c b/src/psbt.c index 17cc614ba..c038a8f9e 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -554,14 +554,12 @@ int wally_psbt_input_clear_value(struct wally_psbt_input *input) return WALLY_OK; } -int wally_psbt_input_set_value_blinder(struct wally_psbt_input *input, - const unsigned char *value_blinder, - size_t value_blinder_len) +int wally_psbt_input_set_vbf(struct wally_psbt_input *input, + const unsigned char *vbf, size_t vbf_len) { - if (!input) + if (!input || (vbf && vbf_len != BLINDING_FACTOR_LEN)) return WALLY_EINVAL; - return replace_bytes(value_blinder, value_blinder_len, - &input->value_blinder, &input->value_blinder_len); + return replace_bytes(vbf, vbf_len, &input->vbf, &input->vbf_len); } int wally_psbt_input_set_asset(struct wally_psbt_input *input, @@ -572,14 +570,12 @@ int wally_psbt_input_set_asset(struct wally_psbt_input *input, return replace_bytes(asset, asset_len, &input->asset, &input->asset_len); } -int wally_psbt_input_set_asset_blinder(struct wally_psbt_input *input, - const unsigned char *asset_blinder, - size_t asset_blinder_len) +int wally_psbt_input_set_abf(struct wally_psbt_input *input, + const unsigned char *abf, size_t abf_len) { - if (!input) + if (!input || (abf && abf_len != BLINDING_FACTOR_LEN)) return WALLY_EINVAL; - return replace_bytes(asset_blinder, asset_blinder_len, - &input->asset_blinder, &input->asset_blinder_len); + return replace_bytes(abf, abf_len, &input->abf, &input->abf_len); } int wally_psbt_input_set_peg_in_tx(struct wally_psbt_input *input, @@ -645,9 +641,9 @@ static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) wally_unknowns_map_free(input->unknowns); #ifdef BUILD_ELEMENTS - clear_and_free(input->value_blinder, input->value_blinder_len); + clear_and_free(input->vbf, input->vbf_len); clear_and_free(input->asset, input->asset_len); - clear_and_free(input->asset_blinder, input->asset_blinder_len); + clear_and_free(input->abf, input->abf_len); wally_tx_free(input->peg_in_tx); clear_and_free(input->txout_proof, input->txout_proof_len); clear_and_free(input->genesis_hash, input->genesis_hash_len); @@ -705,73 +701,69 @@ int wally_psbt_output_set_blinding_pubkey(struct wally_psbt_output *output, } int wally_psbt_output_set_value_commitment(struct wally_psbt_output *output, - const unsigned char *value_commitment, - size_t value_commitment_len) + const unsigned char *commitment, + size_t commitment_len) { - if (!output) + if (!output || (commitment && commitment_len != ASSET_COMMITMENT_LEN)) return WALLY_EINVAL; - return replace_bytes(value_commitment, value_commitment_len, + return replace_bytes(commitment, commitment_len, &output->value_commitment, &output->value_commitment_len); } -int wally_psbt_output_set_value_blinder(struct wally_psbt_output *output, - const unsigned char *value_blinder, - size_t value_blinder_len) +int wally_psbt_output_set_vbf(struct wally_psbt_output *output, + const unsigned char *vbf, size_t vbf_len) { - if (!output) + if (!output || (vbf && vbf_len != BLINDING_FACTOR_LEN)) return WALLY_EINVAL; - return replace_bytes(value_blinder, value_blinder_len, - &output->value_blinder, &output->value_blinder_len); + return replace_bytes(vbf, vbf_len, &output->vbf, &output->vbf_len); } int wally_psbt_output_set_asset_commitment(struct wally_psbt_output *output, - const unsigned char *asset_commitment, - size_t asset_commitment_len) + const unsigned char *commitment, + size_t commitment_len) { - if (!output) + if (!output || (commitment && commitment_len != ASSET_COMMITMENT_LEN)) return WALLY_EINVAL; - return replace_bytes(asset_commitment, asset_commitment_len, + return replace_bytes(commitment, commitment_len, &output->asset_commitment, &output->asset_commitment_len); } -int wally_psbt_output_set_asset_blinder(struct wally_psbt_output *output, - const unsigned char *asset_blinder, - size_t asset_blinder_len) +int wally_psbt_output_set_abf(struct wally_psbt_output *output, + const unsigned char *abf, size_t abf_len) { - if (!output) + if (!output || (abf && abf_len != BLINDING_FACTOR_LEN)) return WALLY_EINVAL; - return replace_bytes(asset_blinder, asset_blinder_len, - &output->asset_blinder, &output->asset_blinder_len); + return replace_bytes(abf, abf_len, &output->abf, &output->abf_len); } -int wally_psbt_output_set_nonce_commitment(struct wally_psbt_output *output, - const unsigned char *nonce_commitment, - size_t nonce_commitment_len) +int wally_psbt_output_set_nonce(struct wally_psbt_output *output, + const unsigned char *nonce, + size_t nonce_len) { - if (!output) + if (!output || (nonce_len && nonce_len != WALLY_TX_ASSET_CT_NONCE_LEN)) return WALLY_EINVAL; - return replace_bytes(nonce_commitment, nonce_commitment_len, - &output->nonce_commitment, &output->nonce_commitment_len); + return replace_bytes(nonce, nonce_len, + &output->nonce, &output->nonce_len); } -int wally_psbt_output_set_range_proof(struct wally_psbt_output *output, - const unsigned char *range_proof, - size_t range_proof_len) +int wally_psbt_output_set_rangeproof(struct wally_psbt_output *output, + const unsigned char *rangeproof, + size_t rangeproof_len) { if (!output) return WALLY_EINVAL; - return replace_bytes(range_proof, range_proof_len, - &output->range_proof, &output->range_proof_len); + return replace_bytes(rangeproof, rangeproof_len, + &output->rangeproof, &output->rangeproof_len); } -int wally_psbt_output_set_surjection_proof(struct wally_psbt_output *output, - const unsigned char *surjection_proof, - size_t surjection_proof_len) +int wally_psbt_output_set_surjectionproof(struct wally_psbt_output *output, + const unsigned char *surjectionproof, + size_t surjectionproof_len) { if (!output) return WALLY_EINVAL; - return replace_bytes(surjection_proof, surjection_proof_len, - &output->surjection_proof, &output->surjection_proof_len); + return replace_bytes(surjectionproof, surjectionproof_len, + &output->surjectionproof, &output->surjectionproof_len); } #endif/* BUILD_ELEMENTS */ @@ -785,12 +777,12 @@ static int psbt_output_free(struct wally_psbt_output *output, bool free_parent) #ifdef BUILD_ELEMENTS clear_and_free(output->value_commitment, output->value_commitment_len); - clear_and_free(output->value_blinder, output->value_blinder_len); + clear_and_free(output->vbf, output->vbf_len); clear_and_free(output->asset_commitment, output->asset_commitment_len); - clear_and_free(output->asset_blinder, output->asset_blinder_len); - clear_and_free(output->nonce_commitment, output->nonce_commitment_len); - clear_and_free(output->range_proof, output->range_proof_len); - clear_and_free(output->surjection_proof, output->surjection_proof_len); + clear_and_free(output->abf, output->abf_len); + clear_and_free(output->nonce, output->nonce_len); + clear_and_free(output->rangeproof, output->rangeproof_len); + clear_and_free(output->surjectionproof, output->surjectionproof_len); #endif /* BUILD_ELEMENTS */ wally_clear(output, sizeof(*output)); @@ -1400,18 +1392,18 @@ static int pull_psbt_input( } case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: { valid_type = true; - if (result->value_blinder) { + if (result->vbf) { return WALLY_EINVAL; /* Already have value blinding factor */ } subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->value_blinder, - &result->value_blinder_len, + if (!clone_varlength(&result->vbf, + &result->vbf_len, cursor, max)) { return WALLY_ENOMEM; } - if (result->value_blinder_len == 0) { - result->value_blinder = wally_malloc(1); + if (result->vbf_len == 0) { + result->vbf = wally_malloc(1); } break; } @@ -1434,18 +1426,18 @@ static int pull_psbt_input( } case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: { valid_type = true; - if (result->asset_blinder) { + if (result->abf) { return WALLY_EINVAL; /* Already have asset blinding factor */ } subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->asset_blinder, - &result->asset_blinder_len, + if (!clone_varlength(&result->abf, + &result->abf_len, cursor, max)) { return WALLY_ENOMEM; } - if (result->asset_blinder_len == 0) { - result->asset_blinder = wally_malloc(1); + if (result->abf_len == 0) { + result->abf = wally_malloc(1); } break; } @@ -1632,18 +1624,18 @@ static int pull_psbt_output( } case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: { valid_type = true; - if (result->value_blinder) { + if (result->vbf) { return WALLY_EINVAL; /* Already have value blinder */ } subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->value_blinder, - &result->value_blinder_len, + if (!clone_varlength(&result->vbf, + &result->vbf_len, cursor, max)) { return WALLY_ENOMEM; } - if (result->value_blinder_len == 0) { - result->value_blinder = wally_malloc(1); + if (result->vbf_len == 0) { + result->vbf = wally_malloc(1); } break; } @@ -1666,52 +1658,52 @@ static int pull_psbt_output( } case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: { valid_type = true; - if (result->asset_blinder) { + if (result->abf) { return WALLY_EINVAL; /* Already have asset blinder */ } subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->asset_blinder, - &result->asset_blinder_len, + if (!clone_varlength(&result->abf, + &result->abf_len, cursor, max)) { return WALLY_ENOMEM; } - if (result->asset_blinder_len == 0) { - result->asset_blinder = wally_malloc(1); + if (result->abf_len == 0) { + result->abf = wally_malloc(1); } break; } case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: { valid_type = true; - if (result->range_proof) { + if (result->rangeproof) { return WALLY_EINVAL; /* Already have range proof */ } subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->range_proof, - &result->range_proof_len, + if (!clone_varlength(&result->rangeproof, + &result->rangeproof_len, cursor, max)) { return WALLY_ENOMEM; } - if (result->range_proof_len == 0) { - result->range_proof = wally_malloc(1); + if (result->rangeproof_len == 0) { + result->rangeproof = wally_malloc(1); } break; } case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: { valid_type = true; - if (result->surjection_proof) { + if (result->surjectionproof) { return WALLY_EINVAL; /* Already have surjection proof */ } subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->surjection_proof, - &result->surjection_proof_len, + if (!clone_varlength(&result->surjectionproof, + &result->surjectionproof_len, cursor, max)) { return WALLY_ENOMEM; } - if (result->surjection_proof_len == 0) { - result->surjection_proof = wally_malloc(1); + if (result->surjectionproof_len == 0) { + result->surjectionproof = wally_malloc(1); } break; } @@ -1735,18 +1727,18 @@ static int pull_psbt_output( } case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: { valid_type = true; - if (result->nonce_commitment) { + if (result->nonce) { return WALLY_EINVAL; /* Already have nonce commitment */ } subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->nonce_commitment, - &result->nonce_commitment_len, + if (!clone_varlength(&result->nonce, + &result->nonce_len, cursor, max)) { return WALLY_ENOMEM; } - if (result->nonce_commitment_len == 0) { - result->nonce_commitment = wally_malloc(1); + if (result->nonce_len == 0) { + result->nonce = wally_malloc(1); } break; } @@ -2129,17 +2121,17 @@ static int push_psbt_input( push_varint(cursor, max, sizeof(leint64_t)); push_le64(cursor, max, input->value); } - if (input->value_blinder) { + if (input->vbf) { push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER, NULL, 0); - push_varbuff(cursor, max, input->value_blinder, input->value_blinder_len); + push_varbuff(cursor, max, input->vbf, input->vbf_len); } if (input->asset) { push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_ASSET, NULL, 0); push_varbuff(cursor, max, input->asset, input->asset_len); } - if (input->asset_blinder) { + if (input->abf) { push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER, NULL, 0); - push_varbuff(cursor, max, input->asset_blinder, input->asset_blinder_len); + push_varbuff(cursor, max, input->abf, input->abf_len); } /* Peg ins */ if (input->peg_in_tx) { @@ -2209,33 +2201,33 @@ static int push_psbt_output( push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT, NULL, 0); push_varbuff(cursor, max, output->value_commitment, output->value_commitment_len); } - if (output->value_blinder) { + if (output->vbf) { push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER, NULL, 0); - push_varbuff(cursor, max, output->value_blinder, output->value_blinder_len); + push_varbuff(cursor, max, output->vbf, output->vbf_len); } if (output->asset_commitment) { push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT, NULL, 0); push_varbuff(cursor, max, output->asset_commitment, output->asset_commitment_len); } - if (output->asset_blinder) { + if (output->abf) { push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER, NULL, 0); - push_varbuff(cursor, max, output->asset_blinder, output->asset_blinder_len); + push_varbuff(cursor, max, output->abf, output->abf_len); } - if (output->range_proof) { + if (output->rangeproof) { push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF, NULL, 0); - push_varbuff(cursor, max, output->range_proof, output->range_proof_len); + push_varbuff(cursor, max, output->rangeproof, output->rangeproof_len); } - if (output->surjection_proof) { + if (output->surjectionproof) { push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF, NULL, 0); - push_varbuff(cursor, max, output->surjection_proof, output->surjection_proof_len); + push_varbuff(cursor, max, output->surjectionproof, output->surjectionproof_len); } if (output->blinding_pubkey) { push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY, NULL, 0); push_varbuff(cursor, max, output->blinding_pubkey, output->blinding_pubkey_len); } - if (output->nonce_commitment) { + if (output->nonce) { push_psbt_elements_key(cursor, max, WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT, NULL, 0); - push_varbuff(cursor, max, output->nonce_commitment, output->nonce_commitment_len); + push_varbuff(cursor, max, output->nonce, output->nonce_len); } #endif /* BUILD_ELEMENTS */ /* Unknowns */ @@ -2530,9 +2522,9 @@ static int combine_inputs(struct wally_psbt_input *dst, dst->value = src->value; dst->has_value = true; } - COMBINE_BYTES(input, value_blinder); + COMBINE_BYTES(input, vbf); COMBINE_BYTES(input, asset); - COMBINE_BYTES(input, asset_blinder); + COMBINE_BYTES(input, abf); if ((ret = combine_txs(&dst->peg_in_tx, src->peg_in_tx)) != WALLY_OK) return ret; COMBINE_BYTES(input, txout_proof); @@ -2558,12 +2550,12 @@ static int combine_outputs(struct wally_psbt_output *dst, #ifdef BUILD_ELEMENTS COMBINE_BYTES(output, blinding_pubkey); COMBINE_BYTES(output, value_commitment); - COMBINE_BYTES(output, value_blinder); + COMBINE_BYTES(output, vbf); COMBINE_BYTES(output, asset_commitment); - COMBINE_BYTES(output, asset_blinder); - COMBINE_BYTES(output, nonce_commitment); - COMBINE_BYTES(output, range_proof); - COMBINE_BYTES(output, surjection_proof); + COMBINE_BYTES(output, abf); + COMBINE_BYTES(output, nonce); + COMBINE_BYTES(output, rangeproof); + COMBINE_BYTES(output, surjectionproof); #endif return WALLY_OK; } @@ -3132,5 +3124,15 @@ PSBT_SET_B(output, redeem_script) PSBT_SET_B(output, witness_script) PSBT_SET_S(output, keypaths, wally_keypath_map) PSBT_SET_S(output, unknowns, wally_unknowns_map) +#ifdef BUILD_ELEMENTS +PSBT_SET_B(output, blinding_pubkey) +PSBT_SET_B(output, value_commitment) +PSBT_SET_B(output, vbf) +PSBT_SET_B(output, asset_commitment) +PSBT_SET_B(output, abf) +PSBT_SET_B(output, nonce) +PSBT_SET_B(output, rangeproof) +PSBT_SET_B(output, surjectionproof) +#endif /* BUILD_ELEMENTS */ #endif /* SWIG/SWIG_JAVA_BUILD/SWIG_PYTHON_BUILD/SWIG_JAVASCRIPT_BUILD */ diff --git a/src/psbt_int.h b/src/psbt_int.h index 474786870..f938bd8f7 100644 --- a/src/psbt_int.h +++ b/src/psbt_int.h @@ -36,9 +36,14 @@ WALLY_CORE_API int wally_psbt_set_output_keypaths(struct wally_psbt *psbt, size_ WALLY_CORE_API int wally_psbt_set_output_unknowns(struct wally_psbt *psbt, size_t index, const struct wally_unknowns_map *unknowns); #ifdef BUILD_ELEMENTS -#endif /* BUILD_ELEMENTS */ - -#ifdef BUILD_ELEMENTS +WALLY_CORE_API int wally_psbt_set_output_blinding_pubkey(struct wally_psbt *psbt, size_t index, const unsigned char *pub_key, size_t pub_key_len); +WALLY_CORE_API int wally_psbt_set_output_value_commitment(struct wally_psbt *psbt, size_t index, const unsigned char *commitment, size_t commitment_len); +WALLY_CORE_API int wally_psbt_set_output_vbf(struct wally_psbt *psbt, size_t index, const unsigned char *vbf, size_t vbf_len); +WALLY_CORE_API int wally_psbt_set_output_asset_commitment(struct wally_psbt *psbt, size_t index, const unsigned char *commitment, size_t commitment_len); +WALLY_CORE_API int wally_psbt_set_output_abf(struct wally_psbt *psbt, size_t index, const unsigned char *abf, size_t abf_len); +WALLY_CORE_API int wally_psbt_set_output_nonce(struct wally_psbt *psbt, size_t index, const unsigned char *nonce, size_t nonce_len); +WALLY_CORE_API int wally_psbt_set_output_rangeproof(struct wally_psbt *psbt, size_t index, const unsigned char *rangeproof, size_t rangeproof_len); +WALLY_CORE_API int wally_psbt_set_output_surjectionproof(struct wally_psbt *psbt, size_t index, const unsigned char *surjectionproof, size_t surjectionproof_len); #endif /* BUILD_ELEMENTS */ #ifdef __cplusplus diff --git a/src/swig_python/contrib/psbt.py b/src/swig_python/contrib/psbt.py index 50ba6d7c6..a3e8c75ae 100644 --- a/src/swig_python/contrib/psbt.py +++ b/src/swig_python/contrib/psbt.py @@ -46,6 +46,10 @@ def test_psbt(self): dummy_fingerprint = bytearray(b'\x00' * BIP32_KEY_FINGERPRINT_LEN) dummy_path = [1234, 1234, 1234] dummy_sig = bytearray(b'\x00' * 72) + if is_elements_build(): + dummy_nonce = bytearray(b'\x00' * WALLY_TX_ASSET_CT_NONCE_LEN) + dummy_bf = bytearray(b'\x00' * BLINDING_FACTOR_LEN) + dummy_commitment = bytearray(b'\x00' * ASSET_COMMITMENT_LEN) dummy_keypaths = keypath_map_init(0) self.assertIsNotNone(dummy_keypaths) @@ -83,6 +87,15 @@ def test_psbt(self): self._try_set(psbt_set_output_witness_script, psbt, dummy_bytes) self._try_set(psbt_set_output_keypaths, psbt, dummy_keypaths) self._try_set(psbt_set_output_unknowns, psbt, dummy_unknowns) + if is_elements_build(): + self._try_set(psbt_set_output_blinding_pubkey, psbt, dummy_pubkey) + self._try_set(psbt_set_output_value_commitment, psbt, dummy_commitment) + self._try_set(psbt_set_output_vbf, psbt, dummy_bf) + self._try_set(psbt_set_output_asset_commitment, psbt, dummy_commitment) + self._try_set(psbt_set_output_abf, psbt, dummy_bf) + self._try_set(psbt_set_output_nonce, psbt, dummy_nonce) + self._try_set(psbt_set_output_rangeproof, psbt, dummy_bytes) + self._try_set(psbt_set_output_surjectionproof, psbt, dummy_bytes) if __name__ == '__main__': diff --git a/src/swig_python/swig.i b/src/swig_python/swig.i index 5270e05d5..093725a4e 100644 --- a/src/swig_python/swig.i +++ b/src/swig_python/swig.i @@ -193,11 +193,11 @@ static void destroy_words(PyObject *obj) { (void)obj; } /* Input buffers with lengths are passed as python buffers */ -%pybuffer_nonnull_binary(const unsigned char *abf, size_t abf_len); +%pybuffer_nullable_binary(const unsigned char *abf, size_t abf_len); %pybuffer_nonnull_binary(const unsigned char *asset, size_t asset_len); %pybuffer_nullable_binary(const unsigned char *bytes, size_t bytes_len); %pybuffer_nonnull_binary(const unsigned char *chain_code, size_t chain_code_len); -%pybuffer_nonnull_binary(const unsigned char *commitment, size_t commitment_len); +%pybuffer_nullable_binary(const unsigned char *commitment, size_t commitment_len); %pybuffer_nullable_binary(const unsigned char *extra, size_t extra_len); %pybuffer_nonnull_binary(const unsigned char *generator, size_t generator_len); %pybuffer_nullable_binary(const unsigned char *hash160, size_t hash160_len); @@ -217,7 +217,7 @@ static void destroy_words(PyObject *obj) { (void)obj; } %pybuffer_nonnull_binary(const unsigned char *sig, size_t sig_len); %pybuffer_nonnull_binary(const unsigned char *sighash, size_t sighash_len); %pybuffer_nonnull_binary(const unsigned char *txhash, size_t txhash_len); -%pybuffer_nonnull_binary(const unsigned char *vbf, size_t vbf_len); +%pybuffer_nullable_binary(const unsigned char *vbf, size_t vbf_len); %pybuffer_nullable_binary(const unsigned char *witness, size_t witness_len); %pybuffer_nonnull_binary(const unsigned char *nonce, size_t nonce_len); %pybuffer_nonnull_binary(const unsigned char *nonce_hash, size_t nonce_hash_len); diff --git a/src/test/util.py b/src/test/util.py index f72f61483..4e215bfbd 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -163,12 +163,12 @@ class wally_psbt_input(Structure): ('sighash_type', c_ulong), ('value', c_uint64), ('has_value', c_ulong), - ('value_blinder', c_void_p), - ('value_blinder_len', c_ulong), + ('vbf', c_void_p), + ('vbf_len', c_ulong), ('asset', c_void_p), ('asset_len', c_ulong), - ('asset_blinder', c_void_p), - ('asset_blinder_len', c_ulong), + ('abf', c_void_p), + ('abf_len', c_ulong), ('peg_in_tx', POINTER(wally_tx)), ('txout_proof', c_void_p), ('txout_proof_len', c_ulong), @@ -188,18 +188,18 @@ class wally_psbt_output(Structure): ('has_blinding_pubkey', c_ulong), ('value_commitment', c_void_p), ('value_commitment_len', c_ulong), - ('value_blinder', c_void_p), - ('value_blinder_len', c_ulong), + ('vbf', c_void_p), + ('vbf_len', c_ulong), ('asset_commitment', c_void_p), ('asset_commitment_len', c_ulong), - ('asset_blinder', c_void_p), - ('asset_blinder_len', c_ulong), - ('nonce_commitment', c_void_p), - ('nonce_commitment_len', c_ulong), - ('range_proof', c_void_p), - ('range_proof_len', c_ulong), - ('surjection_proof', c_void_p), - ('surjection_proof_len', c_ulong)] + ('abf', c_void_p), + ('abf_len', c_ulong), + ('nonce', c_void_p), + ('nonce_len', c_ulong), + ('rangeproof', c_void_p), + ('rangeproof_len', c_ulong), + ('surjectionproof', c_void_p), + ('surjectionproof_len', c_ulong)] class wally_psbt(Structure): _fields_ = [('magic', c_ubyte * 5), @@ -321,21 +321,21 @@ class wally_psbt(Structure): ('wally_psbt_combine', c_int, [POINTER(wally_psbt), POINTER(wally_psbt)]), ('wally_psbt_elements_init_alloc', c_int, [c_uint, c_ulong, c_ulong, c_ulong, POINTER(POINTER(wally_psbt))]), ('wally_psbt_input_clear_value', c_int, [POINTER(wally_psbt_input)]), - ('wally_psbt_input_set_asset_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_abf', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_claim_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_genesis_hash', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_peg_in_tx', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), ('wally_psbt_input_set_txout_proof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_input_set_value_blinder', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_vbf', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_value', c_int, [POINTER(wally_psbt_input), c_uint64]), - ('wally_psbt_output_set_asset_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_abf', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_output_set_asset_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_output_set_blinding_pubkey', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_output_set_nonce_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_output_set_range_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_output_set_surjection_proof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), - ('wally_psbt_output_set_value_blinder', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_nonce', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_rangeproof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_surjectionproof', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), + ('wally_psbt_output_set_vbf', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_output_set_value_commitment', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_extract', c_int, [POINTER(wally_psbt), POINTER(POINTER(wally_tx))]), ('wally_psbt_finalize', c_int, [POINTER(wally_psbt)]), From d20c66bd4317c3c156a325a27db38837e1f31689 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 23 Jul 2020 09:12:04 +1200 Subject: [PATCH 201/205] psbt: Simplify input/output pull logic --- src/psbt.c | 535 +++++++++++++++++++++++++---------------------------- 1 file changed, 255 insertions(+), 280 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index c038a8f9e..9e3fd6bd4 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -1363,167 +1363,155 @@ static int pull_psbt_input( subfield_nomore_end(cursor, max, val, val_max); break; } - case WALLY_PSBT_PROPRIETARY_TYPE: { #ifdef BUILD_ELEMENTS - uint64_t id_len; - bool valid_type = false; - - id_len = pull_varlength(&key, &key_len); - if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { - /* Skip the elements_id prefix */ - pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); - - switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_IN_ELEMENTS_VALUE: { - valid_type = true; - if (result->has_value) { - return WALLY_EINVAL; /* Already have value */ - } - subfield_nomore_end(cursor, max, key, key_len); - - /* Start parsing the value field. */ - pull_subfield_start(cursor, max, - pull_varint(cursor, max), - &val, &val_max); - result->value = pull_le64(&val, &val_max); - subfield_nomore_end(cursor, max, val, val_max); - result->has_value = true; - break; - } - case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: { - valid_type = true; - if (result->vbf) { - return WALLY_EINVAL; /* Already have value blinding factor */ - } - subfield_nomore_end(cursor, max, key, key_len); + case WALLY_PSBT_PROPRIETARY_TYPE: { + const uint64_t id_len = pull_varlength(&key, &key_len); - if (!clone_varlength(&result->vbf, - &result->vbf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->vbf_len == 0) { - result->vbf = wally_malloc(1); - } - break; + if (id_len != WALLY_ELEMENTS_ID_LEN || memcmp(key, WALLY_ELEMENTS_ID, id_len)) + goto unknown_type; + + /* Skip the elements_id prefix */ + pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); + + switch (pull_varint(&key, &key_len)) { + case WALLY_PSBT_IN_ELEMENTS_VALUE: { + if (result->has_value) { + return WALLY_EINVAL; /* Already have value */ } - case WALLY_PSBT_IN_ELEMENTS_ASSET: { - valid_type = true; - if (result->asset) { - return WALLY_EINVAL; /* Already have asset */ - } - subfield_nomore_end(cursor, max, key, key_len); + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->asset, - &result->asset_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->asset_len == 0) { - result->asset = wally_malloc(1); - } - break; + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + result->value = pull_le64(&val, &val_max); + subfield_nomore_end(cursor, max, val, val_max); + result->has_value = true; + break; + } + case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: { + if (result->vbf) { + return WALLY_EINVAL; /* Already have value blinding factor */ } - case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: { - valid_type = true; - if (result->abf) { - return WALLY_EINVAL; /* Already have asset blinding factor */ - } - subfield_nomore_end(cursor, max, key, key_len); + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->abf, - &result->abf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->abf_len == 0) { - result->abf = wally_malloc(1); - } - break; + if (!clone_varlength(&result->vbf, + &result->vbf_len, + cursor, max)) { + return WALLY_ENOMEM; } - case WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX: { - valid_type = true; - if (result->peg_in_tx) { - return WALLY_EINVAL; /* Already have asset */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (result->vbf_len == 0) { + result->vbf = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_ASSET: { + if (result->asset) { + return WALLY_EINVAL; /* Already have asset */ + } + subfield_nomore_end(cursor, max, key, key_len); - /* Start parsing the value field. */ - pull_subfield_start(cursor, max, - pull_varint(cursor, max), - &val, &val_max); + if (!clone_varlength(&result->asset, + &result->asset_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->asset_len == 0) { + result->asset = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: { + if (result->abf) { + return WALLY_EINVAL; /* Already have asset blinding factor */ + } + subfield_nomore_end(cursor, max, key, key_len); - ret = wally_tx_from_bytes(val, val_max, flags, &result->peg_in_tx); - if (ret != WALLY_OK) { - return ret; - } - pull_subfield_end(cursor, max, val, val_max); - break; + if (!clone_varlength(&result->abf, + &result->abf_len, + cursor, max)) { + return WALLY_ENOMEM; } - case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: { - valid_type = true; - if (result->txout_proof) { - return WALLY_EINVAL; /* Already have txout proof */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (result->abf_len == 0) { + result->abf = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX: { + if (result->peg_in_tx) { + return WALLY_EINVAL; /* Already have asset */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->txout_proof, - &result->txout_proof_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->txout_proof_len == 0) { - result->txout_proof = wally_malloc(1); - } - break; + /* Start parsing the value field. */ + pull_subfield_start(cursor, max, + pull_varint(cursor, max), + &val, &val_max); + + ret = wally_tx_from_bytes(val, val_max, flags, &result->peg_in_tx); + if (ret != WALLY_OK) { + return ret; } - case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: { - valid_type = true; - if (result->genesis_hash) { - return WALLY_EINVAL; /* Already have genesis hash */ - } - subfield_nomore_end(cursor, max, key, key_len); + pull_subfield_end(cursor, max, val, val_max); + break; + } + case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: { + if (result->txout_proof) { + return WALLY_EINVAL; /* Already have txout proof */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->genesis_hash, - &result->genesis_hash_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->genesis_hash_len == 0) { - result->genesis_hash = wally_malloc(1); - } - break; + if (!clone_varlength(&result->txout_proof, + &result->txout_proof_len, + cursor, max)) { + return WALLY_ENOMEM; } - case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: { - valid_type = true; - if (result->claim_script) { - return WALLY_EINVAL; /* Already have asset */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (result->txout_proof_len == 0) { + result->txout_proof = wally_malloc(1); + } + break; + } + case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: { + if (result->genesis_hash) { + return WALLY_EINVAL; /* Already have genesis hash */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->claim_script, - &result->claim_script_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->claim_script_len == 0) { - result->claim_script = wally_malloc(1); - } - break; + if (!clone_varlength(&result->genesis_hash, + &result->genesis_hash_len, + cursor, max)) { + return WALLY_ENOMEM; } - default: - valid_type = false; + if (result->genesis_hash_len == 0) { + result->genesis_hash = wally_malloc(1); } + break; } - if (valid_type) { + case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: { + if (result->claim_script) { + return WALLY_EINVAL; /* Already have asset */ + } + subfield_nomore_end(cursor, max, key, key_len); + + if (!clone_varlength(&result->claim_script, + &result->claim_script_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->claim_script_len == 0) { + result->claim_script = wally_malloc(1); + } break; } -#endif /* BUILD_ELEMENTS */ + default: + goto unknown_type; + } + break; } - /* For unknown case without elements or for unknown proprietary types */ - /* fall through */ - /* Unknowns */ +#endif /* BUILD_ELEMENTS */ default: { +unknown_type: + /* Unknown case without elements or for unknown proprietary types */ ret = pull_unknown_key_value(cursor, max, pre_key, &result->unknowns); if (ret != WALLY_OK) return ret; @@ -1531,7 +1519,6 @@ static int pull_psbt_input( } } pre_key = *cursor; - } return WALLY_OK; @@ -1594,167 +1581,155 @@ static int pull_psbt_output( return ret; break; } - case WALLY_PSBT_PROPRIETARY_TYPE: { #ifdef BUILD_ELEMENTS - uint64_t id_len; - bool valid_type = false; - - id_len = pull_varlength(&key, &key_len); - if (id_len == WALLY_ELEMENTS_ID_LEN && memcmp(key, WALLY_ELEMENTS_ID, id_len) == 0) { - /* Skip the elements_id prefix */ - pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); - - switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: { - valid_type = true; - if (result->value_commitment) { - return WALLY_EINVAL; /* Already have value commitment */ - } - subfield_nomore_end(cursor, max, key, key_len); + case WALLY_PSBT_PROPRIETARY_TYPE: { + const uint64_t id_len = pull_varlength(&key, &key_len); - if (!clone_varlength(&result->value_commitment, - &result->value_commitment_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->value_commitment_len == 0) { - result->value_commitment = wally_malloc(1); - } - break; - } - case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: { - valid_type = true; - if (result->vbf) { - return WALLY_EINVAL; /* Already have value blinder */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (id_len != WALLY_ELEMENTS_ID_LEN || memcmp(key, WALLY_ELEMENTS_ID, id_len)) + goto unknown_type; - if (!clone_varlength(&result->vbf, - &result->vbf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->vbf_len == 0) { - result->vbf = wally_malloc(1); - } - break; + /* Skip the elements_id prefix */ + pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); + + switch (pull_varint(&key, &key_len)) { + case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: { + if (result->value_commitment) { + return WALLY_EINVAL; /* Already have value commitment */ } - case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: { - valid_type = true; - if (result->asset_commitment) { - return WALLY_EINVAL; /* Already have asset commitment */ - } - subfield_nomore_end(cursor, max, key, key_len); + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->asset_commitment, - &result->asset_commitment_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->asset_commitment_len == 0) { - result->asset_commitment = wally_malloc(1); - } - break; + if (!clone_varlength(&result->value_commitment, + &result->value_commitment_len, + cursor, max)) { + return WALLY_ENOMEM; } - case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: { - valid_type = true; - if (result->abf) { - return WALLY_EINVAL; /* Already have asset blinder */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (result->value_commitment_len == 0) { + result->value_commitment = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: { + if (result->vbf) { + return WALLY_EINVAL; /* Already have value blinder */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->abf, - &result->abf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->abf_len == 0) { - result->abf = wally_malloc(1); - } - break; + if (!clone_varlength(&result->vbf, + &result->vbf_len, + cursor, max)) { + return WALLY_ENOMEM; } - case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: { - valid_type = true; - if (result->rangeproof) { - return WALLY_EINVAL; /* Already have range proof */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (result->vbf_len == 0) { + result->vbf = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: { + if (result->asset_commitment) { + return WALLY_EINVAL; /* Already have asset commitment */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->rangeproof, - &result->rangeproof_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->rangeproof_len == 0) { - result->rangeproof = wally_malloc(1); - } - break; + if (!clone_varlength(&result->asset_commitment, + &result->asset_commitment_len, + cursor, max)) { + return WALLY_ENOMEM; } - case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: { - valid_type = true; - if (result->surjectionproof) { - return WALLY_EINVAL; /* Already have surjection proof */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (result->asset_commitment_len == 0) { + result->asset_commitment = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: { + if (result->abf) { + return WALLY_EINVAL; /* Already have asset blinder */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->surjectionproof, - &result->surjectionproof_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->surjectionproof_len == 0) { - result->surjectionproof = wally_malloc(1); - } - break; + if (!clone_varlength(&result->abf, + &result->abf_len, + cursor, max)) { + return WALLY_ENOMEM; } - case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: { - valid_type = true; - if (result->blinding_pubkey) { - return WALLY_EINVAL; /* Already have blinding pubkey */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (result->abf_len == 0) { + result->abf = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: { + if (result->rangeproof) { + return WALLY_EINVAL; /* Already have range proof */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->blinding_pubkey, - &result->blinding_pubkey_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (!is_valid_optional_pubkey_len(result->blinding_pubkey_len)) - return WALLY_EINVAL; - if (result->blinding_pubkey_len == 0) - result->blinding_pubkey = wally_malloc(1); - break; - } - case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: { - valid_type = true; - if (result->nonce) { - return WALLY_EINVAL; /* Already have nonce commitment */ - } - subfield_nomore_end(cursor, max, key, key_len); + if (!clone_varlength(&result->rangeproof, + &result->rangeproof_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->rangeproof_len == 0) { + result->rangeproof = wally_malloc(1); + } + break; + } + case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: { + if (result->surjectionproof) { + return WALLY_EINVAL; /* Already have surjection proof */ + } + subfield_nomore_end(cursor, max, key, key_len); - if (!clone_varlength(&result->nonce, - &result->nonce_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->nonce_len == 0) { - result->nonce = wally_malloc(1); - } - break; + if (!clone_varlength(&result->surjectionproof, + &result->surjectionproof_len, + cursor, max)) { + return WALLY_ENOMEM; } - default: - valid_type = false; + if (result->surjectionproof_len == 0) { + result->surjectionproof = wally_malloc(1); } + break; } - if (valid_type) { + case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: { + if (result->blinding_pubkey) { + return WALLY_EINVAL; /* Already have blinding pubkey */ + } + subfield_nomore_end(cursor, max, key, key_len); + + if (!clone_varlength(&result->blinding_pubkey, + &result->blinding_pubkey_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (!is_valid_optional_pubkey_len(result->blinding_pubkey_len)) + return WALLY_EINVAL; + if (result->blinding_pubkey_len == 0) + result->blinding_pubkey = wally_malloc(1); break; } -#endif /* BUILD_ELEMENTS */ + case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: { + if (result->nonce) { + return WALLY_EINVAL; /* Already have nonce commitment */ + } + subfield_nomore_end(cursor, max, key, key_len); + + if (!clone_varlength(&result->nonce, + &result->nonce_len, + cursor, max)) { + return WALLY_ENOMEM; + } + if (result->nonce_len == 0) { + result->nonce = wally_malloc(1); + } + break; + } + default: + goto unknown_type; + } + break; } - /* For unknown case without elements or for unknown proprietary types */ - /* fall through */ - /* Unknowns */ +#endif /* BUILD_ELEMENTS */ default: { +unknown_type: + /* Unknown case without elements or for unknown proprietary types */ ret = pull_unknown_key_value(cursor, max, pre_key, &result->unknowns); if (ret != WALLY_OK) return ret; From 846a4d85aefd7f44f96d8a9b027452f8dc8f34bb Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Thu, 23 Jul 2020 10:10:44 +1200 Subject: [PATCH 202/205] psbt: cleanup code for and validate field lengths when reading in psbts --- src/psbt.c | 455 ++++++++++++----------------------------------------- 1 file changed, 102 insertions(+), 353 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index 9e3fd6bd4..e4db28f6f 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -940,15 +940,6 @@ int wally_psbt_set_global_tx(struct wally_psbt *psbt, const struct wally_tx *tx) return psbt_set_global_tx(psbt, (struct wally_tx *)tx, true); } -/* clones varlength field entirely. */ -static bool clone_varlength(unsigned char **dst, - size_t *len, - const unsigned char **cursor, size_t *max) -{ - *len = pull_varlength(cursor, max); - return clone_bytes(dst, pull_skip(cursor, max, *len), *len); -} - /* Stricter version of pull_subfield_end which insists there's nothing left. */ static void subfield_nomore_end(const unsigned char **cursor, size_t *max, const unsigned char *subcursor, @@ -1163,15 +1154,30 @@ static int pull_nonce(const unsigned char **cursor, #endif /* BUILD_ELEMENTS */ -static int pull_psbt_input( - const unsigned char **cursor, - size_t *max, - uint32_t flags, - struct wally_psbt_input *result) +static void fetch_varlength_ptr(const unsigned char **dst, size_t *len, + const unsigned char **cursor, size_t *max) +{ + *len = pull_varlength(cursor, max); + *dst = pull_skip(cursor, max, *len); +} + +/* Pull and set a variable length byte buffer */ +#define PSBT_PULL_B(typ, name) \ + if (result->name) \ + return WALLY_EINVAL; /* Duplicate value */ \ + subfield_nomore_end(cursor, max, key, key_len); \ + fetch_varlength_ptr(&vl_p, &vl_len, cursor, max); \ + if (!vl_len) \ + result->name = wally_malloc(1); /* TODO: handle empty values more elegantly */ \ + else if ((ret = wally_psbt_ ## typ ## _set_ ## name(result, vl_p, vl_len)) != WALLY_OK) \ + return ret + +static int pull_psbt_input(const unsigned char **cursor, size_t *max, + uint32_t flags, struct wally_psbt_input *result) { int ret; - size_t key_len; - const unsigned char *pre_key; + size_t key_len, vl_len; + const unsigned char *pre_key, *vl_p; /* Read key value pairs */ pre_key = *cursor; @@ -1185,61 +1191,58 @@ static int pull_psbt_input( /* Process based on type */ switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_IN_NON_WITNESS_UTXO: { - if (result->non_witness_utxo) { + if (result->non_witness_utxo) return WALLY_EINVAL; /* We already have a non witness utxo */ - } + subfield_nomore_end(cursor, max, key, key_len); /* Start parsing the value field. */ - pull_subfield_start(cursor, max, - pull_varint(cursor, max), + pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); - ret = wally_tx_from_bytes(val, val_max, flags, - &result->non_witness_utxo); - if (ret != WALLY_OK) { + if ((ret = wally_tx_from_bytes(val, val_max, flags, + &result->non_witness_utxo)) != WALLY_OK) return ret; - } + pull_subfield_end(cursor, max, val, val_max); break; } case WALLY_PSBT_IN_WITNESS_UTXO: { uint64_t amount, script_len; const unsigned char *script; - if (result->witness_utxo) { - return WALLY_EINVAL; /* We already have a witness utxo */ - } + + if (result->witness_utxo) + return WALLY_EINVAL; /* Duplicate value */ + subfield_nomore_end(cursor, max, key, key_len); + /* Start parsing the value field. */ - pull_subfield_start(cursor, max, - pull_varint(cursor, max), + pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); #ifdef BUILD_ELEMENTS if (flags & WALLY_TX_FLAG_USE_ELEMENTS) { const unsigned char *asset, *value, *nonce; size_t asset_len, value_len, nonce_len; - if ((ret = pull_confidential_asset(&val, &val_max, &asset, &asset_len)) != WALLY_OK) { + if ((ret = pull_confidential_asset(&val, &val_max, &asset, &asset_len)) != WALLY_OK) return ret; - } - if ((ret = pull_confidential_value(&val, &val_max, &value, &value_len)) != WALLY_OK) { + if ((ret = pull_confidential_value(&val, &val_max, &value, &value_len)) != WALLY_OK) return ret; - } - if ((ret = pull_nonce(&val, &val_max, &nonce, &nonce_len)) != WALLY_OK) { + if ((ret = pull_nonce(&val, &val_max, &nonce, &nonce_len)) != WALLY_OK) return ret; - } + script_len = pull_varint(&val, &val_max); script = pull_skip(&val, &val_max, script_len); - if (!script || !script_len) { + if (!script || !script_len) return WALLY_EINVAL; - } + ret = wally_tx_elements_output_init_alloc(script, script_len, asset, asset_len, value, value_len, nonce, nonce_len, NULL, 0, NULL, 0, &result->witness_utxo); - if (ret != WALLY_OK) { + if (ret != WALLY_OK) return ret; - } + subfield_nomore_end(cursor, max, val, val_max); break; } @@ -1248,14 +1251,13 @@ static int pull_psbt_input( amount = pull_le64(&val, &val_max); script_len = pull_varint(&val, &val_max); script = pull_skip(&val, &val_max, script_len); - if (!script || !script_len) { + if (!script || !script_len) return WALLY_EINVAL; - } ret = wally_tx_output_init_alloc(amount, script, script_len, &result->witness_utxo); - if (ret != WALLY_OK) { + if (ret != WALLY_OK) return ret; - } + subfield_nomore_end(cursor, max, val, val_max); break; } @@ -1266,9 +1268,9 @@ static int pull_psbt_input( break; } case WALLY_PSBT_IN_SIGHASH_TYPE: { - if (result->sighash_type > 0) { - return WALLY_EINVAL; /* Sighash already provided */ - } + if (result->sighash_type != 0) + return WALLY_EINVAL; /* Duplicate value */ + subfield_nomore_end(cursor, max, key, key_len); /* Start parsing the value field. */ @@ -1279,36 +1281,11 @@ static int pull_psbt_input( subfield_nomore_end(cursor, max, val, val_max); break; } - case WALLY_PSBT_IN_REDEEM_SCRIPT: { - if (result->redeem_script) { - return WALLY_EINVAL; /* Already have a redeem script */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->redeem_script, - &result->redeem_script_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->redeem_script_len == 0) { - result->redeem_script = wally_malloc(1); - } + case WALLY_PSBT_IN_REDEEM_SCRIPT: + PSBT_PULL_B(input, redeem_script); break; - } case WALLY_PSBT_IN_WITNESS_SCRIPT: { - if (result->witness_script) { - return WALLY_EINVAL; /* Already have a witness script */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->witness_script, - &result->witness_script_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->witness_script_len == 0) { - result->witness_script = wally_malloc(1); - } + PSBT_PULL_B(input, witness_script); break; } case WALLY_PSBT_IN_BIP32_DERIVATION: { @@ -1317,28 +1294,14 @@ static int pull_psbt_input( return ret; break; } - case WALLY_PSBT_IN_FINAL_SCRIPTSIG: { - if (result->final_script_sig) { - return WALLY_EINVAL; /* Already have a scriptSig */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->final_script_sig, - &result->final_script_sig_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->final_script_sig_len == 0) { - result->final_script_sig = wally_malloc(1); - } + case WALLY_PSBT_IN_FINAL_SCRIPTSIG: + PSBT_PULL_B(input, final_script_sig); break; - } case WALLY_PSBT_IN_FINAL_SCRIPTWITNESS: { uint64_t num_witnesses; size_t i; - if (result->final_witness) { - return WALLY_EINVAL; /* Already have a scriptWitness */ - } + if (result->final_witness) + return WALLY_EINVAL; /* Duplicate value */ subfield_nomore_end(cursor, max, key, key_len); /* Start parsing the value field. */ @@ -1347,18 +1310,16 @@ static int pull_psbt_input( &val, &val_max); num_witnesses = pull_varint(&val, &val_max); ret = wally_tx_witness_stack_init_alloc(num_witnesses, &result->final_witness); - if (ret != WALLY_OK) { + if (ret != WALLY_OK) return ret; - } for (i = 0; i < num_witnesses; ++i) { uint64_t witness_len = pull_varint(&val, &val_max); ret = wally_tx_witness_stack_set(result->final_witness, i, pull_skip(&val, &val_max, witness_len), witness_len); - if (ret != WALLY_OK) { + if (ret != WALLY_OK) return ret; - } } subfield_nomore_end(cursor, max, val, val_max); break; @@ -1375,72 +1336,32 @@ static int pull_psbt_input( switch (pull_varint(&key, &key_len)) { case WALLY_PSBT_IN_ELEMENTS_VALUE: { - if (result->has_value) { - return WALLY_EINVAL; /* Already have value */ - } + if (result->has_value) + return WALLY_EINVAL; /* Duplicate value */ + subfield_nomore_end(cursor, max, key, key_len); /* Start parsing the value field. */ - pull_subfield_start(cursor, max, - pull_varint(cursor, max), + pull_subfield_start(cursor, max, pull_varint(cursor, max), &val, &val_max); result->value = pull_le64(&val, &val_max); subfield_nomore_end(cursor, max, val, val_max); result->has_value = true; break; } - case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: { - if (result->vbf) { - return WALLY_EINVAL; /* Already have value blinding factor */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->vbf, - &result->vbf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->vbf_len == 0) { - result->vbf = wally_malloc(1); - } + case WALLY_PSBT_IN_ELEMENTS_VALUE_BLINDER: + PSBT_PULL_B(input, vbf); break; - } - case WALLY_PSBT_IN_ELEMENTS_ASSET: { - if (result->asset) { - return WALLY_EINVAL; /* Already have asset */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->asset, - &result->asset_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->asset_len == 0) { - result->asset = wally_malloc(1); - } + case WALLY_PSBT_IN_ELEMENTS_ASSET: + PSBT_PULL_B(input, asset); break; - } - case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: { - if (result->abf) { - return WALLY_EINVAL; /* Already have asset blinding factor */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->abf, - &result->abf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->abf_len == 0) { - result->abf = wally_malloc(1); - } + case WALLY_PSBT_IN_ELEMENTS_ASSET_BLINDER: + PSBT_PULL_B(input, abf); break; - } case WALLY_PSBT_IN_ELEMENTS_PEG_IN_TX: { - if (result->peg_in_tx) { - return WALLY_EINVAL; /* Already have asset */ - } + if (result->peg_in_tx) + return WALLY_EINVAL; /* Duplicate value */ + subfield_nomore_end(cursor, max, key, key_len); /* Start parsing the value field. */ @@ -1449,60 +1370,21 @@ static int pull_psbt_input( &val, &val_max); ret = wally_tx_from_bytes(val, val_max, flags, &result->peg_in_tx); - if (ret != WALLY_OK) { + if (ret != WALLY_OK) return ret; - } + pull_subfield_end(cursor, max, val, val_max); break; } - case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: { - if (result->txout_proof) { - return WALLY_EINVAL; /* Already have txout proof */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->txout_proof, - &result->txout_proof_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->txout_proof_len == 0) { - result->txout_proof = wally_malloc(1); - } + case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: + PSBT_PULL_B(input, txout_proof); break; - } - case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: { - if (result->genesis_hash) { - return WALLY_EINVAL; /* Already have genesis hash */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->genesis_hash, - &result->genesis_hash_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->genesis_hash_len == 0) { - result->genesis_hash = wally_malloc(1); - } + case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: + PSBT_PULL_B(input, genesis_hash); break; - } - case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: { - if (result->claim_script) { - return WALLY_EINVAL; /* Already have asset */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->claim_script, - &result->claim_script_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->claim_script_len == 0) { - result->claim_script = wally_malloc(1); - } + case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: + PSBT_PULL_B(input, claim_script); break; - } default: goto unknown_type; } @@ -1524,14 +1406,12 @@ static int pull_psbt_input( return WALLY_OK; } -static int pull_psbt_output( - const unsigned char **cursor, - size_t *max, - struct wally_psbt_output *result) +static int pull_psbt_output(const unsigned char **cursor, size_t *max, + struct wally_psbt_output *result) { int ret; - size_t key_len; - const unsigned char *pre_key; + size_t key_len, vl_len; + const unsigned char *pre_key, *vl_p; /* Read key value */ pre_key = *cursor; @@ -1543,38 +1423,12 @@ static int pull_psbt_output( /* Process based on type */ switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_OUT_REDEEM_SCRIPT: { - if (result->redeem_script) { - return WALLY_EINVAL; /* Already have a redeem script */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->redeem_script, - &result->redeem_script_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->redeem_script_len == 0) { - result->redeem_script = wally_malloc(1); - } + case WALLY_PSBT_OUT_REDEEM_SCRIPT: + PSBT_PULL_B(output, redeem_script); break; - } - case WALLY_PSBT_OUT_WITNESS_SCRIPT: { - if (result->witness_script) { - return WALLY_EINVAL; /* Already have a witness script */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->witness_script, - &result->witness_script_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->witness_script_len == 0) { - result->witness_script = wally_malloc(1); - } + case WALLY_PSBT_OUT_WITNESS_SCRIPT: + PSBT_PULL_B(output, witness_script); break; - } case WALLY_PSBT_OUT_BIP32_DERIVATION: { ret = pull_keypath(cursor, max, key, key_len, &result->keypaths); if (ret != WALLY_OK) @@ -1592,135 +1446,30 @@ static int pull_psbt_output( pull_skip(&key, &key_len, WALLY_ELEMENTS_ID_LEN); switch (pull_varint(&key, &key_len)) { - case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: { - if (result->value_commitment) { - return WALLY_EINVAL; /* Already have value commitment */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->value_commitment, - &result->value_commitment_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->value_commitment_len == 0) { - result->value_commitment = wally_malloc(1); - } + case WALLY_PSBT_OUT_ELEMENTS_VALUE_COMMITMENT: + PSBT_PULL_B(output, value_commitment); break; - } - case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: { - if (result->vbf) { - return WALLY_EINVAL; /* Already have value blinder */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->vbf, - &result->vbf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->vbf_len == 0) { - result->vbf = wally_malloc(1); - } + case WALLY_PSBT_OUT_ELEMENTS_VALUE_BLINDER: + PSBT_PULL_B(output, vbf); break; - } - case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: { - if (result->asset_commitment) { - return WALLY_EINVAL; /* Already have asset commitment */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->asset_commitment, - &result->asset_commitment_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->asset_commitment_len == 0) { - result->asset_commitment = wally_malloc(1); - } + case WALLY_PSBT_OUT_ELEMENTS_ASSET_COMMITMENT: + PSBT_PULL_B(output, asset_commitment); break; - } - case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: { - if (result->abf) { - return WALLY_EINVAL; /* Already have asset blinder */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->abf, - &result->abf_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->abf_len == 0) { - result->abf = wally_malloc(1); - } + case WALLY_PSBT_OUT_ELEMENTS_ASSET_BLINDER: + PSBT_PULL_B(output, abf); break; - } - case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: { - if (result->rangeproof) { - return WALLY_EINVAL; /* Already have range proof */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->rangeproof, - &result->rangeproof_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->rangeproof_len == 0) { - result->rangeproof = wally_malloc(1); - } + case WALLY_PSBT_OUT_ELEMENTS_RANGE_PROOF: + PSBT_PULL_B(output, rangeproof); break; - } - case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: { - if (result->surjectionproof) { - return WALLY_EINVAL; /* Already have surjection proof */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->surjectionproof, - &result->surjectionproof_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->surjectionproof_len == 0) { - result->surjectionproof = wally_malloc(1); - } + case WALLY_PSBT_OUT_ELEMENTS_SURJECTION_PROOF: + PSBT_PULL_B(output, surjectionproof); break; - } - case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: { - if (result->blinding_pubkey) { - return WALLY_EINVAL; /* Already have blinding pubkey */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->blinding_pubkey, - &result->blinding_pubkey_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (!is_valid_optional_pubkey_len(result->blinding_pubkey_len)) - return WALLY_EINVAL; - if (result->blinding_pubkey_len == 0) - result->blinding_pubkey = wally_malloc(1); + case WALLY_PSBT_OUT_ELEMENTS_BLINDING_PUBKEY: + PSBT_PULL_B(output, blinding_pubkey); break; - } - case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: { - if (result->nonce) { - return WALLY_EINVAL; /* Already have nonce commitment */ - } - subfield_nomore_end(cursor, max, key, key_len); - - if (!clone_varlength(&result->nonce, - &result->nonce_len, - cursor, max)) { - return WALLY_ENOMEM; - } - if (result->nonce_len == 0) { - result->nonce = wally_malloc(1); - } + case WALLY_PSBT_OUT_ELEMENTS_NONCE_COMMITMENT: + PSBT_PULL_B(output, nonce); break; - } default: goto unknown_type; } From f6ef71907a16ef5548445910fc5c07f5b7dd65a3 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 24 Jul 2020 00:49:05 +1200 Subject: [PATCH 203/205] psbt: Expose input setters to python, with tests Also fix innteger setters to go through the setter function to get proper error checking. --- include/wally.hpp | 4 +- include/wally_psbt.h | 84 ++++++++++++++-------------- include/wally_script.h | 24 ++++---- src/psbt.c | 97 +++++++++++++++++++-------------- src/psbt_int.h | 13 ++++- src/script.c | 24 ++++---- src/swig_java/swig.i | 4 +- src/swig_python/contrib/psbt.py | 15 +++++ src/swig_python/swig.i | 6 +- src/test/util.py | 12 ++-- 10 files changed, 160 insertions(+), 123 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 0b5995125..66511fb54 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -685,8 +685,8 @@ WALLY_FN_P6(psbt_input_set_value, wally_psbt_input_set_value) WALLY_FN_PB(psbt_input_set_asset, wally_psbt_input_set_asset) WALLY_FN_PB(psbt_input_set_abf, wally_psbt_input_set_abf) WALLY_FN_PB(psbt_input_set_claim_script, wally_psbt_input_set_claim_script) -WALLY_FN_PB(psbt_input_set_genesis_hash, wally_psbt_input_set_genesis_hash) -WALLY_FN_PB(psbt_input_set_txout_proof, wally_psbt_input_set_txout_proof) +WALLY_FN_PB(psbt_input_set_genesis_blockhash, wally_psbt_input_set_genesis_blockhash) +WALLY_FN_PB(psbt_input_set_txoutproof, wally_psbt_input_set_txoutproof) WALLY_FN_PB(psbt_input_set_vbf, wally_psbt_input_set_vbf) WALLY_FN_PB(psbt_output_set_abf, wally_psbt_output_set_abf) WALLY_FN_PB(psbt_output_set_asset_commitment, wally_psbt_output_set_asset_commitment) diff --git a/include/wally_psbt.h b/include/wally_psbt.h index fe1c86666..bfba52e2d 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -133,10 +133,10 @@ struct wally_psbt_input { unsigned char *abf; size_t abf_len; struct wally_tx *peg_in_tx; - unsigned char *txout_proof; - size_t txout_proof_len; - unsigned char *genesis_hash; - size_t genesis_hash_len; + unsigned char *txoutproof; + size_t txoutproof_len; + unsigned char *genesis_blockhash; + size_t genesis_blockhash_len; unsigned char *claim_script; size_t claim_script_len; #endif /* BUILD_ELEMENTS */ @@ -368,25 +368,25 @@ WALLY_CORE_API int wally_psbt_input_set_witness_utxo( * Set the redeem_script in an input. * * :param input: The input to update. - * :param redeem_script: The redeem script for this input. - * :param redeem_script_len: Length of ``redeem_script`` in bytes. + * :param script: The redeem script for this input. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_redeem_script( struct wally_psbt_input *input, - const unsigned char *redeem_script, - size_t redeem_script_len); + const unsigned char *script, + size_t script_len); /** * Set the witness_script in an input. * * :param input: The input to update. - * :param witness_script: The witness script for this input. - * :param witness_script_len: Length of ``witness_script`` in bytes. + * :param script: The witness script for this input. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_witness_script( struct wally_psbt_input *input, - const unsigned char *witness_script, - size_t witness_script_len); + const unsigned char *script, + size_t script_len); /** * Set the final_script_sig in an input. @@ -454,25 +454,25 @@ WALLY_CORE_API int wally_psbt_input_set_sighash_type( * Set the redeem_script in an output. * * :param output: The input to update. - * :param redeem_script: The redeem script for this output. - * :param redeem_script_len: Length of ``redeem_script`` in bytes. + * :param script: The redeem script for this output. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_redeem_script( struct wally_psbt_output *output, - const unsigned char *redeem_script, - size_t redeem_script_len); + const unsigned char *script, + size_t script_len); /** * Set the witness_script in an output. * * :param output: The output to update. - * :param witness_script: The witness script for this output. - * :param witness_script_len: Length of ``witness_script`` in bytes. + * :param script: The witness script for this output. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_witness_script( struct wally_psbt_output *output, - const unsigned char *witness_script, - size_t witness_script_len); + const unsigned char *script, + size_t script_len); /** * Set the keypaths in an output. @@ -736,37 +736,37 @@ WALLY_CORE_API int wally_psbt_input_set_peg_in_tx( * Set the txout proof in an elements input. * * :param input: The input to update. - * :param txout_proof: The txout proof for this input. - * :param txout_proof_len: Length of ``txout_proof`` in bytes. + * :param proof: The txout proof for this input. + * :param proof_len: Length of ``proof`` in bytes. */ -WALLY_CORE_API int wally_psbt_input_set_txout_proof( +WALLY_CORE_API int wally_psbt_input_set_txoutproof( struct wally_psbt_input *input, - const unsigned char *txout_proof, - size_t txout_proof_len); + const unsigned char *proof, + size_t proof_len); /** * Set the genesis hash in an elements input. * * :param input: The input to update. - * :param genesis_hash: The genesis hash for this input. - * :param genesis_hash_len: Length of ``genesis_hash`` in bytes. + * :param genesis_blockhash: The genesis hash for this input. + * :param genesis_blockhash_len: Length of ``genesis_blockhash`` in bytes. Must be ``SHA256_LEN``. */ -WALLY_CORE_API int wally_psbt_input_set_genesis_hash( +WALLY_CORE_API int wally_psbt_input_set_genesis_blockhash( struct wally_psbt_input *input, - const unsigned char *genesis_hash, - size_t genesis_hash_len); + const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len); /** * Set the claim script in an elements input. * * :param input: The input to update. - * :param claim_script: The claim script for this input. - * :param claim_script_len: Length of ``claim_script`` in bytes. + * :param script: The claim script for this input. + * :param script_len: Length of ``script`` in bytes. */ WALLY_CORE_API int wally_psbt_input_set_claim_script( struct wally_psbt_input *input, - const unsigned char *claim_script, - size_t claim_script_len); + const unsigned char *script, + size_t script_len); /** * Set the blinding pubkey in an elements output. @@ -844,25 +844,25 @@ WALLY_CORE_API int wally_psbt_output_set_nonce( * Set the range proof in an elements output. * * :param output: The output to update. - * :param rangeproof: The rangeproof for this output. - * :param rangeproof_len: Length of ``rangeproof`` in bytes. + * :param proof: The range proof for this output. + * :param proof_len: Length of ``proof`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_rangeproof( struct wally_psbt_output *output, - const unsigned char *rangeproof, - size_t rangeproof_len); + const unsigned char *proof, + size_t proof_len); /** * Set the surjection proof in an elements output. * * :param output: The output to update. - * :param surjectionproof: The surjection proof for this output. - * :param surjectionproof_len: Length of ``surjectionproof`` in bytes. + * :param proof: The surjection proof for this output. + * :param proof_len: Length of ``proof`` in bytes. */ WALLY_CORE_API int wally_psbt_output_set_surjectionproof( struct wally_psbt_output *output, - const unsigned char *surjectionproof, - size_t surjectionproof_len); + const unsigned char *proof, + size_t proof_len); #endif /* SWIG */ #endif /* BUILD_ELEMENTS */ diff --git a/include/wally_script.h b/include/wally_script.h index 0ba227133..cfd803514 100644 --- a/include/wally_script.h +++ b/include/wally_script.h @@ -495,44 +495,44 @@ WALLY_CORE_API int wally_witness_program_from_bytes( /** * Get the pegout script size. * - * :param parent_genesis_blockhash_len: Length of ``parent_genesis_blockhash`` in bytes. Must be 32. + * :param genesis_blockhash_len: Length of ``genesis_blockhash`` in bytes. Must be ``SHA256_LEN``. * :param mainchain_script_len: Length of ``mainchain_script`` in bytes. * :param sub_pubkey_len: Length of ``sub_pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. - * :param whitelist_proof_len: The length of ``whitelist_proof`` in bytes. + * :param whitelistproof_len: The length of ``whitelistproof`` in bytes. * :param written: Destination for the number of bytes required to hold the pegout script. */ WALLY_CORE_API int wally_elements_pegout_script_size( - size_t parent_genesis_blockhash_len, + size_t genesis_blockhash_len, size_t mainchain_script_len, size_t sub_pubkey_len, - size_t whitelist_proof_len, + size_t whitelistproof_len, size_t *written); /** * Create a pegout script. * - * :param parent_genesis_blockhash: The genesis blockhash of the parent chain. - * :param parent_genesis_blockhash_len: Length of ``parent_genesis_blockhash`` in bytes. Must be 32. + * :param genesis_blockhash: The genesis blockhash of the parent chain. + * :param genesis_blockhash_len: Length of ``genesis_blockhash`` in bytes. Must be ``SHA256_LEN``. * :param mainchain_script: The parent chain script. * :param mainchain_script_len: Length of ``mainchain_script`` in bytes. * :param sub_pubkey: The whitelisted public key. * :param sub_pubkey_len: Length of ``sub_pubkey`` in bytes. Must be ``EC_PUBLIC_KEY_LEN``. - * :param whitelist_proof: The whitelist proof. - * :param whitelist_proof_len: The length of ``whitelist_proof`` in bytes. + * :param whitelistproof: The whitelist proof. + * :param whitelistproof_len: The length of ``whitelistproof`` in bytes. * :param flags: Must be zero. * :param bytes_out: Destination for the resulting pegout 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_elements_pegout_script_from_bytes( - const unsigned char *parent_genesis_blockhash, - size_t parent_genesis_blockhash_len, + const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len, const unsigned char *mainchain_script, size_t mainchain_script_len, const unsigned char *sub_pubkey, size_t sub_pubkey_len, - const unsigned char *whitelist_proof, - size_t whitelist_proof_len, + const unsigned char *whitelistproof, + size_t whitelistproof_len, uint32_t flags, unsigned char *bytes_out, size_t len, diff --git a/src/psbt.c b/src/psbt.c index e4db28f6f..1b3e979b6 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -467,22 +467,22 @@ int wally_psbt_input_set_witness_utxo(struct wally_psbt_input *input, } int wally_psbt_input_set_redeem_script(struct wally_psbt_input *input, - const unsigned char *redeem_script, - size_t redeem_script_len) + const unsigned char *script, + size_t script_len) { if (!input) return WALLY_EINVAL; - return replace_bytes(redeem_script, redeem_script_len, + return replace_bytes(script, script_len, &input->redeem_script, &input->redeem_script_len); } int wally_psbt_input_set_witness_script(struct wally_psbt_input *input, - const unsigned char *witness_script, - size_t witness_script_len) + const unsigned char *script, + size_t script_len) { if (!input) return WALLY_EINVAL; - return replace_bytes(witness_script, witness_script_len, + return replace_bytes(script, script_len, &input->witness_script, &input->witness_script_len); } @@ -542,6 +542,8 @@ int wally_psbt_input_set_sighash_type(struct wally_psbt_input *input, uint32_t s #ifdef BUILD_ELEMENTS int wally_psbt_input_set_value(struct wally_psbt_input *input, uint64_t value) { + if (!input) + return WALLY_EINVAL; input->value = value; input->has_value = 1u; return WALLY_OK; @@ -549,6 +551,8 @@ int wally_psbt_input_set_value(struct wally_psbt_input *input, uint64_t value) int wally_psbt_input_clear_value(struct wally_psbt_input *input) { + if (!input) + return WALLY_EINVAL; input->value = 0; input->has_value = 0; return WALLY_OK; @@ -565,7 +569,7 @@ int wally_psbt_input_set_vbf(struct wally_psbt_input *input, int wally_psbt_input_set_asset(struct wally_psbt_input *input, const unsigned char *asset, size_t asset_len) { - if (!input) + if (!input || (asset && asset_len != ASSET_TAG_LEN)) return WALLY_EINVAL; return replace_bytes(asset, asset_len, &input->asset, &input->asset_len); } @@ -596,33 +600,33 @@ int wally_psbt_input_set_peg_in_tx(struct wally_psbt_input *input, return ret; } -int wally_psbt_input_set_txout_proof(struct wally_psbt_input *input, - const unsigned char *txout_proof, - size_t txout_proof_len) +int wally_psbt_input_set_txoutproof(struct wally_psbt_input *input, + const unsigned char *txoutproof, + size_t txoutproof_len) { if (!input) return WALLY_EINVAL; - return replace_bytes(txout_proof, txout_proof_len, - &input->txout_proof, &input->txout_proof_len); + return replace_bytes(txoutproof, txoutproof_len, + &input->txoutproof, &input->txoutproof_len); } -int wally_psbt_input_set_genesis_hash(struct wally_psbt_input *input, - const unsigned char *genesis_hash, - size_t genesis_hash_len) +int wally_psbt_input_set_genesis_blockhash(struct wally_psbt_input *input, + const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len) { - if (!input) + if (!input || (genesis_blockhash && genesis_blockhash_len != SHA256_LEN)) return WALLY_EINVAL; - return replace_bytes(genesis_hash, genesis_hash_len, - &input->genesis_hash, &input->genesis_hash_len); + return replace_bytes(genesis_blockhash, genesis_blockhash_len, + &input->genesis_blockhash, &input->genesis_blockhash_len); } int wally_psbt_input_set_claim_script(struct wally_psbt_input *input, - const unsigned char *claim_script, - size_t claim_script_len) + const unsigned char *script, + size_t script_len) { if (!input) return WALLY_EINVAL; - return replace_bytes(claim_script, claim_script_len, + return replace_bytes(script, script_len, &input->claim_script, &input->claim_script_len); } #endif /* BUILD_ELEMENTS */ @@ -645,8 +649,8 @@ static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) clear_and_free(input->asset, input->asset_len); clear_and_free(input->abf, input->abf_len); wally_tx_free(input->peg_in_tx); - clear_and_free(input->txout_proof, input->txout_proof_len); - clear_and_free(input->genesis_hash, input->genesis_hash_len); + clear_and_free(input->txoutproof, input->txoutproof_len); + clear_and_free(input->genesis_blockhash, input->genesis_blockhash_len); clear_and_free(input->claim_script, input->claim_script_len); #endif /* BUILD_ELEMENTS */ @@ -658,22 +662,22 @@ static int psbt_input_free(struct wally_psbt_input *input, bool free_parent) } int wally_psbt_output_set_redeem_script(struct wally_psbt_output *output, - const unsigned char *redeem_script, - size_t redeem_script_len) + const unsigned char *script, + size_t script_len) { if (!output) return WALLY_EINVAL; - return replace_bytes(redeem_script, redeem_script_len, + return replace_bytes(script, script_len, &output->redeem_script, &output->redeem_script_len); } int wally_psbt_output_set_witness_script(struct wally_psbt_output *output, - const unsigned char *witness_script, - size_t witness_script_len) + const unsigned char *script, + size_t script_len) { if (!output) return WALLY_EINVAL; - return replace_bytes(witness_script, witness_script_len, + return replace_bytes(script, script_len, &output->witness_script, &output->witness_script_len); } @@ -1377,10 +1381,10 @@ static int pull_psbt_input(const unsigned char **cursor, size_t *max, break; } case WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF: - PSBT_PULL_B(input, txout_proof); + PSBT_PULL_B(input, txoutproof); break; case WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH: - PSBT_PULL_B(input, genesis_hash); + PSBT_PULL_B(input, genesis_blockhash); break; case WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT: PSBT_PULL_B(input, claim_script); @@ -1867,13 +1871,13 @@ static int push_psbt_input( return ret; } } - if (input->txout_proof) { + if (input->txoutproof) { push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_TXOUT_PROOF, NULL, 0); - push_varbuff(cursor, max, input->txout_proof, input->txout_proof_len); + push_varbuff(cursor, max, input->txoutproof, input->txoutproof_len); } - if (input->genesis_hash) { + if (input->genesis_blockhash) { push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_GENESIS_HASH, NULL, 0); - push_varbuff(cursor, max, input->genesis_hash, input->genesis_hash_len); + push_varbuff(cursor, max, input->genesis_blockhash, input->genesis_blockhash_len); } if (input->claim_script) { push_psbt_elements_key(cursor, max, WALLY_PSBT_IN_ELEMENTS_CLAIM_SCRIPT, NULL, 0); @@ -2251,8 +2255,8 @@ static int combine_inputs(struct wally_psbt_input *dst, COMBINE_BYTES(input, abf); if ((ret = combine_txs(&dst->peg_in_tx, src->peg_in_tx)) != WALLY_OK) return ret; - COMBINE_BYTES(input, txout_proof); - COMBINE_BYTES(input, genesis_hash); + COMBINE_BYTES(input, txoutproof); + COMBINE_BYTES(input, genesis_blockhash); COMBINE_BYTES(input, claim_script); #endif return WALLY_OK; @@ -2818,11 +2822,7 @@ static struct wally_psbt_output *psbt_get_output(const struct wally_psbt *psbt, #define PSBT_SET_I(typ, name, inttyp) \ int wally_psbt_set_ ## typ ## _ ## name(struct wally_psbt *psbt, size_t index, \ inttyp v) { \ - struct wally_psbt_ ## typ *p = psbt_get_ ## typ(psbt, index); \ - if (!p) \ - return WALLY_EINVAL; \ - p->name = v; \ - return WALLY_OK; \ + return wally_psbt_ ## typ ## _set_ ## name(psbt_get_ ## typ(psbt, index), v); \ } /* Set a struct on an input/output */ @@ -2843,6 +2843,19 @@ PSBT_SET_S(input, keypaths, wally_keypath_map) PSBT_SET_S(input, partial_sigs, wally_partial_sigs_map) PSBT_SET_S(input, unknowns, wally_unknowns_map) PSBT_SET_I(input, sighash_type, uint32_t) +#ifdef BUILD_ELEMENTS +PSBT_SET_I(input, value, uint64_t) +int wally_psbt_clear_input_value(struct wally_psbt *psbt, size_t index) { + return wally_psbt_input_clear_value(psbt_get_input(psbt, index)); +} +PSBT_SET_B(input, vbf) +PSBT_SET_B(input, asset) +PSBT_SET_B(input, abf) +PSBT_SET_S(input, peg_in_tx, wally_tx) +PSBT_SET_B(input, txoutproof) +PSBT_SET_B(input, genesis_blockhash) +PSBT_SET_B(input, claim_script) +#endif /* BUILD_ELEMENTS */ PSBT_SET_B(output, redeem_script) PSBT_SET_B(output, witness_script) diff --git a/src/psbt_int.h b/src/psbt_int.h index f938bd8f7..2eecc0c35 100644 --- a/src/psbt_int.h +++ b/src/psbt_int.h @@ -26,6 +26,15 @@ WALLY_CORE_API int wally_psbt_set_input_partial_sigs(struct wally_psbt *psbt, si WALLY_CORE_API int wally_psbt_set_input_unknowns(struct wally_psbt *psbt, size_t index, const struct wally_unknowns_map *unknowns); WALLY_CORE_API int wally_psbt_set_input_sighash_type(struct wally_psbt *psbt, size_t index, uint32_t sighash_type); #ifdef BUILD_ELEMENTS +WALLY_CORE_API int wally_psbt_set_input_value(struct wally_psbt *psbt, size_t index, uint64_t value); +WALLY_CORE_API int wally_psbt_clear_input_value(struct wally_psbt *psbt, size_t index); +WALLY_CORE_API int wally_psbt_set_input_vbf(struct wally_psbt *psbt, size_t index, const unsigned char *vbf, size_t vbf_len); +WALLY_CORE_API int wally_psbt_set_input_asset(struct wally_psbt *psbt, size_t index, const unsigned char *asset, size_t asset_len); +WALLY_CORE_API int wally_psbt_set_input_abf(struct wally_psbt *psbt, size_t index, const unsigned char *abf, size_t abf_len); +WALLY_CORE_API int wally_psbt_set_input_peg_in_tx(struct wally_psbt *psbt, size_t index, const struct wally_tx *peg_in_tx); +WALLY_CORE_API int wally_psbt_set_input_txoutproof(struct wally_psbt *psbt, size_t index, const unsigned char *proof, size_t proof_len); +WALLY_CORE_API int wally_psbt_set_input_genesis_blockhash(struct wally_psbt *psbt, size_t index, const unsigned char *genesis_blockhash, size_t genesis_blockhash_len); +WALLY_CORE_API int wally_psbt_set_input_claim_script(struct wally_psbt *psbt, size_t index, const unsigned char *script, size_t script_len); #endif /* BUILD_ELEMENTS */ /* Outputs */ @@ -42,8 +51,8 @@ WALLY_CORE_API int wally_psbt_set_output_vbf(struct wally_psbt *psbt, size_t ind WALLY_CORE_API int wally_psbt_set_output_asset_commitment(struct wally_psbt *psbt, size_t index, const unsigned char *commitment, size_t commitment_len); WALLY_CORE_API int wally_psbt_set_output_abf(struct wally_psbt *psbt, size_t index, const unsigned char *abf, size_t abf_len); WALLY_CORE_API int wally_psbt_set_output_nonce(struct wally_psbt *psbt, size_t index, const unsigned char *nonce, size_t nonce_len); -WALLY_CORE_API int wally_psbt_set_output_rangeproof(struct wally_psbt *psbt, size_t index, const unsigned char *rangeproof, size_t rangeproof_len); -WALLY_CORE_API int wally_psbt_set_output_surjectionproof(struct wally_psbt *psbt, size_t index, const unsigned char *surjectionproof, size_t surjectionproof_len); +WALLY_CORE_API int wally_psbt_set_output_rangeproof(struct wally_psbt *psbt, size_t index, const unsigned char *proof, size_t proof_len); +WALLY_CORE_API int wally_psbt_set_output_surjectionproof(struct wally_psbt *psbt, size_t index, const unsigned char *proof, size_t proof_len); #endif /* BUILD_ELEMENTS */ #ifdef __cplusplus diff --git a/src/script.c b/src/script.c index 10eb20ee2..fe2494909 100644 --- a/src/script.c +++ b/src/script.c @@ -885,28 +885,28 @@ int wally_witness_program_from_bytes(const unsigned char *bytes, size_t bytes_le return ret; } -int wally_elements_pegout_script_size(size_t parent_genesis_blockhash_len, +int wally_elements_pegout_script_size(size_t genesis_blockhash_len, size_t mainchain_script_len, size_t sub_pubkey_len, - size_t whitelist_proof_len, + size_t whitelistproof_len, size_t *written) { *written = 1 - + parent_genesis_blockhash_len + calc_push_opcode_size(parent_genesis_blockhash_len) + + genesis_blockhash_len + calc_push_opcode_size(genesis_blockhash_len) + mainchain_script_len + calc_push_opcode_size(mainchain_script_len) + sub_pubkey_len + calc_push_opcode_size(sub_pubkey_len) - + whitelist_proof_len + calc_push_opcode_size(whitelist_proof_len); + + whitelistproof_len + calc_push_opcode_size(whitelistproof_len); return WALLY_OK; } -int wally_elements_pegout_script_from_bytes(const unsigned char *parent_genesis_blockhash, - size_t parent_genesis_blockhash_len, +int wally_elements_pegout_script_from_bytes(const unsigned char *genesis_blockhash, + size_t genesis_blockhash_len, const unsigned char *mainchain_script, size_t mainchain_script_len, const unsigned char *sub_pubkey, size_t sub_pubkey_len, - const unsigned char *whitelist_proof, - size_t whitelist_proof_len, + const unsigned char *whitelistproof, + size_t whitelistproof_len, uint32_t flags, unsigned char *bytes_out, size_t len, @@ -928,19 +928,19 @@ int wally_elements_pegout_script_from_bytes(const unsigned char *parent_genesis_ if (written) *written = 0; - if (!parent_genesis_blockhash || parent_genesis_blockhash_len != 32 || + if (!genesis_blockhash || genesis_blockhash_len != SHA256_LEN || !mainchain_script || !mainchain_script_len || !sub_pubkey || sub_pubkey_len != EC_PUBLIC_KEY_LEN || - !whitelist_proof || !whitelist_proof_len || flags || !bytes_out || !len) + !whitelistproof || !whitelistproof_len || flags || !bytes_out || !len) return WALLY_EINVAL; *bytes_out = OP_RETURN; if (written) *written += bytes_written; - pegout_script_push(parent_genesis_blockhash, parent_genesis_blockhash_len); + pegout_script_push(genesis_blockhash, genesis_blockhash_len); pegout_script_push(mainchain_script, mainchain_script_len); pegout_script_push(sub_pubkey, sub_pubkey_len); - pegout_script_push(whitelist_proof, whitelist_proof_len); + pegout_script_push(whitelistproof, whitelistproof_len); return WALLY_OK; diff --git a/src/swig_java/swig.i b/src/swig_java/swig.i index 7d8ae5ee2..c29356f52 100644 --- a/src/swig_java/swig.i +++ b/src/swig_java/swig.i @@ -243,10 +243,10 @@ static jbyteArray create_array(JNIEnv *jenv, const unsigned char* p, size_t len) %apply(char *STRING, size_t LENGTH) { (const unsigned char *vbf, size_t vbf_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *witness, size_t witness_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *label, size_t label_len) }; -%apply(char *STRING, size_t LENGTH) { (const unsigned char *parent_genesis_blockhash, size_t parent_genesis_blockhash_len) }; +%apply(char *STRING, size_t LENGTH) { (const unsigned char *genesis_blockhash, size_t genesis_blockhash_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *mainchain_script, size_t mainchain_script_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *sub_pubkey, size_t sub_pubkey_len) }; -%apply(char *STRING, size_t LENGTH) { (const unsigned char *whitelist_proof, size_t whitelist_proof_len) }; +%apply(char *STRING, size_t LENGTH) { (const unsigned char *whitelistproof, size_t whitelistproof_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *online_keys, size_t online_keys_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *offline_keys, size_t offline_keys_len) }; %apply(char *STRING, size_t LENGTH) { (const unsigned char *online_priv_key, size_t online_priv_key_len) }; diff --git a/src/swig_python/contrib/psbt.py b/src/swig_python/contrib/psbt.py index a3e8c75ae..609fa96be 100644 --- a/src/swig_python/contrib/psbt.py +++ b/src/swig_python/contrib/psbt.py @@ -50,6 +50,7 @@ def test_psbt(self): dummy_nonce = bytearray(b'\x00' * WALLY_TX_ASSET_CT_NONCE_LEN) dummy_bf = bytearray(b'\x00' * BLINDING_FACTOR_LEN) dummy_commitment = bytearray(b'\x00' * ASSET_COMMITMENT_LEN) + dummy_asset = bytearray(b'\x00' * ASSET_TAG_LEN) dummy_keypaths = keypath_map_init(0) self.assertIsNotNone(dummy_keypaths) @@ -79,6 +80,20 @@ def test_psbt(self): self._try_set(psbt_set_input_redeem_script, psbt, dummy_bytes) self._try_set(psbt_set_input_witness_script, psbt, dummy_bytes) self._try_set(psbt_set_input_final_script_sig, psbt, dummy_bytes) + if is_elements_build(): + self._try_set(psbt_set_input_value, psbt, 1234567, 0) + psbt_clear_input_value(psbt, 0) + with self.assertRaises(ValueError): + psbt_clear_input_value(None, 0) # Null PSBT + with self.assertRaises(ValueError): + psbt_clear_input_value(psbt, 1) # Invalid index + self._try_set(psbt_set_input_vbf, psbt, dummy_bf) + self._try_set(psbt_set_input_asset, psbt, dummy_asset) + self._try_set(psbt_set_input_abf, psbt, dummy_bf) + self._try_set(psbt_set_input_peg_in_tx, psbt, dummy_tx) + self._try_set(psbt_set_input_txoutproof, psbt, dummy_bytes) + self._try_set(psbt_set_input_genesis_blockhash, psbt, dummy_bytes) + self._try_set(psbt_set_input_claim_script, psbt, dummy_bytes) # # Outputs diff --git a/src/swig_python/swig.i b/src/swig_python/swig.i index 093725a4e..a3f5757e0 100644 --- a/src/swig_python/swig.i +++ b/src/swig_python/swig.i @@ -209,7 +209,7 @@ static void destroy_words(PyObject *obj) { (void)obj; } %pybuffer_nonnull_binary(const unsigned char *pass, size_t pass_len); %pybuffer_nullable_binary(const unsigned char *parent160, size_t parent160_len); %pybuffer_nullable_binary(const unsigned char *priv_key, size_t priv_key_len); -%pybuffer_nonnull_binary(const unsigned char *proof, size_t proof_len); +%pybuffer_nullable_binary(const unsigned char *proof, size_t proof_len); %pybuffer_nullable_binary(const unsigned char *pub_key, size_t pub_key_len); %pybuffer_nonnull_binary(const unsigned char *salt, size_t salt_len); %pybuffer_nullable_binary(const unsigned char *script, size_t script_len); @@ -239,9 +239,9 @@ static void destroy_words(PyObject *obj) { (void)obj; } %pybuffer_nonnull_binary(const unsigned char *sub_pubkey, size_t sub_pubkey_len); %pybuffer_nonnull_binary(const unsigned char *online_priv_key, size_t online_priv_key_len); %pybuffer_nonnull_binary(const unsigned char *summed_key, size_t summed_key_len); -%pybuffer_nonnull_binary(const unsigned char *parent_genesis_blockhash, size_t parent_genesis_blockhash_len); +%pybuffer_nullable_binary(const unsigned char *genesis_blockhash, size_t genesis_blockhash_len); %pybuffer_nonnull_binary(const unsigned char *mainchain_script, size_t mainchain_script_len); -%pybuffer_nonnull_binary(const unsigned char *whitelist_proof, size_t whitelist_proof_len); +%pybuffer_nonnull_binary(const unsigned char *whitelistproof, size_t whitelistproof_len); %pybuffer_nullable_binary(const unsigned char *redeem_script, size_t redeem_script_len); %pybuffer_nullable_binary(const unsigned char *witness_script, size_t witness_script_len); %pybuffer_nullable_binary(const unsigned char *final_script_sig, size_t final_script_sig_len); diff --git a/src/test/util.py b/src/test/util.py index 4e215bfbd..2dbefc4ee 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -170,10 +170,10 @@ class wally_psbt_input(Structure): ('abf', c_void_p), ('abf_len', c_ulong), ('peg_in_tx', POINTER(wally_tx)), - ('txout_proof', c_void_p), - ('txout_proof_len', c_ulong), - ('genesis_hash', c_void_p), - ('genesis_hash_len', c_ulong), + ('txoutproof', c_void_p), + ('txoutproof_len', c_ulong), + ('genesis_blockhash', c_void_p), + ('genesis_blockhash_len', c_ulong), ('claim_script', c_void_p), ('claim_script_len', c_ulong)] @@ -324,9 +324,9 @@ class wally_psbt(Structure): ('wally_psbt_input_set_abf', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_asset', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_claim_script', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), - ('wally_psbt_input_set_genesis_hash', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_genesis_blockhash', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_peg_in_tx', c_int, [POINTER(wally_psbt_input), POINTER(wally_tx)]), - ('wally_psbt_input_set_txout_proof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), + ('wally_psbt_input_set_txoutproof', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_vbf', c_int, [POINTER(wally_psbt_input), c_void_p, c_ulong]), ('wally_psbt_input_set_value', c_int, [POINTER(wally_psbt_input), c_uint64]), ('wally_psbt_output_set_abf', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), From b396b852844f519f7988028d61aaa498e9acfeac Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 24 Jul 2020 01:41:43 +1200 Subject: [PATCH 204/205] psbt: Allow the caller to control sig grinding when signing Note the definition of EC_FLAGS_ALL uses the hex values as the JS bindings require this to compile. --- include/wally.hpp | 6 +++++- include/wally_crypto.h | 2 ++ include/wally_psbt.h | 4 +++- src/psbt.c | 8 +++++--- src/sign.c | 1 - src/test/test_psbt.py | 6 ++++-- src/test/util.py | 2 +- 7 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/wally.hpp b/include/wally.hpp index 66511fb54..006373c3e 100644 --- a/include/wally.hpp +++ b/include/wally.hpp @@ -290,6 +290,10 @@ template <> inline auto get_p(const std::nullptr_t& p) { return ::N(WALLYP(p1), WALLYB(i1)); \ } +#define WALLY_FN_PB3(F, N) template inline int F(const P1 &p1, const I1 &i1, uint32_t i321) { \ + return ::N(WALLYP(p1), WALLYB(i1), i321); \ +} + #define WALLY_FN_PBB(F, N) template \ inline int F(const P1 &p1, const I1 &i1, const I2 &i2) { return ::N(WALLYP(p1), WALLYB(i1), WALLYB(i2)); } @@ -564,8 +568,8 @@ WALLY_FN_PB(psbt_input_set_redeem_script, wally_psbt_input_set_redeem_script) WALLY_FN_PB(psbt_input_set_witness_script, wally_psbt_input_set_witness_script) WALLY_FN_PB(psbt_output_set_redeem_script, wally_psbt_output_set_redeem_script) WALLY_FN_PB(psbt_output_set_witness_script, wally_psbt_output_set_witness_script) -WALLY_FN_PB(psbt_sign, wally_psbt_sign) WALLY_FN_PB(tx_witness_stack_add, wally_tx_witness_stack_add) +WALLY_FN_PB3(psbt_sign, wally_psbt_sign) WALLY_FN_PB33BP3(tx_add_raw_input, wally_tx_add_raw_input) WALLY_FN_PB3_A(bip32_key_from_parent_path_alloc, bip32_key_from_parent_path_alloc) WALLY_FN_PB3_B(bip38_to_private_key, bip38_to_private_key) diff --git a/include/wally_crypto.h b/include/wally_crypto.h index 8b71e3e5c..cca9c1b72 100644 --- a/include/wally_crypto.h +++ b/include/wally_crypto.h @@ -293,6 +293,8 @@ WALLY_CORE_API int wally_pbkdf2_hmac_sha512( /** Indicates that the signature is recoverable */ #define EC_FLAG_RECOVERABLE 0x8 +/* All defined flags */ +#define EC_FLAGS_ALL (0x1 | 0x2 | 0x4 | 0x8) /** * Verify that a private key is valid. diff --git a/include/wally_psbt.h b/include/wally_psbt.h index bfba52e2d..176725a2b 100644 --- a/include/wally_psbt.h +++ b/include/wally_psbt.h @@ -613,6 +613,7 @@ WALLY_CORE_API int wally_psbt_combine( * :param psbt: PSBT to sign. Directly modifies this PSBT. * :param key: Private key to sign PSBT with. * :param key_len: Length of key in bytes. Must be ``EC_PRIVATE_KEY_LEN``. + * :param flags: Flags controlling sigining. Must be 0 or EC_FLAG_GRIND_R. * * .. note:: See https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki#simple-signer-algorithm *| for a description of the simple signer algorithm. @@ -620,7 +621,8 @@ WALLY_CORE_API int wally_psbt_combine( WALLY_CORE_API int wally_psbt_sign( struct wally_psbt *psbt, const unsigned char *key, - size_t key_len); + size_t key_len, + uint32_t flags); /** * Finalize a PSBT. diff --git a/src/psbt.c b/src/psbt.c index 1b3e979b6..e9d0fb6ee 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2318,7 +2318,7 @@ int wally_psbt_combine(struct wally_psbt *psbt, const struct wally_psbt *src) } int wally_psbt_sign(struct wally_psbt *psbt, - const unsigned char *key, size_t key_len) + const unsigned char *key, size_t key_len, uint32_t flags) { unsigned char pubkey[EC_PUBLIC_KEY_LEN], full_pubkey[EC_PUBLIC_KEY_UNCOMPRESSED_LEN]; unsigned char sig[EC_SIGNATURE_LEN], der_sig[EC_SIGNATURE_DER_MAX_LEN + 1]; @@ -2326,7 +2326,8 @@ int wally_psbt_sign(struct wally_psbt *psbt, size_t i, der_sig_len, is_elements; int ret; - if (!psbt || !psbt->tx || !key || key_len != EC_PRIVATE_KEY_LEN) { + if (!psbt || !psbt->tx || !key || key_len != EC_PRIVATE_KEY_LEN || + (flags & ~EC_FLAGS_ALL)) { return WALLY_EINVAL; } @@ -2471,7 +2472,8 @@ int wally_psbt_sign(struct wally_psbt *psbt, } /* Sign the sighash */ - if ((ret = wally_ec_sig_from_bytes(key, key_len, sighash, SHA256_LEN, EC_FLAG_ECDSA | EC_FLAG_GRIND_R, sig, EC_SIGNATURE_LEN)) != WALLY_OK) { + flags = flags & EC_FLAG_GRIND_R; /* Only grinding flag is relevant */ + if ((ret = wally_ec_sig_from_bytes(key, key_len, sighash, SHA256_LEN, EC_FLAG_ECDSA | flags, sig, EC_SIGNATURE_LEN)) != WALLY_OK) { return ret; } if ((ret = wally_ec_sig_normalize(sig, EC_SIGNATURE_LEN, sig, EC_SIGNATURE_LEN)) != WALLY_OK) { diff --git a/src/sign.c b/src/sign.c index d397f1ef3..00ec61cbb 100644 --- a/src/sign.c +++ b/src/sign.c @@ -8,7 +8,6 @@ #include #define EC_FLAGS_TYPES (EC_FLAG_ECDSA | EC_FLAG_SCHNORR) -#define EC_FLAGS_ALL (EC_FLAG_ECDSA | EC_FLAG_SCHNORR | EC_FLAG_GRIND_R | EC_FLAG_RECOVERABLE) #define MSG_ALL_FLAGS (BITCOIN_MESSAGE_FLAG_HASH) diff --git a/src/test/test_psbt.py b/src/test/test_psbt.py index def925902..80fb5c679 100644 --- a/src/test/test_psbt.py +++ b/src/test/test_psbt.py @@ -3,6 +3,8 @@ import unittest from util import * +FLAG_GRIND_R = 0x4 + class PSBTTests(unittest.TestCase): def test_serialization(self): @@ -79,7 +81,7 @@ def test_serialization(self): for priv in signer['privkeys']: buf, buf_len = make_cbuffer('00'*32) self.assertEqual(WALLY_OK, wally_wif_to_bytes(priv.encode('utf-8'), 0xEF, 0, buf, buf_len)) - self.assertEqual(WALLY_OK, wally_psbt_sign(psbt, buf, buf_len)) + self.assertEqual(WALLY_OK, wally_psbt_sign(psbt, buf, buf_len, FLAG_GRIND_R)) ret, reser = wally_psbt_to_base64(psbt, 0) self.assertEqual(WALLY_OK, ret) @@ -94,7 +96,7 @@ def test_serialization(self): for priv in inval_signer['privkeys']: buf, buf_len = make_cbuffer('00'*32) self.assertEqual(WALLY_OK, wally_wif_to_bytes(priv.encode('utf-8'), 0xEF, 0, buf, buf_len)) - self.assertEqual(WALLY_EINVAL, wally_psbt_sign(psbt, buf, buf_len)) + self.assertEqual(WALLY_EINVAL, wally_psbt_sign(psbt, buf, buf_len, FLAG_GRIND_R)) for finalizer in finalizers: psbt = pointer(wally_psbt()) diff --git a/src/test/util.py b/src/test/util.py index 2dbefc4ee..1bd541f97 100755 --- a/src/test/util.py +++ b/src/test/util.py @@ -360,7 +360,7 @@ class wally_psbt(Structure): ('wally_psbt_output_set_unknowns', c_int, [POINTER(wally_psbt_output), POINTER(wally_unknowns_map)]), ('wally_psbt_output_set_witness_script', c_int, [POINTER(wally_psbt_output), c_void_p, c_ulong]), ('wally_psbt_set_global_tx', c_int, [POINTER(wally_psbt), POINTER(wally_tx)]), - ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong]), + ('wally_psbt_sign', c_int, [POINTER(wally_psbt), c_void_p, c_ulong, c_uint]), ('wally_psbt_to_base64', c_int, [POINTER(wally_psbt), c_uint, c_char_p_p]), ('wally_psbt_to_bytes', c_int, [POINTER(wally_psbt), c_uint, c_void_p, c_ulong, c_ulong_p]), ('wally_scriptpubkey_csv_2of2_then_1_from_bytes', c_int, [c_void_p, c_ulong, c_uint, c_uint, c_void_p, c_ulong, c_ulong_p]), From c9c45b68c5a18ca1b5bca41f3c3c8350a23b1bd8 Mon Sep 17 00:00:00 2001 From: Jon Griffiths Date: Fri, 24 Jul 2020 01:43:53 +1200 Subject: [PATCH 205/205] psbt: Don't normalise signatures after signing libsecp always produces low-s signatures so this isn't required. --- src/psbt.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/psbt.c b/src/psbt.c index e9d0fb6ee..092dc5ac0 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -2473,15 +2473,10 @@ int wally_psbt_sign(struct wally_psbt *psbt, /* Sign the sighash */ flags = flags & EC_FLAG_GRIND_R; /* Only grinding flag is relevant */ - if ((ret = wally_ec_sig_from_bytes(key, key_len, sighash, SHA256_LEN, EC_FLAG_ECDSA | flags, sig, EC_SIGNATURE_LEN)) != WALLY_OK) { + if ((ret = wally_ec_sig_from_bytes(key, key_len, sighash, SHA256_LEN, EC_FLAG_ECDSA | flags, sig, EC_SIGNATURE_LEN)) != WALLY_OK) return ret; - } - if ((ret = wally_ec_sig_normalize(sig, EC_SIGNATURE_LEN, sig, EC_SIGNATURE_LEN)) != WALLY_OK) { - return ret; - } - if ((ret = wally_ec_sig_to_der(sig, EC_SIGNATURE_LEN, der_sig, EC_SIGNATURE_DER_MAX_LEN, &der_sig_len)) != WALLY_OK) { + if ((ret = wally_ec_sig_to_der(sig, EC_SIGNATURE_LEN, der_sig, EC_SIGNATURE_DER_MAX_LEN, &der_sig_len)) != WALLY_OK) return ret; - } /* Add the sighash type to the end of the sig */ der_sig[der_sig_len] = (unsigned char)sighash_type;