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)]
4473pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4476 let mut i = 0;
4477 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4478 i += adv1;
4479 if i >= script_sig.len() {
4480 return None;
4481 }
4482 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4483 i += adv2;
4484 if i != script_sig.len() {
4485 return None;
4486 }
4487 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4488}
4489
4490pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4493 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4494 if advance != script_sig.len() {
4495 return None;
4496 }
4497 Some(&script_sig[data_start..data_end])
4498}
4499
4500fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4502 if i >= script.len() {
4503 return None;
4504 }
4505 let opcode = script[i];
4506 let (advance, data_start, data_end) = if opcode == OP_0 {
4507 return None;
4508 } else if opcode <= 0x4b {
4509 let len = opcode as usize;
4510 if i + 1 + len > script.len() {
4511 return None;
4512 }
4513 (1 + len, i + 1, i + 1 + len)
4514 } else if opcode == OP_PUSHDATA1 {
4515 if i + 1 >= script.len() {
4516 return None;
4517 }
4518 let len = script[i + 1] as usize;
4519 if i + 2 + len > script.len() {
4520 return None;
4521 }
4522 (2 + len, i + 2, i + 2 + len)
4523 } else if opcode == OP_PUSHDATA2 {
4524 if i + 2 >= script.len() {
4525 return None;
4526 }
4527 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4528 if i + 3 + len > script.len() {
4529 return None;
4530 }
4531 (3 + len, i + 3, i + 3 + len)
4532 } else if opcode == OP_PUSHDATA4 {
4533 if i + 4 >= script.len() {
4534 return None;
4535 }
4536 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4537 as usize;
4538 if i + 5 + len > script.len() {
4539 return None;
4540 }
4541 (5 + len, i + 5, i + 5 + len)
4542 } else {
4543 return None;
4544 };
4545 Some((advance, data_start, data_end))
4546}
4547
4548#[spec_locked("5.2.1")]
4551pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4552 parse_script_sig_push_only(script_sig).is_some()
4553}
4554
4555fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4559 let mut out = Vec::new();
4560 let mut i = 0;
4561 while i < script_sig.len() {
4562 let opcode = script_sig[i];
4563 if !is_push_opcode(opcode) {
4564 return None;
4565 }
4566 let (advance, data) = if opcode == OP_0 {
4567 (1, vec![])
4568 } else if opcode <= 0x4b {
4569 let len = opcode as usize;
4570 if i + 1 + len > script_sig.len() {
4571 return None;
4572 }
4573 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4574 } else if opcode == OP_PUSHDATA1 {
4575 if i + 1 >= script_sig.len() {
4576 return None;
4577 }
4578 let len = script_sig[i + 1] as usize;
4579 if i + 2 + len > script_sig.len() {
4580 return None;
4581 }
4582 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4583 } else if opcode == OP_PUSHDATA2 {
4584 if i + 2 >= script_sig.len() {
4585 return None;
4586 }
4587 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4588 if i + 3 + len > script_sig.len() {
4589 return None;
4590 }
4591 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4592 } else if opcode == OP_PUSHDATA4 {
4593 if i + 4 >= script_sig.len() {
4594 return None;
4595 }
4596 let len = u32::from_le_bytes([
4597 script_sig[i + 1],
4598 script_sig[i + 2],
4599 script_sig[i + 3],
4600 script_sig[i + 4],
4601 ]) as usize;
4602 if i + 5 + len > script_sig.len() {
4603 return None;
4604 }
4605 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4606 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4607 let n = script_num_from_opcode(opcode);
4609 (1, script_num_encode(n))
4610 } else {
4611 return None;
4612 };
4613 out.push(to_stack_element(&data));
4614 i += advance;
4615 }
4616 Some(out)
4617}
4618
4619fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4623 parse_script_sig_push_only(script_sig)
4624}
4625
4626fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4631 if redeem.len() < 4 {
4632 return None;
4633 }
4634 let n_op = redeem[0];
4635 if !(OP_1..=OP_16).contains(&n_op) {
4636 return None;
4637 }
4638 let n = (n_op - OP_1 + 1) as usize;
4639 let mut i = 1;
4640 let mut pubkeys = Vec::with_capacity(n);
4641 for _ in 0..n {
4642 if i >= redeem.len() {
4643 return None;
4644 }
4645 let first = redeem[i];
4646 let pk_len = if first == 0x02 || first == 0x03 {
4647 33
4648 } else if first == 0x04 {
4649 65
4650 } else {
4651 return None;
4652 };
4653 if i + pk_len > redeem.len() {
4654 return None;
4655 }
4656 pubkeys.push(&redeem[i..i + pk_len]);
4657 i += pk_len;
4658 }
4659 if i + 2 > redeem.len() {
4660 return None;
4661 }
4662 let m_op = redeem[i];
4663 if !(OP_1..=OP_16).contains(&m_op) {
4664 return None;
4665 }
4666 let m = m_op - OP_1 + 1;
4667 if redeem[i + 1] != OP_CHECKMULTISIG {
4668 return None;
4669 }
4670 Some((m, n as u8, pubkeys))
4671}
4672
4673fn script_num_from_opcode(opcode: u8) -> i64 {
4675 match opcode {
4676 OP_1NEGATE => -1,
4677 OP_1 => 1,
4678 OP_2 => 2,
4679 OP_3 => 3,
4680 OP_4 => 4,
4681 OP_5 => 5,
4682 OP_6 => 6,
4683 OP_7 => 7,
4684 OP_8 => 8,
4685 OP_9 => 9,
4686 OP_10 => 10,
4687 OP_11 => 11,
4688 OP_12 => 12,
4689 OP_13 => 13,
4690 OP_14 => 14,
4691 OP_15 => 15,
4692 OP_16 => 16,
4693 _ => 0,
4694 }
4695}
4696
4697pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
4701 let len = data.len();
4702 let mut result = Vec::with_capacity(len + 5);
4703 if len < 76 {
4704 result.push(len as u8);
4705 } else if len < 256 {
4706 result.push(OP_PUSHDATA1);
4707 result.push(len as u8);
4708 } else if len < 65536 {
4709 result.push(OP_PUSHDATA2);
4710 result.push((len & 0xff) as u8);
4711 result.push(((len >> 8) & 0xff) as u8);
4712 } else {
4713 result.push(OP_PUSHDATA4);
4714 result.push((len & 0xff) as u8);
4715 result.push(((len >> 8) & 0xff) as u8);
4716 result.push(((len >> 16) & 0xff) as u8);
4717 result.push(((len >> 24) & 0xff) as u8);
4718 }
4719 result.extend_from_slice(data);
4720 result
4721}
4722
4723#[inline]
4725fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
4726 if pc >= script.len() {
4727 return None;
4728 }
4729 let opcode = script[pc];
4730 let advance = if opcode <= 0x4b {
4731 1 + opcode as usize
4732 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
4733 2 + script[pc + 1] as usize
4734 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
4735 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
4736 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
4737 5 + ((script[pc + 1] as usize)
4738 | ((script[pc + 2] as usize) << 8)
4739 | ((script[pc + 3] as usize) << 16)
4740 | ((script[pc + 4] as usize) << 24))
4741 } else {
4742 1
4743 };
4744 let next = pc + advance;
4745 if next > script.len() {
4746 None
4747 } else {
4748 Some(next)
4749 }
4750}
4751
4752#[spec_locked("5.1.1")]
4758#[inline]
4759pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
4760 if pattern.is_empty() {
4761 return std::borrow::Cow::Borrowed(script);
4762 }
4763 if pattern.len() > script.len() {
4764 return std::borrow::Cow::Borrowed(script);
4765 }
4766 if !script.windows(pattern.len()).any(|w| w == pattern) {
4771 return std::borrow::Cow::Borrowed(script);
4772 }
4773 let end = script.len();
4774 let mut n_found = 0usize;
4775 let mut result = Vec::new();
4776 let mut pc = 0usize;
4777 let mut pc2 = 0usize;
4778
4779 loop {
4780 result.extend_from_slice(&script[pc2..pc]);
4781 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
4782 pc += pattern.len();
4783 n_found += 1;
4784 }
4785 pc2 = pc;
4786 if pc >= end {
4787 break;
4788 }
4789 let Some(next_pc) = script_get_op_advance(script, pc) else {
4790 break;
4791 };
4792 pc = next_pc;
4793 }
4794
4795 if n_found > 0 {
4796 result.extend_from_slice(&script[pc2..end]);
4797 std::borrow::Cow::Owned(result)
4798 } else {
4799 std::borrow::Cow::Borrowed(script)
4800 }
4801}
4802
4803fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
4805 let mut pos = 0u32;
4806 let mut i = 0usize;
4807 while i < script.len() && i <= byte_index {
4808 let opcode = script[i];
4809 let advance = if opcode <= 0x4b {
4810 1 + opcode as usize
4811 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
4812 2 + script[i + 1] as usize
4813 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
4814 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
4815 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
4816 5 + ((script[i + 1] as usize)
4817 | ((script[i + 2] as usize) << 8)
4818 | ((script[i + 3] as usize) << 16)
4819 | ((script[i + 4] as usize) << 24))
4820 } else {
4821 1
4822 };
4823 if i == byte_index {
4824 return pos;
4825 }
4826 pos += 1;
4827 i = std::cmp::min(i + advance, script.len());
4828 }
4829 0xffff_ffff
4830}
4831
4832#[cfg_attr(feature = "production", inline(always))]
4834fn execute_opcode_with_context_full(
4835 opcode: u8,
4836 stack: &mut Vec<StackElement>,
4837 flags: u32,
4838 ctx: &context::ScriptContext<'_>,
4839 effective_script_code: Option<&[u8]>,
4840) -> Result<bool> {
4841 let tx = ctx.tx;
4842 let input_index = ctx.input_index;
4843 let prevout_values = ctx.prevout_values;
4844 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
4845 let block_height = ctx.block_height;
4846 let median_time_past = ctx.median_time_past;
4847 let network = ctx.network;
4848 let sigversion = ctx.sigversion;
4849 let script_sig_for_sighash = ctx.script_sig_for_sighash;
4850 let tapscript_for_sighash = ctx.tapscript_for_sighash;
4851 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
4852 let redeem_script_for_sighash = effective_script_code;
4853 #[cfg(feature = "production")]
4854 let schnorr_collector = ctx.schnorr_collector;
4855 #[cfg(feature = "production")]
4856 let precomputed_bip143 = ctx.precomputed_bip143;
4857 #[cfg(feature = "production")]
4858 let sighash_cache = ctx.sighash_cache;
4859
4860 match opcode {
4862 OP_CHECKSIG => {
4864 if stack.len() >= 2 {
4865 let pubkey_bytes = stack.pop().unwrap();
4866 let signature_bytes = stack.pop().unwrap();
4867
4868 if signature_bytes.is_empty() {
4870 stack.push(to_stack_element(&[0]));
4871 return Ok(true);
4872 }
4873
4874 if sigversion == SigVersion::Tapscript {
4877 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
4879 let sighash_byte = 0x00;
4880 let (tapscript, codesep_pos) = tapscript_for_sighash
4881 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
4882 .unwrap_or((&[] as &[u8], 0xffff_ffff));
4883 let sighash = if tapscript.is_empty() {
4884 crate::taproot::compute_taproot_signature_hash(
4885 tx,
4886 input_index,
4887 prevout_values,
4888 prevout_script_pubkeys,
4889 sighash_byte,
4890 )?
4891 } else {
4892 crate::taproot::compute_tapscript_signature_hash(
4893 tx,
4894 input_index,
4895 prevout_values,
4896 prevout_script_pubkeys,
4897 tapscript,
4898 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
4899 codesep_pos,
4900 sighash_byte,
4901 )?
4902 };
4903
4904 #[cfg(feature = "production")]
4906 let is_valid = {
4907 use crate::bip348::verify_tapscript_schnorr_signature;
4908 verify_tapscript_schnorr_signature(
4909 &sighash,
4910 &pubkey_bytes,
4911 &signature_bytes,
4912 schnorr_collector,
4913 )
4914 .unwrap_or(false)
4915 };
4916
4917 #[cfg(not(feature = "production"))]
4918 let is_valid = {
4919 #[cfg(feature = "csfs")]
4920 let x = {
4921 use crate::bip348::verify_tapscript_schnorr_signature;
4922 verify_tapscript_schnorr_signature(
4923 &sighash,
4924 &pubkey_bytes,
4925 &signature_bytes,
4926 None,
4927 )
4928 .unwrap_or(false)
4929 };
4930 #[cfg(not(feature = "csfs"))]
4931 let x = false;
4932 x
4933 };
4934
4935 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
4936 return Ok(true);
4937 }
4938 }
4940
4941 let sig_len = signature_bytes.len();
4945 let sighash_byte = signature_bytes[sig_len - 1];
4946 let _der_sig = &signature_bytes[..sig_len - 1];
4947
4948 let sighash = if sigversion == SigVersion::WitnessV0 {
4952 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
4954
4955 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
4957 prevout_script_pubkeys
4958 .get(input_index)
4959 .copied()
4960 .unwrap_or(&[])
4961 });
4962
4963 crate::transaction_hash::calculate_bip143_sighash(
4964 tx,
4965 input_index,
4966 script_code,
4967 amount,
4968 sighash_byte,
4969 precomputed_bip143,
4970 )?
4971 } else {
4972 use crate::transaction_hash::{
4974 calculate_transaction_sighash_single_input, SighashType,
4975 };
4976 let sighash_type = SighashType::from_byte(sighash_byte);
4977
4978 let pattern = serialize_push_data(signature_bytes.as_ref());
4982
4983 let base_script = match (
4984 redeem_script_for_sighash,
4985 prevout_script_pubkeys.get(input_index),
4986 ) {
4987 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
4988 (Some(redeem), _) => redeem,
4989 (None, Some(prevout)) => *prevout,
4990 (None, None) => &[],
4991 };
4992 let cleaned = find_and_delete(base_script, &pattern);
4993
4994 calculate_transaction_sighash_single_input(
4995 tx,
4996 input_index,
4997 cleaned.as_ref(),
4998 prevout_values[input_index],
4999 sighash_type,
5000 #[cfg(feature = "production")]
5001 sighash_cache,
5002 )?
5003 };
5004
5005 let height = block_height.unwrap_or(0);
5009 #[cfg(feature = "production")]
5010 let is_valid = signature::with_secp_context(|secp| {
5011 signature::verify_signature(
5012 secp,
5013 &pubkey_bytes,
5014 &signature_bytes, &sighash,
5016 flags,
5017 height,
5018 network,
5019 sigversion,
5020 )
5021 })?;
5022
5023 #[cfg(not(feature = "production"))]
5024 let is_valid = {
5025 let secp = signature::new_secp();
5026 signature::verify_signature(
5027 &secp,
5028 &pubkey_bytes,
5029 &signature_bytes, &sighash,
5031 flags,
5032 height,
5033 network,
5034 sigversion,
5035 )?
5036 };
5037
5038 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5039 Ok(true)
5040 } else {
5041 Ok(false)
5042 }
5043 }
5044
5045 OP_CHECKSIGVERIFY => {
5047 if stack.len() >= 2 {
5048 let pubkey_bytes = stack.pop().unwrap();
5049 let signature_bytes = stack.pop().unwrap();
5050
5051 if signature_bytes.is_empty() {
5053 return Ok(false);
5054 }
5055
5056 let sig_len = signature_bytes.len();
5060 let sighash_byte = signature_bytes[sig_len - 1];
5061 let _der_sig = &signature_bytes[..sig_len - 1];
5062
5063 let sighash = if sigversion == SigVersion::WitnessV0 {
5067 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5069
5070 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5071 prevout_script_pubkeys
5072 .get(input_index)
5073 .copied()
5074 .unwrap_or(&[])
5075 });
5076
5077 crate::transaction_hash::calculate_bip143_sighash(
5078 tx,
5079 input_index,
5080 script_code,
5081 amount,
5082 sighash_byte,
5083 precomputed_bip143,
5084 )?
5085 } else {
5086 use crate::transaction_hash::{
5088 calculate_transaction_sighash_single_input, SighashType,
5089 };
5090 let sighash_type = SighashType::from_byte(sighash_byte);
5091
5092 let pattern = serialize_push_data(signature_bytes.as_ref());
5094
5095 let base_script = match (
5096 redeem_script_for_sighash,
5097 prevout_script_pubkeys.get(input_index),
5098 ) {
5099 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5100 (Some(redeem), _) => redeem,
5101 (None, Some(prevout)) => *prevout,
5102 (None, None) => &[],
5103 };
5104 let cleaned = find_and_delete(base_script, &pattern);
5105
5106 calculate_transaction_sighash_single_input(
5107 tx,
5108 input_index,
5109 cleaned.as_ref(),
5110 prevout_values[input_index],
5111 sighash_type,
5112 #[cfg(feature = "production")]
5113 sighash_cache,
5114 )?
5115 };
5116
5117 let height = block_height.unwrap_or(0);
5121 #[cfg(feature = "production")]
5122 let is_valid = signature::with_secp_context(|secp| {
5123 signature::verify_signature(
5124 secp,
5125 &pubkey_bytes,
5126 &signature_bytes, &sighash,
5128 flags,
5129 height,
5130 network,
5131 sigversion,
5132 )
5133 })?;
5134
5135 #[cfg(not(feature = "production"))]
5136 let is_valid = {
5137 let secp = signature::new_secp();
5138 signature::verify_signature(
5139 &secp,
5140 &pubkey_bytes,
5141 &signature_bytes, &sighash,
5143 flags,
5144 height,
5145 network,
5146 sigversion,
5147 )?
5148 };
5149
5150 if is_valid {
5151 Ok(true)
5152 } else {
5153 Ok(false)
5154 }
5155 } else {
5156 Ok(false)
5157 }
5158 }
5159
5160 OP_CHECKSIGADD => {
5162 if sigversion != SigVersion::Tapscript {
5163 return Err(ConsensusError::ScriptErrorWithCode {
5164 code: ScriptErrorCode::DisabledOpcode,
5165 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5166 });
5167 }
5168 if stack.len() < 3 {
5169 return Err(ConsensusError::ScriptErrorWithCode {
5170 code: ScriptErrorCode::InvalidStackOperation,
5171 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5172 });
5173 }
5174 let pubkey_bytes = stack.pop().unwrap();
5176 let n_bytes = stack.pop().unwrap();
5177 let signature_bytes = stack.pop().unwrap();
5178 let n = script_num_decode(&n_bytes, 4)?;
5179
5180 if signature_bytes.is_empty() {
5182 stack.push(to_stack_element(&script_num_encode(n)));
5183 return Ok(true);
5184 }
5185
5186 if pubkey_bytes.len() == 32 && signature_bytes.len() == 64 {
5188 let sighash_byte = 0x00;
5189 let (tapscript, codesep_pos) = tapscript_for_sighash
5190 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5191 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5192 let sighash = if tapscript.is_empty() {
5193 crate::taproot::compute_taproot_signature_hash(
5194 tx,
5195 input_index,
5196 prevout_values,
5197 prevout_script_pubkeys,
5198 sighash_byte,
5199 )?
5200 } else {
5201 crate::taproot::compute_tapscript_signature_hash(
5202 tx,
5203 input_index,
5204 prevout_values,
5205 prevout_script_pubkeys,
5206 tapscript,
5207 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5208 codesep_pos,
5209 sighash_byte,
5210 )?
5211 };
5212
5213 #[cfg(feature = "production")]
5214 let is_valid = {
5215 use crate::bip348::verify_tapscript_schnorr_signature;
5216 verify_tapscript_schnorr_signature(
5217 &sighash,
5218 &pubkey_bytes,
5219 &signature_bytes,
5220 schnorr_collector,
5221 )
5222 .unwrap_or(false)
5223 };
5224
5225 #[cfg(not(feature = "production"))]
5226 let is_valid = {
5227 #[cfg(feature = "csfs")]
5228 let x = {
5229 use crate::bip348::verify_tapscript_schnorr_signature;
5230 verify_tapscript_schnorr_signature(
5231 &sighash,
5232 &pubkey_bytes,
5233 &signature_bytes,
5234 None,
5235 )
5236 .unwrap_or(false)
5237 };
5238 #[cfg(not(feature = "csfs"))]
5239 let x = false;
5240 x
5241 };
5242
5243 if !is_valid {
5244 return Ok(false); }
5246 stack.push(to_stack_element(&script_num_encode(n + 1)));
5247 return Ok(true);
5248 }
5249
5250 stack.push(to_stack_element(&script_num_encode(n + 1)));
5252 Ok(true)
5253 }
5254
5255 OP_CHECKMULTISIG => {
5257 if stack.len() < 2 {
5260 return Ok(false);
5261 }
5262
5263 let n_bytes = stack.pop().unwrap();
5266 let n = if n_bytes.is_empty() {
5267 0
5268 } else {
5269 n_bytes[0] as usize
5270 };
5271 if n > 20 || stack.len() < n + 1 {
5272 return Ok(false);
5273 }
5274
5275 let mut pubkeys = Vec::with_capacity(n);
5277 for _ in 0..n {
5278 pubkeys.push(stack.pop().unwrap());
5279 }
5280
5281 let m_bytes = stack.pop().unwrap();
5284 let m = if m_bytes.is_empty() {
5285 0
5286 } else {
5287 m_bytes[0] as usize
5288 };
5289 if m > n || m > 20 || stack.len() < m + 1 {
5290 return Ok(false);
5291 }
5292
5293 let mut signatures = Vec::with_capacity(m);
5295 for _ in 0..m {
5296 signatures.push(stack.pop().unwrap());
5297 }
5298
5299 let dummy = stack.pop().unwrap();
5302 if flags & 0x10 != 0 {
5303 let height = block_height.unwrap_or(0);
5304 use crate::bip_validation::Bip147Network;
5306 let bip147_network = match network {
5307 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5308 crate::types::Network::Testnet => Bip147Network::Testnet,
5309 crate::types::Network::Regtest => Bip147Network::Regtest,
5310 };
5311
5312 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5316
5317 let bip147_active = height
5318 >= match bip147_network {
5319 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5320 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5321 Bip147Network::Regtest => 0,
5322 };
5323
5324 if bip147_active {
5325 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5329 if !is_empty {
5330 return Err(ConsensusError::ScriptErrorWithCode {
5331 code: ScriptErrorCode::SigNullDummy,
5332 message: format!(
5333 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5334 )
5335 .into(),
5336 });
5337 }
5338 }
5339 }
5340
5341 let height = block_height.unwrap_or(0);
5344
5345 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5348 let base_script = match (
5349 redeem_script_for_sighash,
5350 prevout_script_pubkeys.get(input_index),
5351 ) {
5352 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5353 (Some(redeem), _) => redeem,
5354 (None, Some(prevout)) => *prevout,
5355 (None, None) => &[],
5356 };
5357 let mut cleaned = base_script.to_vec();
5358 for sig in &signatures {
5359 if !sig.is_empty() {
5360 let pattern = serialize_push_data(sig.as_ref());
5361 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5362 }
5363 }
5364 cleaned
5365 } else {
5366 redeem_script_for_sighash
5368 .map(|s| s.to_vec())
5369 .unwrap_or_else(|| {
5370 prevout_script_pubkeys
5371 .get(input_index)
5372 .map(|p| p.to_vec())
5373 .unwrap_or_default()
5374 })
5375 };
5376
5377 use crate::transaction_hash::{
5378 calculate_transaction_sighash_single_input, SighashType,
5379 };
5380
5381 #[cfg(feature = "production")]
5383 let use_batch = pubkeys.len() * signatures.len() >= 4;
5384
5385 #[cfg(feature = "production")]
5386 let (valid_sigs, _) = if use_batch {
5387 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5389 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5390 if non_empty.is_empty() {
5391 vec![]
5392 } else {
5393 let specs: Vec<(usize, u8, &[u8])> = non_empty
5394 .iter()
5395 .map(|s| {
5396 (
5397 input_index,
5398 s.as_ref()[s.as_ref().len() - 1],
5399 cleaned_script_for_multisig.as_ref(),
5400 )
5401 })
5402 .collect();
5403 crate::transaction_hash::batch_compute_legacy_sighashes(
5404 tx,
5405 prevout_values,
5406 prevout_script_pubkeys,
5407 &specs,
5408 )?
5409 }
5410 } else {
5411 signatures
5412 .iter()
5413 .filter(|s| !s.is_empty())
5414 .map(|sig_bytes| {
5415 let sighash_type =
5416 SighashType::from_byte(sig_bytes[sig_bytes.len() - 1]);
5417 calculate_transaction_sighash_single_input(
5418 tx,
5419 input_index,
5420 &cleaned_script_for_multisig,
5421 prevout_values[input_index],
5422 sighash_type,
5423 sighash_cache,
5424 )
5425 })
5426 .collect::<Result<Vec<_>>>()?
5427 };
5428
5429 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5431 Vec::with_capacity(pubkeys.len() * signatures.len());
5432 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5433 let mut sighash_idx = 0usize;
5434 for (j, sig_bytes) in signatures.iter().enumerate() {
5435 if sig_bytes.is_empty() {
5436 sig_idx_to_sighash_idx.push(usize::MAX);
5437 } else {
5438 sig_idx_to_sighash_idx.push(sighash_idx);
5439 let sh = sighashes[sighash_idx];
5440 sighash_idx += 1;
5441 for pubkey_bytes in &pubkeys {
5442 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5443 }
5444 }
5445 }
5446
5447 let results = if tasks.is_empty() {
5448 vec![]
5449 } else {
5450 batch_verify_signatures(&tasks, flags, height, network)?
5451 };
5452
5453 let mut sig_index = 0;
5455 let mut valid_sigs = 0usize;
5456 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5457 if sig_index >= signatures.len() {
5458 break;
5459 }
5460 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5462 sig_index += 1;
5463 }
5464 if sig_index >= signatures.len() {
5465 break;
5466 }
5467 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5468 if sh_idx == usize::MAX {
5469 continue;
5470 }
5471 let task_idx = sh_idx * pubkeys.len() + i;
5472 if task_idx < results.len() && results[task_idx] {
5473 valid_sigs += 1;
5474 sig_index += 1;
5475 }
5476 }
5477
5478 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5480 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5481 for (j, sig_bytes) in signatures.iter().enumerate() {
5482 if sig_bytes.is_empty() {
5483 continue;
5484 }
5485 let sh_idx = sig_idx_to_sighash_idx[j];
5486 if sh_idx == usize::MAX {
5487 continue;
5488 }
5489 let sig_start = sh_idx * pubkeys.len();
5490 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5491 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5492 if !matched {
5493 return Err(ConsensusError::ScriptErrorWithCode {
5494 code: ScriptErrorCode::SigNullFail,
5495 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5496 });
5497 }
5498 }
5499 }
5500 (valid_sigs, ())
5501 } else {
5502 let mut sig_index = 0;
5503 let mut valid_sigs = 0;
5504
5505 for pubkey_bytes in &pubkeys {
5506 if sig_index >= signatures.len() {
5507 break;
5508 }
5509
5510 let signature_bytes = &signatures[sig_index];
5511
5512 if signature_bytes.is_empty() {
5513 continue;
5514 }
5515
5516 let sig_len = signature_bytes.len();
5517 let sighash_byte = signature_bytes[sig_len - 1];
5518 let sighash_type = SighashType::from_byte(sighash_byte);
5519
5520 let sighash = calculate_transaction_sighash_single_input(
5521 tx,
5522 input_index,
5523 &cleaned_script_for_multisig,
5524 prevout_values[input_index],
5525 sighash_type,
5526 #[cfg(feature = "production")]
5527 sighash_cache,
5528 )?;
5529
5530 #[cfg(feature = "production")]
5531 let is_valid = signature::with_secp_context(|secp| {
5532 signature::verify_signature(
5533 secp,
5534 pubkey_bytes,
5535 signature_bytes,
5536 &sighash,
5537 flags,
5538 height,
5539 network,
5540 sigversion,
5541 )
5542 })?;
5543
5544 #[cfg(not(feature = "production"))]
5545 let is_valid = {
5546 let secp = signature::new_secp();
5547 signature::verify_signature(
5548 &secp,
5549 pubkey_bytes,
5550 signature_bytes,
5551 &sighash,
5552 flags,
5553 height,
5554 network,
5555 sigversion,
5556 )?
5557 };
5558
5559 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5560 if !is_valid
5561 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5562 && !signature_bytes.is_empty()
5563 {
5564 return Err(ConsensusError::ScriptErrorWithCode {
5565 code: ScriptErrorCode::SigNullFail,
5566 message:
5567 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5568 .into(),
5569 });
5570 }
5571
5572 if is_valid {
5573 valid_sigs += 1;
5574 sig_index += 1;
5575 }
5576 }
5577 (valid_sigs, ())
5578 };
5579
5580 #[cfg(not(feature = "production"))]
5581 let (valid_sigs, _) = {
5582 let mut sig_index = 0;
5583 let mut valid_sigs = 0;
5584
5585 for pubkey_bytes in &pubkeys {
5586 if sig_index >= signatures.len() {
5587 break;
5588 }
5589 let signature_bytes = &signatures[sig_index];
5590 if signature_bytes.is_empty() {
5591 continue;
5592 }
5593 let sig_len = signature_bytes.len();
5594 let sighash_type = SighashType::from_byte(signature_bytes[sig_len - 1]);
5595 let sighash = calculate_transaction_sighash_single_input(
5596 tx,
5597 input_index,
5598 &cleaned_script_for_multisig,
5599 prevout_values[input_index],
5600 sighash_type,
5601 #[cfg(feature = "production")]
5602 sighash_cache,
5603 )?;
5604 let secp = signature::new_secp();
5605 let is_valid = signature::verify_signature(
5606 &secp,
5607 pubkey_bytes,
5608 signature_bytes,
5609 &sighash,
5610 flags,
5611 height,
5612 network,
5613 sigversion,
5614 )?;
5615 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5616 if !is_valid
5617 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5618 && !signature_bytes.is_empty()
5619 {
5620 return Err(ConsensusError::ScriptErrorWithCode {
5621 code: ScriptErrorCode::SigNullFail,
5622 message:
5623 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5624 .into(),
5625 });
5626 }
5627 if is_valid {
5628 valid_sigs += 1;
5629 sig_index += 1;
5630 }
5631 }
5632 (valid_sigs, ())
5633 };
5634
5635 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
5637 Ok(true)
5638 }
5639
5640 OP_CHECKMULTISIGVERIFY => {
5642 let ctx_checkmultisig = context::ScriptContext {
5644 tx,
5645 input_index,
5646 prevout_values,
5647 prevout_script_pubkeys,
5648 block_height,
5649 median_time_past,
5650 network,
5651 sigversion,
5652 redeem_script_for_sighash,
5653 script_sig_for_sighash,
5654 tapscript_for_sighash,
5655 tapscript_codesep_pos,
5656 #[cfg(feature = "production")]
5657 schnorr_collector: None,
5658 #[cfg(feature = "production")]
5659 precomputed_bip143,
5660 #[cfg(feature = "production")]
5661 sighash_cache,
5662 };
5663 let result = execute_opcode_with_context_full(
5664 OP_CHECKMULTISIG,
5665 stack,
5666 flags,
5667 &ctx_checkmultisig,
5668 redeem_script_for_sighash,
5669 )?;
5670 if !result {
5671 return Ok(false);
5672 }
5673 if let Some(top) = stack.pop() {
5675 if !cast_to_bool(&top) {
5676 return Ok(false);
5677 }
5678 Ok(true)
5679 } else {
5680 Ok(false)
5681 }
5682 }
5683
5684 OP_CHECKLOCKTIMEVERIFY => {
5689 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
5691 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5692 return Ok(true);
5693 }
5694
5695 use crate::locktime::{check_bip65, decode_locktime_value};
5696
5697 if stack.is_empty() {
5698 return Err(ConsensusError::ScriptErrorWithCode {
5699 code: ScriptErrorCode::InvalidStackOperation,
5700 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
5701 });
5702 }
5703
5704 let locktime_bytes = stack.last().expect("Stack is not empty");
5706 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
5707 Some(v) => v,
5708 None => {
5709 return Err(ConsensusError::ScriptErrorWithCode {
5710 code: ScriptErrorCode::MinimalData,
5711 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
5712 })
5713 }
5714 };
5715
5716 let tx_locktime = tx.lock_time as u32;
5717
5718 if !check_bip65(tx_locktime, locktime_value) {
5720 return Ok(false);
5721 }
5722
5723 let input_seq = if input_index < tx.inputs.len() {
5725 tx.inputs[input_index].sequence
5726 } else {
5727 0xffffffff
5728 };
5729 if input_seq == 0xffffffff {
5730 return Ok(false);
5731 }
5732
5733 Ok(true)
5735 }
5736
5737 OP_CHECKSEQUENCEVERIFY => {
5746 use crate::locktime::{
5747 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
5748 is_sequence_disabled,
5749 };
5750
5751 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
5753 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
5754 return Ok(true);
5755 }
5756
5757 if stack.is_empty() {
5758 return Ok(false);
5759 }
5760
5761 let sequence_bytes = stack.last().expect("Stack is not empty");
5764 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
5765 Some(v) => v,
5766 None => return Ok(false), };
5768
5769 if input_index >= tx.inputs.len() {
5771 return Ok(false);
5772 }
5773 let input_sequence = tx.inputs[input_index].sequence as u32;
5774
5775 if is_sequence_disabled(input_sequence) {
5777 return Ok(true);
5778 }
5779
5780 let type_flag = extract_sequence_type_flag(sequence_value);
5782 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
5783
5784 let input_type_flag = extract_sequence_type_flag(input_sequence);
5786 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
5787
5788 if type_flag != input_type_flag {
5790 return Ok(false);
5791 }
5792
5793 if input_locktime < locktime_mask {
5795 return Ok(false);
5796 }
5797
5798 Ok(true)
5800 }
5801
5802 OP_CHECKTEMPLATEVERIFY => {
5811 #[cfg(not(feature = "ctv"))]
5812 {
5813 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5815 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5816 return Err(ConsensusError::ScriptErrorWithCode {
5817 code: ScriptErrorCode::BadOpcode,
5818 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
5819 });
5820 }
5821 Ok(true) }
5823
5824 #[cfg(feature = "ctv")]
5825 {
5826 use crate::constants::{
5827 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
5828 };
5829
5830 let ctv_activation = match network {
5832 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
5833 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
5834 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
5835 };
5836
5837 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
5838 if !ctv_active {
5839 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5841 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5842 return Err(ConsensusError::ScriptErrorWithCode {
5843 code: ScriptErrorCode::BadOpcode,
5844 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
5845 });
5846 }
5847 return Ok(true); }
5849
5850 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
5852 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
5853 return Ok(true);
5855 }
5856
5857 use crate::bip119::calculate_template_hash;
5858
5859 if stack.is_empty() {
5861 return Err(ConsensusError::ScriptErrorWithCode {
5862 code: ScriptErrorCode::InvalidStackOperation,
5863 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
5864 });
5865 }
5866
5867 let template_hash_bytes = stack.pop().unwrap();
5868
5869 if template_hash_bytes.len() != 32 {
5871 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5874 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5875 return Err(ConsensusError::ScriptErrorWithCode {
5876 code: ScriptErrorCode::InvalidStackOperation,
5877 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
5878 .into(),
5879 });
5880 }
5881 return Ok(true); }
5883
5884 let mut expected_hash = [0u8; 32];
5886 expected_hash.copy_from_slice(&template_hash_bytes);
5887
5888 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
5889 ConsensusError::ScriptErrorWithCode {
5890 code: ScriptErrorCode::TxInvalid,
5891 message: format!("CTV hash calculation failed: {e}").into(),
5892 }
5893 })?;
5894
5895 use crate::crypto::hash_compare::hash_eq;
5897 let matches = hash_eq(&expected_hash, &actual_hash);
5898
5899 if !matches {
5900 return Ok(false); }
5902
5903 Ok(true)
5905 }
5906 }
5907
5908 OP_CHECKSIGFROMSTACK => {
5919 #[cfg(not(feature = "csfs"))]
5920 {
5921 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5924 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5925 return Err(ConsensusError::ScriptErrorWithCode {
5926 code: ScriptErrorCode::BadOpcode,
5927 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
5928 });
5929 }
5930 Ok(true) }
5932
5933 #[cfg(feature = "csfs")]
5934 {
5935 use crate::constants::{
5936 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
5937 };
5938
5939 if sigversion != SigVersion::Tapscript {
5941 return Err(ConsensusError::ScriptErrorWithCode {
5942 code: ScriptErrorCode::BadOpcode,
5943 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
5944 });
5945 }
5946
5947 let csfs_activation = match network {
5949 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
5950 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
5951 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
5952 };
5953
5954 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
5955 if !csfs_active {
5956 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5958 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5959 return Err(ConsensusError::ScriptErrorWithCode {
5960 code: ScriptErrorCode::BadOpcode,
5961 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
5962 });
5963 }
5964 return Ok(true); }
5966
5967 use crate::bip348::verify_signature_from_stack;
5968
5969 if stack.len() < 3 {
5971 return Err(ConsensusError::ScriptErrorWithCode {
5972 code: ScriptErrorCode::InvalidStackOperation,
5973 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
5974 });
5975 }
5976
5977 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
5984 return Err(ConsensusError::ScriptErrorWithCode {
5985 code: ScriptErrorCode::PubkeyType,
5986 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
5987 });
5988 }
5989
5990 if signature_bytes.is_empty() {
5992 stack.push(to_stack_element(&[])); return Ok(true);
5994 }
5995
5996 #[cfg(feature = "production")]
5999 let is_valid = {
6000 verify_signature_from_stack(
6001 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6006 .unwrap_or(false)
6007 };
6008 #[cfg(not(feature = "production"))]
6009 let is_valid = verify_signature_from_stack(
6010 &message_bytes, &pubkey_bytes, &signature_bytes, )
6014 .unwrap_or(false);
6015
6016 if !is_valid {
6017 return Ok(false);
6019 }
6020
6021 stack.push(to_stack_element(&[0x01])); Ok(true)
6028 }
6029 }
6030
6031 _ => execute_opcode_cold(opcode, stack, flags),
6033 }
6034}
6035
6036#[cold]
6038fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6039 execute_opcode(opcode, stack, flags, SigVersion::Base)
6040}
6041
6042#[cfg(feature = "production")]
6057pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6058 (
6059 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6060 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6061 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6062 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6063 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6064 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6065 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6066 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6067 )
6068}
6069
6070#[cfg(all(feature = "production", feature = "benchmarking"))]
6077pub fn clear_script_cache() {
6078 if let Some(cache) = SCRIPT_CACHE.get() {
6079 let mut cache = cache.write().unwrap();
6080 cache.clear();
6081 }
6082}
6083
6084#[cfg(all(feature = "production", feature = "benchmarking"))]
6098pub fn clear_hash_cache() {
6099 crypto_ops::clear_hash_cache();
6100}
6101
6102#[cfg(all(feature = "production", feature = "benchmarking"))]
6115pub fn clear_all_caches() {
6116 clear_script_cache();
6117 clear_hash_cache();
6118}
6119
6120#[cfg(all(feature = "production", feature = "benchmarking"))]
6134pub fn clear_stack_pool() {
6135 STACK_POOL.with(|pool| {
6136 let mut pool = pool.borrow_mut();
6137 pool.clear();
6138 });
6139}
6140
6141#[cfg(all(feature = "production", feature = "benchmarking"))]
6155pub fn reset_benchmarking_state() {
6156 clear_all_caches();
6157 clear_stack_pool();
6158 disable_caching(false); #[cfg(feature = "benchmarking")]
6161 crate::transaction_hash::clear_sighash_templates();
6162}
6163
6164#[cfg(test)]
6165mod tests {
6166 use super::*;
6167
6168 #[test]
6169 fn test_eval_script_simple() {
6170 let script = vec![OP_1]; let mut stack = Vec::new();
6172
6173 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6174 assert_eq!(stack.len(), 1);
6175 assert_eq!(stack[0].as_ref(), &[1]);
6176 }
6177
6178 #[test]
6179 fn test_eval_script_overflow() {
6180 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6182
6183 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6184 }
6185
6186 #[test]
6187 fn test_verify_script_simple() {
6188 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());
6199 }
6200
6201 #[test]
6206 fn test_op_0() {
6207 let script = vec![OP_0]; let mut stack = Vec::new();
6209 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6210 assert!(!result); assert_eq!(stack.len(), 1);
6212 assert!(stack[0].is_empty());
6213 }
6214
6215 #[test]
6216 fn test_op_1_to_op_16() {
6217 for i in 1..=16 {
6219 let opcode = 0x50 + i;
6220 let script = vec![opcode];
6221 let mut stack = Vec::new();
6222 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6223 assert!(result);
6224 assert_eq!(stack.len(), 1);
6225 assert_eq!(stack[0].as_ref(), &[i]);
6226 }
6227 }
6228
6229 #[test]
6230 fn test_op_dup() {
6231 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6233 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6234 assert!(!result); assert_eq!(stack.len(), 2);
6236 assert_eq!(stack[0].as_ref(), &[1]);
6237 assert_eq!(stack[1].as_ref(), &[1]);
6238 }
6239
6240 #[test]
6241 fn test_op_dup_empty_stack() {
6242 let script = vec![OP_DUP]; let mut stack = Vec::new();
6244 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6245 assert!(!result);
6246 }
6247
6248 #[test]
6249 fn test_op_hash160() {
6250 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6252 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6253 assert!(result);
6254 assert_eq!(stack.len(), 1);
6255 assert_eq!(stack[0].len(), 20); }
6257
6258 #[test]
6259 fn test_op_hash160_empty_stack() {
6260 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6262 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6263 assert!(!result);
6264 }
6265
6266 #[test]
6267 fn test_op_hash256() {
6268 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6270 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6271 assert!(result);
6272 assert_eq!(stack.len(), 1);
6273 assert_eq!(stack[0].len(), 32); }
6275
6276 #[test]
6277 fn test_op_hash256_empty_stack() {
6278 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6280 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6281 assert!(!result);
6282 }
6283
6284 #[test]
6285 fn test_op_equal() {
6286 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6288 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6289 assert!(result);
6290 assert_eq!(stack.len(), 1);
6291 assert_eq!(stack[0].as_ref(), &[1]); }
6293
6294 #[test]
6295 fn test_op_equal_false() {
6296 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6298 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6299 assert!(!result); assert_eq!(stack.len(), 1);
6301 assert_eq!(stack[0].as_ref(), &[0]); }
6303
6304 #[test]
6305 fn test_op_equal_insufficient_stack() {
6306 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6308 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6309 assert!(
6310 result.is_err(),
6311 "OP_EQUAL with insufficient stack should return error"
6312 );
6313 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6314 assert_eq!(
6315 code,
6316 crate::error::ScriptErrorCode::InvalidStackOperation,
6317 "Should return InvalidStackOperation"
6318 );
6319 }
6320 }
6321
6322 #[test]
6323 fn test_op_verify() {
6324 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6326 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6327 assert!(!result); assert_eq!(stack.len(), 0); }
6330
6331 #[test]
6332 fn test_op_verify_false() {
6333 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6335 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6336 assert!(!result);
6337 }
6338
6339 #[test]
6340 fn test_op_verify_empty_stack() {
6341 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6343 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6344 assert!(!result);
6345 }
6346
6347 #[test]
6348 fn test_op_equalverify() {
6349 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6351 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6352 assert!(!result); assert_eq!(stack.len(), 0); }
6355
6356 #[test]
6357 fn test_op_equalverify_false() {
6358 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6360 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6361 assert!(
6362 result.is_err(),
6363 "OP_EQUALVERIFY with false condition should return error"
6364 );
6365 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6366 assert_eq!(
6367 code,
6368 crate::error::ScriptErrorCode::EqualVerify,
6369 "Should return EqualVerify"
6370 );
6371 }
6372 }
6373
6374 #[test]
6375 fn test_op_checksig() {
6376 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6380 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6381 assert!(!result); assert_eq!(stack.len(), 1);
6383 }
6385
6386 #[test]
6387 fn test_op_checksig_insufficient_stack() {
6388 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6390 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6391 assert!(
6392 result.is_err(),
6393 "OP_CHECKSIG with insufficient stack should return error"
6394 );
6395 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6396 assert_eq!(
6397 code,
6398 crate::error::ScriptErrorCode::InvalidStackOperation,
6399 "Should return InvalidStackOperation"
6400 );
6401 }
6402 }
6403
6404 #[test]
6405 fn test_unknown_opcode() {
6406 let script = vec![0xff]; let mut stack = Vec::new();
6408 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6409 assert!(!result);
6410 }
6411
6412 #[test]
6413 fn test_script_size_limit() {
6414 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6416 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6417 assert!(result.is_err());
6418 }
6419
6420 #[test]
6421 fn test_operation_count_limit() {
6422 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6425 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6426 assert!(result.is_err());
6427 }
6428
6429 #[test]
6430 fn test_stack_underflow_multiple_ops() {
6431 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6433 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6434 assert!(result.is_err(), "Stack underflow should return error");
6435 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6436 assert_eq!(
6437 code,
6438 crate::error::ScriptErrorCode::InvalidStackOperation,
6439 "Should return InvalidStackOperation"
6440 );
6441 }
6442 }
6443
6444 #[test]
6445 fn test_final_stack_empty() {
6446 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6448 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6449 assert!(!result);
6450 }
6451
6452 #[test]
6453 fn test_final_stack_false() {
6454 let script = vec![OP_0]; let mut stack = Vec::new();
6456 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6457 assert!(!result);
6458 }
6459
6460 #[test]
6461 fn test_verify_script_with_witness() {
6462 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6466
6467 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6468 assert!(!result); }
6470
6471 #[test]
6472 fn test_verify_script_failure() {
6473 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_2]; let witness = None;
6476 let flags = 0;
6477
6478 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6479 assert!(!result);
6480 }
6481
6482 #[test]
6487 fn test_op_ifdup_true() {
6488 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6490 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6491 assert!(!result); assert_eq!(stack.len(), 2);
6493 assert_eq!(stack[0].as_ref(), &[1]);
6494 assert_eq!(stack[1].as_ref(), &[1]);
6495 }
6496
6497 #[test]
6498 fn test_op_ifdup_false() {
6499 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6501 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6502 assert!(!result); assert_eq!(stack.len(), 1);
6504 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6505 }
6506
6507 #[test]
6508 fn test_op_depth() {
6509 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6511 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6512 assert!(!result); assert_eq!(stack.len(), 3);
6514 assert_eq!(stack[2].as_ref(), &[2]); }
6516
6517 #[test]
6518 fn test_op_drop() {
6519 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
6521 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6522 assert!(result); assert_eq!(stack.len(), 1);
6524 assert_eq!(stack[0].as_ref(), &[1]);
6525 }
6526
6527 #[test]
6528 fn test_op_drop_empty_stack() {
6529 let script = vec![OP_DROP]; let mut stack = Vec::new();
6531 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6532 assert!(!result);
6533 assert_eq!(stack.len(), 0);
6534 }
6535
6536 #[test]
6537 fn test_op_nip() {
6538 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
6540 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6541 assert!(result); assert_eq!(stack.len(), 1);
6543 assert_eq!(stack[0].as_ref(), &[2]);
6544 }
6545
6546 #[test]
6547 fn test_op_nip_insufficient_stack() {
6548 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
6550 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6551 assert!(!result);
6552 assert_eq!(stack.len(), 1);
6553 }
6554
6555 #[test]
6556 fn test_op_over() {
6557 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
6559 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6560 assert!(!result); assert_eq!(stack.len(), 3);
6562 assert_eq!(stack[0].as_ref(), &[1]);
6563 assert_eq!(stack[1].as_ref(), &[2]);
6564 assert_eq!(stack[2].as_ref(), &[1]);
6565 }
6566
6567 #[test]
6568 fn test_op_over_insufficient_stack() {
6569 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
6571 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6572 assert!(!result);
6573 assert_eq!(stack.len(), 1);
6574 }
6575
6576 #[test]
6577 fn test_op_pick() {
6578 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
6580 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6581 assert!(!result); assert_eq!(stack.len(), 4);
6583 assert_eq!(stack[3].as_ref(), &[2]); }
6585
6586 #[test]
6587 fn test_op_pick_empty_n() {
6588 let script = vec![OP_1, OP_0, OP_PICK];
6590 let mut stack = Vec::new();
6591 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6592 assert!(!result); assert_eq!(stack.len(), 2);
6594 assert_eq!(stack[1].as_ref(), &[1]); }
6596
6597 #[test]
6598 fn test_op_pick_invalid_index() {
6599 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
6601 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6602 assert!(!result);
6603 assert_eq!(stack.len(), 1);
6604 }
6605
6606 #[test]
6607 fn test_op_roll() {
6608 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
6610 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6611 assert!(!result); assert_eq!(stack.len(), 3);
6613 assert_eq!(stack[0].as_ref(), &[1]);
6614 assert_eq!(stack[1].as_ref(), &[3]);
6615 assert_eq!(stack[2].as_ref(), &[2]); }
6617
6618 #[test]
6619 fn test_op_roll_zero_n() {
6620 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
6623 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6624 assert!(result); assert_eq!(stack.len(), 1);
6626 assert_eq!(stack[0].as_ref(), &[1]);
6627 }
6628
6629 #[test]
6630 fn test_op_roll_invalid_index() {
6631 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
6633 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6634 assert!(!result);
6635 assert_eq!(stack.len(), 1);
6636 }
6637
6638 #[test]
6639 fn test_op_rot() {
6640 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
6642 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6643 assert!(!result); assert_eq!(stack.len(), 3);
6645 assert_eq!(stack[0].as_ref(), &[2]);
6646 assert_eq!(stack[1].as_ref(), &[3]);
6647 assert_eq!(stack[2].as_ref(), &[1]);
6648 }
6649
6650 #[test]
6651 fn test_op_rot_insufficient_stack() {
6652 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
6654 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6655 assert!(!result);
6656 assert_eq!(stack.len(), 2);
6657 }
6658
6659 #[test]
6660 fn test_op_swap() {
6661 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
6663 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6664 assert!(!result); assert_eq!(stack.len(), 2);
6666 assert_eq!(stack[0].as_ref(), &[2]);
6667 assert_eq!(stack[1].as_ref(), &[1]);
6668 }
6669
6670 #[test]
6671 fn test_op_swap_insufficient_stack() {
6672 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
6674 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6675 assert!(!result);
6676 assert_eq!(stack.len(), 1);
6677 }
6678
6679 #[test]
6680 fn test_op_tuck() {
6681 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
6683 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6684 assert!(!result); assert_eq!(stack.len(), 3);
6686 assert_eq!(stack[0].as_ref(), &[2]);
6687 assert_eq!(stack[1].as_ref(), &[1]);
6688 assert_eq!(stack[2].as_ref(), &[2]);
6689 }
6690
6691 #[test]
6692 fn test_op_tuck_insufficient_stack() {
6693 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
6695 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6696 assert!(!result);
6697 assert_eq!(stack.len(), 1);
6698 }
6699
6700 #[test]
6701 fn test_op_2drop() {
6702 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
6704 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6705 assert!(result); assert_eq!(stack.len(), 1);
6707 assert_eq!(stack[0].as_ref(), &[1]);
6708 }
6709
6710 #[test]
6711 fn test_op_2drop_insufficient_stack() {
6712 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
6714 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6715 assert!(!result);
6716 assert_eq!(stack.len(), 1);
6717 }
6718
6719 #[test]
6720 fn test_op_2dup() {
6721 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
6723 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6724 assert!(!result); assert_eq!(stack.len(), 4);
6726 assert_eq!(stack[0].as_ref(), &[1]);
6727 assert_eq!(stack[1].as_ref(), &[2]);
6728 assert_eq!(stack[2].as_ref(), &[1]);
6729 assert_eq!(stack[3].as_ref(), &[2]);
6730 }
6731
6732 #[test]
6733 fn test_op_2dup_insufficient_stack() {
6734 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
6736 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6737 assert!(!result);
6738 assert_eq!(stack.len(), 1);
6739 }
6740
6741 #[test]
6742 fn test_op_3dup() {
6743 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
6745 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6746 assert!(!result); assert_eq!(stack.len(), 6);
6748 assert_eq!(stack[0].as_ref(), &[1]);
6749 assert_eq!(stack[1].as_ref(), &[2]);
6750 assert_eq!(stack[2].as_ref(), &[3]);
6751 assert_eq!(stack[3].as_ref(), &[1]);
6752 assert_eq!(stack[4].as_ref(), &[2]);
6753 assert_eq!(stack[5].as_ref(), &[3]);
6754 }
6755
6756 #[test]
6757 fn test_op_3dup_insufficient_stack() {
6758 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
6760 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6761 assert!(!result);
6762 assert_eq!(stack.len(), 2);
6763 }
6764
6765 #[test]
6766 fn test_op_2over() {
6767 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
6769 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6770 assert!(!result); assert_eq!(stack.len(), 6);
6772 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
6774 }
6775
6776 #[test]
6777 fn test_op_2over_insufficient_stack() {
6778 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
6780 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6781 assert!(!result);
6782 assert_eq!(stack.len(), 3);
6783 }
6784
6785 #[test]
6786 fn test_op_2rot() {
6787 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
6789 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6790 assert!(!result); assert_eq!(stack.len(), 6);
6792 assert_eq!(stack[4].as_ref(), &[2]); assert_eq!(stack[5].as_ref(), &[1]);
6794 }
6795
6796 #[test]
6797 fn test_op_2rot_insufficient_stack() {
6798 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
6800 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6801 assert!(!result);
6802 assert_eq!(stack.len(), 4);
6803 }
6804
6805 #[test]
6806 fn test_op_2swap() {
6807 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
6809 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6810 assert!(!result); assert_eq!(stack.len(), 4);
6812 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
6814 assert_eq!(stack[2].as_ref(), &[1]);
6815 assert_eq!(stack[3].as_ref(), &[2]);
6816 }
6817
6818 #[test]
6819 fn test_op_2swap_insufficient_stack() {
6820 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
6822 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6823 assert!(!result);
6824 assert_eq!(stack.len(), 3);
6825 }
6826
6827 #[test]
6828 fn test_op_size() {
6829 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
6831 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6832 assert!(!result); assert_eq!(stack.len(), 2);
6834 assert_eq!(stack[0].as_ref(), &[1]);
6835 assert_eq!(stack[1].as_ref(), &[1]); }
6837
6838 #[test]
6839 fn test_op_size_empty_stack() {
6840 let script = vec![OP_SIZE]; let mut stack = Vec::new();
6842 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6843 assert!(!result);
6844 assert_eq!(stack.len(), 0);
6845 }
6846
6847 #[test]
6848 fn test_op_return() {
6849 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
6851 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6852 assert!(!result); assert_eq!(stack.len(), 1);
6854 }
6855
6856 #[test]
6857 fn test_op_checksigverify() {
6858 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6860 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6861 assert!(!result); assert_eq!(stack.len(), 0);
6863 }
6864
6865 #[test]
6866 fn test_op_checksigverify_insufficient_stack() {
6867 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6869 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6870 assert!(!result);
6871 assert_eq!(stack.len(), 1);
6872 }
6873
6874 #[test]
6875 fn test_unknown_opcode_comprehensive() {
6876 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
6878 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6879 assert!(!result); assert_eq!(stack.len(), 1);
6881 }
6882
6883 #[test]
6884 fn test_verify_signature_invalid_pubkey() {
6885 let secp = signature::new_secp();
6886 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
6889 let result = signature::verify_signature(
6890 &secp,
6891 &invalid_pubkey,
6892 &signature,
6893 &dummy_hash,
6894 0,
6895 0,
6896 crate::types::Network::Regtest,
6897 SigVersion::Base,
6898 );
6899 assert!(!result.unwrap_or(false));
6900 }
6901
6902 #[test]
6903 fn test_verify_signature_invalid_signature() {
6904 let secp = signature::new_secp();
6905 let pubkey = vec![
6906 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
6907 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
6908 0x5b, 0x16, 0xf8, 0x17, 0x98,
6909 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
6912 let result = signature::verify_signature(
6913 &secp,
6914 &pubkey,
6915 &invalid_signature,
6916 &dummy_hash,
6917 0,
6918 0,
6919 crate::types::Network::Regtest,
6920 SigVersion::Base,
6921 );
6922 assert!(!result.unwrap_or(false));
6923 }
6924
6925 fn minimal_tx_and_prevouts(
6931 script_sig: &[u8],
6932 script_pubkey: &[u8],
6933 ) -> (
6934 crate::types::Transaction,
6935 Vec<i64>,
6936 Vec<crate::types::ByteString>,
6937 ) {
6938 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
6939 let tx = Transaction {
6940 version: 1,
6941 inputs: vec![TransactionInput {
6942 prevout: OutPoint {
6943 hash: [0u8; 32],
6944 index: 0,
6945 },
6946 sequence: 0xffff_ffff,
6947 script_sig: script_sig.to_vec(),
6948 }]
6949 .into(),
6950 outputs: vec![TransactionOutput {
6951 value: 0,
6952 script_pubkey: script_pubkey.to_vec(),
6953 }]
6954 .into(),
6955 lock_time: 0,
6956 };
6957 let prevout_values = vec![0i64];
6958 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
6959 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
6960 (tx, prevout_values, prevout_script_pubkeys_vec)
6961 }
6962
6963 #[test]
6964 fn test_verify_with_context_p2pkh_hash_mismatch() {
6965 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
6969 script_sig.push(sig.len() as u8);
6970 script_sig.extend(&sig);
6971 script_sig.push(pubkey.len() as u8);
6972 script_sig.extend(&pubkey);
6973
6974 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
6975 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
6977 script_pubkey.push(OP_CHECKSIG);
6978
6979 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
6980 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
6981 let result = verify_script_with_context_full(
6982 &script_sig,
6983 &script_pubkey,
6984 None,
6985 0,
6986 &tx,
6987 0,
6988 &pv,
6989 &psp_refs,
6990 Some(500_000),
6991 None,
6992 crate::types::Network::Mainnet,
6993 SigVersion::Base,
6994 #[cfg(feature = "production")]
6995 None,
6996 None, #[cfg(feature = "production")]
6998 None,
6999 #[cfg(feature = "production")]
7000 None,
7001 #[cfg(feature = "production")]
7002 None,
7003 );
7004 assert!(result.is_ok());
7005 assert!(!result.unwrap());
7006 }
7007
7008 #[test]
7009 fn test_verify_with_context_p2sh_hash_mismatch() {
7010 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7013 script_sig.push(redeem.len() as u8);
7014 script_sig.extend(&redeem);
7015
7016 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7017 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7019
7020 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7021 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7022 let result = verify_script_with_context_full(
7023 &script_sig,
7024 &script_pubkey,
7025 None,
7026 0x01, &tx,
7028 0,
7029 &pv,
7030 &psp_refs,
7031 Some(500_000),
7032 None,
7033 crate::types::Network::Mainnet,
7034 SigVersion::Base,
7035 #[cfg(feature = "production")]
7036 None,
7037 None, #[cfg(feature = "production")]
7039 None,
7040 #[cfg(feature = "production")]
7041 None,
7042 #[cfg(feature = "production")]
7043 None,
7044 );
7045 assert!(result.is_ok());
7046 assert!(!result.unwrap());
7047 }
7048
7049 #[test]
7050 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7051 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7053 script_pubkey.extend(&[0u8; 20]);
7054 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7056 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7057 let empty: Vec<u8> = vec![];
7058 let result = verify_script_with_context_full(
7059 &empty,
7060 &script_pubkey,
7061 Some(&witness),
7062 0,
7063 &tx,
7064 0,
7065 &pv,
7066 &psp_refs,
7067 Some(500_000),
7068 None,
7069 crate::types::Network::Mainnet,
7070 SigVersion::Base,
7071 #[cfg(feature = "production")]
7072 None,
7073 None, #[cfg(feature = "production")]
7075 None,
7076 #[cfg(feature = "production")]
7077 None,
7078 #[cfg(feature = "production")]
7079 None,
7080 );
7081 assert!(result.is_ok());
7082 assert!(!result.unwrap());
7083 }
7084
7085 #[test]
7086 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7087 let witness_script = vec![OP_1];
7089 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7090 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7092 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7093 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7094 let empty: Vec<u8> = vec![];
7095 let result = verify_script_with_context_full(
7096 &empty,
7097 &script_pubkey,
7098 Some(&witness),
7099 0,
7100 &tx,
7101 0,
7102 &pv,
7103 &psp_refs,
7104 Some(500_000),
7105 None,
7106 crate::types::Network::Mainnet,
7107 SigVersion::Base,
7108 #[cfg(feature = "production")]
7109 None,
7110 None, #[cfg(feature = "production")]
7112 None,
7113 #[cfg(feature = "production")]
7114 None,
7115 #[cfg(feature = "production")]
7116 None,
7117 );
7118 assert!(result.is_ok());
7119 assert!(!result.unwrap());
7120 }
7121
7122 #[test]
7123 #[cfg(feature = "production")]
7124 fn test_p2wsh_multisig_fast_path() {
7125 use crate::constants::BIP147_ACTIVATION_MAINNET;
7127 use crate::crypto::OptimizedSha256;
7128
7129 let pk1 = [0x02u8; 33];
7130 let pk2 = [0x03u8; 33];
7131 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7133 witness_script.extend_from_slice(&pk2);
7134 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7138 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7139 script_pubkey.extend_from_slice(&wsh_hash);
7140
7141 let witness: Vec<Vec<u8>> = vec![
7142 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7146 ];
7147
7148 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7149 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7150 let empty: Vec<u8> = vec![];
7151 let result = verify_script_with_context_full(
7152 &empty,
7153 &script_pubkey,
7154 Some(&witness),
7155 0x810, &tx,
7157 0,
7158 &pv,
7159 &psp_refs,
7160 Some(BIP147_ACTIVATION_MAINNET + 1),
7161 None,
7162 crate::types::Network::Mainnet,
7163 SigVersion::Base,
7164 #[cfg(feature = "production")]
7165 None,
7166 None, #[cfg(feature = "production")]
7168 None,
7169 #[cfg(feature = "production")]
7170 None,
7171 #[cfg(feature = "production")]
7172 None,
7173 );
7174 assert!(result.is_ok());
7175 assert!(!result.unwrap());
7176 }
7177}
7178
7179#[cfg(test)]
7180#[allow(unused_doc_comments)]
7181mod property_tests {
7182 use super::*;
7183 use proptest::prelude::*;
7184
7185 proptest! {
7190 #[test]
7191 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7192 let mut stack = Vec::new();
7193 let flags = 0u32;
7194
7195 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7196
7197 if script.len() > MAX_SCRIPT_OPS * 2 {
7205 prop_assert!(result.is_err() || !result.unwrap(),
7208 "Very long scripts should fail or return false");
7209 }
7210 }
7212 }
7213
7214 proptest! {
7219 #[test]
7220 fn prop_verify_script_deterministic(
7221 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7222 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7223 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7224 flags in any::<u32>()
7225 ) {
7226 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7227 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7228
7229 assert_eq!(result1.is_ok(), result2.is_ok());
7230 if result1.is_ok() && result2.is_ok() {
7231 assert_eq!(result1.unwrap(), result2.unwrap());
7232 }
7233 }
7234 }
7235
7236 proptest! {
7241 #[test]
7242 fn prop_execute_opcode_no_panic(
7243 opcode in any::<u8>(),
7244 stack_items in prop::collection::vec(
7245 prop::collection::vec(any::<u8>(), 0..5),
7246 0..10
7247 ),
7248 flags in any::<u32>()
7249 ) {
7250 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7251 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7252
7253 match result {
7256 Ok(success) => {
7257 let _ = success;
7259 },
7260 Err(_) => {
7261 }
7264 }
7265
7266 assert!(stack.len() <= MAX_STACK_SIZE);
7268 }
7269 }
7270
7271 proptest! {
7278 #[test]
7279 fn prop_stack_operations_bounds(
7280 opcode in any::<u8>(),
7281 stack_items in prop::collection::vec(
7282 prop::collection::vec(any::<u8>(), 0..3),
7283 0..5
7284 ),
7285 flags in any::<u32>()
7286 ) {
7287 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7288 let initial_len = stack.len();
7289
7290 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7291
7292 assert!(stack.len() <= MAX_STACK_SIZE);
7294
7295 if result.is_ok() && result.unwrap() {
7297 match opcode {
7299 OP_0 | OP_1..=OP_16 => {
7300 assert!(stack.len() == initial_len + 1);
7302 },
7303 OP_DUP => {
7304 if initial_len > 0 {
7306 assert!(stack.len() == initial_len + 1);
7307 }
7308 },
7309 OP_3DUP => {
7310 if initial_len >= 3 {
7312 assert!(stack.len() == initial_len + 3);
7313 }
7314 },
7315 OP_2OVER => {
7316 if initial_len >= 4 {
7318 assert!(stack.len() == initial_len + 2);
7319 }
7320 },
7321 OP_DROP | OP_NIP | OP_2DROP => {
7322 assert!(stack.len() <= initial_len);
7324 },
7325 _ => {
7326 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7329 }
7330 }
7331 }
7332 }
7333 }
7334
7335 proptest! {
7340 #[test]
7341 fn prop_hash_operations_deterministic(
7342 input in prop::collection::vec(any::<u8>(), 0..10)
7343 ) {
7344 let elem = to_stack_element(&input);
7345 let mut stack1 = vec![elem.clone()];
7346 let mut stack2 = vec![elem];
7347
7348 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());
7352 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7353 assert_eq!(val1, val2);
7354 if val1 {
7355 assert_eq!(stack1, stack2);
7356 }
7357 }
7358 }
7359 }
7360
7361 proptest! {
7366 #[test]
7367 fn prop_equality_operations_symmetric(
7368 a in prop::collection::vec(any::<u8>(), 0..5),
7369 b in prop::collection::vec(any::<u8>(), 0..5)
7370 ) {
7371 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7372 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7373
7374 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());
7378 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7379 assert_eq!(val1, val2);
7380 if val1 {
7381 assert_eq!(stack1.len(), stack2.len());
7383 if !stack1.is_empty() && !stack2.is_empty() {
7384 assert_eq!(stack1[0], stack2[0]);
7385 }
7386 }
7387 }
7388 }
7389 }
7390
7391 proptest! {
7396 #[test]
7397 fn prop_script_execution_terminates(
7398 script in prop::collection::vec(any::<u8>(), 0..50)
7399 ) {
7400 let mut stack = Vec::new();
7401 let flags = 0u32;
7402
7403 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7405
7406 assert!(result.is_ok() || result.is_err());
7408
7409 assert!(stack.len() <= MAX_STACK_SIZE);
7411 }
7412 }
7413}