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