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