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

libbitcoin / libbitcoin-system / 14845904192

05 May 2025 08:45PM UTC coverage: 82.712% (-0.08%) from 82.789%
14845904192

push

github

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

Stub in op_check_sig_add() and op_check_schnorr_sig(), update tests.

230 of 274 new or added lines in 7 files covered. (83.94%)

10200 of 12332 relevant lines covered (82.71%)

3906935.59 hits per line

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

96.76
/include/bitcoin/system/impl/machine/program.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_IPP
20
#define LIBBITCOIN_SYSTEM_MACHINE_PROGRAM_IPP
21

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

31
namespace libbitcoin {
32
namespace system {
33
namespace machine {
34

35
using namespace system::chain;
36
using namespace system::error;
37

38
// Constructors.
39
// ----------------------------------------------------------------------------
40

41
// Input script run (default/empty stack).
42
// 'tx' must remain in scope, this holds state referenced by weak pointers.
43
// This expectation is guaranteed by the retained tx reference.
44
TEMPLATE
45
inline CLASS::
1,559✔
46
program(const chain::transaction& tx, const input_iterator& input,
47
     uint32_t active_flags) NOEXCEPT
48
  : transaction_(tx),
1,559✔
49
    input_(input),
1,559✔
50
    script_((*input)->script_ptr()),
1,559✔
51
    flags_(active_flags),
1,559✔
52
    value_(max_uint64),
1,559✔
53
    version_(script_version::unversioned),
1,559✔
54
    witness_(),
55
    primary_()
1,559✔
56
{
57
}
1,559✔
58

59
// Legacy p2sh or prevout script run (copied input stack - use first).
60
// 'other' must remain in scope, this holds state referenced by weak pointers.
61
// This expectation is guaranteed by the retained transaction_ member reference
62
// and copied program tether (which is not tx state).
63
TEMPLATE
64
inline CLASS::
1,496✔
65
program(const program& other, const script::cptr& script) NOEXCEPT
66
  : transaction_(other.transaction_),
1,496✔
67
    input_(other.input_),
1,496✔
68
    script_(script),
69
    flags_(other.flags_),
1,496✔
70
    value_(other.value_),
1,496✔
71
    version_(other.version_),
1,496✔
72
    witness_(),
73
    primary_(other.primary_)
1,496✔
74
{
75
}
1,496✔
76

77
// Legacy p2sh or prevout script run (moved input stack/tether - use last).
78
TEMPLATE
79
inline CLASS::
17✔
80
program(program&& other, const script::cptr& script) NOEXCEPT
81
  : transaction_(other.transaction_),
17✔
82
    input_(other.input_),
17✔
83
    script_(script),
84
    flags_(other.flags_),
17✔
85
    value_(other.value_),
17✔
86
    version_(other.version_),
17✔
87
    witness_(),
88
    primary_(std::move(other.primary_))
17✔
89
{
90
}
17✔
91

92
// Witness script run (witness-initialized stack).
93
// 'tx', 'input' (and iterated chain::input) must remain in scope, as these
94
// hold chunk state weak references. A witness pointer is explicitly retained
95
// to guarantee the lifetime of its elements.
96
TEMPLATE
97
inline CLASS::
23✔
98
program(const chain::transaction& tx, const input_iterator& input,
99
    const script::cptr& script, uint32_t active_flags, script_version version,
100
    const chunk_cptrs_ptr& witness) NOEXCEPT
101
  : transaction_(tx),
23✔
102
    input_(input),
23✔
103
    script_(script),
104
    flags_(active_flags),
23✔
105
    value_((*input)->prevout->value()),
23✔
106
    version_(version),
23✔
107
    witness_(witness),
108
    primary_(projection<Stack>(*witness))
69✔
109
{
110
}
23✔
111

112
// Public.
113
// ----------------------------------------------------------------------------
114

115
TEMPLATE
116
inline bool CLASS::
1,088✔
117
is_true(bool clean_stack) const NOEXCEPT
118
{
119
    return (!clean_stack || is_stack_clean()) && !is_stack_empty() &&
3,244✔
120
        peek_bool_();
1,088✔
121
}
122

123
TEMPLATE
124
inline const data_chunk& CLASS::
17✔
125
pop() NOEXCEPT
126
{
127
    BC_ASSERT_MSG(!is_stack_empty(), "pop from empty stack");
128

129
    return *pop_chunk_();
17✔
130
}
131

132
// Non-public.
133
// ============================================================================
134

135
TEMPLATE
136
INLINE bool CLASS::
3,095✔
137
is_prefail() const NOEXCEPT
138
{
139
    return script_->is_prefail();
3,095✔
140
}
141

142
TEMPLATE
143
INLINE typename CLASS::op_iterator CLASS::
3,033✔
144
begin() const NOEXCEPT
145
{
146
    return script_->ops().begin();
3,033✔
147
}
148

149
TEMPLATE
150
INLINE typename CLASS::op_iterator CLASS::
25,009✔
151
end() const NOEXCEPT
152
{
153
    return script_->ops().end();
25,009✔
154
}
155

156
TEMPLATE
157
INLINE const chain::input& CLASS::
18✔
158
input() const NOEXCEPT
159
{
160
    return **input_;
161
}
162

163
TEMPLATE
164
INLINE const chain::transaction& CLASS::
7✔
165
transaction() const NOEXCEPT
166
{
167
    return transaction_;
7✔
168
}
169

170
TEMPLATE
171
INLINE bool CLASS::
12,467✔
172
is_enabled(chain::flags flag) const NOEXCEPT
173
{
174
    return to_bool(flags_ & flag);
4,811✔
175
}
176

177
// TODO: only perform is_push_size check on witness initialized stack.
178
// TODO: others are either empty or presumed push_size from prevout script run.
179
TEMPLATE
180
INLINE script_error_t CLASS::
3,095✔
181
validate() const NOEXCEPT
182
{
183
    // TODO: nops rule must first be enabled in tests and config.
184
    const auto bip141 = is_enabled(flags::bip141_rule);
185

186
    // The script was determined by the parser to contain an invalid opcode.
187
    if (is_prefail())
3,095✔
188
        return error::prefail_script;
189

190
    // bip_141 introduces an initialized stack, so must validate.
191
    if (bip141 && witness_ && !witness::is_push_size(*witness_))
3,035✔
192
        return error::invalid_witness_stack;
193

194
    // The nops_rule establishes script size limit.
195
    return script_->is_oversized() ? error::invalid_script_size :
3,035✔
196
        error::script_success;
197
}
198

199
// Primary stack (conversions).
200
// ----------------------------------------------------------------------------
201

202
// static
203
TEMPLATE
204
INLINE bool CLASS::
560✔
205
equal_chunks(const stack_variant& left, const stack_variant& right) NOEXCEPT
206
{
207
    return primary_stack::equal_chunks(left, right);
560✔
208
}
209

210
TEMPLATE
211
INLINE bool CLASS::
1,593✔
212
peek_bool_() const NOEXCEPT
213
{
214
    return primary_.peek_bool();
1,593✔
215
}
216

217
TEMPLATE
218
INLINE chunk_xptr CLASS::
3,578✔
219
peek_chunk_() const NOEXCEPT
220
{
221
    return primary_.peek_chunk();
3,578✔
222
}
223

224
TEMPLATE
225
INLINE size_t CLASS::
58✔
226
peek_size() const NOEXCEPT
227
{
228
    return primary_.peek_size();
58✔
229
}
230

231
// Primary stack (push).
232
// ----------------------------------------------------------------------------
233

234
// This is the only source of push (write) tethering.
235
TEMPLATE
236
INLINE void CLASS::
167✔
237
push_chunk(data_chunk&& datum) NOEXCEPT
238
{
239
    primary_.push(std::move(datum));
240
}
241

242
// Passing data_chunk& would be poor interface design, as it would allow
243
// derived callers to (unsafely) store raw pointers to unshared data_chunk.
244
BC_PUSH_WARNING(SMART_PTR_NOT_NEEDED)
245
BC_PUSH_WARNING(NO_VALUE_OR_CONST_REF_SHARED_PTR)
246
TEMPLATE
247
INLINE void CLASS::
4,474✔
248
push_chunk(const chunk_cptr& datum) NOEXCEPT
249
BC_POP_WARNING()
250
BC_POP_WARNING()
251
{
252
    primary_.emplace_chunk(datum.get());
8,948✔
253
}
254

255
// private
256
TEMPLATE
257
INLINE void CLASS::
258
push_chunk(const chunk_xptr& datum) NOEXCEPT
259
{
260
    primary_.emplace_chunk(datum);
261
}
262

263
TEMPLATE
264
INLINE void CLASS::
2,018✔
265
push_bool(bool value) NOEXCEPT
266
{
267
    primary_.emplace_boolean(value);
2,018✔
268
}
269

270
TEMPLATE
271
INLINE void CLASS::
7,256✔
272
push_signed64(int64_t value) NOEXCEPT
273
{
274
    primary_.emplace_integer(value);
7,073✔
275
}
276

277
TEMPLATE
278
INLINE void CLASS::
241✔
279
push_length(size_t value) NOEXCEPT
280
{
281
    // This is guarded by stack size and push data limits.
282
    BC_ASSERT_MSG(value <= max_int64, "integer overflow");
283

284
    push_signed64(possible_narrow_sign_cast<int64_t>(value));
241✔
285
}
286

287
// Primary stack (pop).
288
// ----------------------------------------------------------------------------
289

290
// This tethers a chunk if the stack value is not chunk.
291
TEMPLATE
292
INLINE chunk_xptr CLASS::
3,578✔
293
pop_chunk_() NOEXCEPT
294
{
295
    const auto value = peek_chunk_();
296
    drop_();
297
    return value;
219✔
298
}
299

300
// This tethers chunks if the stack values are not chunk.
301
TEMPLATE
302
INLINE bool CLASS::
4,102✔
303
pop_chunks(chunk_xptrs& data, size_t count) NOEXCEPT
304
{
305
    if (stack_size() < count)
4,102✔
306
        return false;
307

308
    data.reserve(count);
4,102✔
309
    for (size_t index = 0; index < count; ++index)
7,444✔
310
        data.push_back(pop_chunk_());
3,342✔
311

312
    return true;
313
}
314

315
TEMPLATE
316
INLINE bool CLASS::
2,050✔
317
pop_strict_bool_() NOEXCEPT
318
{
319
    const auto value = primary_.peek_strict_bool();
2,050✔
320
    drop_();
321
    return value;
322
}
323

324
TEMPLATE
325
INLINE bool CLASS::
446✔
326
pop_bool_(bool& value, bool minimal) NOEXCEPT
327
{
328
    if (!minimal)
446✔
329
        value = peek_bool_();
446✔
NEW
330
    else if (!primary_.peek_minimal_bool(value))
×
331
        return false;
332

333
    drop_();
334
    return true;
335
}
336

337
// private
338
TEMPLATE
339
INLINE bool CLASS::
4,738✔
340
pop_signed32_(int32_t& value) NOEXCEPT
341
{
342
    const auto result = peek_signed32_(value);
343
    drop_();
344
    return result;
345
}
346

347
TEMPLATE
348
INLINE bool CLASS::
4,272✔
349
pop_signed32(int32_t& value) NOEXCEPT
350
{
351
    if (is_stack_empty())
4,272✔
352
        return false;
353

354
    return pop_signed32_(value);
355
}
356

357
TEMPLATE
358
INLINE bool CLASS::
242✔
359
pop_binary32(int32_t& left, int32_t& right) NOEXCEPT
360
{
361
    if (stack_size() < 2)
242✔
362
        return false;
363

364
    // The right hand side operand is at the top of the stack.
365
    return pop_signed32_(right) && pop_signed32_(left);
430✔
366
}
367

368
TEMPLATE
369
INLINE bool CLASS::
18✔
370
pop_ternary32(int32_t& upper, int32_t& lower,
371
    int32_t& value) NOEXCEPT
372
{
373
    if (stack_size() < 3)
18✔
374
        return false;
375

376
    // The upper bound is at stack top, lower bound next, value next.
377
    return pop_signed32_(upper) && pop_signed32_(lower) &&
48✔
378
        pop_signed32_(value);
379
}
380

381
// ****************************************************************************
382
// CONSENSUS: Satoshi limits this value to the int32_t domain (getint()).
383
// This value is only used for stack indexing (key/sig counts & pick/roll).
384
// The upper bound of int32_t always exceeds the possible stack size, which
385
// is checked downstream. Similarly, a negative causes a downstream script
386
// failure. As such it is sufficient to fail on non-idexability here,
387
// allowing the value to be returned as a valid and unsigned stack index.
388
// ****************************************************************************
389
TEMPLATE
390
INLINE bool CLASS::
4,160✔
391
pop_index32(size_t& index) NOEXCEPT
392
{
393
    int32_t value;
394
    if (!pop_signed32(value))
4,160✔
395
        return false;
396

397
    if (is_negative(value))
4,160✔
398
        return false;
399

400
    // Cast guarded by stack size.
401
    index = limit<size_t>(value);
46✔
402

403
    // True if popped value valid post-pop stack index (precluded if size < 2).
404
    return index < stack_size();
4,156✔
405
}
406

407
// private
408
TEMPLATE
409
INLINE bool CLASS::
246✔
410
peek_signed32_(int32_t& value) const NOEXCEPT
411
{
412
    return primary_.peek_signed4(value);
4,492✔
413
}
414

415
// private
416
TEMPLATE
417
INLINE bool CLASS::
12✔
418
peek_signed40_(int64_t& value) const NOEXCEPT
419
{
420
    return primary_.peek_signed5(value);
12✔
421
}
422

423
// ****************************************************************************
424
// CONSENSUS: Read of 40 bit (vs. 32 bit) value for comparison against uint32_t
425
// input.sequence allows use of the full unsigned 32 bit domain, without use of
426
// the negative range.
427
// ****************************************************************************
428
TEMPLATE
NEW
429
INLINE bool CLASS::
×
430
peek_unsigned32(uint32_t& value) const NOEXCEPT
431
{
432
    if (is_stack_empty())
×
433
        return false;
434

435
    int64_t signed64;
436
    if (!peek_signed40_(signed64) || is_negative(signed64))
×
437
        return false;
438

439
    // 32 bits are used in unsigned input.sequence compare.
440
    value = narrow_sign_cast<uint32_t>(signed64);
441
    return true;
×
442
}
443

444
// ****************************************************************************
445
// CONSENSUS: Read of 40 bit (vs. 32 bit) value for comparison against uint32_t
446
// input.locktime allows use of the full unsigned 32 bit domain, without use of
447
// the negative range. Otherwise a 2038 limit (vs. the inherent 2106 limit)
448
// would have been introduced.
449
// ****************************************************************************
450
TEMPLATE
451
INLINE bool CLASS::
18✔
452
peek_unsigned40(uint64_t& value) const NOEXCEPT
453
{
454
    if (is_stack_empty())
18✔
455
        return false;
456

457
    int64_t signed64;
458
    if (!peek_signed40_(signed64) || is_negative(signed64))
12✔
459
        return false;
460

461
    // 40 bits are usable in unsigned tx.locktime compare.
462
    value = sign_cast<uint64_t>(signed64);
463
    return true;
7✔
464
}
465

466
// Primary stack (variant - index).
467
// ----------------------------------------------------------------------------
468
// Stack index is zero-based, back() is element zero.
469

470
// This swaps the variant elements of the stack vector.
471
TEMPLATE
472
INLINE void CLASS::
174✔
473
swap_(size_t left_index, size_t right_index) NOEXCEPT
474
{
475
    primary_.swap(left_index, right_index);
476
}
477

478
TEMPLATE
479
INLINE void CLASS::
16✔
480
erase_(size_t index) NOEXCEPT
481
{
482
    primary_.erase(index);
483
}
484

485
TEMPLATE
486
INLINE const stack_variant& CLASS::
9,916✔
487
peek_(size_t index) const NOEXCEPT
488
{
489
    return primary_.peek(index);
490
}
491

492
// Primary stack (variant - top).
493
// ----------------------------------------------------------------------------
494

495
TEMPLATE
496
INLINE void CLASS::
10,927✔
497
drop_() NOEXCEPT
498
{
499
    primary_.drop();
500
}
501

502
TEMPLATE
503
INLINE void CLASS::
9,957✔
504
push_variant(const stack_variant& vary) NOEXCEPT
505
{
506
    primary_.push(vary);
507
}
4✔
508

509
TEMPLATE
510
INLINE const stack_variant& CLASS::
35✔
511
peek_() const NOEXCEPT
512
{
513
    return primary_.top();
514
}
515

516
TEMPLATE
517
INLINE stack_variant CLASS::
1,138✔
518
pop_() NOEXCEPT
519
{
520
    return primary_.pop();
521
}
522

523
// Primary stack state (untyped).
524
// ----------------------------------------------------------------------------
525

526
TEMPLATE
527
INLINE size_t CLASS::
12,749✔
528
stack_size() const NOEXCEPT
529
{
530
    return primary_.size();
531
}
532

533
TEMPLATE
534
INLINE bool CLASS::
8,289✔
535
is_stack_empty() const NOEXCEPT
536
{
537
    return primary_.empty();
538
}
539

540
TEMPLATE
541
INLINE bool CLASS::
20,900✔
542
is_stack_overflow() const NOEXCEPT
543
{
544
    // Addition is safe due to stack size constraint.
545
    return (stack_size() + alternate_.size()) > max_unified_stack_size;
20,900✔
546
}
547

548
// private
549
TEMPLATE
550
INLINE bool CLASS::
21✔
551
is_stack_clean() const NOEXCEPT
552
{
553
    return is_one(stack_size());
554
}
555

556
// Alternate stack.
557
// ----------------------------------------------------------------------------
558

559
TEMPLATE
560
INLINE bool CLASS::
10✔
561
is_alternate_empty() const NOEXCEPT
562
{
563
    return alternate_.empty();
564
}
565

566
// Moving a shared pointer to the alternate stack is optimal and acceptable.
567
BC_PUSH_WARNING(NO_RVALUE_REF_SHARED_PTR)
568
TEMPLATE
569
INLINE void CLASS::
18✔
570
push_alternate(stack_variant&& vary) NOEXCEPT
571
BC_POP_WARNING()
572
{
573
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
574
    alternate_.push_back(std::move(vary));
18✔
575
    BC_POP_WARNING()
576
}
577

578
TEMPLATE
579
INLINE stack_variant CLASS::
6✔
580
pop_alternate_() NOEXCEPT
581
{
582
    BC_ASSERT(!alternate_.empty());
583

584
    stack_variant value{ std::move(alternate_.back()) };
6✔
585
    alternate_.pop_back();
6✔
586
    return value;
6✔
587
}
588

589
// Conditional stack.
590
// ----------------------------------------------------------------------------
591

592
TEMPLATE
593
INLINE void CLASS::
474✔
594
begin_if(bool value) NOEXCEPT
595
{
596
    // Addition is safe due to script size constraint.
597
    BC_ASSERT(value || !is_add_overflow(negative_conditions_, one));
598

599
    negative_conditions_ += (value ? 0 : 1);
474✔
600
    condition_.push_back(value);
474✔
601
}
602

603
// ****************************************************************************
604
// CONSENSUS: "You may have noticed the strange behavior of Bitcoin's ELSE
605
// statement. Bitcoin allows one to switch between true and false conditions
606
// several times. For example, the following script is valid and leaves the
607
// value 2 on the stack: 1 OP_IF OP_ELSE OP_ELSE 2 OP_ENDIF"
608
// bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts
609
// ****************************************************************************
610
TEMPLATE
611
INLINE void CLASS::
442✔
612
else_if_() NOEXCEPT
613
{
614
    // Subtraction must be guarded by caller logical constraints.
615
    BC_ASSERT(!is_balanced());
616

617
    // Addition is safe due to script size constraint.
618
    BC_ASSERT(condition_.back() || !is_add_overflow(negative_conditions_, one));
619

620
    negative_conditions_ += (condition_.back() ? 1 : -1);
442✔
621
    condition_.back() = !condition_.back();
442✔
622
}
623

624
TEMPLATE
625
INLINE void CLASS::
308✔
626
end_if_() NOEXCEPT
627
{
628
    // Subtraction must be guarded by caller logical constraints.
629
    BC_ASSERT(!is_balanced());
630

631
    negative_conditions_ += (condition_.back() ? 0 : -1);
308✔
632
    condition_.pop_back();
308✔
633
}
634

635
TEMPLATE
636
INLINE bool CLASS::
3,368✔
637
is_balanced() const NOEXCEPT
638
{
639
    return condition_.empty();
3,368✔
640
}
641

642
TEMPLATE
643
INLINE bool CLASS::
21,630✔
644
is_succeess() const NOEXCEPT
645
{
646
    // Optimization changes O(n) search [for every operation] to O(1).
647
    // bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts
648
    return is_zero(negative_conditions_);
21,630✔
649
}
650

651
TEMPLATE
652
INLINE bool CLASS::
22,402✔
653
if_(const operation& op) const NOEXCEPT
654
{
655
    // Conditional op execution is not predicated on conditional stack.
656
    return op.is_conditional() || is_succeess();
22,402✔
657
}
658

659
//  Accumulator.
660
// ----------------------------------------------------------------------------
661

662
// ****************************************************************************
663
// CONSENSUS:
664
// Satoshi compares the count to 200 with a composed postfix increment, which
665
// makes the actual maximum 201, not the presumably-intended 200. The code was
666
// later revised to make this explicit, by use of a prefix increment against a
667
// limit of 201.
668
// ****************************************************************************
669
INLINE constexpr bool operation_count_exceeded(size_t count) NOEXCEPT
670
{
671
    return count > max_counted_ops;
672
}
673

674
TEMPLATE
675
INLINE bool CLASS::
22,409✔
676
ops_increment(const operation& op) NOEXCEPT
677
{
678
    // Addition is safe due to script size constraint.
679
    BC_ASSERT(!is_add_overflow(operations_, one));
680

681
    if (operation::is_counted(op.code()))
22,409✔
682
        ++operations_;
10,530✔
683

684
    return operations_ <= max_counted_ops;
22,409✔
685
}
686

687
TEMPLATE
688
INLINE bool CLASS::
2,058✔
689
ops_increment(size_t public_keys) NOEXCEPT
690
{
691
    // Addition is safe due to script size constraint.
692
    BC_ASSERT(!is_add_overflow(operations_, public_keys));
693

694
    operations_ += public_keys;
2,058✔
695
    return !operation_count_exceeded(operations_);
696
}
697

698
// Signature validation helpers.
699
// ----------------------------------------------------------------------------
700

701
// Subscripts are referenced by script.offset mutable metadata. This allows for
702
// efficient subscripting with no copying. However, concurrent execution of any
703
// one input script instance is not thread safe (unnecessary scenario).
704
TEMPLATE
705
inline bool CLASS::
9✔
706
set_subscript(const op_iterator& op) NOEXCEPT
707
{
708
    // End is not reachable if op is an element of script_.
709
    if (script_->ops().empty() || op == script_->ops().end())
9✔
710
        return false;
×
711

712
    // Advance the offset to the op following the found code separator.
713
    // This is non-const because changes script state (despite being mutable).
714
    script_->offset = std::next(op);
9✔
715
    return true;
9✔
716
}
717

718
inline chain::strippers create_strip_ops(
1,958✔
719
    const chunk_xptrs& endorsements) NOEXCEPT
720
{
721
    chain::strippers strip{};
1,958✔
722

723
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
724
    strip.reserve(add1(endorsements.size()));
1,958✔
725

726
    for (const auto& endorsement: endorsements)
1,980✔
727
        strip.emplace_back(endorsement);
22✔
728

729
    strip.emplace_back(opcode::codeseparator);
1,958✔
730
    BC_POP_WARNING()
731

732
    return strip;
1,958✔
733
}
734

735
// ****************************************************************************
736
// CONSENSUS: Endorsement and code separator stripping are always performed in
737
// conjunction and are limited to non-witness signature hash subscripts.
738
// The order of operations is inconsequential, as they are all removed.
739
// Subscripts are not evaluated, they are limited to signature hash creation.
740
// ****************************************************************************
741
TEMPLATE
742
inline script::cptr CLASS::
1,975✔
743
subscript(const chunk_xptrs& endorsements) const NOEXCEPT
744
{
745
    // bip141: establishes the version property.
746
    // bip143: op stripping is not applied to bip141 v0 scripts.
747
    if (is_enabled(flags::bip143_rule) && version_ == script_version::zero)
1,975✔
748
        return script_;
749

750
    // Transform into a set of endorsement push ops and one op_codeseparator.
751
    const auto strip = create_strip_ops(endorsements);
1,958✔
752
    const auto stop = script_->ops().end();
1,958✔
753
    const op_iterator offset{ script_->offset };
1,958✔
754

755
    // If none of the strip ops are found, return the subscript.
756
    // Prefail is not circumvented as subscript used only for signature hash.
757
    if (!is_intersecting<operations>(offset, stop, strip))
1,958✔
758
        return script_;
759

760
    // Create new script from stripped copy of subscript operations.
761
    // Prefail is not copied to the subscript, used only for signature hash.
762
    return to_shared<script>(difference<operations>(offset, stop, strip));
8✔
763
}
1,958✔
764

765
// TODO: use sighash and key to generate signature in sign mode.
766
TEMPLATE
767
inline bool CLASS::
26✔
768
prepare(ec_signature& signature, const data_chunk&, hash_digest& hash,
769
    const chunk_xptr& endorsement) const NOEXCEPT
770
{
771
    uint8_t sighash_flags;
772
    data_slice distinguished;
26✔
773

774
    // Parse Bitcoin endorsement into DER signature and sighash flags.
775
    if (!parse_endorsement(sighash_flags, distinguished, *endorsement))
26✔
776
        return false;
777

778
    // Obtain the signature hash from subscript and sighash flags.
779
    hash = signature_hash(*subscript({ endorsement }), sighash_flags);
78✔
780

781
    // Parse DER signature into an EC signature (bip66 sets strict).
782
    const auto bip66 = is_enabled(flags::bip66_rule);
783
    return parse_signature(signature, distinguished, bip66);
26✔
784
}
785

786
// TODO: use sighash and key to generate signature in sign mode.
787
TEMPLATE
788
inline bool CLASS::
20✔
789
prepare(ec_signature& signature, const data_chunk&, hash_cache& cache,
790
    uint8_t& sighash_flags, const data_chunk& endorsement,
791
    const script& sub) const NOEXCEPT
792
{
793
    data_slice distinguished;
20✔
794

795
    // Parse Bitcoin endorsement into DER signature and sighash flags.
796
    if (!parse_endorsement(sighash_flags, distinguished, endorsement))
20✔
797
        return false;
798

799
    // Obtain the signature hash from subscript and sighash flags.
800
    signature_hash(cache, sub, sighash_flags);
20✔
801

802
    // Parse DER signature into an EC signature (bip66 sets strict).
803
    const auto bip66 = is_enabled(flags::bip66_rule);
804
    return parse_signature(signature, distinguished, bip66);
20✔
805
}
806

807
// Signature hashing.
808
// ----------------------------------------------------------------------------
809

810
TEMPLATE
811
INLINE hash_digest CLASS::
26✔
812
signature_hash(const script& sub, uint8_t flags) const NOEXCEPT
813
{
814
    // The bip141 fork establishes witness version, hashing is a distinct fork.
815
    const auto bip143 = is_enabled(flags::bip143_rule);
816

817
    // bip143: the method of signature hashing is changed for v0 scripts.
818
    return transaction_.signature_hash(input_, sub, value_, flags, version_,
36✔
819
        bip143);
820
}
821

822
// Caches signature hashes in a map against sighash flags.
823
// Prevents recomputation in the common case where flags are the same.
824
TEMPLATE
825
INLINE void CLASS::
20✔
826
signature_hash(hash_cache& cache, const script& sub,
827
    uint8_t sighash_flags) const NOEXCEPT
828
{
829
    BC_PUSH_WARNING(NO_THROW_IN_NOEXCEPT)
830
    if (cache.find(sighash_flags) == cache.end())
20✔
831
        cache.emplace(sighash_flags, signature_hash(sub, sighash_flags));
10✔
832
    BC_POP_WARNING()
833
}
834

835
} // namespace machine
836
} // namespace system
837
} // namespace libbitcoin
838

839
#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