1#![allow(
5 clippy::declare_interior_mutable_const, clippy::type_complexity,
7 clippy::too_many_arguments,
8 clippy::needless_return, )]
10mod arithmetic;
17mod context;
18mod control_flow;
19mod crypto_ops;
20mod signature;
21mod stack;
22
23pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
24pub use stack::{cast_to_bool, to_stack_element, StackElement};
25
26use crate::constants::*;
27use crate::crypto::OptimizedSha256;
28use crate::error::{ConsensusError, Result, ScriptErrorCode};
29use crate::opcodes::*;
30use crate::types::*;
31use blvm_spec_lock::spec_locked;
32use digest::Digest;
33use ripemd::Ripemd160;
34
35#[cfg(feature = "production")]
37use crate::optimizations::{precomputed_constants, prefetch};
38
39#[cold]
41#[allow(dead_code)]
42fn make_operation_limit_error() -> ConsensusError {
43 ConsensusError::ScriptErrorWithCode {
44 code: ScriptErrorCode::OpCount,
45 message: "Operation limit exceeded".into(),
46 }
47}
48
49#[cold]
50fn make_stack_overflow_error() -> ConsensusError {
51 ConsensusError::ScriptErrorWithCode {
52 code: ScriptErrorCode::StackSize,
53 message: "Stack overflow".into(),
54 }
55}
56
57#[cfg(feature = "production")]
58use std::collections::VecDeque;
59#[cfg(feature = "production")]
60use std::sync::{
61 atomic::{AtomicBool, AtomicU64, Ordering},
62 OnceLock, RwLock,
63};
64#[cfg(feature = "production")]
65use std::thread_local;
66
67#[cfg(feature = "production")]
73static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
74
75#[cfg(feature = "production")]
78const SIG_CACHE_SHARDS: usize = 32;
79
80#[cfg(feature = "production")]
81const SIG_CACHE_SHARD: OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>> = OnceLock::new();
82
83#[cfg(feature = "production")]
84static SIG_CACHE: [OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>>; SIG_CACHE_SHARDS] =
85 [SIG_CACHE_SHARD; SIG_CACHE_SHARDS];
86
87#[cfg(feature = "production")]
89fn sig_cache_size() -> usize {
90 std::env::var("BLVM_SIG_CACHE_ENTRIES")
91 .ok()
92 .and_then(|s| s.parse().ok())
93 .filter(|&n: &usize| n > 0 && n <= 1_000_000)
94 .unwrap_or(500_000)
95}
96
97#[cfg(feature = "production")]
98fn sig_cache_shard_index(key: &[u8; 32]) -> usize {
99 let h = (key[0] as usize) | ((key[1] as usize) << 8) | ((key[2] as usize) << 16);
100 h % SIG_CACHE_SHARDS
101}
102
103#[cfg(feature = "production")]
104fn get_sig_cache_shard(key: &[u8; 32]) -> &'static RwLock<lru::LruCache<[u8; 32], bool>> {
105 let idx = sig_cache_shard_index(key);
106 SIG_CACHE[idx].get_or_init(|| {
107 use lru::LruCache;
108 use std::num::NonZeroUsize;
109 let cap = (sig_cache_size() / SIG_CACHE_SHARDS).max(1);
110 RwLock::new(LruCache::new(NonZeroUsize::new(cap).unwrap()))
111 })
112}
113
114#[cfg(feature = "production")]
115thread_local! {
116 static BATCH_PUT_SIG_CACHE_BY_SHARD: std::cell::RefCell<[Vec<([u8; 32], bool)>; SIG_CACHE_SHARDS]> =
117 std::cell::RefCell::new(std::array::from_fn(|_| Vec::new()));
118}
119
120#[cfg(feature = "production")]
122thread_local! {
123 static SOA_BATCH_BUF: std::cell::RefCell<(
124 Vec<[u8; 64]>,
125 Vec<[u8; 32]>,
126 Vec<[u8; 33]>,
127 Vec<usize>,
128 Vec<[u8; 32]>,
129 )> = const { std::cell::RefCell::new((
130 Vec::new(),
131 Vec::new(),
132 Vec::new(),
133 Vec::new(),
134 Vec::new(),
135 )) };
136}
137
138#[cfg(feature = "production")]
139fn batch_put_sig_cache(keys: &[[u8; 32]], results: &[bool]) {
140 BATCH_PUT_SIG_CACHE_BY_SHARD.with(|cell| {
141 let mut by_shard = cell.borrow_mut();
142 for v in by_shard.iter_mut() {
143 v.clear();
144 }
145 for (i, key) in keys.iter().enumerate() {
146 let result = results.get(i).copied().unwrap_or(false);
147 let idx = sig_cache_shard_index(key);
148 by_shard[idx].push((*key, result));
149 }
150 for shard_entries in by_shard.iter() {
151 if shard_entries.is_empty() {
152 continue;
153 }
154 let first_key = &shard_entries[0].0;
155 if let Ok(mut guard) = get_sig_cache_shard(first_key).write() {
156 for (k, v) in shard_entries.iter() {
157 guard.put(*k, *v);
158 }
159 }
160 }
161 });
162}
163
164#[cfg(feature = "production")]
170fn sig_cache_at_collect_enabled() -> bool {
171 use std::sync::OnceLock;
172 static CACHE: OnceLock<bool> = OnceLock::new();
173 *CACHE.get_or_init(|| {
174 std::env::var("BLVM_SIG_CACHE_AT_COLLECT")
175 .map(|s| s == "1" || s.eq_ignore_ascii_case("true"))
176 .unwrap_or(false)
177 })
178}
179
180#[cfg(feature = "production")]
183#[inline(always)]
184fn ecdsa_cache_key(msg: &[u8; 32], pk: &[u8; 33], sig_compact: &[u8; 64], flags: u32) -> [u8; 32] {
185 use siphasher::sip::SipHasher24;
186 use std::hash::{Hash, Hasher};
187 let mut key_input = [0u8; 133];
188 key_input[..32].copy_from_slice(msg);
189 key_input[32..65].copy_from_slice(pk);
190 key_input[65..129].copy_from_slice(sig_compact);
191 key_input[129..133].copy_from_slice(&flags.to_le_bytes());
192 let mut hasher = SipHasher24::new();
193 key_input.hash(&mut hasher);
194 let h = hasher.finish();
195 let mut out = [0u8; 32];
196 out[..8].copy_from_slice(&h.to_le_bytes());
197 out
198}
199
200#[cfg(feature = "production")]
203static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
204#[cfg(feature = "production")]
205static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
206#[cfg(feature = "production")]
207static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
208#[cfg(feature = "production")]
209static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
210#[cfg(feature = "production")]
211static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
212static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
213#[cfg(feature = "production")]
214static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
215#[cfg(feature = "production")]
216static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
217
218#[cfg(feature = "production")]
219fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
220 SCRIPT_CACHE.get_or_init(|| {
221 use lru::LruCache;
225 use std::num::NonZeroUsize;
226 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
227 })
228}
229
230#[cfg(feature = "production")]
235thread_local! {
236 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
237 std::cell::RefCell::new(VecDeque::with_capacity(10));
238}
239
240#[cfg(feature = "production")]
242fn get_pooled_stack() -> Vec<StackElement> {
243 STACK_POOL.with(|pool| {
244 let mut pool = pool.borrow_mut();
245 if let Some(mut stack) = pool.pop_front() {
246 stack.clear();
247 if stack.capacity() < 20 {
248 stack.reserve(20);
249 }
250 stack
251 } else {
252 Vec::with_capacity(20)
253 }
254 })
255}
256
257#[cfg(feature = "production")]
259struct PooledStackGuard(Vec<StackElement>);
260#[cfg(feature = "production")]
261impl Drop for PooledStackGuard {
262 fn drop(&mut self) {
263 return_pooled_stack(std::mem::take(&mut self.0));
264 }
265}
266
267#[cfg(feature = "production")]
269fn return_pooled_stack(mut stack: Vec<StackElement>) {
270 stack.clear();
272
273 STACK_POOL.with(|pool| {
274 let mut pool = pool.borrow_mut();
275 if pool.len() < 10 {
277 pool.push_back(stack);
278 }
279 });
281}
282
283#[cfg(feature = "production")]
288static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
289
290#[cfg(feature = "production")]
306pub fn disable_caching(disabled: bool) {
307 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
308}
309
310#[cfg(feature = "production")]
312fn is_caching_disabled() -> bool {
313 CACHE_DISABLED.load(Ordering::Relaxed)
314}
315
316#[cfg(feature = "production")]
321fn compute_script_cache_key(
322 script_sig: &ByteString,
323 script_pubkey: &[u8],
324 witness: Option<&ByteString>,
325 flags: u32,
326) -> u64 {
327 use std::collections::hash_map::DefaultHasher;
328 use std::hash::{Hash, Hasher};
329
330 let mut hasher = DefaultHasher::new();
331 script_sig.hash(&mut hasher);
332 script_pubkey.hash(&mut hasher);
333 if let Some(w) = witness {
334 w.hash(&mut hasher);
335 }
336 flags.hash(&mut hasher);
337 hasher.finish()
338}
339
340#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub enum SigVersion {
343 Base,
345 WitnessV0,
347 Tapscript,
349}
350
351#[spec_locked("5.2")]
367#[cfg_attr(feature = "production", inline(always))]
368#[cfg_attr(not(feature = "production"), inline)]
369pub fn eval_script(
370 script: &[u8],
371 stack: &mut Vec<StackElement>,
372 flags: u32,
373 sigversion: SigVersion,
374) -> Result<bool> {
375 if stack.capacity() < 20 {
378 stack.reserve(20);
379 }
380 #[cfg(feature = "production")]
381 {
382 eval_script_impl(script, stack, flags, sigversion)
383 }
384 #[cfg(not(feature = "production"))]
385 {
386 eval_script_inner(script, stack, flags, sigversion)
387 }
388}
389#[cfg(feature = "production")]
390fn eval_script_impl(
391 script: &[u8],
392 stack: &mut Vec<StackElement>,
393 flags: u32,
394 sigversion: SigVersion,
395) -> Result<bool> {
396 eval_script_inner(script, stack, flags, sigversion)
397}
398
399#[cfg(not(feature = "production"))]
400#[allow(dead_code)]
401fn eval_script_impl(
402 script: &[u8],
403 stack: &mut Vec<StackElement>,
404 flags: u32,
405 sigversion: SigVersion,
406) -> Result<bool> {
407 eval_script_inner(script, stack, flags, sigversion)
408}
409
410#[inline(always)]
412fn is_push_opcode(opcode: u8) -> bool {
413 opcode <= 0x60
414}
415
416fn eval_script_inner(
417 script: &[u8],
418 stack: &mut Vec<StackElement>,
419 flags: u32,
420 sigversion: SigVersion,
421) -> Result<bool> {
422 use crate::constants::MAX_SCRIPT_SIZE;
423 use crate::error::{ConsensusError, ScriptErrorCode};
424
425 if script.len() > MAX_SCRIPT_SIZE {
426 return Err(ConsensusError::ScriptErrorWithCode {
427 code: ScriptErrorCode::ScriptSize,
428 message: "Script size exceeds maximum".into(),
429 });
430 }
431
432 let mut op_count = 0;
433 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
434 let mut altstack: Vec<StackElement> = Vec::new();
435
436 for opcode in script {
437 let opcode = *opcode;
438
439 let in_false_branch = control_flow::in_false_branch(&control_stack);
440
441 if !is_push_opcode(opcode) {
443 op_count += 1;
444 if op_count > MAX_SCRIPT_OPS {
445 return Err(make_operation_limit_error());
446 }
447 debug_assert!(
448 op_count <= MAX_SCRIPT_OPS,
449 "Operation count ({op_count}) must not exceed MAX_SCRIPT_OPS ({MAX_SCRIPT_OPS})"
450 );
451 }
452
453 if stack.len() + altstack.len() >= MAX_STACK_SIZE {
456 return Err(make_stack_overflow_error());
457 }
458
459 match opcode {
460 OP_IF => {
462 if in_false_branch {
463 control_stack.push(control_flow::ControlBlock::If { executing: false });
464 continue;
465 }
466
467 if stack.is_empty() {
468 return Err(ConsensusError::ScriptErrorWithCode {
469 code: ScriptErrorCode::InvalidStackOperation,
470 message: "OP_IF: empty stack".into(),
471 });
472 }
473 let condition_bytes = stack.pop().unwrap();
474 let condition = cast_to_bool(&condition_bytes);
475
476 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
478 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
479 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
480 && !control_flow::is_minimal_if_condition(&condition_bytes)
481 {
482 return Err(ConsensusError::ScriptErrorWithCode {
483 code: ScriptErrorCode::MinimalIf,
484 message: "OP_IF condition must be minimally encoded".into(),
485 });
486 }
487
488 control_stack.push(control_flow::ControlBlock::If {
489 executing: condition,
490 });
491 }
492 OP_NOTIF => {
494 if in_false_branch {
495 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
496 continue;
497 }
498
499 if stack.is_empty() {
500 return Err(ConsensusError::ScriptErrorWithCode {
501 code: ScriptErrorCode::InvalidStackOperation,
502 message: "OP_NOTIF: empty stack".into(),
503 });
504 }
505 let condition_bytes = stack.pop().unwrap();
506 let condition = cast_to_bool(&condition_bytes);
507
508 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
509 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
510 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
511 && !control_flow::is_minimal_if_condition(&condition_bytes)
512 {
513 return Err(ConsensusError::ScriptErrorWithCode {
514 code: ScriptErrorCode::MinimalIf,
515 message: "OP_NOTIF condition must be minimally encoded".into(),
516 });
517 }
518
519 control_stack.push(control_flow::ControlBlock::NotIf {
520 executing: !condition,
521 });
522 }
523 OP_ELSE => {
525 if let Some(block) = control_stack.last_mut() {
526 match block {
527 control_flow::ControlBlock::If { executing }
528 | control_flow::ControlBlock::NotIf { executing } => {
529 *executing = !*executing;
530 }
531 }
532 } else {
533 return Err(ConsensusError::ScriptErrorWithCode {
534 code: ScriptErrorCode::UnbalancedConditional,
535 message: "OP_ELSE without matching IF/NOTIF".into(),
536 });
537 }
538 }
539 OP_ENDIF => {
541 if control_stack.pop().is_none() {
542 return Err(ConsensusError::ScriptErrorWithCode {
543 code: ScriptErrorCode::UnbalancedConditional,
544 message: "OP_ENDIF without matching IF/NOTIF".into(),
545 });
546 }
547 }
548 OP_TOALTSTACK => {
550 if in_false_branch {
551 continue;
552 }
553 if stack.is_empty() {
554 return Err(ConsensusError::ScriptErrorWithCode {
555 code: ScriptErrorCode::InvalidStackOperation,
556 message: "OP_TOALTSTACK: empty stack".into(),
557 });
558 }
559 altstack.push(stack.pop().unwrap());
560 }
561 OP_FROMALTSTACK => {
563 if in_false_branch {
564 continue;
565 }
566 if altstack.is_empty() {
567 return Err(ConsensusError::ScriptErrorWithCode {
568 code: ScriptErrorCode::InvalidAltstackOperation,
569 message: "OP_FROMALTSTACK: empty altstack".into(),
570 });
571 }
572 stack.push(altstack.pop().unwrap());
573 }
574 _ => {
575 if in_false_branch {
576 continue;
577 }
578
579 if !execute_opcode(opcode, stack, flags, sigversion)? {
580 return Ok(false);
581 }
582
583 debug_assert!(
584 stack.len() + altstack.len() <= MAX_STACK_SIZE,
585 "Combined stack size ({}) must not exceed MAX_STACK_SIZE ({}) after opcode execution",
586 stack.len() + altstack.len(),
587 MAX_STACK_SIZE
588 );
589 }
590 }
591 }
592
593 if !control_stack.is_empty() {
594 return Err(ConsensusError::ScriptErrorWithCode {
595 code: ScriptErrorCode::UnbalancedConditional,
596 message: "Unclosed IF/NOTIF block".into(),
597 });
598 }
599
600 #[cfg(feature = "production")]
603 {
604 if stack.len() == 1 {
605 Ok(cast_to_bool(&stack[0]))
606 } else {
607 Ok(false)
608 }
609 }
610
611 #[cfg(not(feature = "production"))]
612 {
613 Ok(stack.len() == 1 && cast_to_bool(&stack[0]))
614 }
615}
616
617#[spec_locked("5.2")]
627#[cfg_attr(feature = "production", inline(always))]
628#[cfg_attr(not(feature = "production"), inline)]
629pub fn verify_script(
630 script_sig: &ByteString,
631 script_pubkey: &[u8],
632 witness: Option<&ByteString>,
633 flags: u32,
634) -> Result<bool> {
635 let sigversion = SigVersion::Base;
637
638 #[cfg(feature = "production")]
639 {
640 if !is_caching_disabled() {
642 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
643 {
644 let cache = get_script_cache().read().unwrap();
645 if let Some(&cached_result) = cache.peek(&cache_key) {
646 return Ok(cached_result);
647 }
648 }
649 }
650
651 let mut stack = get_pooled_stack();
654 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
655 let result = {
656 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
657 if !is_caching_disabled() {
659 let mut cache = get_script_cache().write().unwrap();
660 cache.put(cache_key, false);
661 }
662 false
663 } else if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
664 if !is_caching_disabled() {
665 let mut cache = get_script_cache().write().unwrap();
666 cache.put(cache_key, false);
667 }
668 false
669 } else if let Some(w) = witness {
670 if !eval_script(w, &mut stack, flags, sigversion)? {
671 if !is_caching_disabled() {
672 let mut cache = get_script_cache().write().unwrap();
673 cache.put(cache_key, false);
674 }
675 false
676 } else {
677 let res = stack.len() == 1 && cast_to_bool(&stack[0]);
678 if !is_caching_disabled() {
679 let mut cache = get_script_cache().write().unwrap();
680 cache.put(cache_key, res);
681 }
682 res
683 }
684 } else {
685 let res = stack.len() == 1 && cast_to_bool(&stack[0]);
686 if !is_caching_disabled() {
687 let mut cache = get_script_cache().write().unwrap();
688 cache.put(cache_key, res);
689 }
690 res
691 }
692 };
693
694 return_pooled_stack(stack);
696
697 Ok(result)
698 }
699
700 #[cfg(not(feature = "production"))]
701 {
702 let mut stack = Vec::with_capacity(20);
704
705 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
707 return Ok(false);
708 }
709
710 if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
712 return Ok(false);
713 }
714
715 if let Some(w) = witness {
717 if !eval_script(w, &mut stack, flags, sigversion)? {
718 return Ok(false);
719 }
720 }
721
722 Ok(stack.len() == 1 && cast_to_bool(&stack[0]))
724 }
725}
726
727#[spec_locked("5.2")]
732#[cfg_attr(feature = "production", inline(always))]
733#[cfg_attr(not(feature = "production"), inline)]
734#[allow(clippy::too_many_arguments)]
735pub fn verify_script_with_context(
736 script_sig: &ByteString,
737 script_pubkey: &[u8],
738 witness: Option<&crate::witness::Witness>,
739 flags: u32,
740 tx: &Transaction,
741 input_index: usize,
742 prevouts: &[TransactionOutput],
743 network: crate::types::Network,
744) -> Result<bool> {
745 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
747 let prevout_script_pubkeys: Vec<&[u8]> =
748 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
749
750 let sigversion = SigVersion::Base;
752 verify_script_with_context_full(
753 script_sig,
754 script_pubkey,
755 witness,
756 flags,
757 tx,
758 input_index,
759 &prevout_values,
760 &prevout_script_pubkeys,
761 None, None, network,
764 sigversion,
765 #[cfg(feature = "production")]
766 None, None, #[cfg(feature = "production")]
769 None, #[cfg(feature = "production")]
771 None, #[cfg(feature = "production")]
773 None, )
775}
776
777#[spec_locked("5.2")]
788#[allow(clippy::too_many_arguments)]
789#[cfg_attr(feature = "production", inline(always))]
790#[cfg_attr(not(feature = "production"), inline)]
791#[cfg(feature = "production")]
798#[allow(clippy::too_many_arguments)]
799pub fn try_verify_p2pk_fast_path(
800 script_sig: &ByteString,
801 script_pubkey: &[u8],
802 flags: u32,
803 tx: &Transaction,
804 input_index: usize,
805 prevout_values: &[i64],
806 prevout_script_pubkeys: &[&[u8]],
807 block_height: Option<u64>,
808 network: crate::types::Network,
809 #[cfg(feature = "production")] sighash_cache: Option<
810 &crate::transaction_hash::SighashMidstateCache,
811 >,
812) -> Option<Result<bool>> {
813 let len = script_pubkey.len();
816 if len != 35 && len != 67 {
817 return None;
818 }
819 if script_pubkey[len - 1] != OP_CHECKSIG {
820 return None;
821 }
822 let pubkey_len = len - 2; if pubkey_len != 33 && pubkey_len != 65 {
824 return None;
825 }
826 if script_pubkey[0] != 0x21 && script_pubkey[0] != 0x41 {
827 return None; }
829 let pubkey_bytes = &script_pubkey[1..(len - 1)];
830
831 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
832 if signature_bytes.is_empty() {
833 return Some(Ok(false));
834 }
835
836 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
838 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
839 let sighash_type = SighashType::from_byte(sighash_byte);
840 let deleted_storage;
841 let script_code: &[u8] = if script_pubkey.len() < 71 {
842 script_pubkey
843 } else {
844 let pattern = serialize_push_data(signature_bytes);
845 deleted_storage = find_and_delete(script_pubkey, &pattern);
846 deleted_storage.as_ref()
847 };
848 let sighash = match calculate_transaction_sighash_single_input(
849 tx,
850 input_index,
851 script_code,
852 prevout_values[input_index],
853 sighash_type,
854 #[cfg(feature = "production")]
855 sighash_cache,
856 ) {
857 Ok(h) => h,
858 Err(e) => return Some(Err(e)),
859 };
860
861 let height = block_height.unwrap_or(0);
862 let is_valid = signature::with_secp_context(|secp| {
863 signature::verify_signature(
864 secp,
865 pubkey_bytes,
866 signature_bytes,
867 &sighash,
868 flags,
869 height,
870 network,
871 SigVersion::Base,
872 )
873 });
874 Some(is_valid)
875}
876
877#[cfg(feature = "production")]
880#[allow(clippy::too_many_arguments)]
881pub fn try_verify_p2pkh_fast_path(
882 script_sig: &ByteString,
883 script_pubkey: &[u8],
884 flags: u32,
885 tx: &Transaction,
886 input_index: usize,
887 prevout_values: &[i64],
888 prevout_script_pubkeys: &[&[u8]],
889 block_height: Option<u64>,
890 network: crate::types::Network,
891 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
892 #[cfg(feature = "production")] sighash_cache: Option<
893 &crate::transaction_hash::SighashMidstateCache,
894 >,
895 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
896) -> Option<Result<bool>> {
897 #[cfg(all(feature = "production", feature = "profile"))]
898 let _t_entry = std::time::Instant::now();
899 if script_pubkey.len() != 25 {
901 return None;
902 }
903 if script_pubkey[0] != OP_DUP
904 || script_pubkey[1] != OP_HASH160
905 || script_pubkey[2] != PUSH_20_BYTES
906 || script_pubkey[23] != OP_EQUALVERIFY
907 || script_pubkey[24] != OP_CHECKSIG
908 {
909 return None;
910 }
911 let expected_hash = &script_pubkey[3..23];
912
913 #[cfg(all(feature = "production", feature = "profile"))]
914 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
915 #[cfg(all(feature = "production", feature = "profile"))]
916 let _t_parse = std::time::Instant::now();
917 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
918 #[cfg(all(feature = "production", feature = "profile"))]
919 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
920
921 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
923 return Some(Ok(false));
924 }
925 if signature_bytes.is_empty() {
927 return Some(Ok(false));
928 }
929
930 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
932 Some(h) => h,
933 None => {
934 #[cfg(all(feature = "production", feature = "profile"))]
935 let _t_hash = std::time::Instant::now();
936 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
937 let h = Ripemd160::digest(sha256_hash);
938 #[cfg(all(feature = "production", feature = "profile"))]
939 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
940 h.into()
941 }
942 };
943 if &pubkey_hash[..] != expected_hash {
944 return Some(Ok(false));
945 }
946
947 use crate::transaction_hash::SighashType;
950 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
951 let sighash_type = SighashType::from_byte(sighash_byte);
952 let deleted_storage;
953 let script_code: &[u8] = if script_pubkey.len() < 71 {
954 script_pubkey
955 } else {
956 let pattern = serialize_push_data(signature_bytes);
957 deleted_storage = find_and_delete(script_pubkey, &pattern);
958 deleted_storage.as_ref()
959 };
960 let sighash = {
961 #[cfg(feature = "production")]
962 {
963 if let Some(precomp) = precomputed_sighash_all {
964 precomp
965 } else {
966 crate::transaction_hash::compute_legacy_sighash_nocache(
967 tx,
968 input_index,
969 script_code,
970 sighash_byte,
971 )
972 }
973 }
974 #[cfg(not(feature = "production"))]
975 {
976 match calculate_transaction_sighash_single_input(
977 tx,
978 input_index,
979 script_code,
980 prevout_values[input_index],
981 sighash_type,
982 ) {
983 Ok(h) => h,
984 Err(e) => return Some(Err(e)),
985 }
986 }
987 };
988
989 #[cfg(all(feature = "production", feature = "profile"))]
990 let _t_secp = std::time::Instant::now();
991 let height = block_height.unwrap_or(0);
992 let is_valid: Result<bool> = {
993 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
994 if flags & 0x04 != 0
995 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
996 .unwrap_or(false)
997 {
998 Ok(false)
999 } else if flags & 0x02 != 0 {
1000 let base_sighash = sighash_byte & !0x80;
1001 if !(0x01..=0x03).contains(&base_sighash) {
1002 Ok(false)
1003 } else if pubkey_bytes.len() == 33 {
1004 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
1005 Ok(false)
1006 } else {
1007 let strict_der = flags & 0x04 != 0;
1008 let enforce_low_s = flags & 0x08 != 0;
1009 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1010 der_sig,
1011 pubkey_bytes,
1012 &sighash,
1013 strict_der,
1014 enforce_low_s,
1015 )
1016 .unwrap_or(false))
1017 }
1018 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1019 let strict_der = flags & 0x04 != 0;
1020 let enforce_low_s = flags & 0x08 != 0;
1021 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1022 der_sig,
1023 pubkey_bytes,
1024 &sighash,
1025 strict_der,
1026 enforce_low_s,
1027 )
1028 .unwrap_or(false))
1029 } else {
1030 Ok(false)
1031 }
1032 } else {
1033 let strict_der = flags & 0x04 != 0;
1034 let enforce_low_s = flags & 0x08 != 0;
1035 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1036 der_sig,
1037 pubkey_bytes,
1038 &sighash,
1039 strict_der,
1040 enforce_low_s,
1041 )
1042 .unwrap_or(false))
1043 }
1044 };
1045 #[cfg(all(feature = "production", feature = "profile"))]
1046 {
1047 let ns = _t_secp.elapsed().as_nanos() as u64;
1048 crate::script_profile::add_p2pkh_collect_ns(ns);
1049 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1050 }
1051 Some(is_valid)
1052}
1053
1054#[cfg(feature = "production")]
1060#[inline]
1061pub fn verify_p2pkh_inline(
1062 script_sig: &[u8],
1063 script_pubkey: &[u8],
1064 flags: u32,
1065 tx: &Transaction,
1066 input_index: usize,
1067 height: u64,
1068 network: crate::types::Network,
1069 precomputed_sighash_all: Option<[u8; 32]>,
1070) -> Result<bool> {
1071 #[cfg(feature = "profile")]
1072 let _t0 = std::time::Instant::now();
1073
1074 let expected_hash = &script_pubkey[3..23];
1075
1076 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1077 Some(pair) => pair,
1078 None => return Ok(false),
1079 };
1080
1081 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1082 return Ok(false);
1083 }
1084
1085 #[cfg(feature = "profile")]
1086 let _t_hash = std::time::Instant::now();
1087
1088 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1089 let pubkey_hash: [u8; 20] = Ripemd160::digest(sha256_hash).into();
1090 if &pubkey_hash[..] != expected_hash {
1091 return Ok(false);
1092 }
1093
1094 #[cfg(feature = "profile")]
1095 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1096
1097 #[cfg(feature = "profile")]
1098 let _t_sighash = std::time::Instant::now();
1099
1100 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1101 let sighash = if let Some(precomp) = precomputed_sighash_all {
1102 precomp
1103 } else {
1104 crate::transaction_hash::compute_legacy_sighash_buffered(
1105 tx,
1106 input_index,
1107 script_pubkey,
1108 sighash_byte,
1109 )
1110 };
1111
1112 #[cfg(feature = "profile")]
1113 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1114
1115 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1116 let strict_der = flags & 0x04 != 0;
1117 let enforce_low_s = flags & 0x08 != 0;
1118
1119 if strict_der
1120 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1121 .unwrap_or(false)
1122 {
1123 return Ok(false);
1124 }
1125
1126 if flags & 0x02 != 0 {
1127 let sighash_base = sighash_byte & !0x80;
1128 if !(0x01..=0x03).contains(&sighash_base) {
1129 return Ok(false);
1130 }
1131 match pubkey_bytes.len() {
1132 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1133 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1134 33 | 65 => {}
1135 _ => return Ok(false),
1136 }
1137 }
1138
1139 #[cfg(feature = "profile")]
1140 let _t_secp = std::time::Instant::now();
1141
1142 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1143 der_sig,
1144 pubkey_bytes,
1145 &sighash,
1146 strict_der,
1147 enforce_low_s,
1148 )
1149 .unwrap_or(false);
1150
1151 #[cfg(feature = "profile")]
1152 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1153
1154 #[cfg(feature = "profile")]
1155 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1156
1157 Ok(result)
1158}
1159
1160#[cfg(feature = "production")]
1162#[inline]
1163pub fn verify_p2pk_inline(
1164 script_sig: &[u8],
1165 script_pubkey: &[u8],
1166 flags: u32,
1167 tx: &Transaction,
1168 input_index: usize,
1169 height: u64,
1170 network: crate::types::Network,
1171) -> Result<bool> {
1172 let pk_len = script_pubkey.len() - 2; let pubkey_bytes = &script_pubkey[1..1 + pk_len];
1174
1175 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1176 Some(s) => s,
1177 None => return Ok(false),
1178 };
1179 if signature_bytes.is_empty() {
1180 return Ok(false);
1181 }
1182
1183 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1184 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_buffered(
1187 tx,
1188 input_index,
1189 script_code,
1190 sighash_byte,
1191 );
1192
1193 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1194 let strict_der = flags & 0x04 != 0;
1195 let enforce_low_s = flags & 0x08 != 0;
1196
1197 if strict_der
1198 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1199 .unwrap_or(false)
1200 {
1201 return Ok(false);
1202 }
1203
1204 if flags & 0x02 != 0 {
1205 let sighash_base = sighash_byte & !0x80;
1206 if !(0x01..=0x03).contains(&sighash_base) {
1207 return Ok(false);
1208 }
1209 match pubkey_bytes.len() {
1210 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1211 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1212 33 | 65 => {}
1213 _ => return Ok(false),
1214 }
1215 }
1216
1217 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1218 der_sig,
1219 pubkey_bytes,
1220 &sighash,
1221 strict_der,
1222 enforce_low_s,
1223 )
1224 .unwrap_or(false))
1225}
1226
1227#[allow(clippy::too_many_arguments)]
1231fn try_verify_p2sh_multisig_fast_path(
1232 script_sig: &ByteString,
1233 script_pubkey: &[u8],
1234 flags: u32,
1235 tx: &Transaction,
1236 input_index: usize,
1237 prevout_values: &[i64],
1238 prevout_script_pubkeys: &[&[u8]],
1239 block_height: Option<u64>,
1240 network: crate::types::Network,
1241 #[cfg(feature = "production")] sighash_cache: Option<
1242 &crate::transaction_hash::SighashMidstateCache,
1243 >,
1244) -> Option<Result<bool>> {
1245 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1246 if pushes.len() < 2 {
1247 return None;
1248 }
1249 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1250 let expected_hash = &script_pubkey[2..22];
1251 let sha256_hash = OptimizedSha256::new().hash(redeem);
1252 let redeem_hash = Ripemd160::digest(sha256_hash);
1253 if &redeem_hash[..] != expected_hash {
1254 return Some(Ok(false));
1255 }
1256 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1257 let signatures: Vec<&[u8]> = pushes
1258 .iter()
1259 .take(pushes.len() - 1)
1260 .skip(1)
1261 .map(|e| e.as_ref())
1262 .collect();
1263 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1264
1265 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1266 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1267 let height = block_height.unwrap_or(0);
1268 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1269 let activation = match network {
1270 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1271 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1272 crate::types::Network::Regtest => 0,
1273 };
1274 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1275 return Some(Ok(false));
1276 }
1277 }
1278
1279 let mut cleaned = redeem.to_vec();
1280 for sig in &signatures {
1281 if !sig.is_empty() {
1282 let pattern = serialize_push_data(sig);
1283 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1284 }
1285 }
1286
1287 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1288
1289 let mut sig_index = 0;
1290 let mut valid_sigs = 0u8;
1291
1292 for pubkey_bytes in pubkeys {
1293 if sig_index >= signatures.len() {
1294 break;
1295 }
1296 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1297 sig_index += 1;
1298 }
1299 if sig_index >= signatures.len() {
1300 break;
1301 }
1302 let signature_bytes = &signatures[sig_index];
1303 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1304 let sighash_type = SighashType::from_byte(sighash_byte);
1305 let sighash = match calculate_transaction_sighash_single_input(
1306 tx,
1307 input_index,
1308 &cleaned,
1309 prevout_values[input_index],
1310 sighash_type,
1311 #[cfg(feature = "production")]
1312 sighash_cache,
1313 ) {
1314 Ok(h) => h,
1315 Err(e) => return Some(Err(e)),
1316 };
1317
1318 #[cfg(feature = "production")]
1319 let is_valid = signature::with_secp_context(|secp| {
1320 signature::verify_signature(
1321 secp,
1322 pubkey_bytes,
1323 signature_bytes,
1324 &sighash,
1325 flags,
1326 height,
1327 network,
1328 SigVersion::Base,
1329 )
1330 });
1331
1332 #[cfg(not(feature = "production"))]
1333 let is_valid = {
1334 let secp = signature::new_secp();
1335 signature::verify_signature(
1336 &secp,
1337 pubkey_bytes,
1338 signature_bytes,
1339 &sighash,
1340 flags,
1341 height,
1342 network,
1343 SigVersion::Base,
1344 )
1345 };
1346
1347 let is_valid = match is_valid {
1348 Ok(v) => v,
1349 Err(e) => return Some(Err(e)),
1350 };
1351
1352 if is_valid {
1353 valid_sigs += 1;
1354 sig_index += 1;
1355 }
1356 }
1357
1358 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1359 for sig_bytes in &signatures[sig_index..] {
1360 if !sig_bytes.is_empty() {
1361 return Some(Err(ConsensusError::ScriptErrorWithCode {
1362 code: ScriptErrorCode::SigNullFail,
1363 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1364 .into(),
1365 }));
1366 }
1367 }
1368 }
1369
1370 Some(Ok(valid_sigs >= m))
1371}
1372
1373#[allow(clippy::too_many_arguments)]
1376fn try_verify_bare_multisig_fast_path(
1377 script_sig: &ByteString,
1378 script_pubkey: &[u8],
1379 flags: u32,
1380 tx: &Transaction,
1381 input_index: usize,
1382 prevout_values: &[i64],
1383 prevout_script_pubkeys: &[&[u8]],
1384 block_height: Option<u64>,
1385 network: crate::types::Network,
1386 #[cfg(feature = "production")] sighash_cache: Option<
1387 &crate::transaction_hash::SighashMidstateCache,
1388 >,
1389) -> Option<Result<bool>> {
1390 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1391 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1392 if pushes.len() < 2 {
1393 return None;
1394 }
1395 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1396 let signatures: Vec<&[u8]> = pushes[1..].iter().map(|e| e.as_ref()).collect();
1397
1398 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1399 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1400 let height = block_height.unwrap_or(0);
1401 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1402 let activation = match network {
1403 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1404 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1405 crate::types::Network::Regtest => 0,
1406 };
1407 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1408 return Some(Ok(false));
1409 }
1410 }
1411
1412 let mut cleaned = script_pubkey.to_vec();
1413 for sig in &signatures {
1414 if !sig.is_empty() {
1415 let pattern = serialize_push_data(sig);
1416 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1417 }
1418 }
1419
1420 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1421
1422 let mut sig_index = 0;
1423 let mut valid_sigs = 0u8;
1424
1425 for pubkey_bytes in pubkeys {
1426 if sig_index >= signatures.len() {
1427 break;
1428 }
1429 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1430 sig_index += 1;
1431 }
1432 if sig_index >= signatures.len() {
1433 break;
1434 }
1435 let signature_bytes = &signatures[sig_index];
1436 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1437 let sighash_type = SighashType::from_byte(sighash_byte);
1438 let sighash = match calculate_transaction_sighash_single_input(
1439 tx,
1440 input_index,
1441 &cleaned,
1442 prevout_values[input_index],
1443 sighash_type,
1444 #[cfg(feature = "production")]
1445 sighash_cache,
1446 ) {
1447 Ok(h) => h,
1448 Err(e) => return Some(Err(e)),
1449 };
1450
1451 #[cfg(feature = "production")]
1452 let is_valid = signature::with_secp_context(|secp| {
1453 signature::verify_signature(
1454 secp,
1455 pubkey_bytes,
1456 signature_bytes,
1457 &sighash,
1458 flags,
1459 height,
1460 network,
1461 SigVersion::Base,
1462 )
1463 });
1464
1465 #[cfg(not(feature = "production"))]
1466 let is_valid = {
1467 let secp = signature::new_secp();
1468 signature::verify_signature(
1469 &secp,
1470 pubkey_bytes,
1471 signature_bytes,
1472 &sighash,
1473 flags,
1474 height,
1475 network,
1476 SigVersion::Base,
1477 )
1478 };
1479
1480 let is_valid = match is_valid {
1481 Ok(v) => v,
1482 Err(e) => return Some(Err(e)),
1483 };
1484
1485 if is_valid {
1486 valid_sigs += 1;
1487 sig_index += 1;
1488 }
1489 }
1490
1491 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1492 for sig_bytes in &signatures[sig_index..] {
1493 if !sig_bytes.is_empty() {
1494 return Some(Err(ConsensusError::ScriptErrorWithCode {
1495 code: ScriptErrorCode::SigNullFail,
1496 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1497 .into(),
1498 }));
1499 }
1500 }
1501 }
1502
1503 Some(Ok(valid_sigs >= m))
1504}
1505
1506#[cfg(feature = "production")]
1510#[allow(clippy::too_many_arguments)]
1511fn try_verify_p2sh_fast_path(
1512 script_sig: &ByteString,
1513 script_pubkey: &[u8],
1514 flags: u32,
1515 tx: &Transaction,
1516 input_index: usize,
1517 prevout_values: &[i64],
1518 prevout_script_pubkeys: &[&[u8]],
1519 block_height: Option<u64>,
1520 median_time_past: Option<u64>,
1521 network: crate::types::Network,
1522 #[cfg(feature = "production")] sighash_cache: Option<
1523 &crate::transaction_hash::SighashMidstateCache,
1524 >,
1525 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1526) -> Option<Result<bool>> {
1527 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1528 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1529 return None;
1530 }
1531 if script_pubkey.len() != 23
1533 || script_pubkey[0] != OP_HASH160
1534 || script_pubkey[1] != PUSH_20_BYTES
1535 || script_pubkey[22] != OP_EQUAL
1536 {
1537 return None;
1538 }
1539 let expected_hash = &script_pubkey[2..22];
1540
1541 let mut pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1542 if pushes.is_empty() {
1543 return None;
1544 }
1545 let redeem = pushes.pop().expect("at least one push");
1546 let mut stack = pushes;
1547
1548 if redeem.len() >= 3
1550 && redeem[0] == OP_0
1551 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
1552 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
1553 {
1554 return None;
1555 }
1556
1557 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1559 let redeem_hash = Ripemd160::digest(sha256_hash);
1560 if &redeem_hash[..] != expected_hash {
1561 return Some(Ok(false));
1562 }
1563
1564 if redeem.len() == 25
1566 && redeem[0] == OP_DUP
1567 && redeem[1] == OP_HASH160
1568 && redeem[2] == PUSH_20_BYTES
1569 && redeem[23] == OP_EQUALVERIFY
1570 && redeem[24] == OP_CHECKSIG
1571 && stack.len() == 2
1572 {
1573 let signature_bytes = &stack[0];
1574 let pubkey_bytes = &stack[1];
1575 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1576 let expected_pubkey_hash = &redeem[3..23];
1577 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1578 let pubkey_hash = Ripemd160::digest(sha256_hash);
1579 if &pubkey_hash[..] == expected_pubkey_hash {
1580 #[cfg(feature = "production")]
1581 let sighash = if let Some(precomp) = precomputed_sighash_all {
1582 precomp
1583 } else {
1584 use crate::transaction_hash::{
1585 calculate_transaction_sighash_single_input, SighashType,
1586 };
1587 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1588 let sighash_type = SighashType::from_byte(sighash_byte);
1589 let deleted_storage;
1590 let script_code: &[u8] = if redeem.len() < 71 {
1591 redeem.as_ref()
1592 } else {
1593 let pattern = serialize_push_data(signature_bytes);
1594 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1595 deleted_storage.as_ref()
1596 };
1597 match calculate_transaction_sighash_single_input(
1598 tx,
1599 input_index,
1600 script_code,
1601 prevout_values[input_index],
1602 sighash_type,
1603 sighash_cache,
1604 ) {
1605 Ok(h) => h,
1606 Err(e) => return Some(Err(e)),
1607 }
1608 };
1609 #[cfg(not(feature = "production"))]
1610 let sighash = {
1611 use crate::transaction_hash::{
1612 calculate_transaction_sighash_single_input, SighashType,
1613 };
1614 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1615 let sighash_type = SighashType::from_byte(sighash_byte);
1616 let deleted_storage;
1617 let script_code: &[u8] = if redeem.len() < 71 {
1618 redeem.as_ref()
1619 } else {
1620 let pattern = serialize_push_data(signature_bytes);
1621 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1622 deleted_storage.as_ref()
1623 };
1624 match calculate_transaction_sighash_single_input(
1625 tx,
1626 input_index,
1627 script_code,
1628 prevout_values[input_index],
1629 sighash_type,
1630 ) {
1631 Ok(h) => h,
1632 Err(e) => return Some(Err(e)),
1633 }
1634 };
1635 let height = block_height.unwrap_or(0);
1636 let is_valid = signature::with_secp_context(|secp| {
1637 signature::verify_signature(
1638 secp,
1639 pubkey_bytes,
1640 signature_bytes,
1641 &sighash,
1642 flags,
1643 height,
1644 network,
1645 SigVersion::Base,
1646 )
1647 });
1648 return Some(is_valid);
1649 }
1650 }
1651 }
1652
1653 if (redeem.len() == 35 || redeem.len() == 67)
1655 && redeem[redeem.len() - 1] == OP_CHECKSIG
1656 && (redeem[0] == 0x21 || redeem[0] == 0x41)
1657 && stack.len() == 1
1658 {
1659 let pubkey_len = redeem.len() - 2;
1660 if pubkey_len == 33 || pubkey_len == 65 {
1661 let pubkey_bytes = &redeem.as_ref()[1..(redeem.len() - 1)];
1662 let signature_bytes = &stack[0];
1663 if !signature_bytes.is_empty() {
1664 use crate::transaction_hash::{
1665 calculate_transaction_sighash_single_input, SighashType,
1666 };
1667 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1668 let sighash_type = SighashType::from_byte(sighash_byte);
1669 let deleted_storage;
1671 let script_code: &[u8] = if redeem.len() < 71 {
1672 redeem.as_ref()
1673 } else {
1674 let pattern = serialize_push_data(signature_bytes);
1675 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1676 deleted_storage.as_ref()
1677 };
1678 match calculate_transaction_sighash_single_input(
1679 tx,
1680 input_index,
1681 script_code,
1682 prevout_values[input_index],
1683 sighash_type,
1684 #[cfg(feature = "production")]
1685 sighash_cache,
1686 ) {
1687 Ok(sighash) => {
1688 let height = block_height.unwrap_or(0);
1689 let is_valid = signature::with_secp_context(|secp| {
1690 signature::verify_signature(
1691 secp,
1692 pubkey_bytes,
1693 signature_bytes,
1694 &sighash,
1695 flags,
1696 height,
1697 network,
1698 SigVersion::Base,
1699 )
1700 });
1701 return Some(is_valid);
1702 }
1703 Err(e) => return Some(Err(e)),
1704 }
1705 }
1706 }
1707 }
1708
1709 let result = eval_script_with_context_full_inner(
1711 &redeem,
1712 &mut stack,
1713 flags,
1714 tx,
1715 input_index,
1716 prevout_values,
1717 prevout_script_pubkeys,
1718 block_height,
1719 median_time_past,
1720 network,
1721 SigVersion::Base,
1722 Some(redeem.as_ref()),
1723 None, #[cfg(feature = "production")]
1725 None, None, #[cfg(feature = "production")]
1728 sighash_cache,
1729 );
1730 Some(result)
1731}
1732
1733#[cfg(feature = "production")]
1736#[allow(clippy::too_many_arguments)]
1737fn try_verify_p2wpkh_fast_path(
1738 script_sig: &ByteString,
1739 script_pubkey: &[u8],
1740 witness: &crate::witness::Witness,
1741 flags: u32,
1742 tx: &Transaction,
1743 input_index: usize,
1744 prevout_values: &[i64],
1745 prevout_script_pubkeys: &[&[u8]],
1746 block_height: Option<u64>,
1747 network: crate::types::Network,
1748 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1749 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1750) -> Option<Result<bool>> {
1751 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
1753 return None;
1754 }
1755 if !script_sig.is_empty() {
1757 return None;
1758 }
1759 if witness.len() != 2 {
1760 return None;
1761 }
1762 let signature_bytes = &witness[0];
1763 let pubkey_bytes = &witness[1];
1764
1765 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1766 return Some(Ok(false));
1767 }
1768 if signature_bytes.is_empty() {
1769 return Some(Ok(false));
1770 }
1771
1772 let expected_hash = &script_pubkey[2..22];
1773 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1774 let pubkey_hash = Ripemd160::digest(sha256_hash);
1775 if &pubkey_hash[..] != expected_hash {
1776 return Some(Ok(false));
1777 }
1778
1779 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1780 let sighash = if sighash_byte == 0x01 {
1781 #[cfg(feature = "production")]
1783 if let Some(precomp) = precomputed_sighash_all {
1784 precomp
1785 } else {
1786 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1787 match crate::transaction_hash::calculate_bip143_sighash(
1788 tx,
1789 input_index,
1790 script_pubkey,
1791 amount,
1792 sighash_byte,
1793 precomputed_bip143,
1794 ) {
1795 Ok(h) => h,
1796 Err(e) => return Some(Err(e)),
1797 }
1798 }
1799 #[cfg(not(feature = "production"))]
1800 {
1801 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1802 match crate::transaction_hash::calculate_bip143_sighash(
1803 tx,
1804 input_index,
1805 script_pubkey,
1806 amount,
1807 sighash_byte,
1808 precomputed_bip143,
1809 ) {
1810 Ok(h) => h,
1811 Err(e) => return Some(Err(e)),
1812 }
1813 }
1814 } else {
1815 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1816 match crate::transaction_hash::calculate_bip143_sighash(
1817 tx,
1818 input_index,
1819 script_pubkey,
1820 amount,
1821 sighash_byte,
1822 precomputed_bip143,
1823 ) {
1824 Ok(h) => h,
1825 Err(e) => return Some(Err(e)),
1826 }
1827 };
1828
1829 let height = block_height.unwrap_or(0);
1830 let is_valid = signature::with_secp_context(|secp| {
1831 signature::verify_signature(
1832 secp,
1833 pubkey_bytes,
1834 signature_bytes,
1835 &sighash,
1836 flags,
1837 height,
1838 network,
1839 SigVersion::WitnessV0,
1840 )
1841 });
1842 Some(is_valid)
1843}
1844
1845#[cfg(feature = "production")]
1847#[allow(clippy::too_many_arguments)]
1848fn try_verify_p2wpkh_in_p2sh_fast_path(
1849 script_sig: &ByteString,
1850 script_pubkey: &[u8],
1851 witness: &crate::witness::Witness,
1852 flags: u32,
1853 tx: &Transaction,
1854 input_index: usize,
1855 prevout_values: &[i64],
1856 prevout_script_pubkeys: &[&[u8]],
1857 block_height: Option<u64>,
1858 network: crate::types::Network,
1859 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1860) -> Option<Result<bool>> {
1861 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1862 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1863 return None;
1864 }
1865 if script_pubkey.len() != 23
1866 || script_pubkey[0] != OP_HASH160
1867 || script_pubkey[1] != PUSH_20_BYTES
1868 || script_pubkey[22] != OP_EQUAL
1869 {
1870 return None;
1871 }
1872 let expected_hash = &script_pubkey[2..22];
1873
1874 let pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1875 if pushes.len() != 1 {
1876 return None;
1877 }
1878 let redeem = &pushes[0];
1879 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
1880 return None;
1881 }
1882 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1883 let redeem_hash = Ripemd160::digest(sha256_hash);
1884 if &redeem_hash[..] != expected_hash {
1885 return Some(Ok(false));
1886 }
1887
1888 if witness.len() != 2 {
1889 return None;
1890 }
1891 let signature_bytes = &witness[0];
1892 let pubkey_bytes = &witness[1];
1893 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1894 return Some(Ok(false));
1895 }
1896 let expected_pubkey_hash = &redeem[2..22];
1897 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
1898 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
1899 if &pubkey_hash[..] != expected_pubkey_hash {
1900 return Some(Ok(false));
1901 }
1902
1903 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1904 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1905 let sighash = match crate::transaction_hash::calculate_bip143_sighash(
1906 tx,
1907 input_index,
1908 redeem.as_ref(),
1909 amount,
1910 sighash_byte,
1911 precomputed_bip143,
1912 ) {
1913 Ok(h) => h,
1914 Err(e) => return Some(Err(e)),
1915 };
1916
1917 let height = block_height.unwrap_or(0);
1918 let is_valid = signature::with_secp_context(|secp| {
1919 signature::verify_signature(
1920 secp,
1921 pubkey_bytes,
1922 signature_bytes,
1923 &sighash,
1924 flags,
1925 height,
1926 network,
1927 SigVersion::WitnessV0,
1928 )
1929 });
1930 Some(is_valid)
1931}
1932
1933#[cfg(feature = "production")]
1936#[allow(clippy::too_many_arguments)]
1937fn try_verify_p2wsh_fast_path(
1938 script_sig: &ByteString,
1939 script_pubkey: &[u8],
1940 witness: &crate::witness::Witness,
1941 flags: u32,
1942 tx: &Transaction,
1943 input_index: usize,
1944 prevout_values: &[i64],
1945 prevout_script_pubkeys: &[&[u8]],
1946 block_height: Option<u64>,
1947 median_time_past: Option<u64>,
1948 network: crate::types::Network,
1949 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
1950 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1951 #[cfg(feature = "production")] sighash_cache: Option<
1952 &crate::transaction_hash::SighashMidstateCache,
1953 >,
1954) -> Option<Result<bool>> {
1955 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
1957 return None;
1958 }
1959 if !script_sig.is_empty() {
1960 return None;
1961 }
1962 if witness.is_empty() {
1963 return None;
1964 }
1965 let witness_script = witness.last().expect("witness not empty").clone();
1966 let mut stack: Vec<StackElement> = witness
1967 .iter()
1968 .take(witness.len() - 1)
1969 .map(|w| to_stack_element(w))
1970 .collect();
1971
1972 let program_hash = &script_pubkey[2..34];
1973 if program_hash.len() != 32 {
1974 return None;
1975 }
1976 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
1977 if &witness_script_hash[..] != program_hash {
1978 return Some(Ok(false));
1979 }
1980
1981 let witness_sigversion = if flags & 0x8000 != 0 {
1982 SigVersion::Tapscript
1983 } else {
1984 SigVersion::WitnessV0
1985 };
1986
1987 if witness_sigversion == SigVersion::WitnessV0
1989 && witness_script.len() == 25
1990 && witness_script[0] == OP_DUP
1991 && witness_script[1] == OP_HASH160
1992 && witness_script[2] == PUSH_20_BYTES
1993 && witness_script[23] == OP_EQUALVERIFY
1994 && witness_script[24] == OP_CHECKSIG
1995 && stack.len() == 2
1996 {
1997 let signature_bytes = &stack[0];
1998 let pubkey_bytes = &stack[1];
1999 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2000 let expected_pubkey_hash = &witness_script[3..23];
2001 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2002 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2003 if &pubkey_hash[..] == expected_pubkey_hash {
2004 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2005 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2006 match crate::transaction_hash::calculate_bip143_sighash(
2007 tx,
2008 input_index,
2009 witness_script.as_ref(),
2010 amount,
2011 sighash_byte,
2012 precomputed_bip143,
2013 ) {
2014 Ok(sighash) => {
2015 let height = block_height.unwrap_or(0);
2016 let is_valid = signature::with_secp_context(|secp| {
2017 signature::verify_signature(
2018 secp,
2019 pubkey_bytes,
2020 signature_bytes,
2021 &sighash,
2022 flags,
2023 height,
2024 network,
2025 SigVersion::WitnessV0,
2026 )
2027 });
2028 return Some(is_valid);
2029 }
2030 Err(e) => return Some(Err(e)),
2031 }
2032 }
2033 }
2034 }
2035
2036 if witness_sigversion == SigVersion::WitnessV0
2038 && (witness_script.len() == 35 || witness_script.len() == 67)
2039 && witness_script[witness_script.len() - 1] == OP_CHECKSIG
2040 && (witness_script[0] == 0x21 || witness_script[0] == 0x41)
2041 && stack.len() == 1
2042 {
2043 let pubkey_len = witness_script.len() - 2;
2044 if (pubkey_len == 33 || pubkey_len == 65) && !stack[0].is_empty() {
2045 let pubkey_bytes = &witness_script[1..(witness_script.len() - 1)];
2046 let signature_bytes = &stack[0];
2047 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2048 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2049 match crate::transaction_hash::calculate_bip143_sighash(
2050 tx,
2051 input_index,
2052 witness_script.as_ref(),
2053 amount,
2054 sighash_byte,
2055 precomputed_bip143,
2056 ) {
2057 Ok(sighash) => {
2058 let height = block_height.unwrap_or(0);
2059 let is_valid = signature::with_secp_context(|secp| {
2060 signature::verify_signature(
2061 secp,
2062 pubkey_bytes,
2063 signature_bytes,
2064 &sighash,
2065 flags,
2066 height,
2067 network,
2068 SigVersion::WitnessV0,
2069 )
2070 });
2071 return Some(is_valid);
2072 }
2073 Err(e) => return Some(Err(e)),
2074 }
2075 }
2076 }
2077
2078 if witness_sigversion == SigVersion::WitnessV0 {
2080 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script.as_ref()) {
2081 if stack.len() < 2 {
2082 return Some(Ok(false));
2083 }
2084 let dummy = stack[0].as_ref();
2085 let signatures: Vec<&[u8]> = stack[1..].iter().map(|e| e.as_ref()).collect();
2086
2087 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
2088 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
2089 let height = block_height.unwrap_or(0);
2090 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
2091 let activation = match network {
2092 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
2093 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
2094 crate::types::Network::Regtest => 0,
2095 };
2096 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
2097 return Some(Ok(false));
2098 }
2099 }
2100
2101 let mut cleaned = witness_script.to_vec();
2102 for sig in &signatures {
2103 if !sig.is_empty() {
2104 let pattern = serialize_push_data(sig);
2105 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
2106 }
2107 }
2108
2109 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2110 let mut sig_index = 0;
2111 let mut valid_sigs = 0u8;
2112
2113 for pubkey_bytes in pubkeys {
2114 if sig_index >= signatures.len() {
2115 break;
2116 }
2117 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
2118 sig_index += 1;
2119 }
2120 if sig_index >= signatures.len() {
2121 break;
2122 }
2123 let signature_bytes = &signatures[sig_index];
2124 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2125 match crate::transaction_hash::calculate_bip143_sighash(
2126 tx,
2127 input_index,
2128 &cleaned,
2129 amount,
2130 sighash_byte,
2131 precomputed_bip143,
2132 ) {
2133 Ok(sighash) => {
2134 let is_valid = signature::with_secp_context(|secp| {
2135 signature::verify_signature(
2136 secp,
2137 pubkey_bytes,
2138 signature_bytes,
2139 &sighash,
2140 flags,
2141 height,
2142 network,
2143 SigVersion::WitnessV0,
2144 )
2145 });
2146 match is_valid {
2147 Ok(v) if v => {
2148 valid_sigs += 1;
2149 sig_index += 1;
2150 }
2151 Ok(_) => {}
2152 Err(e) => return Some(Err(e)),
2153 }
2154 }
2155 Err(e) => return Some(Err(e)),
2156 }
2157 }
2158
2159 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
2160 for sig_bytes in &signatures[sig_index..] {
2161 if !sig_bytes.is_empty() {
2162 return Some(Err(ConsensusError::ScriptErrorWithCode {
2163 code: ScriptErrorCode::SigNullFail,
2164 message:
2165 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
2166 .into(),
2167 }));
2168 }
2169 }
2170 }
2171
2172 return Some(Ok(valid_sigs >= m));
2173 }
2174 }
2175
2176 let result = eval_script_with_context_full_inner(
2179 &witness_script,
2180 &mut stack,
2181 flags,
2182 tx,
2183 input_index,
2184 prevout_values,
2185 prevout_script_pubkeys,
2186 block_height,
2187 median_time_past,
2188 network,
2189 witness_sigversion,
2190 None, None, schnorr_collector,
2193 precomputed_bip143,
2194 #[cfg(feature = "production")]
2195 sighash_cache,
2196 );
2197 Some(result)
2198}
2199
2200#[cfg(feature = "production")]
2202#[allow(clippy::too_many_arguments)]
2203fn try_verify_p2tr_scriptpath_p2pk_fast_path(
2204 script_sig: &ByteString,
2205 script_pubkey: &[u8],
2206 witness: &crate::witness::Witness,
2207 _flags: u32,
2208 tx: &Transaction,
2209 input_index: usize,
2210 prevout_values: &[i64],
2211 prevout_script_pubkeys: &[&[u8]],
2212 block_height: Option<u64>,
2213 network: crate::types::Network,
2214 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2215) -> Option<Result<bool>> {
2216 use crate::activation::taproot_activation_height;
2217 use crate::taproot::parse_taproot_script_path_witness;
2218
2219 let tap_h = taproot_activation_height(network);
2220 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2221 return None;
2222 }
2223 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2224 return None;
2225 }
2226 if !script_sig.is_empty() {
2227 return None;
2228 }
2229 if witness.len() < 2 {
2230 return None;
2231 }
2232 let mut output_key = [0u8; 32];
2233 output_key.copy_from_slice(&script_pubkey[2..34]);
2234 let parsed = match parse_taproot_script_path_witness(witness, &output_key) {
2235 Ok(Some(p)) => p,
2236 Ok(None) | Err(_) => return None,
2237 };
2238 let (tapscript, stack_items, control_block) = parsed;
2239 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
2240 return None;
2241 }
2242 if stack_items.len() != 1 || stack_items[0].len() != 64 {
2243 return None;
2244 }
2245 let sig = stack_items[0].as_ref();
2246 let pubkey_32 = &tapscript[1..33];
2247 let sighash = crate::taproot::compute_tapscript_signature_hash(
2248 tx,
2249 input_index,
2250 prevout_values,
2251 prevout_script_pubkeys,
2252 &tapscript,
2253 control_block.leaf_version,
2254 0xffff_ffff,
2255 0x00,
2256 )
2257 .ok()?;
2258 let result = crate::bip348::verify_tapscript_schnorr_signature(
2259 &sighash,
2260 pubkey_32,
2261 sig,
2262 schnorr_collector,
2263 );
2264 Some(result)
2265}
2266
2267#[cfg(feature = "production")]
2270#[allow(clippy::too_many_arguments)]
2271fn try_verify_p2tr_keypath_fast_path(
2272 script_sig: &ByteString,
2273 script_pubkey: &[u8],
2274 witness: &crate::witness::Witness,
2275 _flags: u32,
2276 tx: &Transaction,
2277 input_index: usize,
2278 prevout_values: &[i64],
2279 prevout_script_pubkeys: &[&[u8]],
2280 block_height: Option<u64>,
2281 network: crate::types::Network,
2282 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2283) -> Option<Result<bool>> {
2284 use crate::activation::taproot_activation_height;
2285 let tap_h = taproot_activation_height(network);
2286 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2287 return None;
2288 }
2289 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2291 return None;
2292 }
2293 if !script_sig.is_empty() {
2294 return None;
2295 }
2296 if witness.len() != 1 || witness[0].len() != 64 {
2298 return None;
2299 }
2300 let output_key = &script_pubkey[2..34];
2301 let sig = &witness[0];
2302 let sighash = crate::taproot::compute_taproot_signature_hash(
2303 tx,
2304 input_index,
2305 prevout_values,
2306 prevout_script_pubkeys,
2307 0x00, )
2309 .ok()?;
2310 let result = crate::bip348::verify_tapscript_schnorr_signature(
2311 &sighash,
2312 output_key,
2313 sig,
2314 schnorr_collector,
2315 );
2316 Some(result)
2317}
2318
2319#[spec_locked("5.2")]
2320pub fn verify_script_with_context_full(
2321 script_sig: &ByteString,
2322 script_pubkey: &[u8],
2323 witness: Option<&crate::witness::Witness>,
2324 flags: u32,
2325 tx: &Transaction,
2326 input_index: usize,
2327 prevout_values: &[i64],
2328 prevout_script_pubkeys: &[&[u8]],
2329 block_height: Option<u64>,
2330 median_time_past: Option<u64>,
2331 network: crate::types::Network,
2332 _sigversion: SigVersion,
2333 #[cfg(feature = "production")] schnorr_collector: Option<
2334 &crate::bip348::SchnorrSignatureCollector,
2335 >,
2336 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2337 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2338 #[cfg(feature = "production")] sighash_cache: Option<
2339 &crate::transaction_hash::SighashMidstateCache,
2340 >,
2341 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
2342) -> Result<bool> {
2343 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
2345 return Err(ConsensusError::ScriptErrorWithCode {
2346 code: ScriptErrorCode::TxInputInvalid,
2347 message: format!(
2348 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
2349 prevout_values.len(),
2350 prevout_script_pubkeys.len(),
2351 tx.inputs.len(),
2352 input_index,
2353 )
2354 .into(),
2355 });
2356 }
2357
2358 if input_index < prevout_values.len() {
2364 let prevout_value = prevout_values[input_index];
2365 if prevout_value < 0 {
2366 return Err(ConsensusError::ScriptErrorWithCode {
2367 code: ScriptErrorCode::ValueOverflow,
2368 message: "Prevout value cannot be negative".into(),
2369 });
2370 }
2371 #[cfg(feature = "production")]
2372 {
2373 use precomputed_constants::MAX_MONEY_U64;
2374 if (prevout_value as u64) > MAX_MONEY_U64 {
2375 return Err(ConsensusError::ScriptErrorWithCode {
2376 code: ScriptErrorCode::ValueOverflow,
2377 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2378 });
2379 }
2380 }
2381 #[cfg(not(feature = "production"))]
2382 {
2383 use crate::constants::MAX_MONEY;
2384 if prevout_value > MAX_MONEY {
2385 return Err(ConsensusError::ScriptErrorWithCode {
2386 code: ScriptErrorCode::ValueOverflow,
2387 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2388 });
2389 }
2390 }
2391 }
2392
2393 if input_index >= tx.inputs.len() {
2395 return Err(ConsensusError::ScriptErrorWithCode {
2396 code: ScriptErrorCode::TxInputInvalid,
2397 message: format!(
2398 "Input index {} out of bounds (tx has {} inputs)",
2399 input_index,
2400 tx.inputs.len()
2401 )
2402 .into(),
2403 });
2404 }
2405
2406 #[cfg(feature = "production")]
2408 if witness.is_none() {
2409 if let Some(result) = try_verify_p2pk_fast_path(
2410 script_sig,
2411 script_pubkey,
2412 flags,
2413 tx,
2414 input_index,
2415 prevout_values,
2416 prevout_script_pubkeys,
2417 block_height,
2418 network,
2419 #[cfg(feature = "production")]
2420 sighash_cache,
2421 ) {
2422 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
2423 return result;
2424 }
2425 if let Some(result) = try_verify_p2pkh_fast_path(
2426 script_sig,
2427 script_pubkey,
2428 flags,
2429 tx,
2430 input_index,
2431 prevout_values,
2432 prevout_script_pubkeys,
2433 block_height,
2434 network,
2435 #[cfg(feature = "production")]
2436 precomputed_sighash_all,
2437 #[cfg(feature = "production")]
2438 sighash_cache,
2439 #[cfg(feature = "production")]
2440 precomputed_p2pkh_hash,
2441 ) {
2442 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
2443 return result;
2444 }
2445 if let Some(result) = try_verify_p2sh_fast_path(
2446 script_sig,
2447 script_pubkey,
2448 flags,
2449 tx,
2450 input_index,
2451 prevout_values,
2452 prevout_script_pubkeys,
2453 block_height,
2454 median_time_past,
2455 network,
2456 #[cfg(feature = "production")]
2457 sighash_cache,
2458 #[cfg(feature = "production")]
2459 precomputed_sighash_all,
2460 ) {
2461 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
2462 return result;
2463 }
2464 if let Some(result) = try_verify_bare_multisig_fast_path(
2465 script_sig,
2466 script_pubkey,
2467 flags,
2468 tx,
2469 input_index,
2470 prevout_values,
2471 prevout_script_pubkeys,
2472 block_height,
2473 network,
2474 #[cfg(feature = "production")]
2475 sighash_cache,
2476 ) {
2477 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
2478 return result;
2479 }
2480 }
2481 #[cfg(feature = "production")]
2483 if let Some(wit) = witness {
2484 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
2485 script_sig,
2486 script_pubkey,
2487 wit,
2488 flags,
2489 tx,
2490 input_index,
2491 prevout_values,
2492 prevout_script_pubkeys,
2493 block_height,
2494 network,
2495 precomputed_bip143,
2496 ) {
2497 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2498 return result;
2499 }
2500 if let Some(result) = try_verify_p2wpkh_fast_path(
2501 script_sig,
2502 script_pubkey,
2503 wit,
2504 flags,
2505 tx,
2506 input_index,
2507 prevout_values,
2508 prevout_script_pubkeys,
2509 block_height,
2510 network,
2511 precomputed_bip143,
2512 precomputed_sighash_all,
2513 ) {
2514 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2515 return result;
2516 }
2517 if let Some(result) = try_verify_p2wsh_fast_path(
2518 script_sig,
2519 script_pubkey,
2520 wit,
2521 flags,
2522 tx,
2523 input_index,
2524 prevout_values,
2525 prevout_script_pubkeys,
2526 block_height,
2527 median_time_past,
2528 network,
2529 schnorr_collector,
2530 precomputed_bip143,
2531 #[cfg(feature = "production")]
2532 sighash_cache,
2533 ) {
2534 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
2535 return result;
2536 }
2537 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
2538 script_sig,
2539 script_pubkey,
2540 wit,
2541 flags,
2542 tx,
2543 input_index,
2544 prevout_values,
2545 prevout_script_pubkeys,
2546 block_height,
2547 network,
2548 schnorr_collector,
2549 ) {
2550 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2551 return result;
2552 }
2553 if let Some(result) = try_verify_p2tr_keypath_fast_path(
2554 script_sig,
2555 script_pubkey,
2556 wit,
2557 flags,
2558 tx,
2559 input_index,
2560 prevout_values,
2561 prevout_script_pubkeys,
2562 block_height,
2563 network,
2564 schnorr_collector,
2565 ) {
2566 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2567 return result;
2568 }
2569 }
2570 #[cfg(feature = "production")]
2571 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
2572
2573 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
2577 let is_p2sh = (flags & SCRIPT_VERIFY_P2SH) != 0
2578 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; if is_p2sh {
2589 let mut i = 0;
2590 while i < script_sig.len() {
2591 let opcode = script_sig[i];
2592 if !is_push_opcode(opcode) {
2593 return Ok(false);
2595 }
2596 if opcode == OP_0 {
2598 i += 1;
2600 } else if opcode <= 0x4b {
2601 let len = opcode as usize;
2603 if i + 1 + len > script_sig.len() {
2604 return Ok(false); }
2606 i += 1 + len;
2607 } else if opcode == OP_PUSHDATA1 {
2608 if i + 1 >= script_sig.len() {
2610 return Ok(false);
2611 }
2612 let len = script_sig[i + 1] as usize;
2613 if i + 2 + len > script_sig.len() {
2614 return Ok(false);
2615 }
2616 i += 2 + len;
2617 } else if opcode == OP_PUSHDATA2 {
2618 if i + 2 >= script_sig.len() {
2620 return Ok(false);
2621 }
2622 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
2623 if i + 3 + len > script_sig.len() {
2624 return Ok(false);
2625 }
2626 i += 3 + len;
2627 } else if opcode == OP_PUSHDATA4 {
2628 if i + 4 >= script_sig.len() {
2630 return Ok(false);
2631 }
2632 let len = u32::from_le_bytes([
2633 script_sig[i + 1],
2634 script_sig[i + 2],
2635 script_sig[i + 3],
2636 script_sig[i + 4],
2637 ]) as usize;
2638 if i + 5 + len > script_sig.len() {
2639 return Ok(false);
2640 }
2641 i += 5 + len;
2642 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
2643 i += 1;
2646 } else {
2647 return Ok(false);
2649 }
2650 }
2651 if let Some(result) = try_verify_p2sh_multisig_fast_path(
2652 script_sig,
2653 script_pubkey,
2654 flags,
2655 tx,
2656 input_index,
2657 prevout_values,
2658 prevout_script_pubkeys,
2659 block_height,
2660 network,
2661 #[cfg(feature = "production")]
2662 sighash_cache,
2663 ) {
2664 return result;
2665 }
2666 }
2667
2668 #[cfg(feature = "production")]
2669 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
2670 #[cfg(feature = "production")]
2671 let stack = &mut _stack_guard.0;
2672 #[cfg(not(feature = "production"))]
2673 let mut stack = Vec::with_capacity(20);
2674
2675 let script_sig_result = eval_script_with_context_full(
2679 script_sig,
2680 stack,
2681 flags,
2682 tx,
2683 input_index,
2684 prevout_values,
2685 prevout_script_pubkeys,
2686 block_height,
2687 median_time_past,
2688 network,
2689 SigVersion::Base,
2690 None, #[cfg(feature = "production")]
2692 schnorr_collector,
2693 None, #[cfg(feature = "production")]
2695 sighash_cache,
2696 )?;
2697 if !script_sig_result {
2698 return Ok(false);
2699 }
2700
2701 let redeem_script: Option<ByteString> = if is_p2sh && !stack.is_empty() {
2703 Some(stack.last().expect("Stack is not empty").as_ref().to_vec())
2704 } else {
2705 None
2706 };
2707
2708 use crate::activation::taproot_activation_height;
2712 let tap_h = taproot_activation_height(network);
2713 let is_taproot = redeem_script.is_none() && block_height.is_some() && block_height.unwrap() >= tap_h
2715 && script_pubkey.len() == 34
2716 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES; if is_taproot && !script_sig.is_empty() {
2721 return Ok(false); }
2723
2724 let is_direct_witness_program = redeem_script.is_none() && !is_taproot && script_pubkey.len() >= 3
2731 && 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;
2737 if is_direct_witness_program {
2738 if let Some(witness_stack) = witness {
2739 if script_pubkey[1] == PUSH_32_BYTES {
2740 if witness_stack.is_empty() {
2743 return Ok(false); }
2745
2746 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2748
2749 let program_bytes = &script_pubkey[2..];
2751 if program_bytes.len() != 32 {
2752 return Ok(false); }
2754
2755 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2756 if &witness_script_hash[..] != program_bytes {
2757 return Ok(false); }
2759
2760 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2762 stack.push(to_stack_element(element));
2763 }
2764
2765 witness_script_to_execute = Some(witness_script.clone());
2767 } else if script_pubkey[1] == PUSH_20_BYTES {
2768 if witness_stack.len() != 2 {
2771 return Ok(false); }
2773
2774 for element in witness_stack.iter() {
2775 stack.push(to_stack_element(element));
2776 }
2777 } else {
2778 return Ok(false); }
2780 } else {
2781 return Ok(false); }
2783 }
2784
2785 if is_taproot {
2786 let Some(witness_stack) = witness else {
2787 return Ok(false);
2788 };
2789 if witness_stack.len() < 2 {
2790 return Ok(false);
2791 }
2792 let mut output_key = [0u8; 32];
2793 output_key.copy_from_slice(&script_pubkey[2..34]);
2794 match crate::taproot::parse_taproot_script_path_witness(witness_stack, &output_key)? {
2795 None => return Ok(false),
2796 Some((tapscript, stack_items, _control_block)) => {
2797 for item in &stack_items {
2798 stack.push(to_stack_element(item));
2799 }
2800 let tapscript_flags = flags | 0x8000;
2801 if !eval_script_with_context_full(
2802 &tapscript,
2803 stack,
2804 tapscript_flags,
2805 tx,
2806 input_index,
2807 prevout_values,
2808 prevout_script_pubkeys,
2809 block_height,
2810 median_time_past,
2811 network,
2812 SigVersion::Tapscript,
2813 None,
2814 #[cfg(feature = "production")]
2815 schnorr_collector,
2816 None,
2817 #[cfg(feature = "production")]
2818 sighash_cache,
2819 )? {
2820 return Ok(false);
2821 }
2822 return Ok(true);
2823 }
2824 }
2825 }
2826
2827 let script_pubkey_result = eval_script_with_context_full(
2834 script_pubkey,
2835 stack,
2836 flags,
2837 tx,
2838 input_index,
2839 prevout_values,
2840 prevout_script_pubkeys,
2841 block_height,
2842 median_time_past,
2843 network,
2844 SigVersion::Base,
2845 Some(script_sig),
2846 #[cfg(feature = "production")]
2847 schnorr_collector,
2848 None, #[cfg(feature = "production")]
2850 sighash_cache,
2851 )?;
2852 if !script_pubkey_result {
2853 return Ok(false);
2854 }
2855
2856 if let Some(witness_script) = witness_script_to_execute {
2858 let witness_sigversion = if flags & 0x8000 != 0 {
2860 SigVersion::Tapscript
2861 } else {
2862 SigVersion::WitnessV0 };
2864
2865 if !eval_script_with_context_full(
2868 &witness_script,
2869 stack,
2870 flags,
2871 tx,
2872 input_index,
2873 prevout_values,
2874 prevout_script_pubkeys,
2875 block_height,
2876 median_time_past,
2877 network,
2878 witness_sigversion,
2879 None, #[cfg(feature = "production")]
2881 schnorr_collector,
2882 precomputed_bip143, #[cfg(feature = "production")]
2884 sighash_cache,
2885 )? {
2886 return Ok(false);
2887 }
2888 }
2889
2890 if let Some(redeem) = redeem_script {
2895 if stack.is_empty() {
2897 return Ok(false); }
2899
2900 let top = stack.last().expect("Stack is not empty");
2902 if !cast_to_bool(top) {
2903 return Ok(false); }
2905
2906 stack.pop();
2908
2909 let is_witness_program = redeem.len() >= 3
2914 && 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() {
2919 let program_bytes = &redeem[2..];
2928
2929 if redeem[1] == PUSH_32_BYTES {
2930 if program_bytes.len() != 32 {
2933 return Ok(false); }
2935
2936 if let Some(witness_stack) = witness {
2941 if witness_stack.is_empty() {
2942 return Ok(false); }
2944
2945 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2947 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2948 if &witness_script_hash[..] != program_bytes {
2949 return Ok(false); }
2951
2952 stack.clear();
2955
2956 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2959 stack.push(to_stack_element(element));
2960 }
2961
2962 let witness_sigversion = if flags & 0x8000 != 0 {
2964 SigVersion::Tapscript
2965 } else {
2966 SigVersion::WitnessV0 };
2968
2969 if !eval_script_with_context_full(
2971 witness_script,
2972 stack,
2973 flags,
2974 tx,
2975 input_index,
2976 prevout_values,
2977 prevout_script_pubkeys,
2978 block_height,
2979 median_time_past,
2980 network,
2981 witness_sigversion,
2982 None, #[cfg(feature = "production")]
2984 schnorr_collector,
2985 precomputed_bip143, #[cfg(feature = "production")]
2987 sighash_cache,
2988 )? {
2989 return Ok(false);
2990 }
2991 } else {
2992 return Ok(false); }
2994 } else if redeem[1] == PUSH_20_BYTES {
2995 stack.clear();
2999 } else {
3000 return Ok(false); }
3002 } else {
3004 let redeem_result = eval_script_with_context_full_inner(
3008 &redeem,
3009 stack,
3010 flags,
3011 tx,
3012 input_index,
3013 prevout_values,
3014 prevout_script_pubkeys,
3015 block_height,
3016 median_time_past,
3017 network,
3018 SigVersion::Base,
3019 Some(redeem.as_ref()), Some(script_sig), #[cfg(feature = "production")]
3022 None, None, #[cfg(feature = "production")]
3025 sighash_cache,
3026 )?;
3027 if !redeem_result {
3028 return Ok(false);
3029 }
3030 }
3031 }
3032
3033 assert!(
3035 stack.len() <= 1000,
3036 "Stack size {} exceeds reasonable maximum after scriptPubkey",
3037 stack.len()
3038 );
3039
3040 if let Some(_witness_stack) = witness {
3049 }
3053
3054 const SCRIPT_VERIFY_CLEANSTACK: u32 = 0x100;
3060
3061 let final_result = if (flags & SCRIPT_VERIFY_CLEANSTACK) != 0 {
3062 stack.len() == 1 && cast_to_bool(&stack[0])
3064 } else {
3065 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
3067 };
3068 Ok(final_result)
3069}
3070
3071#[allow(dead_code)]
3073fn eval_script_with_context(
3074 script: &ByteString,
3075 stack: &mut Vec<StackElement>,
3076 flags: u32,
3077 tx: &Transaction,
3078 input_index: usize,
3079 prevouts: &[TransactionOutput],
3080 network: crate::types::Network,
3081) -> Result<bool> {
3082 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
3084 let prevout_script_pubkeys: Vec<&[u8]> =
3085 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
3086 eval_script_with_context_full(
3087 script,
3088 stack,
3089 flags,
3090 tx,
3091 input_index,
3092 &prevout_values,
3093 &prevout_script_pubkeys,
3094 None, None, network,
3097 SigVersion::Base,
3098 None, #[cfg(feature = "production")]
3100 None, None, #[cfg(feature = "production")]
3103 None, )
3105}
3106
3107#[allow(clippy::too_many_arguments)]
3109fn eval_script_with_context_full(
3110 script: &[u8],
3111 stack: &mut Vec<StackElement>,
3112 flags: u32,
3113 tx: &Transaction,
3114 input_index: usize,
3115 prevout_values: &[i64],
3116 prevout_script_pubkeys: &[&[u8]],
3117 block_height: Option<u64>,
3118 median_time_past: Option<u64>,
3119 network: crate::types::Network,
3120 sigversion: SigVersion,
3121 script_sig_for_sighash: Option<&ByteString>,
3122 #[cfg(feature = "production")] schnorr_collector: Option<
3123 &crate::bip348::SchnorrSignatureCollector,
3124 >,
3125 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3126 #[cfg(feature = "production")] sighash_cache: Option<
3127 &crate::transaction_hash::SighashMidstateCache,
3128 >,
3129) -> Result<bool> {
3130 #[cfg(all(feature = "production", feature = "profile"))]
3131 let _t0 = std::time::Instant::now();
3132 let r = eval_script_with_context_full_inner(
3133 script,
3134 stack,
3135 flags,
3136 tx,
3137 input_index,
3138 prevout_values,
3139 prevout_script_pubkeys,
3140 block_height,
3141 median_time_past,
3142 network,
3143 sigversion,
3144 None,
3145 script_sig_for_sighash,
3146 #[cfg(feature = "production")]
3147 schnorr_collector,
3148 precomputed_bip143,
3149 #[cfg(feature = "production")]
3150 sighash_cache,
3151 );
3152 #[cfg(all(feature = "production", feature = "profile"))]
3153 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
3154 r
3155}
3156
3157fn eval_script_with_context_full_inner(
3159 script: &[u8],
3160 stack: &mut Vec<StackElement>,
3161 flags: u32,
3162 tx: &Transaction,
3163 input_index: usize,
3164 prevout_values: &[i64],
3165 prevout_script_pubkeys: &[&[u8]],
3166 block_height: Option<u64>,
3167 median_time_past: Option<u64>,
3168 network: crate::types::Network,
3169 sigversion: SigVersion,
3170 redeem_script_for_sighash: Option<&[u8]>,
3171 script_sig_for_sighash: Option<&ByteString>,
3172 #[cfg(feature = "production")] schnorr_collector: Option<
3173 &crate::bip348::SchnorrSignatureCollector,
3174 >,
3175 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3176 #[cfg(feature = "production")] sighash_cache: Option<
3177 &crate::transaction_hash::SighashMidstateCache,
3178 >,
3179) -> Result<bool> {
3180 assert!(
3183 script.len() <= 10000,
3184 "Script length {} exceeds reasonable maximum",
3185 script.len()
3186 );
3187 assert!(
3188 stack.len() <= 1000,
3189 "Stack size {} exceeds reasonable maximum at start",
3190 stack.len()
3191 );
3192
3193 use crate::error::{ConsensusError, ScriptErrorCode};
3194
3195 if stack.capacity() < 20 {
3197 stack.reserve(20);
3198 }
3199 let mut op_count = 0;
3200 assert!(op_count == 0, "Op count must start at zero");
3202
3203 #[cfg(feature = "production")]
3205 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
3206 #[cfg(not(feature = "production"))]
3207 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
3208 assert!(control_stack.is_empty(), "Control stack must start empty");
3210
3211 #[cfg(feature = "production")]
3212 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
3213 #[cfg(not(feature = "production"))]
3214 let mut altstack: Vec<StackElement> = Vec::new();
3215
3216 let mut code_separator_pos: usize = 0;
3220 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
3221
3222 let mut i = 0;
3224 while i < script.len() {
3225 #[cfg(feature = "production")]
3226 {
3227 prefetch::prefetch_ahead(script, i, 64); }
3230 let opcode = {
3232 #[cfg(feature = "production")]
3233 {
3234 unsafe { *script.get_unchecked(i) }
3235 }
3236 #[cfg(not(feature = "production"))]
3237 {
3238 script[i]
3239 }
3240 };
3241
3242 let in_false_branch = control_flow::in_false_branch(&control_stack);
3244
3245 if !is_push_opcode(opcode) {
3247 op_count += 1;
3248 assert!(
3250 op_count <= MAX_SCRIPT_OPS + 1,
3251 "Op count {op_count} must not exceed MAX_SCRIPT_OPS + 1"
3252 );
3253 if op_count > MAX_SCRIPT_OPS {
3254 return Err(make_operation_limit_error());
3255 }
3256 }
3257
3258 if stack.len() + altstack.len() > MAX_STACK_SIZE {
3260 return Err(make_stack_overflow_error());
3261 }
3262
3263 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
3265 let (data, advance) = if opcode <= 0x4b {
3266 let len = opcode as usize;
3268 if i + 1 + len > script.len() {
3269 return Ok(false); }
3271 (&script[i + 1..i + 1 + len], 1 + len)
3272 } else if opcode == OP_PUSHDATA1 {
3273 if i + 1 >= script.len() {
3275 return Ok(false);
3276 }
3277 let len = script[i + 1] as usize;
3278 if i + 2 + len > script.len() {
3279 return Ok(false);
3280 }
3281 (&script[i + 2..i + 2 + len], 2 + len)
3282 } else if opcode == OP_PUSHDATA2 {
3283 if i + 2 >= script.len() {
3285 return Ok(false);
3286 }
3287 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
3288 if i + 3 + len > script.len() {
3289 return Ok(false);
3290 }
3291 (&script[i + 3..i + 3 + len], 3 + len)
3292 } else {
3293 if i + 4 >= script.len() {
3296 return Ok(false);
3297 }
3298 let len = u32::from_le_bytes([
3299 script[i + 1],
3300 script[i + 2],
3301 script[i + 3],
3302 script[i + 4],
3303 ]) as usize;
3304 let data_start = i.saturating_add(5);
3305 let data_end = data_start.saturating_add(len);
3306 let advance = 5usize.saturating_add(len);
3307 if advance < 5 || data_end > script.len() || data_end < data_start {
3308 return Ok(false); }
3310 (&script[data_start..data_end], advance)
3311 };
3312
3313 if !in_false_branch {
3315 stack.push(to_stack_element(data));
3316 }
3317 i += advance;
3318 continue;
3319 }
3320
3321 if opcode == OP_DUP {
3327 if !in_false_branch {
3328 if stack.is_empty() {
3329 return Err(ConsensusError::ScriptErrorWithCode {
3330 code: ScriptErrorCode::InvalidStackOperation,
3331 message: "OP_DUP: empty stack".into(),
3332 });
3333 }
3334 let len = stack.len();
3337 #[cfg(feature = "production")]
3338 {
3339 if stack.capacity() == stack.len() {
3341 stack.reserve(1);
3342 }
3343 let item = unsafe { stack.get_unchecked(len - 1).clone() };
3345 stack.push(item);
3346 }
3347 #[cfg(not(feature = "production"))]
3348 {
3349 let item = stack.last().unwrap();
3350 stack.push(item.clone());
3351 }
3352 }
3353 i += 1;
3354 continue;
3355 }
3356
3357 if opcode == OP_EQUALVERIFY {
3359 if !in_false_branch {
3360 if stack.len() < 2 {
3361 return Err(ConsensusError::ScriptErrorWithCode {
3362 code: ScriptErrorCode::InvalidStackOperation,
3363 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3364 });
3365 }
3366 let a = stack.pop().unwrap();
3367 let b = stack.pop().unwrap();
3368 if a != b {
3369 return Ok(false);
3370 }
3371 }
3372 i += 1;
3373 continue;
3374 }
3375
3376 if opcode == OP_HASH160 {
3378 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
3379 return Ok(false);
3380 }
3381 i += 1;
3382 continue;
3383 }
3384
3385 if opcode == OP_VERIFY {
3387 if !in_false_branch {
3388 if let Some(item) = stack.pop() {
3389 if !cast_to_bool(&item) {
3390 return Ok(false);
3391 }
3392 } else {
3393 return Ok(false);
3394 }
3395 }
3396 i += 1;
3397 continue;
3398 }
3399
3400 if opcode == OP_EQUAL {
3402 if !in_false_branch {
3403 if stack.len() < 2 {
3404 return Err(ConsensusError::ScriptErrorWithCode {
3405 code: ScriptErrorCode::InvalidStackOperation,
3406 message: "OP_EQUAL: insufficient stack items".into(),
3407 });
3408 }
3409 let a = stack.pop().unwrap();
3410 let b = stack.pop().unwrap();
3411 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3412 }
3413 i += 1;
3414 continue;
3415 }
3416
3417 if opcode == OP_CHECKSIG
3420 || opcode == OP_CHECKSIGVERIFY
3421 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
3422 {
3423 if !in_false_branch {
3424 let effective_script_code = Some(&script[code_separator_pos..]);
3425 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3426 (Some(script), Some(last_codesep_opcode_pos))
3427 } else {
3428 (None, None)
3429 };
3430 let ctx = context::ScriptContext {
3431 tx,
3432 input_index,
3433 prevout_values,
3434 prevout_script_pubkeys,
3435 block_height,
3436 median_time_past,
3437 network,
3438 sigversion,
3439 redeem_script_for_sighash,
3440 script_sig_for_sighash,
3441 tapscript_for_sighash: tapscript,
3442 tapscript_codesep_pos: codesep,
3443 #[cfg(feature = "production")]
3444 schnorr_collector,
3445 #[cfg(feature = "production")]
3446 precomputed_bip143,
3447 #[cfg(feature = "production")]
3448 sighash_cache,
3449 };
3450 if !execute_opcode_with_context_full(
3451 opcode,
3452 stack,
3453 flags,
3454 &ctx,
3455 effective_script_code,
3456 )? {
3457 return Ok(false);
3458 }
3459 }
3460 i += 1;
3461 continue;
3462 }
3463
3464 match opcode {
3465 OP_0 => {
3467 if !in_false_branch {
3468 stack.push(to_stack_element(&[]));
3469 }
3470 }
3471
3472 OP_1_RANGE_START..=OP_1_RANGE_END => {
3474 if !in_false_branch {
3475 let num = opcode - OP_N_BASE;
3476 stack.push(to_stack_element(&[num]));
3477 }
3478 }
3479
3480 OP_1NEGATE => {
3482 if !in_false_branch {
3483 stack.push(to_stack_element(&[0x81])); }
3485 }
3486
3487 OP_NOP => {
3489 }
3491
3492 OP_VER => {
3497 if !in_false_branch {
3498 return Err(ConsensusError::ScriptErrorWithCode {
3499 code: ScriptErrorCode::DisabledOpcode,
3500 message: "OP_VER is disabled".into(),
3501 });
3502 }
3503 }
3504
3505 OP_IF => {
3506 if in_false_branch {
3508 control_stack.push(control_flow::ControlBlock::If { executing: false });
3509 i += 1;
3510 continue;
3511 }
3512
3513 if stack.is_empty() {
3514 return Err(ConsensusError::ScriptErrorWithCode {
3515 code: ScriptErrorCode::InvalidStackOperation,
3516 message: "OP_IF: empty stack".into(),
3517 });
3518 }
3519 let condition_bytes = stack.pop().unwrap();
3520 let condition = cast_to_bool(&condition_bytes);
3521
3522 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3523 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3524 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3525 && !control_flow::is_minimal_if_condition(&condition_bytes)
3526 {
3527 return Err(ConsensusError::ScriptErrorWithCode {
3528 code: ScriptErrorCode::MinimalIf,
3529 message: "OP_IF condition must be minimally encoded".into(),
3530 });
3531 }
3532
3533 control_stack.push(control_flow::ControlBlock::If {
3534 executing: condition,
3535 });
3536 }
3537 OP_NOTIF => {
3538 if in_false_branch {
3540 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
3541 i += 1;
3542 continue;
3543 }
3544
3545 if stack.is_empty() {
3546 return Err(ConsensusError::ScriptErrorWithCode {
3547 code: ScriptErrorCode::InvalidStackOperation,
3548 message: "OP_NOTIF: empty stack".into(),
3549 });
3550 }
3551 let condition_bytes = stack.pop().unwrap();
3552 let condition = cast_to_bool(&condition_bytes);
3553
3554 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3555 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3556 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3557 && !control_flow::is_minimal_if_condition(&condition_bytes)
3558 {
3559 return Err(ConsensusError::ScriptErrorWithCode {
3560 code: ScriptErrorCode::MinimalIf,
3561 message: "OP_NOTIF condition must be minimally encoded".into(),
3562 });
3563 }
3564
3565 control_stack.push(control_flow::ControlBlock::NotIf {
3566 executing: !condition,
3567 });
3568 }
3569 OP_ELSE => {
3570 if let Some(block) = control_stack.last_mut() {
3572 match block {
3573 control_flow::ControlBlock::If { executing }
3574 | control_flow::ControlBlock::NotIf { executing } => {
3575 *executing = !*executing;
3576 }
3577 }
3578 } else {
3579 return Err(ConsensusError::ScriptErrorWithCode {
3580 code: ScriptErrorCode::UnbalancedConditional,
3581 message: "OP_ELSE without matching IF/NOTIF".into(),
3582 });
3583 }
3584 }
3585 OP_ENDIF => {
3586 if control_stack.pop().is_none() {
3588 return Err(ConsensusError::ScriptErrorWithCode {
3589 code: ScriptErrorCode::UnbalancedConditional,
3590 message: "OP_ENDIF without matching IF/NOTIF".into(),
3591 });
3592 }
3593 }
3594
3595 OP_TOALTSTACK => {
3600 if in_false_branch {
3601 i += 1;
3602 continue;
3603 }
3604 if stack.is_empty() {
3605 return Err(ConsensusError::ScriptErrorWithCode {
3606 code: ScriptErrorCode::InvalidStackOperation,
3607 message: "OP_TOALTSTACK: empty stack".into(),
3608 });
3609 }
3610 altstack.push(stack.pop().unwrap());
3611 }
3612 OP_FROMALTSTACK => {
3614 if in_false_branch {
3615 i += 1;
3616 continue;
3617 }
3618 if altstack.is_empty() {
3619 return Err(ConsensusError::ScriptErrorWithCode {
3620 code: ScriptErrorCode::InvalidAltstackOperation,
3621 message: "OP_FROMALTSTACK: empty altstack".into(),
3622 });
3623 }
3624 stack.push(altstack.pop().unwrap());
3625 }
3626 OP_CODESEPARATOR => {
3628 if in_false_branch {
3629 i += 1;
3630 continue;
3631 }
3632 code_separator_pos = i + 1;
3633 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
3634 }
3635 _ => {
3636 if in_false_branch {
3637 i += 1;
3638 continue;
3639 }
3640
3641 let subscript_for_sighash = if matches!(
3646 opcode,
3647 OP_CHECKSIG
3648 | OP_CHECKSIGVERIFY
3649 | OP_CHECKSIGADD
3650 | OP_CHECKMULTISIG
3651 | OP_CHECKMULTISIGVERIFY
3652 ) {
3653 Some(&script[code_separator_pos..])
3654 } else {
3655 None
3656 };
3657 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
3658 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3659 (Some(script), Some(last_codesep_opcode_pos))
3660 } else {
3661 (None, None)
3662 };
3663 let ctx = context::ScriptContext {
3664 tx,
3665 input_index,
3666 prevout_values,
3667 prevout_script_pubkeys,
3668 block_height,
3669 median_time_past,
3670 network,
3671 sigversion,
3672 redeem_script_for_sighash,
3673 script_sig_for_sighash,
3674 tapscript_for_sighash: tapscript,
3675 tapscript_codesep_pos: codesep,
3676 #[cfg(feature = "production")]
3677 schnorr_collector,
3678 #[cfg(feature = "production")]
3679 precomputed_bip143,
3680 #[cfg(feature = "production")]
3681 sighash_cache,
3682 };
3683 if !execute_opcode_with_context_full(
3684 opcode,
3685 stack,
3686 flags,
3687 &ctx,
3688 effective_script_code,
3689 )? {
3690 return Ok(false);
3691 }
3692 }
3693 }
3694 i += 1;
3695 }
3696
3697 if !control_stack.is_empty() {
3699 return Err(ConsensusError::ScriptErrorWithCode {
3700 code: ScriptErrorCode::UnbalancedConditional,
3701 message: "Unclosed IF/NOTIF block".into(),
3702 });
3703 }
3704
3705 Ok(true)
3709}
3710
3711#[spec_locked("5.4.5")]
3715#[cfg(feature = "production")]
3716#[inline(always)]
3717pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3718 if data.len() > max_num_size {
3719 return Err(ConsensusError::ScriptErrorWithCode {
3720 code: ScriptErrorCode::InvalidStackOperation,
3721 message: format!(
3722 "Script number overflow: {} > {} bytes",
3723 data.len(),
3724 max_num_size
3725 )
3726 .into(),
3727 });
3728 }
3729 if data.is_empty() {
3730 return Ok(0);
3731 }
3732
3733 let len = data.len();
3735 let result = match len {
3736 1 => {
3737 let byte = data[0];
3738 if byte & 0x80 != 0 {
3739 -((byte & 0x7f) as i64)
3741 } else {
3742 byte as i64
3743 }
3744 }
3745 2 => {
3746 let byte0 = data[0] as i64;
3747 let byte1 = data[1] as i64;
3748 let value = byte0 | (byte1 << 8);
3749 if byte1 & 0x80 != 0 {
3750 -(value & !(0x80i64 << 8))
3752 } else {
3753 value
3754 }
3755 }
3756 _ => {
3757 let mut result: i64 = 0;
3759 for (i, &byte) in data.iter().enumerate() {
3760 result |= (byte as i64) << (8 * i);
3761 }
3762 let last_idx = len - 1;
3764 if data[last_idx] & 0x80 != 0 {
3765 result &= !(0x80i64 << (8 * last_idx));
3767 result = -result;
3768 }
3769 result
3770 }
3771 };
3772
3773 Ok(result)
3774}
3775
3776#[cfg(not(feature = "production"))]
3777#[inline]
3778pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3779 if data.len() > max_num_size {
3780 return Err(ConsensusError::ScriptErrorWithCode {
3781 code: ScriptErrorCode::InvalidStackOperation,
3782 message: format!(
3783 "Script number overflow: {} > {} bytes",
3784 data.len(),
3785 max_num_size
3786 )
3787 .into(),
3788 });
3789 }
3790 if data.is_empty() {
3791 return Ok(0);
3792 }
3793 let mut result: i64 = 0;
3795 for (i, &byte) in data.iter().enumerate() {
3796 result |= (byte as i64) << (8 * i);
3797 }
3798 if data.last().expect("Data is not empty") & 0x80 != 0 {
3800 result &= !(0x80i64 << (8 * (data.len() - 1)));
3802 result = -result;
3803 }
3804 Ok(result)
3805}
3806
3807#[cfg(feature = "production")]
3810pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3811 match value {
3813 0 => return vec![],
3814 1 => return vec![1],
3815 -1 => return vec![0x81],
3816 _ => {}
3817 }
3818
3819 let neg = value < 0;
3820 let mut absvalue = if neg {
3821 (-(value as i128)) as u64
3822 } else {
3823 value as u64
3824 };
3825 let mut result = Vec::with_capacity(4);
3827 while absvalue > 0 {
3828 result.push((absvalue & 0xff) as u8);
3829 absvalue >>= 8;
3830 }
3831 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3833 result.push(if neg { 0x80 } else { 0x00 });
3834 } else if neg {
3835 *result.last_mut().unwrap() |= 0x80;
3836 }
3837 result
3838}
3839
3840#[cfg(not(feature = "production"))]
3841pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3842 if value == 0 {
3843 return vec![];
3844 }
3845 let neg = value < 0;
3846 let mut absvalue = if neg {
3847 (-(value as i128)) as u64
3848 } else {
3849 value as u64
3850 };
3851 let mut result = Vec::new();
3852 while absvalue > 0 {
3853 result.push((absvalue & 0xff) as u8);
3854 absvalue >>= 8;
3855 }
3856 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3858 result.push(if neg { 0x80 } else { 0x00 });
3859 } else if neg {
3860 *result.last_mut().unwrap() |= 0x80;
3861 }
3862 result
3863}
3864
3865#[cfg(feature = "production")]
3867#[inline(always)]
3868fn execute_opcode(
3869 opcode: u8,
3870 stack: &mut Vec<StackElement>,
3871 flags: u32,
3872 _sigversion: SigVersion,
3873) -> Result<bool> {
3874 match opcode {
3875 OP_0 => {
3877 stack.push(to_stack_element(&[]));
3878 Ok(true)
3879 }
3880
3881 OP_1..=OP_16 => {
3883 let num = opcode - OP_N_BASE;
3884 stack.push(to_stack_element(&[num]));
3885 Ok(true)
3886 }
3887
3888 OP_NOP => Ok(true),
3890
3891 OP_VER => Ok(false),
3893
3894 OP_DEPTH => {
3896 let depth = stack.len() as i64;
3897 stack.push(to_stack_element(&script_num_encode(depth)));
3898 Ok(true)
3899 }
3900
3901 OP_DUP => {
3903 if let Some(item) = stack.last().cloned() {
3904 stack.push(item);
3905 Ok(true)
3906 } else {
3907 Ok(false)
3908 }
3909 }
3910
3911 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
3913
3914 OP_SHA1 => crypto_ops::op_sha1(stack),
3916
3917 OP_SHA256 => crypto_ops::op_sha256(stack),
3919
3920 OP_HASH160 => crypto_ops::op_hash160(stack),
3922
3923 OP_HASH256 => crypto_ops::op_hash256(stack),
3925
3926 OP_EQUAL => {
3928 if stack.len() < 2 {
3929 return Err(ConsensusError::ScriptErrorWithCode {
3930 code: ScriptErrorCode::InvalidStackOperation,
3931 message: "OP_EQUAL: insufficient stack items".into(),
3932 });
3933 }
3934 let a = stack.pop().unwrap();
3935 let b = stack.pop().unwrap();
3936 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3937 Ok(true)
3938 }
3939
3940 OP_EQUALVERIFY => {
3943 if stack.len() < 2 {
3944 return Err(ConsensusError::ScriptErrorWithCode {
3945 code: ScriptErrorCode::InvalidStackOperation,
3946 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3947 });
3948 }
3949 let a = stack.pop().unwrap();
3950 let b = stack.pop().unwrap();
3951 let f_equal = a == b;
3952 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
3954 if f_equal {
3955 stack.pop();
3957 Ok(true)
3958 } else {
3959 Err(ConsensusError::ScriptErrorWithCode {
3960 code: ScriptErrorCode::EqualVerify,
3961 message: "OP_EQUALVERIFY: stack items not equal".into(),
3962 })
3963 }
3964 }
3965
3966 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
3968
3969 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
3971
3972 OP_RETURN => Ok(false),
3974
3975 OP_VERIFY => {
3977 if let Some(item) = stack.pop() {
3978 Ok(cast_to_bool(&item))
3979 } else {
3980 Ok(false)
3981 }
3982 }
3983
3984 OP_CHECKLOCKTIMEVERIFY => {
3988 Ok(false)
3991 }
3992
3993 OP_CHECKSEQUENCEVERIFY => {
3997 Ok(false)
4000 }
4001
4002 OP_IFDUP => {
4004 if let Some(item) = stack.last().cloned() {
4005 if cast_to_bool(&item) {
4006 stack.push(item);
4007 }
4008 Ok(true)
4009 } else {
4010 Ok(false)
4011 }
4012 }
4013
4014 OP_DROP => {
4017 if stack.pop().is_some() {
4018 Ok(true)
4019 } else {
4020 Ok(false)
4021 }
4022 }
4023
4024 OP_NIP => {
4026 if stack.len() >= 2 {
4027 let top = stack.pop().unwrap();
4028 stack.pop(); stack.push(top);
4030 Ok(true)
4031 } else {
4032 Ok(false)
4033 }
4034 }
4035
4036 OP_OVER => {
4038 if stack.len() >= 2 {
4039 let len = stack.len();
4040 #[cfg(feature = "production")]
4041 {
4042 unsafe {
4044 let second = stack.get_unchecked(len - 2);
4045 stack.push(second.clone());
4046 }
4047 }
4048 #[cfg(not(feature = "production"))]
4049 {
4050 let second = stack[stack.len() - 2].clone();
4051 stack.push(second);
4052 }
4053 Ok(true)
4054 } else {
4055 Ok(false)
4056 }
4057 }
4058
4059 OP_PICK => {
4061 if let Some(n_bytes) = stack.pop() {
4062 let n_val = script_num_decode(&n_bytes, 4)?;
4065 if n_val < 0 || n_val as usize >= stack.len() {
4066 return Ok(false);
4067 }
4068 let n = n_val as usize;
4069 let len = stack.len();
4070 #[cfg(feature = "production")]
4071 {
4072 unsafe {
4074 let item = stack.get_unchecked(len - 1 - n);
4075 stack.push(item.clone());
4076 }
4077 }
4078 #[cfg(not(feature = "production"))]
4079 {
4080 let item = stack[stack.len() - 1 - n].clone();
4081 stack.push(item);
4082 }
4083 Ok(true)
4084 } else {
4085 Ok(false)
4086 }
4087 }
4088
4089 OP_ROLL => {
4091 if let Some(n_bytes) = stack.pop() {
4092 let n_val = script_num_decode(&n_bytes, 4)?;
4095 if n_val < 0 || n_val as usize >= stack.len() {
4096 return Ok(false);
4097 }
4098 let n = n_val as usize;
4099 let len = stack.len();
4100 #[cfg(feature = "production")]
4101 {
4102 let idx = len - 1 - n;
4104 let item = stack.remove(idx);
4105 stack.push(item);
4106 }
4107 #[cfg(not(feature = "production"))]
4108 {
4109 let item = stack.remove(stack.len() - 1 - n);
4110 stack.push(item);
4111 }
4112 Ok(true)
4113 } else {
4114 Ok(false)
4115 }
4116 }
4117
4118 OP_ROT => {
4120 if stack.len() >= 3 {
4121 let top = stack.pop().unwrap();
4122 let second = stack.pop().unwrap();
4123 let third = stack.pop().unwrap();
4124 stack.push(second);
4125 stack.push(top);
4126 stack.push(third);
4127 Ok(true)
4128 } else {
4129 Ok(false)
4130 }
4131 }
4132
4133 OP_SWAP => {
4135 if stack.len() >= 2 {
4136 let top = stack.pop().unwrap();
4137 let second = stack.pop().unwrap();
4138 stack.push(top);
4139 stack.push(second);
4140 Ok(true)
4141 } else {
4142 Ok(false)
4143 }
4144 }
4145
4146 OP_TUCK => {
4148 if stack.len() >= 2 {
4149 let top = stack.pop().unwrap();
4150 let second = stack.pop().unwrap();
4151 stack.push(top.clone());
4152 stack.push(second);
4153 stack.push(top);
4154 Ok(true)
4155 } else {
4156 Ok(false)
4157 }
4158 }
4159
4160 OP_2DROP => {
4162 if stack.len() >= 2 {
4163 stack.pop();
4164 stack.pop();
4165 Ok(true)
4166 } else {
4167 Ok(false)
4168 }
4169 }
4170
4171 OP_2DUP => {
4173 if stack.len() >= 2 {
4174 let top = stack[stack.len() - 1].clone();
4175 let second = stack[stack.len() - 2].clone();
4176 stack.push(second);
4177 stack.push(top);
4178 Ok(true)
4179 } else {
4180 Ok(false)
4181 }
4182 }
4183
4184 OP_3DUP => {
4186 if stack.len() >= 3 {
4187 let top = stack[stack.len() - 1].clone();
4188 let second = stack[stack.len() - 2].clone();
4189 let third = stack[stack.len() - 3].clone();
4190 stack.push(third);
4191 stack.push(second);
4192 stack.push(top);
4193 Ok(true)
4194 } else {
4195 Ok(false)
4196 }
4197 }
4198
4199 OP_2OVER => {
4201 if stack.len() >= 4 {
4202 let fourth = stack[stack.len() - 4].clone();
4203 let third = stack[stack.len() - 3].clone();
4204 stack.push(fourth);
4205 stack.push(third);
4206 Ok(true)
4207 } else {
4208 Ok(false)
4209 }
4210 }
4211
4212 OP_2ROT => {
4214 if stack.len() >= 6 {
4215 let sixth = stack.remove(stack.len() - 6);
4216 let fifth = stack.remove(stack.len() - 5);
4217 stack.push(fifth);
4218 stack.push(sixth);
4219 Ok(true)
4220 } else {
4221 Ok(false)
4222 }
4223 }
4224
4225 OP_2SWAP => {
4227 if stack.len() >= 4 {
4228 let top = stack.pop().unwrap();
4229 let second = stack.pop().unwrap();
4230 let third = stack.pop().unwrap();
4231 let fourth = stack.pop().unwrap();
4232 stack.push(second);
4233 stack.push(top);
4234 stack.push(fourth);
4235 stack.push(third);
4236 Ok(true)
4237 } else {
4238 Ok(false)
4239 }
4240 }
4241
4242 OP_SIZE => {
4245 if let Some(item) = stack.last() {
4246 let size = item.len() as i64;
4247 stack.push(to_stack_element(&script_num_encode(size)));
4248 Ok(true)
4249 } else {
4250 Ok(false)
4251 }
4252 }
4253
4254 OP_1ADD => {
4259 if let Some(item) = stack.pop() {
4260 let a = script_num_decode(&item, 4)?;
4261 stack.push(to_stack_element(&script_num_encode(a + 1)));
4262 Ok(true)
4263 } else {
4264 Ok(false)
4265 }
4266 }
4267 OP_1SUB => {
4269 if let Some(item) = stack.pop() {
4270 let a = script_num_decode(&item, 4)?;
4271 stack.push(to_stack_element(&script_num_encode(a - 1)));
4272 Ok(true)
4273 } else {
4274 Ok(false)
4275 }
4276 }
4277 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4279 code: ScriptErrorCode::DisabledOpcode,
4280 message: "OP_2MUL is disabled".into(),
4281 }),
4282 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4284 code: ScriptErrorCode::DisabledOpcode,
4285 message: "OP_2DIV is disabled".into(),
4286 }),
4287 OP_NEGATE => {
4289 if let Some(item) = stack.pop() {
4290 let a = script_num_decode(&item, 4)?;
4291 stack.push(to_stack_element(&script_num_encode(-a)));
4292 Ok(true)
4293 } else {
4294 Ok(false)
4295 }
4296 }
4297 OP_ABS => {
4299 if let Some(item) = stack.pop() {
4300 let a = script_num_decode(&item, 4)?;
4301 stack.push(to_stack_element(&script_num_encode(a.abs())));
4302 Ok(true)
4303 } else {
4304 Ok(false)
4305 }
4306 }
4307 OP_NOT => {
4309 if let Some(item) = stack.pop() {
4310 let a = script_num_decode(&item, 4)?;
4311 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4312 1
4313 } else {
4314 0
4315 })));
4316 Ok(true)
4317 } else {
4318 Ok(false)
4319 }
4320 }
4321 OP_0NOTEQUAL => {
4323 if let Some(item) = stack.pop() {
4324 let a = script_num_decode(&item, 4)?;
4325 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4326 1
4327 } else {
4328 0
4329 })));
4330 Ok(true)
4331 } else {
4332 Ok(false)
4333 }
4334 }
4335 OP_ADD => arithmetic::op_add(stack),
4336 OP_SUB => arithmetic::op_sub(stack),
4337 OP_MUL => arithmetic::op_mul_disabled(),
4338 OP_DIV => arithmetic::op_div_disabled(),
4339 OP_MOD => arithmetic::op_mod_disabled(),
4340 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4341 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4342 OP_BOOLAND => arithmetic::op_booland(stack),
4343 OP_BOOLOR => arithmetic::op_boolor(stack),
4344 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4345 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4346 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4347 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4348 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4349 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4350 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4351 OP_MIN => arithmetic::op_min(stack),
4352 OP_MAX => arithmetic::op_max(stack),
4353 OP_WITHIN => arithmetic::op_within(stack),
4354
4355 OP_CODESEPARATOR => Ok(true),
4357
4358 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4361
4362 OP_CHECKTEMPLATEVERIFY => {
4364 #[cfg(not(feature = "ctv"))]
4365 {
4366 Ok(true)
4368 }
4369
4370 #[cfg(feature = "ctv")]
4371 {
4372 return Err(ConsensusError::ScriptErrorWithCode {
4374 code: ScriptErrorCode::TxInvalid,
4375 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4376 });
4377 }
4378 }
4379
4380 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4382 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4383 Err(ConsensusError::ScriptErrorWithCode {
4384 code: ScriptErrorCode::DisabledOpcode,
4385 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4386 })
4387 }
4388
4389 _ => Ok(false),
4391 }
4392}
4393
4394#[allow(dead_code)]
4396fn execute_opcode_with_context(
4397 opcode: u8,
4398 stack: &mut Vec<StackElement>,
4399 flags: u32,
4400 tx: &Transaction,
4401 input_index: usize,
4402 prevouts: &[TransactionOutput],
4403 network: crate::types::Network,
4404) -> Result<bool> {
4405 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4407 let prevout_script_pubkeys: Vec<&[u8]> =
4408 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4409 let ctx = context::ScriptContext {
4410 tx,
4411 input_index,
4412 prevout_values: &prevout_values,
4413 prevout_script_pubkeys: &prevout_script_pubkeys,
4414 block_height: None,
4415 median_time_past: None,
4416 network,
4417 sigversion: SigVersion::Base,
4418 redeem_script_for_sighash: None,
4419 script_sig_for_sighash: None,
4420 tapscript_for_sighash: None,
4421 tapscript_codesep_pos: None,
4422 #[cfg(feature = "production")]
4423 schnorr_collector: None,
4424 #[cfg(feature = "production")]
4425 precomputed_bip143: None,
4426 #[cfg(feature = "production")]
4427 sighash_cache: None,
4428 };
4429 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4430}
4431
4432#[cfg(feature = "production")]
4436#[inline(always)]
4437pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4438 let mut i = 0;
4439 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4440 i += adv1;
4441 if i >= script_sig.len() {
4442 return None;
4443 }
4444 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4445 i += adv2;
4446 if i >= script_sig.len() {
4447 return None;
4448 }
4449 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4450 i += adv3;
4451 if i != script_sig.len() {
4452 return None;
4453 }
4454 let sig = &script_sig[s_start..s_end];
4455 let redeem = &script_sig[r_start..r_end];
4456 if sig.is_empty() || redeem.len() != 25 {
4457 return None;
4458 }
4459 if redeem[0] != OP_DUP
4460 || redeem[1] != OP_HASH160
4461 || redeem[2] != PUSH_20_BYTES
4462 || redeem[23] != OP_EQUALVERIFY
4463 || redeem[24] != OP_CHECKSIG
4464 {
4465 return None;
4466 }
4467 Some((sig[sig.len() - 1], redeem))
4468}
4469
4470#[inline(always)]
4474pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4475 let mut i = 0;
4476 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4477 i += adv1;
4478 if i >= script_sig.len() {
4479 return None;
4480 }
4481 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4482 i += adv2;
4483 if i != script_sig.len() {
4484 return None;
4485 }
4486 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4487}
4488
4489pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4492 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4493 if advance != script_sig.len() {
4494 return None;
4495 }
4496 Some(&script_sig[data_start..data_end])
4497}
4498
4499fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4501 if i >= script.len() {
4502 return None;
4503 }
4504 let opcode = script[i];
4505 let (advance, data_start, data_end) = if opcode == OP_0 {
4506 return None;
4507 } else if opcode <= 0x4b {
4508 let len = opcode as usize;
4509 if i + 1 + len > script.len() {
4510 return None;
4511 }
4512 (1 + len, i + 1, i + 1 + len)
4513 } else if opcode == OP_PUSHDATA1 {
4514 if i + 1 >= script.len() {
4515 return None;
4516 }
4517 let len = script[i + 1] as usize;
4518 if i + 2 + len > script.len() {
4519 return None;
4520 }
4521 (2 + len, i + 2, i + 2 + len)
4522 } else if opcode == OP_PUSHDATA2 {
4523 if i + 2 >= script.len() {
4524 return None;
4525 }
4526 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4527 if i + 3 + len > script.len() {
4528 return None;
4529 }
4530 (3 + len, i + 3, i + 3 + len)
4531 } else if opcode == OP_PUSHDATA4 {
4532 if i + 4 >= script.len() {
4533 return None;
4534 }
4535 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4536 as usize;
4537 if i + 5 + len > script.len() {
4538 return None;
4539 }
4540 (5 + len, i + 5, i + 5 + len)
4541 } else {
4542 return None;
4543 };
4544 Some((advance, data_start, data_end))
4545}
4546
4547#[spec_locked("5.2.1")]
4550pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4551 parse_script_sig_push_only(script_sig).is_some()
4552}
4553
4554fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4558 let mut out = Vec::new();
4559 let mut i = 0;
4560 while i < script_sig.len() {
4561 let opcode = script_sig[i];
4562 if !is_push_opcode(opcode) {
4563 return None;
4564 }
4565 let (advance, data) = if opcode == OP_0 {
4566 (1, vec![])
4567 } else if opcode <= 0x4b {
4568 let len = opcode as usize;
4569 if i + 1 + len > script_sig.len() {
4570 return None;
4571 }
4572 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4573 } else if opcode == OP_PUSHDATA1 {
4574 if i + 1 >= script_sig.len() {
4575 return None;
4576 }
4577 let len = script_sig[i + 1] as usize;
4578 if i + 2 + len > script_sig.len() {
4579 return None;
4580 }
4581 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4582 } else if opcode == OP_PUSHDATA2 {
4583 if i + 2 >= script_sig.len() {
4584 return None;
4585 }
4586 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4587 if i + 3 + len > script_sig.len() {
4588 return None;
4589 }
4590 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4591 } else if opcode == OP_PUSHDATA4 {
4592 if i + 4 >= script_sig.len() {
4593 return None;
4594 }
4595 let len = u32::from_le_bytes([
4596 script_sig[i + 1],
4597 script_sig[i + 2],
4598 script_sig[i + 3],
4599 script_sig[i + 4],
4600 ]) as usize;
4601 if i + 5 + len > script_sig.len() {
4602 return None;
4603 }
4604 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4605 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4606 let n = script_num_from_opcode(opcode);
4608 (1, script_num_encode(n))
4609 } else {
4610 return None;
4611 };
4612 out.push(to_stack_element(&data));
4613 i += advance;
4614 }
4615 Some(out)
4616}
4617
4618fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4622 parse_script_sig_push_only(script_sig)
4623}
4624
4625fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4630 if redeem.len() < 4 {
4631 return None;
4632 }
4633 let n_op = redeem[0];
4634 if !(OP_1..=OP_16).contains(&n_op) {
4635 return None;
4636 }
4637 let n = (n_op - OP_1 + 1) as usize;
4638 let mut i = 1;
4639 let mut pubkeys = Vec::with_capacity(n);
4640 for _ in 0..n {
4641 if i >= redeem.len() {
4642 return None;
4643 }
4644 let first = redeem[i];
4645 let pk_len = if first == 0x02 || first == 0x03 {
4646 33
4647 } else if first == 0x04 {
4648 65
4649 } else {
4650 return None;
4651 };
4652 if i + pk_len > redeem.len() {
4653 return None;
4654 }
4655 pubkeys.push(&redeem[i..i + pk_len]);
4656 i += pk_len;
4657 }
4658 if i + 2 > redeem.len() {
4659 return None;
4660 }
4661 let m_op = redeem[i];
4662 if !(OP_1..=OP_16).contains(&m_op) {
4663 return None;
4664 }
4665 let m = m_op - OP_1 + 1;
4666 if redeem[i + 1] != OP_CHECKMULTISIG {
4667 return None;
4668 }
4669 Some((m, n as u8, pubkeys))
4670}
4671
4672fn script_num_from_opcode(opcode: u8) -> i64 {
4674 match opcode {
4675 OP_1NEGATE => -1,
4676 OP_1 => 1,
4677 OP_2 => 2,
4678 OP_3 => 3,
4679 OP_4 => 4,
4680 OP_5 => 5,
4681 OP_6 => 6,
4682 OP_7 => 7,
4683 OP_8 => 8,
4684 OP_9 => 9,
4685 OP_10 => 10,
4686 OP_11 => 11,
4687 OP_12 => 12,
4688 OP_13 => 13,
4689 OP_14 => 14,
4690 OP_15 => 15,
4691 OP_16 => 16,
4692 _ => 0,
4693 }
4694}
4695
4696pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
4700 let len = data.len();
4701 let mut result = Vec::with_capacity(len + 5);
4702 if len < 76 {
4703 result.push(len as u8);
4704 } else if len < 256 {
4705 result.push(OP_PUSHDATA1);
4706 result.push(len as u8);
4707 } else if len < 65536 {
4708 result.push(OP_PUSHDATA2);
4709 result.push((len & 0xff) as u8);
4710 result.push(((len >> 8) & 0xff) as u8);
4711 } else {
4712 result.push(OP_PUSHDATA4);
4713 result.push((len & 0xff) as u8);
4714 result.push(((len >> 8) & 0xff) as u8);
4715 result.push(((len >> 16) & 0xff) as u8);
4716 result.push(((len >> 24) & 0xff) as u8);
4717 }
4718 result.extend_from_slice(data);
4719 result
4720}
4721
4722#[inline]
4724fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
4725 if pc >= script.len() {
4726 return None;
4727 }
4728 let opcode = script[pc];
4729 let advance = if opcode <= 0x4b {
4730 1 + opcode as usize
4731 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
4732 2 + script[pc + 1] as usize
4733 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
4734 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
4735 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
4736 5 + ((script[pc + 1] as usize)
4737 | ((script[pc + 2] as usize) << 8)
4738 | ((script[pc + 3] as usize) << 16)
4739 | ((script[pc + 4] as usize) << 24))
4740 } else {
4741 1
4742 };
4743 let next = pc + advance;
4744 if next > script.len() {
4745 None
4746 } else {
4747 Some(next)
4748 }
4749}
4750
4751#[spec_locked("5.1.1")]
4757#[inline]
4758pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
4759 if pattern.is_empty() {
4760 return std::borrow::Cow::Borrowed(script);
4761 }
4762 if pattern.len() > script.len() {
4763 return std::borrow::Cow::Borrowed(script);
4764 }
4765 if !script.windows(pattern.len()).any(|w| w == pattern) {
4770 return std::borrow::Cow::Borrowed(script);
4771 }
4772 let end = script.len();
4773 let mut n_found = 0usize;
4774 let mut result = Vec::new();
4775 let mut pc = 0usize;
4776 let mut pc2 = 0usize;
4777
4778 loop {
4779 result.extend_from_slice(&script[pc2..pc]);
4780 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
4781 pc += pattern.len();
4782 n_found += 1;
4783 }
4784 pc2 = pc;
4785 if pc >= end {
4786 break;
4787 }
4788 let Some(next_pc) = script_get_op_advance(script, pc) else {
4789 break;
4790 };
4791 pc = next_pc;
4792 }
4793
4794 if n_found > 0 {
4795 result.extend_from_slice(&script[pc2..end]);
4796 std::borrow::Cow::Owned(result)
4797 } else {
4798 std::borrow::Cow::Borrowed(script)
4799 }
4800}
4801
4802fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
4804 let mut pos = 0u32;
4805 let mut i = 0usize;
4806 while i < script.len() && i <= byte_index {
4807 let opcode = script[i];
4808 let advance = if opcode <= 0x4b {
4809 1 + opcode as usize
4810 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
4811 2 + script[i + 1] as usize
4812 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
4813 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
4814 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
4815 5 + ((script[i + 1] as usize)
4816 | ((script[i + 2] as usize) << 8)
4817 | ((script[i + 3] as usize) << 16)
4818 | ((script[i + 4] as usize) << 24))
4819 } else {
4820 1
4821 };
4822 if i == byte_index {
4823 return pos;
4824 }
4825 pos += 1;
4826 i = std::cmp::min(i + advance, script.len());
4827 }
4828 0xffff_ffff
4829}
4830
4831#[cfg_attr(feature = "production", inline(always))]
4833fn execute_opcode_with_context_full(
4834 opcode: u8,
4835 stack: &mut Vec<StackElement>,
4836 flags: u32,
4837 ctx: &context::ScriptContext<'_>,
4838 effective_script_code: Option<&[u8]>,
4839) -> Result<bool> {
4840 let tx = ctx.tx;
4841 let input_index = ctx.input_index;
4842 let prevout_values = ctx.prevout_values;
4843 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
4844 let block_height = ctx.block_height;
4845 let median_time_past = ctx.median_time_past;
4846 let network = ctx.network;
4847 let sigversion = ctx.sigversion;
4848 let script_sig_for_sighash = ctx.script_sig_for_sighash;
4849 let tapscript_for_sighash = ctx.tapscript_for_sighash;
4850 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
4851 let redeem_script_for_sighash = effective_script_code;
4852 #[cfg(feature = "production")]
4853 let schnorr_collector = ctx.schnorr_collector;
4854 #[cfg(feature = "production")]
4855 let precomputed_bip143 = ctx.precomputed_bip143;
4856 #[cfg(feature = "production")]
4857 let sighash_cache = ctx.sighash_cache;
4858
4859 match opcode {
4861 OP_CHECKSIG => {
4863 if stack.len() >= 2 {
4864 let pubkey_bytes = stack.pop().unwrap();
4865 let signature_bytes = stack.pop().unwrap();
4866
4867 if signature_bytes.is_empty() {
4869 stack.push(to_stack_element(&[0]));
4870 return Ok(true);
4871 }
4872
4873 if sigversion == SigVersion::Tapscript {
4876 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
4878 let sighash_byte = 0x00;
4879 let (tapscript, codesep_pos) = tapscript_for_sighash
4880 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
4881 .unwrap_or((&[] as &[u8], 0xffff_ffff));
4882 let sighash = if tapscript.is_empty() {
4883 crate::taproot::compute_taproot_signature_hash(
4884 tx,
4885 input_index,
4886 prevout_values,
4887 prevout_script_pubkeys,
4888 sighash_byte,
4889 )?
4890 } else {
4891 crate::taproot::compute_tapscript_signature_hash(
4892 tx,
4893 input_index,
4894 prevout_values,
4895 prevout_script_pubkeys,
4896 tapscript,
4897 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
4898 codesep_pos,
4899 sighash_byte,
4900 )?
4901 };
4902
4903 #[cfg(feature = "production")]
4905 let is_valid = {
4906 use crate::bip348::verify_tapscript_schnorr_signature;
4907 verify_tapscript_schnorr_signature(
4908 &sighash,
4909 &pubkey_bytes,
4910 &signature_bytes,
4911 schnorr_collector,
4912 )
4913 .unwrap_or(false)
4914 };
4915
4916 #[cfg(not(feature = "production"))]
4917 let is_valid = {
4918 #[cfg(feature = "csfs")]
4919 let x = {
4920 use crate::bip348::verify_tapscript_schnorr_signature;
4921 verify_tapscript_schnorr_signature(
4922 &sighash,
4923 &pubkey_bytes,
4924 &signature_bytes,
4925 None,
4926 )
4927 .unwrap_or(false)
4928 };
4929 #[cfg(not(feature = "csfs"))]
4930 let x = false;
4931 x
4932 };
4933
4934 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
4935 return Ok(true);
4936 }
4937 }
4939
4940 let sig_len = signature_bytes.len();
4944 let sighash_byte = signature_bytes[sig_len - 1];
4945 let _der_sig = &signature_bytes[..sig_len - 1];
4946
4947 let sighash = if sigversion == SigVersion::WitnessV0 {
4951 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
4953
4954 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
4956 prevout_script_pubkeys
4957 .get(input_index)
4958 .copied()
4959 .unwrap_or(&[])
4960 });
4961
4962 crate::transaction_hash::calculate_bip143_sighash(
4963 tx,
4964 input_index,
4965 script_code,
4966 amount,
4967 sighash_byte,
4968 precomputed_bip143,
4969 )?
4970 } else {
4971 use crate::transaction_hash::{
4973 calculate_transaction_sighash_single_input, SighashType,
4974 };
4975 let sighash_type = SighashType::from_byte(sighash_byte);
4976
4977 let pattern = serialize_push_data(signature_bytes.as_ref());
4981
4982 let base_script = match (
4983 redeem_script_for_sighash,
4984 prevout_script_pubkeys.get(input_index),
4985 ) {
4986 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
4987 (Some(redeem), _) => redeem,
4988 (None, Some(prevout)) => *prevout,
4989 (None, None) => &[],
4990 };
4991 let cleaned = find_and_delete(base_script, &pattern);
4992
4993 calculate_transaction_sighash_single_input(
4994 tx,
4995 input_index,
4996 cleaned.as_ref(),
4997 prevout_values[input_index],
4998 sighash_type,
4999 #[cfg(feature = "production")]
5000 sighash_cache,
5001 )?
5002 };
5003
5004 let height = block_height.unwrap_or(0);
5008 #[cfg(feature = "production")]
5009 let is_valid = signature::with_secp_context(|secp| {
5010 signature::verify_signature(
5011 secp,
5012 &pubkey_bytes,
5013 &signature_bytes, &sighash,
5015 flags,
5016 height,
5017 network,
5018 sigversion,
5019 )
5020 })?;
5021
5022 #[cfg(not(feature = "production"))]
5023 let is_valid = {
5024 let secp = signature::new_secp();
5025 signature::verify_signature(
5026 &secp,
5027 &pubkey_bytes,
5028 &signature_bytes, &sighash,
5030 flags,
5031 height,
5032 network,
5033 sigversion,
5034 )?
5035 };
5036
5037 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5038 Ok(true)
5039 } else {
5040 Ok(false)
5041 }
5042 }
5043
5044 OP_CHECKSIGVERIFY => {
5046 if stack.len() >= 2 {
5047 let pubkey_bytes = stack.pop().unwrap();
5048 let signature_bytes = stack.pop().unwrap();
5049
5050 if signature_bytes.is_empty() {
5052 return Ok(false);
5053 }
5054
5055 let sig_len = signature_bytes.len();
5059 let sighash_byte = signature_bytes[sig_len - 1];
5060 let _der_sig = &signature_bytes[..sig_len - 1];
5061
5062 let sighash = if sigversion == SigVersion::WitnessV0 {
5066 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5068
5069 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5070 prevout_script_pubkeys
5071 .get(input_index)
5072 .copied()
5073 .unwrap_or(&[])
5074 });
5075
5076 crate::transaction_hash::calculate_bip143_sighash(
5077 tx,
5078 input_index,
5079 script_code,
5080 amount,
5081 sighash_byte,
5082 precomputed_bip143,
5083 )?
5084 } else {
5085 use crate::transaction_hash::{
5087 calculate_transaction_sighash_single_input, SighashType,
5088 };
5089 let sighash_type = SighashType::from_byte(sighash_byte);
5090
5091 let pattern = serialize_push_data(signature_bytes.as_ref());
5093
5094 let base_script = match (
5095 redeem_script_for_sighash,
5096 prevout_script_pubkeys.get(input_index),
5097 ) {
5098 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5099 (Some(redeem), _) => redeem,
5100 (None, Some(prevout)) => *prevout,
5101 (None, None) => &[],
5102 };
5103 let cleaned = find_and_delete(base_script, &pattern);
5104
5105 calculate_transaction_sighash_single_input(
5106 tx,
5107 input_index,
5108 cleaned.as_ref(),
5109 prevout_values[input_index],
5110 sighash_type,
5111 #[cfg(feature = "production")]
5112 sighash_cache,
5113 )?
5114 };
5115
5116 let height = block_height.unwrap_or(0);
5120 #[cfg(feature = "production")]
5121 let is_valid = signature::with_secp_context(|secp| {
5122 signature::verify_signature(
5123 secp,
5124 &pubkey_bytes,
5125 &signature_bytes, &sighash,
5127 flags,
5128 height,
5129 network,
5130 sigversion,
5131 )
5132 })?;
5133
5134 #[cfg(not(feature = "production"))]
5135 let is_valid = {
5136 let secp = signature::new_secp();
5137 signature::verify_signature(
5138 &secp,
5139 &pubkey_bytes,
5140 &signature_bytes, &sighash,
5142 flags,
5143 height,
5144 network,
5145 sigversion,
5146 )?
5147 };
5148
5149 if is_valid {
5150 Ok(true)
5151 } else {
5152 Ok(false)
5153 }
5154 } else {
5155 Ok(false)
5156 }
5157 }
5158
5159 OP_CHECKSIGADD => {
5161 if sigversion != SigVersion::Tapscript {
5162 return Err(ConsensusError::ScriptErrorWithCode {
5163 code: ScriptErrorCode::DisabledOpcode,
5164 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5165 });
5166 }
5167 if stack.len() < 3 {
5168 return Err(ConsensusError::ScriptErrorWithCode {
5169 code: ScriptErrorCode::InvalidStackOperation,
5170 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5171 });
5172 }
5173 let pubkey_bytes = stack.pop().unwrap();
5175 let n_bytes = stack.pop().unwrap();
5176 let signature_bytes = stack.pop().unwrap();
5177 let n = script_num_decode(&n_bytes, 4)?;
5178
5179 if signature_bytes.is_empty() {
5181 stack.push(to_stack_element(&script_num_encode(n)));
5182 return Ok(true);
5183 }
5184
5185 if pubkey_bytes.len() == 32 && signature_bytes.len() == 64 {
5187 let sighash_byte = 0x00;
5188 let (tapscript, codesep_pos) = tapscript_for_sighash
5189 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5190 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5191 let sighash = if tapscript.is_empty() {
5192 crate::taproot::compute_taproot_signature_hash(
5193 tx,
5194 input_index,
5195 prevout_values,
5196 prevout_script_pubkeys,
5197 sighash_byte,
5198 )?
5199 } else {
5200 crate::taproot::compute_tapscript_signature_hash(
5201 tx,
5202 input_index,
5203 prevout_values,
5204 prevout_script_pubkeys,
5205 tapscript,
5206 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5207 codesep_pos,
5208 sighash_byte,
5209 )?
5210 };
5211
5212 #[cfg(feature = "production")]
5213 let is_valid = {
5214 use crate::bip348::verify_tapscript_schnorr_signature;
5215 verify_tapscript_schnorr_signature(
5216 &sighash,
5217 &pubkey_bytes,
5218 &signature_bytes,
5219 schnorr_collector,
5220 )
5221 .unwrap_or(false)
5222 };
5223
5224 #[cfg(not(feature = "production"))]
5225 let is_valid = {
5226 #[cfg(feature = "csfs")]
5227 let x = {
5228 use crate::bip348::verify_tapscript_schnorr_signature;
5229 verify_tapscript_schnorr_signature(
5230 &sighash,
5231 &pubkey_bytes,
5232 &signature_bytes,
5233 None,
5234 )
5235 .unwrap_or(false)
5236 };
5237 #[cfg(not(feature = "csfs"))]
5238 let x = false;
5239 x
5240 };
5241
5242 if !is_valid {
5243 return Ok(false); }
5245 stack.push(to_stack_element(&script_num_encode(n + 1)));
5246 return Ok(true);
5247 }
5248
5249 stack.push(to_stack_element(&script_num_encode(n + 1)));
5251 Ok(true)
5252 }
5253
5254 OP_CHECKMULTISIG => {
5256 if stack.len() < 2 {
5259 return Ok(false);
5260 }
5261
5262 let n_bytes = stack.pop().unwrap();
5265 let n = if n_bytes.is_empty() {
5266 0
5267 } else {
5268 n_bytes[0] as usize
5269 };
5270 if n > 20 || stack.len() < n + 1 {
5271 return Ok(false);
5272 }
5273
5274 let mut pubkeys = Vec::with_capacity(n);
5276 for _ in 0..n {
5277 pubkeys.push(stack.pop().unwrap());
5278 }
5279
5280 let m_bytes = stack.pop().unwrap();
5283 let m = if m_bytes.is_empty() {
5284 0
5285 } else {
5286 m_bytes[0] as usize
5287 };
5288 if m > n || m > 20 || stack.len() < m + 1 {
5289 return Ok(false);
5290 }
5291
5292 let mut signatures = Vec::with_capacity(m);
5294 for _ in 0..m {
5295 signatures.push(stack.pop().unwrap());
5296 }
5297
5298 let dummy = stack.pop().unwrap();
5301 if flags & 0x10 != 0 {
5302 let height = block_height.unwrap_or(0);
5303 use crate::bip_validation::Bip147Network;
5305 let bip147_network = match network {
5306 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5307 crate::types::Network::Testnet => Bip147Network::Testnet,
5308 crate::types::Network::Regtest => Bip147Network::Regtest,
5309 };
5310
5311 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5315
5316 let bip147_active = height
5317 >= match bip147_network {
5318 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5319 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5320 Bip147Network::Regtest => 0,
5321 };
5322
5323 if bip147_active {
5324 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5328 if !is_empty {
5329 return Err(ConsensusError::ScriptErrorWithCode {
5330 code: ScriptErrorCode::SigNullDummy,
5331 message: format!(
5332 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5333 )
5334 .into(),
5335 });
5336 }
5337 }
5338 }
5339
5340 let height = block_height.unwrap_or(0);
5343
5344 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5347 let base_script = match (
5348 redeem_script_for_sighash,
5349 prevout_script_pubkeys.get(input_index),
5350 ) {
5351 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5352 (Some(redeem), _) => redeem,
5353 (None, Some(prevout)) => *prevout,
5354 (None, None) => &[],
5355 };
5356 let mut cleaned = base_script.to_vec();
5357 for sig in &signatures {
5358 if !sig.is_empty() {
5359 let pattern = serialize_push_data(sig.as_ref());
5360 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5361 }
5362 }
5363 cleaned
5364 } else {
5365 redeem_script_for_sighash
5367 .map(|s| s.to_vec())
5368 .unwrap_or_else(|| {
5369 prevout_script_pubkeys
5370 .get(input_index)
5371 .map(|p| p.to_vec())
5372 .unwrap_or_default()
5373 })
5374 };
5375
5376 use crate::transaction_hash::{
5377 calculate_transaction_sighash_single_input, SighashType,
5378 };
5379
5380 #[cfg(feature = "production")]
5382 let use_batch = pubkeys.len() * signatures.len() >= 4;
5383
5384 #[cfg(feature = "production")]
5385 let (valid_sigs, _) = if use_batch {
5386 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5388 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5389 if non_empty.is_empty() {
5390 vec![]
5391 } else {
5392 let specs: Vec<(usize, u8, &[u8])> = non_empty
5393 .iter()
5394 .map(|s| {
5395 (
5396 input_index,
5397 s.as_ref()[s.as_ref().len() - 1],
5398 cleaned_script_for_multisig.as_ref(),
5399 )
5400 })
5401 .collect();
5402 crate::transaction_hash::batch_compute_legacy_sighashes(
5403 tx,
5404 prevout_values,
5405 prevout_script_pubkeys,
5406 &specs,
5407 )?
5408 }
5409 } else {
5410 signatures
5411 .iter()
5412 .filter(|s| !s.is_empty())
5413 .map(|sig_bytes| {
5414 let sighash_type =
5415 SighashType::from_byte(sig_bytes[sig_bytes.len() - 1]);
5416 calculate_transaction_sighash_single_input(
5417 tx,
5418 input_index,
5419 &cleaned_script_for_multisig,
5420 prevout_values[input_index],
5421 sighash_type,
5422 sighash_cache,
5423 )
5424 })
5425 .collect::<Result<Vec<_>>>()?
5426 };
5427
5428 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5430 Vec::with_capacity(pubkeys.len() * signatures.len());
5431 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5432 let mut sighash_idx = 0usize;
5433 for (j, sig_bytes) in signatures.iter().enumerate() {
5434 if sig_bytes.is_empty() {
5435 sig_idx_to_sighash_idx.push(usize::MAX);
5436 } else {
5437 sig_idx_to_sighash_idx.push(sighash_idx);
5438 let sh = sighashes[sighash_idx];
5439 sighash_idx += 1;
5440 for pubkey_bytes in &pubkeys {
5441 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5442 }
5443 }
5444 }
5445
5446 let results = if tasks.is_empty() {
5447 vec![]
5448 } else {
5449 batch_verify_signatures(&tasks, flags, height, network)?
5450 };
5451
5452 let mut sig_index = 0;
5454 let mut valid_sigs = 0usize;
5455 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5456 if sig_index >= signatures.len() {
5457 break;
5458 }
5459 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5461 sig_index += 1;
5462 }
5463 if sig_index >= signatures.len() {
5464 break;
5465 }
5466 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5467 if sh_idx == usize::MAX {
5468 continue;
5469 }
5470 let task_idx = sh_idx * pubkeys.len() + i;
5471 if task_idx < results.len() && results[task_idx] {
5472 valid_sigs += 1;
5473 sig_index += 1;
5474 }
5475 }
5476
5477 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5479 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5480 for (j, sig_bytes) in signatures.iter().enumerate() {
5481 if sig_bytes.is_empty() {
5482 continue;
5483 }
5484 let sh_idx = sig_idx_to_sighash_idx[j];
5485 if sh_idx == usize::MAX {
5486 continue;
5487 }
5488 let sig_start = sh_idx * pubkeys.len();
5489 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5490 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5491 if !matched {
5492 return Err(ConsensusError::ScriptErrorWithCode {
5493 code: ScriptErrorCode::SigNullFail,
5494 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5495 });
5496 }
5497 }
5498 }
5499 (valid_sigs, ())
5500 } else {
5501 let mut sig_index = 0;
5502 let mut valid_sigs = 0;
5503
5504 for pubkey_bytes in &pubkeys {
5505 if sig_index >= signatures.len() {
5506 break;
5507 }
5508
5509 let signature_bytes = &signatures[sig_index];
5510
5511 if signature_bytes.is_empty() {
5512 continue;
5513 }
5514
5515 let sig_len = signature_bytes.len();
5516 let sighash_byte = signature_bytes[sig_len - 1];
5517 let sighash_type = SighashType::from_byte(sighash_byte);
5518
5519 let sighash = calculate_transaction_sighash_single_input(
5520 tx,
5521 input_index,
5522 &cleaned_script_for_multisig,
5523 prevout_values[input_index],
5524 sighash_type,
5525 #[cfg(feature = "production")]
5526 sighash_cache,
5527 )?;
5528
5529 #[cfg(feature = "production")]
5530 let is_valid = signature::with_secp_context(|secp| {
5531 signature::verify_signature(
5532 secp,
5533 pubkey_bytes,
5534 signature_bytes,
5535 &sighash,
5536 flags,
5537 height,
5538 network,
5539 sigversion,
5540 )
5541 })?;
5542
5543 #[cfg(not(feature = "production"))]
5544 let is_valid = {
5545 let secp = signature::new_secp();
5546 signature::verify_signature(
5547 &secp,
5548 pubkey_bytes,
5549 signature_bytes,
5550 &sighash,
5551 flags,
5552 height,
5553 network,
5554 sigversion,
5555 )?
5556 };
5557
5558 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5559 if !is_valid
5560 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5561 && !signature_bytes.is_empty()
5562 {
5563 return Err(ConsensusError::ScriptErrorWithCode {
5564 code: ScriptErrorCode::SigNullFail,
5565 message:
5566 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5567 .into(),
5568 });
5569 }
5570
5571 if is_valid {
5572 valid_sigs += 1;
5573 sig_index += 1;
5574 }
5575 }
5576 (valid_sigs, ())
5577 };
5578
5579 #[cfg(not(feature = "production"))]
5580 let (valid_sigs, _) = {
5581 let mut sig_index = 0;
5582 let mut valid_sigs = 0;
5583
5584 for pubkey_bytes in &pubkeys {
5585 if sig_index >= signatures.len() {
5586 break;
5587 }
5588 let signature_bytes = &signatures[sig_index];
5589 if signature_bytes.is_empty() {
5590 continue;
5591 }
5592 let sig_len = signature_bytes.len();
5593 let sighash_type = SighashType::from_byte(signature_bytes[sig_len - 1]);
5594 let sighash = calculate_transaction_sighash_single_input(
5595 tx,
5596 input_index,
5597 &cleaned_script_for_multisig,
5598 prevout_values[input_index],
5599 sighash_type,
5600 #[cfg(feature = "production")]
5601 sighash_cache,
5602 )?;
5603 let secp = signature::new_secp();
5604 let is_valid = signature::verify_signature(
5605 &secp,
5606 pubkey_bytes,
5607 signature_bytes,
5608 &sighash,
5609 flags,
5610 height,
5611 network,
5612 sigversion,
5613 )?;
5614 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5615 if !is_valid
5616 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5617 && !signature_bytes.is_empty()
5618 {
5619 return Err(ConsensusError::ScriptErrorWithCode {
5620 code: ScriptErrorCode::SigNullFail,
5621 message:
5622 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5623 .into(),
5624 });
5625 }
5626 if is_valid {
5627 valid_sigs += 1;
5628 sig_index += 1;
5629 }
5630 }
5631 (valid_sigs, ())
5632 };
5633
5634 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
5636 Ok(true)
5637 }
5638
5639 OP_CHECKMULTISIGVERIFY => {
5641 let ctx_checkmultisig = context::ScriptContext {
5643 tx,
5644 input_index,
5645 prevout_values,
5646 prevout_script_pubkeys,
5647 block_height,
5648 median_time_past,
5649 network,
5650 sigversion,
5651 redeem_script_for_sighash,
5652 script_sig_for_sighash,
5653 tapscript_for_sighash,
5654 tapscript_codesep_pos,
5655 #[cfg(feature = "production")]
5656 schnorr_collector: None,
5657 #[cfg(feature = "production")]
5658 precomputed_bip143,
5659 #[cfg(feature = "production")]
5660 sighash_cache,
5661 };
5662 let result = execute_opcode_with_context_full(
5663 OP_CHECKMULTISIG,
5664 stack,
5665 flags,
5666 &ctx_checkmultisig,
5667 redeem_script_for_sighash,
5668 )?;
5669 if !result {
5670 return Ok(false);
5671 }
5672 if let Some(top) = stack.pop() {
5674 if !cast_to_bool(&top) {
5675 return Ok(false);
5676 }
5677 Ok(true)
5678 } else {
5679 Ok(false)
5680 }
5681 }
5682
5683 OP_CHECKLOCKTIMEVERIFY => {
5688 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
5690 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5691 return Ok(true);
5692 }
5693
5694 use crate::locktime::{check_bip65, decode_locktime_value};
5695
5696 if stack.is_empty() {
5697 return Err(ConsensusError::ScriptErrorWithCode {
5698 code: ScriptErrorCode::InvalidStackOperation,
5699 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
5700 });
5701 }
5702
5703 let locktime_bytes = stack.last().expect("Stack is not empty");
5705 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
5706 Some(v) => v,
5707 None => {
5708 return Err(ConsensusError::ScriptErrorWithCode {
5709 code: ScriptErrorCode::MinimalData,
5710 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
5711 })
5712 }
5713 };
5714
5715 let tx_locktime = tx.lock_time as u32;
5716
5717 if !check_bip65(tx_locktime, locktime_value) {
5719 return Ok(false);
5720 }
5721
5722 let input_seq = if input_index < tx.inputs.len() {
5724 tx.inputs[input_index].sequence
5725 } else {
5726 0xffffffff
5727 };
5728 if input_seq == 0xffffffff {
5729 return Ok(false);
5730 }
5731
5732 Ok(true)
5734 }
5735
5736 OP_CHECKSEQUENCEVERIFY => {
5745 use crate::locktime::{
5746 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
5747 is_sequence_disabled,
5748 };
5749
5750 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
5752 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
5753 return Ok(true);
5754 }
5755
5756 if stack.is_empty() {
5757 return Ok(false);
5758 }
5759
5760 let sequence_bytes = stack.last().expect("Stack is not empty");
5763 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
5764 Some(v) => v,
5765 None => return Ok(false), };
5767
5768 if input_index >= tx.inputs.len() {
5770 return Ok(false);
5771 }
5772 let input_sequence = tx.inputs[input_index].sequence as u32;
5773
5774 if is_sequence_disabled(input_sequence) {
5776 return Ok(true);
5777 }
5778
5779 let type_flag = extract_sequence_type_flag(sequence_value);
5781 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
5782
5783 let input_type_flag = extract_sequence_type_flag(input_sequence);
5785 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
5786
5787 if type_flag != input_type_flag {
5789 return Ok(false);
5790 }
5791
5792 if input_locktime < locktime_mask {
5794 return Ok(false);
5795 }
5796
5797 Ok(true)
5799 }
5800
5801 OP_CHECKTEMPLATEVERIFY => {
5810 #[cfg(not(feature = "ctv"))]
5811 {
5812 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5814 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5815 return Err(ConsensusError::ScriptErrorWithCode {
5816 code: ScriptErrorCode::BadOpcode,
5817 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
5818 });
5819 }
5820 Ok(true) }
5822
5823 #[cfg(feature = "ctv")]
5824 {
5825 use crate::constants::{
5826 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
5827 };
5828
5829 let ctv_activation = match network {
5831 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
5832 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
5833 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
5834 };
5835
5836 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
5837 if !ctv_active {
5838 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5840 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5841 return Err(ConsensusError::ScriptErrorWithCode {
5842 code: ScriptErrorCode::BadOpcode,
5843 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
5844 });
5845 }
5846 return Ok(true); }
5848
5849 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
5851 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
5852 return Ok(true);
5854 }
5855
5856 use crate::bip119::calculate_template_hash;
5857
5858 if stack.is_empty() {
5860 return Err(ConsensusError::ScriptErrorWithCode {
5861 code: ScriptErrorCode::InvalidStackOperation,
5862 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
5863 });
5864 }
5865
5866 let template_hash_bytes = stack.pop().unwrap();
5867
5868 if template_hash_bytes.len() != 32 {
5870 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5873 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5874 return Err(ConsensusError::ScriptErrorWithCode {
5875 code: ScriptErrorCode::InvalidStackOperation,
5876 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
5877 .into(),
5878 });
5879 }
5880 return Ok(true); }
5882
5883 let mut expected_hash = [0u8; 32];
5885 expected_hash.copy_from_slice(&template_hash_bytes);
5886
5887 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
5888 ConsensusError::ScriptErrorWithCode {
5889 code: ScriptErrorCode::TxInvalid,
5890 message: format!("CTV hash calculation failed: {e}").into(),
5891 }
5892 })?;
5893
5894 use crate::crypto::hash_compare::hash_eq;
5896 let matches = hash_eq(&expected_hash, &actual_hash);
5897
5898 if !matches {
5899 return Ok(false); }
5901
5902 Ok(true)
5904 }
5905 }
5906
5907 OP_CHECKSIGFROMSTACK => {
5918 #[cfg(not(feature = "csfs"))]
5919 {
5920 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5923 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5924 return Err(ConsensusError::ScriptErrorWithCode {
5925 code: ScriptErrorCode::BadOpcode,
5926 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
5927 });
5928 }
5929 Ok(true) }
5931
5932 #[cfg(feature = "csfs")]
5933 {
5934 use crate::constants::{
5935 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
5936 };
5937
5938 if sigversion != SigVersion::Tapscript {
5940 return Err(ConsensusError::ScriptErrorWithCode {
5941 code: ScriptErrorCode::BadOpcode,
5942 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
5943 });
5944 }
5945
5946 let csfs_activation = match network {
5948 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
5949 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
5950 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
5951 };
5952
5953 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
5954 if !csfs_active {
5955 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5957 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5958 return Err(ConsensusError::ScriptErrorWithCode {
5959 code: ScriptErrorCode::BadOpcode,
5960 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
5961 });
5962 }
5963 return Ok(true); }
5965
5966 use crate::bip348::verify_signature_from_stack;
5967
5968 if stack.len() < 3 {
5970 return Err(ConsensusError::ScriptErrorWithCode {
5971 code: ScriptErrorCode::InvalidStackOperation,
5972 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
5973 });
5974 }
5975
5976 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
5983 return Err(ConsensusError::ScriptErrorWithCode {
5984 code: ScriptErrorCode::PubkeyType,
5985 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
5986 });
5987 }
5988
5989 if signature_bytes.is_empty() {
5991 stack.push(to_stack_element(&[])); return Ok(true);
5993 }
5994
5995 #[cfg(feature = "production")]
5998 let is_valid = {
5999 verify_signature_from_stack(
6000 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6005 .unwrap_or(false)
6006 };
6007 #[cfg(not(feature = "production"))]
6008 let is_valid = verify_signature_from_stack(
6009 &message_bytes, &pubkey_bytes, &signature_bytes, )
6013 .unwrap_or(false);
6014
6015 if !is_valid {
6016 return Ok(false);
6018 }
6019
6020 stack.push(to_stack_element(&[0x01])); Ok(true)
6027 }
6028 }
6029
6030 _ => execute_opcode_cold(opcode, stack, flags),
6032 }
6033}
6034
6035#[cold]
6037fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6038 execute_opcode(opcode, stack, flags, SigVersion::Base)
6039}
6040
6041#[cfg(feature = "production")]
6056pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6057 (
6058 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6059 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6060 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6061 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6062 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6063 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6064 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6065 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6066 )
6067}
6068
6069#[cfg(all(feature = "production", feature = "benchmarking"))]
6076pub fn clear_script_cache() {
6077 if let Some(cache) = SCRIPT_CACHE.get() {
6078 let mut cache = cache.write().unwrap();
6079 cache.clear();
6080 }
6081}
6082
6083#[cfg(all(feature = "production", feature = "benchmarking"))]
6097pub fn clear_hash_cache() {
6098 crypto_ops::clear_hash_cache();
6099}
6100
6101#[cfg(all(feature = "production", feature = "benchmarking"))]
6114pub fn clear_all_caches() {
6115 clear_script_cache();
6116 clear_hash_cache();
6117}
6118
6119#[cfg(all(feature = "production", feature = "benchmarking"))]
6133pub fn clear_stack_pool() {
6134 STACK_POOL.with(|pool| {
6135 let mut pool = pool.borrow_mut();
6136 pool.clear();
6137 });
6138}
6139
6140#[cfg(all(feature = "production", feature = "benchmarking"))]
6154pub fn reset_benchmarking_state() {
6155 clear_all_caches();
6156 clear_stack_pool();
6157 disable_caching(false); #[cfg(feature = "benchmarking")]
6160 crate::transaction_hash::clear_sighash_templates();
6161}
6162
6163#[cfg(test)]
6164mod tests {
6165 use super::*;
6166
6167 #[test]
6168 fn test_eval_script_simple() {
6169 let script = vec![OP_1]; let mut stack = Vec::new();
6171
6172 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6173 assert_eq!(stack.len(), 1);
6174 assert_eq!(stack[0].as_ref(), &[1]);
6175 }
6176
6177 #[test]
6178 fn test_eval_script_overflow() {
6179 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6181
6182 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6183 }
6184
6185 #[test]
6186 fn test_verify_script_simple() {
6187 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());
6198 }
6199
6200 #[test]
6205 fn test_op_0() {
6206 let script = vec![OP_0]; let mut stack = Vec::new();
6208 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6209 assert!(!result); assert_eq!(stack.len(), 1);
6211 assert!(stack[0].is_empty());
6212 }
6213
6214 #[test]
6215 fn test_op_1_to_op_16() {
6216 for i in 1..=16 {
6218 let opcode = 0x50 + i;
6219 let script = vec![opcode];
6220 let mut stack = Vec::new();
6221 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6222 assert!(result);
6223 assert_eq!(stack.len(), 1);
6224 assert_eq!(stack[0].as_ref(), &[i]);
6225 }
6226 }
6227
6228 #[test]
6229 fn test_op_dup() {
6230 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6232 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6233 assert!(!result); assert_eq!(stack.len(), 2);
6235 assert_eq!(stack[0].as_ref(), &[1]);
6236 assert_eq!(stack[1].as_ref(), &[1]);
6237 }
6238
6239 #[test]
6240 fn test_op_dup_empty_stack() {
6241 let script = vec![OP_DUP]; let mut stack = Vec::new();
6243 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6244 assert!(!result);
6245 }
6246
6247 #[test]
6248 fn test_op_hash160() {
6249 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6251 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6252 assert!(result);
6253 assert_eq!(stack.len(), 1);
6254 assert_eq!(stack[0].len(), 20); }
6256
6257 #[test]
6258 fn test_op_hash160_empty_stack() {
6259 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6261 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6262 assert!(!result);
6263 }
6264
6265 #[test]
6266 fn test_op_hash256() {
6267 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6269 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6270 assert!(result);
6271 assert_eq!(stack.len(), 1);
6272 assert_eq!(stack[0].len(), 32); }
6274
6275 #[test]
6276 fn test_op_hash256_empty_stack() {
6277 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6279 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6280 assert!(!result);
6281 }
6282
6283 #[test]
6284 fn test_op_equal() {
6285 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6287 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6288 assert!(result);
6289 assert_eq!(stack.len(), 1);
6290 assert_eq!(stack[0].as_ref(), &[1]); }
6292
6293 #[test]
6294 fn test_op_equal_false() {
6295 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6297 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6298 assert!(!result); assert_eq!(stack.len(), 1);
6300 assert_eq!(stack[0].as_ref(), &[0]); }
6302
6303 #[test]
6304 fn test_op_equal_insufficient_stack() {
6305 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6307 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6308 assert!(
6309 result.is_err(),
6310 "OP_EQUAL with insufficient stack should return error"
6311 );
6312 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6313 assert_eq!(
6314 code,
6315 crate::error::ScriptErrorCode::InvalidStackOperation,
6316 "Should return InvalidStackOperation"
6317 );
6318 }
6319 }
6320
6321 #[test]
6322 fn test_op_verify() {
6323 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6325 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6326 assert!(!result); assert_eq!(stack.len(), 0); }
6329
6330 #[test]
6331 fn test_op_verify_false() {
6332 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6334 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6335 assert!(!result);
6336 }
6337
6338 #[test]
6339 fn test_op_verify_empty_stack() {
6340 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6342 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6343 assert!(!result);
6344 }
6345
6346 #[test]
6347 fn test_op_equalverify() {
6348 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6350 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6351 assert!(!result); assert_eq!(stack.len(), 0); }
6354
6355 #[test]
6356 fn test_op_equalverify_false() {
6357 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6359 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6360 assert!(
6361 result.is_err(),
6362 "OP_EQUALVERIFY with false condition should return error"
6363 );
6364 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6365 assert_eq!(
6366 code,
6367 crate::error::ScriptErrorCode::EqualVerify,
6368 "Should return EqualVerify"
6369 );
6370 }
6371 }
6372
6373 #[test]
6374 fn test_op_checksig() {
6375 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6379 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6380 assert!(!result); assert_eq!(stack.len(), 1);
6382 }
6384
6385 #[test]
6386 fn test_op_checksig_insufficient_stack() {
6387 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6389 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6390 assert!(
6391 result.is_err(),
6392 "OP_CHECKSIG with insufficient stack should return error"
6393 );
6394 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6395 assert_eq!(
6396 code,
6397 crate::error::ScriptErrorCode::InvalidStackOperation,
6398 "Should return InvalidStackOperation"
6399 );
6400 }
6401 }
6402
6403 #[test]
6404 fn test_unknown_opcode() {
6405 let script = vec![0xff]; let mut stack = Vec::new();
6407 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6408 assert!(!result);
6409 }
6410
6411 #[test]
6412 fn test_script_size_limit() {
6413 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6415 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6416 assert!(result.is_err());
6417 }
6418
6419 #[test]
6420 fn test_operation_count_limit() {
6421 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6424 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6425 assert!(result.is_err());
6426 }
6427
6428 #[test]
6429 fn test_stack_underflow_multiple_ops() {
6430 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6432 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6433 assert!(result.is_err(), "Stack underflow should return error");
6434 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6435 assert_eq!(
6436 code,
6437 crate::error::ScriptErrorCode::InvalidStackOperation,
6438 "Should return InvalidStackOperation"
6439 );
6440 }
6441 }
6442
6443 #[test]
6444 fn test_final_stack_empty() {
6445 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6447 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6448 assert!(!result);
6449 }
6450
6451 #[test]
6452 fn test_final_stack_false() {
6453 let script = vec![OP_0]; let mut stack = Vec::new();
6455 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6456 assert!(!result);
6457 }
6458
6459 #[test]
6460 fn test_verify_script_with_witness() {
6461 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6465
6466 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6467 assert!(!result); }
6469
6470 #[test]
6471 fn test_verify_script_failure() {
6472 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_2]; let witness = None;
6475 let flags = 0;
6476
6477 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6478 assert!(!result);
6479 }
6480
6481 #[test]
6486 fn test_op_ifdup_true() {
6487 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6489 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6490 assert!(!result); assert_eq!(stack.len(), 2);
6492 assert_eq!(stack[0].as_ref(), &[1]);
6493 assert_eq!(stack[1].as_ref(), &[1]);
6494 }
6495
6496 #[test]
6497 fn test_op_ifdup_false() {
6498 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6500 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6501 assert!(!result); assert_eq!(stack.len(), 1);
6503 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6504 }
6505
6506 #[test]
6507 fn test_op_depth() {
6508 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6510 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6511 assert!(!result); assert_eq!(stack.len(), 3);
6513 assert_eq!(stack[2].as_ref(), &[2]); }
6515
6516 #[test]
6517 fn test_op_drop() {
6518 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
6520 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6521 assert!(result); assert_eq!(stack.len(), 1);
6523 assert_eq!(stack[0].as_ref(), &[1]);
6524 }
6525
6526 #[test]
6527 fn test_op_drop_empty_stack() {
6528 let script = vec![OP_DROP]; let mut stack = Vec::new();
6530 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6531 assert!(!result);
6532 assert_eq!(stack.len(), 0);
6533 }
6534
6535 #[test]
6536 fn test_op_nip() {
6537 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
6539 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6540 assert!(result); assert_eq!(stack.len(), 1);
6542 assert_eq!(stack[0].as_ref(), &[2]);
6543 }
6544
6545 #[test]
6546 fn test_op_nip_insufficient_stack() {
6547 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
6549 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6550 assert!(!result);
6551 assert_eq!(stack.len(), 1);
6552 }
6553
6554 #[test]
6555 fn test_op_over() {
6556 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
6558 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6559 assert!(!result); assert_eq!(stack.len(), 3);
6561 assert_eq!(stack[0].as_ref(), &[1]);
6562 assert_eq!(stack[1].as_ref(), &[2]);
6563 assert_eq!(stack[2].as_ref(), &[1]);
6564 }
6565
6566 #[test]
6567 fn test_op_over_insufficient_stack() {
6568 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
6570 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6571 assert!(!result);
6572 assert_eq!(stack.len(), 1);
6573 }
6574
6575 #[test]
6576 fn test_op_pick() {
6577 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
6579 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6580 assert!(!result); assert_eq!(stack.len(), 4);
6582 assert_eq!(stack[3].as_ref(), &[2]); }
6584
6585 #[test]
6586 fn test_op_pick_empty_n() {
6587 let script = vec![OP_1, OP_0, OP_PICK];
6589 let mut stack = Vec::new();
6590 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6591 assert!(!result); assert_eq!(stack.len(), 2);
6593 assert_eq!(stack[1].as_ref(), &[1]); }
6595
6596 #[test]
6597 fn test_op_pick_invalid_index() {
6598 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
6600 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6601 assert!(!result);
6602 assert_eq!(stack.len(), 1);
6603 }
6604
6605 #[test]
6606 fn test_op_roll() {
6607 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
6609 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6610 assert!(!result); assert_eq!(stack.len(), 3);
6612 assert_eq!(stack[0].as_ref(), &[1]);
6613 assert_eq!(stack[1].as_ref(), &[3]);
6614 assert_eq!(stack[2].as_ref(), &[2]); }
6616
6617 #[test]
6618 fn test_op_roll_zero_n() {
6619 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
6622 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6623 assert!(result); assert_eq!(stack.len(), 1);
6625 assert_eq!(stack[0].as_ref(), &[1]);
6626 }
6627
6628 #[test]
6629 fn test_op_roll_invalid_index() {
6630 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
6632 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6633 assert!(!result);
6634 assert_eq!(stack.len(), 1);
6635 }
6636
6637 #[test]
6638 fn test_op_rot() {
6639 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
6641 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6642 assert!(!result); assert_eq!(stack.len(), 3);
6644 assert_eq!(stack[0].as_ref(), &[2]);
6645 assert_eq!(stack[1].as_ref(), &[3]);
6646 assert_eq!(stack[2].as_ref(), &[1]);
6647 }
6648
6649 #[test]
6650 fn test_op_rot_insufficient_stack() {
6651 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
6653 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6654 assert!(!result);
6655 assert_eq!(stack.len(), 2);
6656 }
6657
6658 #[test]
6659 fn test_op_swap() {
6660 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
6662 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6663 assert!(!result); assert_eq!(stack.len(), 2);
6665 assert_eq!(stack[0].as_ref(), &[2]);
6666 assert_eq!(stack[1].as_ref(), &[1]);
6667 }
6668
6669 #[test]
6670 fn test_op_swap_insufficient_stack() {
6671 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
6673 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6674 assert!(!result);
6675 assert_eq!(stack.len(), 1);
6676 }
6677
6678 #[test]
6679 fn test_op_tuck() {
6680 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
6682 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6683 assert!(!result); assert_eq!(stack.len(), 3);
6685 assert_eq!(stack[0].as_ref(), &[2]);
6686 assert_eq!(stack[1].as_ref(), &[1]);
6687 assert_eq!(stack[2].as_ref(), &[2]);
6688 }
6689
6690 #[test]
6691 fn test_op_tuck_insufficient_stack() {
6692 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
6694 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6695 assert!(!result);
6696 assert_eq!(stack.len(), 1);
6697 }
6698
6699 #[test]
6700 fn test_op_2drop() {
6701 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
6703 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6704 assert!(result); assert_eq!(stack.len(), 1);
6706 assert_eq!(stack[0].as_ref(), &[1]);
6707 }
6708
6709 #[test]
6710 fn test_op_2drop_insufficient_stack() {
6711 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
6713 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6714 assert!(!result);
6715 assert_eq!(stack.len(), 1);
6716 }
6717
6718 #[test]
6719 fn test_op_2dup() {
6720 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
6722 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6723 assert!(!result); assert_eq!(stack.len(), 4);
6725 assert_eq!(stack[0].as_ref(), &[1]);
6726 assert_eq!(stack[1].as_ref(), &[2]);
6727 assert_eq!(stack[2].as_ref(), &[1]);
6728 assert_eq!(stack[3].as_ref(), &[2]);
6729 }
6730
6731 #[test]
6732 fn test_op_2dup_insufficient_stack() {
6733 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
6735 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6736 assert!(!result);
6737 assert_eq!(stack.len(), 1);
6738 }
6739
6740 #[test]
6741 fn test_op_3dup() {
6742 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
6744 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6745 assert!(!result); assert_eq!(stack.len(), 6);
6747 assert_eq!(stack[0].as_ref(), &[1]);
6748 assert_eq!(stack[1].as_ref(), &[2]);
6749 assert_eq!(stack[2].as_ref(), &[3]);
6750 assert_eq!(stack[3].as_ref(), &[1]);
6751 assert_eq!(stack[4].as_ref(), &[2]);
6752 assert_eq!(stack[5].as_ref(), &[3]);
6753 }
6754
6755 #[test]
6756 fn test_op_3dup_insufficient_stack() {
6757 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
6759 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6760 assert!(!result);
6761 assert_eq!(stack.len(), 2);
6762 }
6763
6764 #[test]
6765 fn test_op_2over() {
6766 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
6768 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6769 assert!(!result); assert_eq!(stack.len(), 6);
6771 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
6773 }
6774
6775 #[test]
6776 fn test_op_2over_insufficient_stack() {
6777 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
6779 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6780 assert!(!result);
6781 assert_eq!(stack.len(), 3);
6782 }
6783
6784 #[test]
6785 fn test_op_2rot() {
6786 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
6788 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6789 assert!(!result); assert_eq!(stack.len(), 6);
6791 assert_eq!(stack[4].as_ref(), &[2]); assert_eq!(stack[5].as_ref(), &[1]);
6793 }
6794
6795 #[test]
6796 fn test_op_2rot_insufficient_stack() {
6797 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
6799 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6800 assert!(!result);
6801 assert_eq!(stack.len(), 4);
6802 }
6803
6804 #[test]
6805 fn test_op_2swap() {
6806 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
6808 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6809 assert!(!result); assert_eq!(stack.len(), 4);
6811 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
6813 assert_eq!(stack[2].as_ref(), &[1]);
6814 assert_eq!(stack[3].as_ref(), &[2]);
6815 }
6816
6817 #[test]
6818 fn test_op_2swap_insufficient_stack() {
6819 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
6821 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6822 assert!(!result);
6823 assert_eq!(stack.len(), 3);
6824 }
6825
6826 #[test]
6827 fn test_op_size() {
6828 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
6830 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6831 assert!(!result); assert_eq!(stack.len(), 2);
6833 assert_eq!(stack[0].as_ref(), &[1]);
6834 assert_eq!(stack[1].as_ref(), &[1]); }
6836
6837 #[test]
6838 fn test_op_size_empty_stack() {
6839 let script = vec![OP_SIZE]; let mut stack = Vec::new();
6841 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6842 assert!(!result);
6843 assert_eq!(stack.len(), 0);
6844 }
6845
6846 #[test]
6847 fn test_op_return() {
6848 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
6850 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6851 assert!(!result); assert_eq!(stack.len(), 1);
6853 }
6854
6855 #[test]
6856 fn test_op_checksigverify() {
6857 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6859 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6860 assert!(!result); assert_eq!(stack.len(), 0);
6862 }
6863
6864 #[test]
6865 fn test_op_checksigverify_insufficient_stack() {
6866 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6868 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6869 assert!(!result);
6870 assert_eq!(stack.len(), 1);
6871 }
6872
6873 #[test]
6874 fn test_unknown_opcode_comprehensive() {
6875 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
6877 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6878 assert!(!result); assert_eq!(stack.len(), 1);
6880 }
6881
6882 #[test]
6883 fn test_verify_signature_invalid_pubkey() {
6884 let secp = signature::new_secp();
6885 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
6888 let result = signature::verify_signature(
6889 &secp,
6890 &invalid_pubkey,
6891 &signature,
6892 &dummy_hash,
6893 0,
6894 0,
6895 crate::types::Network::Regtest,
6896 SigVersion::Base,
6897 );
6898 assert!(!result.unwrap_or(false));
6899 }
6900
6901 #[test]
6902 fn test_verify_signature_invalid_signature() {
6903 let secp = signature::new_secp();
6904 let pubkey = vec![
6905 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
6906 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
6907 0x5b, 0x16, 0xf8, 0x17, 0x98,
6908 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
6911 let result = signature::verify_signature(
6912 &secp,
6913 &pubkey,
6914 &invalid_signature,
6915 &dummy_hash,
6916 0,
6917 0,
6918 crate::types::Network::Regtest,
6919 SigVersion::Base,
6920 );
6921 assert!(!result.unwrap_or(false));
6922 }
6923
6924 fn minimal_tx_and_prevouts(
6930 script_sig: &[u8],
6931 script_pubkey: &[u8],
6932 ) -> (
6933 crate::types::Transaction,
6934 Vec<i64>,
6935 Vec<crate::types::ByteString>,
6936 ) {
6937 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
6938 let tx = Transaction {
6939 version: 1,
6940 inputs: vec![TransactionInput {
6941 prevout: OutPoint {
6942 hash: [0u8; 32],
6943 index: 0,
6944 },
6945 sequence: 0xffff_ffff,
6946 script_sig: script_sig.to_vec(),
6947 }]
6948 .into(),
6949 outputs: vec![TransactionOutput {
6950 value: 0,
6951 script_pubkey: script_pubkey.to_vec(),
6952 }]
6953 .into(),
6954 lock_time: 0,
6955 };
6956 let prevout_values = vec![0i64];
6957 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
6958 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
6959 (tx, prevout_values, prevout_script_pubkeys_vec)
6960 }
6961
6962 #[test]
6963 fn test_verify_with_context_p2pkh_hash_mismatch() {
6964 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
6968 script_sig.push(sig.len() as u8);
6969 script_sig.extend(&sig);
6970 script_sig.push(pubkey.len() as u8);
6971 script_sig.extend(&pubkey);
6972
6973 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
6974 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
6976 script_pubkey.push(OP_CHECKSIG);
6977
6978 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
6979 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
6980 let result = verify_script_with_context_full(
6981 &script_sig,
6982 &script_pubkey,
6983 None,
6984 0,
6985 &tx,
6986 0,
6987 &pv,
6988 &psp_refs,
6989 Some(500_000),
6990 None,
6991 crate::types::Network::Mainnet,
6992 SigVersion::Base,
6993 #[cfg(feature = "production")]
6994 None,
6995 None, #[cfg(feature = "production")]
6997 None,
6998 #[cfg(feature = "production")]
6999 None,
7000 #[cfg(feature = "production")]
7001 None,
7002 );
7003 assert!(result.is_ok());
7004 assert!(!result.unwrap());
7005 }
7006
7007 #[test]
7008 fn test_verify_with_context_p2sh_hash_mismatch() {
7009 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7012 script_sig.push(redeem.len() as u8);
7013 script_sig.extend(&redeem);
7014
7015 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7016 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7018
7019 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7020 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7021 let result = verify_script_with_context_full(
7022 &script_sig,
7023 &script_pubkey,
7024 None,
7025 0x01, &tx,
7027 0,
7028 &pv,
7029 &psp_refs,
7030 Some(500_000),
7031 None,
7032 crate::types::Network::Mainnet,
7033 SigVersion::Base,
7034 #[cfg(feature = "production")]
7035 None,
7036 None, #[cfg(feature = "production")]
7038 None,
7039 #[cfg(feature = "production")]
7040 None,
7041 #[cfg(feature = "production")]
7042 None,
7043 );
7044 assert!(result.is_ok());
7045 assert!(!result.unwrap());
7046 }
7047
7048 #[test]
7049 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7050 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7052 script_pubkey.extend(&[0u8; 20]);
7053 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7055 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7056 let empty: Vec<u8> = vec![];
7057 let result = verify_script_with_context_full(
7058 &empty,
7059 &script_pubkey,
7060 Some(&witness),
7061 0,
7062 &tx,
7063 0,
7064 &pv,
7065 &psp_refs,
7066 Some(500_000),
7067 None,
7068 crate::types::Network::Mainnet,
7069 SigVersion::Base,
7070 #[cfg(feature = "production")]
7071 None,
7072 None, #[cfg(feature = "production")]
7074 None,
7075 #[cfg(feature = "production")]
7076 None,
7077 #[cfg(feature = "production")]
7078 None,
7079 );
7080 assert!(result.is_ok());
7081 assert!(!result.unwrap());
7082 }
7083
7084 #[test]
7085 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7086 let witness_script = vec![OP_1];
7088 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7089 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7091 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7092 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7093 let empty: Vec<u8> = vec![];
7094 let result = verify_script_with_context_full(
7095 &empty,
7096 &script_pubkey,
7097 Some(&witness),
7098 0,
7099 &tx,
7100 0,
7101 &pv,
7102 &psp_refs,
7103 Some(500_000),
7104 None,
7105 crate::types::Network::Mainnet,
7106 SigVersion::Base,
7107 #[cfg(feature = "production")]
7108 None,
7109 None, #[cfg(feature = "production")]
7111 None,
7112 #[cfg(feature = "production")]
7113 None,
7114 #[cfg(feature = "production")]
7115 None,
7116 );
7117 assert!(result.is_ok());
7118 assert!(!result.unwrap());
7119 }
7120
7121 #[test]
7122 #[cfg(feature = "production")]
7123 fn test_p2wsh_multisig_fast_path() {
7124 use crate::constants::BIP147_ACTIVATION_MAINNET;
7126 use crate::crypto::OptimizedSha256;
7127
7128 let pk1 = [0x02u8; 33];
7129 let pk2 = [0x03u8; 33];
7130 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7132 witness_script.extend_from_slice(&pk2);
7133 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7137 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7138 script_pubkey.extend_from_slice(&wsh_hash);
7139
7140 let witness: Vec<Vec<u8>> = vec![
7141 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7145 ];
7146
7147 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7148 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7149 let empty: Vec<u8> = vec![];
7150 let result = verify_script_with_context_full(
7151 &empty,
7152 &script_pubkey,
7153 Some(&witness),
7154 0x810, &tx,
7156 0,
7157 &pv,
7158 &psp_refs,
7159 Some(BIP147_ACTIVATION_MAINNET + 1),
7160 None,
7161 crate::types::Network::Mainnet,
7162 SigVersion::Base,
7163 #[cfg(feature = "production")]
7164 None,
7165 None, #[cfg(feature = "production")]
7167 None,
7168 #[cfg(feature = "production")]
7169 None,
7170 #[cfg(feature = "production")]
7171 None,
7172 );
7173 assert!(result.is_ok());
7174 assert!(!result.unwrap());
7175 }
7176}
7177
7178#[cfg(test)]
7179#[allow(unused_doc_comments)]
7180mod property_tests {
7181 use super::*;
7182 use proptest::prelude::*;
7183
7184 proptest! {
7189 #[test]
7190 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7191 let mut stack = Vec::new();
7192 let flags = 0u32;
7193
7194 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7195
7196 if script.len() > MAX_SCRIPT_OPS * 2 {
7204 prop_assert!(result.is_err() || !result.unwrap(),
7207 "Very long scripts should fail or return false");
7208 }
7209 }
7211 }
7212
7213 proptest! {
7218 #[test]
7219 fn prop_verify_script_deterministic(
7220 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7221 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7222 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7223 flags in any::<u32>()
7224 ) {
7225 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7226 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7227
7228 assert_eq!(result1.is_ok(), result2.is_ok());
7229 if result1.is_ok() && result2.is_ok() {
7230 assert_eq!(result1.unwrap(), result2.unwrap());
7231 }
7232 }
7233 }
7234
7235 proptest! {
7240 #[test]
7241 fn prop_execute_opcode_no_panic(
7242 opcode in any::<u8>(),
7243 stack_items in prop::collection::vec(
7244 prop::collection::vec(any::<u8>(), 0..5),
7245 0..10
7246 ),
7247 flags in any::<u32>()
7248 ) {
7249 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7250 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7251
7252 match result {
7255 Ok(success) => {
7256 let _ = success;
7258 },
7259 Err(_) => {
7260 }
7263 }
7264
7265 assert!(stack.len() <= MAX_STACK_SIZE);
7267 }
7268 }
7269
7270 proptest! {
7277 #[test]
7278 fn prop_stack_operations_bounds(
7279 opcode in any::<u8>(),
7280 stack_items in prop::collection::vec(
7281 prop::collection::vec(any::<u8>(), 0..3),
7282 0..5
7283 ),
7284 flags in any::<u32>()
7285 ) {
7286 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7287 let initial_len = stack.len();
7288
7289 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7290
7291 assert!(stack.len() <= MAX_STACK_SIZE);
7293
7294 if result.is_ok() && result.unwrap() {
7296 match opcode {
7298 OP_0 | OP_1..=OP_16 => {
7299 assert!(stack.len() == initial_len + 1);
7301 },
7302 OP_DUP => {
7303 if initial_len > 0 {
7305 assert!(stack.len() == initial_len + 1);
7306 }
7307 },
7308 OP_3DUP => {
7309 if initial_len >= 3 {
7311 assert!(stack.len() == initial_len + 3);
7312 }
7313 },
7314 OP_2OVER => {
7315 if initial_len >= 4 {
7317 assert!(stack.len() == initial_len + 2);
7318 }
7319 },
7320 OP_DROP | OP_NIP | OP_2DROP => {
7321 assert!(stack.len() <= initial_len);
7323 },
7324 _ => {
7325 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7328 }
7329 }
7330 }
7331 }
7332 }
7333
7334 proptest! {
7339 #[test]
7340 fn prop_hash_operations_deterministic(
7341 input in prop::collection::vec(any::<u8>(), 0..10)
7342 ) {
7343 let elem = to_stack_element(&input);
7344 let mut stack1 = vec![elem.clone()];
7345 let mut stack2 = vec![elem];
7346
7347 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());
7351 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7352 assert_eq!(val1, val2);
7353 if val1 {
7354 assert_eq!(stack1, stack2);
7355 }
7356 }
7357 }
7358 }
7359
7360 proptest! {
7365 #[test]
7366 fn prop_equality_operations_symmetric(
7367 a in prop::collection::vec(any::<u8>(), 0..5),
7368 b in prop::collection::vec(any::<u8>(), 0..5)
7369 ) {
7370 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7371 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7372
7373 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());
7377 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7378 assert_eq!(val1, val2);
7379 if val1 {
7380 assert_eq!(stack1.len(), stack2.len());
7382 if !stack1.is_empty() && !stack2.is_empty() {
7383 assert_eq!(stack1[0], stack2[0]);
7384 }
7385 }
7386 }
7387 }
7388 }
7389
7390 proptest! {
7395 #[test]
7396 fn prop_script_execution_terminates(
7397 script in prop::collection::vec(any::<u8>(), 0..50)
7398 ) {
7399 let mut stack = Vec::new();
7400 let flags = 0u32;
7401
7402 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7404
7405 assert!(result.is_ok() || result.is_err());
7407
7408 assert!(stack.len() <= MAX_STACK_SIZE);
7410 }
7411 }
7412}