diff --git a/include/wally_transaction.h b/include/wally_transaction.h index ae238db84..d0fff1fb6 100644 --- a/include/wally_transaction.h +++ b/include/wally_transaction.h @@ -772,6 +772,9 @@ WALLY_CORE_API int wally_tx_get_total_output_satoshi( /** * Get the hash of the preimage for signing a BTC transaction input. * + * Deprecated, this call will be removed in a future release. Please + * use ``wally_tx_get_input_signature_hash``. + * * :param tx: The transaction to generate the signature hash from. * :param index: The input index of the input being signed for. * :param script: The (unprefixed) scriptCode for the input being signed. @@ -798,6 +801,9 @@ WALLY_CORE_API int wally_tx_get_btc_signature_hash( /** * Get the hash of the preimage for signing a BTC taproot transaction input. * + * Deprecated, this call will be removed in a future release. Please + * use ``wally_tx_get_input_signature_hash``. + * * :param tx: The transaction to generate the signature hash from. * :param index: The input index of the input being signed for. * :param scripts: Map of input index to (unprefixed) scriptCodes for each input in ``tx``. @@ -834,6 +840,9 @@ WALLY_CORE_API int wally_tx_get_btc_taproot_signature_hash( /** * Get the hash of the preimage for signing a BTC transaction input. * + * Deprecated, this call will be removed in a future release. Please + * use ``wally_tx_get_input_signature_hash``. + * * :param tx: The transaction to generate the signature hash from. * :param index: The input index of the input being signed for. * :param script: The (unprefixed) scriptCode for the input being signed. @@ -1362,6 +1371,9 @@ WALLY_CORE_API int wally_tx_confidential_value_to_satoshi( /** * Get the hash of the preimage for signing an Elements transaction input. * + * Deprecated, this call will be removed in a future release. Please + * use ``wally_tx_get_input_signature_hash``. + * * :param tx: The transaction to generate the signature hash from. * :param index: The input index of the input being signed for. * :param script: The (unprefixed) scriptCode for the input being signed. diff --git a/src/psbt.c b/src/psbt.c index 4d3262ad0..9c6670229 100644 --- a/src/psbt.c +++ b/src/psbt.c @@ -4491,16 +4491,16 @@ int wally_psbt_get_input_signature_hash(struct wally_psbt *psbt, size_t index, uint32_t flags, unsigned char *bytes_out, size_t len) { + struct wally_map scripts, assets, values, *assets_p; const struct wally_psbt_input *inp = psbt_get_input(psbt, index); - const struct wally_tx_output *utxo = utxo_from_input(psbt, inp); size_t is_pset; - uint32_t sighash; + uint32_t sighash, sighash_type; const bool is_taproot = is_taproot_input(psbt, inp); /* FIXME: Determine segwitness in a smarter way (e.g. prevout script */ - const bool is_segwit = inp->witness_utxo != NULL; + const bool is_segwit = inp && inp->witness_utxo != NULL; int ret; - if (!tx || !inp || !utxo || flags) + if (!tx || !inp || flags) return WALLY_EINVAL; if ((ret = wally_psbt_is_elements(psbt, &is_pset)) != WALLY_OK) @@ -4509,6 +4509,7 @@ int wally_psbt_get_input_signature_hash(struct wally_psbt *psbt, size_t index, if (is_pset) return WALLY_EINVAL; /* Unsupported */ #endif + assets_p = is_pset ? &assets : NULL; sighash = inp->sighash; if (!sighash) @@ -4516,44 +4517,31 @@ int wally_psbt_get_input_signature_hash(struct wally_psbt *psbt, size_t index, else if (sighash & 0xffffff00) return WALLY_EINVAL; - if (is_taproot || is_segwit) { - struct wally_map scripts, assets, values; - struct wally_map *assets_p = is_pset ? &assets : NULL; - - if (is_taproot) { - /* FIXME: Support script path spends */ - script = NULL; - script_len = 0; - } - ret = get_signing_data(psbt, &scripts, assets_p, &values); - if (ret == WALLY_OK) - ret = wally_tx_get_input_signature_hash(tx, index, - &scripts, assets_p, &values, - script, script_len, - 0, WALLY_NO_CODESEPARATOR, NULL, 0, - psbt->genesis_blockhash, sizeof(psbt->genesis_blockhash), - sighash, - is_taproot ? WALLY_SIGTYPE_SW_V1 : WALLY_SIGTYPE_SW_V0, - psbt->signing_cache, bytes_out, len); - - wally_free(scripts.items); /* No need to clear the value pointers */ - wally_free(values.items); - if (assets_p) - wally_free(assets_p->items); - return ret; - } + if (is_taproot) { + /* FIXME: Support script path spends */ + script = NULL; + script_len = 0; + sighash_type = WALLY_SIGTYPE_SW_V1; + } else if (is_segwit) + sighash_type = WALLY_SIGTYPE_SW_V0; + else + sighash_type = WALLY_SIGTYPE_PRE_SW; -#ifdef BUILD_ELEMENTS - if (is_pset) - return wally_tx_get_elements_signature_hash(tx, index, - script, script_len, - utxo->value, utxo->value_len, - sighash, 0, bytes_out, - len); -#endif - return wally_tx_get_btc_signature_hash(tx, index, script, script_len, - utxo->satoshi, sighash, 0, - bytes_out, len); + ret = get_signing_data(psbt, &scripts, assets_p, &values); + if (ret == WALLY_OK) + ret = wally_tx_get_input_signature_hash(tx, index, + &scripts, assets_p, &values, + script, script_len, + 0, WALLY_NO_CODESEPARATOR, NULL, 0, + psbt->genesis_blockhash, sizeof(psbt->genesis_blockhash), + sighash, sighash_type, + psbt->signing_cache, bytes_out, len); + + wally_free(scripts.items); /* No need to clear the value pointers */ + wally_free(values.items); + if (assets_p) + wally_free(assets_p->items); + return ret; } int wally_psbt_sign_input_bip32(struct wally_psbt *psbt, diff --git a/src/transaction.c b/src/transaction.c index 4356bc274..d168a8a55 100644 --- a/src/transaction.c +++ b/src/transaction.c @@ -34,23 +34,6 @@ static const unsigned char DUMMY_SIG[EC_SIGNATURE_DER_MAX_LEN + 1]; /* +1 for si #define MAX_INVALID_SATOSHI ((uint64_t) -1) -/* Extra options when serializing for hashing */ -struct tx_serialize_opts -{ - uint32_t sighash; /* 8 bit sighash value for sig */ - uint32_t tx_sighash; /* 32 bit sighash value for tx */ - size_t index; /* index of input we are signing */ - const unsigned char *script; /* scriptPubkey spent by the input we are signing */ - size_t script_len; /* length of 'script' in bytes */ - uint64_t satoshi; /* Amount of the input we are signing */ - const unsigned char *value; /* Confidential value of the input we are signing */ - size_t value_len; /* length of 'value' in bytes */ -}; - -static const unsigned char EMPTY_OUTPUT[9] = { - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 -}; - #define WALLY_SATOSHI_MAX ((uint64_t)WALLY_BTC_MAX * WALLY_SATOSHI_PER_BTC) /* LCOV_EXCL_START */ @@ -1699,16 +1682,11 @@ static int get_txin_issuance_size(const struct wally_tx_input *input, * without iterating the transaction twice with different flags. */ static int tx_get_lengths(const struct wally_tx *tx, - const struct tx_serialize_opts *opts, uint32_t flags, + uint32_t flags, size_t *base_size, size_t *witness_size, size_t *witness_count, bool is_elements) { size_t n, i, j; - const unsigned char sighash = opts ? opts->sighash : 0; - const bool sh_anyonecanpay = sighash & WALLY_SIGHASH_ANYONECANPAY; - const bool sh_rangeproof = is_elements && (sighash & WALLY_SIGHASH_RANGEPROOF); - const bool sh_none = (sighash & WALLY_SIGHASH_MASK) == WALLY_SIGHASH_NONE; - const bool sh_single = (sighash & WALLY_SIGHASH_MASK) == WALLY_SIGHASH_SINGLE; *base_size = 0; *witness_size = 0; @@ -1717,11 +1695,6 @@ static int tx_get_lengths(const struct wally_tx *tx, if (!is_valid_tx(tx)) return WALLY_EINVAL; - if (opts) { - if (flags & WALLY_TX_FLAG_USE_WITNESS) - return WALLY_ERROR; /* Segwit tx hashing done elsewhere */ - } - if ((flags & ~WALLY_TX_ALL_FLAGS) || ((flags & WALLY_TX_FLAG_USE_WITNESS) && wally_tx_get_witness_count(tx, witness_count) != WALLY_OK)) @@ -1731,20 +1704,15 @@ static int tx_get_lengths(const struct wally_tx *tx, flags &= ~WALLY_TX_FLAG_USE_WITNESS; n = sizeof(tx->version) + - varint_get_length(sh_anyonecanpay ? 1 : tx->num_inputs) + - (sh_none ? 1 : varint_get_length(sh_single ? opts->index + 1 : tx->num_outputs)) + - sizeof(tx->locktime) + - (opts ? sizeof(leint32_t) : 0); /* Include trailing tx_sighash */ + varint_get_length(tx->num_inputs) + + varint_get_length(tx->num_outputs) + sizeof(tx->locktime); - if (!opts && is_elements) + if (is_elements) n += sizeof(uint8_t); /* witness flag */ for (i = 0; i < tx->num_inputs; ++i) { const struct wally_tx_input *input = tx->inputs + i; size_t issuance_size = 0; - if (sh_anyonecanpay && i != opts->index) - continue; /* sh_anyonecanpay only signs the given index */ - n += sizeof(input->txhash) + sizeof(input->index) + sizeof(input->sequence); @@ -1752,32 +1720,15 @@ static int tx_get_lengths(const struct wally_tx *tx, if (get_txin_issuance_size(input, &issuance_size, NULL) != WALLY_OK) return WALLY_EINVAL; n += issuance_size; - - if (opts) { - if (i == opts->index) - n += varbuff_get_length(opts->script_len); - else - ++n; - } else - n += varbuff_get_length(input->script_len); - + n += varbuff_get_length(input->script_len); } - if (!sh_none) { - size_t num_outputs = sh_single ? opts->index + 1 : tx->num_outputs; - - for (i = 0; i < num_outputs; ++i) { - const struct wally_tx_output *output = tx->outputs + i; - if (sh_single && i != opts->index) - n += sizeof(EMPTY_OUTPUT); - else { - size_t wit_size = 0, *wit_p = sh_rangeproof ? &wit_size : NULL; - size_t txout_len = txout_get_serialized_len(output, is_elements, wit_p); - if (!txout_len) - return WALLY_EINVAL; /* Error getting txout length */ - n += txout_len + wit_size; - } - } + for (i = 0; i < tx->num_outputs; ++i) { + const struct wally_tx_output *output = tx->outputs + i; + size_t txout_len = txout_get_serialized_len(output, is_elements, NULL); + if (!txout_len) + return WALLY_EINVAL; /* Error getting txout length */ + n += txout_len; } *base_size = n; @@ -1834,8 +1785,7 @@ static int tx_get_lengths(const struct wally_tx *tx, } static int tx_get_length(const struct wally_tx *tx, - const struct tx_serialize_opts *opts, uint32_t flags, - size_t *written, bool is_elements) + uint32_t flags, size_t *written, bool is_elements) { size_t base_size, witness_size, witness_count; int ret; @@ -1844,7 +1794,7 @@ static int tx_get_length(const struct wally_tx *tx, *written = 0; if (!written) return WALLY_EINVAL; - ret = tx_get_lengths(tx, opts, flags, &base_size, &witness_size, + ret = tx_get_lengths(tx, flags, &base_size, &witness_size, &witness_count, is_elements); if (ret == WALLY_OK) { if (witness_count && (flags & WALLY_TX_FLAG_USE_WITNESS)) @@ -1864,7 +1814,7 @@ int wally_tx_get_length(const struct wally_tx *tx, uint32_t flags, return WALLY_EINVAL; #endif - return tx_get_length(tx, NULL, flags, written, is_elements != 0); + return tx_get_length(tx, flags, written, is_elements != 0); } int wally_tx_get_weight(const struct wally_tx *tx, size_t *written) @@ -1881,7 +1831,7 @@ int wally_tx_get_weight(const struct wally_tx *tx, size_t *written) #endif if (!written || - tx_get_lengths(tx, NULL, WALLY_TX_FLAG_USE_WITNESS, &base_size, + tx_get_lengths(tx, WALLY_TX_FLAG_USE_WITNESS, &base_size, &witness_size, &witness_count, is_elements != 0) != WALLY_OK) return WALLY_EINVAL; @@ -2018,33 +1968,22 @@ int wally_tx_get_hash_prevouts(const struct wally_tx *tx, } static int tx_to_bytes(const struct wally_tx *tx, - const struct tx_serialize_opts *opts, uint32_t flags, unsigned char *bytes_out, size_t len, size_t *written, bool is_elements) { size_t n, i, j, witness_count; - const unsigned char sighash = opts ? opts->sighash : 0; - const bool sh_anyonecanpay = sighash & WALLY_SIGHASH_ANYONECANPAY; - const bool sh_rangeproof = sighash & WALLY_SIGHASH_RANGEPROOF; - const bool sh_none = (sighash & WALLY_SIGHASH_MASK) == WALLY_SIGHASH_NONE; - const bool sh_single = (sighash & WALLY_SIGHASH_MASK) == WALLY_SIGHASH_SINGLE; unsigned char *p = bytes_out; - (void)sh_rangeproof; - if (written) *written = 0; if (!is_valid_tx(tx) || (flags & ~WALLY_TX_ALL_FLAGS) || !bytes_out || !written || - tx_get_length(tx, opts, flags, &n, is_elements) != WALLY_OK) + tx_get_length(tx, flags, &n, is_elements) != WALLY_OK) return WALLY_EINVAL; - if (opts && (flags & WALLY_TX_FLAG_USE_WITNESS)) - return WALLY_ERROR; /* Segwit tx hashing is handled elsewhere */ - if (!(flags & WALLY_TX_FLAG_ALLOW_PARTIAL)) { /* 0-input/output txs can be only be written with this flag */ if (!tx->num_inputs || !tx->num_outputs) @@ -2075,44 +2014,28 @@ static int tx_to_bytes(const struct wally_tx *tx, p += uint32_to_le_bytes(tx->version, p); if (is_elements) { - if (!opts) - *p++ = flags & WALLY_TX_FLAG_USE_WITNESS ? 1 : 0; + *p++ = flags & WALLY_TX_FLAG_USE_WITNESS ? 1 : 0; } else { if (flags & WALLY_TX_FLAG_USE_WITNESS) { *p++ = 0; /* Write BIP 144 marker */ *p++ = 1; /* Write BIP 144 flag */ } } - if (sh_anyonecanpay) - *p++ = 1; - else - p += varint_to_bytes(tx->num_inputs, p); + + p += varint_to_bytes(tx->num_inputs, p); for (i = 0; i < tx->num_inputs; ++i) { const struct wally_tx_input *input = tx->inputs + i; - if (sh_anyonecanpay && i != opts->index) - continue; /* sh_anyonecanpay only signs the given index */ - memcpy(p, input->txhash, sizeof(input->txhash)); p += sizeof(input->txhash); - if (!opts && (input->features & WALLY_TX_IS_ISSUANCE)) + if (input->features & WALLY_TX_IS_ISSUANCE) p += uint32_to_le_bytes(input->index | WALLY_TX_ISSUANCE_FLAG, p); - else if (!opts && (input->features & WALLY_TX_IS_PEGIN)) + else if (input->features & WALLY_TX_IS_PEGIN) p += uint32_to_le_bytes(input->index | WALLY_TX_PEGIN_FLAG, p); else p += uint32_to_le_bytes(input->index, p); - if (opts) { - if (i == opts->index) - p += varbuff_to_bytes(opts->script, opts->script_len, p); - else - *p++ = 0; /* Blank scripts for non-signing inputs */ - } else - p += varbuff_to_bytes(input->script, input->script_len, p); - - if ((sh_none || sh_single) && i != opts->index) - p += uint32_to_le_bytes(0, p); - else - p += uint32_to_le_bytes(input->sequence, p); + p += varbuff_to_bytes(input->script, input->script_len, p); + p += uint32_to_le_bytes(input->sequence, p); if (input->features & WALLY_TX_IS_ISSUANCE) { if (!is_elements) return WALLY_EINVAL; @@ -2127,41 +2050,22 @@ static int tx_to_bytes(const struct wally_tx *tx, } } - if (sh_none) - *p++ = 0; - else { - size_t num_outputs = sh_single ? opts->index + 1 : tx->num_outputs; - p += varint_to_bytes(num_outputs, p); - - for (i = 0; i < num_outputs; ++i) { - const struct wally_tx_output *output = tx->outputs + i; - if (sh_single && i != opts->index) { - memcpy(p, EMPTY_OUTPUT, sizeof(EMPTY_OUTPUT)); - p += sizeof(EMPTY_OUTPUT); - } else { - if (output->features & WALLY_TX_IS_ELEMENTS) { - if (!is_elements) - return WALLY_EINVAL; -#ifdef BUILD_ELEMENTS - p += confidential_value_to_bytes(output->asset, output->asset_len, p); - p += confidential_value_to_bytes(output->value, output->value_len, p); - p += confidential_value_to_bytes(output->nonce, output->nonce_len, p); -#endif - } else { - p += uint64_to_le_bytes(output->satoshi, p); - } - p += varbuff_to_bytes(output->script, output->script_len, p); + p += varint_to_bytes(tx->num_outputs, p); + for (i = 0; i < tx->num_outputs; ++i) { + const struct wally_tx_output *output = tx->outputs + i; + if (output->features & WALLY_TX_IS_ELEMENTS) { + if (!is_elements) + return WALLY_EINVAL; #ifdef BUILD_ELEMENTS - if (is_elements && sh_rangeproof) { - p += varbuff_to_bytes(output->rangeproof, - output->rangeproof_len, p); - p += varbuff_to_bytes(output->surjectionproof, - output->surjectionproof_len, p); - } + p += confidential_value_to_bytes(output->asset, output->asset_len, p); + p += confidential_value_to_bytes(output->value, output->value_len, p); + p += confidential_value_to_bytes(output->nonce, output->nonce_len, p); #endif - } + } else { + p += uint64_to_le_bytes(output->satoshi, p); } + p += varbuff_to_bytes(output->script, output->script_len, p); } if (!is_elements && (flags & WALLY_TX_FLAG_USE_WITNESS)) { @@ -2178,8 +2082,6 @@ static int tx_to_bytes(const struct wally_tx *tx, } p += uint32_to_le_bytes(tx->locktime, p); - if (opts) - uint32_to_le_bytes(opts->tx_sighash, p); #ifdef BUILD_ELEMENTS if (is_elements && (flags & WALLY_TX_FLAG_USE_WITNESS)) { @@ -2224,7 +2126,7 @@ int wally_tx_to_bytes(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_bytes(tx, NULL, flags, bytes_out, len, written, is_elements); + return tx_to_bytes(tx, flags, bytes_out, len, written, is_elements); } /* Common implementation for hex conversion and txid calculation */ @@ -2244,12 +2146,12 @@ static int tx_to_hex_or_txid(const struct wally_tx *tx, uint32_t flags, (!output && (!bytes_out || len != WALLY_TXHASH_LEN))) return WALLY_EINVAL; - ret = tx_to_bytes(tx, NULL, flags, buff_p, sizeof(buff), &n, is_elements); + ret = tx_to_bytes(tx, flags, buff_p, sizeof(buff), &n, is_elements); if (ret == WALLY_OK) { if (n > sizeof(buff)) { if ((buff_p = wally_malloc(n)) == NULL) return WALLY_ENOMEM; - ret = tx_to_bytes(tx, NULL, flags, buff_p, n, &written, is_elements); + ret = tx_to_bytes(tx, flags, buff_p, n, &written, is_elements); if (n != written) ret = WALLY_ERROR; /* Length calculated incorrectly */ } @@ -2732,79 +2634,41 @@ static int tx_get_signature_hash(const struct wally_tx *tx, uint32_t sighash, uint32_t tx_sighash, uint32_t flags, unsigned char *bytes_out, size_t len) { + struct wally_map_item value_item; + struct wally_map values = { &value_item, 1, 1, NULL }; size_t is_elements = 0; + uint32_t sighash_type = WALLY_SIGTYPE_PRE_SW; #ifdef BUILD_ELEMENTS if (wally_tx_is_elements(tx, &is_elements) != WALLY_OK) return WALLY_EINVAL; #endif + if (flags & ~WALLY_TX_ALL_FLAGS) + return WALLY_EINVAL; + if (sighash != tx_sighash) + return WALLY_EINVAL; /* Nonstandard tx sighash flags aren't supported */ if (extra || extra_len || extra_offset) return WALLY_ERROR; /* Not implemented, not planned */ - if (flags & WALLY_TX_FLAG_USE_WITNESS) { - struct wally_map_item value_item; - struct wally_map values = { &value_item, 1, 1, NULL }; - values.items[0].key = NULL; - values.items[0].key_len = index; - if (is_elements) { - value_item.value = (unsigned char*)value; - value_item.value_len = value_len; - } else { - value_item.value = (unsigned char*)&satoshi; - value_item.value_len = sizeof(uint64_t); - } - return wally_tx_get_input_signature_hash(tx, index, NULL, NULL, - &values, script, script_len, - 0, WALLY_NO_CODESEPARATOR, - NULL, 0, NULL, 0, - sighash, WALLY_SIGTYPE_SW_V0, - NULL, bytes_out, len); - } else { - unsigned char buff[TX_STACK_SIZE], *buff_p = buff; - size_t n, n2; - int ret; - const struct tx_serialize_opts opts = { - sighash, tx_sighash, index, script, script_len, satoshi, - value, value_len - }; - - if (!is_valid_tx(tx) || BYTES_INVALID(script, script_len) || - BYTES_INVALID(extra, extra_len) || - satoshi > WALLY_SATOSHI_MAX || (sighash & 0xffffff00) || - (flags & ~WALLY_TX_ALL_FLAGS) || !bytes_out || len < SHA256_LEN) - return WALLY_EINVAL; - - if (index >= tx->num_inputs || - (index >= tx->num_outputs && (sighash & WALLY_SIGHASH_MASK) == WALLY_SIGHASH_SINGLE)) { - memset(bytes_out, 0, SHA256_LEN); - bytes_out[0] = 0x1; - return WALLY_OK; - } + if (flags & WALLY_TX_FLAG_USE_WITNESS) + sighash_type = WALLY_SIGTYPE_SW_V0; - if ((ret = tx_get_length(tx, &opts, 0, &n, is_elements != 0)) != WALLY_OK) - goto fail; - - if (n > sizeof(buff) && (buff_p = wally_malloc(n)) == NULL) { - ret = WALLY_ENOMEM; - goto fail; + values.items[0].key = NULL; + values.items[0].key_len = index; + if (is_elements) { + value_item.value = (unsigned char*)value; + value_item.value_len = value_len; + } else { + value_item.value = (unsigned char*)&satoshi; + value_item.value_len = sizeof(uint64_t); } - - if ((ret = tx_to_bytes(tx, &opts, 0, buff_p, n, &n2, is_elements != 0)) != WALLY_OK) - goto fail; - - if (n != n2) - ret = WALLY_ERROR; /* tx_get_length/tx_to_bytes mismatch, should not happen! */ - else - ret = wally_sha256d(buff_p, n2, bytes_out, len); - -fail: - if (buff_p != buff) - clear_and_free(buff_p, n); - else - wally_clear(buff, sizeof(buff)); - return ret; -} + return wally_tx_get_input_signature_hash(tx, index, NULL, NULL, + &values, script, script_len, + 0, WALLY_NO_CODESEPARATOR, + NULL, 0, NULL, 0, + sighash, sighash_type, + NULL, bytes_out, len); } int wally_tx_get_signature_hash(const struct wally_tx *tx, @@ -2825,9 +2689,9 @@ int wally_tx_get_btc_signature_hash(const struct wally_tx *tx, size_t index, uint64_t satoshi, uint32_t sighash, uint32_t flags, unsigned char *bytes_out, size_t len) { - return wally_tx_get_signature_hash(tx, index, script, script_len, - NULL, 0, 0, satoshi, sighash, sighash, - flags, bytes_out, len); + return tx_get_signature_hash(tx, index, script, script_len, + NULL, 0, 0, satoshi, + NULL, 0, sighash, sighash, flags, bytes_out, len); } int wally_tx_get_btc_taproot_signature_hash( diff --git a/src/tx_io.c b/src/tx_io.c index b4eb4db71..374d8e6bd 100644 --- a/src/tx_io.c +++ b/src/tx_io.c @@ -38,6 +38,9 @@ /* ... end of segwit cached data */ static const unsigned char zero_hash[SHA256_LEN]; +static const unsigned char EMPTY_PRE_SW_OUTPUT[9] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00 +}; /* SHA256(TapSighash) */ static const unsigned char TAPSIGHASH_SHA256[SHA256_LEN] = { @@ -147,13 +150,19 @@ static inline void hash_bytes(struct sha256_ctx *ctx, sha256_update(ctx, bytes, bytes_len); } +static void hash_varint(struct sha256_ctx *ctx, + uint64_t v) +{ + unsigned char buff[9]; + size_t n = varint_to_bytes(v, buff); + hash_bytes(ctx, buff, n); +} + static void hash_varbuff(struct sha256_ctx *ctx, const unsigned char *bytes, size_t bytes_len) { - unsigned char varbuff_len[9]; - size_t n = varint_to_bytes(bytes_len, varbuff_len); - sha256_update(ctx, varbuff_len, n); - sha256_update(ctx, bytes, bytes_len); + hash_varint(ctx, bytes_len); + hash_bytes(ctx, bytes, bytes_len); } static void hash_map_varbuff(struct sha256_ctx *ctx, @@ -230,6 +239,15 @@ static void hash_map_commmitment(struct sha256_ctx *ctx, hash_commmitment(ctx, item->value, item->value_len); } +static void hash_asset_issuance(struct sha256_ctx *ctx, + const struct wally_tx_input *txin) +{ + hash_bytes(ctx, txin->blinding_nonce, sizeof(txin->blinding_nonce)); + hash_bytes(ctx, txin->entropy, sizeof(txin->entropy)); + hash_commmitment(ctx, txin->issuance_amount, txin->issuance_amount_len); + hash_commmitment(ctx, txin->inflation_keys, txin->inflation_keys_len); +} + static void hash_issuance_rangeproofs(struct sha256_ctx *ctx, const struct wally_tx_input *txin) { @@ -303,14 +321,10 @@ static void txio_hash_sha_issuances(cursor_io *io, const struct wally_tx *tx, ui sha256_init(&ctx); for (size_t i = 0; i < tx->num_inputs; ++i) { const struct wally_tx_input *txin = tx->inputs + i; - if (!(txin->features & WALLY_TX_IS_ISSUANCE)) { + if (txin->features & WALLY_TX_IS_ISSUANCE) + hash_asset_issuance(&ctx, txin); + else hash_u8(&ctx, 0); - continue; - } - hash_bytes(&ctx, txin->blinding_nonce, sizeof(txin->blinding_nonce)); - hash_bytes(&ctx, txin->entropy, sizeof(txin->entropy)); - hash_commmitment(&ctx, txin->issuance_amount, txin->issuance_amount_len); - hash_commmitment(&ctx, txin->inflation_keys, txin->inflation_keys_len); } txio_hash_sha256_ctx(io, &ctx, key); } @@ -384,11 +398,7 @@ static void txio_hash_input_elements(cursor_io *io, if (hash_type != WALLY_SIGTYPE_SW_V0) hash_u8(&io->ctx, 0); } else { - /* asset_issuance */ - hash_bytes(&io->ctx, txin->blinding_nonce, sizeof(txin->blinding_nonce)); - hash_bytes(&io->ctx, txin->entropy, sizeof(txin->entropy)); - hash_commmitment(&io->ctx, txin->issuance_amount, txin->issuance_amount_len); - hash_commmitment(&io->ctx, txin->inflation_keys, txin->inflation_keys_len); + hash_asset_issuance(&io->ctx, txin); if (hash_type != WALLY_SIGTYPE_SW_V0) { /* sha_single_issuance_rangeproofs */ struct sha256_ctx ctx; @@ -420,16 +430,28 @@ static void txio_hash_sha_single_output_witness(cursor_io *io, } #endif /* BUILD_ELEMENTS */ +static void hash_output(struct sha256_ctx *ctx, + const struct wally_tx_output *txout) +{ + hash_le64(ctx, txout->satoshi); + hash_varbuff(ctx, txout->script, txout->script_len); +} + +static void hash_outpoint(struct sha256_ctx *ctx, + const struct wally_tx_input *txin) +{ + hash_bytes(ctx, txin->txhash, sizeof(txin->txhash)); + hash_le32(ctx, txin->index); +} + static void txio_hash_sha_prevouts(cursor_io *io, const struct wally_tx *tx, uint32_t key) { if (!txio_hash_cached_item(io, key)) { struct sha256_ctx ctx; sha256_init(&ctx); - for (size_t i = 0; i < tx->num_inputs; ++i) { - hash_bytes(&ctx, tx->inputs[i].txhash, WALLY_TXHASH_LEN); - hash_le32(&ctx, tx->inputs[i].index); - } + for (size_t i = 0; i < tx->num_inputs; ++i) + hash_outpoint(&ctx, tx->inputs + i); txio_hash_sha256_ctx(io, &ctx, key); } } @@ -474,20 +496,12 @@ static void txio_hash_sha_outputs(cursor_io *io, const struct wally_tx *tx, if (!txio_hash_cached_item(io, key)) { struct sha256_ctx ctx; sha256_init(&ctx); - for (size_t i = 0; i < tx->num_outputs; ++i) { - hash_le64(&ctx, tx->outputs[i].satoshi); - hash_varbuff(&ctx, tx->outputs[i].script, tx->outputs[i].script_len); - } + for (size_t i = 0; i < tx->num_outputs; ++i) + hash_output(&ctx, tx->outputs + i); txio_hash_sha256_ctx(io, &ctx, key); } } -static void txio_hash_outpoint(cursor_io *io, const struct wally_tx_input *txin) -{ - hash_bytes(&io->ctx, txin->txhash, sizeof(txin->txhash)); - hash_le32(&io->ctx, txin->index); -} - static void txio_hash_input(cursor_io *io, const struct wally_tx *tx, size_t index, const struct wally_map *scripts, @@ -512,8 +526,7 @@ static void txio_hash_sha_single_output(cursor_io *io, { struct sha256_ctx ctx; sha256_init(&ctx); - hash_le64(&ctx, txout->satoshi); - hash_varbuff(&ctx, txout->script, txout->script_len); + hash_output(&ctx, txout); txio_hash_sha256_ctx(io, &ctx, key); } @@ -557,6 +570,92 @@ static void txio_hash_tapleaf_hash(cursor_io *io, } } +/* Pre-segwit */ +static int legacy_signature_hash( + const struct wally_tx *tx, size_t index, + const struct wally_map *values, + const unsigned char *script, size_t script_len, + uint32_t sighash, + struct wally_map *cache, + bool is_elements, + unsigned char *bytes_out, size_t len) +{ + const bool sh_anyonecanpay = sighash & WALLY_SIGHASH_ANYONECANPAY; + const bool sh_none = (sighash & WALLY_SIGHASH_MASK) == WALLY_SIGHASH_NONE; + const bool sh_single = (sighash & WALLY_SIGHASH_MASK) == WALLY_SIGHASH_SINGLE; + cursor_io io; + + /* Note that script can be empty, so we don't check it here */ + if (!tx || !values || BYTES_INVALID(script, script_len) || + !bytes_out || len != SHA256_LEN) + return WALLY_EINVAL; + + if (index >= tx->num_inputs || (sh_single && index >= tx->num_outputs)) { + memset(bytes_out, 0, SHA256_LEN); + bytes_out[0] = 0x1; + return WALLY_OK; + } + + /* Init */ + io.cache = cache; + io.cursor = bytes_out; + io.max = len; + sha256_init(&io.ctx); + /* Tx data */ + hash_le32(&io.ctx, tx->version); + /* Input data */ + hash_varint(&io.ctx, sh_anyonecanpay ? 1 : tx->num_inputs); + for (size_t i = 0; i < tx->num_inputs; ++i) { + const struct wally_tx_input *txin = tx->inputs + i; + if (sh_anyonecanpay && i != index) + continue; /* sh_anyonecanpay only signs the given index */ + + hash_outpoint(&io.ctx, txin); + if (i == index) + hash_varbuff(&io.ctx, script, script_len); + else + hash_u8(&io.ctx, 0); /* Blank scripts for non-signing inputs */ + + if ((sh_none || sh_single) && i != index) + hash_le32(&io.ctx, 0); + else + hash_le32(&io.ctx, txin->sequence); +#ifdef BUILD_ELEMENTS + if (is_elements && txin->features & WALLY_TX_IS_ISSUANCE) + hash_asset_issuance(&io.ctx, txin); +#endif + } + + /* Output data */ + if (sh_none) + hash_u8(&io.ctx, 0); + else { + size_t num_outputs = sh_single ? index + 1 : tx->num_outputs; + hash_varint(&io.ctx, num_outputs); + + for (size_t i = 0; i < num_outputs; ++i) { + const struct wally_tx_output *txout = tx->outputs + i; + if (sh_single && i != index) + hash_bytes(&io.ctx, + EMPTY_PRE_SW_OUTPUT, sizeof(EMPTY_PRE_SW_OUTPUT)); + else { +#ifdef BUILD_ELEMENTS + if (is_elements) { + hash_output_elements(&io.ctx, txout); + if (sighash & WALLY_SIGHASH_RANGEPROOF) + hash_output_witness(&io.ctx, txout, TXIO_UNCACHED_D); + } else +#endif + hash_output(&io.ctx, txout); + } + } + } + + hash_le32(&io.ctx, tx->locktime); + hash_le32(&io.ctx, sighash); + return txio_done(&io, TXIO_SHA256_D); +} + /* BIP 143 */ static int bip143_signature_hash( const struct wally_tx *tx, size_t index, @@ -613,7 +712,7 @@ static int bip143_signature_hash( } #endif /* Input data */ - txio_hash_outpoint(&io, txin); + hash_outpoint(&io.ctx, txin); #ifdef BUILD_ELEMENTS if (is_elements) txio_hash_input_elements(&io, tx, index, NULL, NULL, values, @@ -799,7 +898,7 @@ static int bip341_signature_hash( if (is_elements) txio_hash_outpoint_flag(&io, txin); #endif - txio_hash_outpoint(&io, txin); + hash_outpoint(&io.ctx, txin); } #ifdef BUILD_ELEMENTS if (is_elements) @@ -863,9 +962,11 @@ int wally_tx_get_input_signature_hash( !flags || (flags & ~SIGTYPE_ALL) || !bytes_out || len != SHA256_LEN) return WALLY_EINVAL; -#ifdef BUILD_ELEMENTS if ((ret = wally_tx_is_elements(tx, &is_elements)) != WALLY_OK) return ret; +#ifndef BUILD_ELEMENTS + if (is_elements) + return WALLY_EINVAL; #endif switch (sighash) { @@ -902,7 +1003,10 @@ int wally_tx_get_input_signature_hash( return WALLY_EINVAL; /* Unknown sighash type */ } - /* FIXME: Support pre-segwit hashing */ + if (sighash_type == WALLY_SIGTYPE_PRE_SW) + return legacy_signature_hash(tx, index, values, script, script_len, + sighash, cache, is_elements, + bytes_out, len); if (sighash_type == WALLY_SIGTYPE_SW_V0) return bip143_signature_hash(tx, index, values, script, script_len, sighash, cache, is_elements, @@ -915,5 +1019,5 @@ int wally_tx_get_input_signature_hash( genesis_blockhash, genesis_blockhash_len, sighash, cache, is_elements, bytes_out, len); - return ret; + return WALLY_EINVAL; /* Unknown sighash type */ }