1#![allow(
5 clippy::declare_interior_mutable_const, clippy::type_complexity,
7 clippy::too_many_arguments,
8 clippy::needless_return, )]
10mod arithmetic;
17mod context;
18mod control_flow;
19mod crypto_ops;
20pub mod flags;
21mod signature;
22mod stack;
23
24pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
25pub use stack::{StackElement, cast_to_bool, to_stack_element};
26
27use crate::constants::*;
28use crate::crypto::OptimizedSha256;
29use crate::error::{ConsensusError, Result, ScriptErrorCode};
30use crate::opcodes::*;
31use crate::types::*;
32use blvm_spec_lock::spec_locked;
33use digest::Digest;
34use ripemd::Ripemd160;
35
36#[cfg(feature = "production")]
38use crate::optimizations::{precomputed_constants, prefetch};
39
40#[cold]
42#[allow(dead_code)]
43fn make_operation_limit_error() -> ConsensusError {
44 ConsensusError::ScriptErrorWithCode {
45 code: ScriptErrorCode::OpCount,
46 message: "Operation limit exceeded".into(),
47 }
48}
49
50#[cold]
51fn make_stack_overflow_error() -> ConsensusError {
52 ConsensusError::ScriptErrorWithCode {
53 code: ScriptErrorCode::StackSize,
54 message: "Stack overflow".into(),
55 }
56}
57
58#[inline]
59fn bip143_p2wpkh_script_code(pubkey_hash: &[u8]) -> [u8; 25] {
60 let mut hash = [0u8; 20];
61 hash.copy_from_slice(pubkey_hash);
62 crate::transaction_hash::derive_bip143_script_code_p2wpkh(&hash)
63}
64
65#[cfg(feature = "production")]
66use std::collections::VecDeque;
67#[cfg(feature = "production")]
68use std::sync::{
69 OnceLock, RwLock,
70 atomic::{AtomicBool, AtomicU64, Ordering},
71};
72#[cfg(feature = "production")]
73use std::thread_local;
74
75#[cfg(feature = "production")]
81static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
82
83#[cfg(feature = "production")]
86const SIG_CACHE_SHARDS: usize = 32;
87
88#[cfg(feature = "production")]
89const SIG_CACHE_SHARD: OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>> = OnceLock::new();
90
91#[cfg(feature = "production")]
92static SIG_CACHE: [OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>>; SIG_CACHE_SHARDS] =
93 [SIG_CACHE_SHARD; SIG_CACHE_SHARDS];
94
95#[cfg(feature = "production")]
97fn sig_cache_size() -> usize {
98 std::env::var("BLVM_SIG_CACHE_ENTRIES")
99 .ok()
100 .and_then(|s| s.parse().ok())
101 .filter(|&n: &usize| n > 0 && n <= 1_000_000)
102 .unwrap_or(500_000)
103}
104
105#[cfg(feature = "production")]
106fn sig_cache_shard_index(key: &[u8; 32]) -> usize {
107 let h = (key[0] as usize) | ((key[1] as usize) << 8) | ((key[2] as usize) << 16);
108 h % SIG_CACHE_SHARDS
109}
110
111#[cfg(feature = "production")]
112fn get_sig_cache_shard(key: &[u8; 32]) -> &'static RwLock<lru::LruCache<[u8; 32], bool>> {
113 let idx = sig_cache_shard_index(key);
114 SIG_CACHE[idx].get_or_init(|| {
115 use lru::LruCache;
116 use std::num::NonZeroUsize;
117 let cap = (sig_cache_size() / SIG_CACHE_SHARDS).max(1);
118 RwLock::new(LruCache::new(NonZeroUsize::new(cap).unwrap()))
119 })
120}
121
122#[cfg(feature = "production")]
123thread_local! {
124 static BATCH_PUT_SIG_CACHE_BY_SHARD: std::cell::RefCell<[Vec<([u8; 32], bool)>; SIG_CACHE_SHARDS]> =
125 std::cell::RefCell::new(std::array::from_fn(|_| Vec::new()));
126}
127
128#[cfg(feature = "production")]
130thread_local! {
131 static SOA_BATCH_BUF: std::cell::RefCell<(
132 Vec<[u8; 64]>,
133 Vec<[u8; 32]>,
134 Vec<[u8; 33]>,
135 Vec<usize>,
136 Vec<[u8; 32]>,
137 )> = const { std::cell::RefCell::new((
138 Vec::new(),
139 Vec::new(),
140 Vec::new(),
141 Vec::new(),
142 Vec::new(),
143 )) };
144}
145
146#[cfg(feature = "production")]
147fn batch_put_sig_cache(keys: &[[u8; 32]], results: &[bool]) {
148 BATCH_PUT_SIG_CACHE_BY_SHARD.with(|cell| {
149 let mut by_shard = cell.borrow_mut();
150 for v in by_shard.iter_mut() {
151 v.clear();
152 }
153 for (i, key) in keys.iter().enumerate() {
154 let result = results.get(i).copied().unwrap_or(false);
155 let idx = sig_cache_shard_index(key);
156 by_shard[idx].push((*key, result));
157 }
158 for shard_entries in by_shard.iter() {
159 if shard_entries.is_empty() {
160 continue;
161 }
162 let first_key = &shard_entries[0].0;
163 if let Ok(mut guard) = get_sig_cache_shard(first_key).write() {
164 for (k, v) in shard_entries.iter() {
165 guard.put(*k, *v);
166 }
167 }
168 }
169 });
170}
171
172#[cfg(feature = "production")]
178fn sig_cache_at_collect_enabled() -> bool {
179 use std::sync::OnceLock;
180 static CACHE: OnceLock<bool> = OnceLock::new();
181 *CACHE.get_or_init(|| {
182 std::env::var("BLVM_SIG_CACHE_AT_COLLECT")
183 .map(|s| s == "1" || s.eq_ignore_ascii_case("true"))
184 .unwrap_or(false)
185 })
186}
187
188#[cfg(feature = "production")]
191#[inline(always)]
192fn ecdsa_cache_key(msg: &[u8; 32], pk: &[u8; 33], sig_compact: &[u8; 64], flags: u32) -> [u8; 32] {
193 use siphasher::sip::SipHasher24;
194 use std::hash::{Hash, Hasher};
195 let mut key_input = [0u8; 133];
196 key_input[..32].copy_from_slice(msg);
197 key_input[32..65].copy_from_slice(pk);
198 key_input[65..129].copy_from_slice(sig_compact);
199 key_input[129..133].copy_from_slice(&flags.to_le_bytes());
200 let mut hasher = SipHasher24::new();
201 key_input.hash(&mut hasher);
202 let h = hasher.finish();
203 let mut out = [0u8; 32];
204 out[..8].copy_from_slice(&h.to_le_bytes());
205 out
206}
207
208#[cfg(feature = "production")]
211static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
212#[cfg(feature = "production")]
213static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
214#[cfg(feature = "production")]
215static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
216#[cfg(feature = "production")]
217static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
218#[cfg(feature = "production")]
219static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
220static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
221#[cfg(feature = "production")]
222static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
223#[cfg(feature = "production")]
224static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
225
226#[cfg(feature = "production")]
227fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
228 SCRIPT_CACHE.get_or_init(|| {
229 use lru::LruCache;
233 use std::num::NonZeroUsize;
234 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
235 })
236}
237
238#[cfg(feature = "production")]
243thread_local! {
244 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
245 std::cell::RefCell::new(VecDeque::with_capacity(10));
246}
247
248#[cfg(feature = "production")]
250fn get_pooled_stack() -> Vec<StackElement> {
251 STACK_POOL.with(|pool| {
252 let mut pool = pool.borrow_mut();
253 if let Some(mut stack) = pool.pop_front() {
254 stack.clear();
255 if stack.capacity() < 20 {
256 stack.reserve(20);
257 }
258 stack
259 } else {
260 Vec::with_capacity(20)
261 }
262 })
263}
264
265#[cfg(feature = "production")]
267struct PooledStackGuard(Vec<StackElement>);
268#[cfg(feature = "production")]
269impl Drop for PooledStackGuard {
270 fn drop(&mut self) {
271 return_pooled_stack(std::mem::take(&mut self.0));
272 }
273}
274
275#[cfg(feature = "production")]
277fn return_pooled_stack(mut stack: Vec<StackElement>) {
278 stack.clear();
280
281 STACK_POOL.with(|pool| {
282 let mut pool = pool.borrow_mut();
283 if pool.len() < 10 {
285 pool.push_back(stack);
286 }
287 });
289}
290
291#[cfg(feature = "production")]
296static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
297
298#[cfg(feature = "production")]
300static FAST_PATHS_DISABLED: AtomicBool = AtomicBool::new(false);
301
302#[cfg(feature = "production")]
318pub fn disable_caching(disabled: bool) {
319 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
320}
321
322#[cfg(feature = "production")]
324pub fn disable_fast_paths(disabled: bool) {
325 FAST_PATHS_DISABLED.store(disabled, Ordering::Relaxed);
326}
327
328#[cfg(feature = "production")]
330fn is_caching_disabled() -> bool {
331 CACHE_DISABLED.load(Ordering::Relaxed)
332}
333
334#[cfg(feature = "production")]
335fn fast_paths_disabled() -> bool {
336 FAST_PATHS_DISABLED.load(Ordering::Relaxed)
337}
338
339#[cfg(feature = "production")]
344fn compute_script_cache_key(
345 script_sig: &ByteString,
346 script_pubkey: &[u8],
347 witness: Option<&ByteString>,
348 flags: u32,
349) -> u64 {
350 use std::collections::hash_map::DefaultHasher;
351 use std::hash::{Hash, Hasher};
352
353 let mut hasher = DefaultHasher::new();
354 script_sig.hash(&mut hasher);
355 script_pubkey.hash(&mut hasher);
356 if let Some(w) = witness {
357 w.hash(&mut hasher);
358 }
359 flags.hash(&mut hasher);
360 hasher.finish()
361}
362
363#[derive(Debug, Clone, Copy, PartialEq, Eq)]
365pub enum SigVersion {
366 Base,
368 WitnessV0,
370 Tapscript,
372}
373
374#[spec_locked("5.2", "EvalScript")]
391#[cfg_attr(feature = "production", inline(always))]
392#[cfg_attr(not(feature = "production"), inline)]
393pub fn eval_script(
394 script: &[u8],
395 stack: &mut Vec<StackElement>,
396 flags: u32,
397 sigversion: SigVersion,
398) -> Result<bool> {
399 if stack.capacity() < 20 {
402 stack.reserve(20);
403 }
404 #[cfg(feature = "production")]
405 {
406 eval_script_impl(script, stack, flags, sigversion)
407 }
408 #[cfg(not(feature = "production"))]
409 {
410 eval_script_inner(script, stack, flags, sigversion)
411 }
412}
413#[cfg(feature = "production")]
414fn eval_script_impl(
415 script: &[u8],
416 stack: &mut Vec<StackElement>,
417 flags: u32,
418 sigversion: SigVersion,
419) -> Result<bool> {
420 eval_script_inner(script, stack, flags, sigversion)
421}
422
423#[cfg(not(feature = "production"))]
424#[allow(dead_code)]
425fn eval_script_impl(
426 script: &[u8],
427 stack: &mut Vec<StackElement>,
428 flags: u32,
429 sigversion: SigVersion,
430) -> Result<bool> {
431 eval_script_inner(script, stack, flags, sigversion)
432}
433
434#[inline(always)]
436fn is_push_opcode(opcode: u8) -> bool {
437 opcode <= 0x60
438}
439
440#[inline]
443fn is_op_success(opcode: u8) -> bool {
444 matches!(
445 opcode,
446 80 | 98
447 | 126..=129
448 | 131..=134
449 | 137..=138
450 | 141..=142
451 | 149..=153
452 | 187..=254
453 )
454}
455
456#[inline]
459fn op_advance(script: &[u8], pc: usize) -> usize {
460 let opcode = script[pc];
461 match opcode {
462 0x01..=0x4b => 1 + opcode as usize,
464 0x4c => {
466 if pc + 1 < script.len() {
467 2 + script[pc + 1] as usize
468 } else {
469 1
470 }
471 }
472 0x4d => {
474 if pc + 2 < script.len() {
475 3 + u16::from_le_bytes([script[pc + 1], script[pc + 2]]) as usize
476 } else {
477 1
478 }
479 }
480 0x4e => {
482 if pc + 4 < script.len() {
483 5 + u32::from_le_bytes([
484 script[pc + 1],
485 script[pc + 2],
486 script[pc + 3],
487 script[pc + 4],
488 ]) as usize
489 } else {
490 1
491 }
492 }
493 _ => 1,
494 }
495}
496
497fn eval_script_inner(
498 script: &[u8],
499 stack: &mut Vec<StackElement>,
500 flags: u32,
501 sigversion: SigVersion,
502) -> Result<bool> {
503 use crate::constants::MAX_SCRIPT_SIZE;
504 use crate::error::{ConsensusError, ScriptErrorCode};
505
506 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
507 && script.len() > MAX_SCRIPT_SIZE
508 {
509 return Err(ConsensusError::ScriptErrorWithCode {
510 code: ScriptErrorCode::ScriptSize,
511 message: "Script size exceeds maximum".into(),
512 });
513 }
514
515 let mut op_count = 0;
516 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
517 let mut altstack: Vec<StackElement> = Vec::new();
518
519 let mut i = 0;
520 while i < script.len() {
521 let opcode = script[i];
522 let in_false_branch = control_flow::in_false_branch(&control_stack);
523
524 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
527 op_count += 1;
528 if op_count > MAX_SCRIPT_OPS {
529 return Err(make_operation_limit_error());
530 }
531 debug_assert!(
532 op_count <= MAX_SCRIPT_OPS,
533 "Operation count ({op_count}) must not exceed MAX_SCRIPT_OPS ({MAX_SCRIPT_OPS})"
534 );
535 }
536
537 if stack.len() + altstack.len() > MAX_STACK_SIZE {
540 return Err(make_stack_overflow_error());
541 }
542
543 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
545 let (data, advance) = if opcode <= 0x4b {
546 let len = opcode as usize;
547 if i + 1 + len > script.len() {
548 return Ok(false);
549 }
550 (&script[i + 1..i + 1 + len], 1 + len)
551 } else if opcode == OP_PUSHDATA1 {
552 if i + 1 >= script.len() {
553 return Ok(false);
554 }
555 let len = script[i + 1] as usize;
556 if i + 2 + len > script.len() {
557 return Ok(false);
558 }
559 (&script[i + 2..i + 2 + len], 2 + len)
560 } else if opcode == OP_PUSHDATA2 {
561 if i + 2 >= script.len() {
562 return Ok(false);
563 }
564 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
565 if i + 3 + len > script.len() {
566 return Ok(false);
567 }
568 (&script[i + 3..i + 3 + len], 3 + len)
569 } else {
570 if i + 4 >= script.len() {
571 return Ok(false);
572 }
573 let len = u32::from_le_bytes([
574 script[i + 1],
575 script[i + 2],
576 script[i + 3],
577 script[i + 4],
578 ]) as usize;
579 let data_start = i.saturating_add(5);
580 let data_end = data_start.saturating_add(len);
581 let advance = 5usize.saturating_add(len);
582 if advance < 5 || data_end > script.len() || data_end < data_start {
583 return Ok(false);
584 }
585 (&script[data_start..data_end], advance)
586 };
587
588 if !in_false_branch {
589 stack.push(to_stack_element(data));
590 }
591 i += advance;
592 continue;
593 }
594
595 match opcode {
596 OP_IF => {
598 if in_false_branch {
599 control_stack.push(control_flow::ControlBlock::If { executing: false });
600 } else if stack.is_empty() {
601 return Err(ConsensusError::ScriptErrorWithCode {
602 code: ScriptErrorCode::InvalidStackOperation,
603 message: "OP_IF: empty stack".into(),
604 });
605 } else {
606 let condition_bytes = stack.pop().unwrap();
607 let condition = cast_to_bool(&condition_bytes);
608
609 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
610 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
611 && (sigversion == SigVersion::WitnessV0
612 || sigversion == SigVersion::Tapscript)
613 && !control_flow::is_minimal_if_condition(&condition_bytes)
614 {
615 return Err(ConsensusError::ScriptErrorWithCode {
616 code: ScriptErrorCode::MinimalIf,
617 message: "OP_IF condition must be minimally encoded".into(),
618 });
619 }
620
621 control_stack.push(control_flow::ControlBlock::If {
622 executing: condition,
623 });
624 }
625 }
626 OP_NOTIF => {
628 if in_false_branch {
629 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
630 } else if stack.is_empty() {
631 return Err(ConsensusError::ScriptErrorWithCode {
632 code: ScriptErrorCode::InvalidStackOperation,
633 message: "OP_NOTIF: empty stack".into(),
634 });
635 } else {
636 let condition_bytes = stack.pop().unwrap();
637 let condition = cast_to_bool(&condition_bytes);
638
639 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
640 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
641 && (sigversion == SigVersion::WitnessV0
642 || sigversion == SigVersion::Tapscript)
643 && !control_flow::is_minimal_if_condition(&condition_bytes)
644 {
645 return Err(ConsensusError::ScriptErrorWithCode {
646 code: ScriptErrorCode::MinimalIf,
647 message: "OP_NOTIF condition must be minimally encoded".into(),
648 });
649 }
650
651 control_stack.push(control_flow::ControlBlock::NotIf {
652 executing: !condition,
653 });
654 }
655 }
656 OP_ELSE => {
658 if let Some(block) = control_stack.last_mut() {
659 match block {
660 control_flow::ControlBlock::If { executing }
661 | control_flow::ControlBlock::NotIf { executing } => {
662 *executing = !*executing;
663 }
664 }
665 } else {
666 return Err(ConsensusError::ScriptErrorWithCode {
667 code: ScriptErrorCode::UnbalancedConditional,
668 message: "OP_ELSE without matching IF/NOTIF".into(),
669 });
670 }
671 }
672 OP_ENDIF => {
674 if control_stack.pop().is_none() {
675 return Err(ConsensusError::ScriptErrorWithCode {
676 code: ScriptErrorCode::UnbalancedConditional,
677 message: "OP_ENDIF without matching IF/NOTIF".into(),
678 });
679 }
680 }
681 OP_TOALTSTACK => {
683 if !in_false_branch {
684 if stack.is_empty() {
685 return Err(ConsensusError::ScriptErrorWithCode {
686 code: ScriptErrorCode::InvalidStackOperation,
687 message: "OP_TOALTSTACK: empty stack".into(),
688 });
689 }
690 altstack.push(stack.pop().unwrap());
691 }
692 }
693 OP_FROMALTSTACK => {
695 if !in_false_branch {
696 if altstack.is_empty() {
697 return Err(ConsensusError::ScriptErrorWithCode {
698 code: ScriptErrorCode::InvalidAltstackOperation,
699 message: "OP_FROMALTSTACK: empty altstack".into(),
700 });
701 }
702 stack.push(altstack.pop().unwrap());
703 }
704 }
705 _ => {
706 if in_false_branch {
707 i += 1;
708 continue;
709 }
710
711 if !execute_opcode(opcode, stack, flags, sigversion)? {
712 return Ok(false);
713 }
714
715 if stack.len() + altstack.len() > MAX_STACK_SIZE {
716 return Err(make_stack_overflow_error());
717 }
718 }
719 }
720 i += 1;
721 }
722
723 if !control_stack.is_empty() {
724 return Err(ConsensusError::ScriptErrorWithCode {
725 code: ScriptErrorCode::UnbalancedConditional,
726 message: "Unclosed IF/NOTIF block".into(),
727 });
728 }
729
730 Ok(true)
732}
733
734#[spec_locked("5.2", "VerifyScript")]
744#[cfg_attr(feature = "production", inline(always))]
745#[cfg_attr(not(feature = "production"), inline)]
746pub fn verify_script(
747 script_sig: &ByteString,
748 script_pubkey: &[u8],
749 witness: Option<&ByteString>,
750 flags: u32,
751) -> Result<bool> {
752 let sigversion = SigVersion::Base;
754
755 #[cfg(feature = "production")]
756 {
757 if !is_caching_disabled() {
759 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
760 {
761 let cache = get_script_cache().read().unwrap_or_else(|e| e.into_inner());
762 if let Some(&cached_result) = cache.peek(&cache_key) {
763 return Ok(cached_result);
764 }
765 }
766 }
767
768 let mut stack = get_pooled_stack();
771 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
772 let result = {
773 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
774 if !is_caching_disabled() {
776 let mut cache = get_script_cache()
777 .write()
778 .unwrap_or_else(|e| e.into_inner());
779 cache.put(cache_key, false);
780 }
781 false
782 } else if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
783 if !is_caching_disabled() {
784 let mut cache = get_script_cache()
785 .write()
786 .unwrap_or_else(|e| e.into_inner());
787 cache.put(cache_key, false);
788 }
789 false
790 } else if let Some(w) = witness {
791 if !eval_script(w, &mut stack, flags, sigversion)? {
792 if !is_caching_disabled() {
793 let mut cache = get_script_cache()
794 .write()
795 .unwrap_or_else(|e| e.into_inner());
796 cache.put(cache_key, false);
797 }
798 false
799 } else {
800 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
801 if !is_caching_disabled() {
802 let mut cache = get_script_cache()
803 .write()
804 .unwrap_or_else(|e| e.into_inner());
805 cache.put(cache_key, res);
806 }
807 res
808 }
809 } else {
810 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
811 if !is_caching_disabled() {
812 let mut cache = get_script_cache()
813 .write()
814 .unwrap_or_else(|e| e.into_inner());
815 cache.put(cache_key, res);
816 }
817 res
818 }
819 };
820
821 return_pooled_stack(stack);
823
824 Ok(result)
825 }
826
827 #[cfg(not(feature = "production"))]
828 {
829 let mut stack = Vec::with_capacity(20);
831
832 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
834 return Ok(false);
835 }
836
837 if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
839 return Ok(false);
840 }
841
842 if let Some(w) = witness {
844 if !eval_script(w, &mut stack, flags, sigversion)? {
845 return Ok(false);
846 }
847 }
848
849 Ok(!stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]))
851 }
852}
853
854#[spec_locked("5.2", "VerifyScript")]
867#[cfg_attr(feature = "production", inline(always))]
868#[cfg_attr(not(feature = "production"), inline)]
869#[allow(clippy::too_many_arguments)]
870pub fn verify_script_with_context(
871 script_sig: &ByteString,
872 script_pubkey: &[u8],
873 witness: Option<&crate::witness::Witness>,
874 flags: u32,
875 tx: &Transaction,
876 input_index: usize,
877 prevouts: &[TransactionOutput],
878 block_height: Option<u64>,
879 network: crate::types::Network,
880) -> Result<bool> {
881 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
883 let prevout_script_pubkeys: Vec<&[u8]> =
884 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
885
886 verify_script_with_context_full(
887 script_sig,
888 script_pubkey,
889 witness,
890 flags,
891 tx,
892 input_index,
893 &prevout_values,
894 &prevout_script_pubkeys,
895 block_height,
896 None, network,
898 SigVersion::Base, #[cfg(feature = "production")]
900 None, None, #[cfg(feature = "production")]
903 None, #[cfg(feature = "production")]
905 None, #[cfg(feature = "production")]
907 None, )
909}
910
911#[cfg(feature = "production")]
918#[allow(clippy::too_many_arguments)]
919pub fn try_verify_p2pk_fast_path(
920 script_sig: &ByteString,
921 script_pubkey: &[u8],
922 flags: u32,
923 tx: &Transaction,
924 input_index: usize,
925 prevout_values: &[i64],
926 prevout_script_pubkeys: &[&[u8]],
927 block_height: Option<u64>,
928 network: crate::types::Network,
929 #[cfg(feature = "production")] sighash_cache: Option<
930 &crate::transaction_hash::SighashMidstateCache,
931 >,
932) -> Option<Result<bool>> {
933 let len = script_pubkey.len();
936 if len != 35 && len != 67 {
937 return None;
938 }
939 if script_pubkey[len - 1] != OP_CHECKSIG {
940 return None;
941 }
942 let pubkey_len = len - 2; if pubkey_len != 33 && pubkey_len != 65 {
944 return None;
945 }
946 if script_pubkey[0] != 0x21 && script_pubkey[0] != 0x41 {
947 return None; }
949 let pubkey_bytes = &script_pubkey[1..(len - 1)];
950
951 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
952 if signature_bytes.is_empty() {
953 return Some(Ok(false));
954 }
955
956 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
958 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
959 let sighash_type = SighashType::from_byte(sighash_byte);
960 let deleted_storage;
961 let script_code: &[u8] = if script_pubkey.len() < 71 {
962 script_pubkey
963 } else {
964 let pattern = serialize_push_data(signature_bytes);
965 deleted_storage = find_and_delete(script_pubkey, &pattern);
966 deleted_storage.as_ref()
967 };
968 let sighash = match calculate_transaction_sighash_single_input(
969 tx,
970 input_index,
971 script_code,
972 prevout_values[input_index],
973 sighash_type,
974 #[cfg(feature = "production")]
975 sighash_cache,
976 ) {
977 Ok(h) => h,
978 Err(e) => return Some(Err(e)),
979 };
980
981 let height = block_height.unwrap_or(0);
982 let is_valid = signature::with_secp_context(|secp| {
983 signature::verify_signature(
984 secp,
985 pubkey_bytes,
986 signature_bytes,
987 &sighash,
988 flags,
989 height,
990 network,
991 SigVersion::Base,
992 )
993 });
994 Some(is_valid)
995}
996
997#[cfg(feature = "production")]
1000#[allow(clippy::too_many_arguments)]
1001pub fn try_verify_p2pkh_fast_path(
1002 script_sig: &ByteString,
1003 script_pubkey: &[u8],
1004 flags: u32,
1005 tx: &Transaction,
1006 input_index: usize,
1007 prevout_values: &[i64],
1008 prevout_script_pubkeys: &[&[u8]],
1009 block_height: Option<u64>,
1010 network: crate::types::Network,
1011 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1012 #[cfg(feature = "production")] sighash_cache: Option<
1013 &crate::transaction_hash::SighashMidstateCache,
1014 >,
1015 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
1016) -> Option<Result<bool>> {
1017 #[cfg(all(feature = "production", feature = "profile"))]
1018 let _t_entry = std::time::Instant::now();
1019 if script_pubkey.len() != 25 {
1021 return None;
1022 }
1023 if script_pubkey[0] != OP_DUP
1024 || script_pubkey[1] != OP_HASH160
1025 || script_pubkey[2] != PUSH_20_BYTES
1026 || script_pubkey[23] != OP_EQUALVERIFY
1027 || script_pubkey[24] != OP_CHECKSIG
1028 {
1029 return None;
1030 }
1031 let expected_hash = &script_pubkey[3..23];
1032
1033 #[cfg(all(feature = "production", feature = "profile"))]
1034 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
1035 #[cfg(all(feature = "production", feature = "profile"))]
1036 let _t_parse = std::time::Instant::now();
1037 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
1038 #[cfg(all(feature = "production", feature = "profile"))]
1039 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
1040
1041 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1043 return Some(Ok(false));
1044 }
1045 if signature_bytes.is_empty() {
1047 return Some(Ok(false));
1048 }
1049
1050 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
1052 Some(h) => h,
1053 None => {
1054 #[cfg(all(feature = "production", feature = "profile"))]
1055 let _t_hash = std::time::Instant::now();
1056 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1057 let h = Ripemd160::digest(sha256_hash);
1058 #[cfg(all(feature = "production", feature = "profile"))]
1059 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1060 h.into()
1061 }
1062 };
1063 if &pubkey_hash[..] != expected_hash {
1064 return Some(Ok(false));
1065 }
1066
1067 use crate::transaction_hash::SighashType;
1070 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1071 let sighash_type = SighashType::from_byte(sighash_byte);
1072 let deleted_storage;
1073 let script_code: &[u8] = if script_pubkey.len() < 71 {
1074 script_pubkey
1075 } else {
1076 let pattern = serialize_push_data(signature_bytes);
1077 deleted_storage = find_and_delete(script_pubkey, &pattern);
1078 deleted_storage.as_ref()
1079 };
1080 let sighash = {
1081 #[cfg(feature = "production")]
1082 {
1083 if let Some(precomp) = precomputed_sighash_all {
1084 precomp
1085 } else {
1086 crate::transaction_hash::compute_legacy_sighash_nocache(
1087 tx,
1088 input_index,
1089 script_code,
1090 sighash_byte,
1091 )
1092 }
1093 }
1094 #[cfg(not(feature = "production"))]
1095 {
1096 match calculate_transaction_sighash_single_input(
1097 tx,
1098 input_index,
1099 script_code,
1100 prevout_values[input_index],
1101 sighash_type,
1102 ) {
1103 Ok(h) => h,
1104 Err(e) => return Some(Err(e)),
1105 }
1106 }
1107 };
1108
1109 #[cfg(all(feature = "production", feature = "profile"))]
1110 let _t_secp = std::time::Instant::now();
1111 let height = block_height.unwrap_or(0);
1112 let is_valid: Result<bool> = {
1113 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1114 if flags & 0x04 != 0
1115 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1116 .unwrap_or(false)
1117 {
1118 Ok(false)
1119 } else if flags & 0x02 != 0 {
1120 let base_sighash = sighash_byte & !0x80;
1121 if !(0x01..=0x03).contains(&base_sighash) {
1122 Ok(false)
1123 } else if pubkey_bytes.len() == 33 {
1124 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
1125 Ok(false)
1126 } else {
1127 let strict_der = flags & 0x04 != 0;
1128 let enforce_low_s = flags & 0x08 != 0;
1129 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1130 der_sig,
1131 pubkey_bytes,
1132 &sighash,
1133 strict_der,
1134 enforce_low_s,
1135 )
1136 .unwrap_or(false))
1137 }
1138 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1139 let strict_der = flags & 0x04 != 0;
1140 let enforce_low_s = flags & 0x08 != 0;
1141 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1142 der_sig,
1143 pubkey_bytes,
1144 &sighash,
1145 strict_der,
1146 enforce_low_s,
1147 )
1148 .unwrap_or(false))
1149 } else {
1150 Ok(false)
1151 }
1152 } else {
1153 let strict_der = flags & 0x04 != 0;
1154 let enforce_low_s = flags & 0x08 != 0;
1155 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1156 der_sig,
1157 pubkey_bytes,
1158 &sighash,
1159 strict_der,
1160 enforce_low_s,
1161 )
1162 .unwrap_or(false))
1163 }
1164 };
1165 #[cfg(all(feature = "production", feature = "profile"))]
1166 {
1167 let ns = _t_secp.elapsed().as_nanos() as u64;
1168 crate::script_profile::add_p2pkh_collect_ns(ns);
1169 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1170 }
1171 Some(is_valid)
1172}
1173
1174#[cfg(feature = "production")]
1180#[inline]
1181pub fn verify_p2pkh_inline(
1182 script_sig: &[u8],
1183 script_pubkey: &[u8],
1184 flags: u32,
1185 tx: &Transaction,
1186 input_index: usize,
1187 height: u64,
1188 network: crate::types::Network,
1189 precomputed_sighash_all: Option<[u8; 32]>,
1190) -> Result<bool> {
1191 #[cfg(feature = "profile")]
1192 let _t0 = std::time::Instant::now();
1193
1194 let expected_hash = &script_pubkey[3..23];
1195
1196 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1197 Some(pair) => pair,
1198 None => return Ok(false),
1199 };
1200
1201 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1202 return Ok(false);
1203 }
1204
1205 #[cfg(feature = "profile")]
1206 let _t_hash = std::time::Instant::now();
1207
1208 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1209 let pubkey_hash: [u8; 20] = Ripemd160::digest(sha256_hash).into();
1210 if &pubkey_hash[..] != expected_hash {
1211 return Ok(false);
1212 }
1213
1214 #[cfg(feature = "profile")]
1215 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1216
1217 #[cfg(feature = "profile")]
1218 let _t_sighash = std::time::Instant::now();
1219
1220 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1221 let sighash = if let Some(precomp) = precomputed_sighash_all {
1222 precomp
1223 } else {
1224 crate::transaction_hash::compute_legacy_sighash_buffered(
1225 tx,
1226 input_index,
1227 script_pubkey,
1228 sighash_byte,
1229 )
1230 };
1231
1232 #[cfg(feature = "profile")]
1233 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1234
1235 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1236 let strict_der = flags & 0x04 != 0;
1237 let enforce_low_s = flags & 0x08 != 0;
1238
1239 if strict_der
1240 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1241 .unwrap_or(false)
1242 {
1243 return Ok(false);
1244 }
1245
1246 if flags & 0x02 != 0 {
1247 let sighash_base = sighash_byte & !0x80;
1248 if !(0x01..=0x03).contains(&sighash_base) {
1249 return Ok(false);
1250 }
1251 match pubkey_bytes.len() {
1252 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1253 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1254 33 | 65 => {}
1255 _ => return Ok(false),
1256 }
1257 }
1258
1259 #[cfg(feature = "profile")]
1260 let _t_secp = std::time::Instant::now();
1261
1262 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1263 der_sig,
1264 pubkey_bytes,
1265 &sighash,
1266 strict_der,
1267 enforce_low_s,
1268 )
1269 .unwrap_or(false);
1270
1271 #[cfg(feature = "profile")]
1272 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1273
1274 #[cfg(feature = "profile")]
1275 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1276
1277 Ok(result)
1278}
1279
1280#[cfg(feature = "production")]
1282#[inline]
1283pub fn verify_p2pk_inline(
1284 script_sig: &[u8],
1285 script_pubkey: &[u8],
1286 flags: u32,
1287 tx: &Transaction,
1288 input_index: usize,
1289 height: u64,
1290 network: crate::types::Network,
1291) -> Result<bool> {
1292 let pk_len = script_pubkey.len() - 2; let pubkey_bytes = &script_pubkey[1..1 + pk_len];
1294
1295 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1296 Some(s) => s,
1297 None => return Ok(false),
1298 };
1299 if signature_bytes.is_empty() {
1300 return Ok(false);
1301 }
1302
1303 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1304 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_buffered(
1307 tx,
1308 input_index,
1309 script_code,
1310 sighash_byte,
1311 );
1312
1313 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1314 let strict_der = flags & 0x04 != 0;
1315 let enforce_low_s = flags & 0x08 != 0;
1316
1317 if strict_der
1318 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1319 .unwrap_or(false)
1320 {
1321 return Ok(false);
1322 }
1323
1324 if flags & 0x02 != 0 {
1325 let sighash_base = sighash_byte & !0x80;
1326 if !(0x01..=0x03).contains(&sighash_base) {
1327 return Ok(false);
1328 }
1329 match pubkey_bytes.len() {
1330 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1331 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1332 33 | 65 => {}
1333 _ => return Ok(false),
1334 }
1335 }
1336
1337 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1338 der_sig,
1339 pubkey_bytes,
1340 &sighash,
1341 strict_der,
1342 enforce_low_s,
1343 )
1344 .unwrap_or(false))
1345}
1346
1347#[allow(clippy::too_many_arguments)]
1351fn try_verify_p2sh_multisig_fast_path(
1352 script_sig: &ByteString,
1353 script_pubkey: &[u8],
1354 flags: u32,
1355 tx: &Transaction,
1356 input_index: usize,
1357 prevout_values: &[i64],
1358 prevout_script_pubkeys: &[&[u8]],
1359 block_height: Option<u64>,
1360 network: crate::types::Network,
1361 #[cfg(feature = "production")] sighash_cache: Option<
1362 &crate::transaction_hash::SighashMidstateCache,
1363 >,
1364) -> Option<Result<bool>> {
1365 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1366 if pushes.len() < 2 {
1367 return None;
1368 }
1369 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1370 let expected_hash = &script_pubkey[2..22];
1371 let sha256_hash = OptimizedSha256::new().hash(redeem);
1372 let redeem_hash = Ripemd160::digest(sha256_hash);
1373 if &redeem_hash[..] != expected_hash {
1374 return Some(Ok(false));
1375 }
1376 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1377 let signatures: Vec<&[u8]> = pushes
1378 .iter()
1379 .take(pushes.len() - 1)
1380 .skip(1)
1381 .map(|e| e.as_ref())
1382 .collect();
1383 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1384
1385 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1386 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1387 let height = block_height.unwrap_or(0);
1388 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1389 let activation = match network {
1390 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1391 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1392 crate::types::Network::Regtest | crate::types::Network::Signet => 0,
1393 };
1394 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1395 return Some(Ok(false));
1396 }
1397 }
1398
1399 let mut cleaned = redeem.to_vec();
1400 for sig in &signatures {
1401 if !sig.is_empty() {
1402 let pattern = serialize_push_data(sig);
1403 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1404 }
1405 }
1406
1407 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1408
1409 let mut sig_index = 0;
1410 let mut valid_sigs = 0u8;
1411
1412 for pubkey_bytes in pubkeys {
1413 if sig_index >= signatures.len() {
1414 break;
1415 }
1416 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1417 sig_index += 1;
1418 }
1419 if sig_index >= signatures.len() {
1420 break;
1421 }
1422 let signature_bytes = &signatures[sig_index];
1423 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1424 let sighash_type = SighashType::from_byte(sighash_byte);
1425 let sighash = match calculate_transaction_sighash_single_input(
1426 tx,
1427 input_index,
1428 &cleaned,
1429 prevout_values[input_index],
1430 sighash_type,
1431 #[cfg(feature = "production")]
1432 sighash_cache,
1433 ) {
1434 Ok(h) => h,
1435 Err(e) => return Some(Err(e)),
1436 };
1437
1438 #[cfg(feature = "production")]
1439 let is_valid = signature::with_secp_context(|secp| {
1440 signature::verify_signature(
1441 secp,
1442 pubkey_bytes,
1443 signature_bytes,
1444 &sighash,
1445 flags,
1446 height,
1447 network,
1448 SigVersion::Base,
1449 )
1450 });
1451
1452 #[cfg(not(feature = "production"))]
1453 let is_valid = {
1454 let secp = signature::new_secp();
1455 signature::verify_signature(
1456 &secp,
1457 pubkey_bytes,
1458 signature_bytes,
1459 &sighash,
1460 flags,
1461 height,
1462 network,
1463 SigVersion::Base,
1464 )
1465 };
1466
1467 let is_valid = match is_valid {
1468 Ok(v) => v,
1469 Err(e) => return Some(Err(e)),
1470 };
1471
1472 if is_valid {
1473 valid_sigs += 1;
1474 sig_index += 1;
1475 }
1476 }
1477
1478 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1479 for sig_bytes in &signatures[sig_index..] {
1480 if !sig_bytes.is_empty() {
1481 return Some(Err(ConsensusError::ScriptErrorWithCode {
1482 code: ScriptErrorCode::SigNullFail,
1483 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1484 .into(),
1485 }));
1486 }
1487 }
1488 }
1489
1490 Some(Ok(valid_sigs >= m))
1491}
1492
1493#[allow(clippy::too_many_arguments)]
1496fn try_verify_bare_multisig_fast_path(
1497 script_sig: &ByteString,
1498 script_pubkey: &[u8],
1499 flags: u32,
1500 tx: &Transaction,
1501 input_index: usize,
1502 prevout_values: &[i64],
1503 prevout_script_pubkeys: &[&[u8]],
1504 block_height: Option<u64>,
1505 network: crate::types::Network,
1506 #[cfg(feature = "production")] sighash_cache: Option<
1507 &crate::transaction_hash::SighashMidstateCache,
1508 >,
1509) -> Option<Result<bool>> {
1510 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1511 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1512 if pushes.len() < 2 {
1513 return None;
1514 }
1515 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1516 let signatures: Vec<&[u8]> = pushes[1..].iter().map(|e| e.as_ref()).collect();
1517
1518 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1519 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1520 let height = block_height.unwrap_or(0);
1521 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1522 let activation = match network {
1523 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1524 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1525 crate::types::Network::Regtest | crate::types::Network::Signet => 0,
1526 };
1527 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1528 return Some(Ok(false));
1529 }
1530 }
1531
1532 let mut cleaned = script_pubkey.to_vec();
1533 for sig in &signatures {
1534 if !sig.is_empty() {
1535 let pattern = serialize_push_data(sig);
1536 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1537 }
1538 }
1539
1540 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1541
1542 let mut sig_index = 0;
1543 let mut valid_sigs = 0u8;
1544
1545 for pubkey_bytes in pubkeys {
1546 if sig_index >= signatures.len() {
1547 break;
1548 }
1549 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1550 sig_index += 1;
1551 }
1552 if sig_index >= signatures.len() {
1553 break;
1554 }
1555 let signature_bytes = &signatures[sig_index];
1556 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1557 let sighash_type = SighashType::from_byte(sighash_byte);
1558 let sighash = match calculate_transaction_sighash_single_input(
1559 tx,
1560 input_index,
1561 &cleaned,
1562 prevout_values[input_index],
1563 sighash_type,
1564 #[cfg(feature = "production")]
1565 sighash_cache,
1566 ) {
1567 Ok(h) => h,
1568 Err(e) => return Some(Err(e)),
1569 };
1570
1571 #[cfg(feature = "production")]
1572 let is_valid = signature::with_secp_context(|secp| {
1573 signature::verify_signature(
1574 secp,
1575 pubkey_bytes,
1576 signature_bytes,
1577 &sighash,
1578 flags,
1579 height,
1580 network,
1581 SigVersion::Base,
1582 )
1583 });
1584
1585 #[cfg(not(feature = "production"))]
1586 let is_valid = {
1587 let secp = signature::new_secp();
1588 signature::verify_signature(
1589 &secp,
1590 pubkey_bytes,
1591 signature_bytes,
1592 &sighash,
1593 flags,
1594 height,
1595 network,
1596 SigVersion::Base,
1597 )
1598 };
1599
1600 let is_valid = match is_valid {
1601 Ok(v) => v,
1602 Err(e) => return Some(Err(e)),
1603 };
1604
1605 if is_valid {
1606 valid_sigs += 1;
1607 sig_index += 1;
1608 }
1609 }
1610
1611 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1612 for sig_bytes in &signatures[sig_index..] {
1613 if !sig_bytes.is_empty() {
1614 return Some(Err(ConsensusError::ScriptErrorWithCode {
1615 code: ScriptErrorCode::SigNullFail,
1616 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1617 .into(),
1618 }));
1619 }
1620 }
1621 }
1622
1623 Some(Ok(valid_sigs >= m))
1624}
1625
1626#[cfg(feature = "production")]
1630#[allow(clippy::too_many_arguments)]
1631fn try_verify_p2sh_fast_path(
1632 script_sig: &ByteString,
1633 script_pubkey: &[u8],
1634 flags: u32,
1635 tx: &Transaction,
1636 input_index: usize,
1637 prevout_values: &[i64],
1638 prevout_script_pubkeys: &[&[u8]],
1639 block_height: Option<u64>,
1640 median_time_past: Option<u64>,
1641 network: crate::types::Network,
1642 #[cfg(feature = "production")] sighash_cache: Option<
1643 &crate::transaction_hash::SighashMidstateCache,
1644 >,
1645 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1646) -> Option<Result<bool>> {
1647 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1648 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1649 return None;
1650 }
1651 if script_pubkey.len() != 23
1653 || script_pubkey[0] != OP_HASH160
1654 || script_pubkey[1] != PUSH_20_BYTES
1655 || script_pubkey[22] != OP_EQUAL
1656 {
1657 return None;
1658 }
1659 let expected_hash = &script_pubkey[2..22];
1660
1661 let mut pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1662 if pushes.is_empty() {
1663 return None;
1664 }
1665 let redeem = pushes.pop().expect("at least one push");
1666 let mut stack = pushes;
1667
1668 if redeem.len() >= 3
1670 && redeem[0] == OP_0
1671 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
1672 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
1673 {
1674 return None;
1675 }
1676
1677 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1679 let redeem_hash = Ripemd160::digest(sha256_hash);
1680 if &redeem_hash[..] != expected_hash {
1681 return Some(Ok(false));
1682 }
1683
1684 if redeem.len() == 25
1686 && redeem[0] == OP_DUP
1687 && redeem[1] == OP_HASH160
1688 && redeem[2] == PUSH_20_BYTES
1689 && redeem[23] == OP_EQUALVERIFY
1690 && redeem[24] == OP_CHECKSIG
1691 && stack.len() == 2
1692 {
1693 let signature_bytes = &stack[0];
1694 let pubkey_bytes = &stack[1];
1695 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1696 let expected_pubkey_hash = &redeem[3..23];
1697 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1698 let pubkey_hash = Ripemd160::digest(sha256_hash);
1699 if &pubkey_hash[..] == expected_pubkey_hash {
1700 #[cfg(feature = "production")]
1701 let sighash = if let Some(precomp) = precomputed_sighash_all {
1702 precomp
1703 } else {
1704 use crate::transaction_hash::{
1705 SighashType, calculate_transaction_sighash_single_input,
1706 };
1707 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1708 let sighash_type = SighashType::from_byte(sighash_byte);
1709 let deleted_storage;
1710 let script_code: &[u8] = if redeem.len() < 71 {
1711 redeem.as_ref()
1712 } else {
1713 let pattern = serialize_push_data(signature_bytes);
1714 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1715 deleted_storage.as_ref()
1716 };
1717 match calculate_transaction_sighash_single_input(
1718 tx,
1719 input_index,
1720 script_code,
1721 prevout_values[input_index],
1722 sighash_type,
1723 sighash_cache,
1724 ) {
1725 Ok(h) => h,
1726 Err(e) => return Some(Err(e)),
1727 }
1728 };
1729 #[cfg(not(feature = "production"))]
1730 let sighash = {
1731 use crate::transaction_hash::{
1732 SighashType, calculate_transaction_sighash_single_input,
1733 };
1734 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1735 let sighash_type = SighashType::from_byte(sighash_byte);
1736 let deleted_storage;
1737 let script_code: &[u8] = if redeem.len() < 71 {
1738 redeem.as_ref()
1739 } else {
1740 let pattern = serialize_push_data(signature_bytes);
1741 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1742 deleted_storage.as_ref()
1743 };
1744 match calculate_transaction_sighash_single_input(
1745 tx,
1746 input_index,
1747 script_code,
1748 prevout_values[input_index],
1749 sighash_type,
1750 ) {
1751 Ok(h) => h,
1752 Err(e) => return Some(Err(e)),
1753 }
1754 };
1755 let height = block_height.unwrap_or(0);
1756 let is_valid = signature::with_secp_context(|secp| {
1757 signature::verify_signature(
1758 secp,
1759 pubkey_bytes,
1760 signature_bytes,
1761 &sighash,
1762 flags,
1763 height,
1764 network,
1765 SigVersion::Base,
1766 )
1767 });
1768 return Some(is_valid);
1769 }
1770 }
1771 }
1772
1773 if (redeem.len() == 35 || redeem.len() == 67)
1775 && redeem[redeem.len() - 1] == OP_CHECKSIG
1776 && (redeem[0] == 0x21 || redeem[0] == 0x41)
1777 && stack.len() == 1
1778 {
1779 let pubkey_len = redeem.len() - 2;
1780 if pubkey_len == 33 || pubkey_len == 65 {
1781 let pubkey_bytes = &redeem.as_ref()[1..(redeem.len() - 1)];
1782 let signature_bytes = &stack[0];
1783 if !signature_bytes.is_empty() {
1784 use crate::transaction_hash::{
1785 SighashType, calculate_transaction_sighash_single_input,
1786 };
1787 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1788 let sighash_type = SighashType::from_byte(sighash_byte);
1789 let deleted_storage;
1791 let script_code: &[u8] = if redeem.len() < 71 {
1792 redeem.as_ref()
1793 } else {
1794 let pattern = serialize_push_data(signature_bytes);
1795 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1796 deleted_storage.as_ref()
1797 };
1798 match calculate_transaction_sighash_single_input(
1799 tx,
1800 input_index,
1801 script_code,
1802 prevout_values[input_index],
1803 sighash_type,
1804 #[cfg(feature = "production")]
1805 sighash_cache,
1806 ) {
1807 Ok(sighash) => {
1808 let height = block_height.unwrap_or(0);
1809 let is_valid = signature::with_secp_context(|secp| {
1810 signature::verify_signature(
1811 secp,
1812 pubkey_bytes,
1813 signature_bytes,
1814 &sighash,
1815 flags,
1816 height,
1817 network,
1818 SigVersion::Base,
1819 )
1820 });
1821 return Some(is_valid);
1822 }
1823 Err(e) => return Some(Err(e)),
1824 }
1825 }
1826 }
1827 }
1828
1829 let result = eval_script_with_context_full_inner(
1831 &redeem,
1832 &mut stack,
1833 flags,
1834 tx,
1835 input_index,
1836 prevout_values,
1837 prevout_script_pubkeys,
1838 block_height,
1839 median_time_past,
1840 network,
1841 SigVersion::Base,
1842 Some(redeem.as_ref()),
1843 None, None, #[cfg(feature = "production")]
1846 None, None, #[cfg(feature = "production")]
1849 sighash_cache,
1850 );
1851 Some(result)
1852}
1853
1854#[cfg(feature = "production")]
1857#[allow(clippy::too_many_arguments)]
1858fn try_verify_p2wpkh_fast_path(
1859 script_sig: &ByteString,
1860 script_pubkey: &[u8],
1861 witness: &crate::witness::Witness,
1862 flags: u32,
1863 tx: &Transaction,
1864 input_index: usize,
1865 prevout_values: &[i64],
1866 prevout_script_pubkeys: &[&[u8]],
1867 block_height: Option<u64>,
1868 network: crate::types::Network,
1869 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1870 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1871) -> Option<Result<bool>> {
1872 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
1874 return None;
1875 }
1876 if !script_sig.is_empty() {
1878 return None;
1879 }
1880 if witness.len() != 2 {
1881 return None;
1882 }
1883 let signature_bytes = &witness[0];
1884 let pubkey_bytes = &witness[1];
1885
1886 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1887 return Some(Ok(false));
1888 }
1889 if signature_bytes.is_empty() {
1890 return Some(Ok(false));
1891 }
1892
1893 let expected_hash = &script_pubkey[2..22];
1894 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1895 let pubkey_hash = Ripemd160::digest(sha256_hash);
1896 if &pubkey_hash[..] != expected_hash {
1897 return Some(Ok(false));
1898 }
1899
1900 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_hash);
1902
1903 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1904 let sighash = if sighash_byte == 0x01 {
1905 #[cfg(feature = "production")]
1907 if let Some(precomp) = precomputed_sighash_all {
1908 precomp
1909 } else {
1910 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1911 match crate::transaction_hash::calculate_bip143_sighash(
1912 tx,
1913 input_index,
1914 &p2pkh_script_code,
1915 amount,
1916 sighash_byte,
1917 precomputed_bip143,
1918 ) {
1919 Ok(h) => h,
1920 Err(e) => return Some(Err(e)),
1921 }
1922 }
1923 #[cfg(not(feature = "production"))]
1924 {
1925 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1926 match crate::transaction_hash::calculate_bip143_sighash(
1927 tx,
1928 input_index,
1929 &p2pkh_script_code,
1930 amount,
1931 sighash_byte,
1932 precomputed_bip143,
1933 ) {
1934 Ok(h) => h,
1935 Err(e) => return Some(Err(e)),
1936 }
1937 }
1938 } else {
1939 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1940 match crate::transaction_hash::calculate_bip143_sighash(
1941 tx,
1942 input_index,
1943 &p2pkh_script_code,
1944 amount,
1945 sighash_byte,
1946 precomputed_bip143,
1947 ) {
1948 Ok(h) => h,
1949 Err(e) => return Some(Err(e)),
1950 }
1951 };
1952
1953 let height = block_height.unwrap_or(0);
1954 let is_valid = signature::with_secp_context(|secp| {
1955 signature::verify_signature(
1956 secp,
1957 pubkey_bytes,
1958 signature_bytes,
1959 &sighash,
1960 flags,
1961 height,
1962 network,
1963 SigVersion::WitnessV0,
1964 )
1965 });
1966 Some(is_valid)
1967}
1968
1969#[cfg(feature = "production")]
1971#[allow(clippy::too_many_arguments)]
1972fn try_verify_p2wpkh_in_p2sh_fast_path(
1973 script_sig: &ByteString,
1974 script_pubkey: &[u8],
1975 witness: &crate::witness::Witness,
1976 flags: u32,
1977 tx: &Transaction,
1978 input_index: usize,
1979 prevout_values: &[i64],
1980 prevout_script_pubkeys: &[&[u8]],
1981 block_height: Option<u64>,
1982 network: crate::types::Network,
1983 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1984) -> Option<Result<bool>> {
1985 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1986 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1987 return None;
1988 }
1989 if script_pubkey.len() != 23
1990 || script_pubkey[0] != OP_HASH160
1991 || script_pubkey[1] != PUSH_20_BYTES
1992 || script_pubkey[22] != OP_EQUAL
1993 {
1994 return None;
1995 }
1996 let expected_hash = &script_pubkey[2..22];
1997
1998 let pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1999 if pushes.len() != 1 {
2000 return None;
2001 }
2002 let redeem = &pushes[0];
2003 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
2004 return None;
2005 }
2006 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
2007 let redeem_hash = Ripemd160::digest(sha256_hash);
2008 if &redeem_hash[..] != expected_hash {
2009 return Some(Ok(false));
2010 }
2011
2012 if witness.len() != 2 {
2013 return None;
2014 }
2015 let signature_bytes = &witness[0];
2016 let pubkey_bytes = &witness[1];
2017 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
2018 return Some(Ok(false));
2019 }
2020 let expected_pubkey_hash = &redeem[2..22];
2021 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2022 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2023 if &pubkey_hash[..] != expected_pubkey_hash {
2024 return Some(Ok(false));
2025 }
2026
2027 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_pubkey_hash);
2029
2030 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2031 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2032 let sighash = match crate::transaction_hash::calculate_bip143_sighash(
2033 tx,
2034 input_index,
2035 &p2pkh_script_code,
2036 amount,
2037 sighash_byte,
2038 precomputed_bip143,
2039 ) {
2040 Ok(h) => h,
2041 Err(e) => return Some(Err(e)),
2042 };
2043
2044 let height = block_height.unwrap_or(0);
2045 let is_valid = signature::with_secp_context(|secp| {
2046 signature::verify_signature(
2047 secp,
2048 pubkey_bytes,
2049 signature_bytes,
2050 &sighash,
2051 flags,
2052 height,
2053 network,
2054 SigVersion::WitnessV0,
2055 )
2056 });
2057 Some(is_valid)
2058}
2059
2060#[cfg(feature = "production")]
2063#[allow(clippy::too_many_arguments)]
2064fn try_verify_p2wsh_fast_path(
2065 script_sig: &ByteString,
2066 script_pubkey: &[u8],
2067 witness: &crate::witness::Witness,
2068 flags: u32,
2069 tx: &Transaction,
2070 input_index: usize,
2071 prevout_values: &[i64],
2072 prevout_script_pubkeys: &[&[u8]],
2073 block_height: Option<u64>,
2074 median_time_past: Option<u64>,
2075 network: crate::types::Network,
2076 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2077 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2078 #[cfg(feature = "production")] sighash_cache: Option<
2079 &crate::transaction_hash::SighashMidstateCache,
2080 >,
2081) -> Option<Result<bool>> {
2082 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
2084 return None;
2085 }
2086 if !script_sig.is_empty() {
2087 return None;
2088 }
2089 if witness.is_empty() {
2090 return None;
2091 }
2092 let witness_script = witness.last().expect("witness not empty").clone();
2093 let mut stack: Vec<StackElement> = witness
2094 .iter()
2095 .take(witness.len() - 1)
2096 .map(|w| to_stack_element(w))
2097 .collect();
2098
2099 let program_hash = &script_pubkey[2..34];
2100 if program_hash.len() != 32 {
2101 return None;
2102 }
2103 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2104 if &witness_script_hash[..] != program_hash {
2105 return Some(Ok(false));
2106 }
2107
2108 let witness_sigversion = SigVersion::WitnessV0;
2112
2113 if witness_sigversion == SigVersion::WitnessV0
2115 && witness_script.len() == 25
2116 && witness_script[0] == OP_DUP
2117 && witness_script[1] == OP_HASH160
2118 && witness_script[2] == PUSH_20_BYTES
2119 && witness_script[23] == OP_EQUALVERIFY
2120 && witness_script[24] == OP_CHECKSIG
2121 && stack.len() == 2
2122 {
2123 let signature_bytes = &stack[0];
2124 let pubkey_bytes = &stack[1];
2125 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2126 let expected_pubkey_hash = &witness_script[3..23];
2127 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2128 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2129 if &pubkey_hash[..] == expected_pubkey_hash {
2130 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2131 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2132 match crate::transaction_hash::calculate_bip143_sighash(
2133 tx,
2134 input_index,
2135 witness_script.as_ref(),
2136 amount,
2137 sighash_byte,
2138 precomputed_bip143,
2139 ) {
2140 Ok(sighash) => {
2141 let height = block_height.unwrap_or(0);
2142 let is_valid = signature::with_secp_context(|secp| {
2143 signature::verify_signature(
2144 secp,
2145 pubkey_bytes,
2146 signature_bytes,
2147 &sighash,
2148 flags,
2149 height,
2150 network,
2151 SigVersion::WitnessV0,
2152 )
2153 });
2154 return Some(is_valid);
2155 }
2156 Err(e) => return Some(Err(e)),
2157 }
2158 }
2159 }
2160 }
2161
2162 if witness_sigversion == SigVersion::WitnessV0
2164 && (witness_script.len() == 35 || witness_script.len() == 67)
2165 && witness_script[witness_script.len() - 1] == OP_CHECKSIG
2166 && (witness_script[0] == 0x21 || witness_script[0] == 0x41)
2167 && stack.len() == 1
2168 {
2169 let pubkey_len = witness_script.len() - 2;
2170 if (pubkey_len == 33 || pubkey_len == 65) && !stack[0].is_empty() {
2171 let pubkey_bytes = &witness_script[1..(witness_script.len() - 1)];
2172 let signature_bytes = &stack[0];
2173 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2174 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2175 match crate::transaction_hash::calculate_bip143_sighash(
2176 tx,
2177 input_index,
2178 witness_script.as_ref(),
2179 amount,
2180 sighash_byte,
2181 precomputed_bip143,
2182 ) {
2183 Ok(sighash) => {
2184 let height = block_height.unwrap_or(0);
2185 let is_valid = signature::with_secp_context(|secp| {
2186 signature::verify_signature(
2187 secp,
2188 pubkey_bytes,
2189 signature_bytes,
2190 &sighash,
2191 flags,
2192 height,
2193 network,
2194 SigVersion::WitnessV0,
2195 )
2196 });
2197 return Some(is_valid);
2198 }
2199 Err(e) => return Some(Err(e)),
2200 }
2201 }
2202 }
2203
2204 if witness_sigversion == SigVersion::WitnessV0 {
2206 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script.as_ref()) {
2207 if stack.len() < 2 {
2208 return Some(Ok(false));
2209 }
2210 let dummy = stack[0].as_ref();
2211 let signatures: Vec<&[u8]> = stack[1..].iter().map(|e| e.as_ref()).collect();
2212
2213 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
2214 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
2215 let height = block_height.unwrap_or(0);
2216 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
2217 let activation = match network {
2218 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
2219 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
2220 crate::types::Network::Regtest | crate::types::Network::Signet => 0,
2221 };
2222 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
2223 return Some(Ok(false));
2224 }
2225 }
2226
2227 let mut cleaned = witness_script.to_vec();
2228 for sig in &signatures {
2229 if !sig.is_empty() {
2230 let pattern = serialize_push_data(sig);
2231 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
2232 }
2233 }
2234
2235 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2236 let mut sig_index = 0;
2237 let mut valid_sigs = 0u8;
2238
2239 for pubkey_bytes in pubkeys {
2240 if sig_index >= signatures.len() {
2241 break;
2242 }
2243 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
2244 sig_index += 1;
2245 }
2246 if sig_index >= signatures.len() {
2247 break;
2248 }
2249 let signature_bytes = &signatures[sig_index];
2250 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2251 match crate::transaction_hash::calculate_bip143_sighash(
2252 tx,
2253 input_index,
2254 &cleaned,
2255 amount,
2256 sighash_byte,
2257 precomputed_bip143,
2258 ) {
2259 Ok(sighash) => {
2260 let is_valid = signature::with_secp_context(|secp| {
2261 signature::verify_signature(
2262 secp,
2263 pubkey_bytes,
2264 signature_bytes,
2265 &sighash,
2266 flags,
2267 height,
2268 network,
2269 SigVersion::WitnessV0,
2270 )
2271 });
2272 match is_valid {
2273 Ok(v) if v => {
2274 valid_sigs += 1;
2275 sig_index += 1;
2276 }
2277 Ok(_) => {}
2278 Err(e) => return Some(Err(e)),
2279 }
2280 }
2281 Err(e) => return Some(Err(e)),
2282 }
2283 }
2284
2285 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
2286 for sig_bytes in &signatures[sig_index..] {
2287 if !sig_bytes.is_empty() {
2288 return Some(Err(ConsensusError::ScriptErrorWithCode {
2289 code: ScriptErrorCode::SigNullFail,
2290 message:
2291 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
2292 .into(),
2293 }));
2294 }
2295 }
2296 }
2297
2298 return Some(Ok(valid_sigs >= m));
2299 }
2300 }
2301
2302 let result = eval_script_with_context_full_inner(
2305 &witness_script,
2306 &mut stack,
2307 flags,
2308 tx,
2309 input_index,
2310 prevout_values,
2311 prevout_script_pubkeys,
2312 block_height,
2313 median_time_past,
2314 network,
2315 witness_sigversion,
2316 None, None, None, schnorr_collector,
2320 precomputed_bip143,
2321 #[cfg(feature = "production")]
2322 sighash_cache,
2323 );
2324 Some(result)
2325}
2326
2327#[cfg(feature = "production")]
2329#[allow(clippy::too_many_arguments)]
2330fn try_verify_p2tr_scriptpath_p2pk_fast_path(
2331 script_sig: &ByteString,
2332 script_pubkey: &[u8],
2333 witness: &crate::witness::Witness,
2334 _flags: u32,
2335 tx: &Transaction,
2336 input_index: usize,
2337 prevout_values: &[i64],
2338 prevout_script_pubkeys: &[&[u8]],
2339 block_height: Option<u64>,
2340 network: crate::types::Network,
2341 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2342) -> Option<Result<bool>> {
2343 use crate::activation::taproot_activation_height;
2344 use crate::taproot::parse_taproot_script_path_witness;
2345
2346 let tap_h = taproot_activation_height(network);
2347 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2348 return None;
2349 }
2350 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2351 return None;
2352 }
2353 if !script_sig.is_empty() {
2354 return None;
2355 }
2356 if witness.len() < 2 {
2357 return None;
2358 }
2359 let mut output_key = [0u8; 32];
2360 output_key.copy_from_slice(&script_pubkey[2..34]);
2361 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
2362 let parsed = match parse_taproot_script_path_witness(&witness_body, &output_key) {
2363 Ok(Some(p)) => p,
2364 Ok(None) | Err(_) => return None,
2365 };
2366 let (tapscript, stack_items, control_block) = parsed;
2367 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
2368 return None;
2369 }
2370 if stack_items.len() != 1 {
2371 return None;
2372 }
2373 let (sig_bytes, sighash_type) =
2374 crate::bip348::try_parse_taproot_schnorr_witness_sig(stack_items[0].as_ref())?;
2375 let pubkey_32 = &tapscript[1..33];
2376 let sighash = crate::taproot::compute_tapscript_signature_hash(
2377 tx,
2378 input_index,
2379 prevout_values,
2380 prevout_script_pubkeys,
2381 &tapscript,
2382 control_block.leaf_version,
2383 0xffff_ffff,
2384 sighash_type,
2385 annex_hash.as_ref(),
2386 )
2387 .ok()?;
2388 let result = crate::bip348::verify_tapscript_schnorr_signature(
2389 &sighash,
2390 pubkey_32,
2391 &sig_bytes,
2392 schnorr_collector,
2393 );
2394 Some(result)
2395}
2396
2397#[cfg(feature = "production")]
2400#[allow(clippy::too_many_arguments)]
2401fn verify_p2tr_keypath_witness(
2402 script_pubkey: &[u8],
2403 witness: &crate::witness::Witness,
2404 tx: &Transaction,
2405 input_index: usize,
2406 prevout_values: &[i64],
2407 prevout_script_pubkeys: &[&[u8]],
2408 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2409) -> Result<bool> {
2410 use crate::bip348::{
2411 try_parse_taproot_schnorr_witness_sig, verify_tapscript_schnorr_signature,
2412 };
2413
2414 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
2415 if witness_body.len() != 1 {
2416 return Ok(false);
2417 }
2418 let Some((sig_bytes, sighash_type)) = try_parse_taproot_schnorr_witness_sig(&witness_body[0])
2419 else {
2420 return Ok(false);
2421 };
2422 let output_key = &script_pubkey[2..34];
2423 let sighash = crate::taproot::compute_taproot_signature_hash(
2424 tx,
2425 input_index,
2426 prevout_values,
2427 prevout_script_pubkeys,
2428 sighash_type,
2429 annex_hash.as_ref(),
2430 )?;
2431 verify_tapscript_schnorr_signature(&sighash, output_key, &sig_bytes, schnorr_collector)
2432}
2433
2434#[cfg(feature = "production")]
2435#[allow(clippy::too_many_arguments)]
2436fn try_verify_p2tr_keypath_fast_path(
2437 script_sig: &ByteString,
2438 script_pubkey: &[u8],
2439 witness: &crate::witness::Witness,
2440 _flags: u32,
2441 tx: &Transaction,
2442 input_index: usize,
2443 prevout_values: &[i64],
2444 prevout_script_pubkeys: &[&[u8]],
2445 block_height: Option<u64>,
2446 network: crate::types::Network,
2447 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2448) -> Option<Result<bool>> {
2449 use crate::activation::taproot_activation_height;
2450 let tap_h = taproot_activation_height(network);
2451 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2452 return None;
2453 }
2454 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2456 return None;
2457 }
2458 if !script_sig.is_empty() {
2459 return None;
2460 }
2461 let (witness_body, _) = crate::taproot::strip_taproot_annex(witness);
2463 if witness_body.len() != 1 {
2464 return None;
2465 }
2466 crate::bip348::try_parse_taproot_schnorr_witness_sig(&witness_body[0])?;
2467 Some(verify_p2tr_keypath_witness(
2468 script_pubkey,
2469 witness,
2470 tx,
2471 input_index,
2472 prevout_values,
2473 prevout_script_pubkeys,
2474 schnorr_collector,
2475 ))
2476}
2477
2478#[spec_locked("5.2", "VerifyScript")]
2479pub fn verify_script_with_context_full(
2480 script_sig: &ByteString,
2481 script_pubkey: &[u8],
2482 witness: Option<&crate::witness::Witness>,
2483 flags: u32,
2484 tx: &Transaction,
2485 input_index: usize,
2486 prevout_values: &[i64],
2487 prevout_script_pubkeys: &[&[u8]],
2488 block_height: Option<u64>,
2489 median_time_past: Option<u64>,
2490 network: crate::types::Network,
2491 _sigversion: SigVersion,
2492 #[cfg(feature = "production")] schnorr_collector: Option<
2493 &crate::bip348::SchnorrSignatureCollector,
2494 >,
2495 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2496 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2497 #[cfg(feature = "production")] sighash_cache: Option<
2498 &crate::transaction_hash::SighashMidstateCache,
2499 >,
2500 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
2501) -> Result<bool> {
2502 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
2504 return Err(ConsensusError::ScriptErrorWithCode {
2505 code: ScriptErrorCode::TxInputInvalid,
2506 message: format!(
2507 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
2508 prevout_values.len(),
2509 prevout_script_pubkeys.len(),
2510 tx.inputs.len(),
2511 input_index,
2512 )
2513 .into(),
2514 });
2515 }
2516
2517 if input_index < prevout_values.len() {
2523 let prevout_value = prevout_values[input_index];
2524 if prevout_value < 0 {
2525 return Err(ConsensusError::ScriptErrorWithCode {
2526 code: ScriptErrorCode::ValueOverflow,
2527 message: "Prevout value cannot be negative".into(),
2528 });
2529 }
2530 #[cfg(feature = "production")]
2531 {
2532 use precomputed_constants::MAX_MONEY_U64;
2533 if (prevout_value as u64) > MAX_MONEY_U64 {
2534 return Err(ConsensusError::ScriptErrorWithCode {
2535 code: ScriptErrorCode::ValueOverflow,
2536 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2537 });
2538 }
2539 }
2540 #[cfg(not(feature = "production"))]
2541 {
2542 use crate::constants::MAX_MONEY;
2543 if prevout_value > MAX_MONEY {
2544 return Err(ConsensusError::ScriptErrorWithCode {
2545 code: ScriptErrorCode::ValueOverflow,
2546 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2547 });
2548 }
2549 }
2550 }
2551
2552 if input_index >= tx.inputs.len() {
2554 return Err(ConsensusError::ScriptErrorWithCode {
2555 code: ScriptErrorCode::TxInputInvalid,
2556 message: format!(
2557 "Input index {} out of bounds (tx has {} inputs)",
2558 input_index,
2559 tx.inputs.len()
2560 )
2561 .into(),
2562 });
2563 }
2564
2565 #[cfg(feature = "production")]
2567 if !fast_paths_disabled() && witness.is_none() {
2568 if let Some(result) = try_verify_p2pk_fast_path(
2569 script_sig,
2570 script_pubkey,
2571 flags,
2572 tx,
2573 input_index,
2574 prevout_values,
2575 prevout_script_pubkeys,
2576 block_height,
2577 network,
2578 #[cfg(feature = "production")]
2579 sighash_cache,
2580 ) {
2581 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
2582 return result;
2583 }
2584 if let Some(result) = try_verify_p2pkh_fast_path(
2585 script_sig,
2586 script_pubkey,
2587 flags,
2588 tx,
2589 input_index,
2590 prevout_values,
2591 prevout_script_pubkeys,
2592 block_height,
2593 network,
2594 #[cfg(feature = "production")]
2595 precomputed_sighash_all,
2596 #[cfg(feature = "production")]
2597 sighash_cache,
2598 #[cfg(feature = "production")]
2599 precomputed_p2pkh_hash,
2600 ) {
2601 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
2602 return result;
2603 }
2604 if let Some(result) = try_verify_p2sh_fast_path(
2605 script_sig,
2606 script_pubkey,
2607 flags,
2608 tx,
2609 input_index,
2610 prevout_values,
2611 prevout_script_pubkeys,
2612 block_height,
2613 median_time_past,
2614 network,
2615 #[cfg(feature = "production")]
2616 sighash_cache,
2617 #[cfg(feature = "production")]
2618 precomputed_sighash_all,
2619 ) {
2620 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
2621 return result;
2622 }
2623 if let Some(result) = try_verify_bare_multisig_fast_path(
2624 script_sig,
2625 script_pubkey,
2626 flags,
2627 tx,
2628 input_index,
2629 prevout_values,
2630 prevout_script_pubkeys,
2631 block_height,
2632 network,
2633 #[cfg(feature = "production")]
2634 sighash_cache,
2635 ) {
2636 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
2637 return result;
2638 }
2639 }
2640 #[cfg(feature = "production")]
2642 if !fast_paths_disabled() {
2643 if let Some(wit) = witness {
2644 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
2645 script_sig,
2646 script_pubkey,
2647 wit,
2648 flags,
2649 tx,
2650 input_index,
2651 prevout_values,
2652 prevout_script_pubkeys,
2653 block_height,
2654 network,
2655 precomputed_bip143,
2656 ) {
2657 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2658 return result;
2659 }
2660 if let Some(result) = try_verify_p2wpkh_fast_path(
2661 script_sig,
2662 script_pubkey,
2663 wit,
2664 flags,
2665 tx,
2666 input_index,
2667 prevout_values,
2668 prevout_script_pubkeys,
2669 block_height,
2670 network,
2671 precomputed_bip143,
2672 precomputed_sighash_all,
2673 ) {
2674 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2675 return result;
2676 }
2677 if let Some(result) = try_verify_p2wsh_fast_path(
2678 script_sig,
2679 script_pubkey,
2680 wit,
2681 flags,
2682 tx,
2683 input_index,
2684 prevout_values,
2685 prevout_script_pubkeys,
2686 block_height,
2687 median_time_past,
2688 network,
2689 schnorr_collector,
2690 precomputed_bip143,
2691 #[cfg(feature = "production")]
2692 sighash_cache,
2693 ) {
2694 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
2695 return result;
2696 }
2697 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
2698 script_sig,
2699 script_pubkey,
2700 wit,
2701 flags,
2702 tx,
2703 input_index,
2704 prevout_values,
2705 prevout_script_pubkeys,
2706 block_height,
2707 network,
2708 schnorr_collector,
2709 ) {
2710 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2711 return result;
2712 }
2713 if let Some(result) = try_verify_p2tr_keypath_fast_path(
2714 script_sig,
2715 script_pubkey,
2716 wit,
2717 flags,
2718 tx,
2719 input_index,
2720 prevout_values,
2721 prevout_script_pubkeys,
2722 block_height,
2723 network,
2724 schnorr_collector,
2725 ) {
2726 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2727 return result;
2728 }
2729 }
2730 }
2731 #[cfg(feature = "production")]
2732 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
2733
2734 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
2738 let is_p2sh = (flags & SCRIPT_VERIFY_P2SH) != 0
2739 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; if is_p2sh {
2750 let mut i = 0;
2751 while i < script_sig.len() {
2752 let opcode = script_sig[i];
2753 if !is_push_opcode(opcode) {
2754 return Ok(false);
2756 }
2757 if opcode == OP_0 {
2759 i += 1;
2761 } else if opcode <= 0x4b {
2762 let len = opcode as usize;
2764 if i + 1 + len > script_sig.len() {
2765 return Ok(false); }
2767 i += 1 + len;
2768 } else if opcode == OP_PUSHDATA1 {
2769 if i + 1 >= script_sig.len() {
2771 return Ok(false);
2772 }
2773 let len = script_sig[i + 1] as usize;
2774 if i + 2 + len > script_sig.len() {
2775 return Ok(false);
2776 }
2777 i += 2 + len;
2778 } else if opcode == OP_PUSHDATA2 {
2779 if i + 2 >= script_sig.len() {
2781 return Ok(false);
2782 }
2783 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
2784 if i + 3 + len > script_sig.len() {
2785 return Ok(false);
2786 }
2787 i += 3 + len;
2788 } else if opcode == OP_PUSHDATA4 {
2789 if i + 4 >= script_sig.len() {
2791 return Ok(false);
2792 }
2793 let len = u32::from_le_bytes([
2794 script_sig[i + 1],
2795 script_sig[i + 2],
2796 script_sig[i + 3],
2797 script_sig[i + 4],
2798 ]) as usize;
2799 if i + 5 + len > script_sig.len() {
2800 return Ok(false);
2801 }
2802 i += 5 + len;
2803 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
2804 i += 1;
2807 } else {
2808 return Ok(false);
2810 }
2811 }
2812 if !fast_paths_disabled() {
2813 if let Some(result) = try_verify_p2sh_multisig_fast_path(
2814 script_sig,
2815 script_pubkey,
2816 flags,
2817 tx,
2818 input_index,
2819 prevout_values,
2820 prevout_script_pubkeys,
2821 block_height,
2822 network,
2823 #[cfg(feature = "production")]
2824 sighash_cache,
2825 ) {
2826 return result;
2827 }
2828 }
2829 }
2830
2831 #[cfg(feature = "production")]
2832 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
2833 #[cfg(feature = "production")]
2834 let stack = &mut _stack_guard.0;
2835 #[cfg(not(feature = "production"))]
2836 let mut stack = Vec::with_capacity(20);
2837
2838 let script_sig_result = eval_script_with_context_full(
2842 script_sig,
2843 stack,
2844 flags,
2845 tx,
2846 input_index,
2847 prevout_values,
2848 prevout_script_pubkeys,
2849 block_height,
2850 median_time_past,
2851 network,
2852 SigVersion::Base,
2853 None, None, #[cfg(feature = "production")]
2856 schnorr_collector,
2857 None, #[cfg(feature = "production")]
2859 sighash_cache,
2860 )?;
2861 if !script_sig_result {
2862 return Ok(false);
2863 }
2864
2865 let redeem_script: Option<ByteString> = if is_p2sh && !stack.is_empty() {
2867 Some(stack.last().expect("Stack is not empty").as_ref().to_vec())
2868 } else {
2869 None
2870 };
2871
2872 use crate::activation::taproot_activation_height;
2876 let tap_h = taproot_activation_height(network);
2877 let is_taproot = redeem_script.is_none() && block_height.is_some() && block_height.unwrap() >= tap_h
2879 && script_pubkey.len() == 34
2880 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES; if is_taproot && !script_sig.is_empty() {
2885 return Ok(false); }
2887
2888 let is_direct_witness_program = redeem_script.is_none() && !is_taproot && script_pubkey.len() >= 3
2895 && script_pubkey[0] == OP_0 && ((script_pubkey[1] == PUSH_20_BYTES && script_pubkey.len() == 22) || (script_pubkey[1] == PUSH_32_BYTES && script_pubkey.len() == 34)); let mut witness_script_to_execute: Option<ByteString> = None;
2901 if is_direct_witness_program {
2902 if let Some(witness_stack) = witness {
2903 if script_pubkey[1] == PUSH_32_BYTES {
2904 if witness_stack.is_empty() {
2907 return Ok(false); }
2909
2910 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2912
2913 let program_bytes = &script_pubkey[2..];
2915 if program_bytes.len() != 32 {
2916 return Ok(false); }
2918
2919 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2920 if &witness_script_hash[..] != program_bytes {
2921 return Ok(false); }
2923
2924 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2926 stack.push(to_stack_element(element));
2927 }
2928
2929 witness_script_to_execute = Some(witness_script.clone());
2931 } else if script_pubkey[1] == PUSH_20_BYTES {
2932 if witness_stack.len() != 2 {
2935 return Ok(false); }
2937
2938 for element in witness_stack.iter() {
2939 stack.push(to_stack_element(element));
2940 }
2941 } else {
2942 return Ok(false); }
2944 } else {
2945 return Ok(false); }
2947 }
2948
2949 if is_taproot {
2950 let Some(witness_stack) = witness else {
2951 return Ok(false);
2952 };
2953 if witness_stack.is_empty() {
2954 return Ok(false);
2955 }
2956 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness_stack);
2958 if witness_body.is_empty() {
2959 return Ok(false);
2960 }
2961 if witness_body.len() == 1 {
2962 #[cfg(feature = "production")]
2963 {
2964 return verify_p2tr_keypath_witness(
2965 script_pubkey,
2966 witness_stack,
2967 tx,
2968 input_index,
2969 prevout_values,
2970 prevout_script_pubkeys,
2971 schnorr_collector,
2972 );
2973 }
2974 #[cfg(not(feature = "production"))]
2975 {
2976 return Ok(false);
2977 }
2978 }
2979 if witness_body.len() < 2 {
2980 return Ok(false);
2981 }
2982 let mut output_key = [0u8; 32];
2983 output_key.copy_from_slice(&script_pubkey[2..34]);
2984 match crate::taproot::parse_taproot_script_path_witness(&witness_body, &output_key)? {
2985 None => return Ok(false),
2986 Some((tapscript, stack_items, _control_block)) => {
2987 for item in &stack_items {
2988 stack.push(to_stack_element(item));
2989 }
2990 let tapscript_flags = flags | 0x8000;
2991 if !eval_script_with_context_full(
2992 &tapscript,
2993 stack,
2994 tapscript_flags,
2995 tx,
2996 input_index,
2997 prevout_values,
2998 prevout_script_pubkeys,
2999 block_height,
3000 median_time_past,
3001 network,
3002 SigVersion::Tapscript,
3003 None,
3004 annex_hash.as_ref(),
3005 #[cfg(feature = "production")]
3006 schnorr_collector,
3007 None,
3008 #[cfg(feature = "production")]
3009 sighash_cache,
3010 )? {
3011 return Ok(false);
3012 }
3013 return Ok(true);
3014 }
3015 }
3016 }
3017
3018 let script_pubkey_result = eval_script_with_context_full(
3025 script_pubkey,
3026 stack,
3027 flags,
3028 tx,
3029 input_index,
3030 prevout_values,
3031 prevout_script_pubkeys,
3032 block_height,
3033 median_time_past,
3034 network,
3035 SigVersion::Base,
3036 Some(script_sig),
3037 None, #[cfg(feature = "production")]
3039 schnorr_collector,
3040 None, #[cfg(feature = "production")]
3042 sighash_cache,
3043 )?;
3044 if !script_pubkey_result {
3045 return Ok(false);
3046 }
3047
3048 if let Some(witness_script) = witness_script_to_execute {
3050 let witness_sigversion = SigVersion::WitnessV0;
3053
3054 if !eval_script_with_context_full(
3057 &witness_script,
3058 stack,
3059 flags,
3060 tx,
3061 input_index,
3062 prevout_values,
3063 prevout_script_pubkeys,
3064 block_height,
3065 median_time_past,
3066 network,
3067 witness_sigversion,
3068 None, None, #[cfg(feature = "production")]
3071 schnorr_collector,
3072 precomputed_bip143, #[cfg(feature = "production")]
3074 sighash_cache,
3075 )? {
3076 return Ok(false);
3077 }
3078 }
3079
3080 if let Some(redeem) = redeem_script {
3085 if stack.is_empty() {
3087 return Ok(false); }
3089
3090 let top = stack.last().expect("Stack is not empty");
3092 if !cast_to_bool(top) {
3093 return Ok(false); }
3095
3096 stack.pop();
3098
3099 let is_witness_program = redeem.len() >= 3
3104 && redeem[0] == OP_0 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22) || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34)); if is_witness_program && witness.is_some() {
3109 let program_bytes = &redeem[2..];
3118
3119 if redeem[1] == PUSH_32_BYTES {
3120 if program_bytes.len() != 32 {
3123 return Ok(false); }
3125
3126 if let Some(witness_stack) = witness {
3131 if witness_stack.is_empty() {
3132 return Ok(false); }
3134
3135 let witness_script = witness_stack.last().expect("Witness stack is not empty");
3137 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
3138 if &witness_script_hash[..] != program_bytes {
3139 return Ok(false); }
3141
3142 stack.clear();
3145
3146 for element in witness_stack.iter().take(witness_stack.len() - 1) {
3149 stack.push(to_stack_element(element));
3150 }
3151
3152 let witness_sigversion = SigVersion::WitnessV0;
3156
3157 if !eval_script_with_context_full(
3159 witness_script,
3160 stack,
3161 flags,
3162 tx,
3163 input_index,
3164 prevout_values,
3165 prevout_script_pubkeys,
3166 block_height,
3167 median_time_past,
3168 network,
3169 witness_sigversion,
3170 None, None, #[cfg(feature = "production")]
3173 schnorr_collector,
3174 precomputed_bip143, #[cfg(feature = "production")]
3176 sighash_cache,
3177 )? {
3178 return Ok(false);
3179 }
3180 } else {
3181 return Ok(false); }
3183 } else if redeem[1] == PUSH_20_BYTES {
3184 let pubkey_hash = &redeem[2..22]; let witness_stack = match witness {
3190 Some(w) => w,
3191 None => return Ok(false), };
3193 if witness_stack.len() != 2 {
3194 return Ok(false); }
3196 let signature_bytes = &witness_stack[0];
3197 let pubkey_bytes = &witness_stack[1];
3198
3199 if signature_bytes.is_empty() {
3200 return Ok(false);
3201 }
3202 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
3203 return Ok(false);
3204 }
3205
3206 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
3208 let computed_hash = Ripemd160::digest(pubkey_sha256);
3209 if &computed_hash[..] != pubkey_hash {
3210 return Ok(false);
3211 }
3212
3213 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
3215 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
3216 let p2pkh_script_code = bip143_p2wpkh_script_code(pubkey_hash);
3217 let sighash = crate::transaction_hash::calculate_bip143_sighash(
3218 tx,
3219 input_index,
3220 &p2pkh_script_code,
3221 amount,
3222 sighash_byte,
3223 precomputed_bip143,
3224 )?;
3225
3226 let height = block_height.unwrap_or(0);
3227 return signature::with_secp_context(|secp| {
3228 signature::verify_signature(
3229 secp,
3230 pubkey_bytes,
3231 signature_bytes,
3232 &sighash,
3233 flags,
3234 height,
3235 network,
3236 SigVersion::WitnessV0,
3237 )
3238 });
3239 } else {
3240 return Ok(false); }
3242 } else {
3244 let redeem_result = eval_script_with_context_full_inner(
3248 &redeem,
3249 stack,
3250 flags,
3251 tx,
3252 input_index,
3253 prevout_values,
3254 prevout_script_pubkeys,
3255 block_height,
3256 median_time_past,
3257 network,
3258 SigVersion::Base,
3259 Some(redeem.as_ref()), Some(script_sig), None, #[cfg(feature = "production")]
3263 None, None, #[cfg(feature = "production")]
3266 sighash_cache,
3267 )?;
3268 if !redeem_result {
3269 return Ok(false);
3270 }
3271 }
3272 }
3273
3274 assert!(
3276 stack.len() <= 1000,
3277 "Stack size {} exceeds reasonable maximum after scriptPubkey",
3278 stack.len()
3279 );
3280
3281 if let Some(_witness_stack) = witness {
3290 }
3294
3295 const SCRIPT_VERIFY_CLEANSTACK: u32 = 0x100;
3301
3302 let final_result = if (flags & SCRIPT_VERIFY_CLEANSTACK) != 0 {
3303 stack.len() == 1 && cast_to_bool(&stack[0])
3305 } else {
3306 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
3308 };
3309 Ok(final_result)
3310}
3311
3312#[allow(dead_code)]
3314fn eval_script_with_context(
3315 script: &ByteString,
3316 stack: &mut Vec<StackElement>,
3317 flags: u32,
3318 tx: &Transaction,
3319 input_index: usize,
3320 prevouts: &[TransactionOutput],
3321 network: crate::types::Network,
3322) -> Result<bool> {
3323 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
3325 let prevout_script_pubkeys: Vec<&[u8]> =
3326 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
3327 eval_script_with_context_full(
3328 script,
3329 stack,
3330 flags,
3331 tx,
3332 input_index,
3333 &prevout_values,
3334 &prevout_script_pubkeys,
3335 None, None, network,
3338 SigVersion::Base,
3339 None, None, #[cfg(feature = "production")]
3342 None, None, #[cfg(feature = "production")]
3345 None, )
3347}
3348
3349#[allow(clippy::too_many_arguments)]
3351fn eval_script_with_context_full(
3352 script: &[u8],
3353 stack: &mut Vec<StackElement>,
3354 flags: u32,
3355 tx: &Transaction,
3356 input_index: usize,
3357 prevout_values: &[i64],
3358 prevout_script_pubkeys: &[&[u8]],
3359 block_height: Option<u64>,
3360 median_time_past: Option<u64>,
3361 network: crate::types::Network,
3362 sigversion: SigVersion,
3363 script_sig_for_sighash: Option<&ByteString>,
3364 taproot_annex_hash: Option<&Hash>,
3365 #[cfg(feature = "production")] schnorr_collector: Option<
3366 &crate::bip348::SchnorrSignatureCollector,
3367 >,
3368 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3369 #[cfg(feature = "production")] sighash_cache: Option<
3370 &crate::transaction_hash::SighashMidstateCache,
3371 >,
3372) -> Result<bool> {
3373 #[cfg(all(feature = "production", feature = "profile"))]
3374 let _t0 = std::time::Instant::now();
3375 let r = eval_script_with_context_full_inner(
3376 script,
3377 stack,
3378 flags,
3379 tx,
3380 input_index,
3381 prevout_values,
3382 prevout_script_pubkeys,
3383 block_height,
3384 median_time_past,
3385 network,
3386 sigversion,
3387 None,
3388 script_sig_for_sighash,
3389 taproot_annex_hash,
3390 #[cfg(feature = "production")]
3391 schnorr_collector,
3392 precomputed_bip143,
3393 #[cfg(feature = "production")]
3394 sighash_cache,
3395 );
3396 #[cfg(all(feature = "production", feature = "profile"))]
3397 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
3398 r
3399}
3400
3401fn eval_script_with_context_full_inner(
3403 script: &[u8],
3404 stack: &mut Vec<StackElement>,
3405 flags: u32,
3406 tx: &Transaction,
3407 input_index: usize,
3408 prevout_values: &[i64],
3409 prevout_script_pubkeys: &[&[u8]],
3410 block_height: Option<u64>,
3411 median_time_past: Option<u64>,
3412 network: crate::types::Network,
3413 sigversion: SigVersion,
3414 redeem_script_for_sighash: Option<&[u8]>,
3415 script_sig_for_sighash: Option<&ByteString>,
3416 taproot_annex_hash: Option<&Hash>,
3417 #[cfg(feature = "production")] schnorr_collector: Option<
3418 &crate::bip348::SchnorrSignatureCollector,
3419 >,
3420 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3421 #[cfg(feature = "production")] sighash_cache: Option<
3422 &crate::transaction_hash::SighashMidstateCache,
3423 >,
3424) -> Result<bool> {
3425 use crate::constants::MAX_SCRIPT_SIZE;
3428 use crate::error::{ConsensusError, ScriptErrorCode};
3429
3430 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
3432 && script.len() > MAX_SCRIPT_SIZE
3433 {
3434 return Err(ConsensusError::ScriptErrorWithCode {
3435 code: ScriptErrorCode::ScriptSize,
3436 message: "Script size exceeds maximum".into(),
3437 });
3438 }
3439 assert!(
3440 stack.len() <= 1000,
3441 "Stack size {} exceeds reasonable maximum at start",
3442 stack.len()
3443 );
3444
3445 if sigversion == SigVersion::Tapscript {
3450 use crate::script::flags::SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS;
3451 let mut pc = 0usize;
3452 while pc < script.len() {
3453 let opcode = script[pc];
3454 if is_op_success(opcode) {
3455 if flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS != 0 {
3456 return Err(ConsensusError::ScriptErrorWithCode {
3457 code: ScriptErrorCode::BadOpcode,
3458 message: format!("OP_SUCCESSx opcode 0x{opcode:02x} is discouraged").into(),
3459 });
3460 }
3461 return Ok(true);
3462 }
3463 pc += op_advance(script, pc);
3465 }
3466 }
3467
3468 if stack.capacity() < 20 {
3470 stack.reserve(20);
3471 }
3472 let mut op_count = 0;
3473 assert!(op_count == 0, "Op count must start at zero");
3475
3476 #[cfg(feature = "production")]
3478 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
3479 #[cfg(not(feature = "production"))]
3480 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
3481 assert!(control_stack.is_empty(), "Control stack must start empty");
3483
3484 #[cfg(feature = "production")]
3485 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
3486 #[cfg(not(feature = "production"))]
3487 let mut altstack: Vec<StackElement> = Vec::new();
3488
3489 let mut code_separator_pos: usize = 0;
3493 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
3494
3495 let mut i = 0;
3497 while i < script.len() {
3498 #[cfg(feature = "production")]
3499 {
3500 prefetch::prefetch_ahead(script, i, 64); }
3503 let opcode = {
3505 #[cfg(feature = "production")]
3506 {
3507 unsafe { *script.get_unchecked(i) }
3508 }
3509 #[cfg(not(feature = "production"))]
3510 {
3511 script[i]
3512 }
3513 };
3514
3515 let in_false_branch = control_flow::in_false_branch(&control_stack);
3517
3518 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
3520 op_count += 1;
3521 assert!(
3523 op_count <= MAX_SCRIPT_OPS + 1,
3524 "Op count {op_count} must not exceed MAX_SCRIPT_OPS + 1"
3525 );
3526 if op_count > MAX_SCRIPT_OPS {
3527 return Err(make_operation_limit_error());
3528 }
3529 }
3530
3531 if stack.len() + altstack.len() > MAX_STACK_SIZE {
3533 return Err(make_stack_overflow_error());
3534 }
3535
3536 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
3538 let (data, advance) = if opcode <= 0x4b {
3539 let len = opcode as usize;
3541 if i + 1 + len > script.len() {
3542 return Ok(false); }
3544 (&script[i + 1..i + 1 + len], 1 + len)
3545 } else if opcode == OP_PUSHDATA1 {
3546 if i + 1 >= script.len() {
3548 return Ok(false);
3549 }
3550 let len = script[i + 1] as usize;
3551 if i + 2 + len > script.len() {
3552 return Ok(false);
3553 }
3554 (&script[i + 2..i + 2 + len], 2 + len)
3555 } else if opcode == OP_PUSHDATA2 {
3556 if i + 2 >= script.len() {
3558 return Ok(false);
3559 }
3560 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
3561 if i + 3 + len > script.len() {
3562 return Ok(false);
3563 }
3564 (&script[i + 3..i + 3 + len], 3 + len)
3565 } else {
3566 if i + 4 >= script.len() {
3569 return Ok(false);
3570 }
3571 let len = u32::from_le_bytes([
3572 script[i + 1],
3573 script[i + 2],
3574 script[i + 3],
3575 script[i + 4],
3576 ]) as usize;
3577 let data_start = i.saturating_add(5);
3578 let data_end = data_start.saturating_add(len);
3579 let advance = 5usize.saturating_add(len);
3580 if advance < 5 || data_end > script.len() || data_end < data_start {
3581 return Ok(false); }
3583 (&script[data_start..data_end], advance)
3584 };
3585
3586 if !in_false_branch {
3588 stack.push(to_stack_element(data));
3589 }
3590 i += advance;
3591 continue;
3592 }
3593
3594 if opcode == OP_DUP {
3600 if !in_false_branch {
3601 if stack.is_empty() {
3602 return Err(ConsensusError::ScriptErrorWithCode {
3603 code: ScriptErrorCode::InvalidStackOperation,
3604 message: "OP_DUP: empty stack".into(),
3605 });
3606 }
3607 let len = stack.len();
3610 #[cfg(feature = "production")]
3611 {
3612 if stack.capacity() == stack.len() {
3614 stack.reserve(1);
3615 }
3616 let item = unsafe { stack.get_unchecked(len - 1).clone() };
3618 stack.push(item);
3619 }
3620 #[cfg(not(feature = "production"))]
3621 {
3622 let item = stack.last().unwrap();
3623 stack.push(item.clone());
3624 }
3625 }
3626 i += 1;
3627 continue;
3628 }
3629
3630 if opcode == OP_EQUALVERIFY {
3632 if !in_false_branch {
3633 if stack.len() < 2 {
3634 return Err(ConsensusError::ScriptErrorWithCode {
3635 code: ScriptErrorCode::InvalidStackOperation,
3636 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3637 });
3638 }
3639 let a = stack.pop().unwrap();
3640 let b = stack.pop().unwrap();
3641 if a != b {
3642 return Ok(false);
3643 }
3644 }
3645 i += 1;
3646 continue;
3647 }
3648
3649 if opcode == OP_HASH160 {
3651 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
3652 return Ok(false);
3653 }
3654 i += 1;
3655 continue;
3656 }
3657
3658 if opcode == OP_VERIFY {
3660 if !in_false_branch {
3661 if let Some(item) = stack.pop() {
3662 if !cast_to_bool(&item) {
3663 return Ok(false);
3664 }
3665 } else {
3666 return Ok(false);
3667 }
3668 }
3669 i += 1;
3670 continue;
3671 }
3672
3673 if opcode == OP_EQUAL {
3675 if !in_false_branch {
3676 if stack.len() < 2 {
3677 return Err(ConsensusError::ScriptErrorWithCode {
3678 code: ScriptErrorCode::InvalidStackOperation,
3679 message: "OP_EQUAL: insufficient stack items".into(),
3680 });
3681 }
3682 let a = stack.pop().unwrap();
3683 let b = stack.pop().unwrap();
3684 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3685 }
3686 i += 1;
3687 continue;
3688 }
3689
3690 if opcode == OP_CHECKSIG
3693 || opcode == OP_CHECKSIGVERIFY
3694 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
3695 {
3696 if !in_false_branch {
3697 let effective_script_code = Some(&script[code_separator_pos..]);
3698 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3699 (Some(script), Some(last_codesep_opcode_pos))
3700 } else {
3701 (None, None)
3702 };
3703 let ctx = context::ScriptContext {
3704 tx,
3705 input_index,
3706 prevout_values,
3707 prevout_script_pubkeys,
3708 block_height,
3709 median_time_past,
3710 network,
3711 sigversion,
3712 redeem_script_for_sighash,
3713 script_sig_for_sighash,
3714 tapscript_for_sighash: tapscript,
3715 tapscript_codesep_pos: codesep,
3716 taproot_annex_hash,
3717 #[cfg(feature = "production")]
3718 schnorr_collector,
3719 #[cfg(feature = "production")]
3720 precomputed_bip143,
3721 #[cfg(feature = "production")]
3722 sighash_cache,
3723 };
3724 if !execute_opcode_with_context_full(
3725 opcode,
3726 stack,
3727 flags,
3728 &ctx,
3729 effective_script_code,
3730 )? {
3731 return Ok(false);
3732 }
3733 }
3734 i += 1;
3735 continue;
3736 }
3737
3738 match opcode {
3739 OP_0 => {
3741 if !in_false_branch {
3742 stack.push(to_stack_element(&[]));
3743 }
3744 }
3745
3746 OP_1_RANGE_START..=OP_1_RANGE_END => {
3748 if !in_false_branch {
3749 let num = opcode - OP_N_BASE;
3750 stack.push(to_stack_element(&[num]));
3751 }
3752 }
3753
3754 OP_1NEGATE => {
3756 if !in_false_branch {
3757 stack.push(to_stack_element(&[0x81])); }
3759 }
3760
3761 OP_NOP => {
3763 }
3765
3766 OP_VER => {
3771 if !in_false_branch {
3772 return Err(ConsensusError::ScriptErrorWithCode {
3773 code: ScriptErrorCode::DisabledOpcode,
3774 message: "OP_VER is disabled".into(),
3775 });
3776 }
3777 }
3778
3779 OP_IF => {
3780 if in_false_branch {
3782 control_stack.push(control_flow::ControlBlock::If { executing: false });
3783 i += 1;
3784 continue;
3785 }
3786
3787 if stack.is_empty() {
3788 return Err(ConsensusError::ScriptErrorWithCode {
3789 code: ScriptErrorCode::InvalidStackOperation,
3790 message: "OP_IF: empty stack".into(),
3791 });
3792 }
3793 let condition_bytes = stack.pop().unwrap();
3794 let condition = cast_to_bool(&condition_bytes);
3795
3796 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3797 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3798 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3799 && !control_flow::is_minimal_if_condition(&condition_bytes)
3800 {
3801 return Err(ConsensusError::ScriptErrorWithCode {
3802 code: ScriptErrorCode::MinimalIf,
3803 message: "OP_IF condition must be minimally encoded".into(),
3804 });
3805 }
3806
3807 control_stack.push(control_flow::ControlBlock::If {
3808 executing: condition,
3809 });
3810 }
3811 OP_NOTIF => {
3812 if in_false_branch {
3814 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
3815 i += 1;
3816 continue;
3817 }
3818
3819 if stack.is_empty() {
3820 return Err(ConsensusError::ScriptErrorWithCode {
3821 code: ScriptErrorCode::InvalidStackOperation,
3822 message: "OP_NOTIF: empty stack".into(),
3823 });
3824 }
3825 let condition_bytes = stack.pop().unwrap();
3826 let condition = cast_to_bool(&condition_bytes);
3827
3828 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3829 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3830 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3831 && !control_flow::is_minimal_if_condition(&condition_bytes)
3832 {
3833 return Err(ConsensusError::ScriptErrorWithCode {
3834 code: ScriptErrorCode::MinimalIf,
3835 message: "OP_NOTIF condition must be minimally encoded".into(),
3836 });
3837 }
3838
3839 control_stack.push(control_flow::ControlBlock::NotIf {
3840 executing: !condition,
3841 });
3842 }
3843 OP_ELSE => {
3844 if let Some(block) = control_stack.last_mut() {
3846 match block {
3847 control_flow::ControlBlock::If { executing }
3848 | control_flow::ControlBlock::NotIf { executing } => {
3849 *executing = !*executing;
3850 }
3851 }
3852 } else {
3853 return Err(ConsensusError::ScriptErrorWithCode {
3854 code: ScriptErrorCode::UnbalancedConditional,
3855 message: "OP_ELSE without matching IF/NOTIF".into(),
3856 });
3857 }
3858 }
3859 OP_ENDIF => {
3860 if control_stack.pop().is_none() {
3862 return Err(ConsensusError::ScriptErrorWithCode {
3863 code: ScriptErrorCode::UnbalancedConditional,
3864 message: "OP_ENDIF without matching IF/NOTIF".into(),
3865 });
3866 }
3867 }
3868
3869 OP_TOALTSTACK => {
3874 if in_false_branch {
3875 i += 1;
3876 continue;
3877 }
3878 if stack.is_empty() {
3879 return Err(ConsensusError::ScriptErrorWithCode {
3880 code: ScriptErrorCode::InvalidStackOperation,
3881 message: "OP_TOALTSTACK: empty stack".into(),
3882 });
3883 }
3884 altstack.push(stack.pop().unwrap());
3885 }
3886 OP_FROMALTSTACK => {
3888 if in_false_branch {
3889 i += 1;
3890 continue;
3891 }
3892 if altstack.is_empty() {
3893 return Err(ConsensusError::ScriptErrorWithCode {
3894 code: ScriptErrorCode::InvalidAltstackOperation,
3895 message: "OP_FROMALTSTACK: empty altstack".into(),
3896 });
3897 }
3898 stack.push(altstack.pop().unwrap());
3899 }
3900 OP_CODESEPARATOR => {
3902 if in_false_branch {
3903 i += 1;
3904 continue;
3905 }
3906 code_separator_pos = i + 1;
3907 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
3908 }
3909 _ => {
3910 if in_false_branch {
3911 i += 1;
3912 continue;
3913 }
3914
3915 let subscript_for_sighash = if matches!(
3920 opcode,
3921 OP_CHECKSIG
3922 | OP_CHECKSIGVERIFY
3923 | OP_CHECKSIGADD
3924 | OP_CHECKMULTISIG
3925 | OP_CHECKMULTISIGVERIFY
3926 ) {
3927 Some(&script[code_separator_pos..])
3928 } else {
3929 None
3930 };
3931 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
3932 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3933 (Some(script), Some(last_codesep_opcode_pos))
3934 } else {
3935 (None, None)
3936 };
3937 let ctx = context::ScriptContext {
3938 tx,
3939 input_index,
3940 prevout_values,
3941 prevout_script_pubkeys,
3942 block_height,
3943 median_time_past,
3944 network,
3945 sigversion,
3946 redeem_script_for_sighash,
3947 script_sig_for_sighash,
3948 tapscript_for_sighash: tapscript,
3949 tapscript_codesep_pos: codesep,
3950 taproot_annex_hash,
3951 #[cfg(feature = "production")]
3952 schnorr_collector,
3953 #[cfg(feature = "production")]
3954 precomputed_bip143,
3955 #[cfg(feature = "production")]
3956 sighash_cache,
3957 };
3958 if !execute_opcode_with_context_full(
3959 opcode,
3960 stack,
3961 flags,
3962 &ctx,
3963 effective_script_code,
3964 )? {
3965 return Ok(false);
3966 }
3967 }
3968 }
3969 i += 1;
3970 }
3971
3972 if !control_stack.is_empty() {
3974 return Err(ConsensusError::ScriptErrorWithCode {
3975 code: ScriptErrorCode::UnbalancedConditional,
3976 message: "Unclosed IF/NOTIF block".into(),
3977 });
3978 }
3979
3980 Ok(true)
3984}
3985
3986#[spec_locked("5.4.5", "DecodeCScriptNum")]
3990#[blvm_spec_lock::axiom(result >= -549755813887)]
3991#[blvm_spec_lock::ensures(result >= -549755813887)]
3992#[cfg(feature = "production")]
3993#[inline(always)]
3994pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3995 if data.len() > max_num_size {
3996 return Err(ConsensusError::ScriptErrorWithCode {
3997 code: ScriptErrorCode::InvalidStackOperation,
3998 message: format!(
3999 "Script number overflow: {} > {} bytes",
4000 data.len(),
4001 max_num_size
4002 )
4003 .into(),
4004 });
4005 }
4006 if data.is_empty() {
4007 return Ok(0);
4008 }
4009
4010 let len = data.len();
4012 let result = match len {
4013 1 => {
4014 let byte = data[0];
4015 if byte & 0x80 != 0 {
4016 -((byte & 0x7f) as i64)
4018 } else {
4019 byte as i64
4020 }
4021 }
4022 2 => {
4023 let byte0 = data[0] as i64;
4024 let byte1 = data[1] as i64;
4025 let value = byte0 | (byte1 << 8);
4026 if byte1 & 0x80 != 0 {
4027 -(value & !(0x80i64 << 8))
4029 } else {
4030 value
4031 }
4032 }
4033 _ => {
4034 let mut result: i64 = 0;
4036 for (i, &byte) in data.iter().enumerate() {
4037 result |= (byte as i64) << (8 * i);
4038 }
4039 let last_idx = len - 1;
4041 if data[last_idx] & 0x80 != 0 {
4042 result &= !(0x80i64 << (8 * last_idx));
4044 result = -result;
4045 }
4046 result
4047 }
4048 };
4049
4050 Ok(result)
4051}
4052
4053#[cfg(not(feature = "production"))]
4054#[inline]
4055pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
4056 if data.len() > max_num_size {
4057 return Err(ConsensusError::ScriptErrorWithCode {
4058 code: ScriptErrorCode::InvalidStackOperation,
4059 message: format!(
4060 "Script number overflow: {} > {} bytes",
4061 data.len(),
4062 max_num_size
4063 )
4064 .into(),
4065 });
4066 }
4067 if data.is_empty() {
4068 return Ok(0);
4069 }
4070 let mut result: i64 = 0;
4072 for (i, &byte) in data.iter().enumerate() {
4073 result |= (byte as i64) << (8 * i);
4074 }
4075 if data.last().expect("Data is not empty") & 0x80 != 0 {
4077 result &= !(0x80i64 << (8 * (data.len() - 1)));
4079 result = -result;
4080 }
4081 Ok(result)
4082}
4083
4084#[cfg(feature = "production")]
4087pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
4088 match value {
4090 0 => return vec![],
4091 1 => return vec![1],
4092 -1 => return vec![0x81],
4093 _ => {}
4094 }
4095
4096 let neg = value < 0;
4097 let mut absvalue = if neg {
4098 (-(value as i128)) as u64
4099 } else {
4100 value as u64
4101 };
4102 let mut result = Vec::with_capacity(4);
4104 while absvalue > 0 {
4105 result.push((absvalue & 0xff) as u8);
4106 absvalue >>= 8;
4107 }
4108 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
4110 result.push(if neg { 0x80 } else { 0x00 });
4111 } else if neg {
4112 *result.last_mut().unwrap() |= 0x80;
4113 }
4114 result
4115}
4116
4117#[cfg(not(feature = "production"))]
4118pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
4119 if value == 0 {
4120 return vec![];
4121 }
4122 let neg = value < 0;
4123 let mut absvalue = if neg {
4124 (-(value as i128)) as u64
4125 } else {
4126 value as u64
4127 };
4128 let mut result = Vec::new();
4129 while absvalue > 0 {
4130 result.push((absvalue & 0xff) as u8);
4131 absvalue >>= 8;
4132 }
4133 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
4135 result.push(if neg { 0x80 } else { 0x00 });
4136 } else if neg {
4137 *result.last_mut().unwrap() |= 0x80;
4138 }
4139 result
4140}
4141
4142#[cfg(feature = "production")]
4144#[inline(always)]
4145fn execute_opcode(
4146 opcode: u8,
4147 stack: &mut Vec<StackElement>,
4148 flags: u32,
4149 _sigversion: SigVersion,
4150) -> Result<bool> {
4151 match opcode {
4152 OP_0 => {
4154 stack.push(to_stack_element(&[]));
4155 Ok(true)
4156 }
4157
4158 OP_1..=OP_16 => {
4160 let num = opcode - OP_N_BASE;
4161 stack.push(to_stack_element(&[num]));
4162 Ok(true)
4163 }
4164
4165 OP_NOP => Ok(true),
4167
4168 OP_VER => Ok(false),
4170
4171 OP_DEPTH => {
4173 let depth = stack.len() as i64;
4174 stack.push(to_stack_element(&script_num_encode(depth)));
4175 Ok(true)
4176 }
4177
4178 OP_DUP => {
4180 if let Some(item) = stack.last().cloned() {
4181 stack.push(item);
4182 Ok(true)
4183 } else {
4184 Ok(false)
4185 }
4186 }
4187
4188 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
4190
4191 OP_SHA1 => crypto_ops::op_sha1(stack),
4193
4194 OP_SHA256 => crypto_ops::op_sha256(stack),
4196
4197 OP_HASH160 => crypto_ops::op_hash160(stack),
4199
4200 OP_HASH256 => crypto_ops::op_hash256(stack),
4202
4203 OP_EQUAL => {
4206 if stack.len() < 2 {
4207 return Err(ConsensusError::ScriptErrorWithCode {
4208 code: ScriptErrorCode::InvalidStackOperation,
4209 message: "OP_EQUAL: insufficient stack items".into(),
4210 });
4211 }
4212 let a = stack.pop().unwrap();
4213 let b = stack.pop().unwrap();
4214 stack.push(to_stack_element(if a == b { &[1u8] } else { &[] }));
4215 Ok(true)
4216 }
4217
4218 OP_EQUALVERIFY => {
4221 if stack.len() < 2 {
4222 return Err(ConsensusError::ScriptErrorWithCode {
4223 code: ScriptErrorCode::InvalidStackOperation,
4224 message: "OP_EQUALVERIFY: insufficient stack items".into(),
4225 });
4226 }
4227 let a = stack.pop().unwrap();
4228 let b = stack.pop().unwrap();
4229 let f_equal = a == b;
4230 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
4232 if f_equal {
4233 stack.pop();
4235 Ok(true)
4236 } else {
4237 Err(ConsensusError::ScriptErrorWithCode {
4238 code: ScriptErrorCode::EqualVerify,
4239 message: "OP_EQUALVERIFY: stack items not equal".into(),
4240 })
4241 }
4242 }
4243
4244 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
4246
4247 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
4249
4250 OP_RETURN => Ok(false),
4252
4253 OP_VERIFY => {
4255 if let Some(item) = stack.pop() {
4256 Ok(cast_to_bool(&item))
4257 } else {
4258 Ok(false)
4259 }
4260 }
4261
4262 OP_CHECKLOCKTIMEVERIFY => {
4266 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
4267 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
4268 Ok(true)
4269 } else {
4270 Ok(false)
4271 }
4272 }
4273
4274 OP_CHECKSEQUENCEVERIFY => {
4278 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
4279 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
4280 Ok(true)
4281 } else {
4282 Ok(false)
4283 }
4284 }
4285
4286 OP_IFDUP => {
4288 if let Some(item) = stack.last().cloned() {
4289 if cast_to_bool(&item) {
4290 stack.push(item);
4291 }
4292 Ok(true)
4293 } else {
4294 Ok(false)
4295 }
4296 }
4297
4298 OP_DROP => {
4301 if stack.pop().is_some() {
4302 Ok(true)
4303 } else {
4304 Ok(false)
4305 }
4306 }
4307
4308 OP_NIP => {
4310 if stack.len() >= 2 {
4311 let top = stack.pop().unwrap();
4312 stack.pop(); stack.push(top);
4314 Ok(true)
4315 } else {
4316 Ok(false)
4317 }
4318 }
4319
4320 OP_OVER => {
4322 if stack.len() >= 2 {
4323 let len = stack.len();
4324 #[cfg(feature = "production")]
4325 {
4326 unsafe {
4328 let second = stack.get_unchecked(len - 2);
4329 stack.push(second.clone());
4330 }
4331 }
4332 #[cfg(not(feature = "production"))]
4333 {
4334 let second = stack[stack.len() - 2].clone();
4335 stack.push(second);
4336 }
4337 Ok(true)
4338 } else {
4339 Ok(false)
4340 }
4341 }
4342
4343 OP_PICK => {
4345 if let Some(n_bytes) = stack.pop() {
4346 let n_val = script_num_decode(&n_bytes, 4)?;
4349 if n_val < 0 || n_val as usize >= stack.len() {
4350 return Ok(false);
4351 }
4352 let n = n_val as usize;
4353 let len = stack.len();
4354 #[cfg(feature = "production")]
4355 {
4356 unsafe {
4358 let item = stack.get_unchecked(len - 1 - n);
4359 stack.push(item.clone());
4360 }
4361 }
4362 #[cfg(not(feature = "production"))]
4363 {
4364 let item = stack[stack.len() - 1 - n].clone();
4365 stack.push(item);
4366 }
4367 Ok(true)
4368 } else {
4369 Ok(false)
4370 }
4371 }
4372
4373 OP_ROLL => {
4375 if let Some(n_bytes) = stack.pop() {
4376 let n_val = script_num_decode(&n_bytes, 4)?;
4379 if n_val < 0 || n_val as usize >= stack.len() {
4380 return Ok(false);
4381 }
4382 let n = n_val as usize;
4383 let len = stack.len();
4384 #[cfg(feature = "production")]
4385 {
4386 let idx = len - 1 - n;
4388 let item = stack.remove(idx);
4389 stack.push(item);
4390 }
4391 #[cfg(not(feature = "production"))]
4392 {
4393 let item = stack.remove(stack.len() - 1 - n);
4394 stack.push(item);
4395 }
4396 Ok(true)
4397 } else {
4398 Ok(false)
4399 }
4400 }
4401
4402 OP_ROT => {
4404 if stack.len() >= 3 {
4405 let top = stack.pop().unwrap();
4406 let second = stack.pop().unwrap();
4407 let third = stack.pop().unwrap();
4408 stack.push(second);
4409 stack.push(top);
4410 stack.push(third);
4411 Ok(true)
4412 } else {
4413 Ok(false)
4414 }
4415 }
4416
4417 OP_SWAP => {
4419 if stack.len() >= 2 {
4420 let top = stack.pop().unwrap();
4421 let second = stack.pop().unwrap();
4422 stack.push(top);
4423 stack.push(second);
4424 Ok(true)
4425 } else {
4426 Ok(false)
4427 }
4428 }
4429
4430 OP_TUCK => {
4432 if stack.len() >= 2 {
4433 let top = stack.pop().unwrap();
4434 let second = stack.pop().unwrap();
4435 stack.push(top.clone());
4436 stack.push(second);
4437 stack.push(top);
4438 Ok(true)
4439 } else {
4440 Ok(false)
4441 }
4442 }
4443
4444 OP_2DROP => {
4446 if stack.len() >= 2 {
4447 stack.pop();
4448 stack.pop();
4449 Ok(true)
4450 } else {
4451 Ok(false)
4452 }
4453 }
4454
4455 OP_2DUP => {
4457 if stack.len() >= 2 {
4458 let top = stack[stack.len() - 1].clone();
4459 let second = stack[stack.len() - 2].clone();
4460 stack.push(second);
4461 stack.push(top);
4462 Ok(true)
4463 } else {
4464 Ok(false)
4465 }
4466 }
4467
4468 OP_3DUP => {
4470 if stack.len() >= 3 {
4471 let top = stack[stack.len() - 1].clone();
4472 let second = stack[stack.len() - 2].clone();
4473 let third = stack[stack.len() - 3].clone();
4474 stack.push(third);
4475 stack.push(second);
4476 stack.push(top);
4477 Ok(true)
4478 } else {
4479 Ok(false)
4480 }
4481 }
4482
4483 OP_2OVER => {
4485 if stack.len() >= 4 {
4486 let fourth = stack[stack.len() - 4].clone();
4487 let third = stack[stack.len() - 3].clone();
4488 stack.push(fourth);
4489 stack.push(third);
4490 Ok(true)
4491 } else {
4492 Ok(false)
4493 }
4494 }
4495
4496 OP_2ROT => {
4499 if stack.len() >= 6 {
4500 let sixth = stack.remove(stack.len() - 6); let fifth = stack.remove(stack.len() - 5); stack.push(sixth);
4506 stack.push(fifth);
4507 Ok(true)
4508 } else {
4509 Ok(false)
4510 }
4511 }
4512
4513 OP_2SWAP => {
4515 if stack.len() >= 4 {
4516 let top = stack.pop().unwrap();
4517 let second = stack.pop().unwrap();
4518 let third = stack.pop().unwrap();
4519 let fourth = stack.pop().unwrap();
4520 stack.push(second);
4521 stack.push(top);
4522 stack.push(fourth);
4523 stack.push(third);
4524 Ok(true)
4525 } else {
4526 Ok(false)
4527 }
4528 }
4529
4530 OP_SIZE => {
4533 if let Some(item) = stack.last() {
4534 let size = item.len() as i64;
4535 stack.push(to_stack_element(&script_num_encode(size)));
4536 Ok(true)
4537 } else {
4538 Ok(false)
4539 }
4540 }
4541
4542 OP_1ADD => {
4547 if let Some(item) = stack.pop() {
4548 let a = script_num_decode(&item, 4)?;
4549 stack.push(to_stack_element(&script_num_encode(a + 1)));
4550 Ok(true)
4551 } else {
4552 Ok(false)
4553 }
4554 }
4555 OP_1SUB => {
4557 if let Some(item) = stack.pop() {
4558 let a = script_num_decode(&item, 4)?;
4559 stack.push(to_stack_element(&script_num_encode(a - 1)));
4560 Ok(true)
4561 } else {
4562 Ok(false)
4563 }
4564 }
4565 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4567 code: ScriptErrorCode::DisabledOpcode,
4568 message: "OP_2MUL is disabled".into(),
4569 }),
4570 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4572 code: ScriptErrorCode::DisabledOpcode,
4573 message: "OP_2DIV is disabled".into(),
4574 }),
4575 OP_NEGATE => {
4577 if let Some(item) = stack.pop() {
4578 let a = script_num_decode(&item, 4)?;
4579 stack.push(to_stack_element(&script_num_encode(-a)));
4580 Ok(true)
4581 } else {
4582 Ok(false)
4583 }
4584 }
4585 OP_ABS => {
4587 if let Some(item) = stack.pop() {
4588 let a = script_num_decode(&item, 4)?;
4589 stack.push(to_stack_element(&script_num_encode(a.abs())));
4590 Ok(true)
4591 } else {
4592 Ok(false)
4593 }
4594 }
4595 OP_NOT => {
4597 if let Some(item) = stack.pop() {
4598 let a = script_num_decode(&item, 4)?;
4599 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4600 1
4601 } else {
4602 0
4603 })));
4604 Ok(true)
4605 } else {
4606 Ok(false)
4607 }
4608 }
4609 OP_0NOTEQUAL => {
4611 if let Some(item) = stack.pop() {
4612 let a = script_num_decode(&item, 4)?;
4613 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4614 1
4615 } else {
4616 0
4617 })));
4618 Ok(true)
4619 } else {
4620 Ok(false)
4621 }
4622 }
4623 OP_ADD => arithmetic::op_add(stack),
4624 OP_SUB => arithmetic::op_sub(stack),
4625 OP_MUL => arithmetic::op_mul_disabled(),
4626 OP_DIV => arithmetic::op_div_disabled(),
4627 OP_MOD => arithmetic::op_mod_disabled(),
4628 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4629 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4630 OP_BOOLAND => arithmetic::op_booland(stack),
4631 OP_BOOLOR => arithmetic::op_boolor(stack),
4632 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4633 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4634 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4635 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4636 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4637 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4638 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4639 OP_MIN => arithmetic::op_min(stack),
4640 OP_MAX => arithmetic::op_max(stack),
4641 OP_WITHIN => arithmetic::op_within(stack),
4642
4643 OP_CODESEPARATOR => Ok(true),
4645
4646 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4649
4650 OP_CHECKTEMPLATEVERIFY => {
4654 const SCRIPT_VERIFY_CHECKTEMPLATEVERIFY: u32 = 0x8000;
4655 #[cfg(feature = "ctv")]
4656 if (flags & SCRIPT_VERIFY_CHECKTEMPLATEVERIFY) != 0 {
4657 return Err(ConsensusError::ScriptErrorWithCode {
4658 code: ScriptErrorCode::TxInvalid,
4659 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4660 });
4661 }
4662 Ok(true)
4663 }
4664
4665 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4667 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4668 Err(ConsensusError::ScriptErrorWithCode {
4669 code: ScriptErrorCode::DisabledOpcode,
4670 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4671 })
4672 }
4673
4674 OP_1NEGATE => {
4676 stack.push(to_stack_element(&[0x81]));
4677 Ok(true)
4678 }
4679
4680 OP_CHECKMULTISIG => {
4685 if stack.is_empty() {
4686 return Ok(false);
4687 }
4688 let n_bytes = stack.pop().unwrap();
4689 let n = match script_num_decode(&n_bytes, 4) {
4690 Ok(v) if (0..=20).contains(&v) => v as usize,
4691 _ => return Ok(false),
4692 };
4693 if stack.len() < n {
4694 return Ok(false);
4695 }
4696 for _ in 0..n {
4697 stack.pop();
4698 }
4699 if stack.is_empty() {
4700 return Ok(false);
4701 }
4702 let m_bytes = stack.pop().unwrap();
4703 let m = match script_num_decode(&m_bytes, 4) {
4704 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4705 _ => return Ok(false),
4706 };
4707 if stack.len() < m {
4708 return Ok(false);
4709 }
4710 for _ in 0..m {
4711 stack.pop();
4712 }
4713 if stack.is_empty() {
4715 return Ok(false);
4716 }
4717 stack.pop();
4718 stack.push(to_stack_element(&[if m == 0 { 1 } else { 0 }]));
4720 Ok(true)
4721 }
4722
4723 OP_CHECKMULTISIGVERIFY => {
4725 if stack.is_empty() {
4726 return Ok(false);
4727 }
4728 let n_bytes = stack.pop().unwrap();
4729 let n = match script_num_decode(&n_bytes, 4) {
4730 Ok(v) if (0..=20).contains(&v) => v as usize,
4731 _ => return Ok(false),
4732 };
4733 if stack.len() < n {
4734 return Ok(false);
4735 }
4736 for _ in 0..n {
4737 stack.pop();
4738 }
4739 if stack.is_empty() {
4740 return Ok(false);
4741 }
4742 let m_bytes = stack.pop().unwrap();
4743 let m = match script_num_decode(&m_bytes, 4) {
4744 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4745 _ => return Ok(false),
4746 };
4747 if stack.len() < m {
4748 return Ok(false);
4749 }
4750 for _ in 0..m {
4751 stack.pop();
4752 }
4753 if stack.is_empty() {
4754 return Ok(false);
4755 }
4756 stack.pop();
4757 Ok(m == 0)
4759 }
4760
4761 _ => Ok(false),
4763 }
4764}
4765
4766#[allow(dead_code)]
4768fn execute_opcode_with_context(
4769 opcode: u8,
4770 stack: &mut Vec<StackElement>,
4771 flags: u32,
4772 tx: &Transaction,
4773 input_index: usize,
4774 prevouts: &[TransactionOutput],
4775 network: crate::types::Network,
4776) -> Result<bool> {
4777 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4779 let prevout_script_pubkeys: Vec<&[u8]> =
4780 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4781 let ctx = context::ScriptContext {
4782 tx,
4783 input_index,
4784 prevout_values: &prevout_values,
4785 prevout_script_pubkeys: &prevout_script_pubkeys,
4786 block_height: None,
4787 median_time_past: None,
4788 network,
4789 sigversion: SigVersion::Base,
4790 redeem_script_for_sighash: None,
4791 script_sig_for_sighash: None,
4792 tapscript_for_sighash: None,
4793 tapscript_codesep_pos: None,
4794 taproot_annex_hash: None,
4795 #[cfg(feature = "production")]
4796 schnorr_collector: None,
4797 #[cfg(feature = "production")]
4798 precomputed_bip143: None,
4799 #[cfg(feature = "production")]
4800 sighash_cache: None,
4801 };
4802 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4803}
4804
4805#[cfg(feature = "production")]
4809#[inline(always)]
4810pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4811 let mut i = 0;
4812 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4813 i += adv1;
4814 if i >= script_sig.len() {
4815 return None;
4816 }
4817 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4818 i += adv2;
4819 if i >= script_sig.len() {
4820 return None;
4821 }
4822 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4823 i += adv3;
4824 if i != script_sig.len() {
4825 return None;
4826 }
4827 let sig = &script_sig[s_start..s_end];
4828 let redeem = &script_sig[r_start..r_end];
4829 if sig.is_empty() || redeem.len() != 25 {
4830 return None;
4831 }
4832 if redeem[0] != OP_DUP
4833 || redeem[1] != OP_HASH160
4834 || redeem[2] != PUSH_20_BYTES
4835 || redeem[23] != OP_EQUALVERIFY
4836 || redeem[24] != OP_CHECKSIG
4837 {
4838 return None;
4839 }
4840 Some((sig[sig.len() - 1], redeem))
4841}
4842
4843#[inline(always)]
4847pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4848 let mut i = 0;
4849 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4850 i += adv1;
4851 if i >= script_sig.len() {
4852 return None;
4853 }
4854 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4855 i += adv2;
4856 if i != script_sig.len() {
4857 return None;
4858 }
4859 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4860}
4861
4862pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4865 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4866 if advance != script_sig.len() {
4867 return None;
4868 }
4869 Some(&script_sig[data_start..data_end])
4870}
4871
4872fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4874 if i >= script.len() {
4875 return None;
4876 }
4877 let opcode = script[i];
4878 let (advance, data_start, data_end) = if opcode == OP_0 {
4879 return None;
4880 } else if opcode <= 0x4b {
4881 let len = opcode as usize;
4882 if i + 1 + len > script.len() {
4883 return None;
4884 }
4885 (1 + len, i + 1, i + 1 + len)
4886 } else if opcode == OP_PUSHDATA1 {
4887 if i + 1 >= script.len() {
4888 return None;
4889 }
4890 let len = script[i + 1] as usize;
4891 if i + 2 + len > script.len() {
4892 return None;
4893 }
4894 (2 + len, i + 2, i + 2 + len)
4895 } else if opcode == OP_PUSHDATA2 {
4896 if i + 2 >= script.len() {
4897 return None;
4898 }
4899 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4900 if i + 3 + len > script.len() {
4901 return None;
4902 }
4903 (3 + len, i + 3, i + 3 + len)
4904 } else if opcode == OP_PUSHDATA4 {
4905 if i + 4 >= script.len() {
4906 return None;
4907 }
4908 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4909 as usize;
4910 if i + 5 + len > script.len() {
4911 return None;
4912 }
4913 (5 + len, i + 5, i + 5 + len)
4914 } else {
4915 return None;
4916 };
4917 Some((advance, data_start, data_end))
4918}
4919
4920#[spec_locked("5.2.1", "P2SHPushOnlyCheck")]
4923pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4924 parse_script_sig_push_only(script_sig).is_some()
4925}
4926
4927fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4931 let mut out = Vec::new();
4932 let mut i = 0;
4933 while i < script_sig.len() {
4934 let opcode = script_sig[i];
4935 if !is_push_opcode(opcode) {
4936 return None;
4937 }
4938 let (advance, data) = if opcode == OP_0 {
4939 (1, vec![])
4940 } else if opcode <= 0x4b {
4941 let len = opcode as usize;
4942 if i + 1 + len > script_sig.len() {
4943 return None;
4944 }
4945 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4946 } else if opcode == OP_PUSHDATA1 {
4947 if i + 1 >= script_sig.len() {
4948 return None;
4949 }
4950 let len = script_sig[i + 1] as usize;
4951 if i + 2 + len > script_sig.len() {
4952 return None;
4953 }
4954 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4955 } else if opcode == OP_PUSHDATA2 {
4956 if i + 2 >= script_sig.len() {
4957 return None;
4958 }
4959 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4960 if i + 3 + len > script_sig.len() {
4961 return None;
4962 }
4963 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4964 } else if opcode == OP_PUSHDATA4 {
4965 if i + 4 >= script_sig.len() {
4966 return None;
4967 }
4968 let len = u32::from_le_bytes([
4969 script_sig[i + 1],
4970 script_sig[i + 2],
4971 script_sig[i + 3],
4972 script_sig[i + 4],
4973 ]) as usize;
4974 if i + 5 + len > script_sig.len() {
4975 return None;
4976 }
4977 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4978 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4979 let n = script_num_from_opcode(opcode);
4981 (1, script_num_encode(n))
4982 } else {
4983 return None;
4984 };
4985 out.push(to_stack_element(&data));
4986 i += advance;
4987 }
4988 Some(out)
4989}
4990
4991fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4995 parse_script_sig_push_only(script_sig)
4996}
4997
4998fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
5003 if redeem.len() < 4 {
5004 return None;
5005 }
5006 let n_op = redeem[0];
5007 if !(OP_1..=OP_16).contains(&n_op) {
5008 return None;
5009 }
5010 let n = (n_op - OP_1 + 1) as usize;
5011 let mut i = 1;
5012 let mut pubkeys = Vec::with_capacity(n);
5013 for _ in 0..n {
5014 if i >= redeem.len() {
5015 return None;
5016 }
5017 let first = redeem[i];
5018 let pk_len = if first == 0x02 || first == 0x03 {
5019 33
5020 } else if first == 0x04 {
5021 65
5022 } else {
5023 return None;
5024 };
5025 if i + pk_len > redeem.len() {
5026 return None;
5027 }
5028 pubkeys.push(&redeem[i..i + pk_len]);
5029 i += pk_len;
5030 }
5031 if i + 2 > redeem.len() {
5032 return None;
5033 }
5034 let m_op = redeem[i];
5035 if !(OP_1..=OP_16).contains(&m_op) {
5036 return None;
5037 }
5038 let m = m_op - OP_1 + 1;
5039 if redeem[i + 1] != OP_CHECKMULTISIG {
5040 return None;
5041 }
5042 Some((m, n as u8, pubkeys))
5043}
5044
5045fn script_num_from_opcode(opcode: u8) -> i64 {
5047 match opcode {
5048 OP_1NEGATE => -1,
5049 OP_1 => 1,
5050 OP_2 => 2,
5051 OP_3 => 3,
5052 OP_4 => 4,
5053 OP_5 => 5,
5054 OP_6 => 6,
5055 OP_7 => 7,
5056 OP_8 => 8,
5057 OP_9 => 9,
5058 OP_10 => 10,
5059 OP_11 => 11,
5060 OP_12 => 12,
5061 OP_13 => 13,
5062 OP_14 => 14,
5063 OP_15 => 15,
5064 OP_16 => 16,
5065 _ => 0,
5066 }
5067}
5068
5069pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
5073 let len = data.len();
5074 let mut result = Vec::with_capacity(len + 5);
5075 if len < 76 {
5076 result.push(len as u8);
5077 } else if len < 256 {
5078 result.push(OP_PUSHDATA1);
5079 result.push(len as u8);
5080 } else if len < 65536 {
5081 result.push(OP_PUSHDATA2);
5082 result.push((len & 0xff) as u8);
5083 result.push(((len >> 8) & 0xff) as u8);
5084 } else {
5085 result.push(OP_PUSHDATA4);
5086 result.push((len & 0xff) as u8);
5087 result.push(((len >> 8) & 0xff) as u8);
5088 result.push(((len >> 16) & 0xff) as u8);
5089 result.push(((len >> 24) & 0xff) as u8);
5090 }
5091 result.extend_from_slice(data);
5092 result
5093}
5094
5095#[inline]
5097fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
5098 if pc >= script.len() {
5099 return None;
5100 }
5101 let opcode = script[pc];
5102 let advance = if opcode <= 0x4b {
5103 1 + opcode as usize
5104 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
5105 2 + script[pc + 1] as usize
5106 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
5107 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
5108 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
5109 5 + ((script[pc + 1] as usize)
5110 | ((script[pc + 2] as usize) << 8)
5111 | ((script[pc + 3] as usize) << 16)
5112 | ((script[pc + 4] as usize) << 24))
5113 } else {
5114 1
5115 };
5116 let next = pc + advance;
5117 if next > script.len() {
5118 None
5119 } else {
5120 Some(next)
5121 }
5122}
5123
5124#[spec_locked("5.1.1", "FindAndDelete")]
5130#[inline]
5131pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
5132 if pattern.is_empty() {
5133 return std::borrow::Cow::Borrowed(script);
5134 }
5135 if pattern.len() > script.len() {
5136 return std::borrow::Cow::Borrowed(script);
5137 }
5138 if !script.windows(pattern.len()).any(|w| w == pattern) {
5143 return std::borrow::Cow::Borrowed(script);
5144 }
5145 let end = script.len();
5146 let mut n_found = 0usize;
5147 let mut result = Vec::new();
5148 let mut pc = 0usize;
5149 let mut pc2 = 0usize;
5150
5151 loop {
5152 result.extend_from_slice(&script[pc2..pc]);
5153 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
5154 pc += pattern.len();
5155 n_found += 1;
5156 }
5157 pc2 = pc;
5158 if pc >= end {
5159 break;
5160 }
5161 let Some(next_pc) = script_get_op_advance(script, pc) else {
5162 break;
5163 };
5164 pc = next_pc;
5165 }
5166
5167 if n_found > 0 {
5168 result.extend_from_slice(&script[pc2..end]);
5169 std::borrow::Cow::Owned(result)
5170 } else {
5171 std::borrow::Cow::Borrowed(script)
5172 }
5173}
5174
5175fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
5177 let mut pos = 0u32;
5178 let mut i = 0usize;
5179 while i < script.len() && i <= byte_index {
5180 let opcode = script[i];
5181 let advance = if opcode <= 0x4b {
5182 1 + opcode as usize
5183 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
5184 2 + script[i + 1] as usize
5185 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
5186 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
5187 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
5188 5 + ((script[i + 1] as usize)
5189 | ((script[i + 2] as usize) << 8)
5190 | ((script[i + 3] as usize) << 16)
5191 | ((script[i + 4] as usize) << 24))
5192 } else {
5193 1
5194 };
5195 if i == byte_index {
5196 return pos;
5197 }
5198 pos += 1;
5199 i = std::cmp::min(i + advance, script.len());
5200 }
5201 0xffff_ffff
5202}
5203
5204#[cfg_attr(feature = "production", inline(always))]
5206fn execute_opcode_with_context_full(
5207 opcode: u8,
5208 stack: &mut Vec<StackElement>,
5209 flags: u32,
5210 ctx: &context::ScriptContext<'_>,
5211 effective_script_code: Option<&[u8]>,
5212) -> Result<bool> {
5213 let tx = ctx.tx;
5214 let input_index = ctx.input_index;
5215 let prevout_values = ctx.prevout_values;
5216 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
5217 let block_height = ctx.block_height;
5218 let median_time_past = ctx.median_time_past;
5219 let network = ctx.network;
5220 let sigversion = ctx.sigversion;
5221 let script_sig_for_sighash = ctx.script_sig_for_sighash;
5222 let tapscript_for_sighash = ctx.tapscript_for_sighash;
5223 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
5224 let redeem_script_for_sighash = effective_script_code;
5225 #[cfg(feature = "production")]
5226 let schnorr_collector = ctx.schnorr_collector;
5227 #[cfg(feature = "production")]
5228 let precomputed_bip143 = ctx.precomputed_bip143;
5229 #[cfg(feature = "production")]
5230 let sighash_cache = ctx.sighash_cache;
5231
5232 match opcode {
5234 OP_CHECKSIG => {
5236 if stack.len() >= 2 {
5237 let pubkey_bytes = stack.pop().unwrap();
5238 let signature_bytes = stack.pop().unwrap();
5239
5240 if signature_bytes.is_empty() {
5242 stack.push(to_stack_element(&[0]));
5243 return Ok(true);
5244 }
5245
5246 if sigversion == SigVersion::Tapscript && pubkey_bytes.len() == 32 {
5248 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5249 if let Some((sig_bytes, sighash_byte)) =
5250 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5251 {
5252 let (tapscript, codesep_pos) = tapscript_for_sighash
5253 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5254 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5255 let sighash = if tapscript.is_empty() {
5256 crate::taproot::compute_taproot_signature_hash(
5257 tx,
5258 input_index,
5259 prevout_values,
5260 prevout_script_pubkeys,
5261 sighash_byte,
5262 None,
5263 )?
5264 } else {
5265 crate::taproot::compute_tapscript_signature_hash(
5266 tx,
5267 input_index,
5268 prevout_values,
5269 prevout_script_pubkeys,
5270 tapscript,
5271 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5272 codesep_pos,
5273 sighash_byte,
5274 ctx.taproot_annex_hash,
5275 )?
5276 };
5277
5278 #[cfg(feature = "production")]
5279 let is_valid = {
5280 use crate::bip348::verify_tapscript_schnorr_signature;
5281 verify_tapscript_schnorr_signature(
5282 &sighash,
5283 &pubkey_bytes,
5284 &sig_bytes,
5285 schnorr_collector,
5286 )
5287 .unwrap_or(false)
5288 };
5289
5290 #[cfg(not(feature = "production"))]
5291 let is_valid = {
5292 #[cfg(feature = "csfs")]
5293 let x = {
5294 use crate::bip348::verify_tapscript_schnorr_signature;
5295 verify_tapscript_schnorr_signature(
5296 &sighash,
5297 &pubkey_bytes,
5298 &sig_bytes,
5299 None,
5300 )
5301 .unwrap_or(false)
5302 };
5303 #[cfg(not(feature = "csfs"))]
5304 let x = false;
5305 x
5306 };
5307
5308 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5309 return Ok(true);
5310 }
5311 stack.push(to_stack_element(&[0]));
5313 return Ok(true);
5314 }
5315 if sigversion == SigVersion::Tapscript {
5316 stack.push(to_stack_element(&[1]));
5318 return Ok(true);
5319 }
5320
5321 let sig_len = signature_bytes.len();
5325 let sighash_byte = signature_bytes[sig_len - 1];
5326 let _der_sig = &signature_bytes[..sig_len - 1];
5327
5328 let sighash = if sigversion == SigVersion::WitnessV0 {
5332 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5334
5335 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5337 prevout_script_pubkeys
5338 .get(input_index)
5339 .copied()
5340 .unwrap_or(&[])
5341 });
5342
5343 crate::transaction_hash::calculate_bip143_sighash(
5344 tx,
5345 input_index,
5346 script_code,
5347 amount,
5348 sighash_byte,
5349 precomputed_bip143,
5350 )?
5351 } else {
5352 use crate::transaction_hash::{
5354 SighashType, calculate_transaction_sighash_single_input,
5355 };
5356 let sighash_type = SighashType::from_byte(sighash_byte);
5357
5358 let pattern = serialize_push_data(signature_bytes.as_ref());
5362
5363 let base_script = match (
5364 redeem_script_for_sighash,
5365 prevout_script_pubkeys.get(input_index),
5366 ) {
5367 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5368 (Some(redeem), _) => redeem,
5369 (None, Some(prevout)) => *prevout,
5370 (None, None) => &[],
5371 };
5372 let cleaned = find_and_delete(base_script, &pattern);
5373
5374 calculate_transaction_sighash_single_input(
5375 tx,
5376 input_index,
5377 cleaned.as_ref(),
5378 prevout_values[input_index],
5379 sighash_type,
5380 #[cfg(feature = "production")]
5381 sighash_cache,
5382 )?
5383 };
5384
5385 let height = block_height.unwrap_or(0);
5389 #[cfg(feature = "production")]
5390 let is_valid = signature::with_secp_context(|secp| {
5391 signature::verify_signature(
5392 secp,
5393 &pubkey_bytes,
5394 &signature_bytes, &sighash,
5396 flags,
5397 height,
5398 network,
5399 sigversion,
5400 )
5401 })?;
5402
5403 #[cfg(not(feature = "production"))]
5404 let is_valid = {
5405 let secp = signature::new_secp();
5406 signature::verify_signature(
5407 &secp,
5408 &pubkey_bytes,
5409 &signature_bytes, &sighash,
5411 flags,
5412 height,
5413 network,
5414 sigversion,
5415 )?
5416 };
5417
5418 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5419 Ok(true)
5420 } else {
5421 Ok(false)
5422 }
5423 }
5424
5425 OP_CHECKSIGVERIFY => {
5427 if stack.len() >= 2 {
5428 let pubkey_bytes = stack.pop().unwrap();
5429 let signature_bytes = stack.pop().unwrap();
5430
5431 if signature_bytes.is_empty() {
5433 return Ok(false);
5434 }
5435
5436 if sigversion == SigVersion::Tapscript {
5438 if pubkey_bytes.len() == 32 {
5439 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5440 if let Some((sig_bytes, sighash_byte)) =
5441 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5442 {
5443 let (tapscript, codesep_pos) = tapscript_for_sighash
5444 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5445 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5446 let sighash = if tapscript.is_empty() {
5447 crate::taproot::compute_taproot_signature_hash(
5448 tx,
5449 input_index,
5450 prevout_values,
5451 prevout_script_pubkeys,
5452 sighash_byte,
5453 None,
5454 )?
5455 } else {
5456 crate::taproot::compute_tapscript_signature_hash(
5457 tx,
5458 input_index,
5459 prevout_values,
5460 prevout_script_pubkeys,
5461 tapscript,
5462 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5463 codesep_pos,
5464 sighash_byte,
5465 ctx.taproot_annex_hash,
5466 )?
5467 };
5468 #[cfg(feature = "production")]
5469 let is_valid = {
5470 use crate::bip348::verify_tapscript_schnorr_signature;
5471 verify_tapscript_schnorr_signature(
5472 &sighash,
5473 &pubkey_bytes,
5474 &sig_bytes,
5475 schnorr_collector,
5476 )
5477 .unwrap_or(false)
5478 };
5479 #[cfg(not(feature = "production"))]
5480 let is_valid = {
5481 #[cfg(feature = "csfs")]
5482 let x = {
5483 use crate::bip348::verify_tapscript_schnorr_signature;
5484 verify_tapscript_schnorr_signature(
5485 &sighash,
5486 &pubkey_bytes,
5487 &sig_bytes,
5488 None,
5489 )
5490 .unwrap_or(false)
5491 };
5492 #[cfg(not(feature = "csfs"))]
5493 let x = false;
5494 x
5495 };
5496 if !is_valid {
5497 return Ok(false); }
5499 return Ok(true);
5500 }
5501 return Ok(false);
5503 }
5504 return Ok(true);
5506 }
5507
5508 let sig_len = signature_bytes.len();
5511 let sighash_byte = signature_bytes[sig_len - 1];
5512 let _der_sig = &signature_bytes[..sig_len - 1];
5513
5514 let sighash = if sigversion == SigVersion::WitnessV0 {
5518 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5520
5521 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5522 prevout_script_pubkeys
5523 .get(input_index)
5524 .copied()
5525 .unwrap_or(&[])
5526 });
5527
5528 crate::transaction_hash::calculate_bip143_sighash(
5529 tx,
5530 input_index,
5531 script_code,
5532 amount,
5533 sighash_byte,
5534 precomputed_bip143,
5535 )?
5536 } else {
5537 use crate::transaction_hash::{
5539 SighashType, calculate_transaction_sighash_single_input,
5540 };
5541 let sighash_type = SighashType::from_byte(sighash_byte);
5542
5543 let pattern = serialize_push_data(signature_bytes.as_ref());
5545
5546 let base_script = match (
5547 redeem_script_for_sighash,
5548 prevout_script_pubkeys.get(input_index),
5549 ) {
5550 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5551 (Some(redeem), _) => redeem,
5552 (None, Some(prevout)) => *prevout,
5553 (None, None) => &[],
5554 };
5555 let cleaned = find_and_delete(base_script, &pattern);
5556
5557 calculate_transaction_sighash_single_input(
5558 tx,
5559 input_index,
5560 cleaned.as_ref(),
5561 prevout_values[input_index],
5562 sighash_type,
5563 #[cfg(feature = "production")]
5564 sighash_cache,
5565 )?
5566 };
5567
5568 let height = block_height.unwrap_or(0);
5572 #[cfg(feature = "production")]
5573 let is_valid = signature::with_secp_context(|secp| {
5574 signature::verify_signature(
5575 secp,
5576 &pubkey_bytes,
5577 &signature_bytes, &sighash,
5579 flags,
5580 height,
5581 network,
5582 sigversion,
5583 )
5584 })?;
5585
5586 #[cfg(not(feature = "production"))]
5587 let is_valid = {
5588 let secp = signature::new_secp();
5589 signature::verify_signature(
5590 &secp,
5591 &pubkey_bytes,
5592 &signature_bytes, &sighash,
5594 flags,
5595 height,
5596 network,
5597 sigversion,
5598 )?
5599 };
5600
5601 if is_valid { Ok(true) } else { Ok(false) }
5602 } else {
5603 Ok(false)
5604 }
5605 }
5606
5607 OP_CHECKSIGADD => {
5609 if sigversion != SigVersion::Tapscript {
5610 return Err(ConsensusError::ScriptErrorWithCode {
5611 code: ScriptErrorCode::DisabledOpcode,
5612 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5613 });
5614 }
5615 if stack.len() < 3 {
5616 return Err(ConsensusError::ScriptErrorWithCode {
5617 code: ScriptErrorCode::InvalidStackOperation,
5618 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5619 });
5620 }
5621 let pubkey_bytes = stack.pop().unwrap();
5623 let n_bytes = stack.pop().unwrap();
5624 let signature_bytes = stack.pop().unwrap();
5625 let n = script_num_decode(&n_bytes, 4)?;
5626
5627 if signature_bytes.is_empty() {
5629 stack.push(to_stack_element(&script_num_encode(n)));
5630 return Ok(true);
5631 }
5632
5633 if pubkey_bytes.len() == 32 {
5635 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5636 if let Some((sig_bytes, sighash_byte)) =
5637 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5638 {
5639 let (tapscript, codesep_pos) = tapscript_for_sighash
5640 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5641 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5642 let sighash = if tapscript.is_empty() {
5643 crate::taproot::compute_taproot_signature_hash(
5644 tx,
5645 input_index,
5646 prevout_values,
5647 prevout_script_pubkeys,
5648 sighash_byte,
5649 None,
5650 )?
5651 } else {
5652 crate::taproot::compute_tapscript_signature_hash(
5653 tx,
5654 input_index,
5655 prevout_values,
5656 prevout_script_pubkeys,
5657 tapscript,
5658 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5659 codesep_pos,
5660 sighash_byte,
5661 ctx.taproot_annex_hash,
5662 )?
5663 };
5664
5665 #[cfg(feature = "production")]
5666 let is_valid = {
5667 use crate::bip348::verify_tapscript_schnorr_signature;
5668 verify_tapscript_schnorr_signature(
5669 &sighash,
5670 &pubkey_bytes,
5671 &sig_bytes,
5672 schnorr_collector,
5673 )
5674 .unwrap_or(false)
5675 };
5676
5677 #[cfg(not(feature = "production"))]
5678 let is_valid = {
5679 #[cfg(feature = "csfs")]
5680 let x = {
5681 use crate::bip348::verify_tapscript_schnorr_signature;
5682 verify_tapscript_schnorr_signature(
5683 &sighash,
5684 &pubkey_bytes,
5685 &sig_bytes,
5686 None,
5687 )
5688 .unwrap_or(false)
5689 };
5690 #[cfg(not(feature = "csfs"))]
5691 let x = false;
5692 x
5693 };
5694
5695 if !is_valid {
5696 return Ok(false); }
5698 stack.push(to_stack_element(&script_num_encode(n + 1)));
5699 return Ok(true);
5700 }
5701 return Ok(false); }
5703
5704 stack.push(to_stack_element(&script_num_encode(n + 1)));
5706 Ok(true)
5707 }
5708
5709 OP_CHECKMULTISIG => {
5711 if stack.len() < 2 {
5714 return Ok(false);
5715 }
5716
5717 let n_bytes = stack.pop().unwrap();
5719 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
5720 ConsensusError::ScriptErrorWithCode {
5721 code: ScriptErrorCode::InvalidStackOperation,
5722 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
5723 }
5724 })?;
5725 if !(0..=20).contains(&n_raw) {
5726 return Ok(false);
5727 }
5728 let n = n_raw as usize;
5729 if stack.len() < n + 1 {
5730 return Ok(false);
5731 }
5732
5733 let mut pubkeys = Vec::with_capacity(n);
5735 for _ in 0..n {
5736 pubkeys.push(stack.pop().unwrap());
5737 }
5738
5739 let m_bytes = stack.pop().unwrap();
5741 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
5742 ConsensusError::ScriptErrorWithCode {
5743 code: ScriptErrorCode::InvalidStackOperation,
5744 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
5745 }
5746 })?;
5747 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
5748 return Ok(false);
5749 }
5750 let m = m_raw as usize;
5751 if stack.len() < m + 1 {
5752 return Ok(false);
5753 }
5754
5755 let mut signatures = Vec::with_capacity(m);
5757 for _ in 0..m {
5758 signatures.push(stack.pop().unwrap());
5759 }
5760
5761 let dummy = stack.pop().unwrap();
5764 if flags & 0x10 != 0 {
5765 let height = block_height.unwrap_or(0);
5766 use crate::bip_validation::Bip147Network;
5768 let bip147_network = match network {
5769 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5770 crate::types::Network::Testnet => Bip147Network::Testnet,
5771 crate::types::Network::Regtest | crate::types::Network::Signet => {
5772 Bip147Network::Regtest
5773 }
5774 };
5775
5776 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5780
5781 let bip147_active = height
5782 >= match bip147_network {
5783 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5784 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5785 Bip147Network::Regtest => 0,
5786 };
5787
5788 if bip147_active {
5789 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5793 if !is_empty {
5794 return Err(ConsensusError::ScriptErrorWithCode {
5795 code: ScriptErrorCode::SigNullDummy,
5796 message: format!(
5797 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5798 )
5799 .into(),
5800 });
5801 }
5802 }
5803 }
5804
5805 let height = block_height.unwrap_or(0);
5808
5809 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5812 let base_script = match (
5813 redeem_script_for_sighash,
5814 prevout_script_pubkeys.get(input_index),
5815 ) {
5816 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5817 (Some(redeem), _) => redeem,
5818 (None, Some(prevout)) => *prevout,
5819 (None, None) => &[],
5820 };
5821 let mut cleaned = base_script.to_vec();
5822 for sig in &signatures {
5823 if !sig.is_empty() {
5824 let pattern = serialize_push_data(sig.as_ref());
5825 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5826 }
5827 }
5828 cleaned
5829 } else {
5830 redeem_script_for_sighash
5832 .map(|s| s.to_vec())
5833 .unwrap_or_else(|| {
5834 prevout_script_pubkeys
5835 .get(input_index)
5836 .map(|p| p.to_vec())
5837 .unwrap_or_default()
5838 })
5839 };
5840
5841 use crate::transaction_hash::{
5842 SighashType, calculate_transaction_sighash_single_input,
5843 };
5844
5845 #[cfg(feature = "production")]
5847 let use_batch = pubkeys.len() * signatures.len() >= 4;
5848
5849 #[cfg(feature = "production")]
5850 let (valid_sigs, _) = if use_batch {
5851 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5853 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5854 if non_empty.is_empty() {
5855 vec![]
5856 } else {
5857 let specs: Vec<(usize, u8, &[u8])> = non_empty
5858 .iter()
5859 .map(|s| {
5860 (
5861 input_index,
5862 s.as_ref()[s.as_ref().len() - 1],
5863 cleaned_script_for_multisig.as_ref(),
5864 )
5865 })
5866 .collect();
5867 crate::transaction_hash::batch_compute_legacy_sighashes(
5868 tx,
5869 prevout_values,
5870 prevout_script_pubkeys,
5871 &specs,
5872 )?
5873 }
5874 } else {
5875 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5877 signatures
5878 .iter()
5879 .filter(|s| !s.is_empty())
5880 .map(|sig_bytes| {
5881 let sighash_byte = sig_bytes[sig_bytes.len() - 1];
5882 crate::transaction_hash::calculate_bip143_sighash(
5883 tx,
5884 input_index,
5885 &cleaned_script_for_multisig,
5886 amount,
5887 sighash_byte,
5888 precomputed_bip143,
5889 )
5890 })
5891 .collect::<Result<Vec<_>>>()?
5892 };
5893
5894 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5896 Vec::with_capacity(pubkeys.len() * signatures.len());
5897 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5898 let mut sighash_idx = 0usize;
5899 for (j, sig_bytes) in signatures.iter().enumerate() {
5900 if sig_bytes.is_empty() {
5901 sig_idx_to_sighash_idx.push(usize::MAX);
5902 } else {
5903 sig_idx_to_sighash_idx.push(sighash_idx);
5904 let sh = sighashes[sighash_idx];
5905 sighash_idx += 1;
5906 for pubkey_bytes in &pubkeys {
5907 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5908 }
5909 }
5910 }
5911
5912 let results = if tasks.is_empty() {
5913 vec![]
5914 } else {
5915 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
5916 };
5917
5918 let mut sig_index = 0;
5920 let mut valid_sigs = 0usize;
5921 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5922 if sig_index >= signatures.len() {
5923 break;
5924 }
5925 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5927 sig_index += 1;
5928 }
5929 if sig_index >= signatures.len() {
5930 break;
5931 }
5932 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5933 if sh_idx == usize::MAX {
5934 continue;
5935 }
5936 let task_idx = sh_idx * pubkeys.len() + i;
5937 if task_idx < results.len() && results[task_idx] {
5938 valid_sigs += 1;
5939 sig_index += 1;
5940 }
5941 }
5942
5943 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5945 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5946 for (j, sig_bytes) in signatures.iter().enumerate() {
5947 if sig_bytes.is_empty() {
5948 continue;
5949 }
5950 let sh_idx = sig_idx_to_sighash_idx[j];
5951 if sh_idx == usize::MAX {
5952 continue;
5953 }
5954 let sig_start = sh_idx * pubkeys.len();
5955 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5956 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5957 if !matched {
5958 return Err(ConsensusError::ScriptErrorWithCode {
5959 code: ScriptErrorCode::SigNullFail,
5960 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5961 });
5962 }
5963 }
5964 }
5965 (valid_sigs, ())
5966 } else {
5967 let mut sig_index = 0;
5968 let mut valid_sigs = 0;
5969 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5970
5971 for pubkey_bytes in &pubkeys {
5972 if sig_index >= signatures.len() {
5973 break;
5974 }
5975
5976 let signature_bytes = &signatures[sig_index];
5977
5978 if signature_bytes.is_empty() {
5979 continue;
5980 }
5981
5982 let sig_len = signature_bytes.len();
5983 let sighash_byte = signature_bytes[sig_len - 1];
5984
5985 let sighash = if sigversion == SigVersion::WitnessV0 {
5987 crate::transaction_hash::calculate_bip143_sighash(
5988 tx,
5989 input_index,
5990 &cleaned_script_for_multisig,
5991 amount,
5992 sighash_byte,
5993 #[cfg(feature = "production")]
5994 precomputed_bip143,
5995 #[cfg(not(feature = "production"))]
5996 None,
5997 )?
5998 } else {
5999 let sighash_type = SighashType::from_byte(sighash_byte);
6000 calculate_transaction_sighash_single_input(
6001 tx,
6002 input_index,
6003 &cleaned_script_for_multisig,
6004 prevout_values[input_index],
6005 sighash_type,
6006 #[cfg(feature = "production")]
6007 sighash_cache,
6008 )?
6009 };
6010
6011 #[cfg(feature = "production")]
6012 let is_valid = signature::with_secp_context(|secp| {
6013 signature::verify_signature(
6014 secp,
6015 pubkey_bytes,
6016 signature_bytes,
6017 &sighash,
6018 flags,
6019 height,
6020 network,
6021 sigversion,
6022 )
6023 })?;
6024
6025 #[cfg(not(feature = "production"))]
6026 let is_valid = {
6027 let secp = signature::new_secp();
6028 signature::verify_signature(
6029 &secp,
6030 pubkey_bytes,
6031 signature_bytes,
6032 &sighash,
6033 flags,
6034 height,
6035 network,
6036 sigversion,
6037 )?
6038 };
6039
6040 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6041 if !is_valid
6042 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6043 && !signature_bytes.is_empty()
6044 {
6045 return Err(ConsensusError::ScriptErrorWithCode {
6046 code: ScriptErrorCode::SigNullFail,
6047 message:
6048 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6049 .into(),
6050 });
6051 }
6052
6053 if is_valid {
6054 valid_sigs += 1;
6055 sig_index += 1;
6056 }
6057 }
6058 (valid_sigs, ())
6059 };
6060
6061 #[cfg(not(feature = "production"))]
6062 let (valid_sigs, _) = {
6063 let mut sig_index = 0;
6064 let mut valid_sigs = 0;
6065 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
6066
6067 for pubkey_bytes in &pubkeys {
6068 if sig_index >= signatures.len() {
6069 break;
6070 }
6071 let signature_bytes = &signatures[sig_index];
6072 if signature_bytes.is_empty() {
6073 continue;
6074 }
6075 let sig_len = signature_bytes.len();
6076 let sighash_byte = signature_bytes[sig_len - 1];
6077
6078 let sighash = if sigversion == SigVersion::WitnessV0 {
6080 crate::transaction_hash::calculate_bip143_sighash(
6081 tx,
6082 input_index,
6083 &cleaned_script_for_multisig,
6084 amount,
6085 sighash_byte,
6086 None,
6087 )?
6088 } else {
6089 let sighash_type = SighashType::from_byte(sighash_byte);
6090 calculate_transaction_sighash_single_input(
6091 tx,
6092 input_index,
6093 &cleaned_script_for_multisig,
6094 prevout_values[input_index],
6095 sighash_type,
6096 )?
6097 };
6098 let secp = signature::new_secp();
6099 let is_valid = signature::verify_signature(
6100 &secp,
6101 pubkey_bytes,
6102 signature_bytes,
6103 &sighash,
6104 flags,
6105 height,
6106 network,
6107 sigversion,
6108 )?;
6109 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6110 if !is_valid
6111 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6112 && !signature_bytes.is_empty()
6113 {
6114 return Err(ConsensusError::ScriptErrorWithCode {
6115 code: ScriptErrorCode::SigNullFail,
6116 message:
6117 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6118 .into(),
6119 });
6120 }
6121 if is_valid {
6122 valid_sigs += 1;
6123 sig_index += 1;
6124 }
6125 }
6126 (valid_sigs, ())
6127 };
6128
6129 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
6131 Ok(true)
6132 }
6133
6134 OP_CHECKMULTISIGVERIFY => {
6136 let ctx_checkmultisig = context::ScriptContext {
6138 tx,
6139 input_index,
6140 prevout_values,
6141 prevout_script_pubkeys,
6142 block_height,
6143 median_time_past,
6144 network,
6145 sigversion,
6146 redeem_script_for_sighash,
6147 script_sig_for_sighash,
6148 tapscript_for_sighash,
6149 tapscript_codesep_pos,
6150 taproot_annex_hash: None,
6151 #[cfg(feature = "production")]
6152 schnorr_collector: None,
6153 #[cfg(feature = "production")]
6154 precomputed_bip143,
6155 #[cfg(feature = "production")]
6156 sighash_cache,
6157 };
6158 let result = execute_opcode_with_context_full(
6159 OP_CHECKMULTISIG,
6160 stack,
6161 flags,
6162 &ctx_checkmultisig,
6163 redeem_script_for_sighash,
6164 )?;
6165 if !result {
6166 return Ok(false);
6167 }
6168 if let Some(top) = stack.pop() {
6170 if !cast_to_bool(&top) {
6171 return Ok(false);
6172 }
6173 Ok(true)
6174 } else {
6175 Ok(false)
6176 }
6177 }
6178
6179 OP_CHECKLOCKTIMEVERIFY => {
6184 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
6186 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
6187 return Ok(true);
6188 }
6189
6190 use crate::locktime::{check_bip65, decode_locktime_value};
6191
6192 if stack.is_empty() {
6193 return Err(ConsensusError::ScriptErrorWithCode {
6194 code: ScriptErrorCode::InvalidStackOperation,
6195 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
6196 });
6197 }
6198
6199 let locktime_bytes = stack.last().expect("Stack is not empty");
6201 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
6202 Some(v) => v,
6203 None => {
6204 return Err(ConsensusError::ScriptErrorWithCode {
6205 code: ScriptErrorCode::MinimalData,
6206 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
6207 });
6208 }
6209 };
6210
6211 let tx_locktime = tx.lock_time as u32;
6212
6213 if !check_bip65(tx_locktime, locktime_value) {
6215 return Ok(false);
6216 }
6217
6218 let input_seq = if input_index < tx.inputs.len() {
6220 tx.inputs[input_index].sequence
6221 } else {
6222 0xffffffff
6223 };
6224 if input_seq == 0xffffffff {
6225 return Ok(false);
6226 }
6227
6228 Ok(true)
6230 }
6231
6232 OP_CHECKSEQUENCEVERIFY => {
6241 use crate::locktime::{
6242 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
6243 is_sequence_disabled,
6244 };
6245
6246 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
6248 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
6249 return Ok(true);
6250 }
6251
6252 if stack.is_empty() {
6253 return Ok(false);
6254 }
6255
6256 let sequence_bytes = stack.last().expect("Stack is not empty");
6259 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
6260 Some(v) => v,
6261 None => return Ok(false), };
6263
6264 if input_index >= tx.inputs.len() {
6266 return Ok(false);
6267 }
6268 let input_sequence = tx.inputs[input_index].sequence as u32;
6269
6270 if is_sequence_disabled(input_sequence) {
6272 return Ok(true);
6273 }
6274
6275 let type_flag = extract_sequence_type_flag(sequence_value);
6277 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
6278
6279 let input_type_flag = extract_sequence_type_flag(input_sequence);
6281 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
6282
6283 if type_flag != input_type_flag {
6285 return Ok(false);
6286 }
6287
6288 if input_locktime < locktime_mask {
6290 return Ok(false);
6291 }
6292
6293 Ok(true)
6295 }
6296
6297 OP_CHECKTEMPLATEVERIFY => {
6306 #[cfg(not(feature = "ctv"))]
6307 {
6308 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6310 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6311 return Err(ConsensusError::ScriptErrorWithCode {
6312 code: ScriptErrorCode::BadOpcode,
6313 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
6314 });
6315 }
6316 Ok(true) }
6318
6319 #[cfg(feature = "ctv")]
6320 {
6321 use crate::constants::{
6322 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
6323 };
6324
6325 let ctv_activation = match network {
6327 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
6328 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
6329 crate::types::Network::Regtest | crate::types::Network::Signet => {
6330 CTV_ACTIVATION_REGTEST
6331 }
6332 };
6333
6334 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
6335 if !ctv_active {
6336 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6338 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6339 return Err(ConsensusError::ScriptErrorWithCode {
6340 code: ScriptErrorCode::BadOpcode,
6341 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
6342 });
6343 }
6344 return Ok(true); }
6346
6347 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
6349 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
6350 return Ok(true);
6352 }
6353
6354 use crate::bip119::calculate_template_hash;
6355
6356 if stack.is_empty() {
6358 return Err(ConsensusError::ScriptErrorWithCode {
6359 code: ScriptErrorCode::InvalidStackOperation,
6360 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
6361 });
6362 }
6363
6364 let template_hash_bytes = stack.pop().unwrap();
6365
6366 if template_hash_bytes.len() != 32 {
6368 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6371 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6372 return Err(ConsensusError::ScriptErrorWithCode {
6373 code: ScriptErrorCode::InvalidStackOperation,
6374 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
6375 .into(),
6376 });
6377 }
6378 return Ok(true); }
6380
6381 let mut expected_hash = [0u8; 32];
6383 expected_hash.copy_from_slice(&template_hash_bytes);
6384
6385 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
6386 ConsensusError::ScriptErrorWithCode {
6387 code: ScriptErrorCode::TxInvalid,
6388 message: format!("CTV hash calculation failed: {e}").into(),
6389 }
6390 })?;
6391
6392 use crate::crypto::hash_compare::hash_eq;
6394 let matches = hash_eq(&expected_hash, &actual_hash);
6395
6396 if !matches {
6397 return Ok(false); }
6399
6400 Ok(true)
6402 }
6403 }
6404
6405 OP_CHECKSIGFROMSTACK => {
6416 #[cfg(not(feature = "csfs"))]
6417 {
6418 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6421 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6422 return Err(ConsensusError::ScriptErrorWithCode {
6423 code: ScriptErrorCode::BadOpcode,
6424 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
6425 });
6426 }
6427 Ok(true) }
6429
6430 #[cfg(feature = "csfs")]
6431 {
6432 use crate::constants::{
6433 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
6434 };
6435
6436 if sigversion != SigVersion::Tapscript {
6438 return Err(ConsensusError::ScriptErrorWithCode {
6439 code: ScriptErrorCode::BadOpcode,
6440 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
6441 });
6442 }
6443
6444 let csfs_activation = match network {
6446 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
6447 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
6448 crate::types::Network::Regtest | crate::types::Network::Signet => {
6449 CSFS_ACTIVATION_REGTEST
6450 }
6451 };
6452
6453 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
6454 if !csfs_active {
6455 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6457 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6458 return Err(ConsensusError::ScriptErrorWithCode {
6459 code: ScriptErrorCode::BadOpcode,
6460 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
6461 });
6462 }
6463 return Ok(true); }
6465
6466 use crate::bip348::verify_signature_from_stack;
6467
6468 if stack.len() < 3 {
6470 return Err(ConsensusError::ScriptErrorWithCode {
6471 code: ScriptErrorCode::InvalidStackOperation,
6472 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
6473 });
6474 }
6475
6476 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
6483 return Err(ConsensusError::ScriptErrorWithCode {
6484 code: ScriptErrorCode::PubkeyType,
6485 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
6486 });
6487 }
6488
6489 if signature_bytes.is_empty() {
6491 stack.push(to_stack_element(&[])); return Ok(true);
6493 }
6494
6495 #[cfg(feature = "production")]
6498 let is_valid = {
6499 verify_signature_from_stack(
6500 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6505 .unwrap_or(false)
6506 };
6507 #[cfg(not(feature = "production"))]
6508 let is_valid = verify_signature_from_stack(
6509 &message_bytes, &pubkey_bytes, &signature_bytes, )
6513 .unwrap_or(false);
6514
6515 if !is_valid {
6516 return Ok(false);
6518 }
6519
6520 stack.push(to_stack_element(&[0x01])); Ok(true)
6527 }
6528 }
6529
6530 _ => execute_opcode_cold(opcode, stack, flags),
6532 }
6533}
6534
6535#[cold]
6537fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6538 execute_opcode(opcode, stack, flags, SigVersion::Base)
6539}
6540
6541#[cfg(feature = "production")]
6556pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6557 (
6558 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6559 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6560 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6561 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6562 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6563 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6564 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6565 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6566 )
6567}
6568
6569#[cfg(all(feature = "production", feature = "benchmarking"))]
6576pub fn clear_script_cache() {
6577 if let Some(cache) = SCRIPT_CACHE.get() {
6578 let mut cache = cache.write().unwrap();
6579 cache.clear();
6580 }
6581}
6582
6583#[cfg(all(feature = "production", feature = "benchmarking"))]
6597pub fn clear_hash_cache() {
6598 crypto_ops::clear_hash_cache();
6599}
6600
6601#[cfg(all(feature = "production", feature = "benchmarking"))]
6614pub fn clear_all_caches() {
6615 clear_script_cache();
6616 clear_hash_cache();
6617}
6618
6619#[cfg(all(feature = "production", feature = "benchmarking"))]
6633pub fn clear_stack_pool() {
6634 STACK_POOL.with(|pool| {
6635 let mut pool = pool.borrow_mut();
6636 pool.clear();
6637 });
6638}
6639
6640#[cfg(all(feature = "production", feature = "benchmarking"))]
6654pub fn reset_benchmarking_state() {
6655 clear_all_caches();
6656 clear_stack_pool();
6657 disable_caching(false); #[cfg(feature = "benchmarking")]
6660 crate::transaction_hash::clear_sighash_templates();
6661}
6662
6663#[cfg(test)]
6664mod tests {
6665 use super::*;
6666
6667 #[test]
6668 fn test_eval_script_simple() {
6669 let script = vec![OP_1]; let mut stack = Vec::new();
6671
6672 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6673 assert_eq!(stack.len(), 1);
6674 assert_eq!(stack[0].as_ref(), &[1]);
6675 }
6676
6677 #[test]
6678 fn test_eval_script_overflow() {
6679 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6681
6682 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6683 }
6684
6685 #[test]
6686 fn test_verify_script_simple() {
6687 let _script_sig = [0x51]; let _script_pubkey = [0x51]; let script_sig = vec![0x51]; let script_pubkey = vec![0x76, 0x88]; assert!(!verify_script(&script_sig, &script_pubkey, None, 0).unwrap());
6698 }
6699
6700 #[test]
6705 fn test_op_0() {
6706 let script = vec![OP_0]; let mut stack = Vec::new();
6708 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6709 assert!(result); assert_eq!(stack.len(), 1);
6711 assert!(stack[0].is_empty());
6712 }
6713
6714 #[test]
6715 fn test_op_1_to_op_16() {
6716 for i in 1..=16 {
6718 let opcode = 0x50 + i;
6719 let script = vec![opcode];
6720 let mut stack = Vec::new();
6721 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6722 assert!(result);
6723 assert_eq!(stack.len(), 1);
6724 assert_eq!(stack[0].as_ref(), &[i]);
6725 }
6726 }
6727
6728 #[test]
6729 fn test_op_dup() {
6730 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6732 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6733 assert!(result); assert_eq!(stack.len(), 2);
6735 assert_eq!(stack[0].as_ref(), &[1]);
6736 assert_eq!(stack[1].as_ref(), &[1]);
6737 }
6738
6739 #[test]
6740 fn test_op_dup_empty_stack() {
6741 let script = vec![OP_DUP]; let mut stack = Vec::new();
6743 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6744 assert!(!result);
6745 }
6746
6747 #[test]
6748 fn test_op_hash160() {
6749 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6751 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6752 assert!(result);
6753 assert_eq!(stack.len(), 1);
6754 assert_eq!(stack[0].len(), 20); }
6756
6757 #[test]
6758 fn test_op_hash160_empty_stack() {
6759 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6761 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6762 assert!(!result);
6763 }
6764
6765 #[test]
6766 fn test_op_hash256() {
6767 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6769 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6770 assert!(result);
6771 assert_eq!(stack.len(), 1);
6772 assert_eq!(stack[0].len(), 32); }
6774
6775 #[test]
6776 fn test_op_hash256_empty_stack() {
6777 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6779 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6780 assert!(!result);
6781 }
6782
6783 #[test]
6784 fn test_op_equal() {
6785 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6787 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6788 assert!(result);
6789 assert_eq!(stack.len(), 1);
6790 assert_eq!(stack[0].as_ref(), &[1]); }
6792
6793 #[test]
6794 fn test_op_equal_false() {
6795 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6797 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6798 assert!(result); assert_eq!(stack.len(), 1);
6800 assert!(stack[0].is_empty()); }
6802
6803 #[test]
6804 fn test_op_equal_insufficient_stack() {
6805 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6807 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6808 assert!(
6809 result.is_err(),
6810 "OP_EQUAL with insufficient stack should return error"
6811 );
6812 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6813 assert_eq!(
6814 code,
6815 crate::error::ScriptErrorCode::InvalidStackOperation,
6816 "Should return InvalidStackOperation"
6817 );
6818 }
6819 }
6820
6821 #[test]
6822 fn test_op_verify() {
6823 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6825 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6826 assert!(result); assert_eq!(stack.len(), 0); }
6829
6830 #[test]
6831 fn test_op_verify_false() {
6832 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6834 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6835 assert!(!result);
6836 }
6837
6838 #[test]
6839 fn test_op_verify_empty_stack() {
6840 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6842 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6843 assert!(!result);
6844 }
6845
6846 #[test]
6847 fn test_op_equalverify() {
6848 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6850 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6851 assert!(result); assert_eq!(stack.len(), 0); }
6854
6855 #[test]
6856 fn test_op_equalverify_false() {
6857 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6859 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6860 assert!(
6861 result.is_err(),
6862 "OP_EQUALVERIFY with false condition should return error"
6863 );
6864 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6865 assert_eq!(
6866 code,
6867 crate::error::ScriptErrorCode::EqualVerify,
6868 "Should return EqualVerify"
6869 );
6870 }
6871 }
6872
6873 #[test]
6874 fn test_op_checksig() {
6875 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6879 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6880 assert!(result); assert_eq!(stack.len(), 1);
6882 }
6884
6885 #[test]
6886 fn test_op_checksig_insufficient_stack() {
6887 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6889 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6890 assert!(
6891 result.is_err(),
6892 "OP_CHECKSIG with insufficient stack should return error"
6893 );
6894 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6895 assert_eq!(
6896 code,
6897 crate::error::ScriptErrorCode::InvalidStackOperation,
6898 "Should return InvalidStackOperation"
6899 );
6900 }
6901 }
6902
6903 #[test]
6904 fn test_unknown_opcode() {
6905 let script = vec![0xff]; let mut stack = Vec::new();
6907 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6908 assert!(!result);
6909 }
6910
6911 #[test]
6912 fn test_script_size_limit() {
6913 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6915 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6916 assert!(result.is_err());
6917 }
6918
6919 #[test]
6920 fn test_operation_count_limit() {
6921 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6924 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6925 assert!(result.is_err());
6926 }
6927
6928 #[test]
6929 fn test_stack_underflow_multiple_ops() {
6930 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6932 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6933 assert!(result.is_err(), "Stack underflow should return error");
6934 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6935 assert_eq!(
6936 code,
6937 crate::error::ScriptErrorCode::InvalidStackOperation,
6938 "Should return InvalidStackOperation"
6939 );
6940 }
6941 }
6942
6943 #[test]
6944 fn test_final_stack_empty() {
6945 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6948 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6949 assert!(result); assert_eq!(stack.len(), 2);
6951 }
6952
6953 #[test]
6954 fn test_final_stack_false() {
6955 let script = vec![OP_0]; let mut stack = Vec::new();
6958 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6959 assert!(result); }
6961
6962 #[test]
6963 fn test_verify_script_with_witness() {
6964 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6969
6970 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6971 assert!(result); }
6973
6974 #[test]
6975 fn test_verify_script_failure() {
6976 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_0]; let witness = None;
6980 let flags = 0;
6981
6982 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6983 assert!(!result); }
6985
6986 #[test]
6991 fn test_op_ifdup_true() {
6992 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6994 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6995 assert!(result); assert_eq!(stack.len(), 2);
6997 assert_eq!(stack[0].as_ref(), &[1]);
6998 assert_eq!(stack[1].as_ref(), &[1]);
6999 }
7000
7001 #[test]
7002 fn test_op_ifdup_false() {
7003 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
7005 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7006 assert!(result); assert_eq!(stack.len(), 1);
7008 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
7009 }
7010
7011 #[test]
7012 fn test_op_depth() {
7013 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
7015 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7016 assert!(result); assert_eq!(stack.len(), 3);
7018 assert_eq!(stack[2].as_ref(), &[2]); }
7020
7021 #[test]
7022 fn test_op_drop() {
7023 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
7025 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7026 assert!(result); assert_eq!(stack.len(), 1);
7028 assert_eq!(stack[0].as_ref(), &[1]);
7029 }
7030
7031 #[test]
7032 fn test_op_drop_empty_stack() {
7033 let script = vec![OP_DROP]; let mut stack = Vec::new();
7035 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7036 assert!(!result);
7037 assert_eq!(stack.len(), 0);
7038 }
7039
7040 #[test]
7041 fn test_op_nip() {
7042 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
7044 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7045 assert!(result); assert_eq!(stack.len(), 1);
7047 assert_eq!(stack[0].as_ref(), &[2]);
7048 }
7049
7050 #[test]
7051 fn test_op_nip_insufficient_stack() {
7052 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
7054 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7055 assert!(!result);
7056 assert_eq!(stack.len(), 1);
7057 }
7058
7059 #[test]
7060 fn test_op_over() {
7061 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
7063 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7064 assert!(result); assert_eq!(stack.len(), 3);
7066 assert_eq!(stack[0].as_ref(), &[1]);
7067 assert_eq!(stack[1].as_ref(), &[2]);
7068 assert_eq!(stack[2].as_ref(), &[1]);
7069 }
7070
7071 #[test]
7072 fn test_op_over_insufficient_stack() {
7073 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
7075 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7076 assert!(!result);
7077 assert_eq!(stack.len(), 1);
7078 }
7079
7080 #[test]
7081 fn test_op_pick() {
7082 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
7084 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7085 assert!(result); assert_eq!(stack.len(), 4);
7087 assert_eq!(stack[3].as_ref(), &[2]); }
7089
7090 #[test]
7091 fn test_op_pick_empty_n() {
7092 let script = vec![OP_1, OP_0, OP_PICK];
7094 let mut stack = Vec::new();
7095 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7096 assert!(result); assert_eq!(stack.len(), 2);
7098 assert_eq!(stack[1].as_ref(), &[1]); }
7100
7101 #[test]
7102 fn test_op_pick_invalid_index() {
7103 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
7105 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7106 assert!(!result);
7107 assert_eq!(stack.len(), 1);
7108 }
7109
7110 #[test]
7111 fn test_op_roll() {
7112 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
7114 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7115 assert!(result); assert_eq!(stack.len(), 3);
7117 assert_eq!(stack[0].as_ref(), &[1]);
7118 assert_eq!(stack[1].as_ref(), &[3]);
7119 assert_eq!(stack[2].as_ref(), &[2]); }
7121
7122 #[test]
7123 fn test_op_roll_zero_n() {
7124 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
7127 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7128 assert!(result); assert_eq!(stack.len(), 1);
7130 assert_eq!(stack[0].as_ref(), &[1]);
7131 }
7132
7133 #[test]
7134 fn test_op_roll_invalid_index() {
7135 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
7137 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7138 assert!(!result);
7139 assert_eq!(stack.len(), 1);
7140 }
7141
7142 #[test]
7143 fn test_op_rot() {
7144 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
7146 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7147 assert!(result); assert_eq!(stack.len(), 3);
7149 assert_eq!(stack[0].as_ref(), &[2]);
7150 assert_eq!(stack[1].as_ref(), &[3]);
7151 assert_eq!(stack[2].as_ref(), &[1]);
7152 }
7153
7154 #[test]
7155 fn test_op_rot_insufficient_stack() {
7156 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
7158 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7159 assert!(!result);
7160 assert_eq!(stack.len(), 2);
7161 }
7162
7163 #[test]
7164 fn test_op_swap() {
7165 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
7167 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7168 assert!(result); assert_eq!(stack.len(), 2);
7170 assert_eq!(stack[0].as_ref(), &[2]);
7171 assert_eq!(stack[1].as_ref(), &[1]);
7172 }
7173
7174 #[test]
7175 fn test_op_swap_insufficient_stack() {
7176 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
7178 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7179 assert!(!result);
7180 assert_eq!(stack.len(), 1);
7181 }
7182
7183 #[test]
7184 fn test_op_tuck() {
7185 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
7187 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7188 assert!(result); assert_eq!(stack.len(), 3);
7190 assert_eq!(stack[0].as_ref(), &[2]);
7191 assert_eq!(stack[1].as_ref(), &[1]);
7192 assert_eq!(stack[2].as_ref(), &[2]);
7193 }
7194
7195 #[test]
7196 fn test_op_tuck_insufficient_stack() {
7197 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
7199 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7200 assert!(!result);
7201 assert_eq!(stack.len(), 1);
7202 }
7203
7204 #[test]
7205 fn test_op_2drop() {
7206 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
7208 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7209 assert!(result); assert_eq!(stack.len(), 1);
7211 assert_eq!(stack[0].as_ref(), &[1]);
7212 }
7213
7214 #[test]
7215 fn test_op_2drop_insufficient_stack() {
7216 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
7218 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7219 assert!(!result);
7220 assert_eq!(stack.len(), 1);
7221 }
7222
7223 #[test]
7224 fn test_op_2dup() {
7225 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
7227 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7228 assert!(result); assert_eq!(stack.len(), 4);
7230 assert_eq!(stack[0].as_ref(), &[1]);
7231 assert_eq!(stack[1].as_ref(), &[2]);
7232 assert_eq!(stack[2].as_ref(), &[1]);
7233 assert_eq!(stack[3].as_ref(), &[2]);
7234 }
7235
7236 #[test]
7237 fn test_op_2dup_insufficient_stack() {
7238 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
7240 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7241 assert!(!result);
7242 assert_eq!(stack.len(), 1);
7243 }
7244
7245 #[test]
7246 fn test_op_3dup() {
7247 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
7249 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7250 assert!(result); assert_eq!(stack.len(), 6);
7252 assert_eq!(stack[0].as_ref(), &[1]);
7253 assert_eq!(stack[1].as_ref(), &[2]);
7254 assert_eq!(stack[2].as_ref(), &[3]);
7255 assert_eq!(stack[3].as_ref(), &[1]);
7256 assert_eq!(stack[4].as_ref(), &[2]);
7257 assert_eq!(stack[5].as_ref(), &[3]);
7258 }
7259
7260 #[test]
7261 fn test_op_3dup_insufficient_stack() {
7262 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
7264 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7265 assert!(!result);
7266 assert_eq!(stack.len(), 2);
7267 }
7268
7269 #[test]
7270 fn test_op_2over() {
7271 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
7273 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7274 assert!(result); assert_eq!(stack.len(), 6);
7276 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
7278 }
7279
7280 #[test]
7281 fn test_op_2over_insufficient_stack() {
7282 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
7284 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7285 assert!(!result);
7286 assert_eq!(stack.len(), 3);
7287 }
7288
7289 #[test]
7290 fn test_op_2rot() {
7291 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
7296 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7297 assert!(result); assert_eq!(stack.len(), 6);
7299 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]); }
7302
7303 #[test]
7304 fn test_op_2rot_insufficient_stack() {
7305 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
7307 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7308 assert!(!result);
7309 assert_eq!(stack.len(), 4);
7310 }
7311
7312 #[test]
7313 fn test_op_2swap() {
7314 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
7316 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7317 assert!(result); assert_eq!(stack.len(), 4);
7319 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
7321 assert_eq!(stack[2].as_ref(), &[1]);
7322 assert_eq!(stack[3].as_ref(), &[2]);
7323 }
7324
7325 #[test]
7326 fn test_op_2swap_insufficient_stack() {
7327 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
7329 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7330 assert!(!result);
7331 assert_eq!(stack.len(), 3);
7332 }
7333
7334 #[test]
7335 fn test_op_size() {
7336 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
7338 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7339 assert!(result); assert_eq!(stack.len(), 2);
7341 assert_eq!(stack[0].as_ref(), &[1]);
7342 assert_eq!(stack[1].as_ref(), &[1]); }
7344
7345 #[test]
7346 fn test_op_size_empty_stack() {
7347 let script = vec![OP_SIZE]; let mut stack = Vec::new();
7349 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7350 assert!(!result);
7351 assert_eq!(stack.len(), 0);
7352 }
7353
7354 #[test]
7355 fn test_op_return() {
7356 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
7358 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7359 assert!(!result); assert_eq!(stack.len(), 1);
7361 }
7362
7363 #[test]
7364 fn test_op_checksigverify() {
7365 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7367 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7368 assert!(!result); assert_eq!(stack.len(), 0);
7370 }
7371
7372 #[test]
7373 fn test_op_checksigverify_insufficient_stack() {
7374 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7376 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7377 assert!(!result);
7378 assert_eq!(stack.len(), 1);
7379 }
7380
7381 #[test]
7382 fn test_unknown_opcode_comprehensive() {
7383 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
7385 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7386 assert!(!result); assert_eq!(stack.len(), 1);
7388 }
7389
7390 #[test]
7391 fn test_verify_signature_invalid_pubkey() {
7392 let secp = signature::new_secp();
7393 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
7396 let result = signature::verify_signature(
7397 &secp,
7398 &invalid_pubkey,
7399 &signature,
7400 &dummy_hash,
7401 0,
7402 0,
7403 crate::types::Network::Regtest,
7404 SigVersion::Base,
7405 );
7406 assert!(!result.unwrap_or(false));
7407 }
7408
7409 #[test]
7410 fn test_verify_signature_invalid_signature() {
7411 let secp = signature::new_secp();
7412 let pubkey = vec![
7413 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
7414 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
7415 0x5b, 0x16, 0xf8, 0x17, 0x98,
7416 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
7419 let result = signature::verify_signature(
7420 &secp,
7421 &pubkey,
7422 &invalid_signature,
7423 &dummy_hash,
7424 0,
7425 0,
7426 crate::types::Network::Regtest,
7427 SigVersion::Base,
7428 );
7429 assert!(!result.unwrap_or(false));
7430 }
7431
7432 fn minimal_tx_and_prevouts(
7438 script_sig: &[u8],
7439 script_pubkey: &[u8],
7440 ) -> (
7441 crate::types::Transaction,
7442 Vec<i64>,
7443 Vec<crate::types::ByteString>,
7444 ) {
7445 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
7446 let tx = Transaction {
7447 version: 1,
7448 inputs: vec![TransactionInput {
7449 prevout: OutPoint {
7450 hash: [0u8; 32],
7451 index: 0,
7452 },
7453 sequence: 0xffff_ffff,
7454 script_sig: script_sig.to_vec(),
7455 }]
7456 .into(),
7457 outputs: vec![TransactionOutput {
7458 value: 0,
7459 script_pubkey: script_pubkey.to_vec(),
7460 }]
7461 .into(),
7462 lock_time: 0,
7463 };
7464 let prevout_values = vec![0i64];
7465 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
7466 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
7467 (tx, prevout_values, prevout_script_pubkeys_vec)
7468 }
7469
7470 #[test]
7471 fn test_verify_with_context_p2pkh_hash_mismatch() {
7472 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
7476 script_sig.push(sig.len() as u8);
7477 script_sig.extend(&sig);
7478 script_sig.push(pubkey.len() as u8);
7479 script_sig.extend(&pubkey);
7480
7481 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
7482 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
7484 script_pubkey.push(OP_CHECKSIG);
7485
7486 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7487 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7488 let result = verify_script_with_context_full(
7489 &script_sig,
7490 &script_pubkey,
7491 None,
7492 0,
7493 &tx,
7494 0,
7495 &pv,
7496 &psp_refs,
7497 Some(500_000),
7498 None,
7499 crate::types::Network::Mainnet,
7500 SigVersion::Base,
7501 #[cfg(feature = "production")]
7502 None,
7503 None, #[cfg(feature = "production")]
7505 None,
7506 #[cfg(feature = "production")]
7507 None,
7508 #[cfg(feature = "production")]
7509 None,
7510 );
7511 assert!(result.is_ok());
7512 assert!(!result.unwrap());
7513 }
7514
7515 #[test]
7516 fn test_verify_with_context_p2sh_hash_mismatch() {
7517 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7520 script_sig.push(redeem.len() as u8);
7521 script_sig.extend(&redeem);
7522
7523 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7524 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7526
7527 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7528 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7529 let result = verify_script_with_context_full(
7530 &script_sig,
7531 &script_pubkey,
7532 None,
7533 0x01, &tx,
7535 0,
7536 &pv,
7537 &psp_refs,
7538 Some(500_000),
7539 None,
7540 crate::types::Network::Mainnet,
7541 SigVersion::Base,
7542 #[cfg(feature = "production")]
7543 None,
7544 None, #[cfg(feature = "production")]
7546 None,
7547 #[cfg(feature = "production")]
7548 None,
7549 #[cfg(feature = "production")]
7550 None,
7551 );
7552 assert!(result.is_ok());
7553 assert!(!result.unwrap());
7554 }
7555
7556 #[test]
7557 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7558 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7560 script_pubkey.extend(&[0u8; 20]);
7561 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7563 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7564 let empty: Vec<u8> = vec![];
7565 let result = verify_script_with_context_full(
7566 &empty,
7567 &script_pubkey,
7568 Some(&witness),
7569 0,
7570 &tx,
7571 0,
7572 &pv,
7573 &psp_refs,
7574 Some(500_000),
7575 None,
7576 crate::types::Network::Mainnet,
7577 SigVersion::Base,
7578 #[cfg(feature = "production")]
7579 None,
7580 None, #[cfg(feature = "production")]
7582 None,
7583 #[cfg(feature = "production")]
7584 None,
7585 #[cfg(feature = "production")]
7586 None,
7587 );
7588 assert!(result.is_ok());
7589 assert!(!result.unwrap());
7590 }
7591
7592 #[test]
7593 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7594 let witness_script = vec![OP_1];
7596 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7597 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7599 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7600 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7601 let empty: Vec<u8> = vec![];
7602 let result = verify_script_with_context_full(
7603 &empty,
7604 &script_pubkey,
7605 Some(&witness),
7606 0,
7607 &tx,
7608 0,
7609 &pv,
7610 &psp_refs,
7611 Some(500_000),
7612 None,
7613 crate::types::Network::Mainnet,
7614 SigVersion::Base,
7615 #[cfg(feature = "production")]
7616 None,
7617 None, #[cfg(feature = "production")]
7619 None,
7620 #[cfg(feature = "production")]
7621 None,
7622 #[cfg(feature = "production")]
7623 None,
7624 );
7625 assert!(result.is_ok());
7626 assert!(!result.unwrap());
7627 }
7628
7629 #[test]
7630 #[cfg(feature = "production")]
7631 fn test_p2wsh_multisig_fast_path() {
7632 use crate::constants::BIP147_ACTIVATION_MAINNET;
7634 use crate::crypto::OptimizedSha256;
7635
7636 let pk1 = [0x02u8; 33];
7637 let pk2 = [0x03u8; 33];
7638 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7640 witness_script.extend_from_slice(&pk2);
7641 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7645 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7646 script_pubkey.extend_from_slice(&wsh_hash);
7647
7648 let witness: Vec<Vec<u8>> = vec![
7649 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7653 ];
7654
7655 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7656 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7657 let empty: Vec<u8> = vec![];
7658 let result = verify_script_with_context_full(
7659 &empty,
7660 &script_pubkey,
7661 Some(&witness),
7662 0x810, &tx,
7664 0,
7665 &pv,
7666 &psp_refs,
7667 Some(BIP147_ACTIVATION_MAINNET + 1),
7668 None,
7669 crate::types::Network::Mainnet,
7670 SigVersion::Base,
7671 #[cfg(feature = "production")]
7672 None,
7673 None, #[cfg(feature = "production")]
7675 None,
7676 #[cfg(feature = "production")]
7677 None,
7678 #[cfg(feature = "production")]
7679 None,
7680 );
7681 assert!(result.is_ok());
7682 assert!(!result.unwrap());
7683 }
7684}
7685
7686#[cfg(test)]
7687#[allow(unused_doc_comments)]
7688mod property_tests {
7689 use super::*;
7690 use proptest::prelude::*;
7691
7692 proptest! {
7697 #[test]
7698 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7699 let mut stack = Vec::new();
7700 let flags = 0u32;
7701
7702 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7703
7704 if script.len() > MAX_SCRIPT_OPS * 2 {
7712 prop_assert!(result.is_err() || !result.unwrap(),
7715 "Very long scripts should fail or return false");
7716 }
7717 }
7719 }
7720
7721 proptest! {
7726 #[test]
7727 fn prop_verify_script_deterministic(
7728 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7729 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7730 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7731 flags in any::<u32>()
7732 ) {
7733 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7734 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7735
7736 assert_eq!(result1.is_ok(), result2.is_ok());
7737 if result1.is_ok() && result2.is_ok() {
7738 assert_eq!(result1.unwrap(), result2.unwrap());
7739 }
7740 }
7741 }
7742
7743 proptest! {
7748 #[test]
7749 fn prop_execute_opcode_no_panic(
7750 opcode in any::<u8>(),
7751 stack_items in prop::collection::vec(
7752 prop::collection::vec(any::<u8>(), 0..5),
7753 0..10
7754 ),
7755 flags in any::<u32>()
7756 ) {
7757 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7758 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7759
7760 match result {
7763 Ok(success) => {
7764 let _ = success;
7766 },
7767 Err(_) => {
7768 }
7771 }
7772
7773 assert!(stack.len() <= MAX_STACK_SIZE);
7775 }
7776 }
7777
7778 proptest! {
7785 #[test]
7786 fn prop_stack_operations_bounds(
7787 opcode in any::<u8>(),
7788 stack_items in prop::collection::vec(
7789 prop::collection::vec(any::<u8>(), 0..3),
7790 0..5
7791 ),
7792 flags in any::<u32>()
7793 ) {
7794 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7795 let initial_len = stack.len();
7796
7797 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7798
7799 assert!(stack.len() <= MAX_STACK_SIZE);
7801
7802 if result.is_ok() && result.unwrap() {
7804 match opcode {
7806 OP_0 | OP_1..=OP_16 => {
7807 assert!(stack.len() == initial_len + 1);
7809 },
7810 OP_DUP => {
7811 if initial_len > 0 {
7813 assert!(stack.len() == initial_len + 1);
7814 }
7815 },
7816 OP_3DUP => {
7817 if initial_len >= 3 {
7819 assert!(stack.len() == initial_len + 3);
7820 }
7821 },
7822 OP_2OVER => {
7823 if initial_len >= 4 {
7825 assert!(stack.len() == initial_len + 2);
7826 }
7827 },
7828 OP_DROP | OP_NIP | OP_2DROP => {
7829 assert!(stack.len() <= initial_len);
7831 },
7832 _ => {
7833 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7836 }
7837 }
7838 }
7839 }
7840 }
7841
7842 proptest! {
7847 #[test]
7848 fn prop_hash_operations_deterministic(
7849 input in prop::collection::vec(any::<u8>(), 0..10)
7850 ) {
7851 let elem = to_stack_element(&input);
7852 let mut stack1 = vec![elem.clone()];
7853 let mut stack2 = vec![elem];
7854
7855 let result1 = execute_opcode(0xa9, &mut stack1, 0, SigVersion::Base); let result2 = execute_opcode(0xa9, &mut stack2, 0, SigVersion::Base); assert_eq!(result1.is_ok(), result2.is_ok());
7859 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7860 assert_eq!(val1, val2);
7861 if val1 {
7862 assert_eq!(stack1, stack2);
7863 }
7864 }
7865 }
7866 }
7867
7868 proptest! {
7873 #[test]
7874 fn prop_equality_operations_symmetric(
7875 a in prop::collection::vec(any::<u8>(), 0..5),
7876 b in prop::collection::vec(any::<u8>(), 0..5)
7877 ) {
7878 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7879 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7880
7881 let result1 = execute_opcode(0x87, &mut stack1, 0, SigVersion::Base); let result2 = execute_opcode(0x87, &mut stack2, 0, SigVersion::Base); assert_eq!(result1.is_ok(), result2.is_ok());
7885 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7886 assert_eq!(val1, val2);
7887 if val1 {
7888 assert_eq!(stack1.len(), stack2.len());
7890 if !stack1.is_empty() && !stack2.is_empty() {
7891 assert_eq!(stack1[0], stack2[0]);
7892 }
7893 }
7894 }
7895 }
7896 }
7897
7898 proptest! {
7903 #[test]
7904 fn prop_script_execution_terminates(
7905 script in prop::collection::vec(any::<u8>(), 0..50)
7906 ) {
7907 let mut stack = Vec::new();
7908 let flags = 0u32;
7909
7910 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7912
7913 assert!(result.is_ok() || result.is_err());
7915
7916 assert!(stack.len() <= MAX_STACK_SIZE);
7918 }
7919 }
7920}