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 if !control_stack.is_empty() {
3701 return Err(ConsensusError::ScriptErrorWithCode {
3702 code: ScriptErrorCode::UnbalancedConditional,
3703 message: "Unclosed IF/NOTIF block".into(),
3704 });
3705 }
3706
3707 Ok(true)
3711}
3712
3713#[spec_locked("5.4.5")]
3717#[cfg(feature = "production")]
3718#[inline(always)]
3719pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3720 if data.len() > max_num_size {
3721 return Err(ConsensusError::ScriptErrorWithCode {
3722 code: ScriptErrorCode::InvalidStackOperation,
3723 message: format!(
3724 "Script number overflow: {} > {} bytes",
3725 data.len(),
3726 max_num_size
3727 )
3728 .into(),
3729 });
3730 }
3731 if data.is_empty() {
3732 return Ok(0);
3733 }
3734
3735 let len = data.len();
3737 let result = match len {
3738 1 => {
3739 let byte = data[0];
3740 if byte & 0x80 != 0 {
3741 -((byte & 0x7f) as i64)
3743 } else {
3744 byte as i64
3745 }
3746 }
3747 2 => {
3748 let byte0 = data[0] as i64;
3749 let byte1 = data[1] as i64;
3750 let value = byte0 | (byte1 << 8);
3751 if byte1 & 0x80 != 0 {
3752 -(value & !(0x80i64 << 8))
3754 } else {
3755 value
3756 }
3757 }
3758 _ => {
3759 let mut result: i64 = 0;
3761 for (i, &byte) in data.iter().enumerate() {
3762 result |= (byte as i64) << (8 * i);
3763 }
3764 let last_idx = len - 1;
3766 if data[last_idx] & 0x80 != 0 {
3767 result &= !(0x80i64 << (8 * last_idx));
3769 result = -result;
3770 }
3771 result
3772 }
3773 };
3774
3775 Ok(result)
3776}
3777
3778#[cfg(not(feature = "production"))]
3779#[inline]
3780pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3781 if data.len() > max_num_size {
3782 return Err(ConsensusError::ScriptErrorWithCode {
3783 code: ScriptErrorCode::InvalidStackOperation,
3784 message: format!(
3785 "Script number overflow: {} > {} bytes",
3786 data.len(),
3787 max_num_size
3788 )
3789 .into(),
3790 });
3791 }
3792 if data.is_empty() {
3793 return Ok(0);
3794 }
3795 let mut result: i64 = 0;
3797 for (i, &byte) in data.iter().enumerate() {
3798 result |= (byte as i64) << (8 * i);
3799 }
3800 if data.last().expect("Data is not empty") & 0x80 != 0 {
3802 result &= !(0x80i64 << (8 * (data.len() - 1)));
3804 result = -result;
3805 }
3806 Ok(result)
3807}
3808
3809#[cfg(feature = "production")]
3812pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3813 match value {
3815 0 => return vec![],
3816 1 => return vec![1],
3817 -1 => return vec![0x81],
3818 _ => {}
3819 }
3820
3821 let neg = value < 0;
3822 let mut absvalue = if neg {
3823 (-(value as i128)) as u64
3824 } else {
3825 value as u64
3826 };
3827 let mut result = Vec::with_capacity(4);
3829 while absvalue > 0 {
3830 result.push((absvalue & 0xff) as u8);
3831 absvalue >>= 8;
3832 }
3833 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3835 result.push(if neg { 0x80 } else { 0x00 });
3836 } else if neg {
3837 *result.last_mut().unwrap() |= 0x80;
3838 }
3839 result
3840}
3841
3842#[cfg(not(feature = "production"))]
3843pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3844 if value == 0 {
3845 return vec![];
3846 }
3847 let neg = value < 0;
3848 let mut absvalue = if neg {
3849 (-(value as i128)) as u64
3850 } else {
3851 value as u64
3852 };
3853 let mut result = Vec::new();
3854 while absvalue > 0 {
3855 result.push((absvalue & 0xff) as u8);
3856 absvalue >>= 8;
3857 }
3858 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3860 result.push(if neg { 0x80 } else { 0x00 });
3861 } else if neg {
3862 *result.last_mut().unwrap() |= 0x80;
3863 }
3864 result
3865}
3866
3867#[cfg(feature = "production")]
3869#[inline(always)]
3870fn execute_opcode(
3871 opcode: u8,
3872 stack: &mut Vec<StackElement>,
3873 flags: u32,
3874 _sigversion: SigVersion,
3875) -> Result<bool> {
3876 match opcode {
3877 OP_0 => {
3879 stack.push(to_stack_element(&[]));
3880 Ok(true)
3881 }
3882
3883 OP_1..=OP_16 => {
3885 let num = opcode - OP_N_BASE;
3886 stack.push(to_stack_element(&[num]));
3887 Ok(true)
3888 }
3889
3890 OP_NOP => Ok(true),
3892
3893 OP_VER => Ok(false),
3895
3896 OP_DEPTH => {
3898 let depth = stack.len() as i64;
3899 stack.push(to_stack_element(&script_num_encode(depth)));
3900 Ok(true)
3901 }
3902
3903 OP_DUP => {
3905 if let Some(item) = stack.last().cloned() {
3906 stack.push(item);
3907 Ok(true)
3908 } else {
3909 Ok(false)
3910 }
3911 }
3912
3913 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
3915
3916 OP_SHA1 => crypto_ops::op_sha1(stack),
3918
3919 OP_SHA256 => crypto_ops::op_sha256(stack),
3921
3922 OP_HASH160 => crypto_ops::op_hash160(stack),
3924
3925 OP_HASH256 => crypto_ops::op_hash256(stack),
3927
3928 OP_EQUAL => {
3930 if stack.len() < 2 {
3931 return Err(ConsensusError::ScriptErrorWithCode {
3932 code: ScriptErrorCode::InvalidStackOperation,
3933 message: "OP_EQUAL: insufficient stack items".into(),
3934 });
3935 }
3936 let a = stack.pop().unwrap();
3937 let b = stack.pop().unwrap();
3938 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3939 Ok(true)
3940 }
3941
3942 OP_EQUALVERIFY => {
3945 if stack.len() < 2 {
3946 return Err(ConsensusError::ScriptErrorWithCode {
3947 code: ScriptErrorCode::InvalidStackOperation,
3948 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3949 });
3950 }
3951 let a = stack.pop().unwrap();
3952 let b = stack.pop().unwrap();
3953 let f_equal = a == b;
3954 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
3956 if f_equal {
3957 stack.pop();
3959 Ok(true)
3960 } else {
3961 Err(ConsensusError::ScriptErrorWithCode {
3962 code: ScriptErrorCode::EqualVerify,
3963 message: "OP_EQUALVERIFY: stack items not equal".into(),
3964 })
3965 }
3966 }
3967
3968 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
3970
3971 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
3973
3974 OP_RETURN => Ok(false),
3976
3977 OP_VERIFY => {
3979 if let Some(item) = stack.pop() {
3980 Ok(cast_to_bool(&item))
3981 } else {
3982 Ok(false)
3983 }
3984 }
3985
3986 OP_CHECKLOCKTIMEVERIFY => {
3990 Ok(false)
3993 }
3994
3995 OP_CHECKSEQUENCEVERIFY => {
3999 Ok(false)
4002 }
4003
4004 OP_IFDUP => {
4006 if let Some(item) = stack.last().cloned() {
4007 if cast_to_bool(&item) {
4008 stack.push(item);
4009 }
4010 Ok(true)
4011 } else {
4012 Ok(false)
4013 }
4014 }
4015
4016 OP_DROP => {
4019 if stack.pop().is_some() {
4020 Ok(true)
4021 } else {
4022 Ok(false)
4023 }
4024 }
4025
4026 OP_NIP => {
4028 if stack.len() >= 2 {
4029 let top = stack.pop().unwrap();
4030 stack.pop(); stack.push(top);
4032 Ok(true)
4033 } else {
4034 Ok(false)
4035 }
4036 }
4037
4038 OP_OVER => {
4040 if stack.len() >= 2 {
4041 let len = stack.len();
4042 #[cfg(feature = "production")]
4043 {
4044 unsafe {
4046 let second = stack.get_unchecked(len - 2);
4047 stack.push(second.clone());
4048 }
4049 }
4050 #[cfg(not(feature = "production"))]
4051 {
4052 let second = stack[stack.len() - 2].clone();
4053 stack.push(second);
4054 }
4055 Ok(true)
4056 } else {
4057 Ok(false)
4058 }
4059 }
4060
4061 OP_PICK => {
4063 if let Some(n_bytes) = stack.pop() {
4064 let n_val = script_num_decode(&n_bytes, 4)?;
4067 if n_val < 0 || n_val as usize >= stack.len() {
4068 return Ok(false);
4069 }
4070 let n = n_val as usize;
4071 let len = stack.len();
4072 #[cfg(feature = "production")]
4073 {
4074 unsafe {
4076 let item = stack.get_unchecked(len - 1 - n);
4077 stack.push(item.clone());
4078 }
4079 }
4080 #[cfg(not(feature = "production"))]
4081 {
4082 let item = stack[stack.len() - 1 - n].clone();
4083 stack.push(item);
4084 }
4085 Ok(true)
4086 } else {
4087 Ok(false)
4088 }
4089 }
4090
4091 OP_ROLL => {
4093 if let Some(n_bytes) = stack.pop() {
4094 let n_val = script_num_decode(&n_bytes, 4)?;
4097 if n_val < 0 || n_val as usize >= stack.len() {
4098 return Ok(false);
4099 }
4100 let n = n_val as usize;
4101 let len = stack.len();
4102 #[cfg(feature = "production")]
4103 {
4104 let idx = len - 1 - n;
4106 let item = stack.remove(idx);
4107 stack.push(item);
4108 }
4109 #[cfg(not(feature = "production"))]
4110 {
4111 let item = stack.remove(stack.len() - 1 - n);
4112 stack.push(item);
4113 }
4114 Ok(true)
4115 } else {
4116 Ok(false)
4117 }
4118 }
4119
4120 OP_ROT => {
4122 if stack.len() >= 3 {
4123 let top = stack.pop().unwrap();
4124 let second = stack.pop().unwrap();
4125 let third = stack.pop().unwrap();
4126 stack.push(second);
4127 stack.push(top);
4128 stack.push(third);
4129 Ok(true)
4130 } else {
4131 Ok(false)
4132 }
4133 }
4134
4135 OP_SWAP => {
4137 if stack.len() >= 2 {
4138 let top = stack.pop().unwrap();
4139 let second = stack.pop().unwrap();
4140 stack.push(top);
4141 stack.push(second);
4142 Ok(true)
4143 } else {
4144 Ok(false)
4145 }
4146 }
4147
4148 OP_TUCK => {
4150 if stack.len() >= 2 {
4151 let top = stack.pop().unwrap();
4152 let second = stack.pop().unwrap();
4153 stack.push(top.clone());
4154 stack.push(second);
4155 stack.push(top);
4156 Ok(true)
4157 } else {
4158 Ok(false)
4159 }
4160 }
4161
4162 OP_2DROP => {
4164 if stack.len() >= 2 {
4165 stack.pop();
4166 stack.pop();
4167 Ok(true)
4168 } else {
4169 Ok(false)
4170 }
4171 }
4172
4173 OP_2DUP => {
4175 if stack.len() >= 2 {
4176 let top = stack[stack.len() - 1].clone();
4177 let second = stack[stack.len() - 2].clone();
4178 stack.push(second);
4179 stack.push(top);
4180 Ok(true)
4181 } else {
4182 Ok(false)
4183 }
4184 }
4185
4186 OP_3DUP => {
4188 if stack.len() >= 3 {
4189 let top = stack[stack.len() - 1].clone();
4190 let second = stack[stack.len() - 2].clone();
4191 let third = stack[stack.len() - 3].clone();
4192 stack.push(third);
4193 stack.push(second);
4194 stack.push(top);
4195 Ok(true)
4196 } else {
4197 Ok(false)
4198 }
4199 }
4200
4201 OP_2OVER => {
4203 if stack.len() >= 4 {
4204 let fourth = stack[stack.len() - 4].clone();
4205 let third = stack[stack.len() - 3].clone();
4206 stack.push(fourth);
4207 stack.push(third);
4208 Ok(true)
4209 } else {
4210 Ok(false)
4211 }
4212 }
4213
4214 OP_2ROT => {
4216 if stack.len() >= 6 {
4217 let sixth = stack.remove(stack.len() - 6);
4218 let fifth = stack.remove(stack.len() - 5);
4219 stack.push(fifth);
4220 stack.push(sixth);
4221 Ok(true)
4222 } else {
4223 Ok(false)
4224 }
4225 }
4226
4227 OP_2SWAP => {
4229 if stack.len() >= 4 {
4230 let top = stack.pop().unwrap();
4231 let second = stack.pop().unwrap();
4232 let third = stack.pop().unwrap();
4233 let fourth = stack.pop().unwrap();
4234 stack.push(second);
4235 stack.push(top);
4236 stack.push(fourth);
4237 stack.push(third);
4238 Ok(true)
4239 } else {
4240 Ok(false)
4241 }
4242 }
4243
4244 OP_SIZE => {
4247 if let Some(item) = stack.last() {
4248 let size = item.len() as i64;
4249 stack.push(to_stack_element(&script_num_encode(size)));
4250 Ok(true)
4251 } else {
4252 Ok(false)
4253 }
4254 }
4255
4256 OP_1ADD => {
4261 if let Some(item) = stack.pop() {
4262 let a = script_num_decode(&item, 4)?;
4263 stack.push(to_stack_element(&script_num_encode(a + 1)));
4264 Ok(true)
4265 } else {
4266 Ok(false)
4267 }
4268 }
4269 OP_1SUB => {
4271 if let Some(item) = stack.pop() {
4272 let a = script_num_decode(&item, 4)?;
4273 stack.push(to_stack_element(&script_num_encode(a - 1)));
4274 Ok(true)
4275 } else {
4276 Ok(false)
4277 }
4278 }
4279 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4281 code: ScriptErrorCode::DisabledOpcode,
4282 message: "OP_2MUL is disabled".into(),
4283 }),
4284 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4286 code: ScriptErrorCode::DisabledOpcode,
4287 message: "OP_2DIV is disabled".into(),
4288 }),
4289 OP_NEGATE => {
4291 if let Some(item) = stack.pop() {
4292 let a = script_num_decode(&item, 4)?;
4293 stack.push(to_stack_element(&script_num_encode(-a)));
4294 Ok(true)
4295 } else {
4296 Ok(false)
4297 }
4298 }
4299 OP_ABS => {
4301 if let Some(item) = stack.pop() {
4302 let a = script_num_decode(&item, 4)?;
4303 stack.push(to_stack_element(&script_num_encode(a.abs())));
4304 Ok(true)
4305 } else {
4306 Ok(false)
4307 }
4308 }
4309 OP_NOT => {
4311 if let Some(item) = stack.pop() {
4312 let a = script_num_decode(&item, 4)?;
4313 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4314 1
4315 } else {
4316 0
4317 })));
4318 Ok(true)
4319 } else {
4320 Ok(false)
4321 }
4322 }
4323 OP_0NOTEQUAL => {
4325 if let Some(item) = stack.pop() {
4326 let a = script_num_decode(&item, 4)?;
4327 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4328 1
4329 } else {
4330 0
4331 })));
4332 Ok(true)
4333 } else {
4334 Ok(false)
4335 }
4336 }
4337 OP_ADD => arithmetic::op_add(stack),
4338 OP_SUB => arithmetic::op_sub(stack),
4339 OP_MUL => arithmetic::op_mul_disabled(),
4340 OP_DIV => arithmetic::op_div_disabled(),
4341 OP_MOD => arithmetic::op_mod_disabled(),
4342 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4343 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4344 OP_BOOLAND => arithmetic::op_booland(stack),
4345 OP_BOOLOR => arithmetic::op_boolor(stack),
4346 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4347 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4348 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4349 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4350 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4351 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4352 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4353 OP_MIN => arithmetic::op_min(stack),
4354 OP_MAX => arithmetic::op_max(stack),
4355 OP_WITHIN => arithmetic::op_within(stack),
4356
4357 OP_CODESEPARATOR => Ok(true),
4359
4360 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4363
4364 OP_CHECKTEMPLATEVERIFY => {
4366 #[cfg(not(feature = "ctv"))]
4367 {
4368 Ok(true)
4370 }
4371
4372 #[cfg(feature = "ctv")]
4373 {
4374 return Err(ConsensusError::ScriptErrorWithCode {
4376 code: ScriptErrorCode::TxInvalid,
4377 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4378 });
4379 }
4380 }
4381
4382 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4384 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4385 Err(ConsensusError::ScriptErrorWithCode {
4386 code: ScriptErrorCode::DisabledOpcode,
4387 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4388 })
4389 }
4390
4391 _ => Ok(false),
4393 }
4394}
4395
4396#[allow(dead_code)]
4398fn execute_opcode_with_context(
4399 opcode: u8,
4400 stack: &mut Vec<StackElement>,
4401 flags: u32,
4402 tx: &Transaction,
4403 input_index: usize,
4404 prevouts: &[TransactionOutput],
4405 network: crate::types::Network,
4406) -> Result<bool> {
4407 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4409 let prevout_script_pubkeys: Vec<&[u8]> =
4410 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4411 let ctx = context::ScriptContext {
4412 tx,
4413 input_index,
4414 prevout_values: &prevout_values,
4415 prevout_script_pubkeys: &prevout_script_pubkeys,
4416 block_height: None,
4417 median_time_past: None,
4418 network,
4419 sigversion: SigVersion::Base,
4420 redeem_script_for_sighash: None,
4421 script_sig_for_sighash: None,
4422 tapscript_for_sighash: None,
4423 tapscript_codesep_pos: None,
4424 #[cfg(feature = "production")]
4425 schnorr_collector: None,
4426 #[cfg(feature = "production")]
4427 precomputed_bip143: None,
4428 #[cfg(feature = "production")]
4429 sighash_cache: None,
4430 };
4431 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4432}
4433
4434#[cfg(feature = "production")]
4438#[inline(always)]
4439pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4440 let mut i = 0;
4441 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4442 i += adv1;
4443 if i >= script_sig.len() {
4444 return None;
4445 }
4446 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4447 i += adv2;
4448 if i >= script_sig.len() {
4449 return None;
4450 }
4451 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4452 i += adv3;
4453 if i != script_sig.len() {
4454 return None;
4455 }
4456 let sig = &script_sig[s_start..s_end];
4457 let redeem = &script_sig[r_start..r_end];
4458 if sig.is_empty() || redeem.len() != 25 {
4459 return None;
4460 }
4461 if redeem[0] != OP_DUP
4462 || redeem[1] != OP_HASH160
4463 || redeem[2] != PUSH_20_BYTES
4464 || redeem[23] != OP_EQUALVERIFY
4465 || redeem[24] != OP_CHECKSIG
4466 {
4467 return None;
4468 }
4469 Some((sig[sig.len() - 1], redeem))
4470}
4471
4472#[inline(always)]
4475pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4478 let mut i = 0;
4479 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4480 i += adv1;
4481 if i >= script_sig.len() {
4482 return None;
4483 }
4484 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4485 i += adv2;
4486 if i != script_sig.len() {
4487 return None;
4488 }
4489 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4490}
4491
4492pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4495 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4496 if advance != script_sig.len() {
4497 return None;
4498 }
4499 Some(&script_sig[data_start..data_end])
4500}
4501
4502fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4504 if i >= script.len() {
4505 return None;
4506 }
4507 let opcode = script[i];
4508 let (advance, data_start, data_end) = if opcode == OP_0 {
4509 return None;
4510 } else if opcode <= 0x4b {
4511 let len = opcode as usize;
4512 if i + 1 + len > script.len() {
4513 return None;
4514 }
4515 (1 + len, i + 1, i + 1 + len)
4516 } else if opcode == OP_PUSHDATA1 {
4517 if i + 1 >= script.len() {
4518 return None;
4519 }
4520 let len = script[i + 1] as usize;
4521 if i + 2 + len > script.len() {
4522 return None;
4523 }
4524 (2 + len, i + 2, i + 2 + len)
4525 } else if opcode == OP_PUSHDATA2 {
4526 if i + 2 >= script.len() {
4527 return None;
4528 }
4529 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4530 if i + 3 + len > script.len() {
4531 return None;
4532 }
4533 (3 + len, i + 3, i + 3 + len)
4534 } else if opcode == OP_PUSHDATA4 {
4535 if i + 4 >= script.len() {
4536 return None;
4537 }
4538 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4539 as usize;
4540 if i + 5 + len > script.len() {
4541 return None;
4542 }
4543 (5 + len, i + 5, i + 5 + len)
4544 } else {
4545 return None;
4546 };
4547 Some((advance, data_start, data_end))
4548}
4549
4550#[spec_locked("5.2.1")]
4553pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4554 parse_script_sig_push_only(script_sig).is_some()
4555}
4556
4557fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4561 let mut out = Vec::new();
4562 let mut i = 0;
4563 while i < script_sig.len() {
4564 let opcode = script_sig[i];
4565 if !is_push_opcode(opcode) {
4566 return None;
4567 }
4568 let (advance, data) = if opcode == OP_0 {
4569 (1, vec![])
4570 } else if opcode <= 0x4b {
4571 let len = opcode as usize;
4572 if i + 1 + len > script_sig.len() {
4573 return None;
4574 }
4575 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4576 } else if opcode == OP_PUSHDATA1 {
4577 if i + 1 >= script_sig.len() {
4578 return None;
4579 }
4580 let len = script_sig[i + 1] as usize;
4581 if i + 2 + len > script_sig.len() {
4582 return None;
4583 }
4584 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4585 } else if opcode == OP_PUSHDATA2 {
4586 if i + 2 >= script_sig.len() {
4587 return None;
4588 }
4589 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4590 if i + 3 + len > script_sig.len() {
4591 return None;
4592 }
4593 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4594 } else if opcode == OP_PUSHDATA4 {
4595 if i + 4 >= script_sig.len() {
4596 return None;
4597 }
4598 let len = u32::from_le_bytes([
4599 script_sig[i + 1],
4600 script_sig[i + 2],
4601 script_sig[i + 3],
4602 script_sig[i + 4],
4603 ]) as usize;
4604 if i + 5 + len > script_sig.len() {
4605 return None;
4606 }
4607 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4608 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4609 let n = script_num_from_opcode(opcode);
4611 (1, script_num_encode(n))
4612 } else {
4613 return None;
4614 };
4615 out.push(to_stack_element(&data));
4616 i += advance;
4617 }
4618 Some(out)
4619}
4620
4621fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4625 parse_script_sig_push_only(script_sig)
4626}
4627
4628fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4633 if redeem.len() < 4 {
4634 return None;
4635 }
4636 let n_op = redeem[0];
4637 if !(OP_1..=OP_16).contains(&n_op) {
4638 return None;
4639 }
4640 let n = (n_op - OP_1 + 1) as usize;
4641 let mut i = 1;
4642 let mut pubkeys = Vec::with_capacity(n);
4643 for _ in 0..n {
4644 if i >= redeem.len() {
4645 return None;
4646 }
4647 let first = redeem[i];
4648 let pk_len = if first == 0x02 || first == 0x03 {
4649 33
4650 } else if first == 0x04 {
4651 65
4652 } else {
4653 return None;
4654 };
4655 if i + pk_len > redeem.len() {
4656 return None;
4657 }
4658 pubkeys.push(&redeem[i..i + pk_len]);
4659 i += pk_len;
4660 }
4661 if i + 2 > redeem.len() {
4662 return None;
4663 }
4664 let m_op = redeem[i];
4665 if !(OP_1..=OP_16).contains(&m_op) {
4666 return None;
4667 }
4668 let m = m_op - OP_1 + 1;
4669 if redeem[i + 1] != OP_CHECKMULTISIG {
4670 return None;
4671 }
4672 Some((m, n as u8, pubkeys))
4673}
4674
4675fn script_num_from_opcode(opcode: u8) -> i64 {
4677 match opcode {
4678 OP_1NEGATE => -1,
4679 OP_1 => 1,
4680 OP_2 => 2,
4681 OP_3 => 3,
4682 OP_4 => 4,
4683 OP_5 => 5,
4684 OP_6 => 6,
4685 OP_7 => 7,
4686 OP_8 => 8,
4687 OP_9 => 9,
4688 OP_10 => 10,
4689 OP_11 => 11,
4690 OP_12 => 12,
4691 OP_13 => 13,
4692 OP_14 => 14,
4693 OP_15 => 15,
4694 OP_16 => 16,
4695 _ => 0,
4696 }
4697}
4698
4699pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
4703 let len = data.len();
4704 let mut result = Vec::with_capacity(len + 5);
4705 if len < 76 {
4706 result.push(len as u8);
4707 } else if len < 256 {
4708 result.push(OP_PUSHDATA1);
4709 result.push(len as u8);
4710 } else if len < 65536 {
4711 result.push(OP_PUSHDATA2);
4712 result.push((len & 0xff) as u8);
4713 result.push(((len >> 8) & 0xff) as u8);
4714 } else {
4715 result.push(OP_PUSHDATA4);
4716 result.push((len & 0xff) as u8);
4717 result.push(((len >> 8) & 0xff) as u8);
4718 result.push(((len >> 16) & 0xff) as u8);
4719 result.push(((len >> 24) & 0xff) as u8);
4720 }
4721 result.extend_from_slice(data);
4722 result
4723}
4724
4725#[inline]
4727fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
4728 if pc >= script.len() {
4729 return None;
4730 }
4731 let opcode = script[pc];
4732 let advance = if opcode <= 0x4b {
4733 1 + opcode as usize
4734 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
4735 2 + script[pc + 1] as usize
4736 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
4737 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
4738 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
4739 5 + ((script[pc + 1] as usize)
4740 | ((script[pc + 2] as usize) << 8)
4741 | ((script[pc + 3] as usize) << 16)
4742 | ((script[pc + 4] as usize) << 24))
4743 } else {
4744 1
4745 };
4746 let next = pc + advance;
4747 if next > script.len() {
4748 None
4749 } else {
4750 Some(next)
4751 }
4752}
4753
4754#[spec_locked("5.1.1")]
4760#[inline]
4761pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
4762 if pattern.is_empty() {
4763 return std::borrow::Cow::Borrowed(script);
4764 }
4765 let end = script.len();
4766 let mut n_found = 0usize;
4767 let mut result = Vec::new();
4768 let mut pc = 0usize;
4769 let mut pc2 = 0usize;
4770
4771 loop {
4772 result.extend_from_slice(&script[pc2..pc]);
4773 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
4774 pc += pattern.len();
4775 n_found += 1;
4776 }
4777 pc2 = pc;
4778 if pc >= end {
4779 break;
4780 }
4781 let Some(next_pc) = script_get_op_advance(script, pc) else {
4782 break;
4783 };
4784 pc = next_pc;
4785 }
4786
4787 if n_found > 0 {
4788 result.extend_from_slice(&script[pc2..end]);
4789 std::borrow::Cow::Owned(result)
4790 } else {
4791 std::borrow::Cow::Borrowed(script)
4792 }
4793}
4794
4795fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
4797 let mut pos = 0u32;
4798 let mut i = 0usize;
4799 while i < script.len() && i <= byte_index {
4800 let opcode = script[i];
4801 let advance = if opcode <= 0x4b {
4802 1 + opcode as usize
4803 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
4804 2 + script[i + 1] as usize
4805 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
4806 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
4807 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
4808 5 + ((script[i + 1] as usize)
4809 | ((script[i + 2] as usize) << 8)
4810 | ((script[i + 3] as usize) << 16)
4811 | ((script[i + 4] as usize) << 24))
4812 } else {
4813 1
4814 };
4815 if i == byte_index {
4816 return pos;
4817 }
4818 pos += 1;
4819 i = std::cmp::min(i + advance, script.len());
4820 }
4821 0xffff_ffff
4822}
4823
4824#[cfg_attr(feature = "production", inline(always))]
4826fn execute_opcode_with_context_full(
4827 opcode: u8,
4828 stack: &mut Vec<StackElement>,
4829 flags: u32,
4830 ctx: &context::ScriptContext<'_>,
4831 effective_script_code: Option<&[u8]>,
4832) -> Result<bool> {
4833 let tx = ctx.tx;
4834 let input_index = ctx.input_index;
4835 let prevout_values = ctx.prevout_values;
4836 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
4837 let block_height = ctx.block_height;
4838 let median_time_past = ctx.median_time_past;
4839 let network = ctx.network;
4840 let sigversion = ctx.sigversion;
4841 let script_sig_for_sighash = ctx.script_sig_for_sighash;
4842 let tapscript_for_sighash = ctx.tapscript_for_sighash;
4843 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
4844 let redeem_script_for_sighash = effective_script_code;
4845 #[cfg(feature = "production")]
4846 let schnorr_collector = ctx.schnorr_collector;
4847 #[cfg(feature = "production")]
4848 let precomputed_bip143 = ctx.precomputed_bip143;
4849 #[cfg(feature = "production")]
4850 let sighash_cache = ctx.sighash_cache;
4851
4852 match opcode {
4854 OP_CHECKSIG => {
4856 if stack.len() >= 2 {
4857 let pubkey_bytes = stack.pop().unwrap();
4858 let signature_bytes = stack.pop().unwrap();
4859
4860 if signature_bytes.is_empty() {
4862 stack.push(to_stack_element(&[0]));
4863 return Ok(true);
4864 }
4865
4866 if sigversion == SigVersion::Tapscript {
4869 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
4871 let sighash_byte = 0x00;
4872 let (tapscript, codesep_pos) = tapscript_for_sighash
4873 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
4874 .unwrap_or((&[] as &[u8], 0xffff_ffff));
4875 let sighash = if tapscript.is_empty() {
4876 crate::taproot::compute_taproot_signature_hash(
4877 tx,
4878 input_index,
4879 prevout_values,
4880 prevout_script_pubkeys,
4881 sighash_byte,
4882 )?
4883 } else {
4884 crate::taproot::compute_tapscript_signature_hash(
4885 tx,
4886 input_index,
4887 prevout_values,
4888 prevout_script_pubkeys,
4889 tapscript,
4890 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
4891 codesep_pos,
4892 sighash_byte,
4893 )?
4894 };
4895
4896 #[cfg(feature = "production")]
4898 let is_valid = {
4899 use crate::bip348::verify_tapscript_schnorr_signature;
4900 verify_tapscript_schnorr_signature(
4901 &sighash,
4902 &pubkey_bytes,
4903 &signature_bytes,
4904 schnorr_collector,
4905 )
4906 .unwrap_or(false)
4907 };
4908
4909 #[cfg(not(feature = "production"))]
4910 let is_valid = {
4911 #[cfg(feature = "csfs")]
4912 let x = {
4913 use crate::bip348::verify_tapscript_schnorr_signature;
4914 verify_tapscript_schnorr_signature(
4915 &sighash,
4916 &pubkey_bytes,
4917 &signature_bytes,
4918 None,
4919 )
4920 .unwrap_or(false)
4921 };
4922 #[cfg(not(feature = "csfs"))]
4923 let x = false;
4924 x
4925 };
4926
4927 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
4928 return Ok(true);
4929 }
4930 }
4932
4933 let sig_len = signature_bytes.len();
4937 let sighash_byte = signature_bytes[sig_len - 1];
4938 let _der_sig = &signature_bytes[..sig_len - 1];
4939
4940 let sighash = if sigversion == SigVersion::WitnessV0 {
4944 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
4946
4947 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
4949 prevout_script_pubkeys
4950 .get(input_index)
4951 .copied()
4952 .unwrap_or(&[])
4953 });
4954
4955 crate::transaction_hash::calculate_bip143_sighash(
4956 tx,
4957 input_index,
4958 script_code,
4959 amount,
4960 sighash_byte,
4961 precomputed_bip143,
4962 )?
4963 } else {
4964 use crate::transaction_hash::{
4966 calculate_transaction_sighash_single_input, SighashType,
4967 };
4968 let sighash_type = SighashType::from_byte(sighash_byte);
4969
4970 let pattern = serialize_push_data(signature_bytes.as_ref());
4974
4975 let base_script = match (
4976 redeem_script_for_sighash,
4977 prevout_script_pubkeys.get(input_index),
4978 ) {
4979 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
4980 (Some(redeem), _) => redeem,
4981 (None, Some(prevout)) => *prevout,
4982 (None, None) => &[],
4983 };
4984 let cleaned = find_and_delete(base_script, &pattern);
4985
4986 calculate_transaction_sighash_single_input(
4987 tx,
4988 input_index,
4989 cleaned.as_ref(),
4990 prevout_values[input_index],
4991 sighash_type,
4992 #[cfg(feature = "production")]
4993 sighash_cache,
4994 )?
4995 };
4996
4997 let height = block_height.unwrap_or(0);
5001 #[cfg(feature = "production")]
5002 let is_valid = signature::with_secp_context(|secp| {
5003 signature::verify_signature(
5004 secp,
5005 &pubkey_bytes,
5006 &signature_bytes, &sighash,
5008 flags,
5009 height,
5010 network,
5011 sigversion,
5012 )
5013 })?;
5014
5015 #[cfg(not(feature = "production"))]
5016 let is_valid = {
5017 let secp = Secp256k1::new();
5018 signature::verify_signature(
5019 &secp,
5020 &pubkey_bytes,
5021 &signature_bytes, &sighash,
5023 flags,
5024 height,
5025 network,
5026 sigversion,
5027 )?
5028 };
5029
5030 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5031 Ok(true)
5032 } else {
5033 Ok(false)
5034 }
5035 }
5036
5037 OP_CHECKSIGVERIFY => {
5039 if stack.len() >= 2 {
5040 let pubkey_bytes = stack.pop().unwrap();
5041 let signature_bytes = stack.pop().unwrap();
5042
5043 if signature_bytes.is_empty() {
5045 return Ok(false);
5046 }
5047
5048 let sig_len = signature_bytes.len();
5052 let sighash_byte = signature_bytes[sig_len - 1];
5053 let _der_sig = &signature_bytes[..sig_len - 1];
5054
5055 let sighash = if sigversion == SigVersion::WitnessV0 {
5059 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5061
5062 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5063 prevout_script_pubkeys
5064 .get(input_index)
5065 .copied()
5066 .unwrap_or(&[])
5067 });
5068
5069 crate::transaction_hash::calculate_bip143_sighash(
5070 tx,
5071 input_index,
5072 script_code,
5073 amount,
5074 sighash_byte,
5075 precomputed_bip143,
5076 )?
5077 } else {
5078 use crate::transaction_hash::{
5080 calculate_transaction_sighash_single_input, SighashType,
5081 };
5082 let sighash_type = SighashType::from_byte(sighash_byte);
5083
5084 let pattern = serialize_push_data(signature_bytes.as_ref());
5086
5087 let base_script = match (
5088 redeem_script_for_sighash,
5089 prevout_script_pubkeys.get(input_index),
5090 ) {
5091 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5092 (Some(redeem), _) => redeem,
5093 (None, Some(prevout)) => *prevout,
5094 (None, None) => &[],
5095 };
5096 let cleaned = find_and_delete(base_script, &pattern);
5097
5098 calculate_transaction_sighash_single_input(
5099 tx,
5100 input_index,
5101 cleaned.as_ref(),
5102 prevout_values[input_index],
5103 sighash_type,
5104 #[cfg(feature = "production")]
5105 sighash_cache,
5106 )?
5107 };
5108
5109 let height = block_height.unwrap_or(0);
5113 #[cfg(feature = "production")]
5114 let is_valid = signature::with_secp_context(|secp| {
5115 signature::verify_signature(
5116 secp,
5117 &pubkey_bytes,
5118 &signature_bytes, &sighash,
5120 flags,
5121 height,
5122 network,
5123 sigversion,
5124 )
5125 })?;
5126
5127 #[cfg(not(feature = "production"))]
5128 let is_valid = {
5129 let secp = Secp256k1::new();
5130 signature::verify_signature(
5131 &secp,
5132 &pubkey_bytes,
5133 &signature_bytes, &sighash,
5135 flags,
5136 height,
5137 network,
5138 sigversion,
5139 )?
5140 };
5141
5142 if is_valid {
5143 Ok(true)
5144 } else {
5145 Ok(false)
5146 }
5147 } else {
5148 Ok(false)
5149 }
5150 }
5151
5152 OP_CHECKSIGADD => {
5154 if sigversion != SigVersion::Tapscript {
5155 return Err(ConsensusError::ScriptErrorWithCode {
5156 code: ScriptErrorCode::DisabledOpcode,
5157 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5158 });
5159 }
5160 if stack.len() < 3 {
5161 return Err(ConsensusError::ScriptErrorWithCode {
5162 code: ScriptErrorCode::InvalidStackOperation,
5163 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5164 });
5165 }
5166 let pubkey_bytes = stack.pop().unwrap();
5168 let n_bytes = stack.pop().unwrap();
5169 let signature_bytes = stack.pop().unwrap();
5170 let n = script_num_decode(&n_bytes, 4)?;
5171
5172 if signature_bytes.is_empty() {
5174 stack.push(to_stack_element(&script_num_encode(n)));
5175 return Ok(true);
5176 }
5177
5178 if pubkey_bytes.len() == 32 && signature_bytes.len() == 64 {
5180 let sighash_byte = 0x00;
5181 let (tapscript, codesep_pos) = tapscript_for_sighash
5182 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5183 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5184 let sighash = if tapscript.is_empty() {
5185 crate::taproot::compute_taproot_signature_hash(
5186 tx,
5187 input_index,
5188 prevout_values,
5189 prevout_script_pubkeys,
5190 sighash_byte,
5191 )?
5192 } else {
5193 crate::taproot::compute_tapscript_signature_hash(
5194 tx,
5195 input_index,
5196 prevout_values,
5197 prevout_script_pubkeys,
5198 tapscript,
5199 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5200 codesep_pos,
5201 sighash_byte,
5202 )?
5203 };
5204
5205 #[cfg(feature = "production")]
5206 let is_valid = {
5207 use crate::bip348::verify_tapscript_schnorr_signature;
5208 verify_tapscript_schnorr_signature(
5209 &sighash,
5210 &pubkey_bytes,
5211 &signature_bytes,
5212 schnorr_collector,
5213 )
5214 .unwrap_or(false)
5215 };
5216
5217 #[cfg(not(feature = "production"))]
5218 let is_valid = {
5219 #[cfg(feature = "csfs")]
5220 let x = {
5221 use crate::bip348::verify_tapscript_schnorr_signature;
5222 verify_tapscript_schnorr_signature(
5223 &sighash,
5224 &pubkey_bytes,
5225 &signature_bytes,
5226 None,
5227 )
5228 .unwrap_or(false)
5229 };
5230 #[cfg(not(feature = "csfs"))]
5231 let x = false;
5232 x
5233 };
5234
5235 if !is_valid {
5236 return Ok(false); }
5238 stack.push(to_stack_element(&script_num_encode(n + 1)));
5239 return Ok(true);
5240 }
5241
5242 stack.push(to_stack_element(&script_num_encode(n + 1)));
5244 Ok(true)
5245 }
5246
5247 OP_CHECKMULTISIG => {
5249 if stack.len() < 2 {
5252 return Ok(false);
5253 }
5254
5255 let n_bytes = stack.pop().unwrap();
5258 let n = if n_bytes.is_empty() {
5259 0
5260 } else {
5261 n_bytes[0] as usize
5262 };
5263 if n > 20 || stack.len() < n + 1 {
5264 return Ok(false);
5265 }
5266
5267 let mut pubkeys = Vec::with_capacity(n);
5269 for _ in 0..n {
5270 pubkeys.push(stack.pop().unwrap());
5271 }
5272
5273 let m_bytes = stack.pop().unwrap();
5276 let m = if m_bytes.is_empty() {
5277 0
5278 } else {
5279 m_bytes[0] as usize
5280 };
5281 if m > n || m > 20 || stack.len() < m + 1 {
5282 return Ok(false);
5283 }
5284
5285 let mut signatures = Vec::with_capacity(m);
5287 for _ in 0..m {
5288 signatures.push(stack.pop().unwrap());
5289 }
5290
5291 let dummy = stack.pop().unwrap();
5294 if flags & 0x10 != 0 {
5295 let height = block_height.unwrap_or(0);
5296 use crate::bip_validation::Bip147Network;
5298 let bip147_network = match network {
5299 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5300 crate::types::Network::Testnet => Bip147Network::Testnet,
5301 crate::types::Network::Regtest => Bip147Network::Regtest,
5302 };
5303
5304 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5308
5309 let bip147_active = height
5310 >= match bip147_network {
5311 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5312 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5313 Bip147Network::Regtest => 0,
5314 };
5315
5316 if bip147_active {
5317 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5321 if !is_empty {
5322 return Err(ConsensusError::ScriptErrorWithCode {
5323 code: ScriptErrorCode::SigNullDummy,
5324 message: format!(
5325 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5326 )
5327 .into(),
5328 });
5329 }
5330 }
5331 }
5332
5333 let height = block_height.unwrap_or(0);
5336
5337 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5340 let base_script = match (
5341 redeem_script_for_sighash,
5342 prevout_script_pubkeys.get(input_index),
5343 ) {
5344 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5345 (Some(redeem), _) => redeem,
5346 (None, Some(prevout)) => *prevout,
5347 (None, None) => &[],
5348 };
5349 let mut cleaned = base_script.to_vec();
5350 for sig in &signatures {
5351 if !sig.is_empty() {
5352 let pattern = serialize_push_data(sig.as_ref());
5353 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5354 }
5355 }
5356 cleaned
5357 } else {
5358 redeem_script_for_sighash
5360 .map(|s| s.to_vec())
5361 .unwrap_or_else(|| {
5362 prevout_script_pubkeys
5363 .get(input_index)
5364 .map(|p| p.to_vec())
5365 .unwrap_or_default()
5366 })
5367 };
5368
5369 use crate::transaction_hash::{
5370 calculate_transaction_sighash_single_input, SighashType,
5371 };
5372
5373 #[cfg(feature = "production")]
5375 let use_batch = pubkeys.len() * signatures.len() >= 4;
5376
5377 #[cfg(feature = "production")]
5378 let (valid_sigs, _) = if use_batch {
5379 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5381 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5382 if non_empty.is_empty() {
5383 vec![]
5384 } else {
5385 let specs: Vec<(usize, u8, &[u8])> = non_empty
5386 .iter()
5387 .map(|s| {
5388 (
5389 input_index,
5390 s.as_ref()[s.as_ref().len() - 1],
5391 cleaned_script_for_multisig.as_ref(),
5392 )
5393 })
5394 .collect();
5395 crate::transaction_hash::batch_compute_legacy_sighashes(
5396 tx,
5397 prevout_values,
5398 prevout_script_pubkeys,
5399 &specs,
5400 )?
5401 }
5402 } else {
5403 signatures
5404 .iter()
5405 .filter(|s| !s.is_empty())
5406 .map(|sig_bytes| {
5407 let sighash_type =
5408 SighashType::from_byte(sig_bytes[sig_bytes.len() - 1]);
5409 calculate_transaction_sighash_single_input(
5410 tx,
5411 input_index,
5412 &cleaned_script_for_multisig,
5413 prevout_values[input_index],
5414 sighash_type,
5415 sighash_cache,
5416 )
5417 })
5418 .collect::<Result<Vec<_>>>()?
5419 };
5420
5421 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5423 Vec::with_capacity(pubkeys.len() * signatures.len());
5424 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5425 let mut sighash_idx = 0usize;
5426 for (j, sig_bytes) in signatures.iter().enumerate() {
5427 if sig_bytes.is_empty() {
5428 sig_idx_to_sighash_idx.push(usize::MAX);
5429 } else {
5430 sig_idx_to_sighash_idx.push(sighash_idx);
5431 let sh = sighashes[sighash_idx];
5432 sighash_idx += 1;
5433 for pubkey_bytes in &pubkeys {
5434 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5435 }
5436 }
5437 }
5438
5439 let results = if tasks.is_empty() {
5440 vec![]
5441 } else {
5442 batch_verify_signatures(&tasks, flags, height, network)?
5443 };
5444
5445 let mut sig_index = 0;
5447 let mut valid_sigs = 0usize;
5448 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5449 if sig_index >= signatures.len() {
5450 break;
5451 }
5452 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5454 sig_index += 1;
5455 }
5456 if sig_index >= signatures.len() {
5457 break;
5458 }
5459 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5460 if sh_idx == usize::MAX {
5461 continue;
5462 }
5463 let task_idx = sh_idx * pubkeys.len() + i;
5464 if task_idx < results.len() && results[task_idx] {
5465 valid_sigs += 1;
5466 sig_index += 1;
5467 }
5468 }
5469
5470 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5472 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5473 for (j, sig_bytes) in signatures.iter().enumerate() {
5474 if sig_bytes.is_empty() {
5475 continue;
5476 }
5477 let sh_idx = sig_idx_to_sighash_idx[j];
5478 if sh_idx == usize::MAX {
5479 continue;
5480 }
5481 let sig_start = sh_idx * pubkeys.len();
5482 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5483 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5484 if !matched {
5485 return Err(ConsensusError::ScriptErrorWithCode {
5486 code: ScriptErrorCode::SigNullFail,
5487 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5488 });
5489 }
5490 }
5491 }
5492 (valid_sigs, ())
5493 } else {
5494 let mut sig_index = 0;
5495 let mut valid_sigs = 0;
5496
5497 for pubkey_bytes in &pubkeys {
5498 if sig_index >= signatures.len() {
5499 break;
5500 }
5501
5502 let signature_bytes = &signatures[sig_index];
5503
5504 if signature_bytes.is_empty() {
5505 continue;
5506 }
5507
5508 let sig_len = signature_bytes.len();
5509 let sighash_byte = signature_bytes[sig_len - 1];
5510 let sighash_type = SighashType::from_byte(sighash_byte);
5511
5512 let sighash = calculate_transaction_sighash_single_input(
5513 tx,
5514 input_index,
5515 &cleaned_script_for_multisig,
5516 prevout_values[input_index],
5517 sighash_type,
5518 #[cfg(feature = "production")]
5519 sighash_cache,
5520 )?;
5521
5522 #[cfg(feature = "production")]
5523 let is_valid = signature::with_secp_context(|secp| {
5524 signature::verify_signature(
5525 secp,
5526 pubkey_bytes,
5527 signature_bytes,
5528 &sighash,
5529 flags,
5530 height,
5531 network,
5532 sigversion,
5533 )
5534 })?;
5535
5536 #[cfg(not(feature = "production"))]
5537 let is_valid = {
5538 let secp = Secp256k1::new();
5539 signature::verify_signature(
5540 &secp,
5541 pubkey_bytes,
5542 signature_bytes,
5543 &sighash,
5544 flags,
5545 height,
5546 network,
5547 sigversion,
5548 )?
5549 };
5550
5551 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5552 if !is_valid
5553 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5554 && !signature_bytes.is_empty()
5555 {
5556 return Err(ConsensusError::ScriptErrorWithCode {
5557 code: ScriptErrorCode::SigNullFail,
5558 message:
5559 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5560 .into(),
5561 });
5562 }
5563
5564 if is_valid {
5565 valid_sigs += 1;
5566 sig_index += 1;
5567 }
5568 }
5569 (valid_sigs, ())
5570 };
5571
5572 #[cfg(not(feature = "production"))]
5573 let (valid_sigs, _) = {
5574 let mut sig_index = 0;
5575 let mut valid_sigs = 0;
5576
5577 for pubkey_bytes in &pubkeys {
5578 if sig_index >= signatures.len() {
5579 break;
5580 }
5581 let signature_bytes = &signatures[sig_index];
5582 if signature_bytes.is_empty() {
5583 continue;
5584 }
5585 let sig_len = signature_bytes.len();
5586 let sighash_type = SighashType::from_byte(signature_bytes[sig_len - 1]);
5587 let sighash = calculate_transaction_sighash_single_input(
5588 tx,
5589 input_index,
5590 &cleaned_script_for_multisig,
5591 prevout_values[input_index],
5592 sighash_type,
5593 #[cfg(feature = "production")]
5594 sighash_cache,
5595 )?;
5596 let secp = Secp256k1::new();
5597 let is_valid = signature::verify_signature(
5598 &secp,
5599 pubkey_bytes,
5600 signature_bytes,
5601 &sighash,
5602 flags,
5603 height,
5604 network,
5605 sigversion,
5606 )?;
5607 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5608 if !is_valid
5609 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5610 && !signature_bytes.is_empty()
5611 {
5612 return Err(ConsensusError::ScriptErrorWithCode {
5613 code: ScriptErrorCode::SigNullFail,
5614 message:
5615 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5616 .into(),
5617 });
5618 }
5619 if is_valid {
5620 valid_sigs += 1;
5621 sig_index += 1;
5622 }
5623 }
5624 (valid_sigs, ())
5625 };
5626
5627 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
5629 Ok(true)
5630 }
5631
5632 OP_CHECKMULTISIGVERIFY => {
5634 let ctx_checkmultisig = context::ScriptContext {
5636 tx,
5637 input_index,
5638 prevout_values,
5639 prevout_script_pubkeys,
5640 block_height,
5641 median_time_past,
5642 network,
5643 sigversion,
5644 redeem_script_for_sighash,
5645 script_sig_for_sighash,
5646 tapscript_for_sighash,
5647 tapscript_codesep_pos,
5648 #[cfg(feature = "production")]
5649 schnorr_collector: None,
5650 #[cfg(feature = "production")]
5651 precomputed_bip143,
5652 #[cfg(feature = "production")]
5653 sighash_cache,
5654 };
5655 let result = execute_opcode_with_context_full(
5656 OP_CHECKMULTISIG,
5657 stack,
5658 flags,
5659 &ctx_checkmultisig,
5660 redeem_script_for_sighash,
5661 )?;
5662 if !result {
5663 return Ok(false);
5664 }
5665 if let Some(top) = stack.pop() {
5667 if !cast_to_bool(&top) {
5668 return Ok(false);
5669 }
5670 Ok(true)
5671 } else {
5672 Ok(false)
5673 }
5674 }
5675
5676 OP_CHECKLOCKTIMEVERIFY => {
5681 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
5683 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5684 return Ok(true);
5685 }
5686
5687 use crate::locktime::{check_bip65, decode_locktime_value};
5688
5689 if stack.is_empty() {
5690 return Err(ConsensusError::ScriptErrorWithCode {
5691 code: ScriptErrorCode::InvalidStackOperation,
5692 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
5693 });
5694 }
5695
5696 let locktime_bytes = stack.last().expect("Stack is not empty");
5698 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
5699 Some(v) => v,
5700 None => {
5701 return Err(ConsensusError::ScriptErrorWithCode {
5702 code: ScriptErrorCode::MinimalData,
5703 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
5704 })
5705 }
5706 };
5707
5708 let tx_locktime = tx.lock_time as u32;
5709
5710 if !check_bip65(tx_locktime, locktime_value) {
5712 return Ok(false);
5713 }
5714
5715 let input_seq = if input_index < tx.inputs.len() {
5717 tx.inputs[input_index].sequence
5718 } else {
5719 0xffffffff
5720 };
5721 if input_seq == 0xffffffff {
5722 return Ok(false);
5723 }
5724
5725 Ok(true)
5727 }
5728
5729 OP_CHECKSEQUENCEVERIFY => {
5738 use crate::locktime::{
5739 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
5740 is_sequence_disabled,
5741 };
5742
5743 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
5745 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
5746 return Ok(true);
5747 }
5748
5749 if stack.is_empty() {
5750 return Ok(false);
5751 }
5752
5753 let sequence_bytes = stack.last().expect("Stack is not empty");
5756 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
5757 Some(v) => v,
5758 None => return Ok(false), };
5760
5761 if input_index >= tx.inputs.len() {
5763 return Ok(false);
5764 }
5765 let input_sequence = tx.inputs[input_index].sequence as u32;
5766
5767 if is_sequence_disabled(input_sequence) {
5769 return Ok(true);
5770 }
5771
5772 let type_flag = extract_sequence_type_flag(sequence_value);
5774 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
5775
5776 let input_type_flag = extract_sequence_type_flag(input_sequence);
5778 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
5779
5780 if type_flag != input_type_flag {
5782 return Ok(false);
5783 }
5784
5785 if input_locktime < locktime_mask {
5787 return Ok(false);
5788 }
5789
5790 Ok(true)
5792 }
5793
5794 OP_CHECKTEMPLATEVERIFY => {
5803 #[cfg(not(feature = "ctv"))]
5804 {
5805 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5807 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5808 return Err(ConsensusError::ScriptErrorWithCode {
5809 code: ScriptErrorCode::BadOpcode,
5810 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
5811 });
5812 }
5813 Ok(true) }
5815
5816 #[cfg(feature = "ctv")]
5817 {
5818 use crate::constants::{
5819 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
5820 };
5821
5822 let ctv_activation = match network {
5824 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
5825 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
5826 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
5827 };
5828
5829 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
5830 if !ctv_active {
5831 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5833 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5834 return Err(ConsensusError::ScriptErrorWithCode {
5835 code: ScriptErrorCode::BadOpcode,
5836 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
5837 });
5838 }
5839 return Ok(true); }
5841
5842 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
5844 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
5845 return Ok(true);
5847 }
5848
5849 use crate::bip119::calculate_template_hash;
5850
5851 if stack.is_empty() {
5853 return Err(ConsensusError::ScriptErrorWithCode {
5854 code: ScriptErrorCode::InvalidStackOperation,
5855 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
5856 });
5857 }
5858
5859 let template_hash_bytes = stack.pop().unwrap();
5860
5861 if template_hash_bytes.len() != 32 {
5863 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5866 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5867 return Err(ConsensusError::ScriptErrorWithCode {
5868 code: ScriptErrorCode::InvalidStackOperation,
5869 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
5870 .into(),
5871 });
5872 }
5873 return Ok(true); }
5875
5876 let mut expected_hash = [0u8; 32];
5878 expected_hash.copy_from_slice(&template_hash_bytes);
5879
5880 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
5881 ConsensusError::ScriptErrorWithCode {
5882 code: ScriptErrorCode::TxInvalid,
5883 message: format!("CTV hash calculation failed: {e}").into(),
5884 }
5885 })?;
5886
5887 use crate::crypto::hash_compare::hash_eq;
5889 let matches = hash_eq(&expected_hash, &actual_hash);
5890
5891 if !matches {
5892 return Ok(false); }
5894
5895 Ok(true)
5897 }
5898 }
5899
5900 OP_CHECKSIGFROMSTACK => {
5911 #[cfg(not(feature = "csfs"))]
5912 {
5913 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5916 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5917 return Err(ConsensusError::ScriptErrorWithCode {
5918 code: ScriptErrorCode::BadOpcode,
5919 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
5920 });
5921 }
5922 Ok(true) }
5924
5925 #[cfg(feature = "csfs")]
5926 {
5927 use crate::constants::{
5928 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
5929 };
5930
5931 if sigversion != SigVersion::Tapscript {
5933 return Err(ConsensusError::ScriptErrorWithCode {
5934 code: ScriptErrorCode::BadOpcode,
5935 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
5936 });
5937 }
5938
5939 let csfs_activation = match network {
5941 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
5942 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
5943 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
5944 };
5945
5946 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
5947 if !csfs_active {
5948 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
5950 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
5951 return Err(ConsensusError::ScriptErrorWithCode {
5952 code: ScriptErrorCode::BadOpcode,
5953 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
5954 });
5955 }
5956 return Ok(true); }
5958
5959 use crate::bip348::verify_signature_from_stack;
5960
5961 if stack.len() < 3 {
5963 return Err(ConsensusError::ScriptErrorWithCode {
5964 code: ScriptErrorCode::InvalidStackOperation,
5965 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
5966 });
5967 }
5968
5969 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
5976 return Err(ConsensusError::ScriptErrorWithCode {
5977 code: ScriptErrorCode::PubkeyType,
5978 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
5979 });
5980 }
5981
5982 if signature_bytes.is_empty() {
5984 stack.push(to_stack_element(&[])); return Ok(true);
5986 }
5987
5988 #[cfg(feature = "production")]
5991 let is_valid = {
5992 verify_signature_from_stack(
5993 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
5998 .unwrap_or(false)
5999 };
6000 #[cfg(not(feature = "production"))]
6001 let is_valid = verify_signature_from_stack(
6002 &message_bytes, &pubkey_bytes, &signature_bytes, )
6006 .unwrap_or(false);
6007
6008 if !is_valid {
6009 return Ok(false);
6011 }
6012
6013 stack.push(to_stack_element(&[0x01])); Ok(true)
6020 }
6021 }
6022
6023 _ => execute_opcode_cold(opcode, stack, flags),
6025 }
6026}
6027
6028#[cold]
6030fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6031 execute_opcode(opcode, stack, flags, SigVersion::Base)
6032}
6033
6034#[cfg(feature = "production")]
6049pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6050 (
6051 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6052 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6053 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6054 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6055 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6056 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6057 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6058 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6059 )
6060}
6061
6062#[cfg(all(feature = "production", feature = "benchmarking"))]
6069pub fn clear_script_cache() {
6070 if let Some(cache) = SCRIPT_CACHE.get() {
6071 let mut cache = cache.write().unwrap();
6072 cache.clear();
6073 }
6074}
6075
6076#[cfg(all(feature = "production", feature = "benchmarking"))]
6090pub fn clear_hash_cache() {
6091 crypto_ops::clear_hash_cache();
6092}
6093
6094#[cfg(all(feature = "production", feature = "benchmarking"))]
6107pub fn clear_all_caches() {
6108 clear_script_cache();
6109 clear_hash_cache();
6110}
6111
6112#[cfg(all(feature = "production", feature = "benchmarking"))]
6126pub fn clear_stack_pool() {
6127 STACK_POOL.with(|pool| {
6128 let mut pool = pool.borrow_mut();
6129 pool.clear();
6130 });
6131}
6132
6133#[cfg(all(feature = "production", feature = "benchmarking"))]
6147pub fn reset_benchmarking_state() {
6148 clear_all_caches();
6149 clear_stack_pool();
6150 disable_caching(false); #[cfg(feature = "benchmarking")]
6153 crate::transaction_hash::clear_sighash_templates();
6154}
6155
6156#[cfg(test)]
6157mod tests {
6158 use super::*;
6159
6160 #[test]
6161 fn test_eval_script_simple() {
6162 let script = vec![OP_1]; let mut stack = Vec::new();
6164
6165 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6166 assert_eq!(stack.len(), 1);
6167 assert_eq!(stack[0].as_ref(), &[1]);
6168 }
6169
6170 #[test]
6171 fn test_eval_script_overflow() {
6172 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6174
6175 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6176 }
6177
6178 #[test]
6179 fn test_verify_script_simple() {
6180 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());
6191 }
6192
6193 #[test]
6198 fn test_op_0() {
6199 let script = vec![OP_0]; let mut stack = Vec::new();
6201 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6202 assert!(!result); assert_eq!(stack.len(), 1);
6204 assert!(stack[0].is_empty());
6205 }
6206
6207 #[test]
6208 fn test_op_1_to_op_16() {
6209 for i in 1..=16 {
6211 let opcode = 0x50 + i;
6212 let script = vec![opcode];
6213 let mut stack = Vec::new();
6214 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6215 assert!(result);
6216 assert_eq!(stack.len(), 1);
6217 assert_eq!(stack[0].as_ref(), &[i]);
6218 }
6219 }
6220
6221 #[test]
6222 fn test_op_dup() {
6223 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6225 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6226 assert!(!result); assert_eq!(stack.len(), 2);
6228 assert_eq!(stack[0].as_ref(), &[1]);
6229 assert_eq!(stack[1].as_ref(), &[1]);
6230 }
6231
6232 #[test]
6233 fn test_op_dup_empty_stack() {
6234 let script = vec![OP_DUP]; let mut stack = Vec::new();
6236 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6237 assert!(!result);
6238 }
6239
6240 #[test]
6241 fn test_op_hash160() {
6242 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6244 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6245 assert!(result);
6246 assert_eq!(stack.len(), 1);
6247 assert_eq!(stack[0].len(), 20); }
6249
6250 #[test]
6251 fn test_op_hash160_empty_stack() {
6252 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6254 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6255 assert!(!result);
6256 }
6257
6258 #[test]
6259 fn test_op_hash256() {
6260 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6262 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6263 assert!(result);
6264 assert_eq!(stack.len(), 1);
6265 assert_eq!(stack[0].len(), 32); }
6267
6268 #[test]
6269 fn test_op_hash256_empty_stack() {
6270 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6272 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6273 assert!(!result);
6274 }
6275
6276 #[test]
6277 fn test_op_equal() {
6278 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6280 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6281 assert!(result);
6282 assert_eq!(stack.len(), 1);
6283 assert_eq!(stack[0].as_ref(), &[1]); }
6285
6286 #[test]
6287 fn test_op_equal_false() {
6288 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6290 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6291 assert!(!result); assert_eq!(stack.len(), 1);
6293 assert_eq!(stack[0].as_ref(), &[0]); }
6295
6296 #[test]
6297 fn test_op_equal_insufficient_stack() {
6298 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6300 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6301 assert!(
6302 result.is_err(),
6303 "OP_EQUAL with insufficient stack should return error"
6304 );
6305 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6306 assert_eq!(
6307 code,
6308 crate::error::ScriptErrorCode::InvalidStackOperation,
6309 "Should return InvalidStackOperation"
6310 );
6311 }
6312 }
6313
6314 #[test]
6315 fn test_op_verify() {
6316 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6318 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6319 assert!(!result); assert_eq!(stack.len(), 0); }
6322
6323 #[test]
6324 fn test_op_verify_false() {
6325 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6327 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6328 assert!(!result);
6329 }
6330
6331 #[test]
6332 fn test_op_verify_empty_stack() {
6333 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6335 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6336 assert!(!result);
6337 }
6338
6339 #[test]
6340 fn test_op_equalverify() {
6341 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6343 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6344 assert!(!result); assert_eq!(stack.len(), 0); }
6347
6348 #[test]
6349 fn test_op_equalverify_false() {
6350 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6352 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6353 assert!(
6354 result.is_err(),
6355 "OP_EQUALVERIFY with false condition should return error"
6356 );
6357 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6358 assert_eq!(
6359 code,
6360 crate::error::ScriptErrorCode::EqualVerify,
6361 "Should return EqualVerify"
6362 );
6363 }
6364 }
6365
6366 #[test]
6367 fn test_op_checksig() {
6368 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6372 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6373 assert!(!result); assert_eq!(stack.len(), 1);
6375 }
6377
6378 #[test]
6379 fn test_op_checksig_insufficient_stack() {
6380 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6382 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6383 assert!(
6384 result.is_err(),
6385 "OP_CHECKSIG with insufficient stack should return error"
6386 );
6387 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6388 assert_eq!(
6389 code,
6390 crate::error::ScriptErrorCode::InvalidStackOperation,
6391 "Should return InvalidStackOperation"
6392 );
6393 }
6394 }
6395
6396 #[test]
6397 fn test_unknown_opcode() {
6398 let script = vec![0xff]; let mut stack = Vec::new();
6400 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6401 assert!(!result);
6402 }
6403
6404 #[test]
6405 fn test_script_size_limit() {
6406 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6408 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6409 assert!(result.is_err());
6410 }
6411
6412 #[test]
6413 fn test_operation_count_limit() {
6414 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6417 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6418 assert!(result.is_err());
6419 }
6420
6421 #[test]
6422 fn test_stack_underflow_multiple_ops() {
6423 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6425 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6426 assert!(result.is_err(), "Stack underflow should return error");
6427 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6428 assert_eq!(
6429 code,
6430 crate::error::ScriptErrorCode::InvalidStackOperation,
6431 "Should return InvalidStackOperation"
6432 );
6433 }
6434 }
6435
6436 #[test]
6437 fn test_final_stack_empty() {
6438 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6440 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6441 assert!(!result);
6442 }
6443
6444 #[test]
6445 fn test_final_stack_false() {
6446 let script = vec![OP_0]; let mut stack = Vec::new();
6448 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6449 assert!(!result);
6450 }
6451
6452 #[test]
6453 fn test_verify_script_with_witness() {
6454 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6458
6459 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6460 assert!(!result); }
6462
6463 #[test]
6464 fn test_verify_script_failure() {
6465 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_2]; let witness = None;
6468 let flags = 0;
6469
6470 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6471 assert!(!result);
6472 }
6473
6474 #[test]
6479 fn test_op_ifdup_true() {
6480 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6482 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6483 assert!(!result); assert_eq!(stack.len(), 2);
6485 assert_eq!(stack[0].as_ref(), &[1]);
6486 assert_eq!(stack[1].as_ref(), &[1]);
6487 }
6488
6489 #[test]
6490 fn test_op_ifdup_false() {
6491 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6493 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6494 assert!(!result); assert_eq!(stack.len(), 1);
6496 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6497 }
6498
6499 #[test]
6500 fn test_op_depth() {
6501 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6503 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6504 assert!(!result); assert_eq!(stack.len(), 3);
6506 assert_eq!(stack[2].as_ref(), &[2]); }
6508
6509 #[test]
6510 fn test_op_drop() {
6511 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
6513 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6514 assert!(result); assert_eq!(stack.len(), 1);
6516 assert_eq!(stack[0].as_ref(), &[1]);
6517 }
6518
6519 #[test]
6520 fn test_op_drop_empty_stack() {
6521 let script = vec![OP_DROP]; let mut stack = Vec::new();
6523 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6524 assert!(!result);
6525 assert_eq!(stack.len(), 0);
6526 }
6527
6528 #[test]
6529 fn test_op_nip() {
6530 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
6532 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6533 assert!(result); assert_eq!(stack.len(), 1);
6535 assert_eq!(stack[0].as_ref(), &[2]);
6536 }
6537
6538 #[test]
6539 fn test_op_nip_insufficient_stack() {
6540 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
6542 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6543 assert!(!result);
6544 assert_eq!(stack.len(), 1);
6545 }
6546
6547 #[test]
6548 fn test_op_over() {
6549 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
6551 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6552 assert!(!result); assert_eq!(stack.len(), 3);
6554 assert_eq!(stack[0].as_ref(), &[1]);
6555 assert_eq!(stack[1].as_ref(), &[2]);
6556 assert_eq!(stack[2].as_ref(), &[1]);
6557 }
6558
6559 #[test]
6560 fn test_op_over_insufficient_stack() {
6561 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
6563 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6564 assert!(!result);
6565 assert_eq!(stack.len(), 1);
6566 }
6567
6568 #[test]
6569 fn test_op_pick() {
6570 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
6572 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6573 assert!(!result); assert_eq!(stack.len(), 4);
6575 assert_eq!(stack[3].as_ref(), &[2]); }
6577
6578 #[test]
6579 fn test_op_pick_empty_n() {
6580 let script = vec![OP_1, OP_0, OP_PICK];
6582 let mut stack = Vec::new();
6583 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6584 assert!(!result); assert_eq!(stack.len(), 2);
6586 assert_eq!(stack[1].as_ref(), &[1]); }
6588
6589 #[test]
6590 fn test_op_pick_invalid_index() {
6591 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
6593 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6594 assert!(!result);
6595 assert_eq!(stack.len(), 1);
6596 }
6597
6598 #[test]
6599 fn test_op_roll() {
6600 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
6602 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6603 assert!(!result); assert_eq!(stack.len(), 3);
6605 assert_eq!(stack[0].as_ref(), &[1]);
6606 assert_eq!(stack[1].as_ref(), &[3]);
6607 assert_eq!(stack[2].as_ref(), &[2]); }
6609
6610 #[test]
6611 fn test_op_roll_zero_n() {
6612 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
6615 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6616 assert!(result); assert_eq!(stack.len(), 1);
6618 assert_eq!(stack[0].as_ref(), &[1]);
6619 }
6620
6621 #[test]
6622 fn test_op_roll_invalid_index() {
6623 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
6625 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6626 assert!(!result);
6627 assert_eq!(stack.len(), 1);
6628 }
6629
6630 #[test]
6631 fn test_op_rot() {
6632 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
6634 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6635 assert!(!result); assert_eq!(stack.len(), 3);
6637 assert_eq!(stack[0].as_ref(), &[2]);
6638 assert_eq!(stack[1].as_ref(), &[3]);
6639 assert_eq!(stack[2].as_ref(), &[1]);
6640 }
6641
6642 #[test]
6643 fn test_op_rot_insufficient_stack() {
6644 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
6646 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6647 assert!(!result);
6648 assert_eq!(stack.len(), 2);
6649 }
6650
6651 #[test]
6652 fn test_op_swap() {
6653 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
6655 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6656 assert!(!result); assert_eq!(stack.len(), 2);
6658 assert_eq!(stack[0].as_ref(), &[2]);
6659 assert_eq!(stack[1].as_ref(), &[1]);
6660 }
6661
6662 #[test]
6663 fn test_op_swap_insufficient_stack() {
6664 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
6666 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6667 assert!(!result);
6668 assert_eq!(stack.len(), 1);
6669 }
6670
6671 #[test]
6672 fn test_op_tuck() {
6673 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
6675 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6676 assert!(!result); assert_eq!(stack.len(), 3);
6678 assert_eq!(stack[0].as_ref(), &[2]);
6679 assert_eq!(stack[1].as_ref(), &[1]);
6680 assert_eq!(stack[2].as_ref(), &[2]);
6681 }
6682
6683 #[test]
6684 fn test_op_tuck_insufficient_stack() {
6685 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
6687 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6688 assert!(!result);
6689 assert_eq!(stack.len(), 1);
6690 }
6691
6692 #[test]
6693 fn test_op_2drop() {
6694 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
6696 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6697 assert!(result); assert_eq!(stack.len(), 1);
6699 assert_eq!(stack[0].as_ref(), &[1]);
6700 }
6701
6702 #[test]
6703 fn test_op_2drop_insufficient_stack() {
6704 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
6706 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6707 assert!(!result);
6708 assert_eq!(stack.len(), 1);
6709 }
6710
6711 #[test]
6712 fn test_op_2dup() {
6713 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
6715 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6716 assert!(!result); assert_eq!(stack.len(), 4);
6718 assert_eq!(stack[0].as_ref(), &[1]);
6719 assert_eq!(stack[1].as_ref(), &[2]);
6720 assert_eq!(stack[2].as_ref(), &[1]);
6721 assert_eq!(stack[3].as_ref(), &[2]);
6722 }
6723
6724 #[test]
6725 fn test_op_2dup_insufficient_stack() {
6726 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
6728 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6729 assert!(!result);
6730 assert_eq!(stack.len(), 1);
6731 }
6732
6733 #[test]
6734 fn test_op_3dup() {
6735 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
6737 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6738 assert!(!result); assert_eq!(stack.len(), 6);
6740 assert_eq!(stack[0].as_ref(), &[1]);
6741 assert_eq!(stack[1].as_ref(), &[2]);
6742 assert_eq!(stack[2].as_ref(), &[3]);
6743 assert_eq!(stack[3].as_ref(), &[1]);
6744 assert_eq!(stack[4].as_ref(), &[2]);
6745 assert_eq!(stack[5].as_ref(), &[3]);
6746 }
6747
6748 #[test]
6749 fn test_op_3dup_insufficient_stack() {
6750 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
6752 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6753 assert!(!result);
6754 assert_eq!(stack.len(), 2);
6755 }
6756
6757 #[test]
6758 fn test_op_2over() {
6759 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
6761 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6762 assert!(!result); assert_eq!(stack.len(), 6);
6764 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
6766 }
6767
6768 #[test]
6769 fn test_op_2over_insufficient_stack() {
6770 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
6772 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6773 assert!(!result);
6774 assert_eq!(stack.len(), 3);
6775 }
6776
6777 #[test]
6778 fn test_op_2rot() {
6779 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
6781 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6782 assert!(!result); assert_eq!(stack.len(), 6);
6784 assert_eq!(stack[4].as_ref(), &[2]); assert_eq!(stack[5].as_ref(), &[1]);
6786 }
6787
6788 #[test]
6789 fn test_op_2rot_insufficient_stack() {
6790 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
6792 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6793 assert!(!result);
6794 assert_eq!(stack.len(), 4);
6795 }
6796
6797 #[test]
6798 fn test_op_2swap() {
6799 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
6801 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6802 assert!(!result); assert_eq!(stack.len(), 4);
6804 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
6806 assert_eq!(stack[2].as_ref(), &[1]);
6807 assert_eq!(stack[3].as_ref(), &[2]);
6808 }
6809
6810 #[test]
6811 fn test_op_2swap_insufficient_stack() {
6812 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
6814 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6815 assert!(!result);
6816 assert_eq!(stack.len(), 3);
6817 }
6818
6819 #[test]
6820 fn test_op_size() {
6821 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
6823 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6824 assert!(!result); assert_eq!(stack.len(), 2);
6826 assert_eq!(stack[0].as_ref(), &[1]);
6827 assert_eq!(stack[1].as_ref(), &[1]); }
6829
6830 #[test]
6831 fn test_op_size_empty_stack() {
6832 let script = vec![OP_SIZE]; let mut stack = Vec::new();
6834 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6835 assert!(!result);
6836 assert_eq!(stack.len(), 0);
6837 }
6838
6839 #[test]
6840 fn test_op_return() {
6841 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
6843 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6844 assert!(!result); assert_eq!(stack.len(), 1);
6846 }
6847
6848 #[test]
6849 fn test_op_checksigverify() {
6850 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6852 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6853 assert!(!result); assert_eq!(stack.len(), 0);
6855 }
6856
6857 #[test]
6858 fn test_op_checksigverify_insufficient_stack() {
6859 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
6861 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6862 assert!(!result);
6863 assert_eq!(stack.len(), 1);
6864 }
6865
6866 #[test]
6867 fn test_unknown_opcode_comprehensive() {
6868 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
6870 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6871 assert!(!result); assert_eq!(stack.len(), 1);
6873 }
6874
6875 #[test]
6876 fn test_verify_signature_invalid_pubkey() {
6877 let secp = Secp256k1::new();
6878 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
6881 let result = signature::verify_signature(
6882 &secp,
6883 &invalid_pubkey,
6884 &signature,
6885 &dummy_hash,
6886 0,
6887 0,
6888 crate::types::Network::Regtest,
6889 SigVersion::Base,
6890 );
6891 assert!(!result.unwrap_or(false));
6892 }
6893
6894 #[test]
6895 fn test_verify_signature_invalid_signature() {
6896 let secp = Secp256k1::new();
6897 let pubkey = vec![
6898 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
6899 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
6900 0x5b, 0x16, 0xf8, 0x17, 0x98,
6901 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
6904 let result = signature::verify_signature(
6905 &secp,
6906 &pubkey,
6907 &invalid_signature,
6908 &dummy_hash,
6909 0,
6910 0,
6911 crate::types::Network::Regtest,
6912 SigVersion::Base,
6913 );
6914 assert!(!result.unwrap_or(false));
6915 }
6916
6917 fn minimal_tx_and_prevouts(
6923 script_sig: &[u8],
6924 script_pubkey: &[u8],
6925 ) -> (
6926 crate::types::Transaction,
6927 Vec<i64>,
6928 Vec<crate::types::ByteString>,
6929 ) {
6930 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
6931 let tx = Transaction {
6932 version: 1,
6933 inputs: vec![TransactionInput {
6934 prevout: OutPoint {
6935 hash: [0u8; 32],
6936 index: 0,
6937 },
6938 sequence: 0xffff_ffff,
6939 script_sig: script_sig.to_vec(),
6940 }]
6941 .into(),
6942 outputs: vec![TransactionOutput {
6943 value: 0,
6944 script_pubkey: script_pubkey.to_vec(),
6945 }]
6946 .into(),
6947 lock_time: 0,
6948 };
6949 let prevout_values = vec![0i64];
6950 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
6951 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
6952 (tx, prevout_values, prevout_script_pubkeys_vec)
6953 }
6954
6955 #[test]
6956 fn test_verify_with_context_p2pkh_hash_mismatch() {
6957 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
6961 script_sig.push(sig.len() as u8);
6962 script_sig.extend(&sig);
6963 script_sig.push(pubkey.len() as u8);
6964 script_sig.extend(&pubkey);
6965
6966 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
6967 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
6969 script_pubkey.push(OP_CHECKSIG);
6970
6971 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
6972 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
6973 let result = verify_script_with_context_full(
6974 &script_sig,
6975 &script_pubkey,
6976 None,
6977 0,
6978 &tx,
6979 0,
6980 &pv,
6981 &psp_refs,
6982 Some(500_000),
6983 None,
6984 crate::types::Network::Mainnet,
6985 SigVersion::Base,
6986 #[cfg(feature = "production")]
6987 None,
6988 None, #[cfg(feature = "production")]
6990 None,
6991 #[cfg(feature = "production")]
6992 None,
6993 #[cfg(feature = "production")]
6994 None,
6995 );
6996 assert!(result.is_ok());
6997 assert!(!result.unwrap());
6998 }
6999
7000 #[test]
7001 fn test_verify_with_context_p2sh_hash_mismatch() {
7002 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7005 script_sig.push(redeem.len() as u8);
7006 script_sig.extend(&redeem);
7007
7008 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7009 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7011
7012 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7013 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7014 let result = verify_script_with_context_full(
7015 &script_sig,
7016 &script_pubkey,
7017 None,
7018 0x01, &tx,
7020 0,
7021 &pv,
7022 &psp_refs,
7023 Some(500_000),
7024 None,
7025 crate::types::Network::Mainnet,
7026 SigVersion::Base,
7027 #[cfg(feature = "production")]
7028 None,
7029 None, #[cfg(feature = "production")]
7031 None,
7032 #[cfg(feature = "production")]
7033 None,
7034 #[cfg(feature = "production")]
7035 None,
7036 );
7037 assert!(result.is_ok());
7038 assert!(!result.unwrap());
7039 }
7040
7041 #[test]
7042 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7043 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7045 script_pubkey.extend(&[0u8; 20]);
7046 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7048 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7049 let empty: Vec<u8> = vec![];
7050 let result = verify_script_with_context_full(
7051 &empty,
7052 &script_pubkey,
7053 Some(&witness),
7054 0,
7055 &tx,
7056 0,
7057 &pv,
7058 &psp_refs,
7059 Some(500_000),
7060 None,
7061 crate::types::Network::Mainnet,
7062 SigVersion::Base,
7063 #[cfg(feature = "production")]
7064 None,
7065 None, #[cfg(feature = "production")]
7067 None,
7068 #[cfg(feature = "production")]
7069 None,
7070 #[cfg(feature = "production")]
7071 None,
7072 );
7073 assert!(result.is_ok());
7074 assert!(!result.unwrap());
7075 }
7076
7077 #[test]
7078 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7079 let witness_script = vec![OP_1];
7081 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7082 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7084 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7085 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7086 let empty: Vec<u8> = vec![];
7087 let result = verify_script_with_context_full(
7088 &empty,
7089 &script_pubkey,
7090 Some(&witness),
7091 0,
7092 &tx,
7093 0,
7094 &pv,
7095 &psp_refs,
7096 Some(500_000),
7097 None,
7098 crate::types::Network::Mainnet,
7099 SigVersion::Base,
7100 #[cfg(feature = "production")]
7101 None,
7102 None, #[cfg(feature = "production")]
7104 None,
7105 #[cfg(feature = "production")]
7106 None,
7107 #[cfg(feature = "production")]
7108 None,
7109 );
7110 assert!(result.is_ok());
7111 assert!(!result.unwrap());
7112 }
7113
7114 #[test]
7115 #[cfg(feature = "production")]
7116 fn test_p2wsh_multisig_fast_path() {
7117 use crate::constants::BIP147_ACTIVATION_MAINNET;
7119 use crate::crypto::OptimizedSha256;
7120
7121 let pk1 = [0x02u8; 33];
7122 let pk2 = [0x03u8; 33];
7123 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7125 witness_script.extend_from_slice(&pk2);
7126 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7130 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7131 script_pubkey.extend_from_slice(&wsh_hash);
7132
7133 let witness: Vec<Vec<u8>> = vec![
7134 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7138 ];
7139
7140 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7141 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7142 let empty: Vec<u8> = vec![];
7143 let result = verify_script_with_context_full(
7144 &empty,
7145 &script_pubkey,
7146 Some(&witness),
7147 0x810, &tx,
7149 0,
7150 &pv,
7151 &psp_refs,
7152 Some(BIP147_ACTIVATION_MAINNET + 1),
7153 None,
7154 crate::types::Network::Mainnet,
7155 SigVersion::Base,
7156 #[cfg(feature = "production")]
7157 None,
7158 None, #[cfg(feature = "production")]
7160 None,
7161 #[cfg(feature = "production")]
7162 None,
7163 #[cfg(feature = "production")]
7164 None,
7165 );
7166 assert!(result.is_ok());
7167 assert!(!result.unwrap());
7168 }
7169}
7170
7171#[cfg(test)]
7172#[allow(unused_doc_comments)]
7173mod property_tests {
7174 use super::*;
7175 use proptest::prelude::*;
7176
7177 proptest! {
7182 #[test]
7183 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7184 let mut stack = Vec::new();
7185 let flags = 0u32;
7186
7187 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7188
7189 if script.len() > MAX_SCRIPT_OPS * 2 {
7197 prop_assert!(result.is_err() || !result.unwrap(),
7200 "Very long scripts should fail or return false");
7201 }
7202 }
7204 }
7205
7206 proptest! {
7211 #[test]
7212 fn prop_verify_script_deterministic(
7213 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7214 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7215 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7216 flags in any::<u32>()
7217 ) {
7218 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7219 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7220
7221 assert_eq!(result1.is_ok(), result2.is_ok());
7222 if result1.is_ok() && result2.is_ok() {
7223 assert_eq!(result1.unwrap(), result2.unwrap());
7224 }
7225 }
7226 }
7227
7228 proptest! {
7233 #[test]
7234 fn prop_execute_opcode_no_panic(
7235 opcode in any::<u8>(),
7236 stack_items in prop::collection::vec(
7237 prop::collection::vec(any::<u8>(), 0..5),
7238 0..10
7239 ),
7240 flags in any::<u32>()
7241 ) {
7242 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7243 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7244
7245 match result {
7248 Ok(success) => {
7249 let _ = success;
7251 },
7252 Err(_) => {
7253 }
7256 }
7257
7258 assert!(stack.len() <= MAX_STACK_SIZE);
7260 }
7261 }
7262
7263 proptest! {
7270 #[test]
7271 fn prop_stack_operations_bounds(
7272 opcode in any::<u8>(),
7273 stack_items in prop::collection::vec(
7274 prop::collection::vec(any::<u8>(), 0..3),
7275 0..5
7276 ),
7277 flags in any::<u32>()
7278 ) {
7279 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7280 let initial_len = stack.len();
7281
7282 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7283
7284 assert!(stack.len() <= MAX_STACK_SIZE);
7286
7287 if result.is_ok() && result.unwrap() {
7289 match opcode {
7291 OP_0 | OP_1..=OP_16 => {
7292 assert!(stack.len() == initial_len + 1);
7294 },
7295 OP_DUP => {
7296 if initial_len > 0 {
7298 assert!(stack.len() == initial_len + 1);
7299 }
7300 },
7301 OP_3DUP => {
7302 if initial_len >= 3 {
7304 assert!(stack.len() == initial_len + 3);
7305 }
7306 },
7307 OP_2OVER => {
7308 if initial_len >= 4 {
7310 assert!(stack.len() == initial_len + 2);
7311 }
7312 },
7313 OP_DROP | OP_NIP | OP_2DROP => {
7314 assert!(stack.len() <= initial_len);
7316 },
7317 _ => {
7318 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7321 }
7322 }
7323 }
7324 }
7325 }
7326
7327 proptest! {
7332 #[test]
7333 fn prop_hash_operations_deterministic(
7334 input in prop::collection::vec(any::<u8>(), 0..10)
7335 ) {
7336 let elem = to_stack_element(&input);
7337 let mut stack1 = vec![elem.clone()];
7338 let mut stack2 = vec![elem];
7339
7340 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());
7344 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7345 assert_eq!(val1, val2);
7346 if val1 {
7347 assert_eq!(stack1, stack2);
7348 }
7349 }
7350 }
7351 }
7352
7353 proptest! {
7358 #[test]
7359 fn prop_equality_operations_symmetric(
7360 a in prop::collection::vec(any::<u8>(), 0..5),
7361 b in prop::collection::vec(any::<u8>(), 0..5)
7362 ) {
7363 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7364 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7365
7366 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());
7370 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7371 assert_eq!(val1, val2);
7372 if val1 {
7373 assert_eq!(stack1.len(), stack2.len());
7375 if !stack1.is_empty() && !stack2.is_empty() {
7376 assert_eq!(stack1[0], stack2[0]);
7377 }
7378 }
7379 }
7380 }
7381 }
7382
7383 proptest! {
7388 #[test]
7389 fn prop_script_execution_terminates(
7390 script in prop::collection::vec(any::<u8>(), 0..50)
7391 ) {
7392 let mut stack = Vec::new();
7393 let flags = 0u32;
7394
7395 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7397
7398 assert!(result.is_ok() || result.is_err());
7400
7401 assert!(stack.len() <= MAX_STACK_SIZE);
7403 }
7404 }
7405}