Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
bip352.cpp
Go to the documentation of this file.
1// Copyright (c) 2026-present The Bitcoin Core developers
2// Distributed under the MIT software license, see the accompanying
3// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5#include <common/bip352.h>
6
7#include <addresstype.h>
8#include <bench/bench.h>
9#include <key.h>
11#include <pubkey.h>
12#include <script/interpreter.h>
13#include <script/script.h>
14#include <util/check.h>
15
16#include <optional>
17#include <span>
18#include <utility>
19#include <variant>
20#include <vector>
21
22enum class InputType {
23 P2PKH, // legacy pubkey-hash
24 P2SH_P2WPKH, // nested segwitv0 witness-pubkey-hash
25 P2WPKH, // segwitv0 witness-pubkey-hash
26 P2TR, // segwitv1, taproot script-path spend (covers more extraction logic than key-path)
27 P2PKH_WorstCase, // legacy pubkey-hash, with scriptSig malleated for worst-case performance (see below)
28};
29
30// The extraction doesn't verify signatures, so dummy ones with realistic sizes suffice.
31static const std::vector<unsigned char> DUMMY_ECDSA_SIG(71, 0x01); // low-R/low-S DER signature (following BIP-461) + sighash byte
32static const std::vector<unsigned char> DUMMY_SCHNORR_SIG(64, 0x01); // BIP-340 signature (SIGHASH_DEFAULT)
33// Likewise, the taproot commitment isn't verified, so a dummy leaf script (<32-byte push> OP_CHECKSIG) suffices.
34static const CScript DUMMY_LEAF_SCRIPT{CScript() << std::vector<unsigned char>(32, 0x01) << OP_CHECKSIG};
35
37{
39 const CPubKey pubkey{GenerateRandomKey().GetPubKey()};
40
42 CTxIn txin;
44 switch (input_type) {
47 txin.scriptSig = CScript() << DUMMY_ECDSA_SIG << ToByteVector(pubkey);
48 break;
50 const CScript redeem_script{GetScriptForDestination(WitnessV0KeyHash{pubkey})};
51 spk = GetScriptForDestination(ScriptHash{redeem_script});
52 txin.scriptSig = CScript() << ToByteVector(redeem_script);
53 txin.scriptWitness.stack = {DUMMY_ECDSA_SIG, ToByteVector(pubkey)};
54 break;
55 }
58 txin.scriptWitness.stack = {DUMMY_ECDSA_SIG, ToByteVector(pubkey)};
59 break;
60 case InputType::P2TR: {
61 // Script-path spend, as it runs all of the key-path extraction logic plus the control
62 // block checks and the NUMS-H comparison. The control block only needs the right shape
63 // (leaf version byte followed by a non-NUMS internal key, no merkle path).
65 std::vector<unsigned char> control_block{TAPROOT_LEAF_TAPSCRIPT};
66 const XOnlyPubKey internal_key{GenerateRandomKey().GetPubKey()};
67 control_block.insert(control_block.end(), internal_key.begin(), internal_key.end());
70 break;
71 }
73 // Worst case for the P2PKH scriptSig scan: prepend as many 33-byte pushes (each of which
74 // is hashed and compared against the pubkey hash) as the consensus scriptSig size limit
75 // allows, followed by the actual <sig> <pubkey>. Data pushes don't count towards
76 // MAX_OPS_PER_SCRIPT, the resulting stack stays below MAX_STACK_SIZE, and leftover stack
77 // elements are fine for legacy scripts (CLEANSTACK is policy only). Note that the
78 // scriptSig exceeds MAX_STANDARD_SCRIPTSIG_SIZE, i.e. such a spend is non-standard.
80 const std::vector<unsigned char> dummy_pubkey(CPubKey::COMPRESSED_SIZE, 0x02);
81 const size_t push_size{(CScript() << dummy_pubkey).size()};
82 const size_t sig_and_pubkey_size{(CScript() << DUMMY_ECDSA_SIG << ToByteVector(pubkey)).size()};
84 for (size_t i = 0; i < num_dummy_pushes; ++i) {
85 txin.scriptSig << dummy_pubkey;
86 }
87 txin.scriptSig << DUMMY_ECDSA_SIG << ToByteVector(pubkey);
88 Assert(txin.scriptSig.size() <= MAX_SCRIPT_SIZE);
90 break;
91 }
92 } // no default case, so the compiler can warn about missing cases
93
95 bench.unit("input").run([&] {
98 });
99}
100
106
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
#define BENCHMARK(n)
Definition bench.h:69
static void BIP352_GetPubKey_P2PKH(benchmark::Bench &bench)
Definition bip352.cpp:101
static void BIP352_GetPubKey_P2PKH_WorstCase(benchmark::Bench &bench)
Definition bip352.cpp:105
static const std::vector< unsigned char > DUMMY_ECDSA_SIG(71, 0x01)
static void BIP352_GetPubKey_P2SH_P2WPKH(benchmark::Bench &bench)
Definition bip352.cpp:102
static const std::vector< unsigned char > DUMMY_SCHNORR_SIG(64, 0x01)
InputType
Definition bip352.cpp:22
static void BIP352_GetPubKey_P2TR(benchmark::Bench &bench)
Definition bip352.cpp:104
static void BIP352_GetPubKey_P2WPKH(benchmark::Bench &bench)
Definition bip352.cpp:103
static void GetPubKeyBench(benchmark::Bench &bench, InputType input_type)
Definition bip352.cpp:36
static const CScript DUMMY_LEAF_SCRIPT
Definition bip352.cpp:34
ECC_Context ecc_context
#define Assert(val)
Identity function.
Definition check.h:119
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition key.cpp:184
An encapsulated public key.
Definition pubkey.h:43
static constexpr unsigned int COMPRESSED_SIZE
Definition pubkey.h:49
Serialized script, used inside transaction inputs and outputs.
Definition script.h:406
An input of a transaction.
Definition transaction.h:63
RAII class initializing and deinitializing global state for elliptic curve support.
Definition key.h:364
Main entry point to nanobench's benchmarking facility.
Definition nanobench.h:649
constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT
CKey GenerateRandomKey(bool compressed) noexcept
Definition key.cpp:354
void doNotOptimizeAway(Arg &&arg)
Makes sure none of the given arguments are optimized away by the compiler.
Definition nanobench.h:1353
std::optional< PubKey > GetPubKeyFromInput(const CTxIn &txin, const CScript &spk)
Get the public key from an input.
Definition bip352.cpp:144
std::variant< CPubKey, XOnlyPubKey > PubKey
Definition bip352.h:39
constexpr int MAX_SCRIPT_SIZE
Definition script.h:41
@ OP_CHECKSIG
Definition script.h:191
constexpr int MAX_STACK_SIZE
Definition script.h:44
std::vector< unsigned char > ToByteVector(const T &in)
Definition script.h:68
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82