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;
20mod signature;
21mod stack;
22
23pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
24pub use stack::{cast_to_bool, to_stack_element, StackElement};
25
26use crate::constants::*;
27use crate::crypto::OptimizedSha256;
28use crate::error::{ConsensusError, Result, ScriptErrorCode};
29use crate::opcodes::*;
30use crate::types::*;
31use blvm_spec_lock::spec_locked;
32use digest::Digest;
33use ripemd::Ripemd160;
34
35#[cfg(feature = "production")]
37use crate::optimizations::{precomputed_constants, prefetch};
38
39#[cold]
41#[allow(dead_code)]
42fn make_operation_limit_error() -> ConsensusError {
43 ConsensusError::ScriptErrorWithCode {
44 code: ScriptErrorCode::OpCount,
45 message: "Operation limit exceeded".into(),
46 }
47}
48
49#[cold]
50fn make_stack_overflow_error() -> ConsensusError {
51 ConsensusError::ScriptErrorWithCode {
52 code: ScriptErrorCode::StackSize,
53 message: "Stack overflow".into(),
54 }
55}
56
57#[cfg(feature = "production")]
58use std::collections::VecDeque;
59#[cfg(feature = "production")]
60use std::sync::{
61 atomic::{AtomicBool, AtomicU64, Ordering},
62 OnceLock, RwLock,
63};
64#[cfg(feature = "production")]
65use std::thread_local;
66
67#[cfg(feature = "production")]
73static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
74
75#[cfg(feature = "production")]
78const SIG_CACHE_SHARDS: usize = 32;
79
80#[cfg(feature = "production")]
81const SIG_CACHE_SHARD: OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>> = OnceLock::new();
82
83#[cfg(feature = "production")]
84static SIG_CACHE: [OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>>; SIG_CACHE_SHARDS] =
85 [SIG_CACHE_SHARD; SIG_CACHE_SHARDS];
86
87#[cfg(feature = "production")]
89fn sig_cache_size() -> usize {
90 std::env::var("BLVM_SIG_CACHE_ENTRIES")
91 .ok()
92 .and_then(|s| s.parse().ok())
93 .filter(|&n: &usize| n > 0 && n <= 1_000_000)
94 .unwrap_or(500_000)
95}
96
97#[cfg(feature = "production")]
98fn sig_cache_shard_index(key: &[u8; 32]) -> usize {
99 let h = (key[0] as usize) | ((key[1] as usize) << 8) | ((key[2] as usize) << 16);
100 h % SIG_CACHE_SHARDS
101}
102
103#[cfg(feature = "production")]
104fn get_sig_cache_shard(key: &[u8; 32]) -> &'static RwLock<lru::LruCache<[u8; 32], bool>> {
105 let idx = sig_cache_shard_index(key);
106 SIG_CACHE[idx].get_or_init(|| {
107 use lru::LruCache;
108 use std::num::NonZeroUsize;
109 let cap = (sig_cache_size() / SIG_CACHE_SHARDS).max(1);
110 RwLock::new(LruCache::new(NonZeroUsize::new(cap).unwrap()))
111 })
112}
113
114#[cfg(feature = "production")]
115thread_local! {
116 static BATCH_PUT_SIG_CACHE_BY_SHARD: std::cell::RefCell<[Vec<([u8; 32], bool)>; SIG_CACHE_SHARDS]> =
117 std::cell::RefCell::new(std::array::from_fn(|_| Vec::new()));
118}
119
120#[cfg(feature = "production")]
122thread_local! {
123 static SOA_BATCH_BUF: std::cell::RefCell<(
124 Vec<[u8; 64]>,
125 Vec<[u8; 32]>,
126 Vec<[u8; 33]>,
127 Vec<usize>,
128 Vec<[u8; 32]>,
129 )> = const { std::cell::RefCell::new((
130 Vec::new(),
131 Vec::new(),
132 Vec::new(),
133 Vec::new(),
134 Vec::new(),
135 )) };
136}
137
138#[cfg(feature = "production")]
139fn batch_put_sig_cache(keys: &[[u8; 32]], results: &[bool]) {
140 BATCH_PUT_SIG_CACHE_BY_SHARD.with(|cell| {
141 let mut by_shard = cell.borrow_mut();
142 for v in by_shard.iter_mut() {
143 v.clear();
144 }
145 for (i, key) in keys.iter().enumerate() {
146 let result = results.get(i).copied().unwrap_or(false);
147 let idx = sig_cache_shard_index(key);
148 by_shard[idx].push((*key, result));
149 }
150 for shard_entries in by_shard.iter() {
151 if shard_entries.is_empty() {
152 continue;
153 }
154 let first_key = &shard_entries[0].0;
155 if let Ok(mut guard) = get_sig_cache_shard(first_key).write() {
156 for (k, v) in shard_entries.iter() {
157 guard.put(*k, *v);
158 }
159 }
160 }
161 });
162}
163
164#[cfg(feature = "production")]
170fn sig_cache_at_collect_enabled() -> bool {
171 use std::sync::OnceLock;
172 static CACHE: OnceLock<bool> = OnceLock::new();
173 *CACHE.get_or_init(|| {
174 std::env::var("BLVM_SIG_CACHE_AT_COLLECT")
175 .map(|s| s == "1" || s.eq_ignore_ascii_case("true"))
176 .unwrap_or(false)
177 })
178}
179
180#[cfg(feature = "production")]
183#[inline(always)]
184fn ecdsa_cache_key(msg: &[u8; 32], pk: &[u8; 33], sig_compact: &[u8; 64], flags: u32) -> [u8; 32] {
185 use siphasher::sip::SipHasher24;
186 use std::hash::{Hash, Hasher};
187 let mut key_input = [0u8; 133];
188 key_input[..32].copy_from_slice(msg);
189 key_input[32..65].copy_from_slice(pk);
190 key_input[65..129].copy_from_slice(sig_compact);
191 key_input[129..133].copy_from_slice(&flags.to_le_bytes());
192 let mut hasher = SipHasher24::new();
193 key_input.hash(&mut hasher);
194 let h = hasher.finish();
195 let mut out = [0u8; 32];
196 out[..8].copy_from_slice(&h.to_le_bytes());
197 out
198}
199
200#[cfg(feature = "production")]
203static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
204#[cfg(feature = "production")]
205static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
206#[cfg(feature = "production")]
207static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
208#[cfg(feature = "production")]
209static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
210#[cfg(feature = "production")]
211static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
212static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
213#[cfg(feature = "production")]
214static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
215#[cfg(feature = "production")]
216static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
217
218#[cfg(feature = "production")]
219fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
220 SCRIPT_CACHE.get_or_init(|| {
221 use lru::LruCache;
225 use std::num::NonZeroUsize;
226 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
227 })
228}
229
230#[cfg(feature = "production")]
235thread_local! {
236 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
237 std::cell::RefCell::new(VecDeque::with_capacity(10));
238}
239
240#[cfg(feature = "production")]
242fn get_pooled_stack() -> Vec<StackElement> {
243 STACK_POOL.with(|pool| {
244 let mut pool = pool.borrow_mut();
245 if let Some(mut stack) = pool.pop_front() {
246 stack.clear();
247 if stack.capacity() < 20 {
248 stack.reserve(20);
249 }
250 stack
251 } else {
252 Vec::with_capacity(20)
253 }
254 })
255}
256
257#[cfg(feature = "production")]
259struct PooledStackGuard(Vec<StackElement>);
260#[cfg(feature = "production")]
261impl Drop for PooledStackGuard {
262 fn drop(&mut self) {
263 return_pooled_stack(std::mem::take(&mut self.0));
264 }
265}
266
267#[cfg(feature = "production")]
269fn return_pooled_stack(mut stack: Vec<StackElement>) {
270 stack.clear();
272
273 STACK_POOL.with(|pool| {
274 let mut pool = pool.borrow_mut();
275 if pool.len() < 10 {
277 pool.push_back(stack);
278 }
279 });
281}
282
283#[cfg(feature = "production")]
288static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
289
290#[cfg(feature = "production")]
306pub fn disable_caching(disabled: bool) {
307 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
308}
309
310#[cfg(feature = "production")]
312fn is_caching_disabled() -> bool {
313 CACHE_DISABLED.load(Ordering::Relaxed)
314}
315
316#[cfg(feature = "production")]
321fn compute_script_cache_key(
322 script_sig: &ByteString,
323 script_pubkey: &[u8],
324 witness: Option<&ByteString>,
325 flags: u32,
326) -> u64 {
327 use std::collections::hash_map::DefaultHasher;
328 use std::hash::{Hash, Hasher};
329
330 let mut hasher = DefaultHasher::new();
331 script_sig.hash(&mut hasher);
332 script_pubkey.hash(&mut hasher);
333 if let Some(w) = witness {
334 w.hash(&mut hasher);
335 }
336 flags.hash(&mut hasher);
337 hasher.finish()
338}
339
340#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub enum SigVersion {
343 Base,
345 WitnessV0,
347 Tapscript,
349}
350
351#[spec_locked("5.2", "EvalScript")]
367#[cfg_attr(feature = "production", inline(always))]
368#[cfg_attr(not(feature = "production"), inline)]
369pub fn eval_script(
370 script: &[u8],
371 stack: &mut Vec<StackElement>,
372 flags: u32,
373 sigversion: SigVersion,
374) -> Result<bool> {
375 if stack.capacity() < 20 {
378 stack.reserve(20);
379 }
380 #[cfg(feature = "production")]
381 {
382 eval_script_impl(script, stack, flags, sigversion)
383 }
384 #[cfg(not(feature = "production"))]
385 {
386 eval_script_inner(script, stack, flags, sigversion)
387 }
388}
389#[cfg(feature = "production")]
390fn eval_script_impl(
391 script: &[u8],
392 stack: &mut Vec<StackElement>,
393 flags: u32,
394 sigversion: SigVersion,
395) -> Result<bool> {
396 eval_script_inner(script, stack, flags, sigversion)
397}
398
399#[cfg(not(feature = "production"))]
400#[allow(dead_code)]
401fn eval_script_impl(
402 script: &[u8],
403 stack: &mut Vec<StackElement>,
404 flags: u32,
405 sigversion: SigVersion,
406) -> Result<bool> {
407 eval_script_inner(script, stack, flags, sigversion)
408}
409
410#[inline(always)]
412fn is_push_opcode(opcode: u8) -> bool {
413 opcode <= 0x60
414}
415
416#[inline]
419fn is_op_success(opcode: u8) -> bool {
420 matches!(
421 opcode,
422 80 | 98
423 | 126..=129
424 | 131..=134
425 | 137..=138
426 | 141..=142
427 | 149..=153
428 | 187..=254
429 )
430}
431
432#[inline]
435fn op_advance(script: &[u8], pc: usize) -> usize {
436 let opcode = script[pc];
437 match opcode {
438 0x01..=0x4b => 1 + opcode as usize,
440 0x4c => {
442 if pc + 1 < script.len() {
443 2 + script[pc + 1] as usize
444 } else {
445 1
446 }
447 }
448 0x4d => {
450 if pc + 2 < script.len() {
451 3 + u16::from_le_bytes([script[pc + 1], script[pc + 2]]) as usize
452 } else {
453 1
454 }
455 }
456 0x4e => {
458 if pc + 4 < script.len() {
459 5 + u32::from_le_bytes([
460 script[pc + 1],
461 script[pc + 2],
462 script[pc + 3],
463 script[pc + 4],
464 ]) as usize
465 } else {
466 1
467 }
468 }
469 _ => 1,
470 }
471}
472
473fn eval_script_inner(
474 script: &[u8],
475 stack: &mut Vec<StackElement>,
476 flags: u32,
477 sigversion: SigVersion,
478) -> Result<bool> {
479 use crate::constants::MAX_SCRIPT_SIZE;
480 use crate::error::{ConsensusError, ScriptErrorCode};
481
482 if script.len() > MAX_SCRIPT_SIZE {
483 return Err(ConsensusError::ScriptErrorWithCode {
484 code: ScriptErrorCode::ScriptSize,
485 message: "Script size exceeds maximum".into(),
486 });
487 }
488
489 let mut op_count = 0;
490 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
491 let mut altstack: Vec<StackElement> = Vec::new();
492
493 for opcode in script {
494 let opcode = *opcode;
495
496 let in_false_branch = control_flow::in_false_branch(&control_stack);
497
498 if !is_push_opcode(opcode) {
500 op_count += 1;
501 if op_count > MAX_SCRIPT_OPS {
502 return Err(make_operation_limit_error());
503 }
504 debug_assert!(
505 op_count <= MAX_SCRIPT_OPS,
506 "Operation count ({op_count}) must not exceed MAX_SCRIPT_OPS ({MAX_SCRIPT_OPS})"
507 );
508 }
509
510 if stack.len() + altstack.len() > MAX_STACK_SIZE {
513 return Err(make_stack_overflow_error());
514 }
515
516 match opcode {
517 OP_IF => {
519 if in_false_branch {
520 control_stack.push(control_flow::ControlBlock::If { executing: false });
521 continue;
522 }
523
524 if stack.is_empty() {
525 return Err(ConsensusError::ScriptErrorWithCode {
526 code: ScriptErrorCode::InvalidStackOperation,
527 message: "OP_IF: empty stack".into(),
528 });
529 }
530 let condition_bytes = stack.pop().unwrap();
531 let condition = cast_to_bool(&condition_bytes);
532
533 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
535 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
536 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
537 && !control_flow::is_minimal_if_condition(&condition_bytes)
538 {
539 return Err(ConsensusError::ScriptErrorWithCode {
540 code: ScriptErrorCode::MinimalIf,
541 message: "OP_IF condition must be minimally encoded".into(),
542 });
543 }
544
545 control_stack.push(control_flow::ControlBlock::If {
546 executing: condition,
547 });
548 }
549 OP_NOTIF => {
551 if in_false_branch {
552 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
553 continue;
554 }
555
556 if stack.is_empty() {
557 return Err(ConsensusError::ScriptErrorWithCode {
558 code: ScriptErrorCode::InvalidStackOperation,
559 message: "OP_NOTIF: empty stack".into(),
560 });
561 }
562 let condition_bytes = stack.pop().unwrap();
563 let condition = cast_to_bool(&condition_bytes);
564
565 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
566 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
567 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
568 && !control_flow::is_minimal_if_condition(&condition_bytes)
569 {
570 return Err(ConsensusError::ScriptErrorWithCode {
571 code: ScriptErrorCode::MinimalIf,
572 message: "OP_NOTIF condition must be minimally encoded".into(),
573 });
574 }
575
576 control_stack.push(control_flow::ControlBlock::NotIf {
577 executing: !condition,
578 });
579 }
580 OP_ELSE => {
582 if let Some(block) = control_stack.last_mut() {
583 match block {
584 control_flow::ControlBlock::If { executing }
585 | control_flow::ControlBlock::NotIf { executing } => {
586 *executing = !*executing;
587 }
588 }
589 } else {
590 return Err(ConsensusError::ScriptErrorWithCode {
591 code: ScriptErrorCode::UnbalancedConditional,
592 message: "OP_ELSE without matching IF/NOTIF".into(),
593 });
594 }
595 }
596 OP_ENDIF => {
598 if control_stack.pop().is_none() {
599 return Err(ConsensusError::ScriptErrorWithCode {
600 code: ScriptErrorCode::UnbalancedConditional,
601 message: "OP_ENDIF without matching IF/NOTIF".into(),
602 });
603 }
604 }
605 OP_TOALTSTACK => {
607 if in_false_branch {
608 continue;
609 }
610 if stack.is_empty() {
611 return Err(ConsensusError::ScriptErrorWithCode {
612 code: ScriptErrorCode::InvalidStackOperation,
613 message: "OP_TOALTSTACK: empty stack".into(),
614 });
615 }
616 altstack.push(stack.pop().unwrap());
617 }
618 OP_FROMALTSTACK => {
620 if in_false_branch {
621 continue;
622 }
623 if altstack.is_empty() {
624 return Err(ConsensusError::ScriptErrorWithCode {
625 code: ScriptErrorCode::InvalidAltstackOperation,
626 message: "OP_FROMALTSTACK: empty altstack".into(),
627 });
628 }
629 stack.push(altstack.pop().unwrap());
630 }
631 _ => {
632 if in_false_branch {
633 continue;
634 }
635
636 if !execute_opcode(opcode, stack, flags, sigversion)? {
637 return Ok(false);
638 }
639
640 if stack.len() + altstack.len() > MAX_STACK_SIZE {
641 return Err(make_stack_overflow_error());
642 }
643 }
644 }
645 }
646
647 if !control_stack.is_empty() {
648 return Err(ConsensusError::ScriptErrorWithCode {
649 code: ScriptErrorCode::UnbalancedConditional,
650 message: "Unclosed IF/NOTIF block".into(),
651 });
652 }
653
654 #[cfg(feature = "production")]
657 {
658 if stack.len() == 1 {
659 Ok(cast_to_bool(&stack[0]))
660 } else {
661 Ok(false)
662 }
663 }
664
665 #[cfg(not(feature = "production"))]
666 {
667 Ok(stack.len() == 1 && cast_to_bool(&stack[0]))
668 }
669}
670
671#[spec_locked("5.2", "VerifyScript")]
681#[cfg_attr(feature = "production", inline(always))]
682#[cfg_attr(not(feature = "production"), inline)]
683pub fn verify_script(
684 script_sig: &ByteString,
685 script_pubkey: &[u8],
686 witness: Option<&ByteString>,
687 flags: u32,
688) -> Result<bool> {
689 let sigversion = SigVersion::Base;
691
692 #[cfg(feature = "production")]
693 {
694 if !is_caching_disabled() {
696 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
697 {
698 let cache = get_script_cache().read().unwrap_or_else(|e| e.into_inner());
699 if let Some(&cached_result) = cache.peek(&cache_key) {
700 return Ok(cached_result);
701 }
702 }
703 }
704
705 let mut stack = get_pooled_stack();
708 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
709 let result = {
710 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
711 if !is_caching_disabled() {
713 let mut cache = get_script_cache()
714 .write()
715 .unwrap_or_else(|e| e.into_inner());
716 cache.put(cache_key, false);
717 }
718 false
719 } else if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
720 if !is_caching_disabled() {
721 let mut cache = get_script_cache()
722 .write()
723 .unwrap_or_else(|e| e.into_inner());
724 cache.put(cache_key, false);
725 }
726 false
727 } else if let Some(w) = witness {
728 if !eval_script(w, &mut stack, flags, sigversion)? {
729 if !is_caching_disabled() {
730 let mut cache = get_script_cache()
731 .write()
732 .unwrap_or_else(|e| e.into_inner());
733 cache.put(cache_key, false);
734 }
735 false
736 } else {
737 let res = stack.len() == 1 && cast_to_bool(&stack[0]);
738 if !is_caching_disabled() {
739 let mut cache = get_script_cache()
740 .write()
741 .unwrap_or_else(|e| e.into_inner());
742 cache.put(cache_key, res);
743 }
744 res
745 }
746 } else {
747 let res = stack.len() == 1 && cast_to_bool(&stack[0]);
748 if !is_caching_disabled() {
749 let mut cache = get_script_cache()
750 .write()
751 .unwrap_or_else(|e| e.into_inner());
752 cache.put(cache_key, res);
753 }
754 res
755 }
756 };
757
758 return_pooled_stack(stack);
760
761 Ok(result)
762 }
763
764 #[cfg(not(feature = "production"))]
765 {
766 let mut stack = Vec::with_capacity(20);
768
769 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
771 return Ok(false);
772 }
773
774 if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
776 return Ok(false);
777 }
778
779 if let Some(w) = witness {
781 if !eval_script(w, &mut stack, flags, sigversion)? {
782 return Ok(false);
783 }
784 }
785
786 Ok(stack.len() == 1 && cast_to_bool(&stack[0]))
788 }
789}
790
791#[spec_locked("5.2", "VerifyScript")]
796#[cfg_attr(feature = "production", inline(always))]
797#[cfg_attr(not(feature = "production"), inline)]
798#[allow(clippy::too_many_arguments)]
799pub fn verify_script_with_context(
800 script_sig: &ByteString,
801 script_pubkey: &[u8],
802 witness: Option<&crate::witness::Witness>,
803 flags: u32,
804 tx: &Transaction,
805 input_index: usize,
806 prevouts: &[TransactionOutput],
807 network: crate::types::Network,
808) -> Result<bool> {
809 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
811 let prevout_script_pubkeys: Vec<&[u8]> =
812 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
813
814 let sigversion = SigVersion::Base;
816 verify_script_with_context_full(
817 script_sig,
818 script_pubkey,
819 witness,
820 flags,
821 tx,
822 input_index,
823 &prevout_values,
824 &prevout_script_pubkeys,
825 None, None, network,
828 sigversion,
829 #[cfg(feature = "production")]
830 None, None, #[cfg(feature = "production")]
833 None, #[cfg(feature = "production")]
835 None, #[cfg(feature = "production")]
837 None, )
839}
840
841#[cfg(feature = "production")]
848#[allow(clippy::too_many_arguments)]
849pub fn try_verify_p2pk_fast_path(
850 script_sig: &ByteString,
851 script_pubkey: &[u8],
852 flags: u32,
853 tx: &Transaction,
854 input_index: usize,
855 prevout_values: &[i64],
856 prevout_script_pubkeys: &[&[u8]],
857 block_height: Option<u64>,
858 network: crate::types::Network,
859 #[cfg(feature = "production")] sighash_cache: Option<
860 &crate::transaction_hash::SighashMidstateCache,
861 >,
862) -> Option<Result<bool>> {
863 let len = script_pubkey.len();
866 if len != 35 && len != 67 {
867 return None;
868 }
869 if script_pubkey[len - 1] != OP_CHECKSIG {
870 return None;
871 }
872 let pubkey_len = len - 2; if pubkey_len != 33 && pubkey_len != 65 {
874 return None;
875 }
876 if script_pubkey[0] != 0x21 && script_pubkey[0] != 0x41 {
877 return None; }
879 let pubkey_bytes = &script_pubkey[1..(len - 1)];
880
881 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
882 if signature_bytes.is_empty() {
883 return Some(Ok(false));
884 }
885
886 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
888 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
889 let sighash_type = SighashType::from_byte(sighash_byte);
890 let deleted_storage;
891 let script_code: &[u8] = if script_pubkey.len() < 71 {
892 script_pubkey
893 } else {
894 let pattern = serialize_push_data(signature_bytes);
895 deleted_storage = find_and_delete(script_pubkey, &pattern);
896 deleted_storage.as_ref()
897 };
898 let sighash = match calculate_transaction_sighash_single_input(
899 tx,
900 input_index,
901 script_code,
902 prevout_values[input_index],
903 sighash_type,
904 #[cfg(feature = "production")]
905 sighash_cache,
906 ) {
907 Ok(h) => h,
908 Err(e) => return Some(Err(e)),
909 };
910
911 let height = block_height.unwrap_or(0);
912 let is_valid = signature::with_secp_context(|secp| {
913 signature::verify_signature(
914 secp,
915 pubkey_bytes,
916 signature_bytes,
917 &sighash,
918 flags,
919 height,
920 network,
921 SigVersion::Base,
922 )
923 });
924 Some(is_valid)
925}
926
927#[cfg(feature = "production")]
930#[allow(clippy::too_many_arguments)]
931pub fn try_verify_p2pkh_fast_path(
932 script_sig: &ByteString,
933 script_pubkey: &[u8],
934 flags: u32,
935 tx: &Transaction,
936 input_index: usize,
937 prevout_values: &[i64],
938 prevout_script_pubkeys: &[&[u8]],
939 block_height: Option<u64>,
940 network: crate::types::Network,
941 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
942 #[cfg(feature = "production")] sighash_cache: Option<
943 &crate::transaction_hash::SighashMidstateCache,
944 >,
945 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
946) -> Option<Result<bool>> {
947 #[cfg(all(feature = "production", feature = "profile"))]
948 let _t_entry = std::time::Instant::now();
949 if script_pubkey.len() != 25 {
951 return None;
952 }
953 if script_pubkey[0] != OP_DUP
954 || script_pubkey[1] != OP_HASH160
955 || script_pubkey[2] != PUSH_20_BYTES
956 || script_pubkey[23] != OP_EQUALVERIFY
957 || script_pubkey[24] != OP_CHECKSIG
958 {
959 return None;
960 }
961 let expected_hash = &script_pubkey[3..23];
962
963 #[cfg(all(feature = "production", feature = "profile"))]
964 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
965 #[cfg(all(feature = "production", feature = "profile"))]
966 let _t_parse = std::time::Instant::now();
967 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
968 #[cfg(all(feature = "production", feature = "profile"))]
969 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
970
971 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
973 return Some(Ok(false));
974 }
975 if signature_bytes.is_empty() {
977 return Some(Ok(false));
978 }
979
980 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
982 Some(h) => h,
983 None => {
984 #[cfg(all(feature = "production", feature = "profile"))]
985 let _t_hash = std::time::Instant::now();
986 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
987 let h = Ripemd160::digest(sha256_hash);
988 #[cfg(all(feature = "production", feature = "profile"))]
989 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
990 h.into()
991 }
992 };
993 if &pubkey_hash[..] != expected_hash {
994 return Some(Ok(false));
995 }
996
997 use crate::transaction_hash::SighashType;
1000 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1001 let sighash_type = SighashType::from_byte(sighash_byte);
1002 let deleted_storage;
1003 let script_code: &[u8] = if script_pubkey.len() < 71 {
1004 script_pubkey
1005 } else {
1006 let pattern = serialize_push_data(signature_bytes);
1007 deleted_storage = find_and_delete(script_pubkey, &pattern);
1008 deleted_storage.as_ref()
1009 };
1010 let sighash = {
1011 #[cfg(feature = "production")]
1012 {
1013 if let Some(precomp) = precomputed_sighash_all {
1014 precomp
1015 } else {
1016 crate::transaction_hash::compute_legacy_sighash_nocache(
1017 tx,
1018 input_index,
1019 script_code,
1020 sighash_byte,
1021 )
1022 }
1023 }
1024 #[cfg(not(feature = "production"))]
1025 {
1026 match calculate_transaction_sighash_single_input(
1027 tx,
1028 input_index,
1029 script_code,
1030 prevout_values[input_index],
1031 sighash_type,
1032 ) {
1033 Ok(h) => h,
1034 Err(e) => return Some(Err(e)),
1035 }
1036 }
1037 };
1038
1039 #[cfg(all(feature = "production", feature = "profile"))]
1040 let _t_secp = std::time::Instant::now();
1041 let height = block_height.unwrap_or(0);
1042 let is_valid: Result<bool> = {
1043 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1044 if flags & 0x04 != 0
1045 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1046 .unwrap_or(false)
1047 {
1048 Ok(false)
1049 } else if flags & 0x02 != 0 {
1050 let base_sighash = sighash_byte & !0x80;
1051 if !(0x01..=0x03).contains(&base_sighash) {
1052 Ok(false)
1053 } else if pubkey_bytes.len() == 33 {
1054 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
1055 Ok(false)
1056 } else {
1057 let strict_der = flags & 0x04 != 0;
1058 let enforce_low_s = flags & 0x08 != 0;
1059 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1060 der_sig,
1061 pubkey_bytes,
1062 &sighash,
1063 strict_der,
1064 enforce_low_s,
1065 )
1066 .unwrap_or(false))
1067 }
1068 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1069 let strict_der = flags & 0x04 != 0;
1070 let enforce_low_s = flags & 0x08 != 0;
1071 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1072 der_sig,
1073 pubkey_bytes,
1074 &sighash,
1075 strict_der,
1076 enforce_low_s,
1077 )
1078 .unwrap_or(false))
1079 } else {
1080 Ok(false)
1081 }
1082 } else {
1083 let strict_der = flags & 0x04 != 0;
1084 let enforce_low_s = flags & 0x08 != 0;
1085 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1086 der_sig,
1087 pubkey_bytes,
1088 &sighash,
1089 strict_der,
1090 enforce_low_s,
1091 )
1092 .unwrap_or(false))
1093 }
1094 };
1095 #[cfg(all(feature = "production", feature = "profile"))]
1096 {
1097 let ns = _t_secp.elapsed().as_nanos() as u64;
1098 crate::script_profile::add_p2pkh_collect_ns(ns);
1099 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1100 }
1101 Some(is_valid)
1102}
1103
1104#[cfg(feature = "production")]
1110#[inline]
1111pub fn verify_p2pkh_inline(
1112 script_sig: &[u8],
1113 script_pubkey: &[u8],
1114 flags: u32,
1115 tx: &Transaction,
1116 input_index: usize,
1117 height: u64,
1118 network: crate::types::Network,
1119 precomputed_sighash_all: Option<[u8; 32]>,
1120) -> Result<bool> {
1121 #[cfg(feature = "profile")]
1122 let _t0 = std::time::Instant::now();
1123
1124 let expected_hash = &script_pubkey[3..23];
1125
1126 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1127 Some(pair) => pair,
1128 None => return Ok(false),
1129 };
1130
1131 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1132 return Ok(false);
1133 }
1134
1135 #[cfg(feature = "profile")]
1136 let _t_hash = std::time::Instant::now();
1137
1138 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1139 let pubkey_hash: [u8; 20] = Ripemd160::digest(sha256_hash).into();
1140 if &pubkey_hash[..] != expected_hash {
1141 return Ok(false);
1142 }
1143
1144 #[cfg(feature = "profile")]
1145 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1146
1147 #[cfg(feature = "profile")]
1148 let _t_sighash = std::time::Instant::now();
1149
1150 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1151 let sighash = if let Some(precomp) = precomputed_sighash_all {
1152 precomp
1153 } else {
1154 crate::transaction_hash::compute_legacy_sighash_buffered(
1155 tx,
1156 input_index,
1157 script_pubkey,
1158 sighash_byte,
1159 )
1160 };
1161
1162 #[cfg(feature = "profile")]
1163 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1164
1165 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1166 let strict_der = flags & 0x04 != 0;
1167 let enforce_low_s = flags & 0x08 != 0;
1168
1169 if strict_der
1170 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1171 .unwrap_or(false)
1172 {
1173 return Ok(false);
1174 }
1175
1176 if flags & 0x02 != 0 {
1177 let sighash_base = sighash_byte & !0x80;
1178 if !(0x01..=0x03).contains(&sighash_base) {
1179 return Ok(false);
1180 }
1181 match pubkey_bytes.len() {
1182 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1183 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1184 33 | 65 => {}
1185 _ => return Ok(false),
1186 }
1187 }
1188
1189 #[cfg(feature = "profile")]
1190 let _t_secp = std::time::Instant::now();
1191
1192 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1193 der_sig,
1194 pubkey_bytes,
1195 &sighash,
1196 strict_der,
1197 enforce_low_s,
1198 )
1199 .unwrap_or(false);
1200
1201 #[cfg(feature = "profile")]
1202 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1203
1204 #[cfg(feature = "profile")]
1205 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1206
1207 Ok(result)
1208}
1209
1210#[cfg(feature = "production")]
1212#[inline]
1213pub fn verify_p2pk_inline(
1214 script_sig: &[u8],
1215 script_pubkey: &[u8],
1216 flags: u32,
1217 tx: &Transaction,
1218 input_index: usize,
1219 height: u64,
1220 network: crate::types::Network,
1221) -> Result<bool> {
1222 let pk_len = script_pubkey.len() - 2; let pubkey_bytes = &script_pubkey[1..1 + pk_len];
1224
1225 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1226 Some(s) => s,
1227 None => return Ok(false),
1228 };
1229 if signature_bytes.is_empty() {
1230 return Ok(false);
1231 }
1232
1233 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1234 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_buffered(
1237 tx,
1238 input_index,
1239 script_code,
1240 sighash_byte,
1241 );
1242
1243 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1244 let strict_der = flags & 0x04 != 0;
1245 let enforce_low_s = flags & 0x08 != 0;
1246
1247 if strict_der
1248 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1249 .unwrap_or(false)
1250 {
1251 return Ok(false);
1252 }
1253
1254 if flags & 0x02 != 0 {
1255 let sighash_base = sighash_byte & !0x80;
1256 if !(0x01..=0x03).contains(&sighash_base) {
1257 return Ok(false);
1258 }
1259 match pubkey_bytes.len() {
1260 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1261 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1262 33 | 65 => {}
1263 _ => return Ok(false),
1264 }
1265 }
1266
1267 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1268 der_sig,
1269 pubkey_bytes,
1270 &sighash,
1271 strict_der,
1272 enforce_low_s,
1273 )
1274 .unwrap_or(false))
1275}
1276
1277#[allow(clippy::too_many_arguments)]
1281fn try_verify_p2sh_multisig_fast_path(
1282 script_sig: &ByteString,
1283 script_pubkey: &[u8],
1284 flags: u32,
1285 tx: &Transaction,
1286 input_index: usize,
1287 prevout_values: &[i64],
1288 prevout_script_pubkeys: &[&[u8]],
1289 block_height: Option<u64>,
1290 network: crate::types::Network,
1291 #[cfg(feature = "production")] sighash_cache: Option<
1292 &crate::transaction_hash::SighashMidstateCache,
1293 >,
1294) -> Option<Result<bool>> {
1295 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1296 if pushes.len() < 2 {
1297 return None;
1298 }
1299 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1300 let expected_hash = &script_pubkey[2..22];
1301 let sha256_hash = OptimizedSha256::new().hash(redeem);
1302 let redeem_hash = Ripemd160::digest(sha256_hash);
1303 if &redeem_hash[..] != expected_hash {
1304 return Some(Ok(false));
1305 }
1306 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1307 let signatures: Vec<&[u8]> = pushes
1308 .iter()
1309 .take(pushes.len() - 1)
1310 .skip(1)
1311 .map(|e| e.as_ref())
1312 .collect();
1313 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1314
1315 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1316 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1317 let height = block_height.unwrap_or(0);
1318 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1319 let activation = match network {
1320 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1321 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1322 crate::types::Network::Regtest => 0,
1323 };
1324 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1325 return Some(Ok(false));
1326 }
1327 }
1328
1329 let mut cleaned = redeem.to_vec();
1330 for sig in &signatures {
1331 if !sig.is_empty() {
1332 let pattern = serialize_push_data(sig);
1333 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1334 }
1335 }
1336
1337 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1338
1339 let mut sig_index = 0;
1340 let mut valid_sigs = 0u8;
1341
1342 for pubkey_bytes in pubkeys {
1343 if sig_index >= signatures.len() {
1344 break;
1345 }
1346 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1347 sig_index += 1;
1348 }
1349 if sig_index >= signatures.len() {
1350 break;
1351 }
1352 let signature_bytes = &signatures[sig_index];
1353 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1354 let sighash_type = SighashType::from_byte(sighash_byte);
1355 let sighash = match calculate_transaction_sighash_single_input(
1356 tx,
1357 input_index,
1358 &cleaned,
1359 prevout_values[input_index],
1360 sighash_type,
1361 #[cfg(feature = "production")]
1362 sighash_cache,
1363 ) {
1364 Ok(h) => h,
1365 Err(e) => return Some(Err(e)),
1366 };
1367
1368 #[cfg(feature = "production")]
1369 let is_valid = signature::with_secp_context(|secp| {
1370 signature::verify_signature(
1371 secp,
1372 pubkey_bytes,
1373 signature_bytes,
1374 &sighash,
1375 flags,
1376 height,
1377 network,
1378 SigVersion::Base,
1379 )
1380 });
1381
1382 #[cfg(not(feature = "production"))]
1383 let is_valid = {
1384 let secp = signature::new_secp();
1385 signature::verify_signature(
1386 &secp,
1387 pubkey_bytes,
1388 signature_bytes,
1389 &sighash,
1390 flags,
1391 height,
1392 network,
1393 SigVersion::Base,
1394 )
1395 };
1396
1397 let is_valid = match is_valid {
1398 Ok(v) => v,
1399 Err(e) => return Some(Err(e)),
1400 };
1401
1402 if is_valid {
1403 valid_sigs += 1;
1404 sig_index += 1;
1405 }
1406 }
1407
1408 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1409 for sig_bytes in &signatures[sig_index..] {
1410 if !sig_bytes.is_empty() {
1411 return Some(Err(ConsensusError::ScriptErrorWithCode {
1412 code: ScriptErrorCode::SigNullFail,
1413 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1414 .into(),
1415 }));
1416 }
1417 }
1418 }
1419
1420 Some(Ok(valid_sigs >= m))
1421}
1422
1423#[allow(clippy::too_many_arguments)]
1426fn try_verify_bare_multisig_fast_path(
1427 script_sig: &ByteString,
1428 script_pubkey: &[u8],
1429 flags: u32,
1430 tx: &Transaction,
1431 input_index: usize,
1432 prevout_values: &[i64],
1433 prevout_script_pubkeys: &[&[u8]],
1434 block_height: Option<u64>,
1435 network: crate::types::Network,
1436 #[cfg(feature = "production")] sighash_cache: Option<
1437 &crate::transaction_hash::SighashMidstateCache,
1438 >,
1439) -> Option<Result<bool>> {
1440 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1441 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1442 if pushes.len() < 2 {
1443 return None;
1444 }
1445 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1446 let signatures: Vec<&[u8]> = pushes[1..].iter().map(|e| e.as_ref()).collect();
1447
1448 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1449 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1450 let height = block_height.unwrap_or(0);
1451 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1452 let activation = match network {
1453 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1454 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1455 crate::types::Network::Regtest => 0,
1456 };
1457 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1458 return Some(Ok(false));
1459 }
1460 }
1461
1462 let mut cleaned = script_pubkey.to_vec();
1463 for sig in &signatures {
1464 if !sig.is_empty() {
1465 let pattern = serialize_push_data(sig);
1466 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1467 }
1468 }
1469
1470 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1471
1472 let mut sig_index = 0;
1473 let mut valid_sigs = 0u8;
1474
1475 for pubkey_bytes in pubkeys {
1476 if sig_index >= signatures.len() {
1477 break;
1478 }
1479 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1480 sig_index += 1;
1481 }
1482 if sig_index >= signatures.len() {
1483 break;
1484 }
1485 let signature_bytes = &signatures[sig_index];
1486 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1487 let sighash_type = SighashType::from_byte(sighash_byte);
1488 let sighash = match calculate_transaction_sighash_single_input(
1489 tx,
1490 input_index,
1491 &cleaned,
1492 prevout_values[input_index],
1493 sighash_type,
1494 #[cfg(feature = "production")]
1495 sighash_cache,
1496 ) {
1497 Ok(h) => h,
1498 Err(e) => return Some(Err(e)),
1499 };
1500
1501 #[cfg(feature = "production")]
1502 let is_valid = signature::with_secp_context(|secp| {
1503 signature::verify_signature(
1504 secp,
1505 pubkey_bytes,
1506 signature_bytes,
1507 &sighash,
1508 flags,
1509 height,
1510 network,
1511 SigVersion::Base,
1512 )
1513 });
1514
1515 #[cfg(not(feature = "production"))]
1516 let is_valid = {
1517 let secp = signature::new_secp();
1518 signature::verify_signature(
1519 &secp,
1520 pubkey_bytes,
1521 signature_bytes,
1522 &sighash,
1523 flags,
1524 height,
1525 network,
1526 SigVersion::Base,
1527 )
1528 };
1529
1530 let is_valid = match is_valid {
1531 Ok(v) => v,
1532 Err(e) => return Some(Err(e)),
1533 };
1534
1535 if is_valid {
1536 valid_sigs += 1;
1537 sig_index += 1;
1538 }
1539 }
1540
1541 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1542 for sig_bytes in &signatures[sig_index..] {
1543 if !sig_bytes.is_empty() {
1544 return Some(Err(ConsensusError::ScriptErrorWithCode {
1545 code: ScriptErrorCode::SigNullFail,
1546 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1547 .into(),
1548 }));
1549 }
1550 }
1551 }
1552
1553 Some(Ok(valid_sigs >= m))
1554}
1555
1556#[cfg(feature = "production")]
1560#[allow(clippy::too_many_arguments)]
1561fn try_verify_p2sh_fast_path(
1562 script_sig: &ByteString,
1563 script_pubkey: &[u8],
1564 flags: u32,
1565 tx: &Transaction,
1566 input_index: usize,
1567 prevout_values: &[i64],
1568 prevout_script_pubkeys: &[&[u8]],
1569 block_height: Option<u64>,
1570 median_time_past: Option<u64>,
1571 network: crate::types::Network,
1572 #[cfg(feature = "production")] sighash_cache: Option<
1573 &crate::transaction_hash::SighashMidstateCache,
1574 >,
1575 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1576) -> Option<Result<bool>> {
1577 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1578 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1579 return None;
1580 }
1581 if script_pubkey.len() != 23
1583 || script_pubkey[0] != OP_HASH160
1584 || script_pubkey[1] != PUSH_20_BYTES
1585 || script_pubkey[22] != OP_EQUAL
1586 {
1587 return None;
1588 }
1589 let expected_hash = &script_pubkey[2..22];
1590
1591 let mut pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1592 if pushes.is_empty() {
1593 return None;
1594 }
1595 let redeem = pushes.pop().expect("at least one push");
1596 let mut stack = pushes;
1597
1598 if redeem.len() >= 3
1600 && redeem[0] == OP_0
1601 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
1602 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
1603 {
1604 return None;
1605 }
1606
1607 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1609 let redeem_hash = Ripemd160::digest(sha256_hash);
1610 if &redeem_hash[..] != expected_hash {
1611 return Some(Ok(false));
1612 }
1613
1614 if redeem.len() == 25
1616 && redeem[0] == OP_DUP
1617 && redeem[1] == OP_HASH160
1618 && redeem[2] == PUSH_20_BYTES
1619 && redeem[23] == OP_EQUALVERIFY
1620 && redeem[24] == OP_CHECKSIG
1621 && stack.len() == 2
1622 {
1623 let signature_bytes = &stack[0];
1624 let pubkey_bytes = &stack[1];
1625 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1626 let expected_pubkey_hash = &redeem[3..23];
1627 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1628 let pubkey_hash = Ripemd160::digest(sha256_hash);
1629 if &pubkey_hash[..] == expected_pubkey_hash {
1630 #[cfg(feature = "production")]
1631 let sighash = if let Some(precomp) = precomputed_sighash_all {
1632 precomp
1633 } else {
1634 use crate::transaction_hash::{
1635 calculate_transaction_sighash_single_input, SighashType,
1636 };
1637 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1638 let sighash_type = SighashType::from_byte(sighash_byte);
1639 let deleted_storage;
1640 let script_code: &[u8] = if redeem.len() < 71 {
1641 redeem.as_ref()
1642 } else {
1643 let pattern = serialize_push_data(signature_bytes);
1644 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1645 deleted_storage.as_ref()
1646 };
1647 match calculate_transaction_sighash_single_input(
1648 tx,
1649 input_index,
1650 script_code,
1651 prevout_values[input_index],
1652 sighash_type,
1653 sighash_cache,
1654 ) {
1655 Ok(h) => h,
1656 Err(e) => return Some(Err(e)),
1657 }
1658 };
1659 #[cfg(not(feature = "production"))]
1660 let sighash = {
1661 use crate::transaction_hash::{
1662 calculate_transaction_sighash_single_input, SighashType,
1663 };
1664 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1665 let sighash_type = SighashType::from_byte(sighash_byte);
1666 let deleted_storage;
1667 let script_code: &[u8] = if redeem.len() < 71 {
1668 redeem.as_ref()
1669 } else {
1670 let pattern = serialize_push_data(signature_bytes);
1671 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1672 deleted_storage.as_ref()
1673 };
1674 match calculate_transaction_sighash_single_input(
1675 tx,
1676 input_index,
1677 script_code,
1678 prevout_values[input_index],
1679 sighash_type,
1680 ) {
1681 Ok(h) => h,
1682 Err(e) => return Some(Err(e)),
1683 }
1684 };
1685 let height = block_height.unwrap_or(0);
1686 let is_valid = signature::with_secp_context(|secp| {
1687 signature::verify_signature(
1688 secp,
1689 pubkey_bytes,
1690 signature_bytes,
1691 &sighash,
1692 flags,
1693 height,
1694 network,
1695 SigVersion::Base,
1696 )
1697 });
1698 return Some(is_valid);
1699 }
1700 }
1701 }
1702
1703 if (redeem.len() == 35 || redeem.len() == 67)
1705 && redeem[redeem.len() - 1] == OP_CHECKSIG
1706 && (redeem[0] == 0x21 || redeem[0] == 0x41)
1707 && stack.len() == 1
1708 {
1709 let pubkey_len = redeem.len() - 2;
1710 if pubkey_len == 33 || pubkey_len == 65 {
1711 let pubkey_bytes = &redeem.as_ref()[1..(redeem.len() - 1)];
1712 let signature_bytes = &stack[0];
1713 if !signature_bytes.is_empty() {
1714 use crate::transaction_hash::{
1715 calculate_transaction_sighash_single_input, SighashType,
1716 };
1717 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1718 let sighash_type = SighashType::from_byte(sighash_byte);
1719 let deleted_storage;
1721 let script_code: &[u8] = if redeem.len() < 71 {
1722 redeem.as_ref()
1723 } else {
1724 let pattern = serialize_push_data(signature_bytes);
1725 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1726 deleted_storage.as_ref()
1727 };
1728 match calculate_transaction_sighash_single_input(
1729 tx,
1730 input_index,
1731 script_code,
1732 prevout_values[input_index],
1733 sighash_type,
1734 #[cfg(feature = "production")]
1735 sighash_cache,
1736 ) {
1737 Ok(sighash) => {
1738 let height = block_height.unwrap_or(0);
1739 let is_valid = signature::with_secp_context(|secp| {
1740 signature::verify_signature(
1741 secp,
1742 pubkey_bytes,
1743 signature_bytes,
1744 &sighash,
1745 flags,
1746 height,
1747 network,
1748 SigVersion::Base,
1749 )
1750 });
1751 return Some(is_valid);
1752 }
1753 Err(e) => return Some(Err(e)),
1754 }
1755 }
1756 }
1757 }
1758
1759 let result = eval_script_with_context_full_inner(
1761 &redeem,
1762 &mut stack,
1763 flags,
1764 tx,
1765 input_index,
1766 prevout_values,
1767 prevout_script_pubkeys,
1768 block_height,
1769 median_time_past,
1770 network,
1771 SigVersion::Base,
1772 Some(redeem.as_ref()),
1773 None, #[cfg(feature = "production")]
1775 None, None, #[cfg(feature = "production")]
1778 sighash_cache,
1779 );
1780 Some(result)
1781}
1782
1783#[cfg(feature = "production")]
1786#[allow(clippy::too_many_arguments)]
1787fn try_verify_p2wpkh_fast_path(
1788 script_sig: &ByteString,
1789 script_pubkey: &[u8],
1790 witness: &crate::witness::Witness,
1791 flags: u32,
1792 tx: &Transaction,
1793 input_index: usize,
1794 prevout_values: &[i64],
1795 prevout_script_pubkeys: &[&[u8]],
1796 block_height: Option<u64>,
1797 network: crate::types::Network,
1798 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1799 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1800) -> Option<Result<bool>> {
1801 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
1803 return None;
1804 }
1805 if !script_sig.is_empty() {
1807 return None;
1808 }
1809 if witness.len() != 2 {
1810 return None;
1811 }
1812 let signature_bytes = &witness[0];
1813 let pubkey_bytes = &witness[1];
1814
1815 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1816 return Some(Ok(false));
1817 }
1818 if signature_bytes.is_empty() {
1819 return Some(Ok(false));
1820 }
1821
1822 let expected_hash = &script_pubkey[2..22];
1823 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1824 let pubkey_hash = Ripemd160::digest(sha256_hash);
1825 if &pubkey_hash[..] != expected_hash {
1826 return Some(Ok(false));
1827 }
1828
1829 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1830 let sighash = if sighash_byte == 0x01 {
1831 #[cfg(feature = "production")]
1833 if let Some(precomp) = precomputed_sighash_all {
1834 precomp
1835 } else {
1836 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1837 match crate::transaction_hash::calculate_bip143_sighash(
1838 tx,
1839 input_index,
1840 script_pubkey,
1841 amount,
1842 sighash_byte,
1843 precomputed_bip143,
1844 ) {
1845 Ok(h) => h,
1846 Err(e) => return Some(Err(e)),
1847 }
1848 }
1849 #[cfg(not(feature = "production"))]
1850 {
1851 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1852 match crate::transaction_hash::calculate_bip143_sighash(
1853 tx,
1854 input_index,
1855 script_pubkey,
1856 amount,
1857 sighash_byte,
1858 precomputed_bip143,
1859 ) {
1860 Ok(h) => h,
1861 Err(e) => return Some(Err(e)),
1862 }
1863 }
1864 } else {
1865 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1866 match crate::transaction_hash::calculate_bip143_sighash(
1867 tx,
1868 input_index,
1869 script_pubkey,
1870 amount,
1871 sighash_byte,
1872 precomputed_bip143,
1873 ) {
1874 Ok(h) => h,
1875 Err(e) => return Some(Err(e)),
1876 }
1877 };
1878
1879 let height = block_height.unwrap_or(0);
1880 let is_valid = signature::with_secp_context(|secp| {
1881 signature::verify_signature(
1882 secp,
1883 pubkey_bytes,
1884 signature_bytes,
1885 &sighash,
1886 flags,
1887 height,
1888 network,
1889 SigVersion::WitnessV0,
1890 )
1891 });
1892 Some(is_valid)
1893}
1894
1895#[cfg(feature = "production")]
1897#[allow(clippy::too_many_arguments)]
1898fn try_verify_p2wpkh_in_p2sh_fast_path(
1899 script_sig: &ByteString,
1900 script_pubkey: &[u8],
1901 witness: &crate::witness::Witness,
1902 flags: u32,
1903 tx: &Transaction,
1904 input_index: usize,
1905 prevout_values: &[i64],
1906 prevout_script_pubkeys: &[&[u8]],
1907 block_height: Option<u64>,
1908 network: crate::types::Network,
1909 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1910) -> Option<Result<bool>> {
1911 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1912 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1913 return None;
1914 }
1915 if script_pubkey.len() != 23
1916 || script_pubkey[0] != OP_HASH160
1917 || script_pubkey[1] != PUSH_20_BYTES
1918 || script_pubkey[22] != OP_EQUAL
1919 {
1920 return None;
1921 }
1922 let expected_hash = &script_pubkey[2..22];
1923
1924 let pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1925 if pushes.len() != 1 {
1926 return None;
1927 }
1928 let redeem = &pushes[0];
1929 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
1930 return None;
1931 }
1932 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1933 let redeem_hash = Ripemd160::digest(sha256_hash);
1934 if &redeem_hash[..] != expected_hash {
1935 return Some(Ok(false));
1936 }
1937
1938 if witness.len() != 2 {
1939 return None;
1940 }
1941 let signature_bytes = &witness[0];
1942 let pubkey_bytes = &witness[1];
1943 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1944 return Some(Ok(false));
1945 }
1946 let expected_pubkey_hash = &redeem[2..22];
1947 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
1948 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
1949 if &pubkey_hash[..] != expected_pubkey_hash {
1950 return Some(Ok(false));
1951 }
1952
1953 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1954 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1955 let sighash = match crate::transaction_hash::calculate_bip143_sighash(
1956 tx,
1957 input_index,
1958 redeem.as_ref(),
1959 amount,
1960 sighash_byte,
1961 precomputed_bip143,
1962 ) {
1963 Ok(h) => h,
1964 Err(e) => return Some(Err(e)),
1965 };
1966
1967 let height = block_height.unwrap_or(0);
1968 let is_valid = signature::with_secp_context(|secp| {
1969 signature::verify_signature(
1970 secp,
1971 pubkey_bytes,
1972 signature_bytes,
1973 &sighash,
1974 flags,
1975 height,
1976 network,
1977 SigVersion::WitnessV0,
1978 )
1979 });
1980 Some(is_valid)
1981}
1982
1983#[cfg(feature = "production")]
1986#[allow(clippy::too_many_arguments)]
1987fn try_verify_p2wsh_fast_path(
1988 script_sig: &ByteString,
1989 script_pubkey: &[u8],
1990 witness: &crate::witness::Witness,
1991 flags: u32,
1992 tx: &Transaction,
1993 input_index: usize,
1994 prevout_values: &[i64],
1995 prevout_script_pubkeys: &[&[u8]],
1996 block_height: Option<u64>,
1997 median_time_past: Option<u64>,
1998 network: crate::types::Network,
1999 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2000 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2001 #[cfg(feature = "production")] sighash_cache: Option<
2002 &crate::transaction_hash::SighashMidstateCache,
2003 >,
2004) -> Option<Result<bool>> {
2005 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
2007 return None;
2008 }
2009 if !script_sig.is_empty() {
2010 return None;
2011 }
2012 if witness.is_empty() {
2013 return None;
2014 }
2015 let witness_script = witness.last().expect("witness not empty").clone();
2016 let mut stack: Vec<StackElement> = witness
2017 .iter()
2018 .take(witness.len() - 1)
2019 .map(|w| to_stack_element(w))
2020 .collect();
2021
2022 let program_hash = &script_pubkey[2..34];
2023 if program_hash.len() != 32 {
2024 return None;
2025 }
2026 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2027 if &witness_script_hash[..] != program_hash {
2028 return Some(Ok(false));
2029 }
2030
2031 let witness_sigversion = SigVersion::WitnessV0;
2035
2036 if witness_sigversion == SigVersion::WitnessV0
2038 && witness_script.len() == 25
2039 && witness_script[0] == OP_DUP
2040 && witness_script[1] == OP_HASH160
2041 && witness_script[2] == PUSH_20_BYTES
2042 && witness_script[23] == OP_EQUALVERIFY
2043 && witness_script[24] == OP_CHECKSIG
2044 && stack.len() == 2
2045 {
2046 let signature_bytes = &stack[0];
2047 let pubkey_bytes = &stack[1];
2048 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2049 let expected_pubkey_hash = &witness_script[3..23];
2050 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2051 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2052 if &pubkey_hash[..] == expected_pubkey_hash {
2053 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2054 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2055 match crate::transaction_hash::calculate_bip143_sighash(
2056 tx,
2057 input_index,
2058 witness_script.as_ref(),
2059 amount,
2060 sighash_byte,
2061 precomputed_bip143,
2062 ) {
2063 Ok(sighash) => {
2064 let height = block_height.unwrap_or(0);
2065 let is_valid = signature::with_secp_context(|secp| {
2066 signature::verify_signature(
2067 secp,
2068 pubkey_bytes,
2069 signature_bytes,
2070 &sighash,
2071 flags,
2072 height,
2073 network,
2074 SigVersion::WitnessV0,
2075 )
2076 });
2077 return Some(is_valid);
2078 }
2079 Err(e) => return Some(Err(e)),
2080 }
2081 }
2082 }
2083 }
2084
2085 if witness_sigversion == SigVersion::WitnessV0
2087 && (witness_script.len() == 35 || witness_script.len() == 67)
2088 && witness_script[witness_script.len() - 1] == OP_CHECKSIG
2089 && (witness_script[0] == 0x21 || witness_script[0] == 0x41)
2090 && stack.len() == 1
2091 {
2092 let pubkey_len = witness_script.len() - 2;
2093 if (pubkey_len == 33 || pubkey_len == 65) && !stack[0].is_empty() {
2094 let pubkey_bytes = &witness_script[1..(witness_script.len() - 1)];
2095 let signature_bytes = &stack[0];
2096 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2097 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2098 match crate::transaction_hash::calculate_bip143_sighash(
2099 tx,
2100 input_index,
2101 witness_script.as_ref(),
2102 amount,
2103 sighash_byte,
2104 precomputed_bip143,
2105 ) {
2106 Ok(sighash) => {
2107 let height = block_height.unwrap_or(0);
2108 let is_valid = signature::with_secp_context(|secp| {
2109 signature::verify_signature(
2110 secp,
2111 pubkey_bytes,
2112 signature_bytes,
2113 &sighash,
2114 flags,
2115 height,
2116 network,
2117 SigVersion::WitnessV0,
2118 )
2119 });
2120 return Some(is_valid);
2121 }
2122 Err(e) => return Some(Err(e)),
2123 }
2124 }
2125 }
2126
2127 if witness_sigversion == SigVersion::WitnessV0 {
2129 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script.as_ref()) {
2130 if stack.len() < 2 {
2131 return Some(Ok(false));
2132 }
2133 let dummy = stack[0].as_ref();
2134 let signatures: Vec<&[u8]> = stack[1..].iter().map(|e| e.as_ref()).collect();
2135
2136 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
2137 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
2138 let height = block_height.unwrap_or(0);
2139 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
2140 let activation = match network {
2141 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
2142 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
2143 crate::types::Network::Regtest => 0,
2144 };
2145 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
2146 return Some(Ok(false));
2147 }
2148 }
2149
2150 let mut cleaned = witness_script.to_vec();
2151 for sig in &signatures {
2152 if !sig.is_empty() {
2153 let pattern = serialize_push_data(sig);
2154 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
2155 }
2156 }
2157
2158 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2159 let mut sig_index = 0;
2160 let mut valid_sigs = 0u8;
2161
2162 for pubkey_bytes in pubkeys {
2163 if sig_index >= signatures.len() {
2164 break;
2165 }
2166 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
2167 sig_index += 1;
2168 }
2169 if sig_index >= signatures.len() {
2170 break;
2171 }
2172 let signature_bytes = &signatures[sig_index];
2173 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2174 match crate::transaction_hash::calculate_bip143_sighash(
2175 tx,
2176 input_index,
2177 &cleaned,
2178 amount,
2179 sighash_byte,
2180 precomputed_bip143,
2181 ) {
2182 Ok(sighash) => {
2183 let is_valid = signature::with_secp_context(|secp| {
2184 signature::verify_signature(
2185 secp,
2186 pubkey_bytes,
2187 signature_bytes,
2188 &sighash,
2189 flags,
2190 height,
2191 network,
2192 SigVersion::WitnessV0,
2193 )
2194 });
2195 match is_valid {
2196 Ok(v) if v => {
2197 valid_sigs += 1;
2198 sig_index += 1;
2199 }
2200 Ok(_) => {}
2201 Err(e) => return Some(Err(e)),
2202 }
2203 }
2204 Err(e) => return Some(Err(e)),
2205 }
2206 }
2207
2208 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
2209 for sig_bytes in &signatures[sig_index..] {
2210 if !sig_bytes.is_empty() {
2211 return Some(Err(ConsensusError::ScriptErrorWithCode {
2212 code: ScriptErrorCode::SigNullFail,
2213 message:
2214 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
2215 .into(),
2216 }));
2217 }
2218 }
2219 }
2220
2221 return Some(Ok(valid_sigs >= m));
2222 }
2223 }
2224
2225 let result = eval_script_with_context_full_inner(
2228 &witness_script,
2229 &mut stack,
2230 flags,
2231 tx,
2232 input_index,
2233 prevout_values,
2234 prevout_script_pubkeys,
2235 block_height,
2236 median_time_past,
2237 network,
2238 witness_sigversion,
2239 None, None, schnorr_collector,
2242 precomputed_bip143,
2243 #[cfg(feature = "production")]
2244 sighash_cache,
2245 );
2246 Some(result)
2247}
2248
2249#[cfg(feature = "production")]
2251#[allow(clippy::too_many_arguments)]
2252fn try_verify_p2tr_scriptpath_p2pk_fast_path(
2253 script_sig: &ByteString,
2254 script_pubkey: &[u8],
2255 witness: &crate::witness::Witness,
2256 _flags: u32,
2257 tx: &Transaction,
2258 input_index: usize,
2259 prevout_values: &[i64],
2260 prevout_script_pubkeys: &[&[u8]],
2261 block_height: Option<u64>,
2262 network: crate::types::Network,
2263 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2264) -> Option<Result<bool>> {
2265 use crate::activation::taproot_activation_height;
2266 use crate::taproot::parse_taproot_script_path_witness;
2267
2268 let tap_h = taproot_activation_height(network);
2269 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2270 return None;
2271 }
2272 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2273 return None;
2274 }
2275 if !script_sig.is_empty() {
2276 return None;
2277 }
2278 if witness.len() < 2 {
2279 return None;
2280 }
2281 let mut output_key = [0u8; 32];
2282 output_key.copy_from_slice(&script_pubkey[2..34]);
2283 let parsed = match parse_taproot_script_path_witness(witness, &output_key) {
2284 Ok(Some(p)) => p,
2285 Ok(None) | Err(_) => return None,
2286 };
2287 let (tapscript, stack_items, control_block) = parsed;
2288 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
2289 return None;
2290 }
2291 if stack_items.len() != 1 || stack_items[0].len() != 64 {
2292 return None;
2293 }
2294 let sig = stack_items[0].as_ref();
2295 let pubkey_32 = &tapscript[1..33];
2296 let sighash = crate::taproot::compute_tapscript_signature_hash(
2297 tx,
2298 input_index,
2299 prevout_values,
2300 prevout_script_pubkeys,
2301 &tapscript,
2302 control_block.leaf_version,
2303 0xffff_ffff,
2304 0x00,
2305 )
2306 .ok()?;
2307 let result = crate::bip348::verify_tapscript_schnorr_signature(
2308 &sighash,
2309 pubkey_32,
2310 sig,
2311 schnorr_collector,
2312 );
2313 Some(result)
2314}
2315
2316#[cfg(feature = "production")]
2319#[allow(clippy::too_many_arguments)]
2320fn try_verify_p2tr_keypath_fast_path(
2321 script_sig: &ByteString,
2322 script_pubkey: &[u8],
2323 witness: &crate::witness::Witness,
2324 _flags: u32,
2325 tx: &Transaction,
2326 input_index: usize,
2327 prevout_values: &[i64],
2328 prevout_script_pubkeys: &[&[u8]],
2329 block_height: Option<u64>,
2330 network: crate::types::Network,
2331 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2332) -> Option<Result<bool>> {
2333 use crate::activation::taproot_activation_height;
2334 let tap_h = taproot_activation_height(network);
2335 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2336 return None;
2337 }
2338 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2340 return None;
2341 }
2342 if !script_sig.is_empty() {
2343 return None;
2344 }
2345 if witness.len() != 1 || witness[0].len() != 64 {
2347 return None;
2348 }
2349 let output_key = &script_pubkey[2..34];
2350 let sig = &witness[0];
2351 let sighash = crate::taproot::compute_taproot_signature_hash(
2352 tx,
2353 input_index,
2354 prevout_values,
2355 prevout_script_pubkeys,
2356 0x00, )
2358 .ok()?;
2359 let result = crate::bip348::verify_tapscript_schnorr_signature(
2360 &sighash,
2361 output_key,
2362 sig,
2363 schnorr_collector,
2364 );
2365 Some(result)
2366}
2367
2368#[spec_locked("5.2", "VerifyScript")]
2369pub fn verify_script_with_context_full(
2370 script_sig: &ByteString,
2371 script_pubkey: &[u8],
2372 witness: Option<&crate::witness::Witness>,
2373 flags: u32,
2374 tx: &Transaction,
2375 input_index: usize,
2376 prevout_values: &[i64],
2377 prevout_script_pubkeys: &[&[u8]],
2378 block_height: Option<u64>,
2379 median_time_past: Option<u64>,
2380 network: crate::types::Network,
2381 _sigversion: SigVersion,
2382 #[cfg(feature = "production")] schnorr_collector: Option<
2383 &crate::bip348::SchnorrSignatureCollector,
2384 >,
2385 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2386 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2387 #[cfg(feature = "production")] sighash_cache: Option<
2388 &crate::transaction_hash::SighashMidstateCache,
2389 >,
2390 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
2391) -> Result<bool> {
2392 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
2394 return Err(ConsensusError::ScriptErrorWithCode {
2395 code: ScriptErrorCode::TxInputInvalid,
2396 message: format!(
2397 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
2398 prevout_values.len(),
2399 prevout_script_pubkeys.len(),
2400 tx.inputs.len(),
2401 input_index,
2402 )
2403 .into(),
2404 });
2405 }
2406
2407 if input_index < prevout_values.len() {
2413 let prevout_value = prevout_values[input_index];
2414 if prevout_value < 0 {
2415 return Err(ConsensusError::ScriptErrorWithCode {
2416 code: ScriptErrorCode::ValueOverflow,
2417 message: "Prevout value cannot be negative".into(),
2418 });
2419 }
2420 #[cfg(feature = "production")]
2421 {
2422 use precomputed_constants::MAX_MONEY_U64;
2423 if (prevout_value as u64) > MAX_MONEY_U64 {
2424 return Err(ConsensusError::ScriptErrorWithCode {
2425 code: ScriptErrorCode::ValueOverflow,
2426 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2427 });
2428 }
2429 }
2430 #[cfg(not(feature = "production"))]
2431 {
2432 use crate::constants::MAX_MONEY;
2433 if prevout_value > MAX_MONEY {
2434 return Err(ConsensusError::ScriptErrorWithCode {
2435 code: ScriptErrorCode::ValueOverflow,
2436 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2437 });
2438 }
2439 }
2440 }
2441
2442 if input_index >= tx.inputs.len() {
2444 return Err(ConsensusError::ScriptErrorWithCode {
2445 code: ScriptErrorCode::TxInputInvalid,
2446 message: format!(
2447 "Input index {} out of bounds (tx has {} inputs)",
2448 input_index,
2449 tx.inputs.len()
2450 )
2451 .into(),
2452 });
2453 }
2454
2455 #[cfg(feature = "production")]
2457 if witness.is_none() {
2458 if let Some(result) = try_verify_p2pk_fast_path(
2459 script_sig,
2460 script_pubkey,
2461 flags,
2462 tx,
2463 input_index,
2464 prevout_values,
2465 prevout_script_pubkeys,
2466 block_height,
2467 network,
2468 #[cfg(feature = "production")]
2469 sighash_cache,
2470 ) {
2471 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
2472 return result;
2473 }
2474 if let Some(result) = try_verify_p2pkh_fast_path(
2475 script_sig,
2476 script_pubkey,
2477 flags,
2478 tx,
2479 input_index,
2480 prevout_values,
2481 prevout_script_pubkeys,
2482 block_height,
2483 network,
2484 #[cfg(feature = "production")]
2485 precomputed_sighash_all,
2486 #[cfg(feature = "production")]
2487 sighash_cache,
2488 #[cfg(feature = "production")]
2489 precomputed_p2pkh_hash,
2490 ) {
2491 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
2492 return result;
2493 }
2494 if let Some(result) = try_verify_p2sh_fast_path(
2495 script_sig,
2496 script_pubkey,
2497 flags,
2498 tx,
2499 input_index,
2500 prevout_values,
2501 prevout_script_pubkeys,
2502 block_height,
2503 median_time_past,
2504 network,
2505 #[cfg(feature = "production")]
2506 sighash_cache,
2507 #[cfg(feature = "production")]
2508 precomputed_sighash_all,
2509 ) {
2510 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
2511 return result;
2512 }
2513 if let Some(result) = try_verify_bare_multisig_fast_path(
2514 script_sig,
2515 script_pubkey,
2516 flags,
2517 tx,
2518 input_index,
2519 prevout_values,
2520 prevout_script_pubkeys,
2521 block_height,
2522 network,
2523 #[cfg(feature = "production")]
2524 sighash_cache,
2525 ) {
2526 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
2527 return result;
2528 }
2529 }
2530 #[cfg(feature = "production")]
2532 if let Some(wit) = witness {
2533 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
2534 script_sig,
2535 script_pubkey,
2536 wit,
2537 flags,
2538 tx,
2539 input_index,
2540 prevout_values,
2541 prevout_script_pubkeys,
2542 block_height,
2543 network,
2544 precomputed_bip143,
2545 ) {
2546 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2547 return result;
2548 }
2549 if let Some(result) = try_verify_p2wpkh_fast_path(
2550 script_sig,
2551 script_pubkey,
2552 wit,
2553 flags,
2554 tx,
2555 input_index,
2556 prevout_values,
2557 prevout_script_pubkeys,
2558 block_height,
2559 network,
2560 precomputed_bip143,
2561 precomputed_sighash_all,
2562 ) {
2563 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2564 return result;
2565 }
2566 if let Some(result) = try_verify_p2wsh_fast_path(
2567 script_sig,
2568 script_pubkey,
2569 wit,
2570 flags,
2571 tx,
2572 input_index,
2573 prevout_values,
2574 prevout_script_pubkeys,
2575 block_height,
2576 median_time_past,
2577 network,
2578 schnorr_collector,
2579 precomputed_bip143,
2580 #[cfg(feature = "production")]
2581 sighash_cache,
2582 ) {
2583 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
2584 return result;
2585 }
2586 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
2587 script_sig,
2588 script_pubkey,
2589 wit,
2590 flags,
2591 tx,
2592 input_index,
2593 prevout_values,
2594 prevout_script_pubkeys,
2595 block_height,
2596 network,
2597 schnorr_collector,
2598 ) {
2599 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2600 return result;
2601 }
2602 if let Some(result) = try_verify_p2tr_keypath_fast_path(
2603 script_sig,
2604 script_pubkey,
2605 wit,
2606 flags,
2607 tx,
2608 input_index,
2609 prevout_values,
2610 prevout_script_pubkeys,
2611 block_height,
2612 network,
2613 schnorr_collector,
2614 ) {
2615 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2616 return result;
2617 }
2618 }
2619 #[cfg(feature = "production")]
2620 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
2621
2622 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
2626 let is_p2sh = (flags & SCRIPT_VERIFY_P2SH) != 0
2627 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; if is_p2sh {
2638 let mut i = 0;
2639 while i < script_sig.len() {
2640 let opcode = script_sig[i];
2641 if !is_push_opcode(opcode) {
2642 return Ok(false);
2644 }
2645 if opcode == OP_0 {
2647 i += 1;
2649 } else if opcode <= 0x4b {
2650 let len = opcode as usize;
2652 if i + 1 + len > script_sig.len() {
2653 return Ok(false); }
2655 i += 1 + len;
2656 } else if opcode == OP_PUSHDATA1 {
2657 if i + 1 >= script_sig.len() {
2659 return Ok(false);
2660 }
2661 let len = script_sig[i + 1] as usize;
2662 if i + 2 + len > script_sig.len() {
2663 return Ok(false);
2664 }
2665 i += 2 + len;
2666 } else if opcode == OP_PUSHDATA2 {
2667 if i + 2 >= script_sig.len() {
2669 return Ok(false);
2670 }
2671 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
2672 if i + 3 + len > script_sig.len() {
2673 return Ok(false);
2674 }
2675 i += 3 + len;
2676 } else if opcode == OP_PUSHDATA4 {
2677 if i + 4 >= script_sig.len() {
2679 return Ok(false);
2680 }
2681 let len = u32::from_le_bytes([
2682 script_sig[i + 1],
2683 script_sig[i + 2],
2684 script_sig[i + 3],
2685 script_sig[i + 4],
2686 ]) as usize;
2687 if i + 5 + len > script_sig.len() {
2688 return Ok(false);
2689 }
2690 i += 5 + len;
2691 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
2692 i += 1;
2695 } else {
2696 return Ok(false);
2698 }
2699 }
2700 if let Some(result) = try_verify_p2sh_multisig_fast_path(
2701 script_sig,
2702 script_pubkey,
2703 flags,
2704 tx,
2705 input_index,
2706 prevout_values,
2707 prevout_script_pubkeys,
2708 block_height,
2709 network,
2710 #[cfg(feature = "production")]
2711 sighash_cache,
2712 ) {
2713 return result;
2714 }
2715 }
2716
2717 #[cfg(feature = "production")]
2718 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
2719 #[cfg(feature = "production")]
2720 let stack = &mut _stack_guard.0;
2721 #[cfg(not(feature = "production"))]
2722 let mut stack = Vec::with_capacity(20);
2723
2724 let script_sig_result = eval_script_with_context_full(
2728 script_sig,
2729 stack,
2730 flags,
2731 tx,
2732 input_index,
2733 prevout_values,
2734 prevout_script_pubkeys,
2735 block_height,
2736 median_time_past,
2737 network,
2738 SigVersion::Base,
2739 None, #[cfg(feature = "production")]
2741 schnorr_collector,
2742 None, #[cfg(feature = "production")]
2744 sighash_cache,
2745 )?;
2746 if !script_sig_result {
2747 return Ok(false);
2748 }
2749
2750 let redeem_script: Option<ByteString> = if is_p2sh && !stack.is_empty() {
2752 Some(stack.last().expect("Stack is not empty").as_ref().to_vec())
2753 } else {
2754 None
2755 };
2756
2757 use crate::activation::taproot_activation_height;
2761 let tap_h = taproot_activation_height(network);
2762 let is_taproot = redeem_script.is_none() && block_height.is_some() && block_height.unwrap() >= tap_h
2764 && script_pubkey.len() == 34
2765 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES; if is_taproot && !script_sig.is_empty() {
2770 return Ok(false); }
2772
2773 let is_direct_witness_program = redeem_script.is_none() && !is_taproot && script_pubkey.len() >= 3
2780 && 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;
2786 if is_direct_witness_program {
2787 if let Some(witness_stack) = witness {
2788 if script_pubkey[1] == PUSH_32_BYTES {
2789 if witness_stack.is_empty() {
2792 return Ok(false); }
2794
2795 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2797
2798 let program_bytes = &script_pubkey[2..];
2800 if program_bytes.len() != 32 {
2801 return Ok(false); }
2803
2804 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2805 if &witness_script_hash[..] != program_bytes {
2806 return Ok(false); }
2808
2809 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2811 stack.push(to_stack_element(element));
2812 }
2813
2814 witness_script_to_execute = Some(witness_script.clone());
2816 } else if script_pubkey[1] == PUSH_20_BYTES {
2817 if witness_stack.len() != 2 {
2820 return Ok(false); }
2822
2823 for element in witness_stack.iter() {
2824 stack.push(to_stack_element(element));
2825 }
2826 } else {
2827 return Ok(false); }
2829 } else {
2830 return Ok(false); }
2832 }
2833
2834 if is_taproot {
2835 let Some(witness_stack) = witness else {
2836 return Ok(false);
2837 };
2838 if witness_stack.len() < 2 {
2839 return Ok(false);
2840 }
2841 let mut output_key = [0u8; 32];
2842 output_key.copy_from_slice(&script_pubkey[2..34]);
2843 match crate::taproot::parse_taproot_script_path_witness(witness_stack, &output_key)? {
2844 None => return Ok(false),
2845 Some((tapscript, stack_items, _control_block)) => {
2846 for item in &stack_items {
2847 stack.push(to_stack_element(item));
2848 }
2849 let tapscript_flags = flags | 0x8000;
2850 if !eval_script_with_context_full(
2851 &tapscript,
2852 stack,
2853 tapscript_flags,
2854 tx,
2855 input_index,
2856 prevout_values,
2857 prevout_script_pubkeys,
2858 block_height,
2859 median_time_past,
2860 network,
2861 SigVersion::Tapscript,
2862 None,
2863 #[cfg(feature = "production")]
2864 schnorr_collector,
2865 None,
2866 #[cfg(feature = "production")]
2867 sighash_cache,
2868 )? {
2869 return Ok(false);
2870 }
2871 return Ok(true);
2872 }
2873 }
2874 }
2875
2876 let script_pubkey_result = eval_script_with_context_full(
2883 script_pubkey,
2884 stack,
2885 flags,
2886 tx,
2887 input_index,
2888 prevout_values,
2889 prevout_script_pubkeys,
2890 block_height,
2891 median_time_past,
2892 network,
2893 SigVersion::Base,
2894 Some(script_sig),
2895 #[cfg(feature = "production")]
2896 schnorr_collector,
2897 None, #[cfg(feature = "production")]
2899 sighash_cache,
2900 )?;
2901 if !script_pubkey_result {
2902 return Ok(false);
2903 }
2904
2905 if let Some(witness_script) = witness_script_to_execute {
2907 let witness_sigversion = SigVersion::WitnessV0;
2910
2911 if !eval_script_with_context_full(
2914 &witness_script,
2915 stack,
2916 flags,
2917 tx,
2918 input_index,
2919 prevout_values,
2920 prevout_script_pubkeys,
2921 block_height,
2922 median_time_past,
2923 network,
2924 witness_sigversion,
2925 None, #[cfg(feature = "production")]
2927 schnorr_collector,
2928 precomputed_bip143, #[cfg(feature = "production")]
2930 sighash_cache,
2931 )? {
2932 return Ok(false);
2933 }
2934 }
2935
2936 if let Some(redeem) = redeem_script {
2941 if stack.is_empty() {
2943 return Ok(false); }
2945
2946 let top = stack.last().expect("Stack is not empty");
2948 if !cast_to_bool(top) {
2949 return Ok(false); }
2951
2952 stack.pop();
2954
2955 let is_witness_program = redeem.len() >= 3
2960 && 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() {
2965 let program_bytes = &redeem[2..];
2974
2975 if redeem[1] == PUSH_32_BYTES {
2976 if program_bytes.len() != 32 {
2979 return Ok(false); }
2981
2982 if let Some(witness_stack) = witness {
2987 if witness_stack.is_empty() {
2988 return Ok(false); }
2990
2991 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2993 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2994 if &witness_script_hash[..] != program_bytes {
2995 return Ok(false); }
2997
2998 stack.clear();
3001
3002 for element in witness_stack.iter().take(witness_stack.len() - 1) {
3005 stack.push(to_stack_element(element));
3006 }
3007
3008 let witness_sigversion = if flags & 0x8000 != 0 {
3010 SigVersion::Tapscript
3011 } else {
3012 SigVersion::WitnessV0 };
3014
3015 if !eval_script_with_context_full(
3017 witness_script,
3018 stack,
3019 flags,
3020 tx,
3021 input_index,
3022 prevout_values,
3023 prevout_script_pubkeys,
3024 block_height,
3025 median_time_past,
3026 network,
3027 witness_sigversion,
3028 None, #[cfg(feature = "production")]
3030 schnorr_collector,
3031 precomputed_bip143, #[cfg(feature = "production")]
3033 sighash_cache,
3034 )? {
3035 return Ok(false);
3036 }
3037 } else {
3038 return Ok(false); }
3040 } else if redeem[1] == PUSH_20_BYTES {
3041 stack.clear();
3045 } else {
3046 return Ok(false); }
3048 } else {
3050 let redeem_result = eval_script_with_context_full_inner(
3054 &redeem,
3055 stack,
3056 flags,
3057 tx,
3058 input_index,
3059 prevout_values,
3060 prevout_script_pubkeys,
3061 block_height,
3062 median_time_past,
3063 network,
3064 SigVersion::Base,
3065 Some(redeem.as_ref()), Some(script_sig), #[cfg(feature = "production")]
3068 None, None, #[cfg(feature = "production")]
3071 sighash_cache,
3072 )?;
3073 if !redeem_result {
3074 return Ok(false);
3075 }
3076 }
3077 }
3078
3079 assert!(
3081 stack.len() <= 1000,
3082 "Stack size {} exceeds reasonable maximum after scriptPubkey",
3083 stack.len()
3084 );
3085
3086 if let Some(_witness_stack) = witness {
3095 }
3099
3100 const SCRIPT_VERIFY_CLEANSTACK: u32 = 0x100;
3106
3107 let final_result = if (flags & SCRIPT_VERIFY_CLEANSTACK) != 0 {
3108 stack.len() == 1 && cast_to_bool(&stack[0])
3110 } else {
3111 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
3113 };
3114 Ok(final_result)
3115}
3116
3117#[allow(dead_code)]
3119fn eval_script_with_context(
3120 script: &ByteString,
3121 stack: &mut Vec<StackElement>,
3122 flags: u32,
3123 tx: &Transaction,
3124 input_index: usize,
3125 prevouts: &[TransactionOutput],
3126 network: crate::types::Network,
3127) -> Result<bool> {
3128 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
3130 let prevout_script_pubkeys: Vec<&[u8]> =
3131 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
3132 eval_script_with_context_full(
3133 script,
3134 stack,
3135 flags,
3136 tx,
3137 input_index,
3138 &prevout_values,
3139 &prevout_script_pubkeys,
3140 None, None, network,
3143 SigVersion::Base,
3144 None, #[cfg(feature = "production")]
3146 None, None, #[cfg(feature = "production")]
3149 None, )
3151}
3152
3153#[allow(clippy::too_many_arguments)]
3155fn eval_script_with_context_full(
3156 script: &[u8],
3157 stack: &mut Vec<StackElement>,
3158 flags: u32,
3159 tx: &Transaction,
3160 input_index: usize,
3161 prevout_values: &[i64],
3162 prevout_script_pubkeys: &[&[u8]],
3163 block_height: Option<u64>,
3164 median_time_past: Option<u64>,
3165 network: crate::types::Network,
3166 sigversion: SigVersion,
3167 script_sig_for_sighash: Option<&ByteString>,
3168 #[cfg(feature = "production")] schnorr_collector: Option<
3169 &crate::bip348::SchnorrSignatureCollector,
3170 >,
3171 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3172 #[cfg(feature = "production")] sighash_cache: Option<
3173 &crate::transaction_hash::SighashMidstateCache,
3174 >,
3175) -> Result<bool> {
3176 #[cfg(all(feature = "production", feature = "profile"))]
3177 let _t0 = std::time::Instant::now();
3178 let r = eval_script_with_context_full_inner(
3179 script,
3180 stack,
3181 flags,
3182 tx,
3183 input_index,
3184 prevout_values,
3185 prevout_script_pubkeys,
3186 block_height,
3187 median_time_past,
3188 network,
3189 sigversion,
3190 None,
3191 script_sig_for_sighash,
3192 #[cfg(feature = "production")]
3193 schnorr_collector,
3194 precomputed_bip143,
3195 #[cfg(feature = "production")]
3196 sighash_cache,
3197 );
3198 #[cfg(all(feature = "production", feature = "profile"))]
3199 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
3200 r
3201}
3202
3203fn eval_script_with_context_full_inner(
3205 script: &[u8],
3206 stack: &mut Vec<StackElement>,
3207 flags: u32,
3208 tx: &Transaction,
3209 input_index: usize,
3210 prevout_values: &[i64],
3211 prevout_script_pubkeys: &[&[u8]],
3212 block_height: Option<u64>,
3213 median_time_past: Option<u64>,
3214 network: crate::types::Network,
3215 sigversion: SigVersion,
3216 redeem_script_for_sighash: Option<&[u8]>,
3217 script_sig_for_sighash: Option<&ByteString>,
3218 #[cfg(feature = "production")] schnorr_collector: Option<
3219 &crate::bip348::SchnorrSignatureCollector,
3220 >,
3221 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3222 #[cfg(feature = "production")] sighash_cache: Option<
3223 &crate::transaction_hash::SighashMidstateCache,
3224 >,
3225) -> Result<bool> {
3226 assert!(
3229 script.len() <= 10000,
3230 "Script length {} exceeds reasonable maximum",
3231 script.len()
3232 );
3233 assert!(
3234 stack.len() <= 1000,
3235 "Stack size {} exceeds reasonable maximum at start",
3236 stack.len()
3237 );
3238
3239 use crate::error::{ConsensusError, ScriptErrorCode};
3240
3241 if sigversion == SigVersion::Tapscript {
3246 const SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS: u32 = 1 << 17;
3247 let mut pc = 0usize;
3248 while pc < script.len() {
3249 let opcode = script[pc];
3250 if is_op_success(opcode) {
3251 if flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS != 0 {
3252 return Err(ConsensusError::ScriptErrorWithCode {
3253 code: ScriptErrorCode::BadOpcode,
3254 message: format!("OP_SUCCESSx opcode 0x{opcode:02x} is discouraged").into(),
3255 });
3256 }
3257 return Ok(true);
3258 }
3259 pc += op_advance(script, pc);
3261 }
3262 }
3263
3264 if stack.capacity() < 20 {
3266 stack.reserve(20);
3267 }
3268 let mut op_count = 0;
3269 assert!(op_count == 0, "Op count must start at zero");
3271
3272 #[cfg(feature = "production")]
3274 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
3275 #[cfg(not(feature = "production"))]
3276 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
3277 assert!(control_stack.is_empty(), "Control stack must start empty");
3279
3280 #[cfg(feature = "production")]
3281 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
3282 #[cfg(not(feature = "production"))]
3283 let mut altstack: Vec<StackElement> = Vec::new();
3284
3285 let mut code_separator_pos: usize = 0;
3289 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
3290
3291 let mut i = 0;
3293 while i < script.len() {
3294 #[cfg(feature = "production")]
3295 {
3296 prefetch::prefetch_ahead(script, i, 64); }
3299 let opcode = {
3301 #[cfg(feature = "production")]
3302 {
3303 unsafe { *script.get_unchecked(i) }
3304 }
3305 #[cfg(not(feature = "production"))]
3306 {
3307 script[i]
3308 }
3309 };
3310
3311 let in_false_branch = control_flow::in_false_branch(&control_stack);
3313
3314 if !is_push_opcode(opcode) {
3316 op_count += 1;
3317 assert!(
3319 op_count <= MAX_SCRIPT_OPS + 1,
3320 "Op count {op_count} must not exceed MAX_SCRIPT_OPS + 1"
3321 );
3322 if op_count > MAX_SCRIPT_OPS {
3323 return Err(make_operation_limit_error());
3324 }
3325 }
3326
3327 if stack.len() + altstack.len() > MAX_STACK_SIZE {
3329 return Err(make_stack_overflow_error());
3330 }
3331
3332 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
3334 let (data, advance) = if opcode <= 0x4b {
3335 let len = opcode as usize;
3337 if i + 1 + len > script.len() {
3338 return Ok(false); }
3340 (&script[i + 1..i + 1 + len], 1 + len)
3341 } else if opcode == OP_PUSHDATA1 {
3342 if i + 1 >= script.len() {
3344 return Ok(false);
3345 }
3346 let len = script[i + 1] as usize;
3347 if i + 2 + len > script.len() {
3348 return Ok(false);
3349 }
3350 (&script[i + 2..i + 2 + len], 2 + len)
3351 } else if opcode == OP_PUSHDATA2 {
3352 if i + 2 >= script.len() {
3354 return Ok(false);
3355 }
3356 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
3357 if i + 3 + len > script.len() {
3358 return Ok(false);
3359 }
3360 (&script[i + 3..i + 3 + len], 3 + len)
3361 } else {
3362 if i + 4 >= script.len() {
3365 return Ok(false);
3366 }
3367 let len = u32::from_le_bytes([
3368 script[i + 1],
3369 script[i + 2],
3370 script[i + 3],
3371 script[i + 4],
3372 ]) as usize;
3373 let data_start = i.saturating_add(5);
3374 let data_end = data_start.saturating_add(len);
3375 let advance = 5usize.saturating_add(len);
3376 if advance < 5 || data_end > script.len() || data_end < data_start {
3377 return Ok(false); }
3379 (&script[data_start..data_end], advance)
3380 };
3381
3382 if !in_false_branch {
3384 stack.push(to_stack_element(data));
3385 }
3386 i += advance;
3387 continue;
3388 }
3389
3390 if opcode == OP_DUP {
3396 if !in_false_branch {
3397 if stack.is_empty() {
3398 return Err(ConsensusError::ScriptErrorWithCode {
3399 code: ScriptErrorCode::InvalidStackOperation,
3400 message: "OP_DUP: empty stack".into(),
3401 });
3402 }
3403 let len = stack.len();
3406 #[cfg(feature = "production")]
3407 {
3408 if stack.capacity() == stack.len() {
3410 stack.reserve(1);
3411 }
3412 let item = unsafe { stack.get_unchecked(len - 1).clone() };
3414 stack.push(item);
3415 }
3416 #[cfg(not(feature = "production"))]
3417 {
3418 let item = stack.last().unwrap();
3419 stack.push(item.clone());
3420 }
3421 }
3422 i += 1;
3423 continue;
3424 }
3425
3426 if opcode == OP_EQUALVERIFY {
3428 if !in_false_branch {
3429 if stack.len() < 2 {
3430 return Err(ConsensusError::ScriptErrorWithCode {
3431 code: ScriptErrorCode::InvalidStackOperation,
3432 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3433 });
3434 }
3435 let a = stack.pop().unwrap();
3436 let b = stack.pop().unwrap();
3437 if a != b {
3438 return Ok(false);
3439 }
3440 }
3441 i += 1;
3442 continue;
3443 }
3444
3445 if opcode == OP_HASH160 {
3447 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
3448 return Ok(false);
3449 }
3450 i += 1;
3451 continue;
3452 }
3453
3454 if opcode == OP_VERIFY {
3456 if !in_false_branch {
3457 if let Some(item) = stack.pop() {
3458 if !cast_to_bool(&item) {
3459 return Ok(false);
3460 }
3461 } else {
3462 return Ok(false);
3463 }
3464 }
3465 i += 1;
3466 continue;
3467 }
3468
3469 if opcode == OP_EQUAL {
3471 if !in_false_branch {
3472 if stack.len() < 2 {
3473 return Err(ConsensusError::ScriptErrorWithCode {
3474 code: ScriptErrorCode::InvalidStackOperation,
3475 message: "OP_EQUAL: insufficient stack items".into(),
3476 });
3477 }
3478 let a = stack.pop().unwrap();
3479 let b = stack.pop().unwrap();
3480 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3481 }
3482 i += 1;
3483 continue;
3484 }
3485
3486 if opcode == OP_CHECKSIG
3489 || opcode == OP_CHECKSIGVERIFY
3490 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
3491 {
3492 if !in_false_branch {
3493 let effective_script_code = Some(&script[code_separator_pos..]);
3494 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3495 (Some(script), Some(last_codesep_opcode_pos))
3496 } else {
3497 (None, None)
3498 };
3499 let ctx = context::ScriptContext {
3500 tx,
3501 input_index,
3502 prevout_values,
3503 prevout_script_pubkeys,
3504 block_height,
3505 median_time_past,
3506 network,
3507 sigversion,
3508 redeem_script_for_sighash,
3509 script_sig_for_sighash,
3510 tapscript_for_sighash: tapscript,
3511 tapscript_codesep_pos: codesep,
3512 #[cfg(feature = "production")]
3513 schnorr_collector,
3514 #[cfg(feature = "production")]
3515 precomputed_bip143,
3516 #[cfg(feature = "production")]
3517 sighash_cache,
3518 };
3519 if !execute_opcode_with_context_full(
3520 opcode,
3521 stack,
3522 flags,
3523 &ctx,
3524 effective_script_code,
3525 )? {
3526 return Ok(false);
3527 }
3528 }
3529 i += 1;
3530 continue;
3531 }
3532
3533 match opcode {
3534 OP_0 => {
3536 if !in_false_branch {
3537 stack.push(to_stack_element(&[]));
3538 }
3539 }
3540
3541 OP_1_RANGE_START..=OP_1_RANGE_END => {
3543 if !in_false_branch {
3544 let num = opcode - OP_N_BASE;
3545 stack.push(to_stack_element(&[num]));
3546 }
3547 }
3548
3549 OP_1NEGATE => {
3551 if !in_false_branch {
3552 stack.push(to_stack_element(&[0x81])); }
3554 }
3555
3556 OP_NOP => {
3558 }
3560
3561 OP_VER => {
3566 if !in_false_branch {
3567 return Err(ConsensusError::ScriptErrorWithCode {
3568 code: ScriptErrorCode::DisabledOpcode,
3569 message: "OP_VER is disabled".into(),
3570 });
3571 }
3572 }
3573
3574 OP_IF => {
3575 if in_false_branch {
3577 control_stack.push(control_flow::ControlBlock::If { executing: false });
3578 i += 1;
3579 continue;
3580 }
3581
3582 if stack.is_empty() {
3583 return Err(ConsensusError::ScriptErrorWithCode {
3584 code: ScriptErrorCode::InvalidStackOperation,
3585 message: "OP_IF: empty stack".into(),
3586 });
3587 }
3588 let condition_bytes = stack.pop().unwrap();
3589 let condition = cast_to_bool(&condition_bytes);
3590
3591 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3592 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3593 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3594 && !control_flow::is_minimal_if_condition(&condition_bytes)
3595 {
3596 return Err(ConsensusError::ScriptErrorWithCode {
3597 code: ScriptErrorCode::MinimalIf,
3598 message: "OP_IF condition must be minimally encoded".into(),
3599 });
3600 }
3601
3602 control_stack.push(control_flow::ControlBlock::If {
3603 executing: condition,
3604 });
3605 }
3606 OP_NOTIF => {
3607 if in_false_branch {
3609 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
3610 i += 1;
3611 continue;
3612 }
3613
3614 if stack.is_empty() {
3615 return Err(ConsensusError::ScriptErrorWithCode {
3616 code: ScriptErrorCode::InvalidStackOperation,
3617 message: "OP_NOTIF: empty stack".into(),
3618 });
3619 }
3620 let condition_bytes = stack.pop().unwrap();
3621 let condition = cast_to_bool(&condition_bytes);
3622
3623 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3624 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3625 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3626 && !control_flow::is_minimal_if_condition(&condition_bytes)
3627 {
3628 return Err(ConsensusError::ScriptErrorWithCode {
3629 code: ScriptErrorCode::MinimalIf,
3630 message: "OP_NOTIF condition must be minimally encoded".into(),
3631 });
3632 }
3633
3634 control_stack.push(control_flow::ControlBlock::NotIf {
3635 executing: !condition,
3636 });
3637 }
3638 OP_ELSE => {
3639 if let Some(block) = control_stack.last_mut() {
3641 match block {
3642 control_flow::ControlBlock::If { executing }
3643 | control_flow::ControlBlock::NotIf { executing } => {
3644 *executing = !*executing;
3645 }
3646 }
3647 } else {
3648 return Err(ConsensusError::ScriptErrorWithCode {
3649 code: ScriptErrorCode::UnbalancedConditional,
3650 message: "OP_ELSE without matching IF/NOTIF".into(),
3651 });
3652 }
3653 }
3654 OP_ENDIF => {
3655 if control_stack.pop().is_none() {
3657 return Err(ConsensusError::ScriptErrorWithCode {
3658 code: ScriptErrorCode::UnbalancedConditional,
3659 message: "OP_ENDIF without matching IF/NOTIF".into(),
3660 });
3661 }
3662 }
3663
3664 OP_TOALTSTACK => {
3669 if in_false_branch {
3670 i += 1;
3671 continue;
3672 }
3673 if stack.is_empty() {
3674 return Err(ConsensusError::ScriptErrorWithCode {
3675 code: ScriptErrorCode::InvalidStackOperation,
3676 message: "OP_TOALTSTACK: empty stack".into(),
3677 });
3678 }
3679 altstack.push(stack.pop().unwrap());
3680 }
3681 OP_FROMALTSTACK => {
3683 if in_false_branch {
3684 i += 1;
3685 continue;
3686 }
3687 if altstack.is_empty() {
3688 return Err(ConsensusError::ScriptErrorWithCode {
3689 code: ScriptErrorCode::InvalidAltstackOperation,
3690 message: "OP_FROMALTSTACK: empty altstack".into(),
3691 });
3692 }
3693 stack.push(altstack.pop().unwrap());
3694 }
3695 OP_CODESEPARATOR => {
3697 if in_false_branch {
3698 i += 1;
3699 continue;
3700 }
3701 code_separator_pos = i + 1;
3702 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
3703 }
3704 _ => {
3705 if in_false_branch {
3706 i += 1;
3707 continue;
3708 }
3709
3710 let subscript_for_sighash = if matches!(
3715 opcode,
3716 OP_CHECKSIG
3717 | OP_CHECKSIGVERIFY
3718 | OP_CHECKSIGADD
3719 | OP_CHECKMULTISIG
3720 | OP_CHECKMULTISIGVERIFY
3721 ) {
3722 Some(&script[code_separator_pos..])
3723 } else {
3724 None
3725 };
3726 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
3727 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3728 (Some(script), Some(last_codesep_opcode_pos))
3729 } else {
3730 (None, None)
3731 };
3732 let ctx = context::ScriptContext {
3733 tx,
3734 input_index,
3735 prevout_values,
3736 prevout_script_pubkeys,
3737 block_height,
3738 median_time_past,
3739 network,
3740 sigversion,
3741 redeem_script_for_sighash,
3742 script_sig_for_sighash,
3743 tapscript_for_sighash: tapscript,
3744 tapscript_codesep_pos: codesep,
3745 #[cfg(feature = "production")]
3746 schnorr_collector,
3747 #[cfg(feature = "production")]
3748 precomputed_bip143,
3749 #[cfg(feature = "production")]
3750 sighash_cache,
3751 };
3752 if !execute_opcode_with_context_full(
3753 opcode,
3754 stack,
3755 flags,
3756 &ctx,
3757 effective_script_code,
3758 )? {
3759 return Ok(false);
3760 }
3761 }
3762 }
3763 i += 1;
3764 }
3765
3766 if !control_stack.is_empty() {
3768 return Err(ConsensusError::ScriptErrorWithCode {
3769 code: ScriptErrorCode::UnbalancedConditional,
3770 message: "Unclosed IF/NOTIF block".into(),
3771 });
3772 }
3773
3774 Ok(true)
3778}
3779
3780#[spec_locked("5.4.5", "DecodeCScriptNum")]
3784#[cfg(feature = "production")]
3785#[inline(always)]
3786pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3787 if data.len() > max_num_size {
3788 return Err(ConsensusError::ScriptErrorWithCode {
3789 code: ScriptErrorCode::InvalidStackOperation,
3790 message: format!(
3791 "Script number overflow: {} > {} bytes",
3792 data.len(),
3793 max_num_size
3794 )
3795 .into(),
3796 });
3797 }
3798 if data.is_empty() {
3799 return Ok(0);
3800 }
3801
3802 let len = data.len();
3804 let result = match len {
3805 1 => {
3806 let byte = data[0];
3807 if byte & 0x80 != 0 {
3808 -((byte & 0x7f) as i64)
3810 } else {
3811 byte as i64
3812 }
3813 }
3814 2 => {
3815 let byte0 = data[0] as i64;
3816 let byte1 = data[1] as i64;
3817 let value = byte0 | (byte1 << 8);
3818 if byte1 & 0x80 != 0 {
3819 -(value & !(0x80i64 << 8))
3821 } else {
3822 value
3823 }
3824 }
3825 _ => {
3826 let mut result: i64 = 0;
3828 for (i, &byte) in data.iter().enumerate() {
3829 result |= (byte as i64) << (8 * i);
3830 }
3831 let last_idx = len - 1;
3833 if data[last_idx] & 0x80 != 0 {
3834 result &= !(0x80i64 << (8 * last_idx));
3836 result = -result;
3837 }
3838 result
3839 }
3840 };
3841
3842 Ok(result)
3843}
3844
3845#[cfg(not(feature = "production"))]
3846#[inline]
3847pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3848 if data.len() > max_num_size {
3849 return Err(ConsensusError::ScriptErrorWithCode {
3850 code: ScriptErrorCode::InvalidStackOperation,
3851 message: format!(
3852 "Script number overflow: {} > {} bytes",
3853 data.len(),
3854 max_num_size
3855 )
3856 .into(),
3857 });
3858 }
3859 if data.is_empty() {
3860 return Ok(0);
3861 }
3862 let mut result: i64 = 0;
3864 for (i, &byte) in data.iter().enumerate() {
3865 result |= (byte as i64) << (8 * i);
3866 }
3867 if data.last().expect("Data is not empty") & 0x80 != 0 {
3869 result &= !(0x80i64 << (8 * (data.len() - 1)));
3871 result = -result;
3872 }
3873 Ok(result)
3874}
3875
3876#[cfg(feature = "production")]
3879pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3880 match value {
3882 0 => return vec![],
3883 1 => return vec![1],
3884 -1 => return vec![0x81],
3885 _ => {}
3886 }
3887
3888 let neg = value < 0;
3889 let mut absvalue = if neg {
3890 (-(value as i128)) as u64
3891 } else {
3892 value as u64
3893 };
3894 let mut result = Vec::with_capacity(4);
3896 while absvalue > 0 {
3897 result.push((absvalue & 0xff) as u8);
3898 absvalue >>= 8;
3899 }
3900 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3902 result.push(if neg { 0x80 } else { 0x00 });
3903 } else if neg {
3904 *result.last_mut().unwrap() |= 0x80;
3905 }
3906 result
3907}
3908
3909#[cfg(not(feature = "production"))]
3910pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3911 if value == 0 {
3912 return vec![];
3913 }
3914 let neg = value < 0;
3915 let mut absvalue = if neg {
3916 (-(value as i128)) as u64
3917 } else {
3918 value as u64
3919 };
3920 let mut result = Vec::new();
3921 while absvalue > 0 {
3922 result.push((absvalue & 0xff) as u8);
3923 absvalue >>= 8;
3924 }
3925 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3927 result.push(if neg { 0x80 } else { 0x00 });
3928 } else if neg {
3929 *result.last_mut().unwrap() |= 0x80;
3930 }
3931 result
3932}
3933
3934#[cfg(feature = "production")]
3936#[inline(always)]
3937fn execute_opcode(
3938 opcode: u8,
3939 stack: &mut Vec<StackElement>,
3940 flags: u32,
3941 _sigversion: SigVersion,
3942) -> Result<bool> {
3943 match opcode {
3944 OP_0 => {
3946 stack.push(to_stack_element(&[]));
3947 Ok(true)
3948 }
3949
3950 OP_1..=OP_16 => {
3952 let num = opcode - OP_N_BASE;
3953 stack.push(to_stack_element(&[num]));
3954 Ok(true)
3955 }
3956
3957 OP_NOP => Ok(true),
3959
3960 OP_VER => Ok(false),
3962
3963 OP_DEPTH => {
3965 let depth = stack.len() as i64;
3966 stack.push(to_stack_element(&script_num_encode(depth)));
3967 Ok(true)
3968 }
3969
3970 OP_DUP => {
3972 if let Some(item) = stack.last().cloned() {
3973 stack.push(item);
3974 Ok(true)
3975 } else {
3976 Ok(false)
3977 }
3978 }
3979
3980 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
3982
3983 OP_SHA1 => crypto_ops::op_sha1(stack),
3985
3986 OP_SHA256 => crypto_ops::op_sha256(stack),
3988
3989 OP_HASH160 => crypto_ops::op_hash160(stack),
3991
3992 OP_HASH256 => crypto_ops::op_hash256(stack),
3994
3995 OP_EQUAL => {
3997 if stack.len() < 2 {
3998 return Err(ConsensusError::ScriptErrorWithCode {
3999 code: ScriptErrorCode::InvalidStackOperation,
4000 message: "OP_EQUAL: insufficient stack items".into(),
4001 });
4002 }
4003 let a = stack.pop().unwrap();
4004 let b = stack.pop().unwrap();
4005 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
4006 Ok(true)
4007 }
4008
4009 OP_EQUALVERIFY => {
4012 if stack.len() < 2 {
4013 return Err(ConsensusError::ScriptErrorWithCode {
4014 code: ScriptErrorCode::InvalidStackOperation,
4015 message: "OP_EQUALVERIFY: insufficient stack items".into(),
4016 });
4017 }
4018 let a = stack.pop().unwrap();
4019 let b = stack.pop().unwrap();
4020 let f_equal = a == b;
4021 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
4023 if f_equal {
4024 stack.pop();
4026 Ok(true)
4027 } else {
4028 Err(ConsensusError::ScriptErrorWithCode {
4029 code: ScriptErrorCode::EqualVerify,
4030 message: "OP_EQUALVERIFY: stack items not equal".into(),
4031 })
4032 }
4033 }
4034
4035 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
4037
4038 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
4040
4041 OP_RETURN => Ok(false),
4043
4044 OP_VERIFY => {
4046 if let Some(item) = stack.pop() {
4047 Ok(cast_to_bool(&item))
4048 } else {
4049 Ok(false)
4050 }
4051 }
4052
4053 OP_CHECKLOCKTIMEVERIFY => {
4057 Ok(false)
4060 }
4061
4062 OP_CHECKSEQUENCEVERIFY => {
4066 Ok(false)
4069 }
4070
4071 OP_IFDUP => {
4073 if let Some(item) = stack.last().cloned() {
4074 if cast_to_bool(&item) {
4075 stack.push(item);
4076 }
4077 Ok(true)
4078 } else {
4079 Ok(false)
4080 }
4081 }
4082
4083 OP_DROP => {
4086 if stack.pop().is_some() {
4087 Ok(true)
4088 } else {
4089 Ok(false)
4090 }
4091 }
4092
4093 OP_NIP => {
4095 if stack.len() >= 2 {
4096 let top = stack.pop().unwrap();
4097 stack.pop(); stack.push(top);
4099 Ok(true)
4100 } else {
4101 Ok(false)
4102 }
4103 }
4104
4105 OP_OVER => {
4107 if stack.len() >= 2 {
4108 let len = stack.len();
4109 #[cfg(feature = "production")]
4110 {
4111 unsafe {
4113 let second = stack.get_unchecked(len - 2);
4114 stack.push(second.clone());
4115 }
4116 }
4117 #[cfg(not(feature = "production"))]
4118 {
4119 let second = stack[stack.len() - 2].clone();
4120 stack.push(second);
4121 }
4122 Ok(true)
4123 } else {
4124 Ok(false)
4125 }
4126 }
4127
4128 OP_PICK => {
4130 if let Some(n_bytes) = stack.pop() {
4131 let n_val = script_num_decode(&n_bytes, 4)?;
4134 if n_val < 0 || n_val as usize >= stack.len() {
4135 return Ok(false);
4136 }
4137 let n = n_val as usize;
4138 let len = stack.len();
4139 #[cfg(feature = "production")]
4140 {
4141 unsafe {
4143 let item = stack.get_unchecked(len - 1 - n);
4144 stack.push(item.clone());
4145 }
4146 }
4147 #[cfg(not(feature = "production"))]
4148 {
4149 let item = stack[stack.len() - 1 - n].clone();
4150 stack.push(item);
4151 }
4152 Ok(true)
4153 } else {
4154 Ok(false)
4155 }
4156 }
4157
4158 OP_ROLL => {
4160 if let Some(n_bytes) = stack.pop() {
4161 let n_val = script_num_decode(&n_bytes, 4)?;
4164 if n_val < 0 || n_val as usize >= stack.len() {
4165 return Ok(false);
4166 }
4167 let n = n_val as usize;
4168 let len = stack.len();
4169 #[cfg(feature = "production")]
4170 {
4171 let idx = len - 1 - n;
4173 let item = stack.remove(idx);
4174 stack.push(item);
4175 }
4176 #[cfg(not(feature = "production"))]
4177 {
4178 let item = stack.remove(stack.len() - 1 - n);
4179 stack.push(item);
4180 }
4181 Ok(true)
4182 } else {
4183 Ok(false)
4184 }
4185 }
4186
4187 OP_ROT => {
4189 if stack.len() >= 3 {
4190 let top = stack.pop().unwrap();
4191 let second = stack.pop().unwrap();
4192 let third = stack.pop().unwrap();
4193 stack.push(second);
4194 stack.push(top);
4195 stack.push(third);
4196 Ok(true)
4197 } else {
4198 Ok(false)
4199 }
4200 }
4201
4202 OP_SWAP => {
4204 if stack.len() >= 2 {
4205 let top = stack.pop().unwrap();
4206 let second = stack.pop().unwrap();
4207 stack.push(top);
4208 stack.push(second);
4209 Ok(true)
4210 } else {
4211 Ok(false)
4212 }
4213 }
4214
4215 OP_TUCK => {
4217 if stack.len() >= 2 {
4218 let top = stack.pop().unwrap();
4219 let second = stack.pop().unwrap();
4220 stack.push(top.clone());
4221 stack.push(second);
4222 stack.push(top);
4223 Ok(true)
4224 } else {
4225 Ok(false)
4226 }
4227 }
4228
4229 OP_2DROP => {
4231 if stack.len() >= 2 {
4232 stack.pop();
4233 stack.pop();
4234 Ok(true)
4235 } else {
4236 Ok(false)
4237 }
4238 }
4239
4240 OP_2DUP => {
4242 if stack.len() >= 2 {
4243 let top = stack[stack.len() - 1].clone();
4244 let second = stack[stack.len() - 2].clone();
4245 stack.push(second);
4246 stack.push(top);
4247 Ok(true)
4248 } else {
4249 Ok(false)
4250 }
4251 }
4252
4253 OP_3DUP => {
4255 if stack.len() >= 3 {
4256 let top = stack[stack.len() - 1].clone();
4257 let second = stack[stack.len() - 2].clone();
4258 let third = stack[stack.len() - 3].clone();
4259 stack.push(third);
4260 stack.push(second);
4261 stack.push(top);
4262 Ok(true)
4263 } else {
4264 Ok(false)
4265 }
4266 }
4267
4268 OP_2OVER => {
4270 if stack.len() >= 4 {
4271 let fourth = stack[stack.len() - 4].clone();
4272 let third = stack[stack.len() - 3].clone();
4273 stack.push(fourth);
4274 stack.push(third);
4275 Ok(true)
4276 } else {
4277 Ok(false)
4278 }
4279 }
4280
4281 OP_2ROT => {
4283 if stack.len() >= 6 {
4284 let sixth = stack.remove(stack.len() - 6);
4285 let fifth = stack.remove(stack.len() - 5);
4286 stack.push(fifth);
4287 stack.push(sixth);
4288 Ok(true)
4289 } else {
4290 Ok(false)
4291 }
4292 }
4293
4294 OP_2SWAP => {
4296 if stack.len() >= 4 {
4297 let top = stack.pop().unwrap();
4298 let second = stack.pop().unwrap();
4299 let third = stack.pop().unwrap();
4300 let fourth = stack.pop().unwrap();
4301 stack.push(second);
4302 stack.push(top);
4303 stack.push(fourth);
4304 stack.push(third);
4305 Ok(true)
4306 } else {
4307 Ok(false)
4308 }
4309 }
4310
4311 OP_SIZE => {
4314 if let Some(item) = stack.last() {
4315 let size = item.len() as i64;
4316 stack.push(to_stack_element(&script_num_encode(size)));
4317 Ok(true)
4318 } else {
4319 Ok(false)
4320 }
4321 }
4322
4323 OP_1ADD => {
4328 if let Some(item) = stack.pop() {
4329 let a = script_num_decode(&item, 4)?;
4330 stack.push(to_stack_element(&script_num_encode(a + 1)));
4331 Ok(true)
4332 } else {
4333 Ok(false)
4334 }
4335 }
4336 OP_1SUB => {
4338 if let Some(item) = stack.pop() {
4339 let a = script_num_decode(&item, 4)?;
4340 stack.push(to_stack_element(&script_num_encode(a - 1)));
4341 Ok(true)
4342 } else {
4343 Ok(false)
4344 }
4345 }
4346 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4348 code: ScriptErrorCode::DisabledOpcode,
4349 message: "OP_2MUL is disabled".into(),
4350 }),
4351 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4353 code: ScriptErrorCode::DisabledOpcode,
4354 message: "OP_2DIV is disabled".into(),
4355 }),
4356 OP_NEGATE => {
4358 if let Some(item) = stack.pop() {
4359 let a = script_num_decode(&item, 4)?;
4360 stack.push(to_stack_element(&script_num_encode(-a)));
4361 Ok(true)
4362 } else {
4363 Ok(false)
4364 }
4365 }
4366 OP_ABS => {
4368 if let Some(item) = stack.pop() {
4369 let a = script_num_decode(&item, 4)?;
4370 stack.push(to_stack_element(&script_num_encode(a.abs())));
4371 Ok(true)
4372 } else {
4373 Ok(false)
4374 }
4375 }
4376 OP_NOT => {
4378 if let Some(item) = stack.pop() {
4379 let a = script_num_decode(&item, 4)?;
4380 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4381 1
4382 } else {
4383 0
4384 })));
4385 Ok(true)
4386 } else {
4387 Ok(false)
4388 }
4389 }
4390 OP_0NOTEQUAL => {
4392 if let Some(item) = stack.pop() {
4393 let a = script_num_decode(&item, 4)?;
4394 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4395 1
4396 } else {
4397 0
4398 })));
4399 Ok(true)
4400 } else {
4401 Ok(false)
4402 }
4403 }
4404 OP_ADD => arithmetic::op_add(stack),
4405 OP_SUB => arithmetic::op_sub(stack),
4406 OP_MUL => arithmetic::op_mul_disabled(),
4407 OP_DIV => arithmetic::op_div_disabled(),
4408 OP_MOD => arithmetic::op_mod_disabled(),
4409 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4410 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4411 OP_BOOLAND => arithmetic::op_booland(stack),
4412 OP_BOOLOR => arithmetic::op_boolor(stack),
4413 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4414 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4415 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4416 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4417 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4418 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4419 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4420 OP_MIN => arithmetic::op_min(stack),
4421 OP_MAX => arithmetic::op_max(stack),
4422 OP_WITHIN => arithmetic::op_within(stack),
4423
4424 OP_CODESEPARATOR => Ok(true),
4426
4427 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4430
4431 OP_CHECKTEMPLATEVERIFY => {
4433 #[cfg(not(feature = "ctv"))]
4434 {
4435 Ok(true)
4437 }
4438
4439 #[cfg(feature = "ctv")]
4440 {
4441 return Err(ConsensusError::ScriptErrorWithCode {
4443 code: ScriptErrorCode::TxInvalid,
4444 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4445 });
4446 }
4447 }
4448
4449 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4451 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4452 Err(ConsensusError::ScriptErrorWithCode {
4453 code: ScriptErrorCode::DisabledOpcode,
4454 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4455 })
4456 }
4457
4458 _ => Ok(false),
4460 }
4461}
4462
4463#[allow(dead_code)]
4465fn execute_opcode_with_context(
4466 opcode: u8,
4467 stack: &mut Vec<StackElement>,
4468 flags: u32,
4469 tx: &Transaction,
4470 input_index: usize,
4471 prevouts: &[TransactionOutput],
4472 network: crate::types::Network,
4473) -> Result<bool> {
4474 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4476 let prevout_script_pubkeys: Vec<&[u8]> =
4477 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4478 let ctx = context::ScriptContext {
4479 tx,
4480 input_index,
4481 prevout_values: &prevout_values,
4482 prevout_script_pubkeys: &prevout_script_pubkeys,
4483 block_height: None,
4484 median_time_past: None,
4485 network,
4486 sigversion: SigVersion::Base,
4487 redeem_script_for_sighash: None,
4488 script_sig_for_sighash: None,
4489 tapscript_for_sighash: None,
4490 tapscript_codesep_pos: None,
4491 #[cfg(feature = "production")]
4492 schnorr_collector: None,
4493 #[cfg(feature = "production")]
4494 precomputed_bip143: None,
4495 #[cfg(feature = "production")]
4496 sighash_cache: None,
4497 };
4498 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4499}
4500
4501#[cfg(feature = "production")]
4505#[inline(always)]
4506pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4507 let mut i = 0;
4508 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4509 i += adv1;
4510 if i >= script_sig.len() {
4511 return None;
4512 }
4513 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4514 i += adv2;
4515 if i >= script_sig.len() {
4516 return None;
4517 }
4518 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4519 i += adv3;
4520 if i != script_sig.len() {
4521 return None;
4522 }
4523 let sig = &script_sig[s_start..s_end];
4524 let redeem = &script_sig[r_start..r_end];
4525 if sig.is_empty() || redeem.len() != 25 {
4526 return None;
4527 }
4528 if redeem[0] != OP_DUP
4529 || redeem[1] != OP_HASH160
4530 || redeem[2] != PUSH_20_BYTES
4531 || redeem[23] != OP_EQUALVERIFY
4532 || redeem[24] != OP_CHECKSIG
4533 {
4534 return None;
4535 }
4536 Some((sig[sig.len() - 1], redeem))
4537}
4538
4539#[inline(always)]
4543pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4544 let mut i = 0;
4545 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4546 i += adv1;
4547 if i >= script_sig.len() {
4548 return None;
4549 }
4550 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4551 i += adv2;
4552 if i != script_sig.len() {
4553 return None;
4554 }
4555 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4556}
4557
4558pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4561 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4562 if advance != script_sig.len() {
4563 return None;
4564 }
4565 Some(&script_sig[data_start..data_end])
4566}
4567
4568fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4570 if i >= script.len() {
4571 return None;
4572 }
4573 let opcode = script[i];
4574 let (advance, data_start, data_end) = if opcode == OP_0 {
4575 return None;
4576 } else if opcode <= 0x4b {
4577 let len = opcode as usize;
4578 if i + 1 + len > script.len() {
4579 return None;
4580 }
4581 (1 + len, i + 1, i + 1 + len)
4582 } else if opcode == OP_PUSHDATA1 {
4583 if i + 1 >= script.len() {
4584 return None;
4585 }
4586 let len = script[i + 1] as usize;
4587 if i + 2 + len > script.len() {
4588 return None;
4589 }
4590 (2 + len, i + 2, i + 2 + len)
4591 } else if opcode == OP_PUSHDATA2 {
4592 if i + 2 >= script.len() {
4593 return None;
4594 }
4595 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4596 if i + 3 + len > script.len() {
4597 return None;
4598 }
4599 (3 + len, i + 3, i + 3 + len)
4600 } else if opcode == OP_PUSHDATA4 {
4601 if i + 4 >= script.len() {
4602 return None;
4603 }
4604 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4605 as usize;
4606 if i + 5 + len > script.len() {
4607 return None;
4608 }
4609 (5 + len, i + 5, i + 5 + len)
4610 } else {
4611 return None;
4612 };
4613 Some((advance, data_start, data_end))
4614}
4615
4616#[spec_locked("5.2.1", "P2SHPushOnlyCheck")]
4619pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4620 parse_script_sig_push_only(script_sig).is_some()
4621}
4622
4623fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4627 let mut out = Vec::new();
4628 let mut i = 0;
4629 while i < script_sig.len() {
4630 let opcode = script_sig[i];
4631 if !is_push_opcode(opcode) {
4632 return None;
4633 }
4634 let (advance, data) = if opcode == OP_0 {
4635 (1, vec![])
4636 } else if opcode <= 0x4b {
4637 let len = opcode as usize;
4638 if i + 1 + len > script_sig.len() {
4639 return None;
4640 }
4641 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4642 } else if opcode == OP_PUSHDATA1 {
4643 if i + 1 >= script_sig.len() {
4644 return None;
4645 }
4646 let len = script_sig[i + 1] as usize;
4647 if i + 2 + len > script_sig.len() {
4648 return None;
4649 }
4650 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4651 } else if opcode == OP_PUSHDATA2 {
4652 if i + 2 >= script_sig.len() {
4653 return None;
4654 }
4655 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4656 if i + 3 + len > script_sig.len() {
4657 return None;
4658 }
4659 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4660 } else if opcode == OP_PUSHDATA4 {
4661 if i + 4 >= script_sig.len() {
4662 return None;
4663 }
4664 let len = u32::from_le_bytes([
4665 script_sig[i + 1],
4666 script_sig[i + 2],
4667 script_sig[i + 3],
4668 script_sig[i + 4],
4669 ]) as usize;
4670 if i + 5 + len > script_sig.len() {
4671 return None;
4672 }
4673 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4674 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4675 let n = script_num_from_opcode(opcode);
4677 (1, script_num_encode(n))
4678 } else {
4679 return None;
4680 };
4681 out.push(to_stack_element(&data));
4682 i += advance;
4683 }
4684 Some(out)
4685}
4686
4687fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4691 parse_script_sig_push_only(script_sig)
4692}
4693
4694fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4699 if redeem.len() < 4 {
4700 return None;
4701 }
4702 let n_op = redeem[0];
4703 if !(OP_1..=OP_16).contains(&n_op) {
4704 return None;
4705 }
4706 let n = (n_op - OP_1 + 1) as usize;
4707 let mut i = 1;
4708 let mut pubkeys = Vec::with_capacity(n);
4709 for _ in 0..n {
4710 if i >= redeem.len() {
4711 return None;
4712 }
4713 let first = redeem[i];
4714 let pk_len = if first == 0x02 || first == 0x03 {
4715 33
4716 } else if first == 0x04 {
4717 65
4718 } else {
4719 return None;
4720 };
4721 if i + pk_len > redeem.len() {
4722 return None;
4723 }
4724 pubkeys.push(&redeem[i..i + pk_len]);
4725 i += pk_len;
4726 }
4727 if i + 2 > redeem.len() {
4728 return None;
4729 }
4730 let m_op = redeem[i];
4731 if !(OP_1..=OP_16).contains(&m_op) {
4732 return None;
4733 }
4734 let m = m_op - OP_1 + 1;
4735 if redeem[i + 1] != OP_CHECKMULTISIG {
4736 return None;
4737 }
4738 Some((m, n as u8, pubkeys))
4739}
4740
4741fn script_num_from_opcode(opcode: u8) -> i64 {
4743 match opcode {
4744 OP_1NEGATE => -1,
4745 OP_1 => 1,
4746 OP_2 => 2,
4747 OP_3 => 3,
4748 OP_4 => 4,
4749 OP_5 => 5,
4750 OP_6 => 6,
4751 OP_7 => 7,
4752 OP_8 => 8,
4753 OP_9 => 9,
4754 OP_10 => 10,
4755 OP_11 => 11,
4756 OP_12 => 12,
4757 OP_13 => 13,
4758 OP_14 => 14,
4759 OP_15 => 15,
4760 OP_16 => 16,
4761 _ => 0,
4762 }
4763}
4764
4765pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
4769 let len = data.len();
4770 let mut result = Vec::with_capacity(len + 5);
4771 if len < 76 {
4772 result.push(len as u8);
4773 } else if len < 256 {
4774 result.push(OP_PUSHDATA1);
4775 result.push(len as u8);
4776 } else if len < 65536 {
4777 result.push(OP_PUSHDATA2);
4778 result.push((len & 0xff) as u8);
4779 result.push(((len >> 8) & 0xff) as u8);
4780 } else {
4781 result.push(OP_PUSHDATA4);
4782 result.push((len & 0xff) as u8);
4783 result.push(((len >> 8) & 0xff) as u8);
4784 result.push(((len >> 16) & 0xff) as u8);
4785 result.push(((len >> 24) & 0xff) as u8);
4786 }
4787 result.extend_from_slice(data);
4788 result
4789}
4790
4791#[inline]
4793fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
4794 if pc >= script.len() {
4795 return None;
4796 }
4797 let opcode = script[pc];
4798 let advance = if opcode <= 0x4b {
4799 1 + opcode as usize
4800 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
4801 2 + script[pc + 1] as usize
4802 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
4803 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
4804 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
4805 5 + ((script[pc + 1] as usize)
4806 | ((script[pc + 2] as usize) << 8)
4807 | ((script[pc + 3] as usize) << 16)
4808 | ((script[pc + 4] as usize) << 24))
4809 } else {
4810 1
4811 };
4812 let next = pc + advance;
4813 if next > script.len() {
4814 None
4815 } else {
4816 Some(next)
4817 }
4818}
4819
4820#[spec_locked("5.1.1", "FindAndDelete")]
4826#[inline]
4827pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
4828 if pattern.is_empty() {
4829 return std::borrow::Cow::Borrowed(script);
4830 }
4831 if pattern.len() > script.len() {
4832 return std::borrow::Cow::Borrowed(script);
4833 }
4834 if !script.windows(pattern.len()).any(|w| w == pattern) {
4839 return std::borrow::Cow::Borrowed(script);
4840 }
4841 let end = script.len();
4842 let mut n_found = 0usize;
4843 let mut result = Vec::new();
4844 let mut pc = 0usize;
4845 let mut pc2 = 0usize;
4846
4847 loop {
4848 result.extend_from_slice(&script[pc2..pc]);
4849 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
4850 pc += pattern.len();
4851 n_found += 1;
4852 }
4853 pc2 = pc;
4854 if pc >= end {
4855 break;
4856 }
4857 let Some(next_pc) = script_get_op_advance(script, pc) else {
4858 break;
4859 };
4860 pc = next_pc;
4861 }
4862
4863 if n_found > 0 {
4864 result.extend_from_slice(&script[pc2..end]);
4865 std::borrow::Cow::Owned(result)
4866 } else {
4867 std::borrow::Cow::Borrowed(script)
4868 }
4869}
4870
4871fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
4873 let mut pos = 0u32;
4874 let mut i = 0usize;
4875 while i < script.len() && i <= byte_index {
4876 let opcode = script[i];
4877 let advance = if opcode <= 0x4b {
4878 1 + opcode as usize
4879 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
4880 2 + script[i + 1] as usize
4881 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
4882 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
4883 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
4884 5 + ((script[i + 1] as usize)
4885 | ((script[i + 2] as usize) << 8)
4886 | ((script[i + 3] as usize) << 16)
4887 | ((script[i + 4] as usize) << 24))
4888 } else {
4889 1
4890 };
4891 if i == byte_index {
4892 return pos;
4893 }
4894 pos += 1;
4895 i = std::cmp::min(i + advance, script.len());
4896 }
4897 0xffff_ffff
4898}
4899
4900#[cfg_attr(feature = "production", inline(always))]
4902fn execute_opcode_with_context_full(
4903 opcode: u8,
4904 stack: &mut Vec<StackElement>,
4905 flags: u32,
4906 ctx: &context::ScriptContext<'_>,
4907 effective_script_code: Option<&[u8]>,
4908) -> Result<bool> {
4909 let tx = ctx.tx;
4910 let input_index = ctx.input_index;
4911 let prevout_values = ctx.prevout_values;
4912 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
4913 let block_height = ctx.block_height;
4914 let median_time_past = ctx.median_time_past;
4915 let network = ctx.network;
4916 let sigversion = ctx.sigversion;
4917 let script_sig_for_sighash = ctx.script_sig_for_sighash;
4918 let tapscript_for_sighash = ctx.tapscript_for_sighash;
4919 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
4920 let redeem_script_for_sighash = effective_script_code;
4921 #[cfg(feature = "production")]
4922 let schnorr_collector = ctx.schnorr_collector;
4923 #[cfg(feature = "production")]
4924 let precomputed_bip143 = ctx.precomputed_bip143;
4925 #[cfg(feature = "production")]
4926 let sighash_cache = ctx.sighash_cache;
4927
4928 match opcode {
4930 OP_CHECKSIG => {
4932 if stack.len() >= 2 {
4933 let pubkey_bytes = stack.pop().unwrap();
4934 let signature_bytes = stack.pop().unwrap();
4935
4936 if signature_bytes.is_empty() {
4938 stack.push(to_stack_element(&[0]));
4939 return Ok(true);
4940 }
4941
4942 if sigversion == SigVersion::Tapscript {
4945 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
4947 let sighash_byte = 0x00;
4948 let (tapscript, codesep_pos) = tapscript_for_sighash
4949 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
4950 .unwrap_or((&[] as &[u8], 0xffff_ffff));
4951 let sighash = if tapscript.is_empty() {
4952 crate::taproot::compute_taproot_signature_hash(
4953 tx,
4954 input_index,
4955 prevout_values,
4956 prevout_script_pubkeys,
4957 sighash_byte,
4958 )?
4959 } else {
4960 crate::taproot::compute_tapscript_signature_hash(
4961 tx,
4962 input_index,
4963 prevout_values,
4964 prevout_script_pubkeys,
4965 tapscript,
4966 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
4967 codesep_pos,
4968 sighash_byte,
4969 )?
4970 };
4971
4972 #[cfg(feature = "production")]
4974 let is_valid = {
4975 use crate::bip348::verify_tapscript_schnorr_signature;
4976 verify_tapscript_schnorr_signature(
4977 &sighash,
4978 &pubkey_bytes,
4979 &signature_bytes,
4980 schnorr_collector,
4981 )
4982 .unwrap_or(false)
4983 };
4984
4985 #[cfg(not(feature = "production"))]
4986 let is_valid = {
4987 #[cfg(feature = "csfs")]
4988 let x = {
4989 use crate::bip348::verify_tapscript_schnorr_signature;
4990 verify_tapscript_schnorr_signature(
4991 &sighash,
4992 &pubkey_bytes,
4993 &signature_bytes,
4994 None,
4995 )
4996 .unwrap_or(false)
4997 };
4998 #[cfg(not(feature = "csfs"))]
4999 let x = false;
5000 x
5001 };
5002
5003 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5004 return Ok(true);
5005 }
5006 }
5008
5009 let sig_len = signature_bytes.len();
5013 let sighash_byte = signature_bytes[sig_len - 1];
5014 let _der_sig = &signature_bytes[..sig_len - 1];
5015
5016 let sighash = if sigversion == SigVersion::WitnessV0 {
5020 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5022
5023 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5025 prevout_script_pubkeys
5026 .get(input_index)
5027 .copied()
5028 .unwrap_or(&[])
5029 });
5030
5031 crate::transaction_hash::calculate_bip143_sighash(
5032 tx,
5033 input_index,
5034 script_code,
5035 amount,
5036 sighash_byte,
5037 precomputed_bip143,
5038 )?
5039 } else {
5040 use crate::transaction_hash::{
5042 calculate_transaction_sighash_single_input, SighashType,
5043 };
5044 let sighash_type = SighashType::from_byte(sighash_byte);
5045
5046 let pattern = serialize_push_data(signature_bytes.as_ref());
5050
5051 let base_script = match (
5052 redeem_script_for_sighash,
5053 prevout_script_pubkeys.get(input_index),
5054 ) {
5055 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5056 (Some(redeem), _) => redeem,
5057 (None, Some(prevout)) => *prevout,
5058 (None, None) => &[],
5059 };
5060 let cleaned = find_and_delete(base_script, &pattern);
5061
5062 calculate_transaction_sighash_single_input(
5063 tx,
5064 input_index,
5065 cleaned.as_ref(),
5066 prevout_values[input_index],
5067 sighash_type,
5068 #[cfg(feature = "production")]
5069 sighash_cache,
5070 )?
5071 };
5072
5073 let height = block_height.unwrap_or(0);
5077 #[cfg(feature = "production")]
5078 let is_valid = signature::with_secp_context(|secp| {
5079 signature::verify_signature(
5080 secp,
5081 &pubkey_bytes,
5082 &signature_bytes, &sighash,
5084 flags,
5085 height,
5086 network,
5087 sigversion,
5088 )
5089 })?;
5090
5091 #[cfg(not(feature = "production"))]
5092 let is_valid = {
5093 let secp = signature::new_secp();
5094 signature::verify_signature(
5095 &secp,
5096 &pubkey_bytes,
5097 &signature_bytes, &sighash,
5099 flags,
5100 height,
5101 network,
5102 sigversion,
5103 )?
5104 };
5105
5106 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5107 Ok(true)
5108 } else {
5109 Ok(false)
5110 }
5111 }
5112
5113 OP_CHECKSIGVERIFY => {
5115 if stack.len() >= 2 {
5116 let pubkey_bytes = stack.pop().unwrap();
5117 let signature_bytes = stack.pop().unwrap();
5118
5119 if signature_bytes.is_empty() {
5121 return Ok(false);
5122 }
5123
5124 if sigversion == SigVersion::Tapscript {
5126 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
5127 let sighash_byte = 0x00u8;
5128 let (tapscript, codesep_pos) = tapscript_for_sighash
5129 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5130 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5131 let sighash = if tapscript.is_empty() {
5132 crate::taproot::compute_taproot_signature_hash(
5133 tx,
5134 input_index,
5135 prevout_values,
5136 prevout_script_pubkeys,
5137 sighash_byte,
5138 )?
5139 } else {
5140 crate::taproot::compute_tapscript_signature_hash(
5141 tx,
5142 input_index,
5143 prevout_values,
5144 prevout_script_pubkeys,
5145 tapscript,
5146 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5147 codesep_pos,
5148 sighash_byte,
5149 )?
5150 };
5151 #[cfg(feature = "production")]
5152 let is_valid = {
5153 use crate::bip348::verify_tapscript_schnorr_signature;
5154 verify_tapscript_schnorr_signature(
5155 &sighash,
5156 &pubkey_bytes,
5157 &signature_bytes,
5158 schnorr_collector,
5159 )
5160 .unwrap_or(false)
5161 };
5162 #[cfg(not(feature = "production"))]
5163 let is_valid = {
5164 #[cfg(feature = "csfs")]
5165 let x = {
5166 use crate::bip348::verify_tapscript_schnorr_signature;
5167 verify_tapscript_schnorr_signature(
5168 &sighash,
5169 &pubkey_bytes,
5170 &signature_bytes,
5171 None,
5172 )
5173 .unwrap_or(false)
5174 };
5175 #[cfg(not(feature = "csfs"))]
5176 let x = false;
5177 x
5178 };
5179 if !is_valid {
5180 return Ok(false); }
5182 return Ok(true);
5183 }
5184 return Ok(false);
5186 }
5187
5188 let sig_len = signature_bytes.len();
5191 let sighash_byte = signature_bytes[sig_len - 1];
5192 let _der_sig = &signature_bytes[..sig_len - 1];
5193
5194 let sighash = if sigversion == SigVersion::WitnessV0 {
5198 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5200
5201 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5202 prevout_script_pubkeys
5203 .get(input_index)
5204 .copied()
5205 .unwrap_or(&[])
5206 });
5207
5208 crate::transaction_hash::calculate_bip143_sighash(
5209 tx,
5210 input_index,
5211 script_code,
5212 amount,
5213 sighash_byte,
5214 precomputed_bip143,
5215 )?
5216 } else {
5217 use crate::transaction_hash::{
5219 calculate_transaction_sighash_single_input, SighashType,
5220 };
5221 let sighash_type = SighashType::from_byte(sighash_byte);
5222
5223 let pattern = serialize_push_data(signature_bytes.as_ref());
5225
5226 let base_script = match (
5227 redeem_script_for_sighash,
5228 prevout_script_pubkeys.get(input_index),
5229 ) {
5230 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5231 (Some(redeem), _) => redeem,
5232 (None, Some(prevout)) => *prevout,
5233 (None, None) => &[],
5234 };
5235 let cleaned = find_and_delete(base_script, &pattern);
5236
5237 calculate_transaction_sighash_single_input(
5238 tx,
5239 input_index,
5240 cleaned.as_ref(),
5241 prevout_values[input_index],
5242 sighash_type,
5243 #[cfg(feature = "production")]
5244 sighash_cache,
5245 )?
5246 };
5247
5248 let height = block_height.unwrap_or(0);
5252 #[cfg(feature = "production")]
5253 let is_valid = signature::with_secp_context(|secp| {
5254 signature::verify_signature(
5255 secp,
5256 &pubkey_bytes,
5257 &signature_bytes, &sighash,
5259 flags,
5260 height,
5261 network,
5262 sigversion,
5263 )
5264 })?;
5265
5266 #[cfg(not(feature = "production"))]
5267 let is_valid = {
5268 let secp = signature::new_secp();
5269 signature::verify_signature(
5270 &secp,
5271 &pubkey_bytes,
5272 &signature_bytes, &sighash,
5274 flags,
5275 height,
5276 network,
5277 sigversion,
5278 )?
5279 };
5280
5281 if is_valid {
5282 Ok(true)
5283 } else {
5284 Ok(false)
5285 }
5286 } else {
5287 Ok(false)
5288 }
5289 }
5290
5291 OP_CHECKSIGADD => {
5293 if sigversion != SigVersion::Tapscript {
5294 return Err(ConsensusError::ScriptErrorWithCode {
5295 code: ScriptErrorCode::DisabledOpcode,
5296 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5297 });
5298 }
5299 if stack.len() < 3 {
5300 return Err(ConsensusError::ScriptErrorWithCode {
5301 code: ScriptErrorCode::InvalidStackOperation,
5302 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5303 });
5304 }
5305 let pubkey_bytes = stack.pop().unwrap();
5307 let n_bytes = stack.pop().unwrap();
5308 let signature_bytes = stack.pop().unwrap();
5309 let n = script_num_decode(&n_bytes, 4)?;
5310
5311 if signature_bytes.is_empty() {
5313 stack.push(to_stack_element(&script_num_encode(n)));
5314 return Ok(true);
5315 }
5316
5317 if pubkey_bytes.len() == 32 && signature_bytes.len() == 64 {
5319 let sighash_byte = 0x00;
5320 let (tapscript, codesep_pos) = tapscript_for_sighash
5321 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5322 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5323 let sighash = if tapscript.is_empty() {
5324 crate::taproot::compute_taproot_signature_hash(
5325 tx,
5326 input_index,
5327 prevout_values,
5328 prevout_script_pubkeys,
5329 sighash_byte,
5330 )?
5331 } else {
5332 crate::taproot::compute_tapscript_signature_hash(
5333 tx,
5334 input_index,
5335 prevout_values,
5336 prevout_script_pubkeys,
5337 tapscript,
5338 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5339 codesep_pos,
5340 sighash_byte,
5341 )?
5342 };
5343
5344 #[cfg(feature = "production")]
5345 let is_valid = {
5346 use crate::bip348::verify_tapscript_schnorr_signature;
5347 verify_tapscript_schnorr_signature(
5348 &sighash,
5349 &pubkey_bytes,
5350 &signature_bytes,
5351 schnorr_collector,
5352 )
5353 .unwrap_or(false)
5354 };
5355
5356 #[cfg(not(feature = "production"))]
5357 let is_valid = {
5358 #[cfg(feature = "csfs")]
5359 let x = {
5360 use crate::bip348::verify_tapscript_schnorr_signature;
5361 verify_tapscript_schnorr_signature(
5362 &sighash,
5363 &pubkey_bytes,
5364 &signature_bytes,
5365 None,
5366 )
5367 .unwrap_or(false)
5368 };
5369 #[cfg(not(feature = "csfs"))]
5370 let x = false;
5371 x
5372 };
5373
5374 if !is_valid {
5375 return Ok(false); }
5377 stack.push(to_stack_element(&script_num_encode(n + 1)));
5378 return Ok(true);
5379 }
5380
5381 stack.push(to_stack_element(&script_num_encode(n + 1)));
5383 Ok(true)
5384 }
5385
5386 OP_CHECKMULTISIG => {
5388 if stack.len() < 2 {
5391 return Ok(false);
5392 }
5393
5394 let n_bytes = stack.pop().unwrap();
5396 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
5397 ConsensusError::ScriptErrorWithCode {
5398 code: ScriptErrorCode::InvalidStackOperation,
5399 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
5400 }
5401 })?;
5402 if !(0..=20).contains(&n_raw) {
5403 return Ok(false);
5404 }
5405 let n = n_raw as usize;
5406 if stack.len() < n + 1 {
5407 return Ok(false);
5408 }
5409
5410 let mut pubkeys = Vec::with_capacity(n);
5412 for _ in 0..n {
5413 pubkeys.push(stack.pop().unwrap());
5414 }
5415
5416 let m_bytes = stack.pop().unwrap();
5418 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
5419 ConsensusError::ScriptErrorWithCode {
5420 code: ScriptErrorCode::InvalidStackOperation,
5421 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
5422 }
5423 })?;
5424 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
5425 return Ok(false);
5426 }
5427 let m = m_raw as usize;
5428 if stack.len() < m + 1 {
5429 return Ok(false);
5430 }
5431
5432 let mut signatures = Vec::with_capacity(m);
5434 for _ in 0..m {
5435 signatures.push(stack.pop().unwrap());
5436 }
5437
5438 let dummy = stack.pop().unwrap();
5441 if flags & 0x10 != 0 {
5442 let height = block_height.unwrap_or(0);
5443 use crate::bip_validation::Bip147Network;
5445 let bip147_network = match network {
5446 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5447 crate::types::Network::Testnet => Bip147Network::Testnet,
5448 crate::types::Network::Regtest => Bip147Network::Regtest,
5449 };
5450
5451 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5455
5456 let bip147_active = height
5457 >= match bip147_network {
5458 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5459 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5460 Bip147Network::Regtest => 0,
5461 };
5462
5463 if bip147_active {
5464 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5468 if !is_empty {
5469 return Err(ConsensusError::ScriptErrorWithCode {
5470 code: ScriptErrorCode::SigNullDummy,
5471 message: format!(
5472 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5473 )
5474 .into(),
5475 });
5476 }
5477 }
5478 }
5479
5480 let height = block_height.unwrap_or(0);
5483
5484 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5487 let base_script = match (
5488 redeem_script_for_sighash,
5489 prevout_script_pubkeys.get(input_index),
5490 ) {
5491 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5492 (Some(redeem), _) => redeem,
5493 (None, Some(prevout)) => *prevout,
5494 (None, None) => &[],
5495 };
5496 let mut cleaned = base_script.to_vec();
5497 for sig in &signatures {
5498 if !sig.is_empty() {
5499 let pattern = serialize_push_data(sig.as_ref());
5500 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5501 }
5502 }
5503 cleaned
5504 } else {
5505 redeem_script_for_sighash
5507 .map(|s| s.to_vec())
5508 .unwrap_or_else(|| {
5509 prevout_script_pubkeys
5510 .get(input_index)
5511 .map(|p| p.to_vec())
5512 .unwrap_or_default()
5513 })
5514 };
5515
5516 use crate::transaction_hash::{
5517 calculate_transaction_sighash_single_input, SighashType,
5518 };
5519
5520 #[cfg(feature = "production")]
5522 let use_batch = pubkeys.len() * signatures.len() >= 4;
5523
5524 #[cfg(feature = "production")]
5525 let (valid_sigs, _) = if use_batch {
5526 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5528 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5529 if non_empty.is_empty() {
5530 vec![]
5531 } else {
5532 let specs: Vec<(usize, u8, &[u8])> = non_empty
5533 .iter()
5534 .map(|s| {
5535 (
5536 input_index,
5537 s.as_ref()[s.as_ref().len() - 1],
5538 cleaned_script_for_multisig.as_ref(),
5539 )
5540 })
5541 .collect();
5542 crate::transaction_hash::batch_compute_legacy_sighashes(
5543 tx,
5544 prevout_values,
5545 prevout_script_pubkeys,
5546 &specs,
5547 )?
5548 }
5549 } else {
5550 signatures
5551 .iter()
5552 .filter(|s| !s.is_empty())
5553 .map(|sig_bytes| {
5554 let sighash_type =
5555 SighashType::from_byte(sig_bytes[sig_bytes.len() - 1]);
5556 calculate_transaction_sighash_single_input(
5557 tx,
5558 input_index,
5559 &cleaned_script_for_multisig,
5560 prevout_values[input_index],
5561 sighash_type,
5562 sighash_cache,
5563 )
5564 })
5565 .collect::<Result<Vec<_>>>()?
5566 };
5567
5568 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5570 Vec::with_capacity(pubkeys.len() * signatures.len());
5571 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5572 let mut sighash_idx = 0usize;
5573 for (j, sig_bytes) in signatures.iter().enumerate() {
5574 if sig_bytes.is_empty() {
5575 sig_idx_to_sighash_idx.push(usize::MAX);
5576 } else {
5577 sig_idx_to_sighash_idx.push(sighash_idx);
5578 let sh = sighashes[sighash_idx];
5579 sighash_idx += 1;
5580 for pubkey_bytes in &pubkeys {
5581 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5582 }
5583 }
5584 }
5585
5586 let results = if tasks.is_empty() {
5587 vec![]
5588 } else {
5589 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
5590 };
5591
5592 let mut sig_index = 0;
5594 let mut valid_sigs = 0usize;
5595 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5596 if sig_index >= signatures.len() {
5597 break;
5598 }
5599 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5601 sig_index += 1;
5602 }
5603 if sig_index >= signatures.len() {
5604 break;
5605 }
5606 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5607 if sh_idx == usize::MAX {
5608 continue;
5609 }
5610 let task_idx = sh_idx * pubkeys.len() + i;
5611 if task_idx < results.len() && results[task_idx] {
5612 valid_sigs += 1;
5613 sig_index += 1;
5614 }
5615 }
5616
5617 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5619 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5620 for (j, sig_bytes) in signatures.iter().enumerate() {
5621 if sig_bytes.is_empty() {
5622 continue;
5623 }
5624 let sh_idx = sig_idx_to_sighash_idx[j];
5625 if sh_idx == usize::MAX {
5626 continue;
5627 }
5628 let sig_start = sh_idx * pubkeys.len();
5629 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5630 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5631 if !matched {
5632 return Err(ConsensusError::ScriptErrorWithCode {
5633 code: ScriptErrorCode::SigNullFail,
5634 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5635 });
5636 }
5637 }
5638 }
5639 (valid_sigs, ())
5640 } else {
5641 let mut sig_index = 0;
5642 let mut valid_sigs = 0;
5643
5644 for pubkey_bytes in &pubkeys {
5645 if sig_index >= signatures.len() {
5646 break;
5647 }
5648
5649 let signature_bytes = &signatures[sig_index];
5650
5651 if signature_bytes.is_empty() {
5652 continue;
5653 }
5654
5655 let sig_len = signature_bytes.len();
5656 let sighash_byte = signature_bytes[sig_len - 1];
5657 let sighash_type = SighashType::from_byte(sighash_byte);
5658
5659 let sighash = calculate_transaction_sighash_single_input(
5660 tx,
5661 input_index,
5662 &cleaned_script_for_multisig,
5663 prevout_values[input_index],
5664 sighash_type,
5665 #[cfg(feature = "production")]
5666 sighash_cache,
5667 )?;
5668
5669 #[cfg(feature = "production")]
5670 let is_valid = signature::with_secp_context(|secp| {
5671 signature::verify_signature(
5672 secp,
5673 pubkey_bytes,
5674 signature_bytes,
5675 &sighash,
5676 flags,
5677 height,
5678 network,
5679 sigversion,
5680 )
5681 })?;
5682
5683 #[cfg(not(feature = "production"))]
5684 let is_valid = {
5685 let secp = signature::new_secp();
5686 signature::verify_signature(
5687 &secp,
5688 pubkey_bytes,
5689 signature_bytes,
5690 &sighash,
5691 flags,
5692 height,
5693 network,
5694 sigversion,
5695 )?
5696 };
5697
5698 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5699 if !is_valid
5700 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5701 && !signature_bytes.is_empty()
5702 {
5703 return Err(ConsensusError::ScriptErrorWithCode {
5704 code: ScriptErrorCode::SigNullFail,
5705 message:
5706 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5707 .into(),
5708 });
5709 }
5710
5711 if is_valid {
5712 valid_sigs += 1;
5713 sig_index += 1;
5714 }
5715 }
5716 (valid_sigs, ())
5717 };
5718
5719 #[cfg(not(feature = "production"))]
5720 let (valid_sigs, _) = {
5721 let mut sig_index = 0;
5722 let mut valid_sigs = 0;
5723
5724 for pubkey_bytes in &pubkeys {
5725 if sig_index >= signatures.len() {
5726 break;
5727 }
5728 let signature_bytes = &signatures[sig_index];
5729 if signature_bytes.is_empty() {
5730 continue;
5731 }
5732 let sig_len = signature_bytes.len();
5733 let sighash_type = SighashType::from_byte(signature_bytes[sig_len - 1]);
5734 let sighash = calculate_transaction_sighash_single_input(
5735 tx,
5736 input_index,
5737 &cleaned_script_for_multisig,
5738 prevout_values[input_index],
5739 sighash_type,
5740 #[cfg(feature = "production")]
5741 sighash_cache,
5742 )?;
5743 let secp = signature::new_secp();
5744 let is_valid = signature::verify_signature(
5745 &secp,
5746 pubkey_bytes,
5747 signature_bytes,
5748 &sighash,
5749 flags,
5750 height,
5751 network,
5752 sigversion,
5753 )?;
5754 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5755 if !is_valid
5756 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5757 && !signature_bytes.is_empty()
5758 {
5759 return Err(ConsensusError::ScriptErrorWithCode {
5760 code: ScriptErrorCode::SigNullFail,
5761 message:
5762 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5763 .into(),
5764 });
5765 }
5766 if is_valid {
5767 valid_sigs += 1;
5768 sig_index += 1;
5769 }
5770 }
5771 (valid_sigs, ())
5772 };
5773
5774 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
5776 Ok(true)
5777 }
5778
5779 OP_CHECKMULTISIGVERIFY => {
5781 let ctx_checkmultisig = context::ScriptContext {
5783 tx,
5784 input_index,
5785 prevout_values,
5786 prevout_script_pubkeys,
5787 block_height,
5788 median_time_past,
5789 network,
5790 sigversion,
5791 redeem_script_for_sighash,
5792 script_sig_for_sighash,
5793 tapscript_for_sighash,
5794 tapscript_codesep_pos,
5795 #[cfg(feature = "production")]
5796 schnorr_collector: None,
5797 #[cfg(feature = "production")]
5798 precomputed_bip143,
5799 #[cfg(feature = "production")]
5800 sighash_cache,
5801 };
5802 let result = execute_opcode_with_context_full(
5803 OP_CHECKMULTISIG,
5804 stack,
5805 flags,
5806 &ctx_checkmultisig,
5807 redeem_script_for_sighash,
5808 )?;
5809 if !result {
5810 return Ok(false);
5811 }
5812 if let Some(top) = stack.pop() {
5814 if !cast_to_bool(&top) {
5815 return Ok(false);
5816 }
5817 Ok(true)
5818 } else {
5819 Ok(false)
5820 }
5821 }
5822
5823 OP_CHECKLOCKTIMEVERIFY => {
5828 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
5830 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5831 return Ok(true);
5832 }
5833
5834 use crate::locktime::{check_bip65, decode_locktime_value};
5835
5836 if stack.is_empty() {
5837 return Err(ConsensusError::ScriptErrorWithCode {
5838 code: ScriptErrorCode::InvalidStackOperation,
5839 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
5840 });
5841 }
5842
5843 let locktime_bytes = stack.last().expect("Stack is not empty");
5845 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
5846 Some(v) => v,
5847 None => {
5848 return Err(ConsensusError::ScriptErrorWithCode {
5849 code: ScriptErrorCode::MinimalData,
5850 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
5851 })
5852 }
5853 };
5854
5855 let tx_locktime = tx.lock_time as u32;
5856
5857 if !check_bip65(tx_locktime, locktime_value) {
5859 return Ok(false);
5860 }
5861
5862 let input_seq = if input_index < tx.inputs.len() {
5864 tx.inputs[input_index].sequence
5865 } else {
5866 0xffffffff
5867 };
5868 if input_seq == 0xffffffff {
5869 return Ok(false);
5870 }
5871
5872 Ok(true)
5874 }
5875
5876 OP_CHECKSEQUENCEVERIFY => {
5885 use crate::locktime::{
5886 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
5887 is_sequence_disabled,
5888 };
5889
5890 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
5892 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
5893 return Ok(true);
5894 }
5895
5896 if stack.is_empty() {
5897 return Ok(false);
5898 }
5899
5900 let sequence_bytes = stack.last().expect("Stack is not empty");
5903 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
5904 Some(v) => v,
5905 None => return Ok(false), };
5907
5908 if input_index >= tx.inputs.len() {
5910 return Ok(false);
5911 }
5912 let input_sequence = tx.inputs[input_index].sequence as u32;
5913
5914 if is_sequence_disabled(input_sequence) {
5916 return Ok(true);
5917 }
5918
5919 let type_flag = extract_sequence_type_flag(sequence_value);
5921 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
5922
5923 let input_type_flag = extract_sequence_type_flag(input_sequence);
5925 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
5926
5927 if type_flag != input_type_flag {
5929 return Ok(false);
5930 }
5931
5932 if input_locktime < locktime_mask {
5934 return Ok(false);
5935 }
5936
5937 Ok(true)
5939 }
5940
5941 OP_CHECKTEMPLATEVERIFY => {
5950 #[cfg(not(feature = "ctv"))]
5951 {
5952 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5954 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5955 return Err(ConsensusError::ScriptErrorWithCode {
5956 code: ScriptErrorCode::BadOpcode,
5957 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
5958 });
5959 }
5960 Ok(true) }
5962
5963 #[cfg(feature = "ctv")]
5964 {
5965 use crate::constants::{
5966 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
5967 };
5968
5969 let ctv_activation = match network {
5971 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
5972 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
5973 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
5974 };
5975
5976 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
5977 if !ctv_active {
5978 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5980 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5981 return Err(ConsensusError::ScriptErrorWithCode {
5982 code: ScriptErrorCode::BadOpcode,
5983 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
5984 });
5985 }
5986 return Ok(true); }
5988
5989 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
5991 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
5992 return Ok(true);
5994 }
5995
5996 use crate::bip119::calculate_template_hash;
5997
5998 if stack.is_empty() {
6000 return Err(ConsensusError::ScriptErrorWithCode {
6001 code: ScriptErrorCode::InvalidStackOperation,
6002 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
6003 });
6004 }
6005
6006 let template_hash_bytes = stack.pop().unwrap();
6007
6008 if template_hash_bytes.len() != 32 {
6010 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6013 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6014 return Err(ConsensusError::ScriptErrorWithCode {
6015 code: ScriptErrorCode::InvalidStackOperation,
6016 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
6017 .into(),
6018 });
6019 }
6020 return Ok(true); }
6022
6023 let mut expected_hash = [0u8; 32];
6025 expected_hash.copy_from_slice(&template_hash_bytes);
6026
6027 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
6028 ConsensusError::ScriptErrorWithCode {
6029 code: ScriptErrorCode::TxInvalid,
6030 message: format!("CTV hash calculation failed: {e}").into(),
6031 }
6032 })?;
6033
6034 use crate::crypto::hash_compare::hash_eq;
6036 let matches = hash_eq(&expected_hash, &actual_hash);
6037
6038 if !matches {
6039 return Ok(false); }
6041
6042 Ok(true)
6044 }
6045 }
6046
6047 OP_CHECKSIGFROMSTACK => {
6058 #[cfg(not(feature = "csfs"))]
6059 {
6060 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6063 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6064 return Err(ConsensusError::ScriptErrorWithCode {
6065 code: ScriptErrorCode::BadOpcode,
6066 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
6067 });
6068 }
6069 Ok(true) }
6071
6072 #[cfg(feature = "csfs")]
6073 {
6074 use crate::constants::{
6075 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
6076 };
6077
6078 if sigversion != SigVersion::Tapscript {
6080 return Err(ConsensusError::ScriptErrorWithCode {
6081 code: ScriptErrorCode::BadOpcode,
6082 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
6083 });
6084 }
6085
6086 let csfs_activation = match network {
6088 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
6089 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
6090 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
6091 };
6092
6093 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
6094 if !csfs_active {
6095 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6097 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6098 return Err(ConsensusError::ScriptErrorWithCode {
6099 code: ScriptErrorCode::BadOpcode,
6100 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
6101 });
6102 }
6103 return Ok(true); }
6105
6106 use crate::bip348::verify_signature_from_stack;
6107
6108 if stack.len() < 3 {
6110 return Err(ConsensusError::ScriptErrorWithCode {
6111 code: ScriptErrorCode::InvalidStackOperation,
6112 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
6113 });
6114 }
6115
6116 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
6123 return Err(ConsensusError::ScriptErrorWithCode {
6124 code: ScriptErrorCode::PubkeyType,
6125 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
6126 });
6127 }
6128
6129 if signature_bytes.is_empty() {
6131 stack.push(to_stack_element(&[])); return Ok(true);
6133 }
6134
6135 #[cfg(feature = "production")]
6138 let is_valid = {
6139 verify_signature_from_stack(
6140 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6145 .unwrap_or(false)
6146 };
6147 #[cfg(not(feature = "production"))]
6148 let is_valid = verify_signature_from_stack(
6149 &message_bytes, &pubkey_bytes, &signature_bytes, )
6153 .unwrap_or(false);
6154
6155 if !is_valid {
6156 return Ok(false);
6158 }
6159
6160 stack.push(to_stack_element(&[0x01])); Ok(true)
6167 }
6168 }
6169
6170 _ => execute_opcode_cold(opcode, stack, flags),
6172 }
6173}
6174
6175#[cold]
6177fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6178 execute_opcode(opcode, stack, flags, SigVersion::Base)
6179}
6180
6181#[cfg(feature = "production")]
6196pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6197 (
6198 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6199 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6200 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6201 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6202 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6203 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6204 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6205 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6206 )
6207}
6208
6209#[cfg(all(feature = "production", feature = "benchmarking"))]
6216pub fn clear_script_cache() {
6217 if let Some(cache) = SCRIPT_CACHE.get() {
6218 let mut cache = cache.write().unwrap();
6219 cache.clear();
6220 }
6221}
6222
6223#[cfg(all(feature = "production", feature = "benchmarking"))]
6237pub fn clear_hash_cache() {
6238 crypto_ops::clear_hash_cache();
6239}
6240
6241#[cfg(all(feature = "production", feature = "benchmarking"))]
6254pub fn clear_all_caches() {
6255 clear_script_cache();
6256 clear_hash_cache();
6257}
6258
6259#[cfg(all(feature = "production", feature = "benchmarking"))]
6273pub fn clear_stack_pool() {
6274 STACK_POOL.with(|pool| {
6275 let mut pool = pool.borrow_mut();
6276 pool.clear();
6277 });
6278}
6279
6280#[cfg(all(feature = "production", feature = "benchmarking"))]
6294pub fn reset_benchmarking_state() {
6295 clear_all_caches();
6296 clear_stack_pool();
6297 disable_caching(false); #[cfg(feature = "benchmarking")]
6300 crate::transaction_hash::clear_sighash_templates();
6301}
6302
6303#[cfg(test)]
6304mod tests {
6305 use super::*;
6306
6307 #[test]
6308 fn test_eval_script_simple() {
6309 let script = vec![OP_1]; let mut stack = Vec::new();
6311
6312 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6313 assert_eq!(stack.len(), 1);
6314 assert_eq!(stack[0].as_ref(), &[1]);
6315 }
6316
6317 #[test]
6318 fn test_eval_script_overflow() {
6319 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6321
6322 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6323 }
6324
6325 #[test]
6326 fn test_verify_script_simple() {
6327 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());
6338 }
6339
6340 #[test]
6345 fn test_op_0() {
6346 let script = vec![OP_0]; let mut stack = Vec::new();
6348 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6349 assert!(!result); assert_eq!(stack.len(), 1);
6351 assert!(stack[0].is_empty());
6352 }
6353
6354 #[test]
6355 fn test_op_1_to_op_16() {
6356 for i in 1..=16 {
6358 let opcode = 0x50 + i;
6359 let script = vec![opcode];
6360 let mut stack = Vec::new();
6361 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6362 assert!(result);
6363 assert_eq!(stack.len(), 1);
6364 assert_eq!(stack[0].as_ref(), &[i]);
6365 }
6366 }
6367
6368 #[test]
6369 fn test_op_dup() {
6370 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6372 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6373 assert!(!result); assert_eq!(stack.len(), 2);
6375 assert_eq!(stack[0].as_ref(), &[1]);
6376 assert_eq!(stack[1].as_ref(), &[1]);
6377 }
6378
6379 #[test]
6380 fn test_op_dup_empty_stack() {
6381 let script = vec![OP_DUP]; let mut stack = Vec::new();
6383 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6384 assert!(!result);
6385 }
6386
6387 #[test]
6388 fn test_op_hash160() {
6389 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6391 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6392 assert!(result);
6393 assert_eq!(stack.len(), 1);
6394 assert_eq!(stack[0].len(), 20); }
6396
6397 #[test]
6398 fn test_op_hash160_empty_stack() {
6399 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6401 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6402 assert!(!result);
6403 }
6404
6405 #[test]
6406 fn test_op_hash256() {
6407 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6409 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6410 assert!(result);
6411 assert_eq!(stack.len(), 1);
6412 assert_eq!(stack[0].len(), 32); }
6414
6415 #[test]
6416 fn test_op_hash256_empty_stack() {
6417 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6419 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6420 assert!(!result);
6421 }
6422
6423 #[test]
6424 fn test_op_equal() {
6425 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6427 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6428 assert!(result);
6429 assert_eq!(stack.len(), 1);
6430 assert_eq!(stack[0].as_ref(), &[1]); }
6432
6433 #[test]
6434 fn test_op_equal_false() {
6435 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6437 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6438 assert!(!result); assert_eq!(stack.len(), 1);
6440 assert_eq!(stack[0].as_ref(), &[0]); }
6442
6443 #[test]
6444 fn test_op_equal_insufficient_stack() {
6445 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6447 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6448 assert!(
6449 result.is_err(),
6450 "OP_EQUAL with insufficient stack should return error"
6451 );
6452 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6453 assert_eq!(
6454 code,
6455 crate::error::ScriptErrorCode::InvalidStackOperation,
6456 "Should return InvalidStackOperation"
6457 );
6458 }
6459 }
6460
6461 #[test]
6462 fn test_op_verify() {
6463 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6465 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6466 assert!(!result); assert_eq!(stack.len(), 0); }
6469
6470 #[test]
6471 fn test_op_verify_false() {
6472 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6474 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6475 assert!(!result);
6476 }
6477
6478 #[test]
6479 fn test_op_verify_empty_stack() {
6480 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6482 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6483 assert!(!result);
6484 }
6485
6486 #[test]
6487 fn test_op_equalverify() {
6488 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6490 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6491 assert!(!result); assert_eq!(stack.len(), 0); }
6494
6495 #[test]
6496 fn test_op_equalverify_false() {
6497 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6499 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6500 assert!(
6501 result.is_err(),
6502 "OP_EQUALVERIFY with false condition should return error"
6503 );
6504 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6505 assert_eq!(
6506 code,
6507 crate::error::ScriptErrorCode::EqualVerify,
6508 "Should return EqualVerify"
6509 );
6510 }
6511 }
6512
6513 #[test]
6514 fn test_op_checksig() {
6515 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6519 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6520 assert!(!result); assert_eq!(stack.len(), 1);
6522 }
6524
6525 #[test]
6526 fn test_op_checksig_insufficient_stack() {
6527 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6529 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6530 assert!(
6531 result.is_err(),
6532 "OP_CHECKSIG with insufficient stack should return error"
6533 );
6534 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6535 assert_eq!(
6536 code,
6537 crate::error::ScriptErrorCode::InvalidStackOperation,
6538 "Should return InvalidStackOperation"
6539 );
6540 }
6541 }
6542
6543 #[test]
6544 fn test_unknown_opcode() {
6545 let script = vec![0xff]; let mut stack = Vec::new();
6547 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6548 assert!(!result);
6549 }
6550
6551 #[test]
6552 fn test_script_size_limit() {
6553 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6555 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6556 assert!(result.is_err());
6557 }
6558
6559 #[test]
6560 fn test_operation_count_limit() {
6561 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6564 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6565 assert!(result.is_err());
6566 }
6567
6568 #[test]
6569 fn test_stack_underflow_multiple_ops() {
6570 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6572 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6573 assert!(result.is_err(), "Stack underflow should return error");
6574 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6575 assert_eq!(
6576 code,
6577 crate::error::ScriptErrorCode::InvalidStackOperation,
6578 "Should return InvalidStackOperation"
6579 );
6580 }
6581 }
6582
6583 #[test]
6584 fn test_final_stack_empty() {
6585 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6587 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6588 assert!(!result);
6589 }
6590
6591 #[test]
6592 fn test_final_stack_false() {
6593 let script = vec![OP_0]; let mut stack = Vec::new();
6595 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6596 assert!(!result);
6597 }
6598
6599 #[test]
6600 fn test_verify_script_with_witness() {
6601 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6605
6606 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6607 assert!(!result); }
6609
6610 #[test]
6611 fn test_verify_script_failure() {
6612 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_2]; let witness = None;
6615 let flags = 0;
6616
6617 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6618 assert!(!result);
6619 }
6620
6621 #[test]
6626 fn test_op_ifdup_true() {
6627 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6629 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6630 assert!(!result); assert_eq!(stack.len(), 2);
6632 assert_eq!(stack[0].as_ref(), &[1]);
6633 assert_eq!(stack[1].as_ref(), &[1]);
6634 }
6635
6636 #[test]
6637 fn test_op_ifdup_false() {
6638 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6640 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6641 assert!(!result); assert_eq!(stack.len(), 1);
6643 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6644 }
6645
6646 #[test]
6647 fn test_op_depth() {
6648 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6650 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6651 assert!(!result); assert_eq!(stack.len(), 3);
6653 assert_eq!(stack[2].as_ref(), &[2]); }
6655
6656 #[test]
6657 fn test_op_drop() {
6658 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
6660 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6661 assert!(result); assert_eq!(stack.len(), 1);
6663 assert_eq!(stack[0].as_ref(), &[1]);
6664 }
6665
6666 #[test]
6667 fn test_op_drop_empty_stack() {
6668 let script = vec![OP_DROP]; let mut stack = Vec::new();
6670 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6671 assert!(!result);
6672 assert_eq!(stack.len(), 0);
6673 }
6674
6675 #[test]
6676 fn test_op_nip() {
6677 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
6679 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6680 assert!(result); assert_eq!(stack.len(), 1);
6682 assert_eq!(stack[0].as_ref(), &[2]);
6683 }
6684
6685 #[test]
6686 fn test_op_nip_insufficient_stack() {
6687 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
6689 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6690 assert!(!result);
6691 assert_eq!(stack.len(), 1);
6692 }
6693
6694 #[test]
6695 fn test_op_over() {
6696 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
6698 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6699 assert!(!result); assert_eq!(stack.len(), 3);
6701 assert_eq!(stack[0].as_ref(), &[1]);
6702 assert_eq!(stack[1].as_ref(), &[2]);
6703 assert_eq!(stack[2].as_ref(), &[1]);
6704 }
6705
6706 #[test]
6707 fn test_op_over_insufficient_stack() {
6708 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
6710 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6711 assert!(!result);
6712 assert_eq!(stack.len(), 1);
6713 }
6714
6715 #[test]
6716 fn test_op_pick() {
6717 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
6719 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6720 assert!(!result); assert_eq!(stack.len(), 4);
6722 assert_eq!(stack[3].as_ref(), &[2]); }
6724
6725 #[test]
6726 fn test_op_pick_empty_n() {
6727 let script = vec![OP_1, OP_0, OP_PICK];
6729 let mut stack = Vec::new();
6730 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6731 assert!(!result); assert_eq!(stack.len(), 2);
6733 assert_eq!(stack[1].as_ref(), &[1]); }
6735
6736 #[test]
6737 fn test_op_pick_invalid_index() {
6738 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
6740 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6741 assert!(!result);
6742 assert_eq!(stack.len(), 1);
6743 }
6744
6745 #[test]
6746 fn test_op_roll() {
6747 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
6749 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6750 assert!(!result); assert_eq!(stack.len(), 3);
6752 assert_eq!(stack[0].as_ref(), &[1]);
6753 assert_eq!(stack[1].as_ref(), &[3]);
6754 assert_eq!(stack[2].as_ref(), &[2]); }
6756
6757 #[test]
6758 fn test_op_roll_zero_n() {
6759 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
6762 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6763 assert!(result); assert_eq!(stack.len(), 1);
6765 assert_eq!(stack[0].as_ref(), &[1]);
6766 }
6767
6768 #[test]
6769 fn test_op_roll_invalid_index() {
6770 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
6772 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6773 assert!(!result);
6774 assert_eq!(stack.len(), 1);
6775 }
6776
6777 #[test]
6778 fn test_op_rot() {
6779 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
6781 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6782 assert!(!result); assert_eq!(stack.len(), 3);
6784 assert_eq!(stack[0].as_ref(), &[2]);
6785 assert_eq!(stack[1].as_ref(), &[3]);
6786 assert_eq!(stack[2].as_ref(), &[1]);
6787 }
6788
6789 #[test]
6790 fn test_op_rot_insufficient_stack() {
6791 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
6793 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6794 assert!(!result);
6795 assert_eq!(stack.len(), 2);
6796 }
6797
6798 #[test]
6799 fn test_op_swap() {
6800 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
6802 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6803 assert!(!result); assert_eq!(stack.len(), 2);
6805 assert_eq!(stack[0].as_ref(), &[2]);
6806 assert_eq!(stack[1].as_ref(), &[1]);
6807 }
6808
6809 #[test]
6810 fn test_op_swap_insufficient_stack() {
6811 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
6813 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6814 assert!(!result);
6815 assert_eq!(stack.len(), 1);
6816 }
6817
6818 #[test]
6819 fn test_op_tuck() {
6820 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
6822 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6823 assert!(!result); assert_eq!(stack.len(), 3);
6825 assert_eq!(stack[0].as_ref(), &[2]);
6826 assert_eq!(stack[1].as_ref(), &[1]);
6827 assert_eq!(stack[2].as_ref(), &[2]);
6828 }
6829
6830 #[test]
6831 fn test_op_tuck_insufficient_stack() {
6832 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
6834 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6835 assert!(!result);
6836 assert_eq!(stack.len(), 1);
6837 }
6838
6839 #[test]
6840 fn test_op_2drop() {
6841 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
6843 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6844 assert!(result); assert_eq!(stack.len(), 1);
6846 assert_eq!(stack[0].as_ref(), &[1]);
6847 }
6848
6849 #[test]
6850 fn test_op_2drop_insufficient_stack() {
6851 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
6853 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6854 assert!(!result);
6855 assert_eq!(stack.len(), 1);
6856 }
6857
6858 #[test]
6859 fn test_op_2dup() {
6860 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
6862 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6863 assert!(!result); assert_eq!(stack.len(), 4);
6865 assert_eq!(stack[0].as_ref(), &[1]);
6866 assert_eq!(stack[1].as_ref(), &[2]);
6867 assert_eq!(stack[2].as_ref(), &[1]);
6868 assert_eq!(stack[3].as_ref(), &[2]);
6869 }
6870
6871 #[test]
6872 fn test_op_2dup_insufficient_stack() {
6873 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
6875 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6876 assert!(!result);
6877 assert_eq!(stack.len(), 1);
6878 }
6879
6880 #[test]
6881 fn test_op_3dup() {
6882 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
6884 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6885 assert!(!result); assert_eq!(stack.len(), 6);
6887 assert_eq!(stack[0].as_ref(), &[1]);
6888 assert_eq!(stack[1].as_ref(), &[2]);
6889 assert_eq!(stack[2].as_ref(), &[3]);
6890 assert_eq!(stack[3].as_ref(), &[1]);
6891 assert_eq!(stack[4].as_ref(), &[2]);
6892 assert_eq!(stack[5].as_ref(), &[3]);
6893 }
6894
6895 #[test]
6896 fn test_op_3dup_insufficient_stack() {
6897 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
6899 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6900 assert!(!result);
6901 assert_eq!(stack.len(), 2);
6902 }
6903
6904 #[test]
6905 fn test_op_2over() {
6906 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
6908 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6909 assert!(!result); assert_eq!(stack.len(), 6);
6911 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
6913 }
6914
6915 #[test]
6916 fn test_op_2over_insufficient_stack() {
6917 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
6919 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6920 assert!(!result);
6921 assert_eq!(stack.len(), 3);
6922 }
6923
6924 #[test]
6925 fn test_op_2rot() {
6926 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
6928 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6929 assert!(!result); assert_eq!(stack.len(), 6);
6931 assert_eq!(stack[4].as_ref(), &[2]); assert_eq!(stack[5].as_ref(), &[1]);
6933 }
6934
6935 #[test]
6936 fn test_op_2rot_insufficient_stack() {
6937 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
6939 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6940 assert!(!result);
6941 assert_eq!(stack.len(), 4);
6942 }
6943
6944 #[test]
6945 fn test_op_2swap() {
6946 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
6948 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6949 assert!(!result); assert_eq!(stack.len(), 4);
6951 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
6953 assert_eq!(stack[2].as_ref(), &[1]);
6954 assert_eq!(stack[3].as_ref(), &[2]);
6955 }
6956
6957 #[test]
6958 fn test_op_2swap_insufficient_stack() {
6959 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
6961 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6962 assert!(!result);
6963 assert_eq!(stack.len(), 3);
6964 }
6965
6966 #[test]
6967 fn test_op_size() {
6968 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
6970 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6971 assert!(!result); assert_eq!(stack.len(), 2);
6973 assert_eq!(stack[0].as_ref(), &[1]);
6974 assert_eq!(stack[1].as_ref(), &[1]); }
6976
6977 #[test]
6978 fn test_op_size_empty_stack() {
6979 let script = vec![OP_SIZE]; let mut stack = Vec::new();
6981 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6982 assert!(!result);
6983 assert_eq!(stack.len(), 0);
6984 }
6985
6986 #[test]
6987 fn test_op_return() {
6988 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
6990 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6991 assert!(!result); assert_eq!(stack.len(), 1);
6993 }
6994
6995 #[test]
6996 fn test_op_checksigverify() {
6997 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6999 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7000 assert!(!result); assert_eq!(stack.len(), 0);
7002 }
7003
7004 #[test]
7005 fn test_op_checksigverify_insufficient_stack() {
7006 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7008 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7009 assert!(!result);
7010 assert_eq!(stack.len(), 1);
7011 }
7012
7013 #[test]
7014 fn test_unknown_opcode_comprehensive() {
7015 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
7017 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7018 assert!(!result); assert_eq!(stack.len(), 1);
7020 }
7021
7022 #[test]
7023 fn test_verify_signature_invalid_pubkey() {
7024 let secp = signature::new_secp();
7025 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
7028 let result = signature::verify_signature(
7029 &secp,
7030 &invalid_pubkey,
7031 &signature,
7032 &dummy_hash,
7033 0,
7034 0,
7035 crate::types::Network::Regtest,
7036 SigVersion::Base,
7037 );
7038 assert!(!result.unwrap_or(false));
7039 }
7040
7041 #[test]
7042 fn test_verify_signature_invalid_signature() {
7043 let secp = signature::new_secp();
7044 let pubkey = vec![
7045 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
7046 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
7047 0x5b, 0x16, 0xf8, 0x17, 0x98,
7048 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
7051 let result = signature::verify_signature(
7052 &secp,
7053 &pubkey,
7054 &invalid_signature,
7055 &dummy_hash,
7056 0,
7057 0,
7058 crate::types::Network::Regtest,
7059 SigVersion::Base,
7060 );
7061 assert!(!result.unwrap_or(false));
7062 }
7063
7064 fn minimal_tx_and_prevouts(
7070 script_sig: &[u8],
7071 script_pubkey: &[u8],
7072 ) -> (
7073 crate::types::Transaction,
7074 Vec<i64>,
7075 Vec<crate::types::ByteString>,
7076 ) {
7077 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
7078 let tx = Transaction {
7079 version: 1,
7080 inputs: vec![TransactionInput {
7081 prevout: OutPoint {
7082 hash: [0u8; 32],
7083 index: 0,
7084 },
7085 sequence: 0xffff_ffff,
7086 script_sig: script_sig.to_vec(),
7087 }]
7088 .into(),
7089 outputs: vec![TransactionOutput {
7090 value: 0,
7091 script_pubkey: script_pubkey.to_vec(),
7092 }]
7093 .into(),
7094 lock_time: 0,
7095 };
7096 let prevout_values = vec![0i64];
7097 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
7098 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
7099 (tx, prevout_values, prevout_script_pubkeys_vec)
7100 }
7101
7102 #[test]
7103 fn test_verify_with_context_p2pkh_hash_mismatch() {
7104 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
7108 script_sig.push(sig.len() as u8);
7109 script_sig.extend(&sig);
7110 script_sig.push(pubkey.len() as u8);
7111 script_sig.extend(&pubkey);
7112
7113 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
7114 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
7116 script_pubkey.push(OP_CHECKSIG);
7117
7118 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7119 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7120 let result = verify_script_with_context_full(
7121 &script_sig,
7122 &script_pubkey,
7123 None,
7124 0,
7125 &tx,
7126 0,
7127 &pv,
7128 &psp_refs,
7129 Some(500_000),
7130 None,
7131 crate::types::Network::Mainnet,
7132 SigVersion::Base,
7133 #[cfg(feature = "production")]
7134 None,
7135 None, #[cfg(feature = "production")]
7137 None,
7138 #[cfg(feature = "production")]
7139 None,
7140 #[cfg(feature = "production")]
7141 None,
7142 );
7143 assert!(result.is_ok());
7144 assert!(!result.unwrap());
7145 }
7146
7147 #[test]
7148 fn test_verify_with_context_p2sh_hash_mismatch() {
7149 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7152 script_sig.push(redeem.len() as u8);
7153 script_sig.extend(&redeem);
7154
7155 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7156 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7158
7159 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7160 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7161 let result = verify_script_with_context_full(
7162 &script_sig,
7163 &script_pubkey,
7164 None,
7165 0x01, &tx,
7167 0,
7168 &pv,
7169 &psp_refs,
7170 Some(500_000),
7171 None,
7172 crate::types::Network::Mainnet,
7173 SigVersion::Base,
7174 #[cfg(feature = "production")]
7175 None,
7176 None, #[cfg(feature = "production")]
7178 None,
7179 #[cfg(feature = "production")]
7180 None,
7181 #[cfg(feature = "production")]
7182 None,
7183 );
7184 assert!(result.is_ok());
7185 assert!(!result.unwrap());
7186 }
7187
7188 #[test]
7189 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7190 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7192 script_pubkey.extend(&[0u8; 20]);
7193 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7195 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7196 let empty: Vec<u8> = vec![];
7197 let result = verify_script_with_context_full(
7198 &empty,
7199 &script_pubkey,
7200 Some(&witness),
7201 0,
7202 &tx,
7203 0,
7204 &pv,
7205 &psp_refs,
7206 Some(500_000),
7207 None,
7208 crate::types::Network::Mainnet,
7209 SigVersion::Base,
7210 #[cfg(feature = "production")]
7211 None,
7212 None, #[cfg(feature = "production")]
7214 None,
7215 #[cfg(feature = "production")]
7216 None,
7217 #[cfg(feature = "production")]
7218 None,
7219 );
7220 assert!(result.is_ok());
7221 assert!(!result.unwrap());
7222 }
7223
7224 #[test]
7225 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7226 let witness_script = vec![OP_1];
7228 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7229 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7231 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7232 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7233 let empty: Vec<u8> = vec![];
7234 let result = verify_script_with_context_full(
7235 &empty,
7236 &script_pubkey,
7237 Some(&witness),
7238 0,
7239 &tx,
7240 0,
7241 &pv,
7242 &psp_refs,
7243 Some(500_000),
7244 None,
7245 crate::types::Network::Mainnet,
7246 SigVersion::Base,
7247 #[cfg(feature = "production")]
7248 None,
7249 None, #[cfg(feature = "production")]
7251 None,
7252 #[cfg(feature = "production")]
7253 None,
7254 #[cfg(feature = "production")]
7255 None,
7256 );
7257 assert!(result.is_ok());
7258 assert!(!result.unwrap());
7259 }
7260
7261 #[test]
7262 #[cfg(feature = "production")]
7263 fn test_p2wsh_multisig_fast_path() {
7264 use crate::constants::BIP147_ACTIVATION_MAINNET;
7266 use crate::crypto::OptimizedSha256;
7267
7268 let pk1 = [0x02u8; 33];
7269 let pk2 = [0x03u8; 33];
7270 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7272 witness_script.extend_from_slice(&pk2);
7273 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7277 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7278 script_pubkey.extend_from_slice(&wsh_hash);
7279
7280 let witness: Vec<Vec<u8>> = vec![
7281 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7285 ];
7286
7287 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7288 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7289 let empty: Vec<u8> = vec![];
7290 let result = verify_script_with_context_full(
7291 &empty,
7292 &script_pubkey,
7293 Some(&witness),
7294 0x810, &tx,
7296 0,
7297 &pv,
7298 &psp_refs,
7299 Some(BIP147_ACTIVATION_MAINNET + 1),
7300 None,
7301 crate::types::Network::Mainnet,
7302 SigVersion::Base,
7303 #[cfg(feature = "production")]
7304 None,
7305 None, #[cfg(feature = "production")]
7307 None,
7308 #[cfg(feature = "production")]
7309 None,
7310 #[cfg(feature = "production")]
7311 None,
7312 );
7313 assert!(result.is_ok());
7314 assert!(!result.unwrap());
7315 }
7316}
7317
7318#[cfg(test)]
7319#[allow(unused_doc_comments)]
7320mod property_tests {
7321 use super::*;
7322 use proptest::prelude::*;
7323
7324 proptest! {
7329 #[test]
7330 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7331 let mut stack = Vec::new();
7332 let flags = 0u32;
7333
7334 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7335
7336 if script.len() > MAX_SCRIPT_OPS * 2 {
7344 prop_assert!(result.is_err() || !result.unwrap(),
7347 "Very long scripts should fail or return false");
7348 }
7349 }
7351 }
7352
7353 proptest! {
7358 #[test]
7359 fn prop_verify_script_deterministic(
7360 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7361 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7362 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7363 flags in any::<u32>()
7364 ) {
7365 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7366 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7367
7368 assert_eq!(result1.is_ok(), result2.is_ok());
7369 if result1.is_ok() && result2.is_ok() {
7370 assert_eq!(result1.unwrap(), result2.unwrap());
7371 }
7372 }
7373 }
7374
7375 proptest! {
7380 #[test]
7381 fn prop_execute_opcode_no_panic(
7382 opcode in any::<u8>(),
7383 stack_items in prop::collection::vec(
7384 prop::collection::vec(any::<u8>(), 0..5),
7385 0..10
7386 ),
7387 flags in any::<u32>()
7388 ) {
7389 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7390 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7391
7392 match result {
7395 Ok(success) => {
7396 let _ = success;
7398 },
7399 Err(_) => {
7400 }
7403 }
7404
7405 assert!(stack.len() <= MAX_STACK_SIZE);
7407 }
7408 }
7409
7410 proptest! {
7417 #[test]
7418 fn prop_stack_operations_bounds(
7419 opcode in any::<u8>(),
7420 stack_items in prop::collection::vec(
7421 prop::collection::vec(any::<u8>(), 0..3),
7422 0..5
7423 ),
7424 flags in any::<u32>()
7425 ) {
7426 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7427 let initial_len = stack.len();
7428
7429 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7430
7431 assert!(stack.len() <= MAX_STACK_SIZE);
7433
7434 if result.is_ok() && result.unwrap() {
7436 match opcode {
7438 OP_0 | OP_1..=OP_16 => {
7439 assert!(stack.len() == initial_len + 1);
7441 },
7442 OP_DUP => {
7443 if initial_len > 0 {
7445 assert!(stack.len() == initial_len + 1);
7446 }
7447 },
7448 OP_3DUP => {
7449 if initial_len >= 3 {
7451 assert!(stack.len() == initial_len + 3);
7452 }
7453 },
7454 OP_2OVER => {
7455 if initial_len >= 4 {
7457 assert!(stack.len() == initial_len + 2);
7458 }
7459 },
7460 OP_DROP | OP_NIP | OP_2DROP => {
7461 assert!(stack.len() <= initial_len);
7463 },
7464 _ => {
7465 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7468 }
7469 }
7470 }
7471 }
7472 }
7473
7474 proptest! {
7479 #[test]
7480 fn prop_hash_operations_deterministic(
7481 input in prop::collection::vec(any::<u8>(), 0..10)
7482 ) {
7483 let elem = to_stack_element(&input);
7484 let mut stack1 = vec![elem.clone()];
7485 let mut stack2 = vec![elem];
7486
7487 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());
7491 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7492 assert_eq!(val1, val2);
7493 if val1 {
7494 assert_eq!(stack1, stack2);
7495 }
7496 }
7497 }
7498 }
7499
7500 proptest! {
7505 #[test]
7506 fn prop_equality_operations_symmetric(
7507 a in prop::collection::vec(any::<u8>(), 0..5),
7508 b in prop::collection::vec(any::<u8>(), 0..5)
7509 ) {
7510 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7511 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7512
7513 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());
7517 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7518 assert_eq!(val1, val2);
7519 if val1 {
7520 assert_eq!(stack1.len(), stack2.len());
7522 if !stack1.is_empty() && !stack2.is_empty() {
7523 assert_eq!(stack1[0], stack2[0]);
7524 }
7525 }
7526 }
7527 }
7528 }
7529
7530 proptest! {
7535 #[test]
7536 fn prop_script_execution_terminates(
7537 script in prop::collection::vec(any::<u8>(), 0..50)
7538 ) {
7539 let mut stack = Vec::new();
7540 let flags = 0u32;
7541
7542 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7544
7545 assert!(result.is_ok() || result.is_err());
7547
7548 assert!(stack.len() <= MAX_STACK_SIZE);
7550 }
7551 }
7552}