mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-02-11 01:33:21 +01:00
44e006d438[kernel] Expose reusable PrecomputedTransactionData in script valid (Josh Doman) Pull request description: This PR exposes a reusable `PrecomputedTransactionData` object in script validation using libkernel. Currently, libkernel computes `PrecomputedTransactionData` each time `btck_script_pubkey_verify` is called, exposing clients to quadratic hashing when validating a transaction with multiple inputs. By externalizing `PrecomputedTransactionData` and making it reusable, libkernel can eliminate this attack vector. I discussed this problem in [this issue](https://github.com/TheCharlatan/rust-bitcoinkernel/issues/46). The design of this PR is inspired by @sedited's comments. The PR introduces three new APIs for managing the `btck_PrecomputedTransactionData` object: ```c /** * @brief Create precomputed transaction data for script verification. * * @param[in] tx_to Non-null. * @param[in] spent_outputs Nullable for non-taproot verification. Points to an array of * outputs spent by the transaction. * @param[in] spent_outputs_len Length of the spent_outputs array. * @return The precomputed data, or null on error. */ btck_PrecomputedTransactionData* btck_precomputed_transaction_data_create( const btck_Transaction* tx_to, const btck_TransactionOutput** spent_outputs, size_t spent_outputs_len) BITCOINKERNEL_ARG_NONNULL(1); /** * @brief Copy precomputed transaction data. * * @param[in] precomputed_txdata Non-null. * @return The copied precomputed transaction data. */ btck_PrecomputedTransactionData* btck_precomputed_transaction_data_copy( const btck_PrecomputedTransactionData* precomputed_txdata) BITCOINKERNEL_ARG_NONNULL(1); /** * Destroy the precomputed transaction data. */ void btck_precomputed_transaction_data_destroy(btck_PrecomputedTransactionData* precomputed_txdata); ``` The PR also modifies `btck_script_pubkey_verify` so that it accepts `precomputed_txdata` instead of `spent_outputs`: ```c /** * @brief Verify if the input at input_index of tx_to spends the script pubkey * under the constraints specified by flags. If the * `btck_ScriptVerificationFlags_WITNESS` flag is set in the flags bitfield, the * amount parameter is used. If the taproot flag is set, the precomputed data * must contain the spent outputs. * * @param[in] script_pubkey Non-null, script pubkey to be spent. * @param[in] amount Amount of the script pubkey's associated output. May be zero if * the witness flag is not set. * @param[in] tx_to Non-null, transaction spending the script_pubkey. * @param[in] precomputed_txdata Nullable if the taproot flag is not set. Otherwise, precomputed data * for tx_to with the spent outputs must be provided. * @param[in] input_index Index of the input in tx_to spending the script_pubkey. * @param[in] flags Bitfield of btck_ScriptVerificationFlags controlling validation constraints. * @param[out] status Nullable, will be set to an error code if the operation fails, or OK otherwise. * @return 1 if the script is valid, 0 otherwise. */ int btck_script_pubkey_verify( const btck_ScriptPubkey* script_pubkey, int64_t amount, const btck_Transaction* tx_to, const btck_PrecomputedTransactionData* precomputed_txdata, unsigned int input_index, btck_ScriptVerificationFlags flags, btck_ScriptVerifyStatus* status) BITCOINKERNEL_ARG_NONNULL(1, 3); ``` As before, an error is thrown if the taproot flag is set and `spent_outputs` is not provided in `precomputed_txdata` (or `precomputed_txdata` is null). For simple single-input non-taproot verification, `precomputed_txdata` may be null, and the kernel will construct the precomputed data on-the-fly. Both the C++ wrapper and the test suite are updated with the new API. Tests cover both `precomputed_txdata` reuse and nullability. Appreciate feedback on this concept / approach! ACKs for top commit: sedited: Re-ACK44e006d438stringintech: ACK44e006dTree-SHA512: 1ed435173e6ff4ec82bc603194cf182c685cb79f167439a442b9b179a32f6c189c358f04d4cb56d153fab04e3424a11b73c31680e42b87b8a6efcc3ccefc366c