1#![allow(
5 clippy::declare_interior_mutable_const, clippy::type_complexity,
7 clippy::too_many_arguments,
8 clippy::needless_return, )]
10mod arithmetic;
17mod context;
18mod control_flow;
19mod crypto_ops;
20mod signature;
21mod stack;
22
23pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
24pub use stack::{cast_to_bool, to_stack_element, StackElement};
25
26use crate::constants::*;
27use crate::crypto::OptimizedSha256;
28use crate::error::{ConsensusError, Result, ScriptErrorCode};
29use crate::opcodes::*;
30use crate::types::*;
31use blvm_spec_lock::spec_locked;
32use digest::Digest;
33use ripemd::Ripemd160;
34
35#[cfg(feature = "production")]
37use crate::optimizations::{precomputed_constants, prefetch};
38
39#[cold]
41#[allow(dead_code)]
42fn make_operation_limit_error() -> ConsensusError {
43 ConsensusError::ScriptErrorWithCode {
44 code: ScriptErrorCode::OpCount,
45 message: "Operation limit exceeded".into(),
46 }
47}
48
49#[cold]
50fn make_stack_overflow_error() -> ConsensusError {
51 ConsensusError::ScriptErrorWithCode {
52 code: ScriptErrorCode::StackSize,
53 message: "Stack overflow".into(),
54 }
55}
56
57#[cfg(feature = "production")]
58use std::collections::VecDeque;
59#[cfg(feature = "production")]
60use std::sync::{
61 atomic::{AtomicBool, AtomicU64, Ordering},
62 OnceLock, RwLock,
63};
64#[cfg(feature = "production")]
65use std::thread_local;
66
67#[cfg(feature = "production")]
73static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
74
75#[cfg(feature = "production")]
78const SIG_CACHE_SHARDS: usize = 32;
79
80#[cfg(feature = "production")]
81const SIG_CACHE_SHARD: OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>> = OnceLock::new();
82
83#[cfg(feature = "production")]
84static SIG_CACHE: [OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>>; SIG_CACHE_SHARDS] =
85 [SIG_CACHE_SHARD; SIG_CACHE_SHARDS];
86
87#[cfg(feature = "production")]
89fn sig_cache_size() -> usize {
90 std::env::var("BLVM_SIG_CACHE_ENTRIES")
91 .ok()
92 .and_then(|s| s.parse().ok())
93 .filter(|&n: &usize| n > 0 && n <= 1_000_000)
94 .unwrap_or(500_000)
95}
96
97#[cfg(feature = "production")]
98fn sig_cache_shard_index(key: &[u8; 32]) -> usize {
99 let h = (key[0] as usize) | ((key[1] as usize) << 8) | ((key[2] as usize) << 16);
100 h % SIG_CACHE_SHARDS
101}
102
103#[cfg(feature = "production")]
104fn get_sig_cache_shard(key: &[u8; 32]) -> &'static RwLock<lru::LruCache<[u8; 32], bool>> {
105 let idx = sig_cache_shard_index(key);
106 SIG_CACHE[idx].get_or_init(|| {
107 use lru::LruCache;
108 use std::num::NonZeroUsize;
109 let cap = (sig_cache_size() / SIG_CACHE_SHARDS).max(1);
110 RwLock::new(LruCache::new(NonZeroUsize::new(cap).unwrap()))
111 })
112}
113
114#[cfg(feature = "production")]
115thread_local! {
116 static BATCH_PUT_SIG_CACHE_BY_SHARD: std::cell::RefCell<[Vec<([u8; 32], bool)>; SIG_CACHE_SHARDS]> =
117 std::cell::RefCell::new(std::array::from_fn(|_| Vec::new()));
118}
119
120#[cfg(feature = "production")]
122thread_local! {
123 static SOA_BATCH_BUF: std::cell::RefCell<(
124 Vec<[u8; 64]>,
125 Vec<[u8; 32]>,
126 Vec<[u8; 33]>,
127 Vec<usize>,
128 Vec<[u8; 32]>,
129 )> = const { std::cell::RefCell::new((
130 Vec::new(),
131 Vec::new(),
132 Vec::new(),
133 Vec::new(),
134 Vec::new(),
135 )) };
136}
137
138#[cfg(feature = "production")]
139fn batch_put_sig_cache(keys: &[[u8; 32]], results: &[bool]) {
140 BATCH_PUT_SIG_CACHE_BY_SHARD.with(|cell| {
141 let mut by_shard = cell.borrow_mut();
142 for v in by_shard.iter_mut() {
143 v.clear();
144 }
145 for (i, key) in keys.iter().enumerate() {
146 let result = results.get(i).copied().unwrap_or(false);
147 let idx = sig_cache_shard_index(key);
148 by_shard[idx].push((*key, result));
149 }
150 for shard_entries in by_shard.iter() {
151 if shard_entries.is_empty() {
152 continue;
153 }
154 let first_key = &shard_entries[0].0;
155 if let Ok(mut guard) = get_sig_cache_shard(first_key).write() {
156 for (k, v) in shard_entries.iter() {
157 guard.put(*k, *v);
158 }
159 }
160 }
161 });
162}
163
164#[cfg(feature = "production")]
170fn sig_cache_at_collect_enabled() -> bool {
171 use std::sync::OnceLock;
172 static CACHE: OnceLock<bool> = OnceLock::new();
173 *CACHE.get_or_init(|| {
174 std::env::var("BLVM_SIG_CACHE_AT_COLLECT")
175 .map(|s| s == "1" || s.eq_ignore_ascii_case("true"))
176 .unwrap_or(false)
177 })
178}
179
180#[cfg(feature = "production")]
183#[inline(always)]
184fn ecdsa_cache_key(msg: &[u8; 32], pk: &[u8; 33], sig_compact: &[u8; 64], flags: u32) -> [u8; 32] {
185 use siphasher::sip::SipHasher24;
186 use std::hash::{Hash, Hasher};
187 let mut key_input = [0u8; 133];
188 key_input[..32].copy_from_slice(msg);
189 key_input[32..65].copy_from_slice(pk);
190 key_input[65..129].copy_from_slice(sig_compact);
191 key_input[129..133].copy_from_slice(&flags.to_le_bytes());
192 let mut hasher = SipHasher24::new();
193 key_input.hash(&mut hasher);
194 let h = hasher.finish();
195 let mut out = [0u8; 32];
196 out[..8].copy_from_slice(&h.to_le_bytes());
197 out
198}
199
200#[cfg(feature = "production")]
203static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
204#[cfg(feature = "production")]
205static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
206#[cfg(feature = "production")]
207static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
208#[cfg(feature = "production")]
209static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
210#[cfg(feature = "production")]
211static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
212static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
213#[cfg(feature = "production")]
214static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
215#[cfg(feature = "production")]
216static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
217
218#[cfg(feature = "production")]
219fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
220 SCRIPT_CACHE.get_or_init(|| {
221 use lru::LruCache;
225 use std::num::NonZeroUsize;
226 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
227 })
228}
229
230#[cfg(feature = "production")]
235thread_local! {
236 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
237 std::cell::RefCell::new(VecDeque::with_capacity(10));
238}
239
240#[cfg(feature = "production")]
242fn get_pooled_stack() -> Vec<StackElement> {
243 STACK_POOL.with(|pool| {
244 let mut pool = pool.borrow_mut();
245 if let Some(mut stack) = pool.pop_front() {
246 stack.clear();
247 if stack.capacity() < 20 {
248 stack.reserve(20);
249 }
250 stack
251 } else {
252 Vec::with_capacity(20)
253 }
254 })
255}
256
257#[cfg(feature = "production")]
259struct PooledStackGuard(Vec<StackElement>);
260#[cfg(feature = "production")]
261impl Drop for PooledStackGuard {
262 fn drop(&mut self) {
263 return_pooled_stack(std::mem::take(&mut self.0));
264 }
265}
266
267#[cfg(feature = "production")]
269fn return_pooled_stack(mut stack: Vec<StackElement>) {
270 stack.clear();
272
273 STACK_POOL.with(|pool| {
274 let mut pool = pool.borrow_mut();
275 if pool.len() < 10 {
277 pool.push_back(stack);
278 }
279 });
281}
282
283#[cfg(feature = "production")]
288static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
289
290#[cfg(feature = "production")]
306pub fn disable_caching(disabled: bool) {
307 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
308}
309
310#[cfg(feature = "production")]
312fn is_caching_disabled() -> bool {
313 CACHE_DISABLED.load(Ordering::Relaxed)
314}
315
316#[cfg(feature = "production")]
321fn compute_script_cache_key(
322 script_sig: &ByteString,
323 script_pubkey: &[u8],
324 witness: Option<&ByteString>,
325 flags: u32,
326) -> u64 {
327 use std::collections::hash_map::DefaultHasher;
328 use std::hash::{Hash, Hasher};
329
330 let mut hasher = DefaultHasher::new();
331 script_sig.hash(&mut hasher);
332 script_pubkey.hash(&mut hasher);
333 if let Some(w) = witness {
334 w.hash(&mut hasher);
335 }
336 flags.hash(&mut hasher);
337 hasher.finish()
338}
339
340#[derive(Debug, Clone, Copy, PartialEq, Eq)]
342pub enum SigVersion {
343 Base,
345 WitnessV0,
347 Tapscript,
349}
350
351#[spec_locked("5.2", "EvalScript")]
367#[cfg_attr(feature = "production", inline(always))]
368#[cfg_attr(not(feature = "production"), inline)]
369pub fn eval_script(
370 script: &[u8],
371 stack: &mut Vec<StackElement>,
372 flags: u32,
373 sigversion: SigVersion,
374) -> Result<bool> {
375 if stack.capacity() < 20 {
378 stack.reserve(20);
379 }
380 #[cfg(feature = "production")]
381 {
382 eval_script_impl(script, stack, flags, sigversion)
383 }
384 #[cfg(not(feature = "production"))]
385 {
386 eval_script_inner(script, stack, flags, sigversion)
387 }
388}
389#[cfg(feature = "production")]
390fn eval_script_impl(
391 script: &[u8],
392 stack: &mut Vec<StackElement>,
393 flags: u32,
394 sigversion: SigVersion,
395) -> Result<bool> {
396 eval_script_inner(script, stack, flags, sigversion)
397}
398
399#[cfg(not(feature = "production"))]
400#[allow(dead_code)]
401fn eval_script_impl(
402 script: &[u8],
403 stack: &mut Vec<StackElement>,
404 flags: u32,
405 sigversion: SigVersion,
406) -> Result<bool> {
407 eval_script_inner(script, stack, flags, sigversion)
408}
409
410#[inline(always)]
412fn is_push_opcode(opcode: u8) -> bool {
413 opcode <= 0x60
414}
415
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", "VerifyScript")]
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", "VerifyScript")]
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#[cfg(feature = "production")]
784#[allow(clippy::too_many_arguments)]
785pub fn try_verify_p2pk_fast_path(
786 script_sig: &ByteString,
787 script_pubkey: &[u8],
788 flags: u32,
789 tx: &Transaction,
790 input_index: usize,
791 prevout_values: &[i64],
792 prevout_script_pubkeys: &[&[u8]],
793 block_height: Option<u64>,
794 network: crate::types::Network,
795 #[cfg(feature = "production")] sighash_cache: Option<
796 &crate::transaction_hash::SighashMidstateCache,
797 >,
798) -> Option<Result<bool>> {
799 let len = script_pubkey.len();
802 if len != 35 && len != 67 {
803 return None;
804 }
805 if script_pubkey[len - 1] != OP_CHECKSIG {
806 return None;
807 }
808 let pubkey_len = len - 2; if pubkey_len != 33 && pubkey_len != 65 {
810 return None;
811 }
812 if script_pubkey[0] != 0x21 && script_pubkey[0] != 0x41 {
813 return None; }
815 let pubkey_bytes = &script_pubkey[1..(len - 1)];
816
817 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
818 if signature_bytes.is_empty() {
819 return Some(Ok(false));
820 }
821
822 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
824 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
825 let sighash_type = SighashType::from_byte(sighash_byte);
826 let deleted_storage;
827 let script_code: &[u8] = if script_pubkey.len() < 71 {
828 script_pubkey
829 } else {
830 let pattern = serialize_push_data(signature_bytes);
831 deleted_storage = find_and_delete(script_pubkey, &pattern);
832 deleted_storage.as_ref()
833 };
834 let sighash = match calculate_transaction_sighash_single_input(
835 tx,
836 input_index,
837 script_code,
838 prevout_values[input_index],
839 sighash_type,
840 #[cfg(feature = "production")]
841 sighash_cache,
842 ) {
843 Ok(h) => h,
844 Err(e) => return Some(Err(e)),
845 };
846
847 let height = block_height.unwrap_or(0);
848 let is_valid = signature::with_secp_context(|secp| {
849 signature::verify_signature(
850 secp,
851 pubkey_bytes,
852 signature_bytes,
853 &sighash,
854 flags,
855 height,
856 network,
857 SigVersion::Base,
858 )
859 });
860 Some(is_valid)
861}
862
863#[cfg(feature = "production")]
866#[allow(clippy::too_many_arguments)]
867pub fn try_verify_p2pkh_fast_path(
868 script_sig: &ByteString,
869 script_pubkey: &[u8],
870 flags: u32,
871 tx: &Transaction,
872 input_index: usize,
873 prevout_values: &[i64],
874 prevout_script_pubkeys: &[&[u8]],
875 block_height: Option<u64>,
876 network: crate::types::Network,
877 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
878 #[cfg(feature = "production")] sighash_cache: Option<
879 &crate::transaction_hash::SighashMidstateCache,
880 >,
881 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
882) -> Option<Result<bool>> {
883 #[cfg(all(feature = "production", feature = "profile"))]
884 let _t_entry = std::time::Instant::now();
885 if script_pubkey.len() != 25 {
887 return None;
888 }
889 if script_pubkey[0] != OP_DUP
890 || script_pubkey[1] != OP_HASH160
891 || script_pubkey[2] != PUSH_20_BYTES
892 || script_pubkey[23] != OP_EQUALVERIFY
893 || script_pubkey[24] != OP_CHECKSIG
894 {
895 return None;
896 }
897 let expected_hash = &script_pubkey[3..23];
898
899 #[cfg(all(feature = "production", feature = "profile"))]
900 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
901 #[cfg(all(feature = "production", feature = "profile"))]
902 let _t_parse = std::time::Instant::now();
903 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
904 #[cfg(all(feature = "production", feature = "profile"))]
905 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
906
907 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
909 return Some(Ok(false));
910 }
911 if signature_bytes.is_empty() {
913 return Some(Ok(false));
914 }
915
916 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
918 Some(h) => h,
919 None => {
920 #[cfg(all(feature = "production", feature = "profile"))]
921 let _t_hash = std::time::Instant::now();
922 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
923 let h = Ripemd160::digest(sha256_hash);
924 #[cfg(all(feature = "production", feature = "profile"))]
925 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
926 h.into()
927 }
928 };
929 if &pubkey_hash[..] != expected_hash {
930 return Some(Ok(false));
931 }
932
933 use crate::transaction_hash::SighashType;
936 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
937 let sighash_type = SighashType::from_byte(sighash_byte);
938 let deleted_storage;
939 let script_code: &[u8] = if script_pubkey.len() < 71 {
940 script_pubkey
941 } else {
942 let pattern = serialize_push_data(signature_bytes);
943 deleted_storage = find_and_delete(script_pubkey, &pattern);
944 deleted_storage.as_ref()
945 };
946 let sighash = {
947 #[cfg(feature = "production")]
948 {
949 if let Some(precomp) = precomputed_sighash_all {
950 precomp
951 } else {
952 crate::transaction_hash::compute_legacy_sighash_nocache(
953 tx,
954 input_index,
955 script_code,
956 sighash_byte,
957 )
958 }
959 }
960 #[cfg(not(feature = "production"))]
961 {
962 match calculate_transaction_sighash_single_input(
963 tx,
964 input_index,
965 script_code,
966 prevout_values[input_index],
967 sighash_type,
968 ) {
969 Ok(h) => h,
970 Err(e) => return Some(Err(e)),
971 }
972 }
973 };
974
975 #[cfg(all(feature = "production", feature = "profile"))]
976 let _t_secp = std::time::Instant::now();
977 let height = block_height.unwrap_or(0);
978 let is_valid: Result<bool> = {
979 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
980 if flags & 0x04 != 0
981 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
982 .unwrap_or(false)
983 {
984 Ok(false)
985 } else if flags & 0x02 != 0 {
986 let base_sighash = sighash_byte & !0x80;
987 if !(0x01..=0x03).contains(&base_sighash) {
988 Ok(false)
989 } else if pubkey_bytes.len() == 33 {
990 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
991 Ok(false)
992 } else {
993 let strict_der = flags & 0x04 != 0;
994 let enforce_low_s = flags & 0x08 != 0;
995 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
996 der_sig,
997 pubkey_bytes,
998 &sighash,
999 strict_der,
1000 enforce_low_s,
1001 )
1002 .unwrap_or(false))
1003 }
1004 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1005 let strict_der = flags & 0x04 != 0;
1006 let enforce_low_s = flags & 0x08 != 0;
1007 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1008 der_sig,
1009 pubkey_bytes,
1010 &sighash,
1011 strict_der,
1012 enforce_low_s,
1013 )
1014 .unwrap_or(false))
1015 } else {
1016 Ok(false)
1017 }
1018 } else {
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 }
1030 };
1031 #[cfg(all(feature = "production", feature = "profile"))]
1032 {
1033 let ns = _t_secp.elapsed().as_nanos() as u64;
1034 crate::script_profile::add_p2pkh_collect_ns(ns);
1035 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1036 }
1037 Some(is_valid)
1038}
1039
1040#[cfg(feature = "production")]
1046#[inline]
1047pub fn verify_p2pkh_inline(
1048 script_sig: &[u8],
1049 script_pubkey: &[u8],
1050 flags: u32,
1051 tx: &Transaction,
1052 input_index: usize,
1053 height: u64,
1054 network: crate::types::Network,
1055 precomputed_sighash_all: Option<[u8; 32]>,
1056) -> Result<bool> {
1057 #[cfg(feature = "profile")]
1058 let _t0 = std::time::Instant::now();
1059
1060 let expected_hash = &script_pubkey[3..23];
1061
1062 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1063 Some(pair) => pair,
1064 None => return Ok(false),
1065 };
1066
1067 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1068 return Ok(false);
1069 }
1070
1071 #[cfg(feature = "profile")]
1072 let _t_hash = std::time::Instant::now();
1073
1074 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1075 let pubkey_hash: [u8; 20] = Ripemd160::digest(sha256_hash).into();
1076 if &pubkey_hash[..] != expected_hash {
1077 return Ok(false);
1078 }
1079
1080 #[cfg(feature = "profile")]
1081 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1082
1083 #[cfg(feature = "profile")]
1084 let _t_sighash = std::time::Instant::now();
1085
1086 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1087 let sighash = if let Some(precomp) = precomputed_sighash_all {
1088 precomp
1089 } else {
1090 crate::transaction_hash::compute_legacy_sighash_buffered(
1091 tx,
1092 input_index,
1093 script_pubkey,
1094 sighash_byte,
1095 )
1096 };
1097
1098 #[cfg(feature = "profile")]
1099 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1100
1101 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1102 let strict_der = flags & 0x04 != 0;
1103 let enforce_low_s = flags & 0x08 != 0;
1104
1105 if strict_der
1106 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1107 .unwrap_or(false)
1108 {
1109 return Ok(false);
1110 }
1111
1112 if flags & 0x02 != 0 {
1113 let sighash_base = sighash_byte & !0x80;
1114 if !(0x01..=0x03).contains(&sighash_base) {
1115 return Ok(false);
1116 }
1117 match pubkey_bytes.len() {
1118 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1119 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1120 33 | 65 => {}
1121 _ => return Ok(false),
1122 }
1123 }
1124
1125 #[cfg(feature = "profile")]
1126 let _t_secp = std::time::Instant::now();
1127
1128 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1129 der_sig,
1130 pubkey_bytes,
1131 &sighash,
1132 strict_der,
1133 enforce_low_s,
1134 )
1135 .unwrap_or(false);
1136
1137 #[cfg(feature = "profile")]
1138 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1139
1140 #[cfg(feature = "profile")]
1141 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1142
1143 Ok(result)
1144}
1145
1146#[cfg(feature = "production")]
1148#[inline]
1149pub fn verify_p2pk_inline(
1150 script_sig: &[u8],
1151 script_pubkey: &[u8],
1152 flags: u32,
1153 tx: &Transaction,
1154 input_index: usize,
1155 height: u64,
1156 network: crate::types::Network,
1157) -> Result<bool> {
1158 let pk_len = script_pubkey.len() - 2; let pubkey_bytes = &script_pubkey[1..1 + pk_len];
1160
1161 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1162 Some(s) => s,
1163 None => return Ok(false),
1164 };
1165 if signature_bytes.is_empty() {
1166 return Ok(false);
1167 }
1168
1169 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1170 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_buffered(
1173 tx,
1174 input_index,
1175 script_code,
1176 sighash_byte,
1177 );
1178
1179 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1180 let strict_der = flags & 0x04 != 0;
1181 let enforce_low_s = flags & 0x08 != 0;
1182
1183 if strict_der
1184 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1185 .unwrap_or(false)
1186 {
1187 return Ok(false);
1188 }
1189
1190 if flags & 0x02 != 0 {
1191 let sighash_base = sighash_byte & !0x80;
1192 if !(0x01..=0x03).contains(&sighash_base) {
1193 return Ok(false);
1194 }
1195 match pubkey_bytes.len() {
1196 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1197 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1198 33 | 65 => {}
1199 _ => return Ok(false),
1200 }
1201 }
1202
1203 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1204 der_sig,
1205 pubkey_bytes,
1206 &sighash,
1207 strict_der,
1208 enforce_low_s,
1209 )
1210 .unwrap_or(false))
1211}
1212
1213#[allow(clippy::too_many_arguments)]
1217fn try_verify_p2sh_multisig_fast_path(
1218 script_sig: &ByteString,
1219 script_pubkey: &[u8],
1220 flags: u32,
1221 tx: &Transaction,
1222 input_index: usize,
1223 prevout_values: &[i64],
1224 prevout_script_pubkeys: &[&[u8]],
1225 block_height: Option<u64>,
1226 network: crate::types::Network,
1227 #[cfg(feature = "production")] sighash_cache: Option<
1228 &crate::transaction_hash::SighashMidstateCache,
1229 >,
1230) -> Option<Result<bool>> {
1231 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1232 if pushes.len() < 2 {
1233 return None;
1234 }
1235 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1236 let expected_hash = &script_pubkey[2..22];
1237 let sha256_hash = OptimizedSha256::new().hash(redeem);
1238 let redeem_hash = Ripemd160::digest(sha256_hash);
1239 if &redeem_hash[..] != expected_hash {
1240 return Some(Ok(false));
1241 }
1242 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1243 let signatures: Vec<&[u8]> = pushes
1244 .iter()
1245 .take(pushes.len() - 1)
1246 .skip(1)
1247 .map(|e| e.as_ref())
1248 .collect();
1249 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1250
1251 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1252 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1253 let height = block_height.unwrap_or(0);
1254 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1255 let activation = match network {
1256 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1257 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1258 crate::types::Network::Regtest => 0,
1259 };
1260 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1261 return Some(Ok(false));
1262 }
1263 }
1264
1265 let mut cleaned = redeem.to_vec();
1266 for sig in &signatures {
1267 if !sig.is_empty() {
1268 let pattern = serialize_push_data(sig);
1269 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1270 }
1271 }
1272
1273 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1274
1275 let mut sig_index = 0;
1276 let mut valid_sigs = 0u8;
1277
1278 for pubkey_bytes in pubkeys {
1279 if sig_index >= signatures.len() {
1280 break;
1281 }
1282 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1283 sig_index += 1;
1284 }
1285 if sig_index >= signatures.len() {
1286 break;
1287 }
1288 let signature_bytes = &signatures[sig_index];
1289 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1290 let sighash_type = SighashType::from_byte(sighash_byte);
1291 let sighash = match calculate_transaction_sighash_single_input(
1292 tx,
1293 input_index,
1294 &cleaned,
1295 prevout_values[input_index],
1296 sighash_type,
1297 #[cfg(feature = "production")]
1298 sighash_cache,
1299 ) {
1300 Ok(h) => h,
1301 Err(e) => return Some(Err(e)),
1302 };
1303
1304 #[cfg(feature = "production")]
1305 let is_valid = signature::with_secp_context(|secp| {
1306 signature::verify_signature(
1307 secp,
1308 pubkey_bytes,
1309 signature_bytes,
1310 &sighash,
1311 flags,
1312 height,
1313 network,
1314 SigVersion::Base,
1315 )
1316 });
1317
1318 #[cfg(not(feature = "production"))]
1319 let is_valid = {
1320 let secp = signature::new_secp();
1321 signature::verify_signature(
1322 &secp,
1323 pubkey_bytes,
1324 signature_bytes,
1325 &sighash,
1326 flags,
1327 height,
1328 network,
1329 SigVersion::Base,
1330 )
1331 };
1332
1333 let is_valid = match is_valid {
1334 Ok(v) => v,
1335 Err(e) => return Some(Err(e)),
1336 };
1337
1338 if is_valid {
1339 valid_sigs += 1;
1340 sig_index += 1;
1341 }
1342 }
1343
1344 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1345 for sig_bytes in &signatures[sig_index..] {
1346 if !sig_bytes.is_empty() {
1347 return Some(Err(ConsensusError::ScriptErrorWithCode {
1348 code: ScriptErrorCode::SigNullFail,
1349 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1350 .into(),
1351 }));
1352 }
1353 }
1354 }
1355
1356 Some(Ok(valid_sigs >= m))
1357}
1358
1359#[allow(clippy::too_many_arguments)]
1362fn try_verify_bare_multisig_fast_path(
1363 script_sig: &ByteString,
1364 script_pubkey: &[u8],
1365 flags: u32,
1366 tx: &Transaction,
1367 input_index: usize,
1368 prevout_values: &[i64],
1369 prevout_script_pubkeys: &[&[u8]],
1370 block_height: Option<u64>,
1371 network: crate::types::Network,
1372 #[cfg(feature = "production")] sighash_cache: Option<
1373 &crate::transaction_hash::SighashMidstateCache,
1374 >,
1375) -> Option<Result<bool>> {
1376 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1377 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1378 if pushes.len() < 2 {
1379 return None;
1380 }
1381 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1382 let signatures: Vec<&[u8]> = pushes[1..].iter().map(|e| e.as_ref()).collect();
1383
1384 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1385 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1386 let height = block_height.unwrap_or(0);
1387 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1388 let activation = match network {
1389 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1390 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1391 crate::types::Network::Regtest => 0,
1392 };
1393 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1394 return Some(Ok(false));
1395 }
1396 }
1397
1398 let mut cleaned = script_pubkey.to_vec();
1399 for sig in &signatures {
1400 if !sig.is_empty() {
1401 let pattern = serialize_push_data(sig);
1402 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1403 }
1404 }
1405
1406 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1407
1408 let mut sig_index = 0;
1409 let mut valid_sigs = 0u8;
1410
1411 for pubkey_bytes in pubkeys {
1412 if sig_index >= signatures.len() {
1413 break;
1414 }
1415 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1416 sig_index += 1;
1417 }
1418 if sig_index >= signatures.len() {
1419 break;
1420 }
1421 let signature_bytes = &signatures[sig_index];
1422 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1423 let sighash_type = SighashType::from_byte(sighash_byte);
1424 let sighash = match calculate_transaction_sighash_single_input(
1425 tx,
1426 input_index,
1427 &cleaned,
1428 prevout_values[input_index],
1429 sighash_type,
1430 #[cfg(feature = "production")]
1431 sighash_cache,
1432 ) {
1433 Ok(h) => h,
1434 Err(e) => return Some(Err(e)),
1435 };
1436
1437 #[cfg(feature = "production")]
1438 let is_valid = signature::with_secp_context(|secp| {
1439 signature::verify_signature(
1440 secp,
1441 pubkey_bytes,
1442 signature_bytes,
1443 &sighash,
1444 flags,
1445 height,
1446 network,
1447 SigVersion::Base,
1448 )
1449 });
1450
1451 #[cfg(not(feature = "production"))]
1452 let is_valid = {
1453 let secp = signature::new_secp();
1454 signature::verify_signature(
1455 &secp,
1456 pubkey_bytes,
1457 signature_bytes,
1458 &sighash,
1459 flags,
1460 height,
1461 network,
1462 SigVersion::Base,
1463 )
1464 };
1465
1466 let is_valid = match is_valid {
1467 Ok(v) => v,
1468 Err(e) => return Some(Err(e)),
1469 };
1470
1471 if is_valid {
1472 valid_sigs += 1;
1473 sig_index += 1;
1474 }
1475 }
1476
1477 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1478 for sig_bytes in &signatures[sig_index..] {
1479 if !sig_bytes.is_empty() {
1480 return Some(Err(ConsensusError::ScriptErrorWithCode {
1481 code: ScriptErrorCode::SigNullFail,
1482 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1483 .into(),
1484 }));
1485 }
1486 }
1487 }
1488
1489 Some(Ok(valid_sigs >= m))
1490}
1491
1492#[cfg(feature = "production")]
1496#[allow(clippy::too_many_arguments)]
1497fn try_verify_p2sh_fast_path(
1498 script_sig: &ByteString,
1499 script_pubkey: &[u8],
1500 flags: u32,
1501 tx: &Transaction,
1502 input_index: usize,
1503 prevout_values: &[i64],
1504 prevout_script_pubkeys: &[&[u8]],
1505 block_height: Option<u64>,
1506 median_time_past: Option<u64>,
1507 network: crate::types::Network,
1508 #[cfg(feature = "production")] sighash_cache: Option<
1509 &crate::transaction_hash::SighashMidstateCache,
1510 >,
1511 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1512) -> Option<Result<bool>> {
1513 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1514 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1515 return None;
1516 }
1517 if script_pubkey.len() != 23
1519 || script_pubkey[0] != OP_HASH160
1520 || script_pubkey[1] != PUSH_20_BYTES
1521 || script_pubkey[22] != OP_EQUAL
1522 {
1523 return None;
1524 }
1525 let expected_hash = &script_pubkey[2..22];
1526
1527 let mut pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1528 if pushes.is_empty() {
1529 return None;
1530 }
1531 let redeem = pushes.pop().expect("at least one push");
1532 let mut stack = pushes;
1533
1534 if redeem.len() >= 3
1536 && redeem[0] == OP_0
1537 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
1538 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
1539 {
1540 return None;
1541 }
1542
1543 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1545 let redeem_hash = Ripemd160::digest(sha256_hash);
1546 if &redeem_hash[..] != expected_hash {
1547 return Some(Ok(false));
1548 }
1549
1550 if redeem.len() == 25
1552 && redeem[0] == OP_DUP
1553 && redeem[1] == OP_HASH160
1554 && redeem[2] == PUSH_20_BYTES
1555 && redeem[23] == OP_EQUALVERIFY
1556 && redeem[24] == OP_CHECKSIG
1557 && stack.len() == 2
1558 {
1559 let signature_bytes = &stack[0];
1560 let pubkey_bytes = &stack[1];
1561 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1562 let expected_pubkey_hash = &redeem[3..23];
1563 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1564 let pubkey_hash = Ripemd160::digest(sha256_hash);
1565 if &pubkey_hash[..] == expected_pubkey_hash {
1566 #[cfg(feature = "production")]
1567 let sighash = if let Some(precomp) = precomputed_sighash_all {
1568 precomp
1569 } else {
1570 use crate::transaction_hash::{
1571 calculate_transaction_sighash_single_input, SighashType,
1572 };
1573 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1574 let sighash_type = SighashType::from_byte(sighash_byte);
1575 let deleted_storage;
1576 let script_code: &[u8] = if redeem.len() < 71 {
1577 redeem.as_ref()
1578 } else {
1579 let pattern = serialize_push_data(signature_bytes);
1580 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1581 deleted_storage.as_ref()
1582 };
1583 match calculate_transaction_sighash_single_input(
1584 tx,
1585 input_index,
1586 script_code,
1587 prevout_values[input_index],
1588 sighash_type,
1589 sighash_cache,
1590 ) {
1591 Ok(h) => h,
1592 Err(e) => return Some(Err(e)),
1593 }
1594 };
1595 #[cfg(not(feature = "production"))]
1596 let sighash = {
1597 use crate::transaction_hash::{
1598 calculate_transaction_sighash_single_input, SighashType,
1599 };
1600 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1601 let sighash_type = SighashType::from_byte(sighash_byte);
1602 let deleted_storage;
1603 let script_code: &[u8] = if redeem.len() < 71 {
1604 redeem.as_ref()
1605 } else {
1606 let pattern = serialize_push_data(signature_bytes);
1607 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1608 deleted_storage.as_ref()
1609 };
1610 match calculate_transaction_sighash_single_input(
1611 tx,
1612 input_index,
1613 script_code,
1614 prevout_values[input_index],
1615 sighash_type,
1616 ) {
1617 Ok(h) => h,
1618 Err(e) => return Some(Err(e)),
1619 }
1620 };
1621 let height = block_height.unwrap_or(0);
1622 let is_valid = signature::with_secp_context(|secp| {
1623 signature::verify_signature(
1624 secp,
1625 pubkey_bytes,
1626 signature_bytes,
1627 &sighash,
1628 flags,
1629 height,
1630 network,
1631 SigVersion::Base,
1632 )
1633 });
1634 return Some(is_valid);
1635 }
1636 }
1637 }
1638
1639 if (redeem.len() == 35 || redeem.len() == 67)
1641 && redeem[redeem.len() - 1] == OP_CHECKSIG
1642 && (redeem[0] == 0x21 || redeem[0] == 0x41)
1643 && stack.len() == 1
1644 {
1645 let pubkey_len = redeem.len() - 2;
1646 if pubkey_len == 33 || pubkey_len == 65 {
1647 let pubkey_bytes = &redeem.as_ref()[1..(redeem.len() - 1)];
1648 let signature_bytes = &stack[0];
1649 if !signature_bytes.is_empty() {
1650 use crate::transaction_hash::{
1651 calculate_transaction_sighash_single_input, SighashType,
1652 };
1653 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1654 let sighash_type = SighashType::from_byte(sighash_byte);
1655 let deleted_storage;
1657 let script_code: &[u8] = if redeem.len() < 71 {
1658 redeem.as_ref()
1659 } else {
1660 let pattern = serialize_push_data(signature_bytes);
1661 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1662 deleted_storage.as_ref()
1663 };
1664 match calculate_transaction_sighash_single_input(
1665 tx,
1666 input_index,
1667 script_code,
1668 prevout_values[input_index],
1669 sighash_type,
1670 #[cfg(feature = "production")]
1671 sighash_cache,
1672 ) {
1673 Ok(sighash) => {
1674 let height = block_height.unwrap_or(0);
1675 let is_valid = signature::with_secp_context(|secp| {
1676 signature::verify_signature(
1677 secp,
1678 pubkey_bytes,
1679 signature_bytes,
1680 &sighash,
1681 flags,
1682 height,
1683 network,
1684 SigVersion::Base,
1685 )
1686 });
1687 return Some(is_valid);
1688 }
1689 Err(e) => return Some(Err(e)),
1690 }
1691 }
1692 }
1693 }
1694
1695 let result = eval_script_with_context_full_inner(
1697 &redeem,
1698 &mut stack,
1699 flags,
1700 tx,
1701 input_index,
1702 prevout_values,
1703 prevout_script_pubkeys,
1704 block_height,
1705 median_time_past,
1706 network,
1707 SigVersion::Base,
1708 Some(redeem.as_ref()),
1709 None, #[cfg(feature = "production")]
1711 None, None, #[cfg(feature = "production")]
1714 sighash_cache,
1715 );
1716 Some(result)
1717}
1718
1719#[cfg(feature = "production")]
1722#[allow(clippy::too_many_arguments)]
1723fn try_verify_p2wpkh_fast_path(
1724 script_sig: &ByteString,
1725 script_pubkey: &[u8],
1726 witness: &crate::witness::Witness,
1727 flags: u32,
1728 tx: &Transaction,
1729 input_index: usize,
1730 prevout_values: &[i64],
1731 prevout_script_pubkeys: &[&[u8]],
1732 block_height: Option<u64>,
1733 network: crate::types::Network,
1734 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1735 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1736) -> Option<Result<bool>> {
1737 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
1739 return None;
1740 }
1741 if !script_sig.is_empty() {
1743 return None;
1744 }
1745 if witness.len() != 2 {
1746 return None;
1747 }
1748 let signature_bytes = &witness[0];
1749 let pubkey_bytes = &witness[1];
1750
1751 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1752 return Some(Ok(false));
1753 }
1754 if signature_bytes.is_empty() {
1755 return Some(Ok(false));
1756 }
1757
1758 let expected_hash = &script_pubkey[2..22];
1759 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1760 let pubkey_hash = Ripemd160::digest(sha256_hash);
1761 if &pubkey_hash[..] != expected_hash {
1762 return Some(Ok(false));
1763 }
1764
1765 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1766 let sighash = if sighash_byte == 0x01 {
1767 #[cfg(feature = "production")]
1769 if let Some(precomp) = precomputed_sighash_all {
1770 precomp
1771 } else {
1772 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1773 match crate::transaction_hash::calculate_bip143_sighash(
1774 tx,
1775 input_index,
1776 script_pubkey,
1777 amount,
1778 sighash_byte,
1779 precomputed_bip143,
1780 ) {
1781 Ok(h) => h,
1782 Err(e) => return Some(Err(e)),
1783 }
1784 }
1785 #[cfg(not(feature = "production"))]
1786 {
1787 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1788 match crate::transaction_hash::calculate_bip143_sighash(
1789 tx,
1790 input_index,
1791 script_pubkey,
1792 amount,
1793 sighash_byte,
1794 precomputed_bip143,
1795 ) {
1796 Ok(h) => h,
1797 Err(e) => return Some(Err(e)),
1798 }
1799 }
1800 } else {
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
1815 let height = block_height.unwrap_or(0);
1816 let is_valid = signature::with_secp_context(|secp| {
1817 signature::verify_signature(
1818 secp,
1819 pubkey_bytes,
1820 signature_bytes,
1821 &sighash,
1822 flags,
1823 height,
1824 network,
1825 SigVersion::WitnessV0,
1826 )
1827 });
1828 Some(is_valid)
1829}
1830
1831#[cfg(feature = "production")]
1833#[allow(clippy::too_many_arguments)]
1834fn try_verify_p2wpkh_in_p2sh_fast_path(
1835 script_sig: &ByteString,
1836 script_pubkey: &[u8],
1837 witness: &crate::witness::Witness,
1838 flags: u32,
1839 tx: &Transaction,
1840 input_index: usize,
1841 prevout_values: &[i64],
1842 prevout_script_pubkeys: &[&[u8]],
1843 block_height: Option<u64>,
1844 network: crate::types::Network,
1845 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1846) -> Option<Result<bool>> {
1847 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1848 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1849 return None;
1850 }
1851 if script_pubkey.len() != 23
1852 || script_pubkey[0] != OP_HASH160
1853 || script_pubkey[1] != PUSH_20_BYTES
1854 || script_pubkey[22] != OP_EQUAL
1855 {
1856 return None;
1857 }
1858 let expected_hash = &script_pubkey[2..22];
1859
1860 let pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1861 if pushes.len() != 1 {
1862 return None;
1863 }
1864 let redeem = &pushes[0];
1865 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
1866 return None;
1867 }
1868 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1869 let redeem_hash = Ripemd160::digest(sha256_hash);
1870 if &redeem_hash[..] != expected_hash {
1871 return Some(Ok(false));
1872 }
1873
1874 if witness.len() != 2 {
1875 return None;
1876 }
1877 let signature_bytes = &witness[0];
1878 let pubkey_bytes = &witness[1];
1879 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1880 return Some(Ok(false));
1881 }
1882 let expected_pubkey_hash = &redeem[2..22];
1883 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
1884 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
1885 if &pubkey_hash[..] != expected_pubkey_hash {
1886 return Some(Ok(false));
1887 }
1888
1889 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1890 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1891 let sighash = match crate::transaction_hash::calculate_bip143_sighash(
1892 tx,
1893 input_index,
1894 redeem.as_ref(),
1895 amount,
1896 sighash_byte,
1897 precomputed_bip143,
1898 ) {
1899 Ok(h) => h,
1900 Err(e) => return Some(Err(e)),
1901 };
1902
1903 let height = block_height.unwrap_or(0);
1904 let is_valid = signature::with_secp_context(|secp| {
1905 signature::verify_signature(
1906 secp,
1907 pubkey_bytes,
1908 signature_bytes,
1909 &sighash,
1910 flags,
1911 height,
1912 network,
1913 SigVersion::WitnessV0,
1914 )
1915 });
1916 Some(is_valid)
1917}
1918
1919#[cfg(feature = "production")]
1922#[allow(clippy::too_many_arguments)]
1923fn try_verify_p2wsh_fast_path(
1924 script_sig: &ByteString,
1925 script_pubkey: &[u8],
1926 witness: &crate::witness::Witness,
1927 flags: u32,
1928 tx: &Transaction,
1929 input_index: usize,
1930 prevout_values: &[i64],
1931 prevout_script_pubkeys: &[&[u8]],
1932 block_height: Option<u64>,
1933 median_time_past: Option<u64>,
1934 network: crate::types::Network,
1935 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
1936 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1937 #[cfg(feature = "production")] sighash_cache: Option<
1938 &crate::transaction_hash::SighashMidstateCache,
1939 >,
1940) -> Option<Result<bool>> {
1941 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
1943 return None;
1944 }
1945 if !script_sig.is_empty() {
1946 return None;
1947 }
1948 if witness.is_empty() {
1949 return None;
1950 }
1951 let witness_script = witness.last().expect("witness not empty").clone();
1952 let mut stack: Vec<StackElement> = witness
1953 .iter()
1954 .take(witness.len() - 1)
1955 .map(|w| to_stack_element(w))
1956 .collect();
1957
1958 let program_hash = &script_pubkey[2..34];
1959 if program_hash.len() != 32 {
1960 return None;
1961 }
1962 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
1963 if &witness_script_hash[..] != program_hash {
1964 return Some(Ok(false));
1965 }
1966
1967 let witness_sigversion = if flags & 0x8000 != 0 {
1968 SigVersion::Tapscript
1969 } else {
1970 SigVersion::WitnessV0
1971 };
1972
1973 if witness_sigversion == SigVersion::WitnessV0
1975 && witness_script.len() == 25
1976 && witness_script[0] == OP_DUP
1977 && witness_script[1] == OP_HASH160
1978 && witness_script[2] == PUSH_20_BYTES
1979 && witness_script[23] == OP_EQUALVERIFY
1980 && witness_script[24] == OP_CHECKSIG
1981 && stack.len() == 2
1982 {
1983 let signature_bytes = &stack[0];
1984 let pubkey_bytes = &stack[1];
1985 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1986 let expected_pubkey_hash = &witness_script[3..23];
1987 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
1988 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
1989 if &pubkey_hash[..] == expected_pubkey_hash {
1990 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1991 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1992 match crate::transaction_hash::calculate_bip143_sighash(
1993 tx,
1994 input_index,
1995 witness_script.as_ref(),
1996 amount,
1997 sighash_byte,
1998 precomputed_bip143,
1999 ) {
2000 Ok(sighash) => {
2001 let height = block_height.unwrap_or(0);
2002 let is_valid = signature::with_secp_context(|secp| {
2003 signature::verify_signature(
2004 secp,
2005 pubkey_bytes,
2006 signature_bytes,
2007 &sighash,
2008 flags,
2009 height,
2010 network,
2011 SigVersion::WitnessV0,
2012 )
2013 });
2014 return Some(is_valid);
2015 }
2016 Err(e) => return Some(Err(e)),
2017 }
2018 }
2019 }
2020 }
2021
2022 if witness_sigversion == SigVersion::WitnessV0
2024 && (witness_script.len() == 35 || witness_script.len() == 67)
2025 && witness_script[witness_script.len() - 1] == OP_CHECKSIG
2026 && (witness_script[0] == 0x21 || witness_script[0] == 0x41)
2027 && stack.len() == 1
2028 {
2029 let pubkey_len = witness_script.len() - 2;
2030 if (pubkey_len == 33 || pubkey_len == 65) && !stack[0].is_empty() {
2031 let pubkey_bytes = &witness_script[1..(witness_script.len() - 1)];
2032 let signature_bytes = &stack[0];
2033 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2034 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2035 match crate::transaction_hash::calculate_bip143_sighash(
2036 tx,
2037 input_index,
2038 witness_script.as_ref(),
2039 amount,
2040 sighash_byte,
2041 precomputed_bip143,
2042 ) {
2043 Ok(sighash) => {
2044 let height = block_height.unwrap_or(0);
2045 let is_valid = signature::with_secp_context(|secp| {
2046 signature::verify_signature(
2047 secp,
2048 pubkey_bytes,
2049 signature_bytes,
2050 &sighash,
2051 flags,
2052 height,
2053 network,
2054 SigVersion::WitnessV0,
2055 )
2056 });
2057 return Some(is_valid);
2058 }
2059 Err(e) => return Some(Err(e)),
2060 }
2061 }
2062 }
2063
2064 if witness_sigversion == SigVersion::WitnessV0 {
2066 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script.as_ref()) {
2067 if stack.len() < 2 {
2068 return Some(Ok(false));
2069 }
2070 let dummy = stack[0].as_ref();
2071 let signatures: Vec<&[u8]> = stack[1..].iter().map(|e| e.as_ref()).collect();
2072
2073 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
2074 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
2075 let height = block_height.unwrap_or(0);
2076 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
2077 let activation = match network {
2078 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
2079 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
2080 crate::types::Network::Regtest => 0,
2081 };
2082 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
2083 return Some(Ok(false));
2084 }
2085 }
2086
2087 let mut cleaned = witness_script.to_vec();
2088 for sig in &signatures {
2089 if !sig.is_empty() {
2090 let pattern = serialize_push_data(sig);
2091 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
2092 }
2093 }
2094
2095 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2096 let mut sig_index = 0;
2097 let mut valid_sigs = 0u8;
2098
2099 for pubkey_bytes in pubkeys {
2100 if sig_index >= signatures.len() {
2101 break;
2102 }
2103 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
2104 sig_index += 1;
2105 }
2106 if sig_index >= signatures.len() {
2107 break;
2108 }
2109 let signature_bytes = &signatures[sig_index];
2110 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2111 match crate::transaction_hash::calculate_bip143_sighash(
2112 tx,
2113 input_index,
2114 &cleaned,
2115 amount,
2116 sighash_byte,
2117 precomputed_bip143,
2118 ) {
2119 Ok(sighash) => {
2120 let is_valid = signature::with_secp_context(|secp| {
2121 signature::verify_signature(
2122 secp,
2123 pubkey_bytes,
2124 signature_bytes,
2125 &sighash,
2126 flags,
2127 height,
2128 network,
2129 SigVersion::WitnessV0,
2130 )
2131 });
2132 match is_valid {
2133 Ok(v) if v => {
2134 valid_sigs += 1;
2135 sig_index += 1;
2136 }
2137 Ok(_) => {}
2138 Err(e) => return Some(Err(e)),
2139 }
2140 }
2141 Err(e) => return Some(Err(e)),
2142 }
2143 }
2144
2145 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
2146 for sig_bytes in &signatures[sig_index..] {
2147 if !sig_bytes.is_empty() {
2148 return Some(Err(ConsensusError::ScriptErrorWithCode {
2149 code: ScriptErrorCode::SigNullFail,
2150 message:
2151 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
2152 .into(),
2153 }));
2154 }
2155 }
2156 }
2157
2158 return Some(Ok(valid_sigs >= m));
2159 }
2160 }
2161
2162 let result = eval_script_with_context_full_inner(
2165 &witness_script,
2166 &mut stack,
2167 flags,
2168 tx,
2169 input_index,
2170 prevout_values,
2171 prevout_script_pubkeys,
2172 block_height,
2173 median_time_past,
2174 network,
2175 witness_sigversion,
2176 None, None, schnorr_collector,
2179 precomputed_bip143,
2180 #[cfg(feature = "production")]
2181 sighash_cache,
2182 );
2183 Some(result)
2184}
2185
2186#[cfg(feature = "production")]
2188#[allow(clippy::too_many_arguments)]
2189fn try_verify_p2tr_scriptpath_p2pk_fast_path(
2190 script_sig: &ByteString,
2191 script_pubkey: &[u8],
2192 witness: &crate::witness::Witness,
2193 _flags: u32,
2194 tx: &Transaction,
2195 input_index: usize,
2196 prevout_values: &[i64],
2197 prevout_script_pubkeys: &[&[u8]],
2198 block_height: Option<u64>,
2199 network: crate::types::Network,
2200 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2201) -> Option<Result<bool>> {
2202 use crate::activation::taproot_activation_height;
2203 use crate::taproot::parse_taproot_script_path_witness;
2204
2205 let tap_h = taproot_activation_height(network);
2206 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2207 return None;
2208 }
2209 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2210 return None;
2211 }
2212 if !script_sig.is_empty() {
2213 return None;
2214 }
2215 if witness.len() < 2 {
2216 return None;
2217 }
2218 let mut output_key = [0u8; 32];
2219 output_key.copy_from_slice(&script_pubkey[2..34]);
2220 let parsed = match parse_taproot_script_path_witness(witness, &output_key) {
2221 Ok(Some(p)) => p,
2222 Ok(None) | Err(_) => return None,
2223 };
2224 let (tapscript, stack_items, control_block) = parsed;
2225 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
2226 return None;
2227 }
2228 if stack_items.len() != 1 || stack_items[0].len() != 64 {
2229 return None;
2230 }
2231 let sig = stack_items[0].as_ref();
2232 let pubkey_32 = &tapscript[1..33];
2233 let sighash = crate::taproot::compute_tapscript_signature_hash(
2234 tx,
2235 input_index,
2236 prevout_values,
2237 prevout_script_pubkeys,
2238 &tapscript,
2239 control_block.leaf_version,
2240 0xffff_ffff,
2241 0x00,
2242 )
2243 .ok()?;
2244 let result = crate::bip348::verify_tapscript_schnorr_signature(
2245 &sighash,
2246 pubkey_32,
2247 sig,
2248 schnorr_collector,
2249 );
2250 Some(result)
2251}
2252
2253#[cfg(feature = "production")]
2256#[allow(clippy::too_many_arguments)]
2257fn try_verify_p2tr_keypath_fast_path(
2258 script_sig: &ByteString,
2259 script_pubkey: &[u8],
2260 witness: &crate::witness::Witness,
2261 _flags: u32,
2262 tx: &Transaction,
2263 input_index: usize,
2264 prevout_values: &[i64],
2265 prevout_script_pubkeys: &[&[u8]],
2266 block_height: Option<u64>,
2267 network: crate::types::Network,
2268 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2269) -> Option<Result<bool>> {
2270 use crate::activation::taproot_activation_height;
2271 let tap_h = taproot_activation_height(network);
2272 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2273 return None;
2274 }
2275 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2277 return None;
2278 }
2279 if !script_sig.is_empty() {
2280 return None;
2281 }
2282 if witness.len() != 1 || witness[0].len() != 64 {
2284 return None;
2285 }
2286 let output_key = &script_pubkey[2..34];
2287 let sig = &witness[0];
2288 let sighash = crate::taproot::compute_taproot_signature_hash(
2289 tx,
2290 input_index,
2291 prevout_values,
2292 prevout_script_pubkeys,
2293 0x00, )
2295 .ok()?;
2296 let result = crate::bip348::verify_tapscript_schnorr_signature(
2297 &sighash,
2298 output_key,
2299 sig,
2300 schnorr_collector,
2301 );
2302 Some(result)
2303}
2304
2305#[spec_locked("5.2", "VerifyScript")]
2306pub fn verify_script_with_context_full(
2307 script_sig: &ByteString,
2308 script_pubkey: &[u8],
2309 witness: Option<&crate::witness::Witness>,
2310 flags: u32,
2311 tx: &Transaction,
2312 input_index: usize,
2313 prevout_values: &[i64],
2314 prevout_script_pubkeys: &[&[u8]],
2315 block_height: Option<u64>,
2316 median_time_past: Option<u64>,
2317 network: crate::types::Network,
2318 _sigversion: SigVersion,
2319 #[cfg(feature = "production")] schnorr_collector: Option<
2320 &crate::bip348::SchnorrSignatureCollector,
2321 >,
2322 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2323 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2324 #[cfg(feature = "production")] sighash_cache: Option<
2325 &crate::transaction_hash::SighashMidstateCache,
2326 >,
2327 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
2328) -> Result<bool> {
2329 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
2331 return Err(ConsensusError::ScriptErrorWithCode {
2332 code: ScriptErrorCode::TxInputInvalid,
2333 message: format!(
2334 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
2335 prevout_values.len(),
2336 prevout_script_pubkeys.len(),
2337 tx.inputs.len(),
2338 input_index,
2339 )
2340 .into(),
2341 });
2342 }
2343
2344 if input_index < prevout_values.len() {
2350 let prevout_value = prevout_values[input_index];
2351 if prevout_value < 0 {
2352 return Err(ConsensusError::ScriptErrorWithCode {
2353 code: ScriptErrorCode::ValueOverflow,
2354 message: "Prevout value cannot be negative".into(),
2355 });
2356 }
2357 #[cfg(feature = "production")]
2358 {
2359 use precomputed_constants::MAX_MONEY_U64;
2360 if (prevout_value as u64) > MAX_MONEY_U64 {
2361 return Err(ConsensusError::ScriptErrorWithCode {
2362 code: ScriptErrorCode::ValueOverflow,
2363 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2364 });
2365 }
2366 }
2367 #[cfg(not(feature = "production"))]
2368 {
2369 use crate::constants::MAX_MONEY;
2370 if prevout_value > MAX_MONEY {
2371 return Err(ConsensusError::ScriptErrorWithCode {
2372 code: ScriptErrorCode::ValueOverflow,
2373 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2374 });
2375 }
2376 }
2377 }
2378
2379 if input_index >= tx.inputs.len() {
2381 return Err(ConsensusError::ScriptErrorWithCode {
2382 code: ScriptErrorCode::TxInputInvalid,
2383 message: format!(
2384 "Input index {} out of bounds (tx has {} inputs)",
2385 input_index,
2386 tx.inputs.len()
2387 )
2388 .into(),
2389 });
2390 }
2391
2392 #[cfg(feature = "production")]
2394 if witness.is_none() {
2395 if let Some(result) = try_verify_p2pk_fast_path(
2396 script_sig,
2397 script_pubkey,
2398 flags,
2399 tx,
2400 input_index,
2401 prevout_values,
2402 prevout_script_pubkeys,
2403 block_height,
2404 network,
2405 #[cfg(feature = "production")]
2406 sighash_cache,
2407 ) {
2408 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
2409 return result;
2410 }
2411 if let Some(result) = try_verify_p2pkh_fast_path(
2412 script_sig,
2413 script_pubkey,
2414 flags,
2415 tx,
2416 input_index,
2417 prevout_values,
2418 prevout_script_pubkeys,
2419 block_height,
2420 network,
2421 #[cfg(feature = "production")]
2422 precomputed_sighash_all,
2423 #[cfg(feature = "production")]
2424 sighash_cache,
2425 #[cfg(feature = "production")]
2426 precomputed_p2pkh_hash,
2427 ) {
2428 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
2429 return result;
2430 }
2431 if let Some(result) = try_verify_p2sh_fast_path(
2432 script_sig,
2433 script_pubkey,
2434 flags,
2435 tx,
2436 input_index,
2437 prevout_values,
2438 prevout_script_pubkeys,
2439 block_height,
2440 median_time_past,
2441 network,
2442 #[cfg(feature = "production")]
2443 sighash_cache,
2444 #[cfg(feature = "production")]
2445 precomputed_sighash_all,
2446 ) {
2447 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
2448 return result;
2449 }
2450 if let Some(result) = try_verify_bare_multisig_fast_path(
2451 script_sig,
2452 script_pubkey,
2453 flags,
2454 tx,
2455 input_index,
2456 prevout_values,
2457 prevout_script_pubkeys,
2458 block_height,
2459 network,
2460 #[cfg(feature = "production")]
2461 sighash_cache,
2462 ) {
2463 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
2464 return result;
2465 }
2466 }
2467 #[cfg(feature = "production")]
2469 if let Some(wit) = witness {
2470 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
2471 script_sig,
2472 script_pubkey,
2473 wit,
2474 flags,
2475 tx,
2476 input_index,
2477 prevout_values,
2478 prevout_script_pubkeys,
2479 block_height,
2480 network,
2481 precomputed_bip143,
2482 ) {
2483 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2484 return result;
2485 }
2486 if let Some(result) = try_verify_p2wpkh_fast_path(
2487 script_sig,
2488 script_pubkey,
2489 wit,
2490 flags,
2491 tx,
2492 input_index,
2493 prevout_values,
2494 prevout_script_pubkeys,
2495 block_height,
2496 network,
2497 precomputed_bip143,
2498 precomputed_sighash_all,
2499 ) {
2500 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2501 return result;
2502 }
2503 if let Some(result) = try_verify_p2wsh_fast_path(
2504 script_sig,
2505 script_pubkey,
2506 wit,
2507 flags,
2508 tx,
2509 input_index,
2510 prevout_values,
2511 prevout_script_pubkeys,
2512 block_height,
2513 median_time_past,
2514 network,
2515 schnorr_collector,
2516 precomputed_bip143,
2517 #[cfg(feature = "production")]
2518 sighash_cache,
2519 ) {
2520 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
2521 return result;
2522 }
2523 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
2524 script_sig,
2525 script_pubkey,
2526 wit,
2527 flags,
2528 tx,
2529 input_index,
2530 prevout_values,
2531 prevout_script_pubkeys,
2532 block_height,
2533 network,
2534 schnorr_collector,
2535 ) {
2536 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2537 return result;
2538 }
2539 if let Some(result) = try_verify_p2tr_keypath_fast_path(
2540 script_sig,
2541 script_pubkey,
2542 wit,
2543 flags,
2544 tx,
2545 input_index,
2546 prevout_values,
2547 prevout_script_pubkeys,
2548 block_height,
2549 network,
2550 schnorr_collector,
2551 ) {
2552 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2553 return result;
2554 }
2555 }
2556 #[cfg(feature = "production")]
2557 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
2558
2559 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
2563 let is_p2sh = (flags & SCRIPT_VERIFY_P2SH) != 0
2564 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; if is_p2sh {
2575 let mut i = 0;
2576 while i < script_sig.len() {
2577 let opcode = script_sig[i];
2578 if !is_push_opcode(opcode) {
2579 return Ok(false);
2581 }
2582 if opcode == OP_0 {
2584 i += 1;
2586 } else if opcode <= 0x4b {
2587 let len = opcode as usize;
2589 if i + 1 + len > script_sig.len() {
2590 return Ok(false); }
2592 i += 1 + len;
2593 } else if opcode == OP_PUSHDATA1 {
2594 if i + 1 >= script_sig.len() {
2596 return Ok(false);
2597 }
2598 let len = script_sig[i + 1] as usize;
2599 if i + 2 + len > script_sig.len() {
2600 return Ok(false);
2601 }
2602 i += 2 + len;
2603 } else if opcode == OP_PUSHDATA2 {
2604 if i + 2 >= script_sig.len() {
2606 return Ok(false);
2607 }
2608 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
2609 if i + 3 + len > script_sig.len() {
2610 return Ok(false);
2611 }
2612 i += 3 + len;
2613 } else if opcode == OP_PUSHDATA4 {
2614 if i + 4 >= script_sig.len() {
2616 return Ok(false);
2617 }
2618 let len = u32::from_le_bytes([
2619 script_sig[i + 1],
2620 script_sig[i + 2],
2621 script_sig[i + 3],
2622 script_sig[i + 4],
2623 ]) as usize;
2624 if i + 5 + len > script_sig.len() {
2625 return Ok(false);
2626 }
2627 i += 5 + len;
2628 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
2629 i += 1;
2632 } else {
2633 return Ok(false);
2635 }
2636 }
2637 if let Some(result) = try_verify_p2sh_multisig_fast_path(
2638 script_sig,
2639 script_pubkey,
2640 flags,
2641 tx,
2642 input_index,
2643 prevout_values,
2644 prevout_script_pubkeys,
2645 block_height,
2646 network,
2647 #[cfg(feature = "production")]
2648 sighash_cache,
2649 ) {
2650 return result;
2651 }
2652 }
2653
2654 #[cfg(feature = "production")]
2655 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
2656 #[cfg(feature = "production")]
2657 let stack = &mut _stack_guard.0;
2658 #[cfg(not(feature = "production"))]
2659 let mut stack = Vec::with_capacity(20);
2660
2661 let script_sig_result = eval_script_with_context_full(
2665 script_sig,
2666 stack,
2667 flags,
2668 tx,
2669 input_index,
2670 prevout_values,
2671 prevout_script_pubkeys,
2672 block_height,
2673 median_time_past,
2674 network,
2675 SigVersion::Base,
2676 None, #[cfg(feature = "production")]
2678 schnorr_collector,
2679 None, #[cfg(feature = "production")]
2681 sighash_cache,
2682 )?;
2683 if !script_sig_result {
2684 return Ok(false);
2685 }
2686
2687 let redeem_script: Option<ByteString> = if is_p2sh && !stack.is_empty() {
2689 Some(stack.last().expect("Stack is not empty").as_ref().to_vec())
2690 } else {
2691 None
2692 };
2693
2694 use crate::activation::taproot_activation_height;
2698 let tap_h = taproot_activation_height(network);
2699 let is_taproot = redeem_script.is_none() && block_height.is_some() && block_height.unwrap() >= tap_h
2701 && script_pubkey.len() == 34
2702 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES; if is_taproot && !script_sig.is_empty() {
2707 return Ok(false); }
2709
2710 let is_direct_witness_program = redeem_script.is_none() && !is_taproot && script_pubkey.len() >= 3
2717 && 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;
2723 if is_direct_witness_program {
2724 if let Some(witness_stack) = witness {
2725 if script_pubkey[1] == PUSH_32_BYTES {
2726 if witness_stack.is_empty() {
2729 return Ok(false); }
2731
2732 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2734
2735 let program_bytes = &script_pubkey[2..];
2737 if program_bytes.len() != 32 {
2738 return Ok(false); }
2740
2741 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2742 if &witness_script_hash[..] != program_bytes {
2743 return Ok(false); }
2745
2746 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2748 stack.push(to_stack_element(element));
2749 }
2750
2751 witness_script_to_execute = Some(witness_script.clone());
2753 } else if script_pubkey[1] == PUSH_20_BYTES {
2754 if witness_stack.len() != 2 {
2757 return Ok(false); }
2759
2760 for element in witness_stack.iter() {
2761 stack.push(to_stack_element(element));
2762 }
2763 } else {
2764 return Ok(false); }
2766 } else {
2767 return Ok(false); }
2769 }
2770
2771 if is_taproot {
2772 let Some(witness_stack) = witness else {
2773 return Ok(false);
2774 };
2775 if witness_stack.len() < 2 {
2776 return Ok(false);
2777 }
2778 let mut output_key = [0u8; 32];
2779 output_key.copy_from_slice(&script_pubkey[2..34]);
2780 match crate::taproot::parse_taproot_script_path_witness(witness_stack, &output_key)? {
2781 None => return Ok(false),
2782 Some((tapscript, stack_items, _control_block)) => {
2783 for item in &stack_items {
2784 stack.push(to_stack_element(item));
2785 }
2786 let tapscript_flags = flags | 0x8000;
2787 if !eval_script_with_context_full(
2788 &tapscript,
2789 stack,
2790 tapscript_flags,
2791 tx,
2792 input_index,
2793 prevout_values,
2794 prevout_script_pubkeys,
2795 block_height,
2796 median_time_past,
2797 network,
2798 SigVersion::Tapscript,
2799 None,
2800 #[cfg(feature = "production")]
2801 schnorr_collector,
2802 None,
2803 #[cfg(feature = "production")]
2804 sighash_cache,
2805 )? {
2806 return Ok(false);
2807 }
2808 return Ok(true);
2809 }
2810 }
2811 }
2812
2813 let script_pubkey_result = eval_script_with_context_full(
2820 script_pubkey,
2821 stack,
2822 flags,
2823 tx,
2824 input_index,
2825 prevout_values,
2826 prevout_script_pubkeys,
2827 block_height,
2828 median_time_past,
2829 network,
2830 SigVersion::Base,
2831 Some(script_sig),
2832 #[cfg(feature = "production")]
2833 schnorr_collector,
2834 None, #[cfg(feature = "production")]
2836 sighash_cache,
2837 )?;
2838 if !script_pubkey_result {
2839 return Ok(false);
2840 }
2841
2842 if let Some(witness_script) = witness_script_to_execute {
2844 let witness_sigversion = if flags & 0x8000 != 0 {
2846 SigVersion::Tapscript
2847 } else {
2848 SigVersion::WitnessV0 };
2850
2851 if !eval_script_with_context_full(
2854 &witness_script,
2855 stack,
2856 flags,
2857 tx,
2858 input_index,
2859 prevout_values,
2860 prevout_script_pubkeys,
2861 block_height,
2862 median_time_past,
2863 network,
2864 witness_sigversion,
2865 None, #[cfg(feature = "production")]
2867 schnorr_collector,
2868 precomputed_bip143, #[cfg(feature = "production")]
2870 sighash_cache,
2871 )? {
2872 return Ok(false);
2873 }
2874 }
2875
2876 if let Some(redeem) = redeem_script {
2881 if stack.is_empty() {
2883 return Ok(false); }
2885
2886 let top = stack.last().expect("Stack is not empty");
2888 if !cast_to_bool(top) {
2889 return Ok(false); }
2891
2892 stack.pop();
2894
2895 let is_witness_program = redeem.len() >= 3
2900 && 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() {
2905 let program_bytes = &redeem[2..];
2914
2915 if redeem[1] == PUSH_32_BYTES {
2916 if program_bytes.len() != 32 {
2919 return Ok(false); }
2921
2922 if let Some(witness_stack) = witness {
2927 if witness_stack.is_empty() {
2928 return Ok(false); }
2930
2931 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2933 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2934 if &witness_script_hash[..] != program_bytes {
2935 return Ok(false); }
2937
2938 stack.clear();
2941
2942 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2945 stack.push(to_stack_element(element));
2946 }
2947
2948 let witness_sigversion = if flags & 0x8000 != 0 {
2950 SigVersion::Tapscript
2951 } else {
2952 SigVersion::WitnessV0 };
2954
2955 if !eval_script_with_context_full(
2957 witness_script,
2958 stack,
2959 flags,
2960 tx,
2961 input_index,
2962 prevout_values,
2963 prevout_script_pubkeys,
2964 block_height,
2965 median_time_past,
2966 network,
2967 witness_sigversion,
2968 None, #[cfg(feature = "production")]
2970 schnorr_collector,
2971 precomputed_bip143, #[cfg(feature = "production")]
2973 sighash_cache,
2974 )? {
2975 return Ok(false);
2976 }
2977 } else {
2978 return Ok(false); }
2980 } else if redeem[1] == PUSH_20_BYTES {
2981 stack.clear();
2985 } else {
2986 return Ok(false); }
2988 } else {
2990 let redeem_result = eval_script_with_context_full_inner(
2994 &redeem,
2995 stack,
2996 flags,
2997 tx,
2998 input_index,
2999 prevout_values,
3000 prevout_script_pubkeys,
3001 block_height,
3002 median_time_past,
3003 network,
3004 SigVersion::Base,
3005 Some(redeem.as_ref()), Some(script_sig), #[cfg(feature = "production")]
3008 None, None, #[cfg(feature = "production")]
3011 sighash_cache,
3012 )?;
3013 if !redeem_result {
3014 return Ok(false);
3015 }
3016 }
3017 }
3018
3019 assert!(
3021 stack.len() <= 1000,
3022 "Stack size {} exceeds reasonable maximum after scriptPubkey",
3023 stack.len()
3024 );
3025
3026 if let Some(_witness_stack) = witness {
3035 }
3039
3040 const SCRIPT_VERIFY_CLEANSTACK: u32 = 0x100;
3046
3047 let final_result = if (flags & SCRIPT_VERIFY_CLEANSTACK) != 0 {
3048 stack.len() == 1 && cast_to_bool(&stack[0])
3050 } else {
3051 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
3053 };
3054 Ok(final_result)
3055}
3056
3057#[allow(dead_code)]
3059fn eval_script_with_context(
3060 script: &ByteString,
3061 stack: &mut Vec<StackElement>,
3062 flags: u32,
3063 tx: &Transaction,
3064 input_index: usize,
3065 prevouts: &[TransactionOutput],
3066 network: crate::types::Network,
3067) -> Result<bool> {
3068 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
3070 let prevout_script_pubkeys: Vec<&[u8]> =
3071 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
3072 eval_script_with_context_full(
3073 script,
3074 stack,
3075 flags,
3076 tx,
3077 input_index,
3078 &prevout_values,
3079 &prevout_script_pubkeys,
3080 None, None, network,
3083 SigVersion::Base,
3084 None, #[cfg(feature = "production")]
3086 None, None, #[cfg(feature = "production")]
3089 None, )
3091}
3092
3093#[allow(clippy::too_many_arguments)]
3095fn eval_script_with_context_full(
3096 script: &[u8],
3097 stack: &mut Vec<StackElement>,
3098 flags: u32,
3099 tx: &Transaction,
3100 input_index: usize,
3101 prevout_values: &[i64],
3102 prevout_script_pubkeys: &[&[u8]],
3103 block_height: Option<u64>,
3104 median_time_past: Option<u64>,
3105 network: crate::types::Network,
3106 sigversion: SigVersion,
3107 script_sig_for_sighash: Option<&ByteString>,
3108 #[cfg(feature = "production")] schnorr_collector: Option<
3109 &crate::bip348::SchnorrSignatureCollector,
3110 >,
3111 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3112 #[cfg(feature = "production")] sighash_cache: Option<
3113 &crate::transaction_hash::SighashMidstateCache,
3114 >,
3115) -> Result<bool> {
3116 #[cfg(all(feature = "production", feature = "profile"))]
3117 let _t0 = std::time::Instant::now();
3118 let r = eval_script_with_context_full_inner(
3119 script,
3120 stack,
3121 flags,
3122 tx,
3123 input_index,
3124 prevout_values,
3125 prevout_script_pubkeys,
3126 block_height,
3127 median_time_past,
3128 network,
3129 sigversion,
3130 None,
3131 script_sig_for_sighash,
3132 #[cfg(feature = "production")]
3133 schnorr_collector,
3134 precomputed_bip143,
3135 #[cfg(feature = "production")]
3136 sighash_cache,
3137 );
3138 #[cfg(all(feature = "production", feature = "profile"))]
3139 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
3140 r
3141}
3142
3143fn eval_script_with_context_full_inner(
3145 script: &[u8],
3146 stack: &mut Vec<StackElement>,
3147 flags: u32,
3148 tx: &Transaction,
3149 input_index: usize,
3150 prevout_values: &[i64],
3151 prevout_script_pubkeys: &[&[u8]],
3152 block_height: Option<u64>,
3153 median_time_past: Option<u64>,
3154 network: crate::types::Network,
3155 sigversion: SigVersion,
3156 redeem_script_for_sighash: Option<&[u8]>,
3157 script_sig_for_sighash: Option<&ByteString>,
3158 #[cfg(feature = "production")] schnorr_collector: Option<
3159 &crate::bip348::SchnorrSignatureCollector,
3160 >,
3161 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3162 #[cfg(feature = "production")] sighash_cache: Option<
3163 &crate::transaction_hash::SighashMidstateCache,
3164 >,
3165) -> Result<bool> {
3166 assert!(
3169 script.len() <= 10000,
3170 "Script length {} exceeds reasonable maximum",
3171 script.len()
3172 );
3173 assert!(
3174 stack.len() <= 1000,
3175 "Stack size {} exceeds reasonable maximum at start",
3176 stack.len()
3177 );
3178
3179 use crate::error::{ConsensusError, ScriptErrorCode};
3180
3181 if stack.capacity() < 20 {
3183 stack.reserve(20);
3184 }
3185 let mut op_count = 0;
3186 assert!(op_count == 0, "Op count must start at zero");
3188
3189 #[cfg(feature = "production")]
3191 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
3192 #[cfg(not(feature = "production"))]
3193 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
3194 assert!(control_stack.is_empty(), "Control stack must start empty");
3196
3197 #[cfg(feature = "production")]
3198 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
3199 #[cfg(not(feature = "production"))]
3200 let mut altstack: Vec<StackElement> = Vec::new();
3201
3202 let mut code_separator_pos: usize = 0;
3206 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
3207
3208 let mut i = 0;
3210 while i < script.len() {
3211 #[cfg(feature = "production")]
3212 {
3213 prefetch::prefetch_ahead(script, i, 64); }
3216 let opcode = {
3218 #[cfg(feature = "production")]
3219 {
3220 unsafe { *script.get_unchecked(i) }
3221 }
3222 #[cfg(not(feature = "production"))]
3223 {
3224 script[i]
3225 }
3226 };
3227
3228 let in_false_branch = control_flow::in_false_branch(&control_stack);
3230
3231 if !is_push_opcode(opcode) {
3233 op_count += 1;
3234 assert!(
3236 op_count <= MAX_SCRIPT_OPS + 1,
3237 "Op count {op_count} must not exceed MAX_SCRIPT_OPS + 1"
3238 );
3239 if op_count > MAX_SCRIPT_OPS {
3240 return Err(make_operation_limit_error());
3241 }
3242 }
3243
3244 if stack.len() + altstack.len() > MAX_STACK_SIZE {
3246 return Err(make_stack_overflow_error());
3247 }
3248
3249 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
3251 let (data, advance) = if opcode <= 0x4b {
3252 let len = opcode as usize;
3254 if i + 1 + len > script.len() {
3255 return Ok(false); }
3257 (&script[i + 1..i + 1 + len], 1 + len)
3258 } else if opcode == OP_PUSHDATA1 {
3259 if i + 1 >= script.len() {
3261 return Ok(false);
3262 }
3263 let len = script[i + 1] as usize;
3264 if i + 2 + len > script.len() {
3265 return Ok(false);
3266 }
3267 (&script[i + 2..i + 2 + len], 2 + len)
3268 } else if opcode == OP_PUSHDATA2 {
3269 if i + 2 >= script.len() {
3271 return Ok(false);
3272 }
3273 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
3274 if i + 3 + len > script.len() {
3275 return Ok(false);
3276 }
3277 (&script[i + 3..i + 3 + len], 3 + len)
3278 } else {
3279 if i + 4 >= script.len() {
3282 return Ok(false);
3283 }
3284 let len = u32::from_le_bytes([
3285 script[i + 1],
3286 script[i + 2],
3287 script[i + 3],
3288 script[i + 4],
3289 ]) as usize;
3290 let data_start = i.saturating_add(5);
3291 let data_end = data_start.saturating_add(len);
3292 let advance = 5usize.saturating_add(len);
3293 if advance < 5 || data_end > script.len() || data_end < data_start {
3294 return Ok(false); }
3296 (&script[data_start..data_end], advance)
3297 };
3298
3299 if !in_false_branch {
3301 stack.push(to_stack_element(data));
3302 }
3303 i += advance;
3304 continue;
3305 }
3306
3307 if opcode == OP_DUP {
3313 if !in_false_branch {
3314 if stack.is_empty() {
3315 return Err(ConsensusError::ScriptErrorWithCode {
3316 code: ScriptErrorCode::InvalidStackOperation,
3317 message: "OP_DUP: empty stack".into(),
3318 });
3319 }
3320 let len = stack.len();
3323 #[cfg(feature = "production")]
3324 {
3325 if stack.capacity() == stack.len() {
3327 stack.reserve(1);
3328 }
3329 let item = unsafe { stack.get_unchecked(len - 1).clone() };
3331 stack.push(item);
3332 }
3333 #[cfg(not(feature = "production"))]
3334 {
3335 let item = stack.last().unwrap();
3336 stack.push(item.clone());
3337 }
3338 }
3339 i += 1;
3340 continue;
3341 }
3342
3343 if opcode == OP_EQUALVERIFY {
3345 if !in_false_branch {
3346 if stack.len() < 2 {
3347 return Err(ConsensusError::ScriptErrorWithCode {
3348 code: ScriptErrorCode::InvalidStackOperation,
3349 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3350 });
3351 }
3352 let a = stack.pop().unwrap();
3353 let b = stack.pop().unwrap();
3354 if a != b {
3355 return Ok(false);
3356 }
3357 }
3358 i += 1;
3359 continue;
3360 }
3361
3362 if opcode == OP_HASH160 {
3364 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
3365 return Ok(false);
3366 }
3367 i += 1;
3368 continue;
3369 }
3370
3371 if opcode == OP_VERIFY {
3373 if !in_false_branch {
3374 if let Some(item) = stack.pop() {
3375 if !cast_to_bool(&item) {
3376 return Ok(false);
3377 }
3378 } else {
3379 return Ok(false);
3380 }
3381 }
3382 i += 1;
3383 continue;
3384 }
3385
3386 if opcode == OP_EQUAL {
3388 if !in_false_branch {
3389 if stack.len() < 2 {
3390 return Err(ConsensusError::ScriptErrorWithCode {
3391 code: ScriptErrorCode::InvalidStackOperation,
3392 message: "OP_EQUAL: insufficient stack items".into(),
3393 });
3394 }
3395 let a = stack.pop().unwrap();
3396 let b = stack.pop().unwrap();
3397 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3398 }
3399 i += 1;
3400 continue;
3401 }
3402
3403 if opcode == OP_CHECKSIG
3406 || opcode == OP_CHECKSIGVERIFY
3407 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
3408 {
3409 if !in_false_branch {
3410 let effective_script_code = Some(&script[code_separator_pos..]);
3411 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3412 (Some(script), Some(last_codesep_opcode_pos))
3413 } else {
3414 (None, None)
3415 };
3416 let ctx = context::ScriptContext {
3417 tx,
3418 input_index,
3419 prevout_values,
3420 prevout_script_pubkeys,
3421 block_height,
3422 median_time_past,
3423 network,
3424 sigversion,
3425 redeem_script_for_sighash,
3426 script_sig_for_sighash,
3427 tapscript_for_sighash: tapscript,
3428 tapscript_codesep_pos: codesep,
3429 #[cfg(feature = "production")]
3430 schnorr_collector,
3431 #[cfg(feature = "production")]
3432 precomputed_bip143,
3433 #[cfg(feature = "production")]
3434 sighash_cache,
3435 };
3436 if !execute_opcode_with_context_full(
3437 opcode,
3438 stack,
3439 flags,
3440 &ctx,
3441 effective_script_code,
3442 )? {
3443 return Ok(false);
3444 }
3445 }
3446 i += 1;
3447 continue;
3448 }
3449
3450 match opcode {
3451 OP_0 => {
3453 if !in_false_branch {
3454 stack.push(to_stack_element(&[]));
3455 }
3456 }
3457
3458 OP_1_RANGE_START..=OP_1_RANGE_END => {
3460 if !in_false_branch {
3461 let num = opcode - OP_N_BASE;
3462 stack.push(to_stack_element(&[num]));
3463 }
3464 }
3465
3466 OP_1NEGATE => {
3468 if !in_false_branch {
3469 stack.push(to_stack_element(&[0x81])); }
3471 }
3472
3473 OP_NOP => {
3475 }
3477
3478 OP_VER => {
3483 if !in_false_branch {
3484 return Err(ConsensusError::ScriptErrorWithCode {
3485 code: ScriptErrorCode::DisabledOpcode,
3486 message: "OP_VER is disabled".into(),
3487 });
3488 }
3489 }
3490
3491 OP_IF => {
3492 if in_false_branch {
3494 control_stack.push(control_flow::ControlBlock::If { executing: false });
3495 i += 1;
3496 continue;
3497 }
3498
3499 if stack.is_empty() {
3500 return Err(ConsensusError::ScriptErrorWithCode {
3501 code: ScriptErrorCode::InvalidStackOperation,
3502 message: "OP_IF: empty stack".into(),
3503 });
3504 }
3505 let condition_bytes = stack.pop().unwrap();
3506 let condition = cast_to_bool(&condition_bytes);
3507
3508 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3509 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3510 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3511 && !control_flow::is_minimal_if_condition(&condition_bytes)
3512 {
3513 return Err(ConsensusError::ScriptErrorWithCode {
3514 code: ScriptErrorCode::MinimalIf,
3515 message: "OP_IF condition must be minimally encoded".into(),
3516 });
3517 }
3518
3519 control_stack.push(control_flow::ControlBlock::If {
3520 executing: condition,
3521 });
3522 }
3523 OP_NOTIF => {
3524 if in_false_branch {
3526 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
3527 i += 1;
3528 continue;
3529 }
3530
3531 if stack.is_empty() {
3532 return Err(ConsensusError::ScriptErrorWithCode {
3533 code: ScriptErrorCode::InvalidStackOperation,
3534 message: "OP_NOTIF: empty stack".into(),
3535 });
3536 }
3537 let condition_bytes = stack.pop().unwrap();
3538 let condition = cast_to_bool(&condition_bytes);
3539
3540 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3541 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3542 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3543 && !control_flow::is_minimal_if_condition(&condition_bytes)
3544 {
3545 return Err(ConsensusError::ScriptErrorWithCode {
3546 code: ScriptErrorCode::MinimalIf,
3547 message: "OP_NOTIF condition must be minimally encoded".into(),
3548 });
3549 }
3550
3551 control_stack.push(control_flow::ControlBlock::NotIf {
3552 executing: !condition,
3553 });
3554 }
3555 OP_ELSE => {
3556 if let Some(block) = control_stack.last_mut() {
3558 match block {
3559 control_flow::ControlBlock::If { executing }
3560 | control_flow::ControlBlock::NotIf { executing } => {
3561 *executing = !*executing;
3562 }
3563 }
3564 } else {
3565 return Err(ConsensusError::ScriptErrorWithCode {
3566 code: ScriptErrorCode::UnbalancedConditional,
3567 message: "OP_ELSE without matching IF/NOTIF".into(),
3568 });
3569 }
3570 }
3571 OP_ENDIF => {
3572 if control_stack.pop().is_none() {
3574 return Err(ConsensusError::ScriptErrorWithCode {
3575 code: ScriptErrorCode::UnbalancedConditional,
3576 message: "OP_ENDIF without matching IF/NOTIF".into(),
3577 });
3578 }
3579 }
3580
3581 OP_TOALTSTACK => {
3586 if in_false_branch {
3587 i += 1;
3588 continue;
3589 }
3590 if stack.is_empty() {
3591 return Err(ConsensusError::ScriptErrorWithCode {
3592 code: ScriptErrorCode::InvalidStackOperation,
3593 message: "OP_TOALTSTACK: empty stack".into(),
3594 });
3595 }
3596 altstack.push(stack.pop().unwrap());
3597 }
3598 OP_FROMALTSTACK => {
3600 if in_false_branch {
3601 i += 1;
3602 continue;
3603 }
3604 if altstack.is_empty() {
3605 return Err(ConsensusError::ScriptErrorWithCode {
3606 code: ScriptErrorCode::InvalidAltstackOperation,
3607 message: "OP_FROMALTSTACK: empty altstack".into(),
3608 });
3609 }
3610 stack.push(altstack.pop().unwrap());
3611 }
3612 OP_CODESEPARATOR => {
3614 if in_false_branch {
3615 i += 1;
3616 continue;
3617 }
3618 code_separator_pos = i + 1;
3619 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
3620 }
3621 _ => {
3622 if in_false_branch {
3623 i += 1;
3624 continue;
3625 }
3626
3627 let subscript_for_sighash = if matches!(
3632 opcode,
3633 OP_CHECKSIG
3634 | OP_CHECKSIGVERIFY
3635 | OP_CHECKSIGADD
3636 | OP_CHECKMULTISIG
3637 | OP_CHECKMULTISIGVERIFY
3638 ) {
3639 Some(&script[code_separator_pos..])
3640 } else {
3641 None
3642 };
3643 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
3644 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3645 (Some(script), Some(last_codesep_opcode_pos))
3646 } else {
3647 (None, None)
3648 };
3649 let ctx = context::ScriptContext {
3650 tx,
3651 input_index,
3652 prevout_values,
3653 prevout_script_pubkeys,
3654 block_height,
3655 median_time_past,
3656 network,
3657 sigversion,
3658 redeem_script_for_sighash,
3659 script_sig_for_sighash,
3660 tapscript_for_sighash: tapscript,
3661 tapscript_codesep_pos: codesep,
3662 #[cfg(feature = "production")]
3663 schnorr_collector,
3664 #[cfg(feature = "production")]
3665 precomputed_bip143,
3666 #[cfg(feature = "production")]
3667 sighash_cache,
3668 };
3669 if !execute_opcode_with_context_full(
3670 opcode,
3671 stack,
3672 flags,
3673 &ctx,
3674 effective_script_code,
3675 )? {
3676 return Ok(false);
3677 }
3678 }
3679 }
3680 i += 1;
3681 }
3682
3683 if !control_stack.is_empty() {
3685 return Err(ConsensusError::ScriptErrorWithCode {
3686 code: ScriptErrorCode::UnbalancedConditional,
3687 message: "Unclosed IF/NOTIF block".into(),
3688 });
3689 }
3690
3691 Ok(true)
3695}
3696
3697#[spec_locked("5.4.5", "DecodeCScriptNum")]
3701#[cfg(feature = "production")]
3702#[inline(always)]
3703pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3704 if data.len() > max_num_size {
3705 return Err(ConsensusError::ScriptErrorWithCode {
3706 code: ScriptErrorCode::InvalidStackOperation,
3707 message: format!(
3708 "Script number overflow: {} > {} bytes",
3709 data.len(),
3710 max_num_size
3711 )
3712 .into(),
3713 });
3714 }
3715 if data.is_empty() {
3716 return Ok(0);
3717 }
3718
3719 let len = data.len();
3721 let result = match len {
3722 1 => {
3723 let byte = data[0];
3724 if byte & 0x80 != 0 {
3725 -((byte & 0x7f) as i64)
3727 } else {
3728 byte as i64
3729 }
3730 }
3731 2 => {
3732 let byte0 = data[0] as i64;
3733 let byte1 = data[1] as i64;
3734 let value = byte0 | (byte1 << 8);
3735 if byte1 & 0x80 != 0 {
3736 -(value & !(0x80i64 << 8))
3738 } else {
3739 value
3740 }
3741 }
3742 _ => {
3743 let mut result: i64 = 0;
3745 for (i, &byte) in data.iter().enumerate() {
3746 result |= (byte as i64) << (8 * i);
3747 }
3748 let last_idx = len - 1;
3750 if data[last_idx] & 0x80 != 0 {
3751 result &= !(0x80i64 << (8 * last_idx));
3753 result = -result;
3754 }
3755 result
3756 }
3757 };
3758
3759 Ok(result)
3760}
3761
3762#[cfg(not(feature = "production"))]
3763#[inline]
3764pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3765 if data.len() > max_num_size {
3766 return Err(ConsensusError::ScriptErrorWithCode {
3767 code: ScriptErrorCode::InvalidStackOperation,
3768 message: format!(
3769 "Script number overflow: {} > {} bytes",
3770 data.len(),
3771 max_num_size
3772 )
3773 .into(),
3774 });
3775 }
3776 if data.is_empty() {
3777 return Ok(0);
3778 }
3779 let mut result: i64 = 0;
3781 for (i, &byte) in data.iter().enumerate() {
3782 result |= (byte as i64) << (8 * i);
3783 }
3784 if data.last().expect("Data is not empty") & 0x80 != 0 {
3786 result &= !(0x80i64 << (8 * (data.len() - 1)));
3788 result = -result;
3789 }
3790 Ok(result)
3791}
3792
3793#[cfg(feature = "production")]
3796pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3797 match value {
3799 0 => return vec![],
3800 1 => return vec![1],
3801 -1 => return vec![0x81],
3802 _ => {}
3803 }
3804
3805 let neg = value < 0;
3806 let mut absvalue = if neg {
3807 (-(value as i128)) as u64
3808 } else {
3809 value as u64
3810 };
3811 let mut result = Vec::with_capacity(4);
3813 while absvalue > 0 {
3814 result.push((absvalue & 0xff) as u8);
3815 absvalue >>= 8;
3816 }
3817 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3819 result.push(if neg { 0x80 } else { 0x00 });
3820 } else if neg {
3821 *result.last_mut().unwrap() |= 0x80;
3822 }
3823 result
3824}
3825
3826#[cfg(not(feature = "production"))]
3827pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3828 if value == 0 {
3829 return vec![];
3830 }
3831 let neg = value < 0;
3832 let mut absvalue = if neg {
3833 (-(value as i128)) as u64
3834 } else {
3835 value as u64
3836 };
3837 let mut result = Vec::new();
3838 while absvalue > 0 {
3839 result.push((absvalue & 0xff) as u8);
3840 absvalue >>= 8;
3841 }
3842 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3844 result.push(if neg { 0x80 } else { 0x00 });
3845 } else if neg {
3846 *result.last_mut().unwrap() |= 0x80;
3847 }
3848 result
3849}
3850
3851#[cfg(feature = "production")]
3853#[inline(always)]
3854fn execute_opcode(
3855 opcode: u8,
3856 stack: &mut Vec<StackElement>,
3857 flags: u32,
3858 _sigversion: SigVersion,
3859) -> Result<bool> {
3860 match opcode {
3861 OP_0 => {
3863 stack.push(to_stack_element(&[]));
3864 Ok(true)
3865 }
3866
3867 OP_1..=OP_16 => {
3869 let num = opcode - OP_N_BASE;
3870 stack.push(to_stack_element(&[num]));
3871 Ok(true)
3872 }
3873
3874 OP_NOP => Ok(true),
3876
3877 OP_VER => Ok(false),
3879
3880 OP_DEPTH => {
3882 let depth = stack.len() as i64;
3883 stack.push(to_stack_element(&script_num_encode(depth)));
3884 Ok(true)
3885 }
3886
3887 OP_DUP => {
3889 if let Some(item) = stack.last().cloned() {
3890 stack.push(item);
3891 Ok(true)
3892 } else {
3893 Ok(false)
3894 }
3895 }
3896
3897 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
3899
3900 OP_SHA1 => crypto_ops::op_sha1(stack),
3902
3903 OP_SHA256 => crypto_ops::op_sha256(stack),
3905
3906 OP_HASH160 => crypto_ops::op_hash160(stack),
3908
3909 OP_HASH256 => crypto_ops::op_hash256(stack),
3911
3912 OP_EQUAL => {
3914 if stack.len() < 2 {
3915 return Err(ConsensusError::ScriptErrorWithCode {
3916 code: ScriptErrorCode::InvalidStackOperation,
3917 message: "OP_EQUAL: insufficient stack items".into(),
3918 });
3919 }
3920 let a = stack.pop().unwrap();
3921 let b = stack.pop().unwrap();
3922 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3923 Ok(true)
3924 }
3925
3926 OP_EQUALVERIFY => {
3929 if stack.len() < 2 {
3930 return Err(ConsensusError::ScriptErrorWithCode {
3931 code: ScriptErrorCode::InvalidStackOperation,
3932 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3933 });
3934 }
3935 let a = stack.pop().unwrap();
3936 let b = stack.pop().unwrap();
3937 let f_equal = a == b;
3938 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
3940 if f_equal {
3941 stack.pop();
3943 Ok(true)
3944 } else {
3945 Err(ConsensusError::ScriptErrorWithCode {
3946 code: ScriptErrorCode::EqualVerify,
3947 message: "OP_EQUALVERIFY: stack items not equal".into(),
3948 })
3949 }
3950 }
3951
3952 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
3954
3955 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
3957
3958 OP_RETURN => Ok(false),
3960
3961 OP_VERIFY => {
3963 if let Some(item) = stack.pop() {
3964 Ok(cast_to_bool(&item))
3965 } else {
3966 Ok(false)
3967 }
3968 }
3969
3970 OP_CHECKLOCKTIMEVERIFY => {
3974 Ok(false)
3977 }
3978
3979 OP_CHECKSEQUENCEVERIFY => {
3983 Ok(false)
3986 }
3987
3988 OP_IFDUP => {
3990 if let Some(item) = stack.last().cloned() {
3991 if cast_to_bool(&item) {
3992 stack.push(item);
3993 }
3994 Ok(true)
3995 } else {
3996 Ok(false)
3997 }
3998 }
3999
4000 OP_DROP => {
4003 if stack.pop().is_some() {
4004 Ok(true)
4005 } else {
4006 Ok(false)
4007 }
4008 }
4009
4010 OP_NIP => {
4012 if stack.len() >= 2 {
4013 let top = stack.pop().unwrap();
4014 stack.pop(); stack.push(top);
4016 Ok(true)
4017 } else {
4018 Ok(false)
4019 }
4020 }
4021
4022 OP_OVER => {
4024 if stack.len() >= 2 {
4025 let len = stack.len();
4026 #[cfg(feature = "production")]
4027 {
4028 unsafe {
4030 let second = stack.get_unchecked(len - 2);
4031 stack.push(second.clone());
4032 }
4033 }
4034 #[cfg(not(feature = "production"))]
4035 {
4036 let second = stack[stack.len() - 2].clone();
4037 stack.push(second);
4038 }
4039 Ok(true)
4040 } else {
4041 Ok(false)
4042 }
4043 }
4044
4045 OP_PICK => {
4047 if let Some(n_bytes) = stack.pop() {
4048 let n_val = script_num_decode(&n_bytes, 4)?;
4051 if n_val < 0 || n_val as usize >= stack.len() {
4052 return Ok(false);
4053 }
4054 let n = n_val as usize;
4055 let len = stack.len();
4056 #[cfg(feature = "production")]
4057 {
4058 unsafe {
4060 let item = stack.get_unchecked(len - 1 - n);
4061 stack.push(item.clone());
4062 }
4063 }
4064 #[cfg(not(feature = "production"))]
4065 {
4066 let item = stack[stack.len() - 1 - n].clone();
4067 stack.push(item);
4068 }
4069 Ok(true)
4070 } else {
4071 Ok(false)
4072 }
4073 }
4074
4075 OP_ROLL => {
4077 if let Some(n_bytes) = stack.pop() {
4078 let n_val = script_num_decode(&n_bytes, 4)?;
4081 if n_val < 0 || n_val as usize >= stack.len() {
4082 return Ok(false);
4083 }
4084 let n = n_val as usize;
4085 let len = stack.len();
4086 #[cfg(feature = "production")]
4087 {
4088 let idx = len - 1 - n;
4090 let item = stack.remove(idx);
4091 stack.push(item);
4092 }
4093 #[cfg(not(feature = "production"))]
4094 {
4095 let item = stack.remove(stack.len() - 1 - n);
4096 stack.push(item);
4097 }
4098 Ok(true)
4099 } else {
4100 Ok(false)
4101 }
4102 }
4103
4104 OP_ROT => {
4106 if stack.len() >= 3 {
4107 let top = stack.pop().unwrap();
4108 let second = stack.pop().unwrap();
4109 let third = stack.pop().unwrap();
4110 stack.push(second);
4111 stack.push(top);
4112 stack.push(third);
4113 Ok(true)
4114 } else {
4115 Ok(false)
4116 }
4117 }
4118
4119 OP_SWAP => {
4121 if stack.len() >= 2 {
4122 let top = stack.pop().unwrap();
4123 let second = stack.pop().unwrap();
4124 stack.push(top);
4125 stack.push(second);
4126 Ok(true)
4127 } else {
4128 Ok(false)
4129 }
4130 }
4131
4132 OP_TUCK => {
4134 if stack.len() >= 2 {
4135 let top = stack.pop().unwrap();
4136 let second = stack.pop().unwrap();
4137 stack.push(top.clone());
4138 stack.push(second);
4139 stack.push(top);
4140 Ok(true)
4141 } else {
4142 Ok(false)
4143 }
4144 }
4145
4146 OP_2DROP => {
4148 if stack.len() >= 2 {
4149 stack.pop();
4150 stack.pop();
4151 Ok(true)
4152 } else {
4153 Ok(false)
4154 }
4155 }
4156
4157 OP_2DUP => {
4159 if stack.len() >= 2 {
4160 let top = stack[stack.len() - 1].clone();
4161 let second = stack[stack.len() - 2].clone();
4162 stack.push(second);
4163 stack.push(top);
4164 Ok(true)
4165 } else {
4166 Ok(false)
4167 }
4168 }
4169
4170 OP_3DUP => {
4172 if stack.len() >= 3 {
4173 let top = stack[stack.len() - 1].clone();
4174 let second = stack[stack.len() - 2].clone();
4175 let third = stack[stack.len() - 3].clone();
4176 stack.push(third);
4177 stack.push(second);
4178 stack.push(top);
4179 Ok(true)
4180 } else {
4181 Ok(false)
4182 }
4183 }
4184
4185 OP_2OVER => {
4187 if stack.len() >= 4 {
4188 let fourth = stack[stack.len() - 4].clone();
4189 let third = stack[stack.len() - 3].clone();
4190 stack.push(fourth);
4191 stack.push(third);
4192 Ok(true)
4193 } else {
4194 Ok(false)
4195 }
4196 }
4197
4198 OP_2ROT => {
4200 if stack.len() >= 6 {
4201 let sixth = stack.remove(stack.len() - 6);
4202 let fifth = stack.remove(stack.len() - 5);
4203 stack.push(fifth);
4204 stack.push(sixth);
4205 Ok(true)
4206 } else {
4207 Ok(false)
4208 }
4209 }
4210
4211 OP_2SWAP => {
4213 if stack.len() >= 4 {
4214 let top = stack.pop().unwrap();
4215 let second = stack.pop().unwrap();
4216 let third = stack.pop().unwrap();
4217 let fourth = stack.pop().unwrap();
4218 stack.push(second);
4219 stack.push(top);
4220 stack.push(fourth);
4221 stack.push(third);
4222 Ok(true)
4223 } else {
4224 Ok(false)
4225 }
4226 }
4227
4228 OP_SIZE => {
4231 if let Some(item) = stack.last() {
4232 let size = item.len() as i64;
4233 stack.push(to_stack_element(&script_num_encode(size)));
4234 Ok(true)
4235 } else {
4236 Ok(false)
4237 }
4238 }
4239
4240 OP_1ADD => {
4245 if let Some(item) = stack.pop() {
4246 let a = script_num_decode(&item, 4)?;
4247 stack.push(to_stack_element(&script_num_encode(a + 1)));
4248 Ok(true)
4249 } else {
4250 Ok(false)
4251 }
4252 }
4253 OP_1SUB => {
4255 if let Some(item) = stack.pop() {
4256 let a = script_num_decode(&item, 4)?;
4257 stack.push(to_stack_element(&script_num_encode(a - 1)));
4258 Ok(true)
4259 } else {
4260 Ok(false)
4261 }
4262 }
4263 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4265 code: ScriptErrorCode::DisabledOpcode,
4266 message: "OP_2MUL is disabled".into(),
4267 }),
4268 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4270 code: ScriptErrorCode::DisabledOpcode,
4271 message: "OP_2DIV is disabled".into(),
4272 }),
4273 OP_NEGATE => {
4275 if let Some(item) = stack.pop() {
4276 let a = script_num_decode(&item, 4)?;
4277 stack.push(to_stack_element(&script_num_encode(-a)));
4278 Ok(true)
4279 } else {
4280 Ok(false)
4281 }
4282 }
4283 OP_ABS => {
4285 if let Some(item) = stack.pop() {
4286 let a = script_num_decode(&item, 4)?;
4287 stack.push(to_stack_element(&script_num_encode(a.abs())));
4288 Ok(true)
4289 } else {
4290 Ok(false)
4291 }
4292 }
4293 OP_NOT => {
4295 if let Some(item) = stack.pop() {
4296 let a = script_num_decode(&item, 4)?;
4297 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4298 1
4299 } else {
4300 0
4301 })));
4302 Ok(true)
4303 } else {
4304 Ok(false)
4305 }
4306 }
4307 OP_0NOTEQUAL => {
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_ADD => arithmetic::op_add(stack),
4322 OP_SUB => arithmetic::op_sub(stack),
4323 OP_MUL => arithmetic::op_mul_disabled(),
4324 OP_DIV => arithmetic::op_div_disabled(),
4325 OP_MOD => arithmetic::op_mod_disabled(),
4326 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4327 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4328 OP_BOOLAND => arithmetic::op_booland(stack),
4329 OP_BOOLOR => arithmetic::op_boolor(stack),
4330 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4331 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4332 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4333 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4334 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4335 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4336 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4337 OP_MIN => arithmetic::op_min(stack),
4338 OP_MAX => arithmetic::op_max(stack),
4339 OP_WITHIN => arithmetic::op_within(stack),
4340
4341 OP_CODESEPARATOR => Ok(true),
4343
4344 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4347
4348 OP_CHECKTEMPLATEVERIFY => {
4350 #[cfg(not(feature = "ctv"))]
4351 {
4352 Ok(true)
4354 }
4355
4356 #[cfg(feature = "ctv")]
4357 {
4358 return Err(ConsensusError::ScriptErrorWithCode {
4360 code: ScriptErrorCode::TxInvalid,
4361 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4362 });
4363 }
4364 }
4365
4366 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4368 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4369 Err(ConsensusError::ScriptErrorWithCode {
4370 code: ScriptErrorCode::DisabledOpcode,
4371 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4372 })
4373 }
4374
4375 _ => Ok(false),
4377 }
4378}
4379
4380#[allow(dead_code)]
4382fn execute_opcode_with_context(
4383 opcode: u8,
4384 stack: &mut Vec<StackElement>,
4385 flags: u32,
4386 tx: &Transaction,
4387 input_index: usize,
4388 prevouts: &[TransactionOutput],
4389 network: crate::types::Network,
4390) -> Result<bool> {
4391 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4393 let prevout_script_pubkeys: Vec<&[u8]> =
4394 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4395 let ctx = context::ScriptContext {
4396 tx,
4397 input_index,
4398 prevout_values: &prevout_values,
4399 prevout_script_pubkeys: &prevout_script_pubkeys,
4400 block_height: None,
4401 median_time_past: None,
4402 network,
4403 sigversion: SigVersion::Base,
4404 redeem_script_for_sighash: None,
4405 script_sig_for_sighash: None,
4406 tapscript_for_sighash: None,
4407 tapscript_codesep_pos: None,
4408 #[cfg(feature = "production")]
4409 schnorr_collector: None,
4410 #[cfg(feature = "production")]
4411 precomputed_bip143: None,
4412 #[cfg(feature = "production")]
4413 sighash_cache: None,
4414 };
4415 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4416}
4417
4418#[cfg(feature = "production")]
4422#[inline(always)]
4423pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4424 let mut i = 0;
4425 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4426 i += adv1;
4427 if i >= script_sig.len() {
4428 return None;
4429 }
4430 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4431 i += adv2;
4432 if i >= script_sig.len() {
4433 return None;
4434 }
4435 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4436 i += adv3;
4437 if i != script_sig.len() {
4438 return None;
4439 }
4440 let sig = &script_sig[s_start..s_end];
4441 let redeem = &script_sig[r_start..r_end];
4442 if sig.is_empty() || redeem.len() != 25 {
4443 return None;
4444 }
4445 if redeem[0] != OP_DUP
4446 || redeem[1] != OP_HASH160
4447 || redeem[2] != PUSH_20_BYTES
4448 || redeem[23] != OP_EQUALVERIFY
4449 || redeem[24] != OP_CHECKSIG
4450 {
4451 return None;
4452 }
4453 Some((sig[sig.len() - 1], redeem))
4454}
4455
4456#[inline(always)]
4460pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4461 let mut i = 0;
4462 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4463 i += adv1;
4464 if i >= script_sig.len() {
4465 return None;
4466 }
4467 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4468 i += adv2;
4469 if i != script_sig.len() {
4470 return None;
4471 }
4472 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4473}
4474
4475pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4478 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4479 if advance != script_sig.len() {
4480 return None;
4481 }
4482 Some(&script_sig[data_start..data_end])
4483}
4484
4485fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4487 if i >= script.len() {
4488 return None;
4489 }
4490 let opcode = script[i];
4491 let (advance, data_start, data_end) = if opcode == OP_0 {
4492 return None;
4493 } else if opcode <= 0x4b {
4494 let len = opcode as usize;
4495 if i + 1 + len > script.len() {
4496 return None;
4497 }
4498 (1 + len, i + 1, i + 1 + len)
4499 } else if opcode == OP_PUSHDATA1 {
4500 if i + 1 >= script.len() {
4501 return None;
4502 }
4503 let len = script[i + 1] as usize;
4504 if i + 2 + len > script.len() {
4505 return None;
4506 }
4507 (2 + len, i + 2, i + 2 + len)
4508 } else if opcode == OP_PUSHDATA2 {
4509 if i + 2 >= script.len() {
4510 return None;
4511 }
4512 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4513 if i + 3 + len > script.len() {
4514 return None;
4515 }
4516 (3 + len, i + 3, i + 3 + len)
4517 } else if opcode == OP_PUSHDATA4 {
4518 if i + 4 >= script.len() {
4519 return None;
4520 }
4521 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4522 as usize;
4523 if i + 5 + len > script.len() {
4524 return None;
4525 }
4526 (5 + len, i + 5, i + 5 + len)
4527 } else {
4528 return None;
4529 };
4530 Some((advance, data_start, data_end))
4531}
4532
4533#[spec_locked("5.2.1", "P2SHPushOnlyCheck")]
4536pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4537 parse_script_sig_push_only(script_sig).is_some()
4538}
4539
4540fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4544 let mut out = Vec::new();
4545 let mut i = 0;
4546 while i < script_sig.len() {
4547 let opcode = script_sig[i];
4548 if !is_push_opcode(opcode) {
4549 return None;
4550 }
4551 let (advance, data) = if opcode == OP_0 {
4552 (1, vec![])
4553 } else if opcode <= 0x4b {
4554 let len = opcode as usize;
4555 if i + 1 + len > script_sig.len() {
4556 return None;
4557 }
4558 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4559 } else if opcode == OP_PUSHDATA1 {
4560 if i + 1 >= script_sig.len() {
4561 return None;
4562 }
4563 let len = script_sig[i + 1] as usize;
4564 if i + 2 + len > script_sig.len() {
4565 return None;
4566 }
4567 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4568 } else if opcode == OP_PUSHDATA2 {
4569 if i + 2 >= script_sig.len() {
4570 return None;
4571 }
4572 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4573 if i + 3 + len > script_sig.len() {
4574 return None;
4575 }
4576 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4577 } else if opcode == OP_PUSHDATA4 {
4578 if i + 4 >= script_sig.len() {
4579 return None;
4580 }
4581 let len = u32::from_le_bytes([
4582 script_sig[i + 1],
4583 script_sig[i + 2],
4584 script_sig[i + 3],
4585 script_sig[i + 4],
4586 ]) as usize;
4587 if i + 5 + len > script_sig.len() {
4588 return None;
4589 }
4590 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4591 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4592 let n = script_num_from_opcode(opcode);
4594 (1, script_num_encode(n))
4595 } else {
4596 return None;
4597 };
4598 out.push(to_stack_element(&data));
4599 i += advance;
4600 }
4601 Some(out)
4602}
4603
4604fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4608 parse_script_sig_push_only(script_sig)
4609}
4610
4611fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4616 if redeem.len() < 4 {
4617 return None;
4618 }
4619 let n_op = redeem[0];
4620 if !(OP_1..=OP_16).contains(&n_op) {
4621 return None;
4622 }
4623 let n = (n_op - OP_1 + 1) as usize;
4624 let mut i = 1;
4625 let mut pubkeys = Vec::with_capacity(n);
4626 for _ in 0..n {
4627 if i >= redeem.len() {
4628 return None;
4629 }
4630 let first = redeem[i];
4631 let pk_len = if first == 0x02 || first == 0x03 {
4632 33
4633 } else if first == 0x04 {
4634 65
4635 } else {
4636 return None;
4637 };
4638 if i + pk_len > redeem.len() {
4639 return None;
4640 }
4641 pubkeys.push(&redeem[i..i + pk_len]);
4642 i += pk_len;
4643 }
4644 if i + 2 > redeem.len() {
4645 return None;
4646 }
4647 let m_op = redeem[i];
4648 if !(OP_1..=OP_16).contains(&m_op) {
4649 return None;
4650 }
4651 let m = m_op - OP_1 + 1;
4652 if redeem[i + 1] != OP_CHECKMULTISIG {
4653 return None;
4654 }
4655 Some((m, n as u8, pubkeys))
4656}
4657
4658fn script_num_from_opcode(opcode: u8) -> i64 {
4660 match opcode {
4661 OP_1NEGATE => -1,
4662 OP_1 => 1,
4663 OP_2 => 2,
4664 OP_3 => 3,
4665 OP_4 => 4,
4666 OP_5 => 5,
4667 OP_6 => 6,
4668 OP_7 => 7,
4669 OP_8 => 8,
4670 OP_9 => 9,
4671 OP_10 => 10,
4672 OP_11 => 11,
4673 OP_12 => 12,
4674 OP_13 => 13,
4675 OP_14 => 14,
4676 OP_15 => 15,
4677 OP_16 => 16,
4678 _ => 0,
4679 }
4680}
4681
4682pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
4686 let len = data.len();
4687 let mut result = Vec::with_capacity(len + 5);
4688 if len < 76 {
4689 result.push(len as u8);
4690 } else if len < 256 {
4691 result.push(OP_PUSHDATA1);
4692 result.push(len as u8);
4693 } else if len < 65536 {
4694 result.push(OP_PUSHDATA2);
4695 result.push((len & 0xff) as u8);
4696 result.push(((len >> 8) & 0xff) as u8);
4697 } else {
4698 result.push(OP_PUSHDATA4);
4699 result.push((len & 0xff) as u8);
4700 result.push(((len >> 8) & 0xff) as u8);
4701 result.push(((len >> 16) & 0xff) as u8);
4702 result.push(((len >> 24) & 0xff) as u8);
4703 }
4704 result.extend_from_slice(data);
4705 result
4706}
4707
4708#[inline]
4710fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
4711 if pc >= script.len() {
4712 return None;
4713 }
4714 let opcode = script[pc];
4715 let advance = if opcode <= 0x4b {
4716 1 + opcode as usize
4717 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
4718 2 + script[pc + 1] as usize
4719 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
4720 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
4721 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
4722 5 + ((script[pc + 1] as usize)
4723 | ((script[pc + 2] as usize) << 8)
4724 | ((script[pc + 3] as usize) << 16)
4725 | ((script[pc + 4] as usize) << 24))
4726 } else {
4727 1
4728 };
4729 let next = pc + advance;
4730 if next > script.len() {
4731 None
4732 } else {
4733 Some(next)
4734 }
4735}
4736
4737#[spec_locked("5.1.1", "FindAndDelete")]
4743#[inline]
4744pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
4745 if pattern.is_empty() {
4746 return std::borrow::Cow::Borrowed(script);
4747 }
4748 if pattern.len() > script.len() {
4749 return std::borrow::Cow::Borrowed(script);
4750 }
4751 if !script.windows(pattern.len()).any(|w| w == pattern) {
4756 return std::borrow::Cow::Borrowed(script);
4757 }
4758 let end = script.len();
4759 let mut n_found = 0usize;
4760 let mut result = Vec::new();
4761 let mut pc = 0usize;
4762 let mut pc2 = 0usize;
4763
4764 loop {
4765 result.extend_from_slice(&script[pc2..pc]);
4766 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
4767 pc += pattern.len();
4768 n_found += 1;
4769 }
4770 pc2 = pc;
4771 if pc >= end {
4772 break;
4773 }
4774 let Some(next_pc) = script_get_op_advance(script, pc) else {
4775 break;
4776 };
4777 pc = next_pc;
4778 }
4779
4780 if n_found > 0 {
4781 result.extend_from_slice(&script[pc2..end]);
4782 std::borrow::Cow::Owned(result)
4783 } else {
4784 std::borrow::Cow::Borrowed(script)
4785 }
4786}
4787
4788fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
4790 let mut pos = 0u32;
4791 let mut i = 0usize;
4792 while i < script.len() && i <= byte_index {
4793 let opcode = script[i];
4794 let advance = if opcode <= 0x4b {
4795 1 + opcode as usize
4796 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
4797 2 + script[i + 1] as usize
4798 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
4799 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
4800 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
4801 5 + ((script[i + 1] as usize)
4802 | ((script[i + 2] as usize) << 8)
4803 | ((script[i + 3] as usize) << 16)
4804 | ((script[i + 4] as usize) << 24))
4805 } else {
4806 1
4807 };
4808 if i == byte_index {
4809 return pos;
4810 }
4811 pos += 1;
4812 i = std::cmp::min(i + advance, script.len());
4813 }
4814 0xffff_ffff
4815}
4816
4817#[cfg_attr(feature = "production", inline(always))]
4819fn execute_opcode_with_context_full(
4820 opcode: u8,
4821 stack: &mut Vec<StackElement>,
4822 flags: u32,
4823 ctx: &context::ScriptContext<'_>,
4824 effective_script_code: Option<&[u8]>,
4825) -> Result<bool> {
4826 let tx = ctx.tx;
4827 let input_index = ctx.input_index;
4828 let prevout_values = ctx.prevout_values;
4829 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
4830 let block_height = ctx.block_height;
4831 let median_time_past = ctx.median_time_past;
4832 let network = ctx.network;
4833 let sigversion = ctx.sigversion;
4834 let script_sig_for_sighash = ctx.script_sig_for_sighash;
4835 let tapscript_for_sighash = ctx.tapscript_for_sighash;
4836 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
4837 let redeem_script_for_sighash = effective_script_code;
4838 #[cfg(feature = "production")]
4839 let schnorr_collector = ctx.schnorr_collector;
4840 #[cfg(feature = "production")]
4841 let precomputed_bip143 = ctx.precomputed_bip143;
4842 #[cfg(feature = "production")]
4843 let sighash_cache = ctx.sighash_cache;
4844
4845 match opcode {
4847 OP_CHECKSIG => {
4849 if stack.len() >= 2 {
4850 let pubkey_bytes = stack.pop().unwrap();
4851 let signature_bytes = stack.pop().unwrap();
4852
4853 if signature_bytes.is_empty() {
4855 stack.push(to_stack_element(&[0]));
4856 return Ok(true);
4857 }
4858
4859 if sigversion == SigVersion::Tapscript {
4862 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
4864 let sighash_byte = 0x00;
4865 let (tapscript, codesep_pos) = tapscript_for_sighash
4866 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
4867 .unwrap_or((&[] as &[u8], 0xffff_ffff));
4868 let sighash = if tapscript.is_empty() {
4869 crate::taproot::compute_taproot_signature_hash(
4870 tx,
4871 input_index,
4872 prevout_values,
4873 prevout_script_pubkeys,
4874 sighash_byte,
4875 )?
4876 } else {
4877 crate::taproot::compute_tapscript_signature_hash(
4878 tx,
4879 input_index,
4880 prevout_values,
4881 prevout_script_pubkeys,
4882 tapscript,
4883 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
4884 codesep_pos,
4885 sighash_byte,
4886 )?
4887 };
4888
4889 #[cfg(feature = "production")]
4891 let is_valid = {
4892 use crate::bip348::verify_tapscript_schnorr_signature;
4893 verify_tapscript_schnorr_signature(
4894 &sighash,
4895 &pubkey_bytes,
4896 &signature_bytes,
4897 schnorr_collector,
4898 )
4899 .unwrap_or(false)
4900 };
4901
4902 #[cfg(not(feature = "production"))]
4903 let is_valid = {
4904 #[cfg(feature = "csfs")]
4905 let x = {
4906 use crate::bip348::verify_tapscript_schnorr_signature;
4907 verify_tapscript_schnorr_signature(
4908 &sighash,
4909 &pubkey_bytes,
4910 &signature_bytes,
4911 None,
4912 )
4913 .unwrap_or(false)
4914 };
4915 #[cfg(not(feature = "csfs"))]
4916 let x = false;
4917 x
4918 };
4919
4920 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
4921 return Ok(true);
4922 }
4923 }
4925
4926 let sig_len = signature_bytes.len();
4930 let sighash_byte = signature_bytes[sig_len - 1];
4931 let _der_sig = &signature_bytes[..sig_len - 1];
4932
4933 let sighash = if sigversion == SigVersion::WitnessV0 {
4937 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
4939
4940 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
4942 prevout_script_pubkeys
4943 .get(input_index)
4944 .copied()
4945 .unwrap_or(&[])
4946 });
4947
4948 crate::transaction_hash::calculate_bip143_sighash(
4949 tx,
4950 input_index,
4951 script_code,
4952 amount,
4953 sighash_byte,
4954 precomputed_bip143,
4955 )?
4956 } else {
4957 use crate::transaction_hash::{
4959 calculate_transaction_sighash_single_input, SighashType,
4960 };
4961 let sighash_type = SighashType::from_byte(sighash_byte);
4962
4963 let pattern = serialize_push_data(signature_bytes.as_ref());
4967
4968 let base_script = match (
4969 redeem_script_for_sighash,
4970 prevout_script_pubkeys.get(input_index),
4971 ) {
4972 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
4973 (Some(redeem), _) => redeem,
4974 (None, Some(prevout)) => *prevout,
4975 (None, None) => &[],
4976 };
4977 let cleaned = find_and_delete(base_script, &pattern);
4978
4979 calculate_transaction_sighash_single_input(
4980 tx,
4981 input_index,
4982 cleaned.as_ref(),
4983 prevout_values[input_index],
4984 sighash_type,
4985 #[cfg(feature = "production")]
4986 sighash_cache,
4987 )?
4988 };
4989
4990 let height = block_height.unwrap_or(0);
4994 #[cfg(feature = "production")]
4995 let is_valid = signature::with_secp_context(|secp| {
4996 signature::verify_signature(
4997 secp,
4998 &pubkey_bytes,
4999 &signature_bytes, &sighash,
5001 flags,
5002 height,
5003 network,
5004 sigversion,
5005 )
5006 })?;
5007
5008 #[cfg(not(feature = "production"))]
5009 let is_valid = {
5010 let secp = signature::new_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 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5024 Ok(true)
5025 } else {
5026 Ok(false)
5027 }
5028 }
5029
5030 OP_CHECKSIGVERIFY => {
5032 if stack.len() >= 2 {
5033 let pubkey_bytes = stack.pop().unwrap();
5034 let signature_bytes = stack.pop().unwrap();
5035
5036 if signature_bytes.is_empty() {
5038 return Ok(false);
5039 }
5040
5041 let sig_len = signature_bytes.len();
5045 let sighash_byte = signature_bytes[sig_len - 1];
5046 let _der_sig = &signature_bytes[..sig_len - 1];
5047
5048 let sighash = if sigversion == SigVersion::WitnessV0 {
5052 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5054
5055 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5056 prevout_script_pubkeys
5057 .get(input_index)
5058 .copied()
5059 .unwrap_or(&[])
5060 });
5061
5062 crate::transaction_hash::calculate_bip143_sighash(
5063 tx,
5064 input_index,
5065 script_code,
5066 amount,
5067 sighash_byte,
5068 precomputed_bip143,
5069 )?
5070 } else {
5071 use crate::transaction_hash::{
5073 calculate_transaction_sighash_single_input, SighashType,
5074 };
5075 let sighash_type = SighashType::from_byte(sighash_byte);
5076
5077 let pattern = serialize_push_data(signature_bytes.as_ref());
5079
5080 let base_script = match (
5081 redeem_script_for_sighash,
5082 prevout_script_pubkeys.get(input_index),
5083 ) {
5084 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5085 (Some(redeem), _) => redeem,
5086 (None, Some(prevout)) => *prevout,
5087 (None, None) => &[],
5088 };
5089 let cleaned = find_and_delete(base_script, &pattern);
5090
5091 calculate_transaction_sighash_single_input(
5092 tx,
5093 input_index,
5094 cleaned.as_ref(),
5095 prevout_values[input_index],
5096 sighash_type,
5097 #[cfg(feature = "production")]
5098 sighash_cache,
5099 )?
5100 };
5101
5102 let height = block_height.unwrap_or(0);
5106 #[cfg(feature = "production")]
5107 let is_valid = signature::with_secp_context(|secp| {
5108 signature::verify_signature(
5109 secp,
5110 &pubkey_bytes,
5111 &signature_bytes, &sighash,
5113 flags,
5114 height,
5115 network,
5116 sigversion,
5117 )
5118 })?;
5119
5120 #[cfg(not(feature = "production"))]
5121 let is_valid = {
5122 let secp = signature::new_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 if is_valid {
5136 Ok(true)
5137 } else {
5138 Ok(false)
5139 }
5140 } else {
5141 Ok(false)
5142 }
5143 }
5144
5145 OP_CHECKSIGADD => {
5147 if sigversion != SigVersion::Tapscript {
5148 return Err(ConsensusError::ScriptErrorWithCode {
5149 code: ScriptErrorCode::DisabledOpcode,
5150 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5151 });
5152 }
5153 if stack.len() < 3 {
5154 return Err(ConsensusError::ScriptErrorWithCode {
5155 code: ScriptErrorCode::InvalidStackOperation,
5156 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5157 });
5158 }
5159 let pubkey_bytes = stack.pop().unwrap();
5161 let n_bytes = stack.pop().unwrap();
5162 let signature_bytes = stack.pop().unwrap();
5163 let n = script_num_decode(&n_bytes, 4)?;
5164
5165 if signature_bytes.is_empty() {
5167 stack.push(to_stack_element(&script_num_encode(n)));
5168 return Ok(true);
5169 }
5170
5171 if pubkey_bytes.len() == 32 && signature_bytes.len() == 64 {
5173 let sighash_byte = 0x00;
5174 let (tapscript, codesep_pos) = tapscript_for_sighash
5175 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5176 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5177 let sighash = if tapscript.is_empty() {
5178 crate::taproot::compute_taproot_signature_hash(
5179 tx,
5180 input_index,
5181 prevout_values,
5182 prevout_script_pubkeys,
5183 sighash_byte,
5184 )?
5185 } else {
5186 crate::taproot::compute_tapscript_signature_hash(
5187 tx,
5188 input_index,
5189 prevout_values,
5190 prevout_script_pubkeys,
5191 tapscript,
5192 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5193 codesep_pos,
5194 sighash_byte,
5195 )?
5196 };
5197
5198 #[cfg(feature = "production")]
5199 let is_valid = {
5200 use crate::bip348::verify_tapscript_schnorr_signature;
5201 verify_tapscript_schnorr_signature(
5202 &sighash,
5203 &pubkey_bytes,
5204 &signature_bytes,
5205 schnorr_collector,
5206 )
5207 .unwrap_or(false)
5208 };
5209
5210 #[cfg(not(feature = "production"))]
5211 let is_valid = {
5212 #[cfg(feature = "csfs")]
5213 let x = {
5214 use crate::bip348::verify_tapscript_schnorr_signature;
5215 verify_tapscript_schnorr_signature(
5216 &sighash,
5217 &pubkey_bytes,
5218 &signature_bytes,
5219 None,
5220 )
5221 .unwrap_or(false)
5222 };
5223 #[cfg(not(feature = "csfs"))]
5224 let x = false;
5225 x
5226 };
5227
5228 if !is_valid {
5229 return Ok(false); }
5231 stack.push(to_stack_element(&script_num_encode(n + 1)));
5232 return Ok(true);
5233 }
5234
5235 stack.push(to_stack_element(&script_num_encode(n + 1)));
5237 Ok(true)
5238 }
5239
5240 OP_CHECKMULTISIG => {
5242 if stack.len() < 2 {
5245 return Ok(false);
5246 }
5247
5248 let n_bytes = stack.pop().unwrap();
5251 let n = if n_bytes.is_empty() {
5252 0
5253 } else {
5254 n_bytes[0] as usize
5255 };
5256 if n > 20 || stack.len() < n + 1 {
5257 return Ok(false);
5258 }
5259
5260 let mut pubkeys = Vec::with_capacity(n);
5262 for _ in 0..n {
5263 pubkeys.push(stack.pop().unwrap());
5264 }
5265
5266 let m_bytes = stack.pop().unwrap();
5269 let m = if m_bytes.is_empty() {
5270 0
5271 } else {
5272 m_bytes[0] as usize
5273 };
5274 if m > n || m > 20 || stack.len() < m + 1 {
5275 return Ok(false);
5276 }
5277
5278 let mut signatures = Vec::with_capacity(m);
5280 for _ in 0..m {
5281 signatures.push(stack.pop().unwrap());
5282 }
5283
5284 let dummy = stack.pop().unwrap();
5287 if flags & 0x10 != 0 {
5288 let height = block_height.unwrap_or(0);
5289 use crate::bip_validation::Bip147Network;
5291 let bip147_network = match network {
5292 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5293 crate::types::Network::Testnet => Bip147Network::Testnet,
5294 crate::types::Network::Regtest => Bip147Network::Regtest,
5295 };
5296
5297 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5301
5302 let bip147_active = height
5303 >= match bip147_network {
5304 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5305 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5306 Bip147Network::Regtest => 0,
5307 };
5308
5309 if bip147_active {
5310 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5314 if !is_empty {
5315 return Err(ConsensusError::ScriptErrorWithCode {
5316 code: ScriptErrorCode::SigNullDummy,
5317 message: format!(
5318 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5319 )
5320 .into(),
5321 });
5322 }
5323 }
5324 }
5325
5326 let height = block_height.unwrap_or(0);
5329
5330 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5333 let base_script = match (
5334 redeem_script_for_sighash,
5335 prevout_script_pubkeys.get(input_index),
5336 ) {
5337 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5338 (Some(redeem), _) => redeem,
5339 (None, Some(prevout)) => *prevout,
5340 (None, None) => &[],
5341 };
5342 let mut cleaned = base_script.to_vec();
5343 for sig in &signatures {
5344 if !sig.is_empty() {
5345 let pattern = serialize_push_data(sig.as_ref());
5346 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5347 }
5348 }
5349 cleaned
5350 } else {
5351 redeem_script_for_sighash
5353 .map(|s| s.to_vec())
5354 .unwrap_or_else(|| {
5355 prevout_script_pubkeys
5356 .get(input_index)
5357 .map(|p| p.to_vec())
5358 .unwrap_or_default()
5359 })
5360 };
5361
5362 use crate::transaction_hash::{
5363 calculate_transaction_sighash_single_input, SighashType,
5364 };
5365
5366 #[cfg(feature = "production")]
5368 let use_batch = pubkeys.len() * signatures.len() >= 4;
5369
5370 #[cfg(feature = "production")]
5371 let (valid_sigs, _) = if use_batch {
5372 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5374 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5375 if non_empty.is_empty() {
5376 vec![]
5377 } else {
5378 let specs: Vec<(usize, u8, &[u8])> = non_empty
5379 .iter()
5380 .map(|s| {
5381 (
5382 input_index,
5383 s.as_ref()[s.as_ref().len() - 1],
5384 cleaned_script_for_multisig.as_ref(),
5385 )
5386 })
5387 .collect();
5388 crate::transaction_hash::batch_compute_legacy_sighashes(
5389 tx,
5390 prevout_values,
5391 prevout_script_pubkeys,
5392 &specs,
5393 )?
5394 }
5395 } else {
5396 signatures
5397 .iter()
5398 .filter(|s| !s.is_empty())
5399 .map(|sig_bytes| {
5400 let sighash_type =
5401 SighashType::from_byte(sig_bytes[sig_bytes.len() - 1]);
5402 calculate_transaction_sighash_single_input(
5403 tx,
5404 input_index,
5405 &cleaned_script_for_multisig,
5406 prevout_values[input_index],
5407 sighash_type,
5408 sighash_cache,
5409 )
5410 })
5411 .collect::<Result<Vec<_>>>()?
5412 };
5413
5414 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5416 Vec::with_capacity(pubkeys.len() * signatures.len());
5417 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5418 let mut sighash_idx = 0usize;
5419 for (j, sig_bytes) in signatures.iter().enumerate() {
5420 if sig_bytes.is_empty() {
5421 sig_idx_to_sighash_idx.push(usize::MAX);
5422 } else {
5423 sig_idx_to_sighash_idx.push(sighash_idx);
5424 let sh = sighashes[sighash_idx];
5425 sighash_idx += 1;
5426 for pubkey_bytes in &pubkeys {
5427 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5428 }
5429 }
5430 }
5431
5432 let results = if tasks.is_empty() {
5433 vec![]
5434 } else {
5435 batch_verify_signatures(&tasks, flags, height, network)?
5436 };
5437
5438 let mut sig_index = 0;
5440 let mut valid_sigs = 0usize;
5441 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5442 if sig_index >= signatures.len() {
5443 break;
5444 }
5445 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5447 sig_index += 1;
5448 }
5449 if sig_index >= signatures.len() {
5450 break;
5451 }
5452 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5453 if sh_idx == usize::MAX {
5454 continue;
5455 }
5456 let task_idx = sh_idx * pubkeys.len() + i;
5457 if task_idx < results.len() && results[task_idx] {
5458 valid_sigs += 1;
5459 sig_index += 1;
5460 }
5461 }
5462
5463 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5465 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5466 for (j, sig_bytes) in signatures.iter().enumerate() {
5467 if sig_bytes.is_empty() {
5468 continue;
5469 }
5470 let sh_idx = sig_idx_to_sighash_idx[j];
5471 if sh_idx == usize::MAX {
5472 continue;
5473 }
5474 let sig_start = sh_idx * pubkeys.len();
5475 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5476 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5477 if !matched {
5478 return Err(ConsensusError::ScriptErrorWithCode {
5479 code: ScriptErrorCode::SigNullFail,
5480 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5481 });
5482 }
5483 }
5484 }
5485 (valid_sigs, ())
5486 } else {
5487 let mut sig_index = 0;
5488 let mut valid_sigs = 0;
5489
5490 for pubkey_bytes in &pubkeys {
5491 if sig_index >= signatures.len() {
5492 break;
5493 }
5494
5495 let signature_bytes = &signatures[sig_index];
5496
5497 if signature_bytes.is_empty() {
5498 continue;
5499 }
5500
5501 let sig_len = signature_bytes.len();
5502 let sighash_byte = signature_bytes[sig_len - 1];
5503 let sighash_type = SighashType::from_byte(sighash_byte);
5504
5505 let sighash = calculate_transaction_sighash_single_input(
5506 tx,
5507 input_index,
5508 &cleaned_script_for_multisig,
5509 prevout_values[input_index],
5510 sighash_type,
5511 #[cfg(feature = "production")]
5512 sighash_cache,
5513 )?;
5514
5515 #[cfg(feature = "production")]
5516 let is_valid = signature::with_secp_context(|secp| {
5517 signature::verify_signature(
5518 secp,
5519 pubkey_bytes,
5520 signature_bytes,
5521 &sighash,
5522 flags,
5523 height,
5524 network,
5525 sigversion,
5526 )
5527 })?;
5528
5529 #[cfg(not(feature = "production"))]
5530 let is_valid = {
5531 let secp = signature::new_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 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5545 if !is_valid
5546 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5547 && !signature_bytes.is_empty()
5548 {
5549 return Err(ConsensusError::ScriptErrorWithCode {
5550 code: ScriptErrorCode::SigNullFail,
5551 message:
5552 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5553 .into(),
5554 });
5555 }
5556
5557 if is_valid {
5558 valid_sigs += 1;
5559 sig_index += 1;
5560 }
5561 }
5562 (valid_sigs, ())
5563 };
5564
5565 #[cfg(not(feature = "production"))]
5566 let (valid_sigs, _) = {
5567 let mut sig_index = 0;
5568 let mut valid_sigs = 0;
5569
5570 for pubkey_bytes in &pubkeys {
5571 if sig_index >= signatures.len() {
5572 break;
5573 }
5574 let signature_bytes = &signatures[sig_index];
5575 if signature_bytes.is_empty() {
5576 continue;
5577 }
5578 let sig_len = signature_bytes.len();
5579 let sighash_type = SighashType::from_byte(signature_bytes[sig_len - 1]);
5580 let sighash = calculate_transaction_sighash_single_input(
5581 tx,
5582 input_index,
5583 &cleaned_script_for_multisig,
5584 prevout_values[input_index],
5585 sighash_type,
5586 #[cfg(feature = "production")]
5587 sighash_cache,
5588 )?;
5589 let secp = signature::new_secp();
5590 let is_valid = signature::verify_signature(
5591 &secp,
5592 pubkey_bytes,
5593 signature_bytes,
5594 &sighash,
5595 flags,
5596 height,
5597 network,
5598 sigversion,
5599 )?;
5600 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5601 if !is_valid
5602 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5603 && !signature_bytes.is_empty()
5604 {
5605 return Err(ConsensusError::ScriptErrorWithCode {
5606 code: ScriptErrorCode::SigNullFail,
5607 message:
5608 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5609 .into(),
5610 });
5611 }
5612 if is_valid {
5613 valid_sigs += 1;
5614 sig_index += 1;
5615 }
5616 }
5617 (valid_sigs, ())
5618 };
5619
5620 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
5622 Ok(true)
5623 }
5624
5625 OP_CHECKMULTISIGVERIFY => {
5627 let ctx_checkmultisig = context::ScriptContext {
5629 tx,
5630 input_index,
5631 prevout_values,
5632 prevout_script_pubkeys,
5633 block_height,
5634 median_time_past,
5635 network,
5636 sigversion,
5637 redeem_script_for_sighash,
5638 script_sig_for_sighash,
5639 tapscript_for_sighash,
5640 tapscript_codesep_pos,
5641 #[cfg(feature = "production")]
5642 schnorr_collector: None,
5643 #[cfg(feature = "production")]
5644 precomputed_bip143,
5645 #[cfg(feature = "production")]
5646 sighash_cache,
5647 };
5648 let result = execute_opcode_with_context_full(
5649 OP_CHECKMULTISIG,
5650 stack,
5651 flags,
5652 &ctx_checkmultisig,
5653 redeem_script_for_sighash,
5654 )?;
5655 if !result {
5656 return Ok(false);
5657 }
5658 if let Some(top) = stack.pop() {
5660 if !cast_to_bool(&top) {
5661 return Ok(false);
5662 }
5663 Ok(true)
5664 } else {
5665 Ok(false)
5666 }
5667 }
5668
5669 OP_CHECKLOCKTIMEVERIFY => {
5674 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
5676 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5677 return Ok(true);
5678 }
5679
5680 use crate::locktime::{check_bip65, decode_locktime_value};
5681
5682 if stack.is_empty() {
5683 return Err(ConsensusError::ScriptErrorWithCode {
5684 code: ScriptErrorCode::InvalidStackOperation,
5685 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
5686 });
5687 }
5688
5689 let locktime_bytes = stack.last().expect("Stack is not empty");
5691 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
5692 Some(v) => v,
5693 None => {
5694 return Err(ConsensusError::ScriptErrorWithCode {
5695 code: ScriptErrorCode::MinimalData,
5696 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
5697 })
5698 }
5699 };
5700
5701 let tx_locktime = tx.lock_time as u32;
5702
5703 if !check_bip65(tx_locktime, locktime_value) {
5705 return Ok(false);
5706 }
5707
5708 let input_seq = if input_index < tx.inputs.len() {
5710 tx.inputs[input_index].sequence
5711 } else {
5712 0xffffffff
5713 };
5714 if input_seq == 0xffffffff {
5715 return Ok(false);
5716 }
5717
5718 Ok(true)
5720 }
5721
5722 OP_CHECKSEQUENCEVERIFY => {
5731 use crate::locktime::{
5732 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
5733 is_sequence_disabled,
5734 };
5735
5736 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
5738 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
5739 return Ok(true);
5740 }
5741
5742 if stack.is_empty() {
5743 return Ok(false);
5744 }
5745
5746 let sequence_bytes = stack.last().expect("Stack is not empty");
5749 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
5750 Some(v) => v,
5751 None => return Ok(false), };
5753
5754 if input_index >= tx.inputs.len() {
5756 return Ok(false);
5757 }
5758 let input_sequence = tx.inputs[input_index].sequence as u32;
5759
5760 if is_sequence_disabled(input_sequence) {
5762 return Ok(true);
5763 }
5764
5765 let type_flag = extract_sequence_type_flag(sequence_value);
5767 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
5768
5769 let input_type_flag = extract_sequence_type_flag(input_sequence);
5771 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
5772
5773 if type_flag != input_type_flag {
5775 return Ok(false);
5776 }
5777
5778 if input_locktime < locktime_mask {
5780 return Ok(false);
5781 }
5782
5783 Ok(true)
5785 }
5786
5787 OP_CHECKTEMPLATEVERIFY => {
5796 #[cfg(not(feature = "ctv"))]
5797 {
5798 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5800 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5801 return Err(ConsensusError::ScriptErrorWithCode {
5802 code: ScriptErrorCode::BadOpcode,
5803 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
5804 });
5805 }
5806 Ok(true) }
5808
5809 #[cfg(feature = "ctv")]
5810 {
5811 use crate::constants::{
5812 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
5813 };
5814
5815 let ctv_activation = match network {
5817 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
5818 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
5819 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
5820 };
5821
5822 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
5823 if !ctv_active {
5824 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5826 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5827 return Err(ConsensusError::ScriptErrorWithCode {
5828 code: ScriptErrorCode::BadOpcode,
5829 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
5830 });
5831 }
5832 return Ok(true); }
5834
5835 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
5837 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
5838 return Ok(true);
5840 }
5841
5842 use crate::bip119::calculate_template_hash;
5843
5844 if stack.is_empty() {
5846 return Err(ConsensusError::ScriptErrorWithCode {
5847 code: ScriptErrorCode::InvalidStackOperation,
5848 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
5849 });
5850 }
5851
5852 let template_hash_bytes = stack.pop().unwrap();
5853
5854 if template_hash_bytes.len() != 32 {
5856 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5859 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5860 return Err(ConsensusError::ScriptErrorWithCode {
5861 code: ScriptErrorCode::InvalidStackOperation,
5862 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
5863 .into(),
5864 });
5865 }
5866 return Ok(true); }
5868
5869 let mut expected_hash = [0u8; 32];
5871 expected_hash.copy_from_slice(&template_hash_bytes);
5872
5873 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
5874 ConsensusError::ScriptErrorWithCode {
5875 code: ScriptErrorCode::TxInvalid,
5876 message: format!("CTV hash calculation failed: {e}").into(),
5877 }
5878 })?;
5879
5880 use crate::crypto::hash_compare::hash_eq;
5882 let matches = hash_eq(&expected_hash, &actual_hash);
5883
5884 if !matches {
5885 return Ok(false); }
5887
5888 Ok(true)
5890 }
5891 }
5892
5893 OP_CHECKSIGFROMSTACK => {
5904 #[cfg(not(feature = "csfs"))]
5905 {
5906 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5909 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5910 return Err(ConsensusError::ScriptErrorWithCode {
5911 code: ScriptErrorCode::BadOpcode,
5912 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
5913 });
5914 }
5915 Ok(true) }
5917
5918 #[cfg(feature = "csfs")]
5919 {
5920 use crate::constants::{
5921 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
5922 };
5923
5924 if sigversion != SigVersion::Tapscript {
5926 return Err(ConsensusError::ScriptErrorWithCode {
5927 code: ScriptErrorCode::BadOpcode,
5928 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
5929 });
5930 }
5931
5932 let csfs_activation = match network {
5934 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
5935 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
5936 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
5937 };
5938
5939 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
5940 if !csfs_active {
5941 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5943 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5944 return Err(ConsensusError::ScriptErrorWithCode {
5945 code: ScriptErrorCode::BadOpcode,
5946 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
5947 });
5948 }
5949 return Ok(true); }
5951
5952 use crate::bip348::verify_signature_from_stack;
5953
5954 if stack.len() < 3 {
5956 return Err(ConsensusError::ScriptErrorWithCode {
5957 code: ScriptErrorCode::InvalidStackOperation,
5958 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
5959 });
5960 }
5961
5962 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
5969 return Err(ConsensusError::ScriptErrorWithCode {
5970 code: ScriptErrorCode::PubkeyType,
5971 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
5972 });
5973 }
5974
5975 if signature_bytes.is_empty() {
5977 stack.push(to_stack_element(&[])); return Ok(true);
5979 }
5980
5981 #[cfg(feature = "production")]
5984 let is_valid = {
5985 verify_signature_from_stack(
5986 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
5991 .unwrap_or(false)
5992 };
5993 #[cfg(not(feature = "production"))]
5994 let is_valid = verify_signature_from_stack(
5995 &message_bytes, &pubkey_bytes, &signature_bytes, )
5999 .unwrap_or(false);
6000
6001 if !is_valid {
6002 return Ok(false);
6004 }
6005
6006 stack.push(to_stack_element(&[0x01])); Ok(true)
6013 }
6014 }
6015
6016 _ => execute_opcode_cold(opcode, stack, flags),
6018 }
6019}
6020
6021#[cold]
6023fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6024 execute_opcode(opcode, stack, flags, SigVersion::Base)
6025}
6026
6027#[cfg(feature = "production")]
6042pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6043 (
6044 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6045 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6046 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6047 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6048 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6049 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6050 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6051 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6052 )
6053}
6054
6055#[cfg(all(feature = "production", feature = "benchmarking"))]
6062pub fn clear_script_cache() {
6063 if let Some(cache) = SCRIPT_CACHE.get() {
6064 let mut cache = cache.write().unwrap();
6065 cache.clear();
6066 }
6067}
6068
6069#[cfg(all(feature = "production", feature = "benchmarking"))]
6083pub fn clear_hash_cache() {
6084 crypto_ops::clear_hash_cache();
6085}
6086
6087#[cfg(all(feature = "production", feature = "benchmarking"))]
6100pub fn clear_all_caches() {
6101 clear_script_cache();
6102 clear_hash_cache();
6103}
6104
6105#[cfg(all(feature = "production", feature = "benchmarking"))]
6119pub fn clear_stack_pool() {
6120 STACK_POOL.with(|pool| {
6121 let mut pool = pool.borrow_mut();
6122 pool.clear();
6123 });
6124}
6125
6126#[cfg(all(feature = "production", feature = "benchmarking"))]
6140pub fn reset_benchmarking_state() {
6141 clear_all_caches();
6142 clear_stack_pool();
6143 disable_caching(false); #[cfg(feature = "benchmarking")]
6146 crate::transaction_hash::clear_sighash_templates();
6147}
6148
6149#[cfg(test)]
6150mod tests {
6151 use super::*;
6152
6153 #[test]
6154 fn test_eval_script_simple() {
6155 let script = vec![OP_1]; let mut stack = Vec::new();
6157
6158 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6159 assert_eq!(stack.len(), 1);
6160 assert_eq!(stack[0].as_ref(), &[1]);
6161 }
6162
6163 #[test]
6164 fn test_eval_script_overflow() {
6165 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6167
6168 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6169 }
6170
6171 #[test]
6172 fn test_verify_script_simple() {
6173 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());
6184 }
6185
6186 #[test]
6191 fn test_op_0() {
6192 let script = vec![OP_0]; let mut stack = Vec::new();
6194 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6195 assert!(!result); assert_eq!(stack.len(), 1);
6197 assert!(stack[0].is_empty());
6198 }
6199
6200 #[test]
6201 fn test_op_1_to_op_16() {
6202 for i in 1..=16 {
6204 let opcode = 0x50 + i;
6205 let script = vec![opcode];
6206 let mut stack = Vec::new();
6207 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6208 assert!(result);
6209 assert_eq!(stack.len(), 1);
6210 assert_eq!(stack[0].as_ref(), &[i]);
6211 }
6212 }
6213
6214 #[test]
6215 fn test_op_dup() {
6216 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6218 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6219 assert!(!result); assert_eq!(stack.len(), 2);
6221 assert_eq!(stack[0].as_ref(), &[1]);
6222 assert_eq!(stack[1].as_ref(), &[1]);
6223 }
6224
6225 #[test]
6226 fn test_op_dup_empty_stack() {
6227 let script = vec![OP_DUP]; let mut stack = Vec::new();
6229 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6230 assert!(!result);
6231 }
6232
6233 #[test]
6234 fn test_op_hash160() {
6235 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6237 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6238 assert!(result);
6239 assert_eq!(stack.len(), 1);
6240 assert_eq!(stack[0].len(), 20); }
6242
6243 #[test]
6244 fn test_op_hash160_empty_stack() {
6245 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6247 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6248 assert!(!result);
6249 }
6250
6251 #[test]
6252 fn test_op_hash256() {
6253 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6255 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6256 assert!(result);
6257 assert_eq!(stack.len(), 1);
6258 assert_eq!(stack[0].len(), 32); }
6260
6261 #[test]
6262 fn test_op_hash256_empty_stack() {
6263 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6265 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6266 assert!(!result);
6267 }
6268
6269 #[test]
6270 fn test_op_equal() {
6271 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6273 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6274 assert!(result);
6275 assert_eq!(stack.len(), 1);
6276 assert_eq!(stack[0].as_ref(), &[1]); }
6278
6279 #[test]
6280 fn test_op_equal_false() {
6281 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6283 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6284 assert!(!result); assert_eq!(stack.len(), 1);
6286 assert_eq!(stack[0].as_ref(), &[0]); }
6288
6289 #[test]
6290 fn test_op_equal_insufficient_stack() {
6291 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6293 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6294 assert!(
6295 result.is_err(),
6296 "OP_EQUAL with insufficient stack should return error"
6297 );
6298 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6299 assert_eq!(
6300 code,
6301 crate::error::ScriptErrorCode::InvalidStackOperation,
6302 "Should return InvalidStackOperation"
6303 );
6304 }
6305 }
6306
6307 #[test]
6308 fn test_op_verify() {
6309 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6311 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6312 assert!(!result); assert_eq!(stack.len(), 0); }
6315
6316 #[test]
6317 fn test_op_verify_false() {
6318 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6320 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6321 assert!(!result);
6322 }
6323
6324 #[test]
6325 fn test_op_verify_empty_stack() {
6326 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6328 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6329 assert!(!result);
6330 }
6331
6332 #[test]
6333 fn test_op_equalverify() {
6334 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6336 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6337 assert!(!result); assert_eq!(stack.len(), 0); }
6340
6341 #[test]
6342 fn test_op_equalverify_false() {
6343 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6345 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6346 assert!(
6347 result.is_err(),
6348 "OP_EQUALVERIFY with false condition should return error"
6349 );
6350 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6351 assert_eq!(
6352 code,
6353 crate::error::ScriptErrorCode::EqualVerify,
6354 "Should return EqualVerify"
6355 );
6356 }
6357 }
6358
6359 #[test]
6360 fn test_op_checksig() {
6361 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6365 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6366 assert!(!result); assert_eq!(stack.len(), 1);
6368 }
6370
6371 #[test]
6372 fn test_op_checksig_insufficient_stack() {
6373 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6375 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6376 assert!(
6377 result.is_err(),
6378 "OP_CHECKSIG with insufficient stack should return error"
6379 );
6380 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6381 assert_eq!(
6382 code,
6383 crate::error::ScriptErrorCode::InvalidStackOperation,
6384 "Should return InvalidStackOperation"
6385 );
6386 }
6387 }
6388
6389 #[test]
6390 fn test_unknown_opcode() {
6391 let script = vec![0xff]; let mut stack = Vec::new();
6393 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6394 assert!(!result);
6395 }
6396
6397 #[test]
6398 fn test_script_size_limit() {
6399 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6401 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6402 assert!(result.is_err());
6403 }
6404
6405 #[test]
6406 fn test_operation_count_limit() {
6407 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6410 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6411 assert!(result.is_err());
6412 }
6413
6414 #[test]
6415 fn test_stack_underflow_multiple_ops() {
6416 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6418 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6419 assert!(result.is_err(), "Stack underflow should return error");
6420 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6421 assert_eq!(
6422 code,
6423 crate::error::ScriptErrorCode::InvalidStackOperation,
6424 "Should return InvalidStackOperation"
6425 );
6426 }
6427 }
6428
6429 #[test]
6430 fn test_final_stack_empty() {
6431 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6433 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6434 assert!(!result);
6435 }
6436
6437 #[test]
6438 fn test_final_stack_false() {
6439 let script = vec![OP_0]; let mut stack = Vec::new();
6441 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6442 assert!(!result);
6443 }
6444
6445 #[test]
6446 fn test_verify_script_with_witness() {
6447 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6451
6452 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6453 assert!(!result); }
6455
6456 #[test]
6457 fn test_verify_script_failure() {
6458 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_2]; let witness = None;
6461 let flags = 0;
6462
6463 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6464 assert!(!result);
6465 }
6466
6467 #[test]
6472 fn test_op_ifdup_true() {
6473 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6475 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6476 assert!(!result); assert_eq!(stack.len(), 2);
6478 assert_eq!(stack[0].as_ref(), &[1]);
6479 assert_eq!(stack[1].as_ref(), &[1]);
6480 }
6481
6482 #[test]
6483 fn test_op_ifdup_false() {
6484 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6486 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6487 assert!(!result); assert_eq!(stack.len(), 1);
6489 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6490 }
6491
6492 #[test]
6493 fn test_op_depth() {
6494 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6496 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6497 assert!(!result); assert_eq!(stack.len(), 3);
6499 assert_eq!(stack[2].as_ref(), &[2]); }
6501
6502 #[test]
6503 fn test_op_drop() {
6504 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
6506 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6507 assert!(result); assert_eq!(stack.len(), 1);
6509 assert_eq!(stack[0].as_ref(), &[1]);
6510 }
6511
6512 #[test]
6513 fn test_op_drop_empty_stack() {
6514 let script = vec![OP_DROP]; let mut stack = Vec::new();
6516 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6517 assert!(!result);
6518 assert_eq!(stack.len(), 0);
6519 }
6520
6521 #[test]
6522 fn test_op_nip() {
6523 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
6525 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6526 assert!(result); assert_eq!(stack.len(), 1);
6528 assert_eq!(stack[0].as_ref(), &[2]);
6529 }
6530
6531 #[test]
6532 fn test_op_nip_insufficient_stack() {
6533 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
6535 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6536 assert!(!result);
6537 assert_eq!(stack.len(), 1);
6538 }
6539
6540 #[test]
6541 fn test_op_over() {
6542 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
6544 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6545 assert!(!result); assert_eq!(stack.len(), 3);
6547 assert_eq!(stack[0].as_ref(), &[1]);
6548 assert_eq!(stack[1].as_ref(), &[2]);
6549 assert_eq!(stack[2].as_ref(), &[1]);
6550 }
6551
6552 #[test]
6553 fn test_op_over_insufficient_stack() {
6554 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
6556 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6557 assert!(!result);
6558 assert_eq!(stack.len(), 1);
6559 }
6560
6561 #[test]
6562 fn test_op_pick() {
6563 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
6565 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6566 assert!(!result); assert_eq!(stack.len(), 4);
6568 assert_eq!(stack[3].as_ref(), &[2]); }
6570
6571 #[test]
6572 fn test_op_pick_empty_n() {
6573 let script = vec![OP_1, OP_0, OP_PICK];
6575 let mut stack = Vec::new();
6576 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6577 assert!(!result); assert_eq!(stack.len(), 2);
6579 assert_eq!(stack[1].as_ref(), &[1]); }
6581
6582 #[test]
6583 fn test_op_pick_invalid_index() {
6584 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
6586 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6587 assert!(!result);
6588 assert_eq!(stack.len(), 1);
6589 }
6590
6591 #[test]
6592 fn test_op_roll() {
6593 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
6595 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6596 assert!(!result); assert_eq!(stack.len(), 3);
6598 assert_eq!(stack[0].as_ref(), &[1]);
6599 assert_eq!(stack[1].as_ref(), &[3]);
6600 assert_eq!(stack[2].as_ref(), &[2]); }
6602
6603 #[test]
6604 fn test_op_roll_zero_n() {
6605 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
6608 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6609 assert!(result); assert_eq!(stack.len(), 1);
6611 assert_eq!(stack[0].as_ref(), &[1]);
6612 }
6613
6614 #[test]
6615 fn test_op_roll_invalid_index() {
6616 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
6618 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6619 assert!(!result);
6620 assert_eq!(stack.len(), 1);
6621 }
6622
6623 #[test]
6624 fn test_op_rot() {
6625 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
6627 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6628 assert!(!result); assert_eq!(stack.len(), 3);
6630 assert_eq!(stack[0].as_ref(), &[2]);
6631 assert_eq!(stack[1].as_ref(), &[3]);
6632 assert_eq!(stack[2].as_ref(), &[1]);
6633 }
6634
6635 #[test]
6636 fn test_op_rot_insufficient_stack() {
6637 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
6639 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6640 assert!(!result);
6641 assert_eq!(stack.len(), 2);
6642 }
6643
6644 #[test]
6645 fn test_op_swap() {
6646 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
6648 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6649 assert!(!result); assert_eq!(stack.len(), 2);
6651 assert_eq!(stack[0].as_ref(), &[2]);
6652 assert_eq!(stack[1].as_ref(), &[1]);
6653 }
6654
6655 #[test]
6656 fn test_op_swap_insufficient_stack() {
6657 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
6659 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6660 assert!(!result);
6661 assert_eq!(stack.len(), 1);
6662 }
6663
6664 #[test]
6665 fn test_op_tuck() {
6666 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
6668 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6669 assert!(!result); assert_eq!(stack.len(), 3);
6671 assert_eq!(stack[0].as_ref(), &[2]);
6672 assert_eq!(stack[1].as_ref(), &[1]);
6673 assert_eq!(stack[2].as_ref(), &[2]);
6674 }
6675
6676 #[test]
6677 fn test_op_tuck_insufficient_stack() {
6678 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
6680 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6681 assert!(!result);
6682 assert_eq!(stack.len(), 1);
6683 }
6684
6685 #[test]
6686 fn test_op_2drop() {
6687 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
6689 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6690 assert!(result); assert_eq!(stack.len(), 1);
6692 assert_eq!(stack[0].as_ref(), &[1]);
6693 }
6694
6695 #[test]
6696 fn test_op_2drop_insufficient_stack() {
6697 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
6699 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6700 assert!(!result);
6701 assert_eq!(stack.len(), 1);
6702 }
6703
6704 #[test]
6705 fn test_op_2dup() {
6706 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
6708 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6709 assert!(!result); assert_eq!(stack.len(), 4);
6711 assert_eq!(stack[0].as_ref(), &[1]);
6712 assert_eq!(stack[1].as_ref(), &[2]);
6713 assert_eq!(stack[2].as_ref(), &[1]);
6714 assert_eq!(stack[3].as_ref(), &[2]);
6715 }
6716
6717 #[test]
6718 fn test_op_2dup_insufficient_stack() {
6719 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
6721 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6722 assert!(!result);
6723 assert_eq!(stack.len(), 1);
6724 }
6725
6726 #[test]
6727 fn test_op_3dup() {
6728 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
6730 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6731 assert!(!result); assert_eq!(stack.len(), 6);
6733 assert_eq!(stack[0].as_ref(), &[1]);
6734 assert_eq!(stack[1].as_ref(), &[2]);
6735 assert_eq!(stack[2].as_ref(), &[3]);
6736 assert_eq!(stack[3].as_ref(), &[1]);
6737 assert_eq!(stack[4].as_ref(), &[2]);
6738 assert_eq!(stack[5].as_ref(), &[3]);
6739 }
6740
6741 #[test]
6742 fn test_op_3dup_insufficient_stack() {
6743 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
6745 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6746 assert!(!result);
6747 assert_eq!(stack.len(), 2);
6748 }
6749
6750 #[test]
6751 fn test_op_2over() {
6752 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
6754 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6755 assert!(!result); assert_eq!(stack.len(), 6);
6757 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
6759 }
6760
6761 #[test]
6762 fn test_op_2over_insufficient_stack() {
6763 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
6765 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6766 assert!(!result);
6767 assert_eq!(stack.len(), 3);
6768 }
6769
6770 #[test]
6771 fn test_op_2rot() {
6772 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
6774 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6775 assert!(!result); assert_eq!(stack.len(), 6);
6777 assert_eq!(stack[4].as_ref(), &[2]); assert_eq!(stack[5].as_ref(), &[1]);
6779 }
6780
6781 #[test]
6782 fn test_op_2rot_insufficient_stack() {
6783 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
6785 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6786 assert!(!result);
6787 assert_eq!(stack.len(), 4);
6788 }
6789
6790 #[test]
6791 fn test_op_2swap() {
6792 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
6794 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6795 assert!(!result); assert_eq!(stack.len(), 4);
6797 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
6799 assert_eq!(stack[2].as_ref(), &[1]);
6800 assert_eq!(stack[3].as_ref(), &[2]);
6801 }
6802
6803 #[test]
6804 fn test_op_2swap_insufficient_stack() {
6805 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
6807 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6808 assert!(!result);
6809 assert_eq!(stack.len(), 3);
6810 }
6811
6812 #[test]
6813 fn test_op_size() {
6814 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
6816 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6817 assert!(!result); assert_eq!(stack.len(), 2);
6819 assert_eq!(stack[0].as_ref(), &[1]);
6820 assert_eq!(stack[1].as_ref(), &[1]); }
6822
6823 #[test]
6824 fn test_op_size_empty_stack() {
6825 let script = vec![OP_SIZE]; let mut stack = Vec::new();
6827 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6828 assert!(!result);
6829 assert_eq!(stack.len(), 0);
6830 }
6831
6832 #[test]
6833 fn test_op_return() {
6834 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
6836 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6837 assert!(!result); assert_eq!(stack.len(), 1);
6839 }
6840
6841 #[test]
6842 fn test_op_checksigverify() {
6843 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6845 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6846 assert!(!result); assert_eq!(stack.len(), 0);
6848 }
6849
6850 #[test]
6851 fn test_op_checksigverify_insufficient_stack() {
6852 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6854 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6855 assert!(!result);
6856 assert_eq!(stack.len(), 1);
6857 }
6858
6859 #[test]
6860 fn test_unknown_opcode_comprehensive() {
6861 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
6863 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6864 assert!(!result); assert_eq!(stack.len(), 1);
6866 }
6867
6868 #[test]
6869 fn test_verify_signature_invalid_pubkey() {
6870 let secp = signature::new_secp();
6871 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
6874 let result = signature::verify_signature(
6875 &secp,
6876 &invalid_pubkey,
6877 &signature,
6878 &dummy_hash,
6879 0,
6880 0,
6881 crate::types::Network::Regtest,
6882 SigVersion::Base,
6883 );
6884 assert!(!result.unwrap_or(false));
6885 }
6886
6887 #[test]
6888 fn test_verify_signature_invalid_signature() {
6889 let secp = signature::new_secp();
6890 let pubkey = vec![
6891 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
6892 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
6893 0x5b, 0x16, 0xf8, 0x17, 0x98,
6894 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
6897 let result = signature::verify_signature(
6898 &secp,
6899 &pubkey,
6900 &invalid_signature,
6901 &dummy_hash,
6902 0,
6903 0,
6904 crate::types::Network::Regtest,
6905 SigVersion::Base,
6906 );
6907 assert!(!result.unwrap_or(false));
6908 }
6909
6910 fn minimal_tx_and_prevouts(
6916 script_sig: &[u8],
6917 script_pubkey: &[u8],
6918 ) -> (
6919 crate::types::Transaction,
6920 Vec<i64>,
6921 Vec<crate::types::ByteString>,
6922 ) {
6923 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
6924 let tx = Transaction {
6925 version: 1,
6926 inputs: vec![TransactionInput {
6927 prevout: OutPoint {
6928 hash: [0u8; 32],
6929 index: 0,
6930 },
6931 sequence: 0xffff_ffff,
6932 script_sig: script_sig.to_vec(),
6933 }]
6934 .into(),
6935 outputs: vec![TransactionOutput {
6936 value: 0,
6937 script_pubkey: script_pubkey.to_vec(),
6938 }]
6939 .into(),
6940 lock_time: 0,
6941 };
6942 let prevout_values = vec![0i64];
6943 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
6944 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
6945 (tx, prevout_values, prevout_script_pubkeys_vec)
6946 }
6947
6948 #[test]
6949 fn test_verify_with_context_p2pkh_hash_mismatch() {
6950 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
6954 script_sig.push(sig.len() as u8);
6955 script_sig.extend(&sig);
6956 script_sig.push(pubkey.len() as u8);
6957 script_sig.extend(&pubkey);
6958
6959 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
6960 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
6962 script_pubkey.push(OP_CHECKSIG);
6963
6964 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
6965 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
6966 let result = verify_script_with_context_full(
6967 &script_sig,
6968 &script_pubkey,
6969 None,
6970 0,
6971 &tx,
6972 0,
6973 &pv,
6974 &psp_refs,
6975 Some(500_000),
6976 None,
6977 crate::types::Network::Mainnet,
6978 SigVersion::Base,
6979 #[cfg(feature = "production")]
6980 None,
6981 None, #[cfg(feature = "production")]
6983 None,
6984 #[cfg(feature = "production")]
6985 None,
6986 #[cfg(feature = "production")]
6987 None,
6988 );
6989 assert!(result.is_ok());
6990 assert!(!result.unwrap());
6991 }
6992
6993 #[test]
6994 fn test_verify_with_context_p2sh_hash_mismatch() {
6995 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
6998 script_sig.push(redeem.len() as u8);
6999 script_sig.extend(&redeem);
7000
7001 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7002 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7004
7005 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7006 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7007 let result = verify_script_with_context_full(
7008 &script_sig,
7009 &script_pubkey,
7010 None,
7011 0x01, &tx,
7013 0,
7014 &pv,
7015 &psp_refs,
7016 Some(500_000),
7017 None,
7018 crate::types::Network::Mainnet,
7019 SigVersion::Base,
7020 #[cfg(feature = "production")]
7021 None,
7022 None, #[cfg(feature = "production")]
7024 None,
7025 #[cfg(feature = "production")]
7026 None,
7027 #[cfg(feature = "production")]
7028 None,
7029 );
7030 assert!(result.is_ok());
7031 assert!(!result.unwrap());
7032 }
7033
7034 #[test]
7035 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7036 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7038 script_pubkey.extend(&[0u8; 20]);
7039 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7041 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7042 let empty: Vec<u8> = vec![];
7043 let result = verify_script_with_context_full(
7044 &empty,
7045 &script_pubkey,
7046 Some(&witness),
7047 0,
7048 &tx,
7049 0,
7050 &pv,
7051 &psp_refs,
7052 Some(500_000),
7053 None,
7054 crate::types::Network::Mainnet,
7055 SigVersion::Base,
7056 #[cfg(feature = "production")]
7057 None,
7058 None, #[cfg(feature = "production")]
7060 None,
7061 #[cfg(feature = "production")]
7062 None,
7063 #[cfg(feature = "production")]
7064 None,
7065 );
7066 assert!(result.is_ok());
7067 assert!(!result.unwrap());
7068 }
7069
7070 #[test]
7071 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7072 let witness_script = vec![OP_1];
7074 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7075 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7077 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7078 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7079 let empty: Vec<u8> = vec![];
7080 let result = verify_script_with_context_full(
7081 &empty,
7082 &script_pubkey,
7083 Some(&witness),
7084 0,
7085 &tx,
7086 0,
7087 &pv,
7088 &psp_refs,
7089 Some(500_000),
7090 None,
7091 crate::types::Network::Mainnet,
7092 SigVersion::Base,
7093 #[cfg(feature = "production")]
7094 None,
7095 None, #[cfg(feature = "production")]
7097 None,
7098 #[cfg(feature = "production")]
7099 None,
7100 #[cfg(feature = "production")]
7101 None,
7102 );
7103 assert!(result.is_ok());
7104 assert!(!result.unwrap());
7105 }
7106
7107 #[test]
7108 #[cfg(feature = "production")]
7109 fn test_p2wsh_multisig_fast_path() {
7110 use crate::constants::BIP147_ACTIVATION_MAINNET;
7112 use crate::crypto::OptimizedSha256;
7113
7114 let pk1 = [0x02u8; 33];
7115 let pk2 = [0x03u8; 33];
7116 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7118 witness_script.extend_from_slice(&pk2);
7119 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7123 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7124 script_pubkey.extend_from_slice(&wsh_hash);
7125
7126 let witness: Vec<Vec<u8>> = vec![
7127 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7131 ];
7132
7133 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7134 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7135 let empty: Vec<u8> = vec![];
7136 let result = verify_script_with_context_full(
7137 &empty,
7138 &script_pubkey,
7139 Some(&witness),
7140 0x810, &tx,
7142 0,
7143 &pv,
7144 &psp_refs,
7145 Some(BIP147_ACTIVATION_MAINNET + 1),
7146 None,
7147 crate::types::Network::Mainnet,
7148 SigVersion::Base,
7149 #[cfg(feature = "production")]
7150 None,
7151 None, #[cfg(feature = "production")]
7153 None,
7154 #[cfg(feature = "production")]
7155 None,
7156 #[cfg(feature = "production")]
7157 None,
7158 );
7159 assert!(result.is_ok());
7160 assert!(!result.unwrap());
7161 }
7162}
7163
7164#[cfg(test)]
7165#[allow(unused_doc_comments)]
7166mod property_tests {
7167 use super::*;
7168 use proptest::prelude::*;
7169
7170 proptest! {
7175 #[test]
7176 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7177 let mut stack = Vec::new();
7178 let flags = 0u32;
7179
7180 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7181
7182 if script.len() > MAX_SCRIPT_OPS * 2 {
7190 prop_assert!(result.is_err() || !result.unwrap(),
7193 "Very long scripts should fail or return false");
7194 }
7195 }
7197 }
7198
7199 proptest! {
7204 #[test]
7205 fn prop_verify_script_deterministic(
7206 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7207 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7208 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7209 flags in any::<u32>()
7210 ) {
7211 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7212 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7213
7214 assert_eq!(result1.is_ok(), result2.is_ok());
7215 if result1.is_ok() && result2.is_ok() {
7216 assert_eq!(result1.unwrap(), result2.unwrap());
7217 }
7218 }
7219 }
7220
7221 proptest! {
7226 #[test]
7227 fn prop_execute_opcode_no_panic(
7228 opcode in any::<u8>(),
7229 stack_items in prop::collection::vec(
7230 prop::collection::vec(any::<u8>(), 0..5),
7231 0..10
7232 ),
7233 flags in any::<u32>()
7234 ) {
7235 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7236 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7237
7238 match result {
7241 Ok(success) => {
7242 let _ = success;
7244 },
7245 Err(_) => {
7246 }
7249 }
7250
7251 assert!(stack.len() <= MAX_STACK_SIZE);
7253 }
7254 }
7255
7256 proptest! {
7263 #[test]
7264 fn prop_stack_operations_bounds(
7265 opcode in any::<u8>(),
7266 stack_items in prop::collection::vec(
7267 prop::collection::vec(any::<u8>(), 0..3),
7268 0..5
7269 ),
7270 flags in any::<u32>()
7271 ) {
7272 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7273 let initial_len = stack.len();
7274
7275 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7276
7277 assert!(stack.len() <= MAX_STACK_SIZE);
7279
7280 if result.is_ok() && result.unwrap() {
7282 match opcode {
7284 OP_0 | OP_1..=OP_16 => {
7285 assert!(stack.len() == initial_len + 1);
7287 },
7288 OP_DUP => {
7289 if initial_len > 0 {
7291 assert!(stack.len() == initial_len + 1);
7292 }
7293 },
7294 OP_3DUP => {
7295 if initial_len >= 3 {
7297 assert!(stack.len() == initial_len + 3);
7298 }
7299 },
7300 OP_2OVER => {
7301 if initial_len >= 4 {
7303 assert!(stack.len() == initial_len + 2);
7304 }
7305 },
7306 OP_DROP | OP_NIP | OP_2DROP => {
7307 assert!(stack.len() <= initial_len);
7309 },
7310 _ => {
7311 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7314 }
7315 }
7316 }
7317 }
7318 }
7319
7320 proptest! {
7325 #[test]
7326 fn prop_hash_operations_deterministic(
7327 input in prop::collection::vec(any::<u8>(), 0..10)
7328 ) {
7329 let elem = to_stack_element(&input);
7330 let mut stack1 = vec![elem.clone()];
7331 let mut stack2 = vec![elem];
7332
7333 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());
7337 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7338 assert_eq!(val1, val2);
7339 if val1 {
7340 assert_eq!(stack1, stack2);
7341 }
7342 }
7343 }
7344 }
7345
7346 proptest! {
7351 #[test]
7352 fn prop_equality_operations_symmetric(
7353 a in prop::collection::vec(any::<u8>(), 0..5),
7354 b in prop::collection::vec(any::<u8>(), 0..5)
7355 ) {
7356 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7357 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7358
7359 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());
7363 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7364 assert_eq!(val1, val2);
7365 if val1 {
7366 assert_eq!(stack1.len(), stack2.len());
7368 if !stack1.is_empty() && !stack2.is_empty() {
7369 assert_eq!(stack1[0], stack2[0]);
7370 }
7371 }
7372 }
7373 }
7374 }
7375
7376 proptest! {
7381 #[test]
7382 fn prop_script_execution_terminates(
7383 script in prop::collection::vec(any::<u8>(), 0..50)
7384 ) {
7385 let mut stack = Vec::new();
7386 let flags = 0u32;
7387
7388 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7390
7391 assert!(result.is_ok() || result.is_err());
7393
7394 assert!(stack.len() <= MAX_STACK_SIZE);
7396 }
7397 }
7398}