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

libbitcoin / libbitcoin-system / 14981247273

12 May 2025 07:50PM UTC coverage: 82.111% (-0.007%) from 82.118%
14981247273

push

github

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

Factor program/interpreter ipp's, update includes/inlines, fix sig bu…

308 of 389 new or added lines in 5 files covered. (79.18%)

10314 of 12561 relevant lines covered (82.11%)

3835839.86 hits per line

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

73.68
/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
NEW
41
inline bool CLASS::
×
42
is_schnorr_sighash(uint8_t sighash_flags) NOEXCEPT
43
{
44
    using namespace chain;
45

NEW
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;
NEW
57
        default:
×
NEW
58
            return false;
×
59
    }
60
}
61

62
// static
63
TEMPLATE
NEW
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

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

NEW
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).
NEW
77
        sighash_flags = coverage::hash_default;
×
78
    }
NEW
79
    else if (size == add1(signature_size))
×
80
    {
81
        // BIP341: signature has sighash byte appended in the usual fashion.
NEW
82
        const auto byte = endorsement.back();
×
NEW
83
        if (is_schnorr_sighash(byte))
×
NEW
84
            sighash_flags = byte;
×
85
    }
86
    else
87
    {
88
        // This makes an invalid return safe to dereference, and may be
89
        // compiled out unless a caller does in fact access it.
90
        static constexpr ec_signature empty{};
91
        return empty;
92
    }
93

NEW
94
    return unsafe_array_cast<uint8_t, signature_size>(endorsement.data());
×
95
}
96

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

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

109
// Signature subscripting.
110
// ----------------------------------------------------------------------------
111

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

224
// Signature hashing.
225
// ----------------------------------------------------------------------------
226

227
TEMPLATE
NEW
228
INLINE hash_digest CLASS::
×
229
signature_hash(uint8_t sighash_flags) const NOEXCEPT
230
{
231
    return signature_hash(subscript(), sighash_flags);
232
}
233

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

243
    return transaction_.signature_hash(input_, subscript, value_,
36✔
244
        sighash_flags, version_, bip143, bip342);
36✔
245
}
246

247
// Multisig signature hash caching.
248
// ----------------------------------------------------------------------------
249

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

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

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

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

281
} // namespace machine
282
} // namespace system
283
} // namespace libbitcoin
284

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

© 2026 Coveralls, Inc