• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

libbitcoin / libbitcoin-system / 15078892484

16 May 2025 11:04PM UTC coverage: 81.885% (-0.3%) from 82.18%
15078892484

push

github

web-flow
Merge pull request #1673 from evoskuil/master

Refactor all signature_hash methods to return bool (tapscript).

293 of 491 new or added lines in 17 files covered. (59.67%)

5 existing lines in 3 files now uncovered.

10365 of 12658 relevant lines covered (81.88%)

3781254.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

73.21
/include/bitcoin/system/impl/machine/program_sign.ipp
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_MACHINE_PROGRAM_SIGN_IPP
20
#define LIBBITCOIN_SYSTEM_MACHINE_PROGRAM_SIGN_IPP
21

22
#include <iterator>
23
#include <bitcoin/system/chain/chain.hpp>
24
#include <bitcoin/system/crypto/crypto.hpp>
25
#include <bitcoin/system/data/data.hpp>
26
#include <bitcoin/system/define.hpp>
27
#include <bitcoin/system/math/math.hpp>
28

29
namespace libbitcoin {
30
namespace system {
31
namespace machine {
32

33
// Endorsement parsing.
34
// ----------------------------------------------------------------------------
35

36
// static/private
37
// BIP341: Using any undefined hash_type causes validation failure if violated.
38
// defined types: 0x00, 0x01, 0x02, 0x03, 0x81, 0x82, or 0x83. [zero is the
39
// default and cannot be explicit, but is serialized for signature hashing].
40
TEMPLATE
41
inline bool CLASS::
×
42
is_schnorr_sighash(uint8_t sighash_flags) NOEXCEPT
43
{
44
    using namespace chain;
45

46
    switch (sighash_flags)
×
47
    {
48
        // BIP341: zero is invalid sighash, must be explicit to prevent mally.
49
        ////case coverage::hash_default:
50
        case coverage::hash_all:
51
        case coverage::hash_none:
52
        case coverage::hash_single:
53
        case coverage::all_anyone_can_pay:
54
        case coverage::none_anyone_can_pay:
55
        case coverage::single_anyone_can_pay:
56
            return true;
57
        default:
×
58
            return false;
×
59
    }
60
}
61

62
// static
63
TEMPLATE
64
inline const ec_signature& CLASS::
×
65
schnorr_split(uint8_t& sighash_flags, const data_chunk& endorsement) NOEXCEPT
66
{
67
    using namespace chain;
68
    using namespace schnorr;
69

70
    sighash_flags = coverage::invalid;
×
71
    const auto size = endorsement.size();
72

73
    if (size == signature_size)
×
74
    {
75
        // BIP341: if [sighash byte] is omitted the resulting signatures are 64
76
        // bytes, and [default == 0] mode is implied (implies SIGHASH_ALL).
77
        sighash_flags = coverage::hash_default;
×
78
    }
79
    else if (size == add1(signature_size))
×
80
    {
81
        // BIP341: signature has sighash byte appended in the usual fashion.
82
        const auto byte = endorsement.back();
×
83

84
        // BIP341: Defined sighash type required (otherwise invalid is set).
85
        if (is_schnorr_sighash(byte))
×
86
            sighash_flags = byte;
×
87
    }
88
    else
89
    {
90
        // This makes an invalid return safe to dereference, and may be
91
        // compiled out unless a caller does in fact access it.
92
        static constexpr ec_signature empty{};
93
        return empty;
94
    }
95

96
    return unsafe_array_cast<uint8_t, signature_size>(endorsement.data());
×
97
}
98

99
// static
100
TEMPLATE
101
INLINE data_slice CLASS::
46✔
102
ecdsa_split(uint8_t& sighash_flags, const data_chunk& endorsement) NOEXCEPT
103
{
104
    BC_ASSERT(!endorsement.empty());
105
    sighash_flags = endorsement.back();
46✔
106

107
    // data_slice is returned since the size of the DER encoding is not fixed.
108
    return { endorsement.begin(), std::prev(endorsement.end()) };
46✔
109
}
110

111
// Signature subscripting.
112
// ----------------------------------------------------------------------------
113

114
// Subscripts are referenced by script.offset mutable metadata. This allows for
115
// efficient subscripting with no copying. As a result concurrent execution of
116
// any one input script instance is not thread safe.
117
TEMPLATE
118
INLINE void CLASS::
9✔
119
set_subscript(const op_iterator& op) NOEXCEPT
120
{
121
    // Not possible unless op is not an element of script_.
122
    BC_ASSERT(!script_->ops().empty() && op != script_->ops().end());
123

124
    // Advance the offset to the op following the found code separator.
125
    // This is non-const because changes script state (despite being mutable).
126
    script_->offset = std::next(op);
9✔
127
}
128

129
// static/private
130
TEMPLATE
131
inline chain::strippers CLASS::
1,948✔
132
create_strip_ops(const chunk_xptrs& endorsements) NOEXCEPT
133
{
134
    chain::strippers strip{};
1,948✔
135
    strip.reserve(add1(endorsements.size()));
1,948✔
136
    for (const auto& endorsement: endorsements)
1,960✔
137
        strip.emplace_back(endorsement);
12✔
138

139
    strip.emplace_back(chain::opcode::codeseparator);
1,948✔
140
    return strip;
1,948✔
141
}
142

143
// static/private
144
TEMPLATE
145
INLINE chain::strippers CLASS::
10✔
146
create_strip_ops(const chunk_xptr& endorsement) NOEXCEPT
147
{
148
    using namespace chain;
149
    return { stripper{ endorsement }, stripper{ opcode::codeseparator } };
20✔
150
}
151

152
// ****************************************************************************
153
// CONSENSUS: Endorsement and code separator stripping are always performed in
154
// conjunction and are limited to non-witness signature hash subscripts.
155
// The order of operations is inconsequential, as they are all removed.
156
// Subscripts are not evaluated, they are limited to signature hash creation.
157
// ****************************************************************************
158
TEMPLATE
159
inline chain::script::cptr CLASS::
1,949✔
160
subscript(const chunk_xptrs& endorsements) const NOEXCEPT
161
{
162
    // bip141: establishes the version property.
163
    // bip143: op stripping is not applied to bip141 v0 scripts.
164
    if (is_enabled(flags::bip143_rule) && version_ == script_version::segwit)
1,949✔
165
        return script_;
166

167
    // Transform into a set of endorsement push ops and one op_codeseparator.
168
    const auto strip = create_strip_ops(endorsements);
1,948✔
169
    const auto stop = script_->ops().end();
1,948✔
170
    const op_iterator start{ script_->offset };
1,948✔
171

172
    // If none of the strip ops are found, return the subscript.
173
    if (!is_intersecting<operations>(start, stop, strip))
1,948✔
174
        return script_;
175

176
    // Create new script from stripped copy of subscript operations.
177
    return to_shared<script>(difference<operations>(start, stop, strip));
2✔
178
}
179

180
TEMPLATE
181
inline chain::script::cptr CLASS::
26✔
182
subscript(const chunk_xptr& endorsement) const NOEXCEPT
183
{
184
    // bip141: establishes the version property.
185
    // bip143: op stripping is not applied to bip141 v0 scripts.
186
    if (is_enabled(flags::bip143_rule) && version_ == script_version::segwit)
26✔
187
        return script_;
188

189
    // Transform into a set with one endorsement push op and op_codeseparator.
190
    const auto strip = create_strip_ops(endorsement);
191
    const auto stop = script_->ops().end();
10✔
192
    const op_iterator start{ script_->offset };
10✔
193

194
    // If none of the strip ops are found, return the subscript.
195
    if (!is_intersecting<operations>(start, stop, strip))
10✔
196
        return script_;
197

198
    // Create new script from stripped copy of subscript operations.
199
    return to_shared<script>(difference<operations>(start, stop, strip));
3✔
200
}
10✔
201

202
TEMPLATE
203
INLINE const chain::script& CLASS::
×
204
subscript() const NOEXCEPT
205
{
206
    return *script_;
207
}
208

209
// private/static
210
TEMPLATE
211
inline uint32_t CLASS::
212
subscript(const script& script) NOEXCEPT
213
{
214
    // This method is only called from the run loop, which means there are ops.
215
    BC_ASSERT(!script.ops().empty());
216

217
    // BIP342: zero-based opcode position of the last executed op_codeseparator
218
    // before currently executed signature opcode (0xffffffff if none).
219
    const auto start = script.ops().begin();
220
    const auto span = std::distance(start, script.offset);
221
    const auto slot = possible_narrow_and_sign_cast<uint32_t>(span);
222
    const auto none = is_zero(slot) && start->code() != opcode::codeseparator;
223
    return none ? chain::default_separators : slot;
224
}
225

226
// Signature hashing.
227
// ----------------------------------------------------------------------------
228

229
TEMPLATE
NEW
230
INLINE bool CLASS::
×
231
signature_hash(hash_digest& out, uint8_t sighash_flags) const NOEXCEPT
232
{
233
    return signature_hash(out, subscript(), sighash_flags);
234
}
235

236
TEMPLATE
237
INLINE bool CLASS::
26✔
238
signature_hash(hash_digest& out, const script& subscript,
239
    uint8_t sighash_flags) const NOEXCEPT
240
{
241
    // bip143: the method of signature hashing is changed for v0 scripts.
242
    // bip342: the method of signature hashing is changed for v1 scripts.
243
    const auto bip143 = is_enabled(flags::bip143_rule);
244
    const auto bip342 = is_enabled(flags::bip342_rule);
245

246
    return transaction_.signature_hash(out, input_, subscript, value_,
36✔
247
        sighash_flags, version_, bip143, bip342);
36✔
248
}
249

250
// Multisig signature hash caching.
251
// ----------------------------------------------------------------------------
252

253
TEMPLATE
254
INLINE void CLASS::
1,949✔
255
initialize_cache() NOEXCEPT
256
{
257
    cache_.first = true;
1,949✔
258
}
259

260
TEMPLATE
261
INLINE bool CLASS::
20✔
262
uncached(uint8_t sighash_flags) const NOEXCEPT
263
{
264
    return cache_.first || cache_.flags != sighash_flags;
20✔
265
}
266

267
TEMPLATE
268
INLINE bool CLASS::
10✔
269
set_hash(const chain::script& subscript, uint8_t sighash_flags) NOEXCEPT
270
{
271
    cache_.first = false;
10✔
272
    cache_.flags = sighash_flags;
10✔
273
    return signature_hash(cache_.hash, subscript, sighash_flags);
10✔
274
}
275

276
TEMPLATE
277
INLINE const hash_digest& CLASS::
20✔
278
cached_hash() const NOEXCEPT
279
{
280
    return cache_.hash;
20✔
281
}
282

283
} // namespace machine
284
} // namespace system
285
} // namespace libbitcoin
286

287
#endif
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc