Skip to content

Commit fcd2a52

Browse files
authored
Merge pull request #1678 from evoskuil/master
Incorporate tapleaf hash into signature hashing.
2 parents a6c2ae2 + 953bc17 commit fcd2a52

26 files changed

+352
-157
lines changed

Makefile.am

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ src_libbitcoin_system_la_SOURCES = \
5050
src/chain/point.cpp \
5151
src/chain/script.cpp \
5252
src/chain/script_extract.cpp \
53+
src/chain/taproot.cpp \
5354
src/chain/transaction.cpp \
5455
src/chain/transaction_cache.cpp \
5556
src/chain/transaction_sighash.cpp \
@@ -234,6 +235,7 @@ test_libbitcoin_system_test_SOURCES = \
234235
test/chain/script.cpp \
235236
test/chain/script.hpp \
236237
test/chain/stripper.cpp \
238+
test/chain/taproot.cpp \
237239
test/chain/transaction.cpp \
238240
test/chain/witness.cpp \
239241
test/chain/enums/opcode.cpp \
@@ -465,6 +467,7 @@ include_bitcoin_system_chain_HEADERS = \
465467
include/bitcoin/system/chain/prevout.hpp \
466468
include/bitcoin/system/chain/script.hpp \
467469
include/bitcoin/system/chain/stripper.hpp \
470+
include/bitcoin/system/chain/taproot.hpp \
468471
include/bitcoin/system/chain/transaction.hpp \
469472
include/bitcoin/system/chain/witness.hpp
470473

builds/cmake/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,7 @@ add_library( ${CANONICAL_LIB_NAME}
491491
"../../src/chain/point.cpp"
492492
"../../src/chain/script.cpp"
493493
"../../src/chain/script_extract.cpp"
494+
"../../src/chain/taproot.cpp"
494495
"../../src/chain/transaction.cpp"
495496
"../../src/chain/transaction_cache.cpp"
496497
"../../src/chain/transaction_sighash.cpp"
@@ -723,6 +724,7 @@ if (with-tests)
723724
"../../test/chain/script.cpp"
724725
"../../test/chain/script.hpp"
725726
"../../test/chain/stripper.cpp"
727+
"../../test/chain/taproot.cpp"
726728
"../../test/chain/transaction.cpp"
727729
"../../test/chain/witness.cpp"
728730
"../../test/chain/enums/opcode.cpp"

builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
<ClCompile Include="..\..\..\..\test\chain\satoshi_words.cpp" />
9393
<ClCompile Include="..\..\..\..\test\chain\script.cpp" />
9494
<ClCompile Include="..\..\..\..\test\chain\stripper.cpp" />
95+
<ClCompile Include="..\..\..\..\test\chain\taproot.cpp" />
9596
<ClCompile Include="..\..\..\..\test\chain\transaction.cpp" />
9697
<ClCompile Include="..\..\..\..\test\chain\witness.cpp" />
9798
<ClCompile Include="..\..\..\..\test\config\base16.cpp" />

builds/msvc/vs2022/libbitcoin-system-test/libbitcoin-system-test.vcxproj.filters

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,9 @@
162162
<ClCompile Include="..\..\..\..\test\chain\stripper.cpp">
163163
<Filter>src\chain</Filter>
164164
</ClCompile>
165+
<ClCompile Include="..\..\..\..\test\chain\taproot.cpp">
166+
<Filter>src\chain</Filter>
167+
</ClCompile>
165168
<ClCompile Include="..\..\..\..\test\chain\transaction.cpp">
166169
<Filter>src\chain</Filter>
167170
</ClCompile>

builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<ObjectFileName>$(IntDir)src_chain_script.obj</ObjectFileName>
101101
</ClCompile>
102102
<ClCompile Include="..\..\..\..\src\chain\script_extract.cpp" />
103+
<ClCompile Include="..\..\..\..\src\chain\taproot.cpp" />
103104
<ClCompile Include="..\..\..\..\src\chain\transaction.cpp">
104105
<ObjectFileName>$(IntDir)src_chain_transaction.obj</ObjectFileName>
105106
</ClCompile>
@@ -275,6 +276,7 @@
275276
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\prevout.hpp" />
276277
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\script.hpp" />
277278
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\stripper.hpp" />
279+
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\taproot.hpp" />
278280
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\transaction.hpp" />
279281
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\witness.hpp" />
280282
<ClInclude Include="..\..\..\..\include\bitcoin\system\config\base16.hpp" />
@@ -366,7 +368,6 @@
366368
<ClInclude Include="..\..\..\..\include\bitcoin\system\hash\sha\sha512.hpp" />
367369
<ClInclude Include="..\..\..\..\include\bitcoin\system\hash\siphash.hpp" />
368370
<ClInclude Include="..\..\..\..\include\bitcoin\system\have.hpp" />
369-
<ClInclude Include="..\..\..\..\include\bitcoin\system\impl\chain\transaction_patterns.ipp" />
370371
<ClInclude Include="..\..\..\..\include\bitcoin\system\intrinsics\arm\arm.hpp" />
371372
<ClInclude Include="..\..\..\..\include\bitcoin\system\intrinsics\arm\functional.hpp" />
372373
<ClInclude Include="..\..\..\..\include\bitcoin\system\intrinsics\arm\sha.hpp" />
@@ -532,6 +533,7 @@
532533
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\compact.ipp" />
533534
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\operation_patterns.ipp" />
534535
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\script_patterns.ipp" />
536+
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\transaction_patterns.ipp" />
535537
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\witness_patterns.ipp" />
536538
<None Include="..\..\..\..\include\bitcoin\system\impl\data\array_cast.ipp" />
537539
<None Include="..\..\..\..\include\bitcoin\system\impl\data\byte_cast.ipp" />
@@ -656,4 +658,4 @@
656658
<ItemGroup>
657659
<Natvis Include="..\..\debug.natvis" />
658660
</ItemGroup>
659-
</Project>
661+
</Project>

builds/msvc/vs2022/libbitcoin-system/libbitcoin-system.vcxproj.filters

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,9 @@
279279
<ClCompile Include="..\..\..\..\src\chain\script_extract.cpp">
280280
<Filter>src\chain</Filter>
281281
</ClCompile>
282+
<ClCompile Include="..\..\..\..\src\chain\taproot.cpp">
283+
<Filter>src\chain</Filter>
284+
</ClCompile>
282285
<ClCompile Include="..\..\..\..\src\chain\transaction.cpp">
283286
<Filter>src\chain</Filter>
284287
</ClCompile>
@@ -710,6 +713,9 @@
710713
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\stripper.hpp">
711714
<Filter>include\bitcoin\system\chain</Filter>
712715
</ClInclude>
716+
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\taproot.hpp">
717+
<Filter>include\bitcoin\system\chain</Filter>
718+
</ClInclude>
713719
<ClInclude Include="..\..\..\..\include\bitcoin\system\chain\transaction.hpp">
714720
<Filter>include\bitcoin\system\chain</Filter>
715721
</ClInclude>
@@ -1460,9 +1466,6 @@
14601466
<ClInclude Include="..\..\resource.h">
14611467
<Filter>resource</Filter>
14621468
</ClInclude>
1463-
<ClInclude Include="..\..\..\..\include\bitcoin\system\impl\chain\transaction_patterns.ipp">
1464-
<Filter>include\bitcoin\system\impl\chain</Filter>
1465-
</ClInclude>
14661469
</ItemGroup>
14671470
<ItemGroup>
14681471
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\annex.ipp">
@@ -1477,6 +1480,9 @@
14771480
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\script_patterns.ipp">
14781481
<Filter>include\bitcoin\system\impl\chain</Filter>
14791482
</None>
1483+
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\transaction_patterns.ipp">
1484+
<Filter>include\bitcoin\system\impl\chain</Filter>
1485+
</None>
14801486
<None Include="..\..\..\..\include\bitcoin\system\impl\chain\witness_patterns.ipp">
14811487
<Filter>include\bitcoin\system\impl\chain</Filter>
14821488
</None>
@@ -1748,4 +1754,4 @@
17481754
<Filter>resource</Filter>
17491755
</ResourceCompile>
17501756
</ItemGroup>
1751-
</Project>
1757+
</Project>

include/bitcoin/system.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
#include <bitcoin/system/chain/prevout.hpp>
4848
#include <bitcoin/system/chain/script.hpp>
4949
#include <bitcoin/system/chain/stripper.hpp>
50+
#include <bitcoin/system/chain/taproot.hpp>
5051
#include <bitcoin/system/chain/transaction.hpp>
5152
#include <bitcoin/system/chain/witness.hpp>
5253
#include <bitcoin/system/chain/enums/coverage.hpp>

include/bitcoin/system/chain/chain.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <bitcoin/system/chain/prevout.hpp>
4646
#include <bitcoin/system/chain/script.hpp>
4747
#include <bitcoin/system/chain/stripper.hpp>
48+
#include <bitcoin/system/chain/taproot.hpp>
4849
#include <bitcoin/system/chain/transaction.hpp>
4950
#include <bitcoin/system/chain/witness.hpp>
5051

include/bitcoin/system/chain/enums/magic_numbers.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,8 @@ constexpr uint8_t witness_enabled = 0x01;
9090
constexpr size_t signature_cost = 50;
9191
constexpr size_t taproot_max_keys = 128;
9292
constexpr uint8_t taproot_annex_prefix = 0x50;
93-
constexpr uint8_t tapleaf_tapscript = 0b1100'0000; // 0xc0
94-
constexpr uint8_t tapleaf_root_mask = 0b1111'1110; // 0xfe
93+
constexpr uint8_t tapscript_mask = 0b1111'1110; // 0xfe
94+
constexpr uint8_t tapscript_version = 0b1100'0000; // 0xc0
9595

9696
/// Policy constants.
9797
/// ---------------------------------------------------------------------------
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* Copyright (c) 2011-2025 libbitcoin developers (see AUTHORS)
3+
*
4+
* This file is part of libbitcoin.
5+
*
6+
* This program is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* This program is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
#ifndef LIBBITCOIN_SYSTEM_CHAIN_TAPROOT_HPP
20+
#define LIBBITCOIN_SYSTEM_CHAIN_TAPROOT_HPP
21+
22+
#include <bitcoin/system/chain/script.hpp>
23+
#include <bitcoin/system/crypto/crypto.hpp>
24+
#include <bitcoin/system/data/data.hpp>
25+
#include <bitcoin/system/define.hpp>
26+
#include <bitcoin/system/hash/hash.hpp>
27+
28+
namespace libbitcoin {
29+
namespace system {
30+
namespace chain {
31+
32+
class BC_API taproot
33+
{
34+
public:
35+
struct tap
36+
{
37+
INLINE operator bool() const NOEXCEPT
38+
{
39+
return version == tapscript_version;
40+
}
41+
42+
uint8_t version;
43+
bool parity;
44+
};
45+
46+
static tap parse(const data_chunk& control) NOEXCEPT;
47+
static bool is_valid_control_block(const data_chunk& control) NOEXCEPT;
48+
static hash_digest leaf_hash(uint8_t version,
49+
const script& script) NOEXCEPT;
50+
51+
static bool verify_commitment(const data_chunk& control,
52+
const data_chunk& program, const hash_digest& hash,
53+
bool parity) NOEXCEPT;
54+
55+
protected:
56+
static hash_digest merkle_root(const data_chunk& control,
57+
const hash_digest& tapleaf_hash) NOEXCEPT;
58+
static hash_digest branch_hash(const hash_digest& left,
59+
const hash_digest& right) NOEXCEPT;
60+
static hash_digest tweak_hash(const ec_xonly& key,
61+
const hash_digest& merkle) NOEXCEPT;
62+
};
63+
} // namespace chain
64+
} // namespace system
65+
} // namespace libbitcoin
66+
67+
68+
#endif

include/bitcoin/system/chain/transaction.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,8 +142,9 @@ class BC_API transaction
142142

143143
/// signature_hash exposed for op_check_multisig caching.
144144
bool signature_hash(hash_digest& out, const input_iterator& input,
145-
const script& sub, uint64_t value, uint8_t sighash_flags,
146-
script_version version, bool bip143, bool bip341) const NOEXCEPT;
145+
const script& subscript, uint64_t value, const hash_cptr& tapleaf,
146+
script_version version, uint8_t sighash_flags,
147+
uint32_t flags) const NOEXCEPT;
147148

