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#[blvm_spec_lock::axiom(result >= -549755813887)]
3793#[blvm_spec_lock::ensures(result >= -549755813887)]
3794#[cfg(feature = "production")]
3795#[inline(always)]
3796pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3797 if data.len() > max_num_size {
3798 return Err(ConsensusError::ScriptErrorWithCode {
3799 code: ScriptErrorCode::InvalidStackOperation,
3800 message: format!(
3801 "Script number overflow: {} > {} bytes",
3802 data.len(),
3803 max_num_size
3804 )
3805 .into(),
3806 });
3807 }
3808 if data.is_empty() {
3809 return Ok(0);
3810 }
3811
3812 let len = data.len();
3814 let result = match len {
3815 1 => {
3816 let byte = data[0];
3817 if byte & 0x80 != 0 {
3818 -((byte & 0x7f) as i64)
3820 } else {
3821 byte as i64
3822 }
3823 }
3824 2 => {
3825 let byte0 = data[0] as i64;
3826 let byte1 = data[1] as i64;
3827 let value = byte0 | (byte1 << 8);
3828 if byte1 & 0x80 != 0 {
3829 -(value & !(0x80i64 << 8))
3831 } else {
3832 value
3833 }
3834 }
3835 _ => {
3836 let mut result: i64 = 0;
3838 for (i, &byte) in data.iter().enumerate() {
3839 result |= (byte as i64) << (8 * i);
3840 }
3841 let last_idx = len - 1;
3843 if data[last_idx] & 0x80 != 0 {
3844 result &= !(0x80i64 << (8 * last_idx));
3846 result = -result;
3847 }
3848 result
3849 }
3850 };
3851
3852 Ok(result)
3853}
3854
3855#[cfg(not(feature = "production"))]
3856#[inline]
3857pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3858 if data.len() > max_num_size {
3859 return Err(ConsensusError::ScriptErrorWithCode {
3860 code: ScriptErrorCode::InvalidStackOperation,
3861 message: format!(
3862 "Script number overflow: {} > {} bytes",
3863 data.len(),
3864 max_num_size
3865 )
3866 .into(),
3867 });
3868 }
3869 if data.is_empty() {
3870 return Ok(0);
3871 }
3872 let mut result: i64 = 0;
3874 for (i, &byte) in data.iter().enumerate() {
3875 result |= (byte as i64) << (8 * i);
3876 }
3877 if data.last().expect("Data is not empty") & 0x80 != 0 {
3879 result &= !(0x80i64 << (8 * (data.len() - 1)));
3881 result = -result;
3882 }
3883 Ok(result)
3884}
3885
3886#[cfg(feature = "production")]
3889pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3890 match value {
3892 0 => return vec![],
3893 1 => return vec![1],
3894 -1 => return vec![0x81],
3895 _ => {}
3896 }
3897
3898 let neg = value < 0;
3899 let mut absvalue = if neg {
3900 (-(value as i128)) as u64
3901 } else {
3902 value as u64
3903 };
3904 let mut result = Vec::with_capacity(4);
3906 while absvalue > 0 {
3907 result.push((absvalue & 0xff) as u8);
3908 absvalue >>= 8;
3909 }
3910 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3912 result.push(if neg { 0x80 } else { 0x00 });
3913 } else if neg {
3914 *result.last_mut().unwrap() |= 0x80;
3915 }
3916 result
3917}
3918
3919#[cfg(not(feature = "production"))]
3920pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3921 if value == 0 {
3922 return vec![];
3923 }
3924 let neg = value < 0;
3925 let mut absvalue = if neg {
3926 (-(value as i128)) as u64
3927 } else {
3928 value as u64
3929 };
3930 let mut result = Vec::new();
3931 while absvalue > 0 {
3932 result.push((absvalue & 0xff) as u8);
3933 absvalue >>= 8;
3934 }
3935 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3937 result.push(if neg { 0x80 } else { 0x00 });
3938 } else if neg {
3939 *result.last_mut().unwrap() |= 0x80;
3940 }
3941 result
3942}
3943
3944#[cfg(feature = "production")]
3946#[inline(always)]
3947fn execute_opcode(
3948 opcode: u8,
3949 stack: &mut Vec<StackElement>,
3950 flags: u32,
3951 _sigversion: SigVersion,
3952) -> Result<bool> {
3953 match opcode {
3954 OP_0 => {
3956 stack.push(to_stack_element(&[]));
3957 Ok(true)
3958 }
3959
3960 OP_1..=OP_16 => {
3962 let num = opcode - OP_N_BASE;
3963 stack.push(to_stack_element(&[num]));
3964 Ok(true)
3965 }
3966
3967 OP_NOP => Ok(true),
3969
3970 OP_VER => Ok(false),
3972
3973 OP_DEPTH => {
3975 let depth = stack.len() as i64;
3976 stack.push(to_stack_element(&script_num_encode(depth)));
3977 Ok(true)
3978 }
3979
3980 OP_DUP => {
3982 if let Some(item) = stack.last().cloned() {
3983 stack.push(item);
3984 Ok(true)
3985 } else {
3986 Ok(false)
3987 }
3988 }
3989
3990 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
3992
3993 OP_SHA1 => crypto_ops::op_sha1(stack),
3995
3996 OP_SHA256 => crypto_ops::op_sha256(stack),
3998
3999 OP_HASH160 => crypto_ops::op_hash160(stack),
4001
4002 OP_HASH256 => crypto_ops::op_hash256(stack),
4004
4005 OP_EQUAL => {
4007 if stack.len() < 2 {
4008 return Err(ConsensusError::ScriptErrorWithCode {
4009 code: ScriptErrorCode::InvalidStackOperation,
4010 message: "OP_EQUAL: insufficient stack items".into(),
4011 });
4012 }
4013 let a = stack.pop().unwrap();
4014 let b = stack.pop().unwrap();
4015 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
4016 Ok(true)
4017 }
4018
4019 OP_EQUALVERIFY => {
4022 if stack.len() < 2 {
4023 return Err(ConsensusError::ScriptErrorWithCode {
4024 code: ScriptErrorCode::InvalidStackOperation,
4025 message: "OP_EQUALVERIFY: insufficient stack items".into(),
4026 });
4027 }
4028 let a = stack.pop().unwrap();
4029 let b = stack.pop().unwrap();
4030 let f_equal = a == b;
4031 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
4033 if f_equal {
4034 stack.pop();
4036 Ok(true)
4037 } else {
4038 Err(ConsensusError::ScriptErrorWithCode {
4039 code: ScriptErrorCode::EqualVerify,
4040 message: "OP_EQUALVERIFY: stack items not equal".into(),
4041 })
4042 }
4043 }
4044
4045 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
4047
4048 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
4050
4051 OP_RETURN => Ok(false),
4053
4054 OP_VERIFY => {
4056 if let Some(item) = stack.pop() {
4057 Ok(cast_to_bool(&item))
4058 } else {
4059 Ok(false)
4060 }
4061 }
4062
4063 OP_CHECKLOCKTIMEVERIFY => {
4067 Ok(false)
4070 }
4071
4072 OP_CHECKSEQUENCEVERIFY => {
4076 Ok(false)
4079 }
4080
4081 OP_IFDUP => {
4083 if let Some(item) = stack.last().cloned() {
4084 if cast_to_bool(&item) {
4085 stack.push(item);
4086 }
4087 Ok(true)
4088 } else {
4089 Ok(false)
4090 }
4091 }
4092
4093 OP_DROP => {
4096 if stack.pop().is_some() {
4097 Ok(true)
4098 } else {
4099 Ok(false)
4100 }
4101 }
4102
4103 OP_NIP => {
4105 if stack.len() >= 2 {
4106 let top = stack.pop().unwrap();
4107 stack.pop(); stack.push(top);
4109 Ok(true)
4110 } else {
4111 Ok(false)
4112 }
4113 }
4114
4115 OP_OVER => {
4117 if stack.len() >= 2 {
4118 let len = stack.len();
4119 #[cfg(feature = "production")]
4120 {
4121 unsafe {
4123 let second = stack.get_unchecked(len - 2);
4124 stack.push(second.clone());
4125 }
4126 }
4127 #[cfg(not(feature = "production"))]
4128 {
4129 let second = stack[stack.len() - 2].clone();
4130 stack.push(second);
4131 }
4132 Ok(true)
4133 } else {
4134 Ok(false)
4135 }
4136 }
4137
4138 OP_PICK => {
4140 if let Some(n_bytes) = stack.pop() {
4141 let n_val = script_num_decode(&n_bytes, 4)?;
4144 if n_val < 0 || n_val as usize >= stack.len() {
4145 return Ok(false);
4146 }
4147 let n = n_val as usize;
4148 let len = stack.len();
4149 #[cfg(feature = "production")]
4150 {
4151 unsafe {
4153 let item = stack.get_unchecked(len - 1 - n);
4154 stack.push(item.clone());
4155 }
4156 }
4157 #[cfg(not(feature = "production"))]
4158 {
4159 let item = stack[stack.len() - 1 - n].clone();
4160 stack.push(item);
4161 }
4162 Ok(true)
4163 } else {
4164 Ok(false)
4165 }
4166 }
4167
4168 OP_ROLL => {
4170 if let Some(n_bytes) = stack.pop() {
4171 let n_val = script_num_decode(&n_bytes, 4)?;
4174 if n_val < 0 || n_val as usize >= stack.len() {
4175 return Ok(false);
4176 }
4177 let n = n_val as usize;
4178 let len = stack.len();
4179 #[cfg(feature = "production")]
4180 {
4181 let idx = len - 1 - n;
4183 let item = stack.remove(idx);
4184 stack.push(item);
4185 }
4186 #[cfg(not(feature = "production"))]
4187 {
4188 let item = stack.remove(stack.len() - 1 - n);
4189 stack.push(item);
4190 }
4191 Ok(true)
4192 } else {
4193 Ok(false)
4194 }
4195 }
4196
4197 OP_ROT => {
4199 if stack.len() >= 3 {
4200 let top = stack.pop().unwrap();
4201 let second = stack.pop().unwrap();
4202 let third = stack.pop().unwrap();
4203 stack.push(second);
4204 stack.push(top);
4205 stack.push(third);
4206 Ok(true)
4207 } else {
4208 Ok(false)
4209 }
4210 }
4211
4212 OP_SWAP => {
4214 if stack.len() >= 2 {
4215 let top = stack.pop().unwrap();
4216 let second = stack.pop().unwrap();
4217 stack.push(top);
4218 stack.push(second);
4219 Ok(true)
4220 } else {
4221 Ok(false)
4222 }
4223 }
4224
4225 OP_TUCK => {
4227 if stack.len() >= 2 {
4228 let top = stack.pop().unwrap();
4229 let second = stack.pop().unwrap();
4230 stack.push(top.clone());
4231 stack.push(second);
4232 stack.push(top);
4233 Ok(true)
4234 } else {
4235 Ok(false)
4236 }
4237 }
4238
4239 OP_2DROP => {
4241 if stack.len() >= 2 {
4242 stack.pop();
4243 stack.pop();
4244 Ok(true)
4245 } else {
4246 Ok(false)
4247 }
4248 }
4249
4250 OP_2DUP => {
4252 if stack.len() >= 2 {
4253 let top = stack[stack.len() - 1].clone();
4254 let second = stack[stack.len() - 2].clone();
4255 stack.push(second);
4256 stack.push(top);
4257 Ok(true)
4258 } else {
4259 Ok(false)
4260 }
4261 }
4262
4263 OP_3DUP => {
4265 if stack.len() >= 3 {
4266 let top = stack[stack.len() - 1].clone();
4267 let second = stack[stack.len() - 2].clone();
4268 let third = stack[stack.len() - 3].clone();
4269 stack.push(third);
4270 stack.push(second);
4271 stack.push(top);
4272 Ok(true)
4273 } else {
4274 Ok(false)
4275 }
4276 }
4277
4278 OP_2OVER => {
4280 if stack.len() >= 4 {
4281 let fourth = stack[stack.len() - 4].clone();
4282 let third = stack[stack.len() - 3].clone();
4283 stack.push(fourth);
4284 stack.push(third);
4285 Ok(true)
4286 } else {
4287 Ok(false)
4288 }
4289 }
4290
4291 OP_2ROT => {
4293 if stack.len() >= 6 {
4294 let sixth = stack.remove(stack.len() - 6);
4295 let fifth = stack.remove(stack.len() - 5);
4296 stack.push(fifth);
4297 stack.push(sixth);
4298 Ok(true)
4299 } else {
4300 Ok(false)
4301 }
4302 }
4303
4304 OP_2SWAP => {
4306 if stack.len() >= 4 {
4307 let top = stack.pop().unwrap();
4308 let second = stack.pop().unwrap();
4309 let third = stack.pop().unwrap();
4310 let fourth = stack.pop().unwrap();
4311 stack.push(second);
4312 stack.push(top);
4313 stack.push(fourth);
4314 stack.push(third);
4315 Ok(true)
4316 } else {
4317 Ok(false)
4318 }
4319 }
4320
4321 OP_SIZE => {
4324 if let Some(item) = stack.last() {
4325 let size = item.len() as i64;
4326 stack.push(to_stack_element(&script_num_encode(size)));
4327 Ok(true)
4328 } else {
4329 Ok(false)
4330 }
4331 }
4332
4333 OP_1ADD => {
4338 if let Some(item) = stack.pop() {
4339 let a = script_num_decode(&item, 4)?;
4340 stack.push(to_stack_element(&script_num_encode(a + 1)));
4341 Ok(true)
4342 } else {
4343 Ok(false)
4344 }
4345 }
4346 OP_1SUB => {
4348 if let Some(item) = stack.pop() {
4349 let a = script_num_decode(&item, 4)?;
4350 stack.push(to_stack_element(&script_num_encode(a - 1)));
4351 Ok(true)
4352 } else {
4353 Ok(false)
4354 }
4355 }
4356 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4358 code: ScriptErrorCode::DisabledOpcode,
4359 message: "OP_2MUL is disabled".into(),
4360 }),
4361 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4363 code: ScriptErrorCode::DisabledOpcode,
4364 message: "OP_2DIV is disabled".into(),
4365 }),
4366 OP_NEGATE => {
4368 if let Some(item) = stack.pop() {
4369 let a = script_num_decode(&item, 4)?;
4370 stack.push(to_stack_element(&script_num_encode(-a)));
4371 Ok(true)
4372 } else {
4373 Ok(false)
4374 }
4375 }
4376 OP_ABS => {
4378 if let Some(item) = stack.pop() {
4379 let a = script_num_decode(&item, 4)?;
4380 stack.push(to_stack_element(&script_num_encode(a.abs())));
4381 Ok(true)
4382 } else {
4383 Ok(false)
4384 }
4385 }
4386 OP_NOT => {
4388 if let Some(item) = stack.pop() {
4389 let a = script_num_decode(&item, 4)?;
4390 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4391 1
4392 } else {
4393 0
4394 })));
4395 Ok(true)
4396 } else {
4397 Ok(false)
4398 }
4399 }
4400 OP_0NOTEQUAL => {
4402 if let Some(item) = stack.pop() {
4403 let a = script_num_decode(&item, 4)?;
4404 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4405 1
4406 } else {
4407 0
4408 })));
4409 Ok(true)
4410 } else {
4411 Ok(false)
4412 }
4413 }
4414 OP_ADD => arithmetic::op_add(stack),
4415 OP_SUB => arithmetic::op_sub(stack),
4416 OP_MUL => arithmetic::op_mul_disabled(),
4417 OP_DIV => arithmetic::op_div_disabled(),
4418 OP_MOD => arithmetic::op_mod_disabled(),
4419 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4420 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4421 OP_BOOLAND => arithmetic::op_booland(stack),
4422 OP_BOOLOR => arithmetic::op_boolor(stack),
4423 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4424 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4425 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4426 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4427 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4428 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4429 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4430 OP_MIN => arithmetic::op_min(stack),
4431 OP_MAX => arithmetic::op_max(stack),
4432 OP_WITHIN => arithmetic::op_within(stack),
4433
4434 OP_CODESEPARATOR => Ok(true),
4436
4437 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4440
4441 OP_CHECKTEMPLATEVERIFY => {
4443 #[cfg(not(feature = "ctv"))]
4444 {
4445 Ok(true)
4447 }
4448
4449 #[cfg(feature = "ctv")]
4450 {
4451 return Err(ConsensusError::ScriptErrorWithCode {
4453 code: ScriptErrorCode::TxInvalid,
4454 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4455 });
4456 }
4457 }
4458
4459 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4461 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4462 Err(ConsensusError::ScriptErrorWithCode {
4463 code: ScriptErrorCode::DisabledOpcode,
4464 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4465 })
4466 }
4467
4468 _ => Ok(false),
4470 }
4471}
4472
4473#[allow(dead_code)]
4475fn execute_opcode_with_context(
4476 opcode: u8,
4477 stack: &mut Vec<StackElement>,
4478 flags: u32,
4479 tx: &Transaction,
4480 input_index: usize,
4481 prevouts: &[TransactionOutput],
4482 network: crate::types::Network,
4483) -> Result<bool> {
4484 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4486 let prevout_script_pubkeys: Vec<&[u8]> =
4487 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4488 let ctx = context::ScriptContext {
4489 tx,
4490 input_index,
4491 prevout_values: &prevout_values,
4492 prevout_script_pubkeys: &prevout_script_pubkeys,
4493 block_height: None,
4494 median_time_past: None,
4495 network,
4496 sigversion: SigVersion::Base,
4497 redeem_script_for_sighash: None,
4498 script_sig_for_sighash: None,
4499 tapscript_for_sighash: None,
4500 tapscript_codesep_pos: None,
4501 #[cfg(feature = "production")]
4502 schnorr_collector: None,
4503 #[cfg(feature = "production")]
4504 precomputed_bip143: None,
4505 #[cfg(feature = "production")]
4506 sighash_cache: None,
4507 };
4508 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4509}
4510
4511#[cfg(feature = "production")]
4515#[inline(always)]
4516pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4517 let mut i = 0;
4518 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4519 i += adv1;
4520 if i >= script_sig.len() {
4521 return None;
4522 }
4523 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4524 i += adv2;
4525 if i >= script_sig.len() {
4526 return None;
4527 }
4528 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4529 i += adv3;
4530 if i != script_sig.len() {
4531 return None;
4532 }
4533 let sig = &script_sig[s_start..s_end];
4534 let redeem = &script_sig[r_start..r_end];
4535 if sig.is_empty() || redeem.len() != 25 {
4536 return None;
4537 }
4538 if redeem[0] != OP_DUP
4539 || redeem[1] != OP_HASH160
4540 || redeem[2] != PUSH_20_BYTES
4541 || redeem[23] != OP_EQUALVERIFY
4542 || redeem[24] != OP_CHECKSIG
4543 {
4544 return None;
4545 }
4546 Some((sig[sig.len() - 1], redeem))
4547}
4548
4549#[inline(always)]
4553pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4554 let mut i = 0;
4555 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4556 i += adv1;
4557 if i >= script_sig.len() {
4558 return None;
4559 }
4560 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4561 i += adv2;
4562 if i != script_sig.len() {
4563 return None;
4564 }
4565 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4566}
4567
4568pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4571 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4572 if advance != script_sig.len() {
4573 return None;
4574 }
4575 Some(&script_sig[data_start..data_end])
4576}
4577
4578fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4580 if i >= script.len() {
4581 return None;
4582 }
4583 let opcode = script[i];
4584 let (advance, data_start, data_end) = if opcode == OP_0 {
4585 return None;
4586 } else if opcode <= 0x4b {
4587 let len = opcode as usize;
4588 if i + 1 + len > script.len() {
4589 return None;
4590 }
4591 (1 + len, i + 1, i + 1 + len)
4592 } else if opcode == OP_PUSHDATA1 {
4593 if i + 1 >= script.len() {
4594 return None;
4595 }
4596 let len = script[i + 1] as usize;
4597 if i + 2 + len > script.len() {
4598 return None;
4599 }
4600 (2 + len, i + 2, i + 2 + len)
4601 } else if opcode == OP_PUSHDATA2 {
4602 if i + 2 >= script.len() {
4603 return None;
4604 }
4605 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4606 if i + 3 + len > script.len() {
4607 return None;
4608 }
4609 (3 + len, i + 3, i + 3 + len)
4610 } else if opcode == OP_PUSHDATA4 {
4611 if i + 4 >= script.len() {
4612 return None;
4613 }
4614 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4615 as usize;
4616 if i + 5 + len > script.len() {
4617 return None;
4618 }
4619 (5 + len, i + 5, i + 5 + len)
4620 } else {
4621 return None;
4622 };
4623 Some((advance, data_start, data_end))
4624}
4625
4626#[spec_locked("5.2.1", "P2SHPushOnlyCheck")]
4629pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4630 parse_script_sig_push_only(script_sig).is_some()
4631}
4632
4633fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4637 let mut out = Vec::new();
4638 let mut i = 0;
4639 while i < script_sig.len() {
4640 let opcode = script_sig[i];
4641 if !is_push_opcode(opcode) {
4642 return None;
4643 }
4644 let (advance, data) = if opcode == OP_0 {
4645 (1, vec![])
4646 } else if opcode <= 0x4b {
4647 let len = opcode as usize;
4648 if i + 1 + len > script_sig.len() {
4649 return None;
4650 }
4651 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4652 } else if opcode == OP_PUSHDATA1 {
4653 if i + 1 >= script_sig.len() {
4654 return None;
4655 }
4656 let len = script_sig[i + 1] as usize;
4657 if i + 2 + len > script_sig.len() {
4658 return None;
4659 }
4660 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4661 } else if opcode == OP_PUSHDATA2 {
4662 if i + 2 >= script_sig.len() {
4663 return None;
4664 }
4665 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4666 if i + 3 + len > script_sig.len() {
4667 return None;
4668 }
4669 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4670 } else if opcode == OP_PUSHDATA4 {
4671 if i + 4 >= script_sig.len() {
4672 return None;
4673 }
4674 let len = u32::from_le_bytes([
4675 script_sig[i + 1],
4676 script_sig[i + 2],
4677 script_sig[i + 3],
4678 script_sig[i + 4],
4679 ]) as usize;
4680 if i + 5 + len > script_sig.len() {
4681 return None;
4682 }
4683 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4684 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4685 let n = script_num_from_opcode(opcode);
4687 (1, script_num_encode(n))
4688 } else {
4689 return None;
4690 };
4691 out.push(to_stack_element(&data));
4692 i += advance;
4693 }
4694 Some(out)
4695}
4696
4697fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4701 parse_script_sig_push_only(script_sig)
4702}
4703
4704fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4709 if redeem.len() < 4 {
4710 return None;
4711 }
4712 let n_op = redeem[0];
4713 if !(OP_1..=OP_16).contains(&n_op) {
4714 return None;
4715 }
4716 let n = (n_op - OP_1 + 1) as usize;
4717 let mut i = 1;
4718 let mut pubkeys = Vec::with_capacity(n);
4719 for _ in 0..n {
4720 if i >= redeem.len() {
4721 return None;
4722 }
4723 let first = redeem[i];
4724 let pk_len = if first == 0x02 || first == 0x03 {
4725 33
4726 } else if first == 0x04 {
4727 65
4728 } else {
4729 return None;
4730 };
4731 if i + pk_len > redeem.len() {
4732 return None;
4733 }
4734 pubkeys.push(&redeem[i..i + pk_len]);
4735 i += pk_len;
4736 }
4737 if i + 2 > redeem.len() {
4738 return None;
4739 }
4740 let m_op = redeem[i];
4741 if !(OP_1..=OP_16).contains(&m_op) {
4742 return None;
4743 }
4744 let m = m_op - OP_1 + 1;
4745 if redeem[i + 1] != OP_CHECKMULTISIG {
4746 return None;
4747 }
4748 Some((m, n as u8, pubkeys))
4749}
4750
4751fn script_num_from_opcode(opcode: u8) -> i64 {
4753 match opcode {
4754 OP_1NEGATE => -1,
4755 OP_1 => 1,
4756 OP_2 => 2,
4757 OP_3 => 3,
4758 OP_4 => 4,
4759 OP_5 => 5,
4760 OP_6 => 6,
4761 OP_7 => 7,
4762 OP_8 => 8,
4763 OP_9 => 9,
4764 OP_10 => 10,
4765 OP_11 => 11,
4766 OP_12 => 12,
4767 OP_13 => 13,
4768 OP_14 => 14,
4769 OP_15 => 15,
4770 OP_16 => 16,
4771 _ => 0,
4772 }
4773}
4774
4775pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
4779 let len = data.len();
4780 let mut result = Vec::with_capacity(len + 5);
4781 if len < 76 {
4782 result.push(len as u8);
4783 } else if len < 256 {
4784 result.push(OP_PUSHDATA1);
4785 result.push(len as u8);
4786 } else if len < 65536 {
4787 result.push(OP_PUSHDATA2);
4788 result.push((len & 0xff) as u8);
4789 result.push(((len >> 8) & 0xff) as u8);
4790 } else {
4791 result.push(OP_PUSHDATA4);
4792 result.push((len & 0xff) as u8);
4793 result.push(((len >> 8) & 0xff) as u8);
4794 result.push(((len >> 16) & 0xff) as u8);
4795 result.push(((len >> 24) & 0xff) as u8);
4796 }
4797 result.extend_from_slice(data);
4798 result
4799}
4800
4801#[inline]
4803fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
4804 if pc >= script.len() {
4805 return None;
4806 }
4807 let opcode = script[pc];
4808 let advance = if opcode <= 0x4b {
4809 1 + opcode as usize
4810 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
4811 2 + script[pc + 1] as usize
4812 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
4813 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
4814 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
4815 5 + ((script[pc + 1] as usize)
4816 | ((script[pc + 2] as usize) << 8)
4817 | ((script[pc + 3] as usize) << 16)
4818 | ((script[pc + 4] as usize) << 24))
4819 } else {
4820 1
4821 };
4822 let next = pc + advance;
4823 if next > script.len() {
4824 None
4825 } else {
4826 Some(next)
4827 }
4828}
4829
4830#[spec_locked("5.1.1", "FindAndDelete")]
4836#[inline]
4837pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
4838 if pattern.is_empty() {
4839 return std::borrow::Cow::Borrowed(script);
4840 }
4841 if pattern.len() > script.len() {
4842 return std::borrow::Cow::Borrowed(script);
4843 }
4844 if !script.windows(pattern.len()).any(|w| w == pattern) {
4849 return std::borrow::Cow::Borrowed(script);
4850 }
4851 let end = script.len();
4852 let mut n_found = 0usize;
4853 let mut result = Vec::new();
4854 let mut pc = 0usize;
4855 let mut pc2 = 0usize;
4856
4857 loop {
4858 result.extend_from_slice(&script[pc2..pc]);
4859 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
4860 pc += pattern.len();
4861 n_found += 1;
4862 }
4863 pc2 = pc;
4864 if pc >= end {
4865 break;
4866 }
4867 let Some(next_pc) = script_get_op_advance(script, pc) else {
4868 break;
4869 };
4870 pc = next_pc;
4871 }
4872
4873 if n_found > 0 {
4874 result.extend_from_slice(&script[pc2..end]);
4875 std::borrow::Cow::Owned(result)
4876 } else {
4877 std::borrow::Cow::Borrowed(script)
4878 }
4879}
4880
4881fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
4883 let mut pos = 0u32;
4884 let mut i = 0usize;
4885 while i < script.len() && i <= byte_index {
4886 let opcode = script[i];
4887 let advance = if opcode <= 0x4b {
4888 1 + opcode as usize
4889 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
4890 2 + script[i + 1] as usize
4891 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
4892 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
4893 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
4894 5 + ((script[i + 1] as usize)
4895 | ((script[i + 2] as usize) << 8)
4896 | ((script[i + 3] as usize) << 16)
4897 | ((script[i + 4] as usize) << 24))
4898 } else {
4899 1
4900 };
4901 if i == byte_index {
4902 return pos;
4903 }
4904 pos += 1;
4905 i = std::cmp::min(i + advance, script.len());
4906 }
4907 0xffff_ffff
4908}
4909
4910#[cfg_attr(feature = "production", inline(always))]
4912fn execute_opcode_with_context_full(
4913 opcode: u8,
4914 stack: &mut Vec<StackElement>,
4915 flags: u32,
4916 ctx: &context::ScriptContext<'_>,
4917 effective_script_code: Option<&[u8]>,
4918) -> Result<bool> {
4919 let tx = ctx.tx;
4920 let input_index = ctx.input_index;
4921 let prevout_values = ctx.prevout_values;
4922 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
4923 let block_height = ctx.block_height;
4924 let median_time_past = ctx.median_time_past;
4925 let network = ctx.network;
4926 let sigversion = ctx.sigversion;
4927 let script_sig_for_sighash = ctx.script_sig_for_sighash;
4928 let tapscript_for_sighash = ctx.tapscript_for_sighash;
4929 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
4930 let redeem_script_for_sighash = effective_script_code;
4931 #[cfg(feature = "production")]
4932 let schnorr_collector = ctx.schnorr_collector;
4933 #[cfg(feature = "production")]
4934 let precomputed_bip143 = ctx.precomputed_bip143;
4935 #[cfg(feature = "production")]
4936 let sighash_cache = ctx.sighash_cache;
4937
4938 match opcode {
4940 OP_CHECKSIG => {
4942 if stack.len() >= 2 {
4943 let pubkey_bytes = stack.pop().unwrap();
4944 let signature_bytes = stack.pop().unwrap();
4945
4946 if signature_bytes.is_empty() {
4948 stack.push(to_stack_element(&[0]));
4949 return Ok(true);
4950 }
4951
4952 if sigversion == SigVersion::Tapscript {
4955 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
4957 let sighash_byte = 0x00;
4958 let (tapscript, codesep_pos) = tapscript_for_sighash
4959 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
4960 .unwrap_or((&[] as &[u8], 0xffff_ffff));
4961 let sighash = if tapscript.is_empty() {
4962 crate::taproot::compute_taproot_signature_hash(
4963 tx,
4964 input_index,
4965 prevout_values,
4966 prevout_script_pubkeys,
4967 sighash_byte,
4968 )?
4969 } else {
4970 crate::taproot::compute_tapscript_signature_hash(
4971 tx,
4972 input_index,
4973 prevout_values,
4974 prevout_script_pubkeys,
4975 tapscript,
4976 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
4977 codesep_pos,
4978 sighash_byte,
4979 )?
4980 };
4981
4982 #[cfg(feature = "production")]
4984 let is_valid = {
4985 use crate::bip348::verify_tapscript_schnorr_signature;
4986 verify_tapscript_schnorr_signature(
4987 &sighash,
4988 &pubkey_bytes,
4989 &signature_bytes,
4990 schnorr_collector,
4991 )
4992 .unwrap_or(false)
4993 };
4994
4995 #[cfg(not(feature = "production"))]
4996 let is_valid = {
4997 #[cfg(feature = "csfs")]
4998 let x = {
4999 use crate::bip348::verify_tapscript_schnorr_signature;
5000 verify_tapscript_schnorr_signature(
5001 &sighash,
5002 &pubkey_bytes,
5003 &signature_bytes,
5004 None,
5005 )
5006 .unwrap_or(false)
5007 };
5008 #[cfg(not(feature = "csfs"))]
5009 let x = false;
5010 x
5011 };
5012
5013 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5014 return Ok(true);
5015 }
5016 }
5018
5019 let sig_len = signature_bytes.len();
5023 let sighash_byte = signature_bytes[sig_len - 1];
5024 let _der_sig = &signature_bytes[..sig_len - 1];
5025
5026 let sighash = if sigversion == SigVersion::WitnessV0 {
5030 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5032
5033 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5035 prevout_script_pubkeys
5036 .get(input_index)
5037 .copied()
5038 .unwrap_or(&[])
5039 });
5040
5041 crate::transaction_hash::calculate_bip143_sighash(
5042 tx,
5043 input_index,
5044 script_code,
5045 amount,
5046 sighash_byte,
5047 precomputed_bip143,
5048 )?
5049 } else {
5050 use crate::transaction_hash::{
5052 calculate_transaction_sighash_single_input, SighashType,
5053 };
5054 let sighash_type = SighashType::from_byte(sighash_byte);
5055
5056 let pattern = serialize_push_data(signature_bytes.as_ref());
5060
5061 let base_script = match (
5062 redeem_script_for_sighash,
5063 prevout_script_pubkeys.get(input_index),
5064 ) {
5065 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5066 (Some(redeem), _) => redeem,
5067 (None, Some(prevout)) => *prevout,
5068 (None, None) => &[],
5069 };
5070 let cleaned = find_and_delete(base_script, &pattern);
5071
5072 calculate_transaction_sighash_single_input(
5073 tx,
5074 input_index,
5075 cleaned.as_ref(),
5076 prevout_values[input_index],
5077 sighash_type,
5078 #[cfg(feature = "production")]
5079 sighash_cache,
5080 )?
5081 };
5082
5083 let height = block_height.unwrap_or(0);
5087 #[cfg(feature = "production")]
5088 let is_valid = signature::with_secp_context(|secp| {
5089 signature::verify_signature(
5090 secp,
5091 &pubkey_bytes,
5092 &signature_bytes, &sighash,
5094 flags,
5095 height,
5096 network,
5097 sigversion,
5098 )
5099 })?;
5100
5101 #[cfg(not(feature = "production"))]
5102 let is_valid = {
5103 let secp = signature::new_secp();
5104 signature::verify_signature(
5105 &secp,
5106 &pubkey_bytes,
5107 &signature_bytes, &sighash,
5109 flags,
5110 height,
5111 network,
5112 sigversion,
5113 )?
5114 };
5115
5116 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5117 Ok(true)
5118 } else {
5119 Ok(false)
5120 }
5121 }
5122
5123 OP_CHECKSIGVERIFY => {
5125 if stack.len() >= 2 {
5126 let pubkey_bytes = stack.pop().unwrap();
5127 let signature_bytes = stack.pop().unwrap();
5128
5129 if signature_bytes.is_empty() {
5131 return Ok(false);
5132 }
5133
5134 if sigversion == SigVersion::Tapscript {
5136 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
5137 let sighash_byte = 0x00u8;
5138 let (tapscript, codesep_pos) = tapscript_for_sighash
5139 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5140 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5141 let sighash = if tapscript.is_empty() {
5142 crate::taproot::compute_taproot_signature_hash(
5143 tx,
5144 input_index,
5145 prevout_values,
5146 prevout_script_pubkeys,
5147 sighash_byte,
5148 )?
5149 } else {
5150 crate::taproot::compute_tapscript_signature_hash(
5151 tx,
5152 input_index,
5153 prevout_values,
5154 prevout_script_pubkeys,
5155 tapscript,
5156 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5157 codesep_pos,
5158 sighash_byte,
5159 )?
5160 };
5161 #[cfg(feature = "production")]
5162 let is_valid = {
5163 use crate::bip348::verify_tapscript_schnorr_signature;
5164 verify_tapscript_schnorr_signature(
5165 &sighash,
5166 &pubkey_bytes,
5167 &signature_bytes,
5168 schnorr_collector,
5169 )
5170 .unwrap_or(false)
5171 };
5172 #[cfg(not(feature = "production"))]
5173 let is_valid = {
5174 #[cfg(feature = "csfs")]
5175 let x = {
5176 use crate::bip348::verify_tapscript_schnorr_signature;
5177 verify_tapscript_schnorr_signature(
5178 &sighash,
5179 &pubkey_bytes,
5180 &signature_bytes,
5181 None,
5182 )
5183 .unwrap_or(false)
5184 };
5185 #[cfg(not(feature = "csfs"))]
5186 let x = false;
5187 x
5188 };
5189 if !is_valid {
5190 return Ok(false); }
5192 return Ok(true);
5193 }
5194 return Ok(false);
5196 }
5197
5198 let sig_len = signature_bytes.len();
5201 let sighash_byte = signature_bytes[sig_len - 1];
5202 let _der_sig = &signature_bytes[..sig_len - 1];
5203
5204 let sighash = if sigversion == SigVersion::WitnessV0 {
5208 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5210
5211 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5212 prevout_script_pubkeys
5213 .get(input_index)
5214 .copied()
5215 .unwrap_or(&[])
5216 });
5217
5218 crate::transaction_hash::calculate_bip143_sighash(
5219 tx,
5220 input_index,
5221 script_code,
5222 amount,
5223 sighash_byte,
5224 precomputed_bip143,
5225 )?
5226 } else {
5227 use crate::transaction_hash::{
5229 calculate_transaction_sighash_single_input, SighashType,
5230 };
5231 let sighash_type = SighashType::from_byte(sighash_byte);
5232
5233 let pattern = serialize_push_data(signature_bytes.as_ref());
5235
5236 let base_script = match (
5237 redeem_script_for_sighash,
5238 prevout_script_pubkeys.get(input_index),
5239 ) {
5240 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5241 (Some(redeem), _) => redeem,
5242 (None, Some(prevout)) => *prevout,
5243 (None, None) => &[],
5244 };
5245 let cleaned = find_and_delete(base_script, &pattern);
5246
5247 calculate_transaction_sighash_single_input(
5248 tx,
5249 input_index,
5250 cleaned.as_ref(),
5251 prevout_values[input_index],
5252 sighash_type,
5253 #[cfg(feature = "production")]
5254 sighash_cache,
5255 )?
5256 };
5257
5258 let height = block_height.unwrap_or(0);
5262 #[cfg(feature = "production")]
5263 let is_valid = signature::with_secp_context(|secp| {
5264 signature::verify_signature(
5265 secp,
5266 &pubkey_bytes,
5267 &signature_bytes, &sighash,
5269 flags,
5270 height,
5271 network,
5272 sigversion,
5273 )
5274 })?;
5275
5276 #[cfg(not(feature = "production"))]
5277 let is_valid = {
5278 let secp = signature::new_secp();
5279 signature::verify_signature(
5280 &secp,
5281 &pubkey_bytes,
5282 &signature_bytes, &sighash,
5284 flags,
5285 height,
5286 network,
5287 sigversion,
5288 )?
5289 };
5290
5291 if is_valid {
5292 Ok(true)
5293 } else {
5294 Ok(false)
5295 }
5296 } else {
5297 Ok(false)
5298 }
5299 }
5300
5301 OP_CHECKSIGADD => {
5303 if sigversion != SigVersion::Tapscript {
5304 return Err(ConsensusError::ScriptErrorWithCode {
5305 code: ScriptErrorCode::DisabledOpcode,
5306 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5307 });
5308 }
5309 if stack.len() < 3 {
5310 return Err(ConsensusError::ScriptErrorWithCode {
5311 code: ScriptErrorCode::InvalidStackOperation,
5312 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5313 });
5314 }
5315 let pubkey_bytes = stack.pop().unwrap();
5317 let n_bytes = stack.pop().unwrap();
5318 let signature_bytes = stack.pop().unwrap();
5319 let n = script_num_decode(&n_bytes, 4)?;
5320
5321 if signature_bytes.is_empty() {
5323 stack.push(to_stack_element(&script_num_encode(n)));
5324 return Ok(true);
5325 }
5326
5327 if pubkey_bytes.len() == 32 && signature_bytes.len() == 64 {
5329 let sighash_byte = 0x00;
5330 let (tapscript, codesep_pos) = tapscript_for_sighash
5331 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5332 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5333 let sighash = if tapscript.is_empty() {
5334 crate::taproot::compute_taproot_signature_hash(
5335 tx,
5336 input_index,
5337 prevout_values,
5338 prevout_script_pubkeys,
5339 sighash_byte,
5340 )?
5341 } else {
5342 crate::taproot::compute_tapscript_signature_hash(
5343 tx,
5344 input_index,
5345 prevout_values,
5346 prevout_script_pubkeys,
5347 tapscript,
5348 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5349 codesep_pos,
5350 sighash_byte,
5351 )?
5352 };
5353
5354 #[cfg(feature = "production")]
5355 let is_valid = {
5356 use crate::bip348::verify_tapscript_schnorr_signature;
5357 verify_tapscript_schnorr_signature(
5358 &sighash,
5359 &pubkey_bytes,
5360 &signature_bytes,
5361 schnorr_collector,
5362 )
5363 .unwrap_or(false)
5364 };
5365
5366 #[cfg(not(feature = "production"))]
5367 let is_valid = {
5368 #[cfg(feature = "csfs")]
5369 let x = {
5370 use crate::bip348::verify_tapscript_schnorr_signature;
5371 verify_tapscript_schnorr_signature(
5372 &sighash,
5373 &pubkey_bytes,
5374 &signature_bytes,
5375 None,
5376 )
5377 .unwrap_or(false)
5378 };
5379 #[cfg(not(feature = "csfs"))]
5380 let x = false;
5381 x
5382 };
5383
5384 if !is_valid {
5385 return Ok(false); }
5387 stack.push(to_stack_element(&script_num_encode(n + 1)));
5388 return Ok(true);
5389 }
5390
5391 stack.push(to_stack_element(&script_num_encode(n + 1)));
5393 Ok(true)
5394 }
5395
5396 OP_CHECKMULTISIG => {
5398 if stack.len() < 2 {
5401 return Ok(false);
5402 }
5403
5404 let n_bytes = stack.pop().unwrap();
5406 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
5407 ConsensusError::ScriptErrorWithCode {
5408 code: ScriptErrorCode::InvalidStackOperation,
5409 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
5410 }
5411 })?;
5412 if !(0..=20).contains(&n_raw) {
5413 return Ok(false);
5414 }
5415 let n = n_raw as usize;
5416 if stack.len() < n + 1 {
5417 return Ok(false);
5418 }
5419
5420 let mut pubkeys = Vec::with_capacity(n);
5422 for _ in 0..n {
5423 pubkeys.push(stack.pop().unwrap());
5424 }
5425
5426 let m_bytes = stack.pop().unwrap();
5428 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
5429 ConsensusError::ScriptErrorWithCode {
5430 code: ScriptErrorCode::InvalidStackOperation,
5431 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
5432 }
5433 })?;
5434 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
5435 return Ok(false);
5436 }
5437 let m = m_raw as usize;
5438 if stack.len() < m + 1 {
5439 return Ok(false);
5440 }
5441
5442 let mut signatures = Vec::with_capacity(m);
5444 for _ in 0..m {
5445 signatures.push(stack.pop().unwrap());
5446 }
5447
5448 let dummy = stack.pop().unwrap();
5451 if flags & 0x10 != 0 {
5452 let height = block_height.unwrap_or(0);
5453 use crate::bip_validation::Bip147Network;
5455 let bip147_network = match network {
5456 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5457 crate::types::Network::Testnet => Bip147Network::Testnet,
5458 crate::types::Network::Regtest => Bip147Network::Regtest,
5459 };
5460
5461 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5465
5466 let bip147_active = height
5467 >= match bip147_network {
5468 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5469 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5470 Bip147Network::Regtest => 0,
5471 };
5472
5473 if bip147_active {
5474 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5478 if !is_empty {
5479 return Err(ConsensusError::ScriptErrorWithCode {
5480 code: ScriptErrorCode::SigNullDummy,
5481 message: format!(
5482 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5483 )
5484 .into(),
5485 });
5486 }
5487 }
5488 }
5489
5490 let height = block_height.unwrap_or(0);
5493
5494 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5497 let base_script = match (
5498 redeem_script_for_sighash,
5499 prevout_script_pubkeys.get(input_index),
5500 ) {
5501 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5502 (Some(redeem), _) => redeem,
5503 (None, Some(prevout)) => *prevout,
5504 (None, None) => &[],
5505 };
5506 let mut cleaned = base_script.to_vec();
5507 for sig in &signatures {
5508 if !sig.is_empty() {
5509 let pattern = serialize_push_data(sig.as_ref());
5510 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5511 }
5512 }
5513 cleaned
5514 } else {
5515 redeem_script_for_sighash
5517 .map(|s| s.to_vec())
5518 .unwrap_or_else(|| {
5519 prevout_script_pubkeys
5520 .get(input_index)
5521 .map(|p| p.to_vec())
5522 .unwrap_or_default()
5523 })
5524 };
5525
5526 use crate::transaction_hash::{
5527 calculate_transaction_sighash_single_input, SighashType,
5528 };
5529
5530 #[cfg(feature = "production")]
5532 let use_batch = pubkeys.len() * signatures.len() >= 4;
5533
5534 #[cfg(feature = "production")]
5535 let (valid_sigs, _) = if use_batch {
5536 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5538 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5539 if non_empty.is_empty() {
5540 vec![]
5541 } else {
5542 let specs: Vec<(usize, u8, &[u8])> = non_empty
5543 .iter()
5544 .map(|s| {
5545 (
5546 input_index,
5547 s.as_ref()[s.as_ref().len() - 1],
5548 cleaned_script_for_multisig.as_ref(),
5549 )
5550 })
5551 .collect();
5552 crate::transaction_hash::batch_compute_legacy_sighashes(
5553 tx,
5554 prevout_values,
5555 prevout_script_pubkeys,
5556 &specs,
5557 )?
5558 }
5559 } else {
5560 signatures
5561 .iter()
5562 .filter(|s| !s.is_empty())
5563 .map(|sig_bytes| {
5564 let sighash_type =
5565 SighashType::from_byte(sig_bytes[sig_bytes.len() - 1]);
5566 calculate_transaction_sighash_single_input(
5567 tx,
5568 input_index,
5569 &cleaned_script_for_multisig,
5570 prevout_values[input_index],
5571 sighash_type,
5572 sighash_cache,
5573 )
5574 })
5575 .collect::<Result<Vec<_>>>()?
5576 };
5577
5578 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5580 Vec::with_capacity(pubkeys.len() * signatures.len());
5581 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5582 let mut sighash_idx = 0usize;
5583 for (j, sig_bytes) in signatures.iter().enumerate() {
5584 if sig_bytes.is_empty() {
5585 sig_idx_to_sighash_idx.push(usize::MAX);
5586 } else {
5587 sig_idx_to_sighash_idx.push(sighash_idx);
5588 let sh = sighashes[sighash_idx];
5589 sighash_idx += 1;
5590 for pubkey_bytes in &pubkeys {
5591 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5592 }
5593 }
5594 }
5595
5596 let results = if tasks.is_empty() {
5597 vec![]
5598 } else {
5599 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
5600 };
5601
5602 let mut sig_index = 0;
5604 let mut valid_sigs = 0usize;
5605 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5606 if sig_index >= signatures.len() {
5607 break;
5608 }
5609 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5611 sig_index += 1;
5612 }
5613 if sig_index >= signatures.len() {
5614 break;
5615 }
5616 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5617 if sh_idx == usize::MAX {
5618 continue;
5619 }
5620 let task_idx = sh_idx * pubkeys.len() + i;
5621 if task_idx < results.len() && results[task_idx] {
5622 valid_sigs += 1;
5623 sig_index += 1;
5624 }
5625 }
5626
5627 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5629 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5630 for (j, sig_bytes) in signatures.iter().enumerate() {
5631 if sig_bytes.is_empty() {
5632 continue;
5633 }
5634 let sh_idx = sig_idx_to_sighash_idx[j];
5635 if sh_idx == usize::MAX {
5636 continue;
5637 }
5638 let sig_start = sh_idx * pubkeys.len();
5639 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5640 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5641 if !matched {
5642 return Err(ConsensusError::ScriptErrorWithCode {
5643 code: ScriptErrorCode::SigNullFail,
5644 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5645 });
5646 }
5647 }
5648 }
5649 (valid_sigs, ())
5650 } else {
5651 let mut sig_index = 0;
5652 let mut valid_sigs = 0;
5653
5654 for pubkey_bytes in &pubkeys {
5655 if sig_index >= signatures.len() {
5656 break;
5657 }
5658
5659 let signature_bytes = &signatures[sig_index];
5660
5661 if signature_bytes.is_empty() {
5662 continue;
5663 }
5664
5665 let sig_len = signature_bytes.len();
5666 let sighash_byte = signature_bytes[sig_len - 1];
5667 let sighash_type = SighashType::from_byte(sighash_byte);
5668
5669 let sighash = calculate_transaction_sighash_single_input(
5670 tx,
5671 input_index,
5672 &cleaned_script_for_multisig,
5673 prevout_values[input_index],
5674 sighash_type,
5675 #[cfg(feature = "production")]
5676 sighash_cache,
5677 )?;
5678
5679 #[cfg(feature = "production")]
5680 let is_valid = signature::with_secp_context(|secp| {
5681 signature::verify_signature(
5682 secp,
5683 pubkey_bytes,
5684 signature_bytes,
5685 &sighash,
5686 flags,
5687 height,
5688 network,
5689 sigversion,
5690 )
5691 })?;
5692
5693 #[cfg(not(feature = "production"))]
5694 let is_valid = {
5695 let secp = signature::new_secp();
5696 signature::verify_signature(
5697 &secp,
5698 pubkey_bytes,
5699 signature_bytes,
5700 &sighash,
5701 flags,
5702 height,
5703 network,
5704 sigversion,
5705 )?
5706 };
5707
5708 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5709 if !is_valid
5710 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5711 && !signature_bytes.is_empty()
5712 {
5713 return Err(ConsensusError::ScriptErrorWithCode {
5714 code: ScriptErrorCode::SigNullFail,
5715 message:
5716 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5717 .into(),
5718 });
5719 }
5720
5721 if is_valid {
5722 valid_sigs += 1;
5723 sig_index += 1;
5724 }
5725 }
5726 (valid_sigs, ())
5727 };
5728
5729 #[cfg(not(feature = "production"))]
5730 let (valid_sigs, _) = {
5731 let mut sig_index = 0;
5732 let mut valid_sigs = 0;
5733
5734 for pubkey_bytes in &pubkeys {
5735 if sig_index >= signatures.len() {
5736 break;
5737 }
5738 let signature_bytes = &signatures[sig_index];
5739 if signature_bytes.is_empty() {
5740 continue;
5741 }
5742 let sig_len = signature_bytes.len();
5743 let sighash_type = SighashType::from_byte(signature_bytes[sig_len - 1]);
5744 let sighash = calculate_transaction_sighash_single_input(
5745 tx,
5746 input_index,
5747 &cleaned_script_for_multisig,
5748 prevout_values[input_index],
5749 sighash_type,
5750 #[cfg(feature = "production")]
5751 sighash_cache,
5752 )?;
5753 let secp = signature::new_secp();
5754 let is_valid = signature::verify_signature(
5755 &secp,
5756 pubkey_bytes,
5757 signature_bytes,
5758 &sighash,
5759 flags,
5760 height,
5761 network,
5762 sigversion,
5763 )?;
5764 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5765 if !is_valid
5766 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5767 && !signature_bytes.is_empty()
5768 {
5769 return Err(ConsensusError::ScriptErrorWithCode {
5770 code: ScriptErrorCode::SigNullFail,
5771 message:
5772 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5773 .into(),
5774 });
5775 }
5776 if is_valid {
5777 valid_sigs += 1;
5778 sig_index += 1;
5779 }
5780 }
5781 (valid_sigs, ())
5782 };
5783
5784 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
5786 Ok(true)
5787 }
5788
5789 OP_CHECKMULTISIGVERIFY => {
5791 let ctx_checkmultisig = context::ScriptContext {
5793 tx,
5794 input_index,
5795 prevout_values,
5796 prevout_script_pubkeys,
5797 block_height,
5798 median_time_past,
5799 network,
5800 sigversion,
5801 redeem_script_for_sighash,
5802 script_sig_for_sighash,
5803 tapscript_for_sighash,
5804 tapscript_codesep_pos,
5805 #[cfg(feature = "production")]
5806 schnorr_collector: None,
5807 #[cfg(feature = "production")]
5808 precomputed_bip143,
5809 #[cfg(feature = "production")]
5810 sighash_cache,
5811 };
5812 let result = execute_opcode_with_context_full(
5813 OP_CHECKMULTISIG,
5814 stack,
5815 flags,
5816 &ctx_checkmultisig,
5817 redeem_script_for_sighash,
5818 )?;
5819 if !result {
5820 return Ok(false);
5821 }
5822 if let Some(top) = stack.pop() {
5824 if !cast_to_bool(&top) {
5825 return Ok(false);
5826 }
5827 Ok(true)
5828 } else {
5829 Ok(false)
5830 }
5831 }
5832
5833 OP_CHECKLOCKTIMEVERIFY => {
5838 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
5840 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5841 return Ok(true);
5842 }
5843
5844 use crate::locktime::{check_bip65, decode_locktime_value};
5845
5846 if stack.is_empty() {
5847 return Err(ConsensusError::ScriptErrorWithCode {
5848 code: ScriptErrorCode::InvalidStackOperation,
5849 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
5850 });
5851 }
5852
5853 let locktime_bytes = stack.last().expect("Stack is not empty");
5855 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
5856 Some(v) => v,
5857 None => {
5858 return Err(ConsensusError::ScriptErrorWithCode {
5859 code: ScriptErrorCode::MinimalData,
5860 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
5861 })
5862 }
5863 };
5864
5865 let tx_locktime = tx.lock_time as u32;
5866
5867 if !check_bip65(tx_locktime, locktime_value) {
5869 return Ok(false);
5870 }
5871
5872 let input_seq = if input_index < tx.inputs.len() {
5874 tx.inputs[input_index].sequence
5875 } else {
5876 0xffffffff
5877 };
5878 if input_seq == 0xffffffff {
5879 return Ok(false);
5880 }
5881
5882 Ok(true)
5884 }
5885
5886 OP_CHECKSEQUENCEVERIFY => {
5895 use crate::locktime::{
5896 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
5897 is_sequence_disabled,
5898 };
5899
5900 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
5902 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
5903 return Ok(true);
5904 }
5905
5906 if stack.is_empty() {
5907 return Ok(false);
5908 }
5909
5910 let sequence_bytes = stack.last().expect("Stack is not empty");
5913 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
5914 Some(v) => v,
5915 None => return Ok(false), };
5917
5918 if input_index >= tx.inputs.len() {
5920 return Ok(false);
5921 }
5922 let input_sequence = tx.inputs[input_index].sequence as u32;
5923
5924 if is_sequence_disabled(input_sequence) {
5926 return Ok(true);
5927 }
5928
5929 let type_flag = extract_sequence_type_flag(sequence_value);
5931 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
5932
5933 let input_type_flag = extract_sequence_type_flag(input_sequence);
5935 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
5936
5937 if type_flag != input_type_flag {
5939 return Ok(false);
5940 }
5941
5942 if input_locktime < locktime_mask {
5944 return Ok(false);
5945 }
5946
5947 Ok(true)
5949 }
5950
5951 OP_CHECKTEMPLATEVERIFY => {
5960 #[cfg(not(feature = "ctv"))]
5961 {
5962 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5964 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5965 return Err(ConsensusError::ScriptErrorWithCode {
5966 code: ScriptErrorCode::BadOpcode,
5967 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
5968 });
5969 }
5970 Ok(true) }
5972
5973 #[cfg(feature = "ctv")]
5974 {
5975 use crate::constants::{
5976 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
5977 };
5978
5979 let ctv_activation = match network {
5981 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
5982 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
5983 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
5984 };
5985
5986 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
5987 if !ctv_active {
5988 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5990 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5991 return Err(ConsensusError::ScriptErrorWithCode {
5992 code: ScriptErrorCode::BadOpcode,
5993 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
5994 });
5995 }
5996 return Ok(true); }
5998
5999 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
6001 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
6002 return Ok(true);
6004 }
6005
6006 use crate::bip119::calculate_template_hash;
6007
6008 if stack.is_empty() {
6010 return Err(ConsensusError::ScriptErrorWithCode {
6011 code: ScriptErrorCode::InvalidStackOperation,
6012 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
6013 });
6014 }
6015
6016 let template_hash_bytes = stack.pop().unwrap();
6017
6018 if template_hash_bytes.len() != 32 {
6020 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6023 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6024 return Err(ConsensusError::ScriptErrorWithCode {
6025 code: ScriptErrorCode::InvalidStackOperation,
6026 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
6027 .into(),
6028 });
6029 }
6030 return Ok(true); }
6032
6033 let mut expected_hash = [0u8; 32];
6035 expected_hash.copy_from_slice(&template_hash_bytes);
6036
6037 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
6038 ConsensusError::ScriptErrorWithCode {
6039 code: ScriptErrorCode::TxInvalid,
6040 message: format!("CTV hash calculation failed: {e}").into(),
6041 }
6042 })?;
6043
6044 use crate::crypto::hash_compare::hash_eq;
6046 let matches = hash_eq(&expected_hash, &actual_hash);
6047
6048 if !matches {
6049 return Ok(false); }
6051
6052 Ok(true)
6054 }
6055 }
6056
6057 OP_CHECKSIGFROMSTACK => {
6068 #[cfg(not(feature = "csfs"))]
6069 {
6070 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6073 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6074 return Err(ConsensusError::ScriptErrorWithCode {
6075 code: ScriptErrorCode::BadOpcode,
6076 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
6077 });
6078 }
6079 Ok(true) }
6081
6082 #[cfg(feature = "csfs")]
6083 {
6084 use crate::constants::{
6085 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
6086 };
6087
6088 if sigversion != SigVersion::Tapscript {
6090 return Err(ConsensusError::ScriptErrorWithCode {
6091 code: ScriptErrorCode::BadOpcode,
6092 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
6093 });
6094 }
6095
6096 let csfs_activation = match network {
6098 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
6099 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
6100 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
6101 };
6102
6103 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
6104 if !csfs_active {
6105 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6107 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6108 return Err(ConsensusError::ScriptErrorWithCode {
6109 code: ScriptErrorCode::BadOpcode,
6110 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
6111 });
6112 }
6113 return Ok(true); }
6115
6116 use crate::bip348::verify_signature_from_stack;
6117
6118 if stack.len() < 3 {
6120 return Err(ConsensusError::ScriptErrorWithCode {
6121 code: ScriptErrorCode::InvalidStackOperation,
6122 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
6123 });
6124 }
6125
6126 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
6133 return Err(ConsensusError::ScriptErrorWithCode {
6134 code: ScriptErrorCode::PubkeyType,
6135 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
6136 });
6137 }
6138
6139 if signature_bytes.is_empty() {
6141 stack.push(to_stack_element(&[])); return Ok(true);
6143 }
6144
6145 #[cfg(feature = "production")]
6148 let is_valid = {
6149 verify_signature_from_stack(
6150 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6155 .unwrap_or(false)
6156 };
6157 #[cfg(not(feature = "production"))]
6158 let is_valid = verify_signature_from_stack(
6159 &message_bytes, &pubkey_bytes, &signature_bytes, )
6163 .unwrap_or(false);
6164
6165 if !is_valid {
6166 return Ok(false);
6168 }
6169
6170 stack.push(to_stack_element(&[0x01])); Ok(true)
6177 }
6178 }
6179
6180 _ => execute_opcode_cold(opcode, stack, flags),
6182 }
6183}
6184
6185#[cold]
6187fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6188 execute_opcode(opcode, stack, flags, SigVersion::Base)
6189}
6190
6191#[cfg(feature = "production")]
6206pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6207 (
6208 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6209 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6210 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6211 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6212 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6213 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6214 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6215 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6216 )
6217}
6218
6219#[cfg(all(feature = "production", feature = "benchmarking"))]
6226pub fn clear_script_cache() {
6227 if let Some(cache) = SCRIPT_CACHE.get() {
6228 let mut cache = cache.write().unwrap();
6229 cache.clear();
6230 }
6231}
6232
6233#[cfg(all(feature = "production", feature = "benchmarking"))]
6247pub fn clear_hash_cache() {
6248 crypto_ops::clear_hash_cache();
6249}
6250
6251#[cfg(all(feature = "production", feature = "benchmarking"))]
6264pub fn clear_all_caches() {
6265 clear_script_cache();
6266 clear_hash_cache();
6267}
6268
6269#[cfg(all(feature = "production", feature = "benchmarking"))]
6283pub fn clear_stack_pool() {
6284 STACK_POOL.with(|pool| {
6285 let mut pool = pool.borrow_mut();
6286 pool.clear();
6287 });
6288}
6289
6290#[cfg(all(feature = "production", feature = "benchmarking"))]
6304pub fn reset_benchmarking_state() {
6305 clear_all_caches();
6306 clear_stack_pool();
6307 disable_caching(false); #[cfg(feature = "benchmarking")]
6310 crate::transaction_hash::clear_sighash_templates();
6311}
6312
6313#[cfg(test)]
6314mod tests {
6315 use super::*;
6316
6317 #[test]
6318 fn test_eval_script_simple() {
6319 let script = vec![OP_1]; let mut stack = Vec::new();
6321
6322 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6323 assert_eq!(stack.len(), 1);
6324 assert_eq!(stack[0].as_ref(), &[1]);
6325 }
6326
6327 #[test]
6328 fn test_eval_script_overflow() {
6329 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6331
6332 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6333 }
6334
6335 #[test]
6336 fn test_verify_script_simple() {
6337 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());
6348 }
6349
6350 #[test]
6355 fn test_op_0() {
6356 let script = vec![OP_0]; let mut stack = Vec::new();
6358 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6359 assert!(!result); assert_eq!(stack.len(), 1);
6361 assert!(stack[0].is_empty());
6362 }
6363
6364 #[test]
6365 fn test_op_1_to_op_16() {
6366 for i in 1..=16 {
6368 let opcode = 0x50 + i;
6369 let script = vec![opcode];
6370 let mut stack = Vec::new();
6371 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6372 assert!(result);
6373 assert_eq!(stack.len(), 1);
6374 assert_eq!(stack[0].as_ref(), &[i]);
6375 }
6376 }
6377
6378 #[test]
6379 fn test_op_dup() {
6380 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6382 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6383 assert!(!result); assert_eq!(stack.len(), 2);
6385 assert_eq!(stack[0].as_ref(), &[1]);
6386 assert_eq!(stack[1].as_ref(), &[1]);
6387 }
6388
6389 #[test]
6390 fn test_op_dup_empty_stack() {
6391 let script = vec![OP_DUP]; let mut stack = Vec::new();
6393 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6394 assert!(!result);
6395 }
6396
6397 #[test]
6398 fn test_op_hash160() {
6399 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6401 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6402 assert!(result);
6403 assert_eq!(stack.len(), 1);
6404 assert_eq!(stack[0].len(), 20); }
6406
6407 #[test]
6408 fn test_op_hash160_empty_stack() {
6409 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6411 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6412 assert!(!result);
6413 }
6414
6415 #[test]
6416 fn test_op_hash256() {
6417 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6419 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6420 assert!(result);
6421 assert_eq!(stack.len(), 1);
6422 assert_eq!(stack[0].len(), 32); }
6424
6425 #[test]
6426 fn test_op_hash256_empty_stack() {
6427 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6429 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6430 assert!(!result);
6431 }
6432
6433 #[test]
6434 fn test_op_equal() {
6435 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6437 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6438 assert!(result);
6439 assert_eq!(stack.len(), 1);
6440 assert_eq!(stack[0].as_ref(), &[1]); }
6442
6443 #[test]
6444 fn test_op_equal_false() {
6445 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6447 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6448 assert!(!result); assert_eq!(stack.len(), 1);
6450 assert_eq!(stack[0].as_ref(), &[0]); }
6452
6453 #[test]
6454 fn test_op_equal_insufficient_stack() {
6455 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6457 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6458 assert!(
6459 result.is_err(),
6460 "OP_EQUAL with insufficient stack should return error"
6461 );
6462 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6463 assert_eq!(
6464 code,
6465 crate::error::ScriptErrorCode::InvalidStackOperation,
6466 "Should return InvalidStackOperation"
6467 );
6468 }
6469 }
6470
6471 #[test]
6472 fn test_op_verify() {
6473 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6475 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6476 assert!(!result); assert_eq!(stack.len(), 0); }
6479
6480 #[test]
6481 fn test_op_verify_false() {
6482 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6484 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6485 assert!(!result);
6486 }
6487
6488 #[test]
6489 fn test_op_verify_empty_stack() {
6490 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6492 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6493 assert!(!result);
6494 }
6495
6496 #[test]
6497 fn test_op_equalverify() {
6498 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6500 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6501 assert!(!result); assert_eq!(stack.len(), 0); }
6504
6505 #[test]
6506 fn test_op_equalverify_false() {
6507 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6509 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6510 assert!(
6511 result.is_err(),
6512 "OP_EQUALVERIFY with false condition should return error"
6513 );
6514 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6515 assert_eq!(
6516 code,
6517 crate::error::ScriptErrorCode::EqualVerify,
6518 "Should return EqualVerify"
6519 );
6520 }
6521 }
6522
6523 #[test]
6524 fn test_op_checksig() {
6525 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6529 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6530 assert!(!result); assert_eq!(stack.len(), 1);
6532 }
6534
6535 #[test]
6536 fn test_op_checksig_insufficient_stack() {
6537 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6539 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6540 assert!(
6541 result.is_err(),
6542 "OP_CHECKSIG with insufficient stack should return error"
6543 );
6544 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6545 assert_eq!(
6546 code,
6547 crate::error::ScriptErrorCode::InvalidStackOperation,
6548 "Should return InvalidStackOperation"
6549 );
6550 }
6551 }
6552
6553 #[test]
6554 fn test_unknown_opcode() {
6555 let script = vec![0xff]; let mut stack = Vec::new();
6557 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6558 assert!(!result);
6559 }
6560
6561 #[test]
6562 fn test_script_size_limit() {
6563 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6565 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6566 assert!(result.is_err());
6567 }
6568
6569 #[test]
6570 fn test_operation_count_limit() {
6571 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6574 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6575 assert!(result.is_err());
6576 }
6577
6578 #[test]
6579 fn test_stack_underflow_multiple_ops() {
6580 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6582 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6583 assert!(result.is_err(), "Stack underflow should return error");
6584 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6585 assert_eq!(
6586 code,
6587 crate::error::ScriptErrorCode::InvalidStackOperation,
6588 "Should return InvalidStackOperation"
6589 );
6590 }
6591 }
6592
6593 #[test]
6594 fn test_final_stack_empty() {
6595 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6597 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6598 assert!(!result);
6599 }
6600
6601 #[test]
6602 fn test_final_stack_false() {
6603 let script = vec![OP_0]; let mut stack = Vec::new();
6605 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6606 assert!(!result);
6607 }
6608
6609 #[test]
6610 fn test_verify_script_with_witness() {
6611 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6615
6616 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6617 assert!(!result); }
6619
6620 #[test]
6621 fn test_verify_script_failure() {
6622 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_2]; let witness = None;
6625 let flags = 0;
6626
6627 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6628 assert!(!result);
6629 }
6630
6631 #[test]
6636 fn test_op_ifdup_true() {
6637 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6639 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6640 assert!(!result); assert_eq!(stack.len(), 2);
6642 assert_eq!(stack[0].as_ref(), &[1]);
6643 assert_eq!(stack[1].as_ref(), &[1]);
6644 }
6645
6646 #[test]
6647 fn test_op_ifdup_false() {
6648 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6650 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6651 assert!(!result); assert_eq!(stack.len(), 1);
6653 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6654 }
6655
6656 #[test]
6657 fn test_op_depth() {
6658 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6660 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6661 assert!(!result); assert_eq!(stack.len(), 3);
6663 assert_eq!(stack[2].as_ref(), &[2]); }
6665
6666 #[test]
6667 fn test_op_drop() {
6668 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
6670 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6671 assert!(result); assert_eq!(stack.len(), 1);
6673 assert_eq!(stack[0].as_ref(), &[1]);
6674 }
6675
6676 #[test]
6677 fn test_op_drop_empty_stack() {
6678 let script = vec![OP_DROP]; let mut stack = Vec::new();
6680 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6681 assert!(!result);
6682 assert_eq!(stack.len(), 0);
6683 }
6684
6685 #[test]
6686 fn test_op_nip() {
6687 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
6689 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6690 assert!(result); assert_eq!(stack.len(), 1);
6692 assert_eq!(stack[0].as_ref(), &[2]);
6693 }
6694
6695 #[test]
6696 fn test_op_nip_insufficient_stack() {
6697 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
6699 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6700 assert!(!result);
6701 assert_eq!(stack.len(), 1);
6702 }
6703
6704 #[test]
6705 fn test_op_over() {
6706 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
6708 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6709 assert!(!result); assert_eq!(stack.len(), 3);
6711 assert_eq!(stack[0].as_ref(), &[1]);
6712 assert_eq!(stack[1].as_ref(), &[2]);
6713 assert_eq!(stack[2].as_ref(), &[1]);
6714 }
6715
6716 #[test]
6717 fn test_op_over_insufficient_stack() {
6718 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
6720 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6721 assert!(!result);
6722 assert_eq!(stack.len(), 1);
6723 }
6724
6725 #[test]
6726 fn test_op_pick() {
6727 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
6729 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6730 assert!(!result); assert_eq!(stack.len(), 4);
6732 assert_eq!(stack[3].as_ref(), &[2]); }
6734
6735 #[test]
6736 fn test_op_pick_empty_n() {
6737 let script = vec![OP_1, OP_0, OP_PICK];
6739 let mut stack = Vec::new();
6740 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6741 assert!(!result); assert_eq!(stack.len(), 2);
6743 assert_eq!(stack[1].as_ref(), &[1]); }
6745
6746 #[test]
6747 fn test_op_pick_invalid_index() {
6748 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
6750 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6751 assert!(!result);
6752 assert_eq!(stack.len(), 1);
6753 }
6754
6755 #[test]
6756 fn test_op_roll() {
6757 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
6759 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6760 assert!(!result); assert_eq!(stack.len(), 3);
6762 assert_eq!(stack[0].as_ref(), &[1]);
6763 assert_eq!(stack[1].as_ref(), &[3]);
6764 assert_eq!(stack[2].as_ref(), &[2]); }
6766
6767 #[test]
6768 fn test_op_roll_zero_n() {
6769 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
6772 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6773 assert!(result); assert_eq!(stack.len(), 1);
6775 assert_eq!(stack[0].as_ref(), &[1]);
6776 }
6777
6778 #[test]
6779 fn test_op_roll_invalid_index() {
6780 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
6782 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6783 assert!(!result);
6784 assert_eq!(stack.len(), 1);
6785 }
6786
6787 #[test]
6788 fn test_op_rot() {
6789 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
6791 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6792 assert!(!result); assert_eq!(stack.len(), 3);
6794 assert_eq!(stack[0].as_ref(), &[2]);
6795 assert_eq!(stack[1].as_ref(), &[3]);
6796 assert_eq!(stack[2].as_ref(), &[1]);
6797 }
6798
6799 #[test]
6800 fn test_op_rot_insufficient_stack() {
6801 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
6803 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6804 assert!(!result);
6805 assert_eq!(stack.len(), 2);
6806 }
6807
6808 #[test]
6809 fn test_op_swap() {
6810 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
6812 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6813 assert!(!result); assert_eq!(stack.len(), 2);
6815 assert_eq!(stack[0].as_ref(), &[2]);
6816 assert_eq!(stack[1].as_ref(), &[1]);
6817 }
6818
6819 #[test]
6820 fn test_op_swap_insufficient_stack() {
6821 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
6823 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6824 assert!(!result);
6825 assert_eq!(stack.len(), 1);
6826 }
6827
6828 #[test]
6829 fn test_op_tuck() {
6830 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
6832 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6833 assert!(!result); assert_eq!(stack.len(), 3);
6835 assert_eq!(stack[0].as_ref(), &[2]);
6836 assert_eq!(stack[1].as_ref(), &[1]);
6837 assert_eq!(stack[2].as_ref(), &[2]);
6838 }
6839
6840 #[test]
6841 fn test_op_tuck_insufficient_stack() {
6842 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
6844 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6845 assert!(!result);
6846 assert_eq!(stack.len(), 1);
6847 }
6848
6849 #[test]
6850 fn test_op_2drop() {
6851 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
6853 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6854 assert!(result); assert_eq!(stack.len(), 1);
6856 assert_eq!(stack[0].as_ref(), &[1]);
6857 }
6858
6859 #[test]
6860 fn test_op_2drop_insufficient_stack() {
6861 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
6863 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6864 assert!(!result);
6865 assert_eq!(stack.len(), 1);
6866 }
6867
6868 #[test]
6869 fn test_op_2dup() {
6870 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
6872 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6873 assert!(!result); assert_eq!(stack.len(), 4);
6875 assert_eq!(stack[0].as_ref(), &[1]);
6876 assert_eq!(stack[1].as_ref(), &[2]);
6877 assert_eq!(stack[2].as_ref(), &[1]);
6878 assert_eq!(stack[3].as_ref(), &[2]);
6879 }
6880
6881 #[test]
6882 fn test_op_2dup_insufficient_stack() {
6883 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
6885 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6886 assert!(!result);
6887 assert_eq!(stack.len(), 1);
6888 }
6889
6890 #[test]
6891 fn test_op_3dup() {
6892 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
6894 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6895 assert!(!result); assert_eq!(stack.len(), 6);
6897 assert_eq!(stack[0].as_ref(), &[1]);
6898 assert_eq!(stack[1].as_ref(), &[2]);
6899 assert_eq!(stack[2].as_ref(), &[3]);
6900 assert_eq!(stack[3].as_ref(), &[1]);
6901 assert_eq!(stack[4].as_ref(), &[2]);
6902 assert_eq!(stack[5].as_ref(), &[3]);
6903 }
6904
6905 #[test]
6906 fn test_op_3dup_insufficient_stack() {
6907 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
6909 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6910 assert!(!result);
6911 assert_eq!(stack.len(), 2);
6912 }
6913
6914 #[test]
6915 fn test_op_2over() {
6916 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
6918 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6919 assert!(!result); assert_eq!(stack.len(), 6);
6921 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
6923 }
6924
6925 #[test]
6926 fn test_op_2over_insufficient_stack() {
6927 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
6929 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6930 assert!(!result);
6931 assert_eq!(stack.len(), 3);
6932 }
6933
6934 #[test]
6935 fn test_op_2rot() {
6936 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
6938 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6939 assert!(!result); assert_eq!(stack.len(), 6);
6941 assert_eq!(stack[4].as_ref(), &[2]); assert_eq!(stack[5].as_ref(), &[1]);
6943 }
6944
6945 #[test]
6946 fn test_op_2rot_insufficient_stack() {
6947 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
6949 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6950 assert!(!result);
6951 assert_eq!(stack.len(), 4);
6952 }
6953
6954 #[test]
6955 fn test_op_2swap() {
6956 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
6958 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6959 assert!(!result); assert_eq!(stack.len(), 4);
6961 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
6963 assert_eq!(stack[2].as_ref(), &[1]);
6964 assert_eq!(stack[3].as_ref(), &[2]);
6965 }
6966
6967 #[test]
6968 fn test_op_2swap_insufficient_stack() {
6969 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
6971 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6972 assert!(!result);
6973 assert_eq!(stack.len(), 3);
6974 }
6975
6976 #[test]
6977 fn test_op_size() {
6978 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
6980 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6981 assert!(!result); assert_eq!(stack.len(), 2);
6983 assert_eq!(stack[0].as_ref(), &[1]);
6984 assert_eq!(stack[1].as_ref(), &[1]); }
6986
6987 #[test]
6988 fn test_op_size_empty_stack() {
6989 let script = vec![OP_SIZE]; let mut stack = Vec::new();
6991 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6992 assert!(!result);
6993 assert_eq!(stack.len(), 0);
6994 }
6995
6996 #[test]
6997 fn test_op_return() {
6998 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
7000 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7001 assert!(!result); assert_eq!(stack.len(), 1);
7003 }
7004
7005 #[test]
7006 fn test_op_checksigverify() {
7007 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7009 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7010 assert!(!result); assert_eq!(stack.len(), 0);
7012 }
7013
7014 #[test]
7015 fn test_op_checksigverify_insufficient_stack() {
7016 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7018 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7019 assert!(!result);
7020 assert_eq!(stack.len(), 1);
7021 }
7022
7023 #[test]
7024 fn test_unknown_opcode_comprehensive() {
7025 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
7027 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7028 assert!(!result); assert_eq!(stack.len(), 1);
7030 }
7031
7032 #[test]
7033 fn test_verify_signature_invalid_pubkey() {
7034 let secp = signature::new_secp();
7035 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
7038 let result = signature::verify_signature(
7039 &secp,
7040 &invalid_pubkey,
7041 &signature,
7042 &dummy_hash,
7043 0,
7044 0,
7045 crate::types::Network::Regtest,
7046 SigVersion::Base,
7047 );
7048 assert!(!result.unwrap_or(false));
7049 }
7050
7051 #[test]
7052 fn test_verify_signature_invalid_signature() {
7053 let secp = signature::new_secp();
7054 let pubkey = vec![
7055 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
7056 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
7057 0x5b, 0x16, 0xf8, 0x17, 0x98,
7058 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
7061 let result = signature::verify_signature(
7062 &secp,
7063 &pubkey,
7064 &invalid_signature,
7065 &dummy_hash,
7066 0,
7067 0,
7068 crate::types::Network::Regtest,
7069 SigVersion::Base,
7070 );
7071 assert!(!result.unwrap_or(false));
7072 }
7073
7074 fn minimal_tx_and_prevouts(
7080 script_sig: &[u8],
7081 script_pubkey: &[u8],
7082 ) -> (
7083 crate::types::Transaction,
7084 Vec<i64>,
7085 Vec<crate::types::ByteString>,
7086 ) {
7087 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
7088 let tx = Transaction {
7089 version: 1,
7090 inputs: vec![TransactionInput {
7091 prevout: OutPoint {
7092 hash: [0u8; 32],
7093 index: 0,
7094 },
7095 sequence: 0xffff_ffff,
7096 script_sig: script_sig.to_vec(),
7097 }]
7098 .into(),
7099 outputs: vec![TransactionOutput {
7100 value: 0,
7101 script_pubkey: script_pubkey.to_vec(),
7102 }]
7103 .into(),
7104 lock_time: 0,
7105 };
7106 let prevout_values = vec![0i64];
7107 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
7108 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
7109 (tx, prevout_values, prevout_script_pubkeys_vec)
7110 }
7111
7112 #[test]
7113 fn test_verify_with_context_p2pkh_hash_mismatch() {
7114 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
7118 script_sig.push(sig.len() as u8);
7119 script_sig.extend(&sig);
7120 script_sig.push(pubkey.len() as u8);
7121 script_sig.extend(&pubkey);
7122
7123 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
7124 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
7126 script_pubkey.push(OP_CHECKSIG);
7127
7128 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7129 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7130 let result = verify_script_with_context_full(
7131 &script_sig,
7132 &script_pubkey,
7133 None,
7134 0,
7135 &tx,
7136 0,
7137 &pv,
7138 &psp_refs,
7139 Some(500_000),
7140 None,
7141 crate::types::Network::Mainnet,
7142 SigVersion::Base,
7143 #[cfg(feature = "production")]
7144 None,
7145 None, #[cfg(feature = "production")]
7147 None,
7148 #[cfg(feature = "production")]
7149 None,
7150 #[cfg(feature = "production")]
7151 None,
7152 );
7153 assert!(result.is_ok());
7154 assert!(!result.unwrap());
7155 }
7156
7157 #[test]
7158 fn test_verify_with_context_p2sh_hash_mismatch() {
7159 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7162 script_sig.push(redeem.len() as u8);
7163 script_sig.extend(&redeem);
7164
7165 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7166 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7168
7169 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7170 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7171 let result = verify_script_with_context_full(
7172 &script_sig,
7173 &script_pubkey,
7174 None,
7175 0x01, &tx,
7177 0,
7178 &pv,
7179 &psp_refs,
7180 Some(500_000),
7181 None,
7182 crate::types::Network::Mainnet,
7183 SigVersion::Base,
7184 #[cfg(feature = "production")]
7185 None,
7186 None, #[cfg(feature = "production")]
7188 None,
7189 #[cfg(feature = "production")]
7190 None,
7191 #[cfg(feature = "production")]
7192 None,
7193 );
7194 assert!(result.is_ok());
7195 assert!(!result.unwrap());
7196 }
7197
7198 #[test]
7199 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7200 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7202 script_pubkey.extend(&[0u8; 20]);
7203 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7205 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7206 let empty: Vec<u8> = vec![];
7207 let result = verify_script_with_context_full(
7208 &empty,
7209 &script_pubkey,
7210 Some(&witness),
7211 0,
7212 &tx,
7213 0,
7214 &pv,
7215 &psp_refs,
7216 Some(500_000),
7217 None,
7218 crate::types::Network::Mainnet,
7219 SigVersion::Base,
7220 #[cfg(feature = "production")]
7221 None,
7222 None, #[cfg(feature = "production")]
7224 None,
7225 #[cfg(feature = "production")]
7226 None,
7227 #[cfg(feature = "production")]
7228 None,
7229 );
7230 assert!(result.is_ok());
7231 assert!(!result.unwrap());
7232 }
7233
7234 #[test]
7235 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7236 let witness_script = vec![OP_1];
7238 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7239 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7241 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7242 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7243 let empty: Vec<u8> = vec![];
7244 let result = verify_script_with_context_full(
7245 &empty,
7246 &script_pubkey,
7247 Some(&witness),
7248 0,
7249 &tx,
7250 0,
7251 &pv,
7252 &psp_refs,
7253 Some(500_000),
7254 None,
7255 crate::types::Network::Mainnet,
7256 SigVersion::Base,
7257 #[cfg(feature = "production")]
7258 None,
7259 None, #[cfg(feature = "production")]
7261 None,
7262 #[cfg(feature = "production")]
7263 None,
7264 #[cfg(feature = "production")]
7265 None,
7266 );
7267 assert!(result.is_ok());
7268 assert!(!result.unwrap());
7269 }
7270
7271 #[test]
7272 #[cfg(feature = "production")]
7273 fn test_p2wsh_multisig_fast_path() {
7274 use crate::constants::BIP147_ACTIVATION_MAINNET;
7276 use crate::crypto::OptimizedSha256;
7277
7278 let pk1 = [0x02u8; 33];
7279 let pk2 = [0x03u8; 33];
7280 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7282 witness_script.extend_from_slice(&pk2);
7283 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7287 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7288 script_pubkey.extend_from_slice(&wsh_hash);
7289
7290 let witness: Vec<Vec<u8>> = vec![
7291 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7295 ];
7296
7297 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7298 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7299 let empty: Vec<u8> = vec![];
7300 let result = verify_script_with_context_full(
7301 &empty,
7302 &script_pubkey,
7303 Some(&witness),
7304 0x810, &tx,
7306 0,
7307 &pv,
7308 &psp_refs,
7309 Some(BIP147_ACTIVATION_MAINNET + 1),
7310 None,
7311 crate::types::Network::Mainnet,
7312 SigVersion::Base,
7313 #[cfg(feature = "production")]
7314 None,
7315 None, #[cfg(feature = "production")]
7317 None,
7318 #[cfg(feature = "production")]
7319 None,
7320 #[cfg(feature = "production")]
7321 None,
7322 );
7323 assert!(result.is_ok());
7324 assert!(!result.unwrap());
7325 }
7326}
7327
7328#[cfg(test)]
7329#[allow(unused_doc_comments)]
7330mod property_tests {
7331 use super::*;
7332 use proptest::prelude::*;
7333
7334 proptest! {
7339 #[test]
7340 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7341 let mut stack = Vec::new();
7342 let flags = 0u32;
7343
7344 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7345
7346 if script.len() > MAX_SCRIPT_OPS * 2 {
7354 prop_assert!(result.is_err() || !result.unwrap(),
7357 "Very long scripts should fail or return false");
7358 }
7359 }
7361 }
7362
7363 proptest! {
7368 #[test]
7369 fn prop_verify_script_deterministic(
7370 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7371 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7372 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7373 flags in any::<u32>()
7374 ) {
7375 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7376 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7377
7378 assert_eq!(result1.is_ok(), result2.is_ok());
7379 if result1.is_ok() && result2.is_ok() {
7380 assert_eq!(result1.unwrap(), result2.unwrap());
7381 }
7382 }
7383 }
7384
7385 proptest! {
7390 #[test]
7391 fn prop_execute_opcode_no_panic(
7392 opcode in any::<u8>(),
7393 stack_items in prop::collection::vec(
7394 prop::collection::vec(any::<u8>(), 0..5),
7395 0..10
7396 ),
7397 flags in any::<u32>()
7398 ) {
7399 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7400 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7401
7402 match result {
7405 Ok(success) => {
7406 let _ = success;
7408 },
7409 Err(_) => {
7410 }
7413 }
7414
7415 assert!(stack.len() <= MAX_STACK_SIZE);
7417 }
7418 }
7419
7420 proptest! {
7427 #[test]
7428 fn prop_stack_operations_bounds(
7429 opcode in any::<u8>(),
7430 stack_items in prop::collection::vec(
7431 prop::collection::vec(any::<u8>(), 0..3),
7432 0..5
7433 ),
7434 flags in any::<u32>()
7435 ) {
7436 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7437 let initial_len = stack.len();
7438
7439 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7440
7441 assert!(stack.len() <= MAX_STACK_SIZE);
7443
7444 if result.is_ok() && result.unwrap() {
7446 match opcode {
7448 OP_0 | OP_1..=OP_16 => {
7449 assert!(stack.len() == initial_len + 1);
7451 },
7452 OP_DUP => {
7453 if initial_len > 0 {
7455 assert!(stack.len() == initial_len + 1);
7456 }
7457 },
7458 OP_3DUP => {
7459 if initial_len >= 3 {
7461 assert!(stack.len() == initial_len + 3);
7462 }
7463 },
7464 OP_2OVER => {
7465 if initial_len >= 4 {
7467 assert!(stack.len() == initial_len + 2);
7468 }
7469 },
7470 OP_DROP | OP_NIP | OP_2DROP => {
7471 assert!(stack.len() <= initial_len);
7473 },
7474 _ => {
7475 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7478 }
7479 }
7480 }
7481 }
7482 }
7483
7484 proptest! {
7489 #[test]
7490 fn prop_hash_operations_deterministic(
7491 input in prop::collection::vec(any::<u8>(), 0..10)
7492 ) {
7493 let elem = to_stack_element(&input);
7494 let mut stack1 = vec![elem.clone()];
7495 let mut stack2 = vec![elem];
7496
7497 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());
7501 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7502 assert_eq!(val1, val2);
7503 if val1 {
7504 assert_eq!(stack1, stack2);
7505 }
7506 }
7507 }
7508 }
7509
7510 proptest! {
7515 #[test]
7516 fn prop_equality_operations_symmetric(
7517 a in prop::collection::vec(any::<u8>(), 0..5),
7518 b in prop::collection::vec(any::<u8>(), 0..5)
7519 ) {
7520 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7521 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7522
7523 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());
7527 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7528 assert_eq!(val1, val2);
7529 if val1 {
7530 assert_eq!(stack1.len(), stack2.len());
7532 if !stack1.is_empty() && !stack2.is_empty() {
7533 assert_eq!(stack1[0], stack2[0]);
7534 }
7535 }
7536 }
7537 }
7538 }
7539
7540 proptest! {
7545 #[test]
7546 fn prop_script_execution_terminates(
7547 script in prop::collection::vec(any::<u8>(), 0..50)
7548 ) {
7549 let mut stack = Vec::new();
7550 let flags = 0u32;
7551
7552 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7554
7555 assert!(result.is_ok() || result.is_err());
7557
7558 assert!(stack.len() <= MAX_STACK_SIZE);
7560 }
7561 }
7562}