148149
/// Not used internally.
149150
bool check_signature(const ec_signature& signature,
@@ -319,7 +320,7 @@ class BC_API transaction
319320
const script& subscript, uint64_t value,
320321
uint8_t sighash_flags) const NOEXCEPT;
321322
bool version1_sighash(hash_digest& out, const input_iterator& input,
322-
const script& script, uint64_t value,
323+
const script& script, uint64_t value, const hash_cptr& tapleaf,
323324
uint8_t sighash_flags) const NOEXCEPT;
324325

325326
// ------------------------------------------------------------------------

include/bitcoin/system/chain/witness.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,8 @@ class BC_API witness
126126
/// Script for witness validation.
127127
code extract_script(script::cptr& out_script, chunk_cptrs_ptr& out_stack,
128128
const script& program_script) const NOEXCEPT;
129+
code extract_script(hash_cptr& out_leaf, script::cptr& out_script,
130+
chunk_cptrs_ptr& out_stack, const script& program_script) const NOEXCEPT;
129131

130132
protected:
131133
witness(chunk_cptrs&& stack, bool valid) NOEXCEPT;

include/bitcoin/system/funclets.hpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#ifndef LIBBITCOIN_SYSTEM_FUNCLETS_HPP
2020
#define LIBBITCOIN_SYSTEM_FUNCLETS_HPP
2121

22+
#include <memory>
2223
#include <type_traits>
2324
#include <bitcoin/system/literals.hpp>
2425

@@ -164,6 +165,13 @@ constexpr bool to_bool(Type value) noexcept
164165
return is_nonzero(value);
165166
}
166167

168+
template <typename Type>
169+
constexpr bool as_bool(const std::shared_ptr<Type>& ptr) noexcept
170+
{
171+
// Use as_bool(ptr) because shared_ptr bool overload is explicit.
172+
return ptr.operator bool();
173+
}
174+
167175
template <typename Enum>
168176
constexpr auto to_value(Enum value) noexcept
169177
{

include/bitcoin/system/impl/chain/annex.ipp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ inline const data_chunk& annex::empty_annex() NOEXCEPT
5757

5858
inline annex::operator bool() const NOEXCEPT
5959
{
60-
return data_.operator bool();
60+
return as_bool(data_);
6161
}
6262

6363
inline size_t annex::size() const NOEXCEPT

include/bitcoin/system/impl/machine/interpreter_connect.ipp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -188,15 +188,14 @@ code CLASS::connect_witness(const chain::context& state,
188188
if (!bip341 || embedded)
189189
return error::script_success;
190190

191+
hash_cptr tapleaf{};
191192
script::cptr script;
192193
chunk_cptrs_ptr stack;
193-
194-
// TODO: extract tapleaf_hash, nullable.
195-
if ((ec = input.witness().extract_script(script, stack, prevout)))
194+
if ((ec = input.witness().extract_script(tapleaf, script, stack,
195+
prevout)))
196196
return ec;
197197

198-
// TODO: pass tapleaf_hash in last parameter, nullable.
199-
interpreter program(tx, it, script, flags, version, stack, {});
198+
interpreter program(tx, it, script, flags, version, stack, tapleaf);
200199

201200
// TODO: capture tapleaf_hash in program construct and use to
202201
// TODO: obtain both tapscript boolean and tapleaf_hash values.

include/bitcoin/system/impl/machine/program_construct.ipp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,22 +106,24 @@ program(const transaction& tx, const input_iterator& input,
106106
}
107107

108108
// Taproot script run (witness-initialized stack).
109-
// Same as segwit but with with budget and unstripped bip342 flag.
109+
// Same as segwit but with tapleaf, budget, and unstripped bip342 flag.
110110
// Sigop budget is 50 plus size of prefixed serialized witness [bip342].
111111
// Budget is initialized add1(50) to make it zero-based, avoiding signed type.
112112
// This program is never used to construct another, so masked flags_ never mix.
113113
TEMPLATE
114114
inline CLASS::
115115
program(const transaction& tx, const input_iterator& input,
116116
const script::cptr& script, uint32_t active_flags,
117-
script_version version, const chunk_cptrs_ptr& witness, bool) NOEXCEPT
117+
script_version version, const chunk_cptrs_ptr& witness,
118+
const hash_cptr& tapleaf) NOEXCEPT
118119
: transaction_(tx),
119120
input_(input),
120121
script_(script),
121122
flags_(active_flags),
122123
value_((*input)->prevout->value()),
123124
version_(version),
124125
witness_(witness),
126+
tapleaf_(tapleaf),
125127
primary_(projection<Stack>(*witness)),
126128
budget_(ceilinged_add(
127129
add1(chain::signature_cost),

include/bitcoin/system/impl/machine/program_sign.ipp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,8 @@ INLINE bool CLASS::
214214
signature_hash(hash_digest& out, const script& subscript,
215215
uint8_t sighash_flags) const NOEXCEPT
216216
{
217-
// bip143: the method of signature hashing is changed for v0 scripts.
218-
// bip342: the method of signature hashing is changed for v1 scripts.
219-
const auto bip143 = is_enabled(flags::bip143_rule);
220-
const auto bip342 = is_enabled(flags::bip342_rule);
221-
222217
return transaction_.signature_hash(out, input_, subscript, value_,
223-
sighash_flags, version_, bip143, bip342);
218+
tapleaf_, version_, sighash_flags, flags_);
224219
}
225220

226221
// Multisig signature hash caching.

0 commit comments

Comments
 (0)