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;
20pub mod flags;
21mod signature;
22mod stack;
23
24pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
25pub use stack::{cast_to_bool, to_stack_element, StackElement};
26
27use crate::constants::*;
28use crate::crypto::OptimizedSha256;
29use crate::error::{ConsensusError, Result, ScriptErrorCode};
30use crate::opcodes::*;
31use crate::types::*;
32use blvm_spec_lock::spec_locked;
33use digest::Digest;
34use ripemd::Ripemd160;
35
36#[cfg(feature = "production")]
38use crate::optimizations::{precomputed_constants, prefetch};
39
40#[cold]
42#[allow(dead_code)]
43fn make_operation_limit_error() -> ConsensusError {
44 ConsensusError::ScriptErrorWithCode {
45 code: ScriptErrorCode::OpCount,
46 message: "Operation limit exceeded".into(),
47 }
48}
49
50#[cold]
51fn make_stack_overflow_error() -> ConsensusError {
52 ConsensusError::ScriptErrorWithCode {
53 code: ScriptErrorCode::StackSize,
54 message: "Stack overflow".into(),
55 }
56}
57
58#[inline]
59fn bip143_p2wpkh_script_code(pubkey_hash: &[u8]) -> [u8; 25] {
60 let mut hash = [0u8; 20];
61 hash.copy_from_slice(pubkey_hash);
62 crate::transaction_hash::derive_bip143_script_code_p2wpkh(&hash)
63}
64
65#[cfg(feature = "production")]
66use std::collections::VecDeque;
67#[cfg(feature = "production")]
68use std::sync::{
69 atomic::{AtomicBool, AtomicU64, Ordering},
70 OnceLock, RwLock,
71};
72#[cfg(feature = "production")]
73use std::thread_local;
74
75#[cfg(feature = "production")]
81static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
82
83#[cfg(feature = "production")]
86const SIG_CACHE_SHARDS: usize = 32;
87
88#[cfg(feature = "production")]
89const SIG_CACHE_SHARD: OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>> = OnceLock::new();
90
91#[cfg(feature = "production")]
92static SIG_CACHE: [OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>>; SIG_CACHE_SHARDS] =
93 [SIG_CACHE_SHARD; SIG_CACHE_SHARDS];
94
95#[cfg(feature = "production")]
97fn sig_cache_size() -> usize {
98 std::env::var("BLVM_SIG_CACHE_ENTRIES")
99 .ok()
100 .and_then(|s| s.parse().ok())
101 .filter(|&n: &usize| n > 0 && n <= 1_000_000)
102 .unwrap_or(500_000)
103}
104
105#[cfg(feature = "production")]
106fn sig_cache_shard_index(key: &[u8; 32]) -> usize {
107 let h = (key[0] as usize) | ((key[1] as usize) << 8) | ((key[2] as usize) << 16);
108 h % SIG_CACHE_SHARDS
109}
110
111#[cfg(feature = "production")]
112fn get_sig_cache_shard(key: &[u8; 32]) -> &'static RwLock<lru::LruCache<[u8; 32], bool>> {
113 let idx = sig_cache_shard_index(key);
114 SIG_CACHE[idx].get_or_init(|| {
115 use lru::LruCache;
116 use std::num::NonZeroUsize;
117 let cap = (sig_cache_size() / SIG_CACHE_SHARDS).max(1);
118 RwLock::new(LruCache::new(NonZeroUsize::new(cap).unwrap()))
119 })
120}
121
122#[cfg(feature = "production")]
123thread_local! {
124 static BATCH_PUT_SIG_CACHE_BY_SHARD: std::cell::RefCell<[Vec<([u8; 32], bool)>; SIG_CACHE_SHARDS]> =
125 std::cell::RefCell::new(std::array::from_fn(|_| Vec::new()));
126}
127
128#[cfg(feature = "production")]
130thread_local! {
131 static SOA_BATCH_BUF: std::cell::RefCell<(
132 Vec<[u8; 64]>,
133 Vec<[u8; 32]>,
134 Vec<[u8; 33]>,
135 Vec<usize>,
136 Vec<[u8; 32]>,
137 )> = const { std::cell::RefCell::new((
138 Vec::new(),
139 Vec::new(),
140 Vec::new(),
141 Vec::new(),
142 Vec::new(),
143 )) };
144}
145
146#[cfg(feature = "production")]
147fn batch_put_sig_cache(keys: &[[u8; 32]], results: &[bool]) {
148 BATCH_PUT_SIG_CACHE_BY_SHARD.with(|cell| {
149 let mut by_shard = cell.borrow_mut();
150 for v in by_shard.iter_mut() {
151 v.clear();
152 }
153 for (i, key) in keys.iter().enumerate() {
154 let result = results.get(i).copied().unwrap_or(false);
155 let idx = sig_cache_shard_index(key);
156 by_shard[idx].push((*key, result));
157 }
158 for shard_entries in by_shard.iter() {
159 if shard_entries.is_empty() {
160 continue;
161 }
162 let first_key = &shard_entries[0].0;
163 if let Ok(mut guard) = get_sig_cache_shard(first_key).write() {
164 for (k, v) in shard_entries.iter() {
165 guard.put(*k, *v);
166 }
167 }
168 }
169 });
170}
171
172#[cfg(feature = "production")]
178fn sig_cache_at_collect_enabled() -> bool {
179 use std::sync::OnceLock;
180 static CACHE: OnceLock<bool> = OnceLock::new();
181 *CACHE.get_or_init(|| {
182 std::env::var("BLVM_SIG_CACHE_AT_COLLECT")
183 .map(|s| s == "1" || s.eq_ignore_ascii_case("true"))
184 .unwrap_or(false)
185 })
186}
187
188#[cfg(feature = "production")]
191#[inline(always)]
192fn ecdsa_cache_key(msg: &[u8; 32], pk: &[u8; 33], sig_compact: &[u8; 64], flags: u32) -> [u8; 32] {
193 use siphasher::sip::SipHasher24;
194 use std::hash::{Hash, Hasher};
195 let mut key_input = [0u8; 133];
196 key_input[..32].copy_from_slice(msg);
197 key_input[32..65].copy_from_slice(pk);
198 key_input[65..129].copy_from_slice(sig_compact);
199 key_input[129..133].copy_from_slice(&flags.to_le_bytes());
200 let mut hasher = SipHasher24::new();
201 key_input.hash(&mut hasher);
202 let h = hasher.finish();
203 let mut out = [0u8; 32];
204 out[..8].copy_from_slice(&h.to_le_bytes());
205 out
206}
207
208#[cfg(feature = "production")]
211static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
212#[cfg(feature = "production")]
213static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
214#[cfg(feature = "production")]
215static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
216#[cfg(feature = "production")]
217static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
218#[cfg(feature = "production")]
219static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
220static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
221#[cfg(feature = "production")]
222static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
223#[cfg(feature = "production")]
224static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
225
226#[cfg(feature = "production")]
227fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
228 SCRIPT_CACHE.get_or_init(|| {
229 use lru::LruCache;
233 use std::num::NonZeroUsize;
234 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
235 })
236}
237
238#[cfg(feature = "production")]
243thread_local! {
244 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
245 std::cell::RefCell::new(VecDeque::with_capacity(10));
246}
247
248#[cfg(feature = "production")]
250fn get_pooled_stack() -> Vec<StackElement> {
251 STACK_POOL.with(|pool| {
252 let mut pool = pool.borrow_mut();
253 if let Some(mut stack) = pool.pop_front() {
254 stack.clear();
255 if stack.capacity() < 20 {
256 stack.reserve(20);
257 }
258 stack
259 } else {
260 Vec::with_capacity(20)
261 }
262 })
263}
264
265#[cfg(feature = "production")]
267struct PooledStackGuard(Vec<StackElement>);
268#[cfg(feature = "production")]
269impl Drop for PooledStackGuard {
270 fn drop(&mut self) {
271 return_pooled_stack(std::mem::take(&mut self.0));
272 }
273}
274
275#[cfg(feature = "production")]
277fn return_pooled_stack(mut stack: Vec<StackElement>) {
278 stack.clear();
280
281 STACK_POOL.with(|pool| {
282 let mut pool = pool.borrow_mut();
283 if pool.len() < 10 {
285 pool.push_back(stack);
286 }
287 });
289}
290
291#[cfg(feature = "production")]
296static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
297
298#[cfg(feature = "production")]
314pub fn disable_caching(disabled: bool) {
315 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
316}
317
318#[cfg(feature = "production")]
320fn is_caching_disabled() -> bool {
321 CACHE_DISABLED.load(Ordering::Relaxed)
322}
323
324#[cfg(feature = "production")]
329fn compute_script_cache_key(
330 script_sig: &ByteString,
331 script_pubkey: &[u8],
332 witness: Option<&ByteString>,
333 flags: u32,
334) -> u64 {
335 use std::collections::hash_map::DefaultHasher;
336 use std::hash::{Hash, Hasher};
337
338 let mut hasher = DefaultHasher::new();
339 script_sig.hash(&mut hasher);
340 script_pubkey.hash(&mut hasher);
341 if let Some(w) = witness {
342 w.hash(&mut hasher);
343 }
344 flags.hash(&mut hasher);
345 hasher.finish()
346}
347
348#[derive(Debug, Clone, Copy, PartialEq, Eq)]
350pub enum SigVersion {
351 Base,
353 WitnessV0,
355 Tapscript,
357}
358
359#[spec_locked("5.2", "EvalScript")]
376#[cfg_attr(feature = "production", inline(always))]
377#[cfg_attr(not(feature = "production"), inline)]
378pub fn eval_script(
379 script: &[u8],
380 stack: &mut Vec<StackElement>,
381 flags: u32,
382 sigversion: SigVersion,
383) -> Result<bool> {
384 if stack.capacity() < 20 {
387 stack.reserve(20);
388 }
389 #[cfg(feature = "production")]
390 {
391 eval_script_impl(script, stack, flags, sigversion)
392 }
393 #[cfg(not(feature = "production"))]
394 {
395 eval_script_inner(script, stack, flags, sigversion)
396 }
397}
398#[cfg(feature = "production")]
399fn eval_script_impl(
400 script: &[u8],
401 stack: &mut Vec<StackElement>,
402 flags: u32,
403 sigversion: SigVersion,
404) -> Result<bool> {
405 eval_script_inner(script, stack, flags, sigversion)
406}
407
408#[cfg(not(feature = "production"))]
409#[allow(dead_code)]
410fn eval_script_impl(
411 script: &[u8],
412 stack: &mut Vec<StackElement>,
413 flags: u32,
414 sigversion: SigVersion,
415) -> Result<bool> {
416 eval_script_inner(script, stack, flags, sigversion)
417}
418
419#[inline(always)]
421fn is_push_opcode(opcode: u8) -> bool {
422 opcode <= 0x60
423}
424
425#[inline]
428fn is_op_success(opcode: u8) -> bool {
429 matches!(
430 opcode,
431 80 | 98
432 | 126..=129
433 | 131..=134
434 | 137..=138
435 | 141..=142
436 | 149..=153
437 | 187..=254
438 )
439}
440
441#[inline]
444fn op_advance(script: &[u8], pc: usize) -> usize {
445 let opcode = script[pc];
446 match opcode {
447 0x01..=0x4b => 1 + opcode as usize,
449 0x4c => {
451 if pc + 1 < script.len() {
452 2 + script[pc + 1] as usize
453 } else {
454 1
455 }
456 }
457 0x4d => {
459 if pc + 2 < script.len() {
460 3 + u16::from_le_bytes([script[pc + 1], script[pc + 2]]) as usize
461 } else {
462 1
463 }
464 }
465 0x4e => {
467 if pc + 4 < script.len() {
468 5 + u32::from_le_bytes([
469 script[pc + 1],
470 script[pc + 2],
471 script[pc + 3],
472 script[pc + 4],
473 ]) as usize
474 } else {
475 1
476 }
477 }
478 _ => 1,
479 }
480}
481
482fn eval_script_inner(
483 script: &[u8],
484 stack: &mut Vec<StackElement>,
485 flags: u32,
486 sigversion: SigVersion,
487) -> Result<bool> {
488 use crate::constants::MAX_SCRIPT_SIZE;
489 use crate::error::{ConsensusError, ScriptErrorCode};
490
491 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
492 && script.len() > MAX_SCRIPT_SIZE
493 {
494 return Err(ConsensusError::ScriptErrorWithCode {
495 code: ScriptErrorCode::ScriptSize,
496 message: "Script size exceeds maximum".into(),
497 });
498 }
499
500 let mut op_count = 0;
501 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
502 let mut altstack: Vec<StackElement> = Vec::new();
503
504 let mut i = 0;
505 while i < script.len() {
506 let opcode = script[i];
507 let in_false_branch = control_flow::in_false_branch(&control_stack);
508
509 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
512 op_count += 1;
513 if op_count > MAX_SCRIPT_OPS {
514 return Err(make_operation_limit_error());
515 }
516 debug_assert!(
517 op_count <= MAX_SCRIPT_OPS,
518 "Operation count ({op_count}) must not exceed MAX_SCRIPT_OPS ({MAX_SCRIPT_OPS})"
519 );
520 }
521
522 if stack.len() + altstack.len() > MAX_STACK_SIZE {
525 return Err(make_stack_overflow_error());
526 }
527
528 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
530 let (data, advance) = if opcode <= 0x4b {
531 let len = opcode as usize;
532 if i + 1 + len > script.len() {
533 return Ok(false);
534 }
535 (&script[i + 1..i + 1 + len], 1 + len)
536 } else if opcode == OP_PUSHDATA1 {
537 if i + 1 >= script.len() {
538 return Ok(false);
539 }
540 let len = script[i + 1] as usize;
541 if i + 2 + len > script.len() {
542 return Ok(false);
543 }
544 (&script[i + 2..i + 2 + len], 2 + len)
545 } else if opcode == OP_PUSHDATA2 {
546 if i + 2 >= script.len() {
547 return Ok(false);
548 }
549 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
550 if i + 3 + len > script.len() {
551 return Ok(false);
552 }
553 (&script[i + 3..i + 3 + len], 3 + len)
554 } else {
555 if i + 4 >= script.len() {
556 return Ok(false);
557 }
558 let len = u32::from_le_bytes([
559 script[i + 1],
560 script[i + 2],
561 script[i + 3],
562 script[i + 4],
563 ]) as usize;
564 let data_start = i.saturating_add(5);
565 let data_end = data_start.saturating_add(len);
566 let advance = 5usize.saturating_add(len);
567 if advance < 5 || data_end > script.len() || data_end < data_start {
568 return Ok(false);
569 }
570 (&script[data_start..data_end], advance)
571 };
572
573 if !in_false_branch {
574 stack.push(to_stack_element(data));
575 }
576 i += advance;
577 continue;
578 }
579
580 match opcode {
581 OP_IF => {
583 if in_false_branch {
584 control_stack.push(control_flow::ControlBlock::If { executing: false });
585 } else if stack.is_empty() {
586 return Err(ConsensusError::ScriptErrorWithCode {
587 code: ScriptErrorCode::InvalidStackOperation,
588 message: "OP_IF: empty stack".into(),
589 });
590 } else {
591 let condition_bytes = stack.pop().unwrap();
592 let condition = cast_to_bool(&condition_bytes);
593
594 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
595 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
596 && (sigversion == SigVersion::WitnessV0
597 || sigversion == SigVersion::Tapscript)
598 && !control_flow::is_minimal_if_condition(&condition_bytes)
599 {
600 return Err(ConsensusError::ScriptErrorWithCode {
601 code: ScriptErrorCode::MinimalIf,
602 message: "OP_IF condition must be minimally encoded".into(),
603 });
604 }
605
606 control_stack.push(control_flow::ControlBlock::If {
607 executing: condition,
608 });
609 }
610 }
611 OP_NOTIF => {
613 if in_false_branch {
614 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
615 } else if stack.is_empty() {
616 return Err(ConsensusError::ScriptErrorWithCode {
617 code: ScriptErrorCode::InvalidStackOperation,
618 message: "OP_NOTIF: empty stack".into(),
619 });
620 } else {
621 let condition_bytes = stack.pop().unwrap();
622 let condition = cast_to_bool(&condition_bytes);
623
624 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
625 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
626 && (sigversion == SigVersion::WitnessV0
627 || sigversion == SigVersion::Tapscript)
628 && !control_flow::is_minimal_if_condition(&condition_bytes)
629 {
630 return Err(ConsensusError::ScriptErrorWithCode {
631 code: ScriptErrorCode::MinimalIf,
632 message: "OP_NOTIF condition must be minimally encoded".into(),
633 });
634 }
635
636 control_stack.push(control_flow::ControlBlock::NotIf {
637 executing: !condition,
638 });
639 }
640 }
641 OP_ELSE => {
643 if let Some(block) = control_stack.last_mut() {
644 match block {
645 control_flow::ControlBlock::If { executing }
646 | control_flow::ControlBlock::NotIf { executing } => {
647 *executing = !*executing;
648 }
649 }
650 } else {
651 return Err(ConsensusError::ScriptErrorWithCode {
652 code: ScriptErrorCode::UnbalancedConditional,
653 message: "OP_ELSE without matching IF/NOTIF".into(),
654 });
655 }
656 }
657 OP_ENDIF => {
659 if control_stack.pop().is_none() {
660 return Err(ConsensusError::ScriptErrorWithCode {
661 code: ScriptErrorCode::UnbalancedConditional,
662 message: "OP_ENDIF without matching IF/NOTIF".into(),
663 });
664 }
665 }
666 OP_TOALTSTACK => {
668 if !in_false_branch {
669 if stack.is_empty() {
670 return Err(ConsensusError::ScriptErrorWithCode {
671 code: ScriptErrorCode::InvalidStackOperation,
672 message: "OP_TOALTSTACK: empty stack".into(),
673 });
674 }
675 altstack.push(stack.pop().unwrap());
676 }
677 }
678 OP_FROMALTSTACK => {
680 if !in_false_branch {
681 if altstack.is_empty() {
682 return Err(ConsensusError::ScriptErrorWithCode {
683 code: ScriptErrorCode::InvalidAltstackOperation,
684 message: "OP_FROMALTSTACK: empty altstack".into(),
685 });
686 }
687 stack.push(altstack.pop().unwrap());
688 }
689 }
690 _ => {
691 if in_false_branch {
692 i += 1;
693 continue;
694 }
695
696 if !execute_opcode(opcode, stack, flags, sigversion)? {
697 return Ok(false);
698 }
699
700 if stack.len() + altstack.len() > MAX_STACK_SIZE {
701 return Err(make_stack_overflow_error());
702 }
703 }
704 }
705 i += 1;
706 }
707
708 if !control_stack.is_empty() {
709 return Err(ConsensusError::ScriptErrorWithCode {
710 code: ScriptErrorCode::UnbalancedConditional,
711 message: "Unclosed IF/NOTIF block".into(),
712 });
713 }
714
715 Ok(true)
717}
718
719#[spec_locked("5.2", "VerifyScript")]
729#[cfg_attr(feature = "production", inline(always))]
730#[cfg_attr(not(feature = "production"), inline)]
731pub fn verify_script(
732 script_sig: &ByteString,
733 script_pubkey: &[u8],
734 witness: Option<&ByteString>,
735 flags: u32,
736) -> Result<bool> {
737 let sigversion = SigVersion::Base;
739
740 #[cfg(feature = "production")]
741 {
742 if !is_caching_disabled() {
744 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
745 {
746 let cache = get_script_cache().read().unwrap_or_else(|e| e.into_inner());
747 if let Some(&cached_result) = cache.peek(&cache_key) {
748 return Ok(cached_result);
749 }
750 }
751 }
752
753 let mut stack = get_pooled_stack();
756 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
757 let result = {
758 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
759 if !is_caching_disabled() {
761 let mut cache = get_script_cache()
762 .write()
763 .unwrap_or_else(|e| e.into_inner());
764 cache.put(cache_key, false);
765 }
766 false
767 } else if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
768 if !is_caching_disabled() {
769 let mut cache = get_script_cache()
770 .write()
771 .unwrap_or_else(|e| e.into_inner());
772 cache.put(cache_key, false);
773 }
774 false
775 } else if let Some(w) = witness {
776 if !eval_script(w, &mut stack, flags, sigversion)? {
777 if !is_caching_disabled() {
778 let mut cache = get_script_cache()
779 .write()
780 .unwrap_or_else(|e| e.into_inner());
781 cache.put(cache_key, false);
782 }
783 false
784 } else {
785 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
786 if !is_caching_disabled() {
787 let mut cache = get_script_cache()
788 .write()
789 .unwrap_or_else(|e| e.into_inner());
790 cache.put(cache_key, res);
791 }
792 res
793 }
794 } else {
795 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
796 if !is_caching_disabled() {
797 let mut cache = get_script_cache()
798 .write()
799 .unwrap_or_else(|e| e.into_inner());
800 cache.put(cache_key, res);
801 }
802 res
803 }
804 };
805
806 return_pooled_stack(stack);
808
809 Ok(result)
810 }
811
812 #[cfg(not(feature = "production"))]
813 {
814 let mut stack = Vec::with_capacity(20);
816
817 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
819 return Ok(false);
820 }
821
822 if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
824 return Ok(false);
825 }
826
827 if let Some(w) = witness {
829 if !eval_script(w, &mut stack, flags, sigversion)? {
830 return Ok(false);
831 }
832 }
833
834 Ok(!stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]))
836 }
837}
838
839#[spec_locked("5.2", "VerifyScript")]
852#[cfg_attr(feature = "production", inline(always))]
853#[cfg_attr(not(feature = "production"), inline)]
854#[allow(clippy::too_many_arguments)]
855pub fn verify_script_with_context(
856 script_sig: &ByteString,
857 script_pubkey: &[u8],
858 witness: Option<&crate::witness::Witness>,
859 flags: u32,
860 tx: &Transaction,
861 input_index: usize,
862 prevouts: &[TransactionOutput],
863 block_height: Option<u64>,
864 network: crate::types::Network,
865) -> Result<bool> {
866 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
868 let prevout_script_pubkeys: Vec<&[u8]> =
869 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
870
871 verify_script_with_context_full(
872 script_sig,
873 script_pubkey,
874 witness,
875 flags,
876 tx,
877 input_index,
878 &prevout_values,
879 &prevout_script_pubkeys,
880 block_height,
881 None, network,
883 SigVersion::Base, #[cfg(feature = "production")]
885 None, None, #[cfg(feature = "production")]
888 None, #[cfg(feature = "production")]
890 None, #[cfg(feature = "production")]
892 None, )
894}
895
896#[cfg(feature = "production")]
903#[allow(clippy::too_many_arguments)]
904pub fn try_verify_p2pk_fast_path(
905 script_sig: &ByteString,
906 script_pubkey: &[u8],
907 flags: u32,
908 tx: &Transaction,
909 input_index: usize,
910 prevout_values: &[i64],
911 prevout_script_pubkeys: &[&[u8]],
912 block_height: Option<u64>,
913 network: crate::types::Network,
914 #[cfg(feature = "production")] sighash_cache: Option<
915 &crate::transaction_hash::SighashMidstateCache,
916 >,
917) -> Option<Result<bool>> {
918 let len = script_pubkey.len();
921 if len != 35 && len != 67 {
922 return None;
923 }
924 if script_pubkey[len - 1] != OP_CHECKSIG {
925 return None;
926 }
927 let pubkey_len = len - 2; if pubkey_len != 33 && pubkey_len != 65 {
929 return None;
930 }
931 if script_pubkey[0] != 0x21 && script_pubkey[0] != 0x41 {
932 return None; }
934 let pubkey_bytes = &script_pubkey[1..(len - 1)];
935
936 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
937 if signature_bytes.is_empty() {
938 return Some(Ok(false));
939 }
940
941 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
943 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
944 let sighash_type = SighashType::from_byte(sighash_byte);
945 let deleted_storage;
946 let script_code: &[u8] = if script_pubkey.len() < 71 {
947 script_pubkey
948 } else {
949 let pattern = serialize_push_data(signature_bytes);
950 deleted_storage = find_and_delete(script_pubkey, &pattern);
951 deleted_storage.as_ref()
952 };
953 let sighash = match calculate_transaction_sighash_single_input(
954 tx,
955 input_index,
956 script_code,
957 prevout_values[input_index],
958 sighash_type,
959 #[cfg(feature = "production")]
960 sighash_cache,
961 ) {
962 Ok(h) => h,
963 Err(e) => return Some(Err(e)),
964 };
965
966 let height = block_height.unwrap_or(0);
967 let is_valid = signature::with_secp_context(|secp| {
968 signature::verify_signature(
969 secp,
970 pubkey_bytes,
971 signature_bytes,
972 &sighash,
973 flags,
974 height,
975 network,
976 SigVersion::Base,
977 )
978 });
979 Some(is_valid)
980}
981
982#[cfg(feature = "production")]
985#[allow(clippy::too_many_arguments)]
986pub fn try_verify_p2pkh_fast_path(
987 script_sig: &ByteString,
988 script_pubkey: &[u8],
989 flags: u32,
990 tx: &Transaction,
991 input_index: usize,
992 prevout_values: &[i64],
993 prevout_script_pubkeys: &[&[u8]],
994 block_height: Option<u64>,
995 network: crate::types::Network,
996 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
997 #[cfg(feature = "production")] sighash_cache: Option<
998 &crate::transaction_hash::SighashMidstateCache,
999 >,
1000 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
1001) -> Option<Result<bool>> {
1002 #[cfg(all(feature = "production", feature = "profile"))]
1003 let _t_entry = std::time::Instant::now();
1004 if script_pubkey.len() != 25 {
1006 return None;
1007 }
1008 if script_pubkey[0] != OP_DUP
1009 || script_pubkey[1] != OP_HASH160
1010 || script_pubkey[2] != PUSH_20_BYTES
1011 || script_pubkey[23] != OP_EQUALVERIFY
1012 || script_pubkey[24] != OP_CHECKSIG
1013 {
1014 return None;
1015 }
1016 let expected_hash = &script_pubkey[3..23];
1017
1018 #[cfg(all(feature = "production", feature = "profile"))]
1019 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
1020 #[cfg(all(feature = "production", feature = "profile"))]
1021 let _t_parse = std::time::Instant::now();
1022 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
1023 #[cfg(all(feature = "production", feature = "profile"))]
1024 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
1025
1026 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1028 return Some(Ok(false));
1029 }
1030 if signature_bytes.is_empty() {
1032 return Some(Ok(false));
1033 }
1034
1035 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
1037 Some(h) => h,
1038 None => {
1039 #[cfg(all(feature = "production", feature = "profile"))]
1040 let _t_hash = std::time::Instant::now();
1041 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1042 let h = Ripemd160::digest(sha256_hash);
1043 #[cfg(all(feature = "production", feature = "profile"))]
1044 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1045 h.into()
1046 }
1047 };
1048 if &pubkey_hash[..] != expected_hash {
1049 return Some(Ok(false));
1050 }
1051
1052 use crate::transaction_hash::SighashType;
1055 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1056 let sighash_type = SighashType::from_byte(sighash_byte);
1057 let deleted_storage;
1058 let script_code: &[u8] = if script_pubkey.len() < 71 {
1059 script_pubkey
1060 } else {
1061 let pattern = serialize_push_data(signature_bytes);
1062 deleted_storage = find_and_delete(script_pubkey, &pattern);
1063 deleted_storage.as_ref()
1064 };
1065 let sighash = {
1066 #[cfg(feature = "production")]
1067 {
1068 if let Some(precomp) = precomputed_sighash_all {
1069 precomp
1070 } else {
1071 crate::transaction_hash::compute_legacy_sighash_nocache(
1072 tx,
1073 input_index,
1074 script_code,
1075 sighash_byte,
1076 )
1077 }
1078 }
1079 #[cfg(not(feature = "production"))]
1080 {
1081 match calculate_transaction_sighash_single_input(
1082 tx,
1083 input_index,
1084 script_code,
1085 prevout_values[input_index],
1086 sighash_type,
1087 ) {
1088 Ok(h) => h,
1089 Err(e) => return Some(Err(e)),
1090 }
1091 }
1092 };
1093
1094 #[cfg(all(feature = "production", feature = "profile"))]
1095 let _t_secp = std::time::Instant::now();
1096 let height = block_height.unwrap_or(0);
1097 let is_valid: Result<bool> = {
1098 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1099 if flags & 0x04 != 0
1100 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1101 .unwrap_or(false)
1102 {
1103 Ok(false)
1104 } else if flags & 0x02 != 0 {
1105 let base_sighash = sighash_byte & !0x80;
1106 if !(0x01..=0x03).contains(&base_sighash) {
1107 Ok(false)
1108 } else if pubkey_bytes.len() == 33 {
1109 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
1110 Ok(false)
1111 } else {
1112 let strict_der = flags & 0x04 != 0;
1113 let enforce_low_s = flags & 0x08 != 0;
1114 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1115 der_sig,
1116 pubkey_bytes,
1117 &sighash,
1118 strict_der,
1119 enforce_low_s,
1120 )
1121 .unwrap_or(false))
1122 }
1123 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1124 let strict_der = flags & 0x04 != 0;
1125 let enforce_low_s = flags & 0x08 != 0;
1126 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1127 der_sig,
1128 pubkey_bytes,
1129 &sighash,
1130 strict_der,
1131 enforce_low_s,
1132 )
1133 .unwrap_or(false))
1134 } else {
1135 Ok(false)
1136 }
1137 } else {
1138 let strict_der = flags & 0x04 != 0;
1139 let enforce_low_s = flags & 0x08 != 0;
1140 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1141 der_sig,
1142 pubkey_bytes,
1143 &sighash,
1144 strict_der,
1145 enforce_low_s,
1146 )
1147 .unwrap_or(false))
1148 }
1149 };
1150 #[cfg(all(feature = "production", feature = "profile"))]
1151 {
1152 let ns = _t_secp.elapsed().as_nanos() as u64;
1153 crate::script_profile::add_p2pkh_collect_ns(ns);
1154 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1155 }
1156 Some(is_valid)
1157}
1158
1159#[cfg(feature = "production")]
1165#[inline]
1166pub fn verify_p2pkh_inline(
1167 script_sig: &[u8],
1168 script_pubkey: &[u8],
1169 flags: u32,
1170 tx: &Transaction,
1171 input_index: usize,
1172 height: u64,
1173 network: crate::types::Network,
1174 precomputed_sighash_all: Option<[u8; 32]>,
1175) -> Result<bool> {
1176 #[cfg(feature = "profile")]
1177 let _t0 = std::time::Instant::now();
1178
1179 let expected_hash = &script_pubkey[3..23];
1180
1181 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1182 Some(pair) => pair,
1183 None => return Ok(false),
1184 };
1185
1186 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1187 return Ok(false);
1188 }
1189
1190 #[cfg(feature = "profile")]
1191 let _t_hash = std::time::Instant::now();
1192
1193 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1194 let pubkey_hash: [u8; 20] = Ripemd160::digest(sha256_hash).into();
1195 if &pubkey_hash[..] != expected_hash {
1196 return Ok(false);
1197 }
1198
1199 #[cfg(feature = "profile")]
1200 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1201
1202 #[cfg(feature = "profile")]
1203 let _t_sighash = std::time::Instant::now();
1204
1205 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1206 let sighash = if let Some(precomp) = precomputed_sighash_all {
1207 precomp
1208 } else {
1209 crate::transaction_hash::compute_legacy_sighash_buffered(
1210 tx,
1211 input_index,
1212 script_pubkey,
1213 sighash_byte,
1214 )
1215 };
1216
1217 #[cfg(feature = "profile")]
1218 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1219
1220 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1221 let strict_der = flags & 0x04 != 0;
1222 let enforce_low_s = flags & 0x08 != 0;
1223
1224 if strict_der
1225 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1226 .unwrap_or(false)
1227 {
1228 return Ok(false);
1229 }
1230
1231 if flags & 0x02 != 0 {
1232 let sighash_base = sighash_byte & !0x80;
1233 if !(0x01..=0x03).contains(&sighash_base) {
1234 return Ok(false);
1235 }
1236 match pubkey_bytes.len() {
1237 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1238 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1239 33 | 65 => {}
1240 _ => return Ok(false),
1241 }
1242 }
1243
1244 #[cfg(feature = "profile")]
1245 let _t_secp = std::time::Instant::now();
1246
1247 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1248 der_sig,
1249 pubkey_bytes,
1250 &sighash,
1251 strict_der,
1252 enforce_low_s,
1253 )
1254 .unwrap_or(false);
1255
1256 #[cfg(feature = "profile")]
1257 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1258
1259 #[cfg(feature = "profile")]
1260 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1261
1262 Ok(result)
1263}
1264
1265#[cfg(feature = "production")]
1267#[inline]
1268pub fn verify_p2pk_inline(
1269 script_sig: &[u8],
1270 script_pubkey: &[u8],
1271 flags: u32,
1272 tx: &Transaction,
1273 input_index: usize,
1274 height: u64,
1275 network: crate::types::Network,
1276) -> Result<bool> {
1277 let pk_len = script_pubkey.len() - 2; let pubkey_bytes = &script_pubkey[1..1 + pk_len];
1279
1280 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1281 Some(s) => s,
1282 None => return Ok(false),
1283 };
1284 if signature_bytes.is_empty() {
1285 return Ok(false);
1286 }
1287
1288 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1289 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_buffered(
1292 tx,
1293 input_index,
1294 script_code,
1295 sighash_byte,
1296 );
1297
1298 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1299 let strict_der = flags & 0x04 != 0;
1300 let enforce_low_s = flags & 0x08 != 0;
1301
1302 if strict_der
1303 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1304 .unwrap_or(false)
1305 {
1306 return Ok(false);
1307 }
1308
1309 if flags & 0x02 != 0 {
1310 let sighash_base = sighash_byte & !0x80;
1311 if !(0x01..=0x03).contains(&sighash_base) {
1312 return Ok(false);
1313 }
1314 match pubkey_bytes.len() {
1315 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1316 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1317 33 | 65 => {}
1318 _ => return Ok(false),
1319 }
1320 }
1321
1322 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1323 der_sig,
1324 pubkey_bytes,
1325 &sighash,
1326 strict_der,
1327 enforce_low_s,
1328 )
1329 .unwrap_or(false))
1330}
1331
1332#[allow(clippy::too_many_arguments)]
1336fn try_verify_p2sh_multisig_fast_path(
1337 script_sig: &ByteString,
1338 script_pubkey: &[u8],
1339 flags: u32,
1340 tx: &Transaction,
1341 input_index: usize,
1342 prevout_values: &[i64],
1343 prevout_script_pubkeys: &[&[u8]],
1344 block_height: Option<u64>,
1345 network: crate::types::Network,
1346 #[cfg(feature = "production")] sighash_cache: Option<
1347 &crate::transaction_hash::SighashMidstateCache,
1348 >,
1349) -> Option<Result<bool>> {
1350 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1351 if pushes.len() < 2 {
1352 return None;
1353 }
1354 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1355 let expected_hash = &script_pubkey[2..22];
1356 let sha256_hash = OptimizedSha256::new().hash(redeem);
1357 let redeem_hash = Ripemd160::digest(sha256_hash);
1358 if &redeem_hash[..] != expected_hash {
1359 return Some(Ok(false));
1360 }
1361 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1362 let signatures: Vec<&[u8]> = pushes
1363 .iter()
1364 .take(pushes.len() - 1)
1365 .skip(1)
1366 .map(|e| e.as_ref())
1367 .collect();
1368 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1369
1370 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1371 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1372 let height = block_height.unwrap_or(0);
1373 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1374 let activation = match network {
1375 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1376 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1377 crate::types::Network::Regtest => 0,
1378 };
1379 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1380 return Some(Ok(false));
1381 }
1382 }
1383
1384 let mut cleaned = redeem.to_vec();
1385 for sig in &signatures {
1386 if !sig.is_empty() {
1387 let pattern = serialize_push_data(sig);
1388 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1389 }
1390 }
1391
1392 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1393
1394 let mut sig_index = 0;
1395 let mut valid_sigs = 0u8;
1396
1397 for pubkey_bytes in pubkeys {
1398 if sig_index >= signatures.len() {
1399 break;
1400 }
1401 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1402 sig_index += 1;
1403 }
1404 if sig_index >= signatures.len() {
1405 break;
1406 }
1407 let signature_bytes = &signatures[sig_index];
1408 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1409 let sighash_type = SighashType::from_byte(sighash_byte);
1410 let sighash = match calculate_transaction_sighash_single_input(
1411 tx,
1412 input_index,
1413 &cleaned,
1414 prevout_values[input_index],
1415 sighash_type,
1416 #[cfg(feature = "production")]
1417 sighash_cache,
1418 ) {
1419 Ok(h) => h,
1420 Err(e) => return Some(Err(e)),
1421 };
1422
1423 #[cfg(feature = "production")]
1424 let is_valid = signature::with_secp_context(|secp| {
1425 signature::verify_signature(
1426 secp,
1427 pubkey_bytes,
1428 signature_bytes,
1429 &sighash,
1430 flags,
1431 height,
1432 network,
1433 SigVersion::Base,
1434 )
1435 });
1436
1437 #[cfg(not(feature = "production"))]
1438 let is_valid = {
1439 let secp = signature::new_secp();
1440 signature::verify_signature(
1441 &secp,
1442 pubkey_bytes,
1443 signature_bytes,
1444 &sighash,
1445 flags,
1446 height,
1447 network,
1448 SigVersion::Base,
1449 )
1450 };
1451
1452 let is_valid = match is_valid {
1453 Ok(v) => v,
1454 Err(e) => return Some(Err(e)),
1455 };
1456
1457 if is_valid {
1458 valid_sigs += 1;
1459 sig_index += 1;
1460 }
1461 }
1462
1463 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1464 for sig_bytes in &signatures[sig_index..] {
1465 if !sig_bytes.is_empty() {
1466 return Some(Err(ConsensusError::ScriptErrorWithCode {
1467 code: ScriptErrorCode::SigNullFail,
1468 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1469 .into(),
1470 }));
1471 }
1472 }
1473 }
1474
1475 Some(Ok(valid_sigs >= m))
1476}
1477
1478#[allow(clippy::too_many_arguments)]
1481fn try_verify_bare_multisig_fast_path(
1482 script_sig: &ByteString,
1483 script_pubkey: &[u8],
1484 flags: u32,
1485 tx: &Transaction,
1486 input_index: usize,
1487 prevout_values: &[i64],
1488 prevout_script_pubkeys: &[&[u8]],
1489 block_height: Option<u64>,
1490 network: crate::types::Network,
1491 #[cfg(feature = "production")] sighash_cache: Option<
1492 &crate::transaction_hash::SighashMidstateCache,
1493 >,
1494) -> Option<Result<bool>> {
1495 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1496 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1497 if pushes.len() < 2 {
1498 return None;
1499 }
1500 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1501 let signatures: Vec<&[u8]> = pushes[1..].iter().map(|e| e.as_ref()).collect();
1502
1503 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1504 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1505 let height = block_height.unwrap_or(0);
1506 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1507 let activation = match network {
1508 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1509 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1510 crate::types::Network::Regtest => 0,
1511 };
1512 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1513 return Some(Ok(false));
1514 }
1515 }
1516
1517 let mut cleaned = script_pubkey.to_vec();
1518 for sig in &signatures {
1519 if !sig.is_empty() {
1520 let pattern = serialize_push_data(sig);
1521 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1522 }
1523 }
1524
1525 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1526
1527 let mut sig_index = 0;
1528 let mut valid_sigs = 0u8;
1529
1530 for pubkey_bytes in pubkeys {
1531 if sig_index >= signatures.len() {
1532 break;
1533 }
1534 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1535 sig_index += 1;
1536 }
1537 if sig_index >= signatures.len() {
1538 break;
1539 }
1540 let signature_bytes = &signatures[sig_index];
1541 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1542 let sighash_type = SighashType::from_byte(sighash_byte);
1543 let sighash = match calculate_transaction_sighash_single_input(
1544 tx,
1545 input_index,
1546 &cleaned,
1547 prevout_values[input_index],
1548 sighash_type,
1549 #[cfg(feature = "production")]
1550 sighash_cache,
1551 ) {
1552 Ok(h) => h,
1553 Err(e) => return Some(Err(e)),
1554 };
1555
1556 #[cfg(feature = "production")]
1557 let is_valid = signature::with_secp_context(|secp| {
1558 signature::verify_signature(
1559 secp,
1560 pubkey_bytes,
1561 signature_bytes,
1562 &sighash,
1563 flags,
1564 height,
1565 network,
1566 SigVersion::Base,
1567 )
1568 });
1569
1570 #[cfg(not(feature = "production"))]
1571 let is_valid = {
1572 let secp = signature::new_secp();
1573 signature::verify_signature(
1574 &secp,
1575 pubkey_bytes,
1576 signature_bytes,
1577 &sighash,
1578 flags,
1579 height,
1580 network,
1581 SigVersion::Base,
1582 )
1583 };
1584
1585 let is_valid = match is_valid {
1586 Ok(v) => v,
1587 Err(e) => return Some(Err(e)),
1588 };
1589
1590 if is_valid {
1591 valid_sigs += 1;
1592 sig_index += 1;
1593 }
1594 }
1595
1596 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1597 for sig_bytes in &signatures[sig_index..] {
1598 if !sig_bytes.is_empty() {
1599 return Some(Err(ConsensusError::ScriptErrorWithCode {
1600 code: ScriptErrorCode::SigNullFail,
1601 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1602 .into(),
1603 }));
1604 }
1605 }
1606 }
1607
1608 Some(Ok(valid_sigs >= m))
1609}
1610
1611#[cfg(feature = "production")]
1615#[allow(clippy::too_many_arguments)]
1616fn try_verify_p2sh_fast_path(
1617 script_sig: &ByteString,
1618 script_pubkey: &[u8],
1619 flags: u32,
1620 tx: &Transaction,
1621 input_index: usize,
1622 prevout_values: &[i64],
1623 prevout_script_pubkeys: &[&[u8]],
1624 block_height: Option<u64>,
1625 median_time_past: Option<u64>,
1626 network: crate::types::Network,
1627 #[cfg(feature = "production")] sighash_cache: Option<
1628 &crate::transaction_hash::SighashMidstateCache,
1629 >,
1630 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1631) -> Option<Result<bool>> {
1632 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1633 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1634 return None;
1635 }
1636 if script_pubkey.len() != 23
1638 || script_pubkey[0] != OP_HASH160
1639 || script_pubkey[1] != PUSH_20_BYTES
1640 || script_pubkey[22] != OP_EQUAL
1641 {
1642 return None;
1643 }
1644 let expected_hash = &script_pubkey[2..22];
1645
1646 let mut pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1647 if pushes.is_empty() {
1648 return None;
1649 }
1650 let redeem = pushes.pop().expect("at least one push");
1651 let mut stack = pushes;
1652
1653 if redeem.len() >= 3
1655 && redeem[0] == OP_0
1656 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
1657 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
1658 {
1659 return None;
1660 }
1661
1662 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1664 let redeem_hash = Ripemd160::digest(sha256_hash);
1665 if &redeem_hash[..] != expected_hash {
1666 return Some(Ok(false));
1667 }
1668
1669 if redeem.len() == 25
1671 && redeem[0] == OP_DUP
1672 && redeem[1] == OP_HASH160
1673 && redeem[2] == PUSH_20_BYTES
1674 && redeem[23] == OP_EQUALVERIFY
1675 && redeem[24] == OP_CHECKSIG
1676 && stack.len() == 2
1677 {
1678 let signature_bytes = &stack[0];
1679 let pubkey_bytes = &stack[1];
1680 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1681 let expected_pubkey_hash = &redeem[3..23];
1682 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1683 let pubkey_hash = Ripemd160::digest(sha256_hash);
1684 if &pubkey_hash[..] == expected_pubkey_hash {
1685 #[cfg(feature = "production")]
1686 let sighash = if let Some(precomp) = precomputed_sighash_all {
1687 precomp
1688 } else {
1689 use crate::transaction_hash::{
1690 calculate_transaction_sighash_single_input, SighashType,
1691 };
1692 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1693 let sighash_type = SighashType::from_byte(sighash_byte);
1694 let deleted_storage;
1695 let script_code: &[u8] = if redeem.len() < 71 {
1696 redeem.as_ref()
1697 } else {
1698 let pattern = serialize_push_data(signature_bytes);
1699 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1700 deleted_storage.as_ref()
1701 };
1702 match calculate_transaction_sighash_single_input(
1703 tx,
1704 input_index,
1705 script_code,
1706 prevout_values[input_index],
1707 sighash_type,
1708 sighash_cache,
1709 ) {
1710 Ok(h) => h,
1711 Err(e) => return Some(Err(e)),
1712 }
1713 };
1714 #[cfg(not(feature = "production"))]
1715 let sighash = {
1716 use crate::transaction_hash::{
1717 calculate_transaction_sighash_single_input, SighashType,
1718 };
1719 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1720 let sighash_type = SighashType::from_byte(sighash_byte);
1721 let deleted_storage;
1722 let script_code: &[u8] = if redeem.len() < 71 {
1723 redeem.as_ref()
1724 } else {
1725 let pattern = serialize_push_data(signature_bytes);
1726 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1727 deleted_storage.as_ref()
1728 };
1729 match calculate_transaction_sighash_single_input(
1730 tx,
1731 input_index,
1732 script_code,
1733 prevout_values[input_index],
1734 sighash_type,
1735 ) {
1736 Ok(h) => h,
1737 Err(e) => return Some(Err(e)),
1738 }
1739 };
1740 let height = block_height.unwrap_or(0);
1741 let is_valid = signature::with_secp_context(|secp| {
1742 signature::verify_signature(
1743 secp,
1744 pubkey_bytes,
1745 signature_bytes,
1746 &sighash,
1747 flags,
1748 height,
1749 network,
1750 SigVersion::Base,
1751 )
1752 });
1753 return Some(is_valid);
1754 }
1755 }
1756 }
1757
1758 if (redeem.len() == 35 || redeem.len() == 67)
1760 && redeem[redeem.len() - 1] == OP_CHECKSIG
1761 && (redeem[0] == 0x21 || redeem[0] == 0x41)
1762 && stack.len() == 1
1763 {
1764 let pubkey_len = redeem.len() - 2;
1765 if pubkey_len == 33 || pubkey_len == 65 {
1766 let pubkey_bytes = &redeem.as_ref()[1..(redeem.len() - 1)];
1767 let signature_bytes = &stack[0];
1768 if !signature_bytes.is_empty() {
1769 use crate::transaction_hash::{
1770 calculate_transaction_sighash_single_input, SighashType,
1771 };
1772 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1773 let sighash_type = SighashType::from_byte(sighash_byte);
1774 let deleted_storage;
1776 let script_code: &[u8] = if redeem.len() < 71 {
1777 redeem.as_ref()
1778 } else {
1779 let pattern = serialize_push_data(signature_bytes);
1780 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1781 deleted_storage.as_ref()
1782 };
1783 match calculate_transaction_sighash_single_input(
1784 tx,
1785 input_index,
1786 script_code,
1787 prevout_values[input_index],
1788 sighash_type,
1789 #[cfg(feature = "production")]
1790 sighash_cache,
1791 ) {
1792 Ok(sighash) => {
1793 let height = block_height.unwrap_or(0);
1794 let is_valid = signature::with_secp_context(|secp| {
1795 signature::verify_signature(
1796 secp,
1797 pubkey_bytes,
1798 signature_bytes,
1799 &sighash,
1800 flags,
1801 height,
1802 network,
1803 SigVersion::Base,
1804 )
1805 });
1806 return Some(is_valid);
1807 }
1808 Err(e) => return Some(Err(e)),
1809 }
1810 }
1811 }
1812 }
1813
1814 let result = eval_script_with_context_full_inner(
1816 &redeem,
1817 &mut stack,
1818 flags,
1819 tx,
1820 input_index,
1821 prevout_values,
1822 prevout_script_pubkeys,
1823 block_height,
1824 median_time_past,
1825 network,
1826 SigVersion::Base,
1827 Some(redeem.as_ref()),
1828 None, None, #[cfg(feature = "production")]
1831 None, None, #[cfg(feature = "production")]
1834 sighash_cache,
1835 );
1836 Some(result)
1837}
1838
1839#[cfg(feature = "production")]
1842#[allow(clippy::too_many_arguments)]
1843fn try_verify_p2wpkh_fast_path(
1844 script_sig: &ByteString,
1845 script_pubkey: &[u8],
1846 witness: &crate::witness::Witness,
1847 flags: u32,
1848 tx: &Transaction,
1849 input_index: usize,
1850 prevout_values: &[i64],
1851 prevout_script_pubkeys: &[&[u8]],
1852 block_height: Option<u64>,
1853 network: crate::types::Network,
1854 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1855 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1856) -> Option<Result<bool>> {
1857 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
1859 return None;
1860 }
1861 if !script_sig.is_empty() {
1863 return None;
1864 }
1865 if witness.len() != 2 {
1866 return None;
1867 }
1868 let signature_bytes = &witness[0];
1869 let pubkey_bytes = &witness[1];
1870
1871 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1872 return Some(Ok(false));
1873 }
1874 if signature_bytes.is_empty() {
1875 return Some(Ok(false));
1876 }
1877
1878 let expected_hash = &script_pubkey[2..22];
1879 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1880 let pubkey_hash = Ripemd160::digest(sha256_hash);
1881 if &pubkey_hash[..] != expected_hash {
1882 return Some(Ok(false));
1883 }
1884
1885 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_hash);
1887
1888 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1889 let sighash = if sighash_byte == 0x01 {
1890 #[cfg(feature = "production")]
1892 if let Some(precomp) = precomputed_sighash_all {
1893 precomp
1894 } else {
1895 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1896 match crate::transaction_hash::calculate_bip143_sighash(
1897 tx,
1898 input_index,
1899 &p2pkh_script_code,
1900 amount,
1901 sighash_byte,
1902 precomputed_bip143,
1903 ) {
1904 Ok(h) => h,
1905 Err(e) => return Some(Err(e)),
1906 }
1907 }
1908 #[cfg(not(feature = "production"))]
1909 {
1910 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1911 match crate::transaction_hash::calculate_bip143_sighash(
1912 tx,
1913 input_index,
1914 &p2pkh_script_code,
1915 amount,
1916 sighash_byte,
1917 precomputed_bip143,
1918 ) {
1919 Ok(h) => h,
1920 Err(e) => return Some(Err(e)),
1921 }
1922 }
1923 } else {
1924 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1925 match crate::transaction_hash::calculate_bip143_sighash(
1926 tx,
1927 input_index,
1928 &p2pkh_script_code,
1929 amount,
1930 sighash_byte,
1931 precomputed_bip143,
1932 ) {
1933 Ok(h) => h,
1934 Err(e) => return Some(Err(e)),
1935 }
1936 };
1937
1938 let height = block_height.unwrap_or(0);
1939 let is_valid = signature::with_secp_context(|secp| {
1940 signature::verify_signature(
1941 secp,
1942 pubkey_bytes,
1943 signature_bytes,
1944 &sighash,
1945 flags,
1946 height,
1947 network,
1948 SigVersion::WitnessV0,
1949 )
1950 });
1951 Some(is_valid)
1952}
1953
1954#[cfg(feature = "production")]
1956#[allow(clippy::too_many_arguments)]
1957fn try_verify_p2wpkh_in_p2sh_fast_path(
1958 script_sig: &ByteString,
1959 script_pubkey: &[u8],
1960 witness: &crate::witness::Witness,
1961 flags: u32,
1962 tx: &Transaction,
1963 input_index: usize,
1964 prevout_values: &[i64],
1965 prevout_script_pubkeys: &[&[u8]],
1966 block_height: Option<u64>,
1967 network: crate::types::Network,
1968 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1969) -> Option<Result<bool>> {
1970 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1971 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1972 return None;
1973 }
1974 if script_pubkey.len() != 23
1975 || script_pubkey[0] != OP_HASH160
1976 || script_pubkey[1] != PUSH_20_BYTES
1977 || script_pubkey[22] != OP_EQUAL
1978 {
1979 return None;
1980 }
1981 let expected_hash = &script_pubkey[2..22];
1982
1983 let pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1984 if pushes.len() != 1 {
1985 return None;
1986 }
1987 let redeem = &pushes[0];
1988 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
1989 return None;
1990 }
1991 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1992 let redeem_hash = Ripemd160::digest(sha256_hash);
1993 if &redeem_hash[..] != expected_hash {
1994 return Some(Ok(false));
1995 }
1996
1997 if witness.len() != 2 {
1998 return None;
1999 }
2000 let signature_bytes = &witness[0];
2001 let pubkey_bytes = &witness[1];
2002 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
2003 return Some(Ok(false));
2004 }
2005 let expected_pubkey_hash = &redeem[2..22];
2006 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2007 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2008 if &pubkey_hash[..] != expected_pubkey_hash {
2009 return Some(Ok(false));
2010 }
2011
2012 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_pubkey_hash);
2014
2015 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2016 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2017 let sighash = match crate::transaction_hash::calculate_bip143_sighash(
2018 tx,
2019 input_index,
2020 &p2pkh_script_code,
2021 amount,
2022 sighash_byte,
2023 precomputed_bip143,
2024 ) {
2025 Ok(h) => h,
2026 Err(e) => return Some(Err(e)),
2027 };
2028
2029 let height = block_height.unwrap_or(0);
2030 let is_valid = signature::with_secp_context(|secp| {
2031 signature::verify_signature(
2032 secp,
2033 pubkey_bytes,
2034 signature_bytes,
2035 &sighash,
2036 flags,
2037 height,
2038 network,
2039 SigVersion::WitnessV0,
2040 )
2041 });
2042 Some(is_valid)
2043}
2044
2045#[cfg(feature = "production")]
2048#[allow(clippy::too_many_arguments)]
2049fn try_verify_p2wsh_fast_path(
2050 script_sig: &ByteString,
2051 script_pubkey: &[u8],
2052 witness: &crate::witness::Witness,
2053 flags: u32,
2054 tx: &Transaction,
2055 input_index: usize,
2056 prevout_values: &[i64],
2057 prevout_script_pubkeys: &[&[u8]],
2058 block_height: Option<u64>,
2059 median_time_past: Option<u64>,
2060 network: crate::types::Network,
2061 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2062 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2063 #[cfg(feature = "production")] sighash_cache: Option<
2064 &crate::transaction_hash::SighashMidstateCache,
2065 >,
2066) -> Option<Result<bool>> {
2067 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
2069 return None;
2070 }
2071 if !script_sig.is_empty() {
2072 return None;
2073 }
2074 if witness.is_empty() {
2075 return None;
2076 }
2077 let witness_script = witness.last().expect("witness not empty").clone();
2078 let mut stack: Vec<StackElement> = witness
2079 .iter()
2080 .take(witness.len() - 1)
2081 .map(|w| to_stack_element(w))
2082 .collect();
2083
2084 let program_hash = &script_pubkey[2..34];
2085 if program_hash.len() != 32 {
2086 return None;
2087 }
2088 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2089 if &witness_script_hash[..] != program_hash {
2090 return Some(Ok(false));
2091 }
2092
2093 let witness_sigversion = SigVersion::WitnessV0;
2097
2098 if witness_sigversion == SigVersion::WitnessV0
2100 && witness_script.len() == 25
2101 && witness_script[0] == OP_DUP
2102 && witness_script[1] == OP_HASH160
2103 && witness_script[2] == PUSH_20_BYTES
2104 && witness_script[23] == OP_EQUALVERIFY
2105 && witness_script[24] == OP_CHECKSIG
2106 && stack.len() == 2
2107 {
2108 let signature_bytes = &stack[0];
2109 let pubkey_bytes = &stack[1];
2110 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2111 let expected_pubkey_hash = &witness_script[3..23];
2112 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2113 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2114 if &pubkey_hash[..] == expected_pubkey_hash {
2115 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2116 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2117 match crate::transaction_hash::calculate_bip143_sighash(
2118 tx,
2119 input_index,
2120 witness_script.as_ref(),
2121 amount,
2122 sighash_byte,
2123 precomputed_bip143,
2124 ) {
2125 Ok(sighash) => {
2126 let height = block_height.unwrap_or(0);
2127 let is_valid = signature::with_secp_context(|secp| {
2128 signature::verify_signature(
2129 secp,
2130 pubkey_bytes,
2131 signature_bytes,
2132 &sighash,
2133 flags,
2134 height,
2135 network,
2136 SigVersion::WitnessV0,
2137 )
2138 });
2139 return Some(is_valid);
2140 }
2141 Err(e) => return Some(Err(e)),
2142 }
2143 }
2144 }
2145 }
2146
2147 if witness_sigversion == SigVersion::WitnessV0
2149 && (witness_script.len() == 35 || witness_script.len() == 67)
2150 && witness_script[witness_script.len() - 1] == OP_CHECKSIG
2151 && (witness_script[0] == 0x21 || witness_script[0] == 0x41)
2152 && stack.len() == 1
2153 {
2154 let pubkey_len = witness_script.len() - 2;
2155 if (pubkey_len == 33 || pubkey_len == 65) && !stack[0].is_empty() {
2156 let pubkey_bytes = &witness_script[1..(witness_script.len() - 1)];
2157 let signature_bytes = &stack[0];
2158 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2159 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2160 match crate::transaction_hash::calculate_bip143_sighash(
2161 tx,
2162 input_index,
2163 witness_script.as_ref(),
2164 amount,
2165 sighash_byte,
2166 precomputed_bip143,
2167 ) {
2168 Ok(sighash) => {
2169 let height = block_height.unwrap_or(0);
2170 let is_valid = signature::with_secp_context(|secp| {
2171 signature::verify_signature(
2172 secp,
2173 pubkey_bytes,
2174 signature_bytes,
2175 &sighash,
2176 flags,
2177 height,
2178 network,
2179 SigVersion::WitnessV0,
2180 )
2181 });
2182 return Some(is_valid);
2183 }
2184 Err(e) => return Some(Err(e)),
2185 }
2186 }
2187 }
2188
2189 if witness_sigversion == SigVersion::WitnessV0 {
2191 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script.as_ref()) {
2192 if stack.len() < 2 {
2193 return Some(Ok(false));
2194 }
2195 let dummy = stack[0].as_ref();
2196 let signatures: Vec<&[u8]> = stack[1..].iter().map(|e| e.as_ref()).collect();
2197
2198 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
2199 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
2200 let height = block_height.unwrap_or(0);
2201 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
2202 let activation = match network {
2203 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
2204 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
2205 crate::types::Network::Regtest => 0,
2206 };
2207 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
2208 return Some(Ok(false));
2209 }
2210 }
2211
2212 let mut cleaned = witness_script.to_vec();
2213 for sig in &signatures {
2214 if !sig.is_empty() {
2215 let pattern = serialize_push_data(sig);
2216 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
2217 }
2218 }
2219
2220 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2221 let mut sig_index = 0;
2222 let mut valid_sigs = 0u8;
2223
2224 for pubkey_bytes in pubkeys {
2225 if sig_index >= signatures.len() {
2226 break;
2227 }
2228 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
2229 sig_index += 1;
2230 }
2231 if sig_index >= signatures.len() {
2232 break;
2233 }
2234 let signature_bytes = &signatures[sig_index];
2235 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2236 match crate::transaction_hash::calculate_bip143_sighash(
2237 tx,
2238 input_index,
2239 &cleaned,
2240 amount,
2241 sighash_byte,
2242 precomputed_bip143,
2243 ) {
2244 Ok(sighash) => {
2245 let is_valid = signature::with_secp_context(|secp| {
2246 signature::verify_signature(
2247 secp,
2248 pubkey_bytes,
2249 signature_bytes,
2250 &sighash,
2251 flags,
2252 height,
2253 network,
2254 SigVersion::WitnessV0,
2255 )
2256 });
2257 match is_valid {
2258 Ok(v) if v => {
2259 valid_sigs += 1;
2260 sig_index += 1;
2261 }
2262 Ok(_) => {}
2263 Err(e) => return Some(Err(e)),
2264 }
2265 }
2266 Err(e) => return Some(Err(e)),
2267 }
2268 }
2269
2270 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
2271 for sig_bytes in &signatures[sig_index..] {
2272 if !sig_bytes.is_empty() {
2273 return Some(Err(ConsensusError::ScriptErrorWithCode {
2274 code: ScriptErrorCode::SigNullFail,
2275 message:
2276 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
2277 .into(),
2278 }));
2279 }
2280 }
2281 }
2282
2283 return Some(Ok(valid_sigs >= m));
2284 }
2285 }
2286
2287 let result = eval_script_with_context_full_inner(
2290 &witness_script,
2291 &mut stack,
2292 flags,
2293 tx,
2294 input_index,
2295 prevout_values,
2296 prevout_script_pubkeys,
2297 block_height,
2298 median_time_past,
2299 network,
2300 witness_sigversion,
2301 None, None, None, schnorr_collector,
2305 precomputed_bip143,
2306 #[cfg(feature = "production")]
2307 sighash_cache,
2308 );
2309 Some(result)
2310}
2311
2312#[cfg(feature = "production")]
2314#[allow(clippy::too_many_arguments)]
2315fn try_verify_p2tr_scriptpath_p2pk_fast_path(
2316 script_sig: &ByteString,
2317 script_pubkey: &[u8],
2318 witness: &crate::witness::Witness,
2319 _flags: u32,
2320 tx: &Transaction,
2321 input_index: usize,
2322 prevout_values: &[i64],
2323 prevout_script_pubkeys: &[&[u8]],
2324 block_height: Option<u64>,
2325 network: crate::types::Network,
2326 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2327) -> Option<Result<bool>> {
2328 use crate::activation::taproot_activation_height;
2329 use crate::taproot::parse_taproot_script_path_witness;
2330
2331 let tap_h = taproot_activation_height(network);
2332 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2333 return None;
2334 }
2335 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2336 return None;
2337 }
2338 if !script_sig.is_empty() {
2339 return None;
2340 }
2341 if witness.len() < 2 {
2342 return None;
2343 }
2344 let mut output_key = [0u8; 32];
2345 output_key.copy_from_slice(&script_pubkey[2..34]);
2346 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
2347 let parsed = match parse_taproot_script_path_witness(&witness_body, &output_key) {
2348 Ok(Some(p)) => p,
2349 Ok(None) | Err(_) => return None,
2350 };
2351 let (tapscript, stack_items, control_block) = parsed;
2352 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
2353 return None;
2354 }
2355 if stack_items.len() != 1 {
2356 return None;
2357 }
2358 let (sig_bytes, sighash_type) =
2359 crate::bip348::try_parse_taproot_schnorr_witness_sig(stack_items[0].as_ref())?;
2360 let pubkey_32 = &tapscript[1..33];
2361 let sighash = crate::taproot::compute_tapscript_signature_hash(
2362 tx,
2363 input_index,
2364 prevout_values,
2365 prevout_script_pubkeys,
2366 &tapscript,
2367 control_block.leaf_version,
2368 0xffff_ffff,
2369 sighash_type,
2370 annex_hash.as_ref(),
2371 )
2372 .ok()?;
2373 let result = crate::bip348::verify_tapscript_schnorr_signature(
2374 &sighash,
2375 pubkey_32,
2376 &sig_bytes,
2377 schnorr_collector,
2378 );
2379 Some(result)
2380}
2381
2382#[cfg(feature = "production")]
2385#[allow(clippy::too_many_arguments)]
2386fn verify_p2tr_keypath_witness(
2387 script_pubkey: &[u8],
2388 witness: &crate::witness::Witness,
2389 tx: &Transaction,
2390 input_index: usize,
2391 prevout_values: &[i64],
2392 prevout_script_pubkeys: &[&[u8]],
2393 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2394) -> Result<bool> {
2395 use crate::bip348::{
2396 try_parse_taproot_schnorr_witness_sig, verify_tapscript_schnorr_signature,
2397 };
2398
2399 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
2400 if witness_body.len() != 1 {
2401 return Ok(false);
2402 }
2403 let Some((sig_bytes, sighash_type)) = try_parse_taproot_schnorr_witness_sig(&witness_body[0])
2404 else {
2405 return Ok(false);
2406 };
2407 let output_key = &script_pubkey[2..34];
2408 let sighash = crate::taproot::compute_taproot_signature_hash(
2409 tx,
2410 input_index,
2411 prevout_values,
2412 prevout_script_pubkeys,
2413 sighash_type,
2414 annex_hash.as_ref(),
2415 )?;
2416 verify_tapscript_schnorr_signature(&sighash, output_key, &sig_bytes, schnorr_collector)
2417}
2418
2419#[cfg(feature = "production")]
2420#[allow(clippy::too_many_arguments)]
2421fn try_verify_p2tr_keypath_fast_path(
2422 script_sig: &ByteString,
2423 script_pubkey: &[u8],
2424 witness: &crate::witness::Witness,
2425 _flags: u32,
2426 tx: &Transaction,
2427 input_index: usize,
2428 prevout_values: &[i64],
2429 prevout_script_pubkeys: &[&[u8]],
2430 block_height: Option<u64>,
2431 network: crate::types::Network,
2432 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2433) -> Option<Result<bool>> {
2434 use crate::activation::taproot_activation_height;
2435 let tap_h = taproot_activation_height(network);
2436 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2437 return None;
2438 }
2439 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2441 return None;
2442 }
2443 if !script_sig.is_empty() {
2444 return None;
2445 }
2446 let (witness_body, _) = crate::taproot::strip_taproot_annex(witness);
2448 if witness_body.len() != 1 {
2449 return None;
2450 }
2451 crate::bip348::try_parse_taproot_schnorr_witness_sig(&witness_body[0])?;
2452 Some(verify_p2tr_keypath_witness(
2453 script_pubkey,
2454 witness,
2455 tx,
2456 input_index,
2457 prevout_values,
2458 prevout_script_pubkeys,
2459 schnorr_collector,
2460 ))
2461}
2462
2463#[spec_locked("5.2", "VerifyScript")]
2464pub fn verify_script_with_context_full(
2465 script_sig: &ByteString,
2466 script_pubkey: &[u8],
2467 witness: Option<&crate::witness::Witness>,
2468 flags: u32,
2469 tx: &Transaction,
2470 input_index: usize,
2471 prevout_values: &[i64],
2472 prevout_script_pubkeys: &[&[u8]],
2473 block_height: Option<u64>,
2474 median_time_past: Option<u64>,
2475 network: crate::types::Network,
2476 _sigversion: SigVersion,
2477 #[cfg(feature = "production")] schnorr_collector: Option<
2478 &crate::bip348::SchnorrSignatureCollector,
2479 >,
2480 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2481 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2482 #[cfg(feature = "production")] sighash_cache: Option<
2483 &crate::transaction_hash::SighashMidstateCache,
2484 >,
2485 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
2486) -> Result<bool> {
2487 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
2489 return Err(ConsensusError::ScriptErrorWithCode {
2490 code: ScriptErrorCode::TxInputInvalid,
2491 message: format!(
2492 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
2493 prevout_values.len(),
2494 prevout_script_pubkeys.len(),
2495 tx.inputs.len(),
2496 input_index,
2497 )
2498 .into(),
2499 });
2500 }
2501
2502 if input_index < prevout_values.len() {
2508 let prevout_value = prevout_values[input_index];
2509 if prevout_value < 0 {
2510 return Err(ConsensusError::ScriptErrorWithCode {
2511 code: ScriptErrorCode::ValueOverflow,
2512 message: "Prevout value cannot be negative".into(),
2513 });
2514 }
2515 #[cfg(feature = "production")]
2516 {
2517 use precomputed_constants::MAX_MONEY_U64;
2518 if (prevout_value as u64) > MAX_MONEY_U64 {
2519 return Err(ConsensusError::ScriptErrorWithCode {
2520 code: ScriptErrorCode::ValueOverflow,
2521 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2522 });
2523 }
2524 }
2525 #[cfg(not(feature = "production"))]
2526 {
2527 use crate::constants::MAX_MONEY;
2528 if prevout_value > MAX_MONEY {
2529 return Err(ConsensusError::ScriptErrorWithCode {
2530 code: ScriptErrorCode::ValueOverflow,
2531 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2532 });
2533 }
2534 }
2535 }
2536
2537 if input_index >= tx.inputs.len() {
2539 return Err(ConsensusError::ScriptErrorWithCode {
2540 code: ScriptErrorCode::TxInputInvalid,
2541 message: format!(
2542 "Input index {} out of bounds (tx has {} inputs)",
2543 input_index,
2544 tx.inputs.len()
2545 )
2546 .into(),
2547 });
2548 }
2549
2550 #[cfg(feature = "production")]
2552 if witness.is_none() {
2553 if let Some(result) = try_verify_p2pk_fast_path(
2554 script_sig,
2555 script_pubkey,
2556 flags,
2557 tx,
2558 input_index,
2559 prevout_values,
2560 prevout_script_pubkeys,
2561 block_height,
2562 network,
2563 #[cfg(feature = "production")]
2564 sighash_cache,
2565 ) {
2566 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
2567 return result;
2568 }
2569 if let Some(result) = try_verify_p2pkh_fast_path(
2570 script_sig,
2571 script_pubkey,
2572 flags,
2573 tx,
2574 input_index,
2575 prevout_values,
2576 prevout_script_pubkeys,
2577 block_height,
2578 network,
2579 #[cfg(feature = "production")]
2580 precomputed_sighash_all,
2581 #[cfg(feature = "production")]
2582 sighash_cache,
2583 #[cfg(feature = "production")]
2584 precomputed_p2pkh_hash,
2585 ) {
2586 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
2587 return result;
2588 }
2589 if let Some(result) = try_verify_p2sh_fast_path(
2590 script_sig,
2591 script_pubkey,
2592 flags,
2593 tx,
2594 input_index,
2595 prevout_values,
2596 prevout_script_pubkeys,
2597 block_height,
2598 median_time_past,
2599 network,
2600 #[cfg(feature = "production")]
2601 sighash_cache,
2602 #[cfg(feature = "production")]
2603 precomputed_sighash_all,
2604 ) {
2605 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
2606 return result;
2607 }
2608 if let Some(result) = try_verify_bare_multisig_fast_path(
2609 script_sig,
2610 script_pubkey,
2611 flags,
2612 tx,
2613 input_index,
2614 prevout_values,
2615 prevout_script_pubkeys,
2616 block_height,
2617 network,
2618 #[cfg(feature = "production")]
2619 sighash_cache,
2620 ) {
2621 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
2622 return result;
2623 }
2624 }
2625 #[cfg(feature = "production")]
2627 if let Some(wit) = witness {
2628 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
2629 script_sig,
2630 script_pubkey,
2631 wit,
2632 flags,
2633 tx,
2634 input_index,
2635 prevout_values,
2636 prevout_script_pubkeys,
2637 block_height,
2638 network,
2639 precomputed_bip143,
2640 ) {
2641 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2642 return result;
2643 }
2644 if let Some(result) = try_verify_p2wpkh_fast_path(
2645 script_sig,
2646 script_pubkey,
2647 wit,
2648 flags,
2649 tx,
2650 input_index,
2651 prevout_values,
2652 prevout_script_pubkeys,
2653 block_height,
2654 network,
2655 precomputed_bip143,
2656 precomputed_sighash_all,
2657 ) {
2658 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2659 return result;
2660 }
2661 if let Some(result) = try_verify_p2wsh_fast_path(
2662 script_sig,
2663 script_pubkey,
2664 wit,
2665 flags,
2666 tx,
2667 input_index,
2668 prevout_values,
2669 prevout_script_pubkeys,
2670 block_height,
2671 median_time_past,
2672 network,
2673 schnorr_collector,
2674 precomputed_bip143,
2675 #[cfg(feature = "production")]
2676 sighash_cache,
2677 ) {
2678 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
2679 return result;
2680 }
2681 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
2682 script_sig,
2683 script_pubkey,
2684 wit,
2685 flags,
2686 tx,
2687 input_index,
2688 prevout_values,
2689 prevout_script_pubkeys,
2690 block_height,
2691 network,
2692 schnorr_collector,
2693 ) {
2694 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2695 return result;
2696 }
2697 if let Some(result) = try_verify_p2tr_keypath_fast_path(
2698 script_sig,
2699 script_pubkey,
2700 wit,
2701 flags,
2702 tx,
2703 input_index,
2704 prevout_values,
2705 prevout_script_pubkeys,
2706 block_height,
2707 network,
2708 schnorr_collector,
2709 ) {
2710 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2711 return result;
2712 }
2713 }
2714 #[cfg(feature = "production")]
2715 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
2716
2717 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
2721 let is_p2sh = (flags & SCRIPT_VERIFY_P2SH) != 0
2722 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; if is_p2sh {
2733 let mut i = 0;
2734 while i < script_sig.len() {
2735 let opcode = script_sig[i];
2736 if !is_push_opcode(opcode) {
2737 return Ok(false);
2739 }
2740 if opcode == OP_0 {
2742 i += 1;
2744 } else if opcode <= 0x4b {
2745 let len = opcode as usize;
2747 if i + 1 + len > script_sig.len() {
2748 return Ok(false); }
2750 i += 1 + len;
2751 } else if opcode == OP_PUSHDATA1 {
2752 if i + 1 >= script_sig.len() {
2754 return Ok(false);
2755 }
2756 let len = script_sig[i + 1] as usize;
2757 if i + 2 + len > script_sig.len() {
2758 return Ok(false);
2759 }
2760 i += 2 + len;
2761 } else if opcode == OP_PUSHDATA2 {
2762 if i + 2 >= script_sig.len() {
2764 return Ok(false);
2765 }
2766 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
2767 if i + 3 + len > script_sig.len() {
2768 return Ok(false);
2769 }
2770 i += 3 + len;
2771 } else if opcode == OP_PUSHDATA4 {
2772 if i + 4 >= script_sig.len() {
2774 return Ok(false);
2775 }
2776 let len = u32::from_le_bytes([
2777 script_sig[i + 1],
2778 script_sig[i + 2],
2779 script_sig[i + 3],
2780 script_sig[i + 4],
2781 ]) as usize;
2782 if i + 5 + len > script_sig.len() {
2783 return Ok(false);
2784 }
2785 i += 5 + len;
2786 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
2787 i += 1;
2790 } else {
2791 return Ok(false);
2793 }
2794 }
2795 if let Some(result) = try_verify_p2sh_multisig_fast_path(
2796 script_sig,
2797 script_pubkey,
2798 flags,
2799 tx,
2800 input_index,
2801 prevout_values,
2802 prevout_script_pubkeys,
2803 block_height,
2804 network,
2805 #[cfg(feature = "production")]
2806 sighash_cache,
2807 ) {
2808 return result;
2809 }
2810 }
2811
2812 #[cfg(feature = "production")]
2813 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
2814 #[cfg(feature = "production")]
2815 let stack = &mut _stack_guard.0;
2816 #[cfg(not(feature = "production"))]
2817 let mut stack = Vec::with_capacity(20);
2818
2819 let script_sig_result = eval_script_with_context_full(
2823 script_sig,
2824 stack,
2825 flags,
2826 tx,
2827 input_index,
2828 prevout_values,
2829 prevout_script_pubkeys,
2830 block_height,
2831 median_time_past,
2832 network,
2833 SigVersion::Base,
2834 None, None, #[cfg(feature = "production")]
2837 schnorr_collector,
2838 None, #[cfg(feature = "production")]
2840 sighash_cache,
2841 )?;
2842 if !script_sig_result {
2843 return Ok(false);
2844 }
2845
2846 let redeem_script: Option<ByteString> = if is_p2sh && !stack.is_empty() {
2848 Some(stack.last().expect("Stack is not empty").as_ref().to_vec())
2849 } else {
2850 None
2851 };
2852
2853 use crate::activation::taproot_activation_height;
2857 let tap_h = taproot_activation_height(network);
2858 let is_taproot = redeem_script.is_none() && block_height.is_some() && block_height.unwrap() >= tap_h
2860 && script_pubkey.len() == 34
2861 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES; if is_taproot && !script_sig.is_empty() {
2866 return Ok(false); }
2868
2869 let is_direct_witness_program = redeem_script.is_none() && !is_taproot && script_pubkey.len() >= 3
2876 && 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;
2882 if is_direct_witness_program {
2883 if let Some(witness_stack) = witness {
2884 if script_pubkey[1] == PUSH_32_BYTES {
2885 if witness_stack.is_empty() {
2888 return Ok(false); }
2890
2891 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2893
2894 let program_bytes = &script_pubkey[2..];
2896 if program_bytes.len() != 32 {
2897 return Ok(false); }
2899
2900 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2901 if &witness_script_hash[..] != program_bytes {
2902 return Ok(false); }
2904
2905 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2907 stack.push(to_stack_element(element));
2908 }
2909
2910 witness_script_to_execute = Some(witness_script.clone());
2912 } else if script_pubkey[1] == PUSH_20_BYTES {
2913 if witness_stack.len() != 2 {
2916 return Ok(false); }
2918
2919 for element in witness_stack.iter() {
2920 stack.push(to_stack_element(element));
2921 }
2922 } else {
2923 return Ok(false); }
2925 } else {
2926 return Ok(false); }
2928 }
2929
2930 if is_taproot {
2931 let Some(witness_stack) = witness else {
2932 return Ok(false);
2933 };
2934 if witness_stack.is_empty() {
2935 return Ok(false);
2936 }
2937 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness_stack);
2939 if witness_body.is_empty() {
2940 return Ok(false);
2941 }
2942 if witness_body.len() == 1 {
2943 #[cfg(feature = "production")]
2944 {
2945 return verify_p2tr_keypath_witness(
2946 script_pubkey,
2947 witness_stack,
2948 tx,
2949 input_index,
2950 prevout_values,
2951 prevout_script_pubkeys,
2952 schnorr_collector,
2953 );
2954 }
2955 #[cfg(not(feature = "production"))]
2956 {
2957 return Ok(false);
2958 }
2959 }
2960 if witness_body.len() < 2 {
2961 return Ok(false);
2962 }
2963 let mut output_key = [0u8; 32];
2964 output_key.copy_from_slice(&script_pubkey[2..34]);
2965 match crate::taproot::parse_taproot_script_path_witness(&witness_body, &output_key)? {
2966 None => return Ok(false),
2967 Some((tapscript, stack_items, _control_block)) => {
2968 for item in &stack_items {
2969 stack.push(to_stack_element(item));
2970 }
2971 let tapscript_flags = flags | 0x8000;
2972 if !eval_script_with_context_full(
2973 &tapscript,
2974 stack,
2975 tapscript_flags,
2976 tx,
2977 input_index,
2978 prevout_values,
2979 prevout_script_pubkeys,
2980 block_height,
2981 median_time_past,
2982 network,
2983 SigVersion::Tapscript,
2984 None,
2985 annex_hash.as_ref(),
2986 #[cfg(feature = "production")]
2987 schnorr_collector,
2988 None,
2989 #[cfg(feature = "production")]
2990 sighash_cache,
2991 )? {
2992 return Ok(false);
2993 }
2994 return Ok(true);
2995 }
2996 }
2997 }
2998
2999 let script_pubkey_result = eval_script_with_context_full(
3006 script_pubkey,
3007 stack,
3008 flags,
3009 tx,
3010 input_index,
3011 prevout_values,
3012 prevout_script_pubkeys,
3013 block_height,
3014 median_time_past,
3015 network,
3016 SigVersion::Base,
3017 Some(script_sig),
3018 None, #[cfg(feature = "production")]
3020 schnorr_collector,
3021 None, #[cfg(feature = "production")]
3023 sighash_cache,
3024 )?;
3025 if !script_pubkey_result {
3026 return Ok(false);
3027 }
3028
3029 if let Some(witness_script) = witness_script_to_execute {
3031 let witness_sigversion = SigVersion::WitnessV0;
3034
3035 if !eval_script_with_context_full(
3038 &witness_script,
3039 stack,
3040 flags,
3041 tx,
3042 input_index,
3043 prevout_values,
3044 prevout_script_pubkeys,
3045 block_height,
3046 median_time_past,
3047 network,
3048 witness_sigversion,
3049 None, None, #[cfg(feature = "production")]
3052 schnorr_collector,
3053 precomputed_bip143, #[cfg(feature = "production")]
3055 sighash_cache,
3056 )? {
3057 return Ok(false);
3058 }
3059 }
3060
3061 if let Some(redeem) = redeem_script {
3066 if stack.is_empty() {
3068 return Ok(false); }
3070
3071 let top = stack.last().expect("Stack is not empty");
3073 if !cast_to_bool(top) {
3074 return Ok(false); }
3076
3077 stack.pop();
3079
3080 let is_witness_program = redeem.len() >= 3
3085 && 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() {
3090 let program_bytes = &redeem[2..];
3099
3100 if redeem[1] == PUSH_32_BYTES {
3101 if program_bytes.len() != 32 {
3104 return Ok(false); }
3106
3107 if let Some(witness_stack) = witness {
3112 if witness_stack.is_empty() {
3113 return Ok(false); }
3115
3116 let witness_script = witness_stack.last().expect("Witness stack is not empty");
3118 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
3119 if &witness_script_hash[..] != program_bytes {
3120 return Ok(false); }
3122
3123 stack.clear();
3126
3127 for element in witness_stack.iter().take(witness_stack.len() - 1) {
3130 stack.push(to_stack_element(element));
3131 }
3132
3133 let witness_sigversion = SigVersion::WitnessV0;
3137
3138 if !eval_script_with_context_full(
3140 witness_script,
3141 stack,
3142 flags,
3143 tx,
3144 input_index,
3145 prevout_values,
3146 prevout_script_pubkeys,
3147 block_height,
3148 median_time_past,
3149 network,
3150 witness_sigversion,
3151 None, None, #[cfg(feature = "production")]
3154 schnorr_collector,
3155 precomputed_bip143, #[cfg(feature = "production")]
3157 sighash_cache,
3158 )? {
3159 return Ok(false);
3160 }
3161 } else {
3162 return Ok(false); }
3164 } else if redeem[1] == PUSH_20_BYTES {
3165 let pubkey_hash = &redeem[2..22]; let witness_stack = match witness {
3171 Some(w) => w,
3172 None => return Ok(false), };
3174 if witness_stack.len() != 2 {
3175 return Ok(false); }
3177 let signature_bytes = &witness_stack[0];
3178 let pubkey_bytes = &witness_stack[1];
3179
3180 if signature_bytes.is_empty() {
3181 return Ok(false);
3182 }
3183 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
3184 return Ok(false);
3185 }
3186
3187 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
3189 let computed_hash = Ripemd160::digest(pubkey_sha256);
3190 if &computed_hash[..] != pubkey_hash {
3191 return Ok(false);
3192 }
3193
3194 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
3196 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
3197 let p2pkh_script_code = bip143_p2wpkh_script_code(pubkey_hash);
3198 let sighash = crate::transaction_hash::calculate_bip143_sighash(
3199 tx,
3200 input_index,
3201 &p2pkh_script_code,
3202 amount,
3203 sighash_byte,
3204 precomputed_bip143,
3205 )?;
3206
3207 let height = block_height.unwrap_or(0);
3208 return signature::with_secp_context(|secp| {
3209 signature::verify_signature(
3210 secp,
3211 pubkey_bytes,
3212 signature_bytes,
3213 &sighash,
3214 flags,
3215 height,
3216 network,
3217 SigVersion::WitnessV0,
3218 )
3219 });
3220 } else {
3221 return Ok(false); }
3223 } else {
3225 let redeem_result = eval_script_with_context_full_inner(
3229 &redeem,
3230 stack,
3231 flags,
3232 tx,
3233 input_index,
3234 prevout_values,
3235 prevout_script_pubkeys,
3236 block_height,
3237 median_time_past,
3238 network,
3239 SigVersion::Base,
3240 Some(redeem.as_ref()), Some(script_sig), None, #[cfg(feature = "production")]
3244 None, None, #[cfg(feature = "production")]
3247 sighash_cache,
3248 )?;
3249 if !redeem_result {
3250 return Ok(false);
3251 }
3252 }
3253 }
3254
3255 assert!(
3257 stack.len() <= 1000,
3258 "Stack size {} exceeds reasonable maximum after scriptPubkey",
3259 stack.len()
3260 );
3261
3262 if let Some(_witness_stack) = witness {
3271 }
3275
3276 const SCRIPT_VERIFY_CLEANSTACK: u32 = 0x100;
3282
3283 let final_result = if (flags & SCRIPT_VERIFY_CLEANSTACK) != 0 {
3284 stack.len() == 1 && cast_to_bool(&stack[0])
3286 } else {
3287 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
3289 };
3290 Ok(final_result)
3291}
3292
3293#[allow(dead_code)]
3295fn eval_script_with_context(
3296 script: &ByteString,
3297 stack: &mut Vec<StackElement>,
3298 flags: u32,
3299 tx: &Transaction,
3300 input_index: usize,
3301 prevouts: &[TransactionOutput],
3302 network: crate::types::Network,
3303) -> Result<bool> {
3304 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
3306 let prevout_script_pubkeys: Vec<&[u8]> =
3307 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
3308 eval_script_with_context_full(
3309 script,
3310 stack,
3311 flags,
3312 tx,
3313 input_index,
3314 &prevout_values,
3315 &prevout_script_pubkeys,
3316 None, None, network,
3319 SigVersion::Base,
3320 None, None, #[cfg(feature = "production")]
3323 None, None, #[cfg(feature = "production")]
3326 None, )
3328}
3329
3330#[allow(clippy::too_many_arguments)]
3332fn eval_script_with_context_full(
3333 script: &[u8],
3334 stack: &mut Vec<StackElement>,
3335 flags: u32,
3336 tx: &Transaction,
3337 input_index: usize,
3338 prevout_values: &[i64],
3339 prevout_script_pubkeys: &[&[u8]],
3340 block_height: Option<u64>,
3341 median_time_past: Option<u64>,
3342 network: crate::types::Network,
3343 sigversion: SigVersion,
3344 script_sig_for_sighash: Option<&ByteString>,
3345 taproot_annex_hash: Option<&Hash>,
3346 #[cfg(feature = "production")] schnorr_collector: Option<
3347 &crate::bip348::SchnorrSignatureCollector,
3348 >,
3349 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3350 #[cfg(feature = "production")] sighash_cache: Option<
3351 &crate::transaction_hash::SighashMidstateCache,
3352 >,
3353) -> Result<bool> {
3354 #[cfg(all(feature = "production", feature = "profile"))]
3355 let _t0 = std::time::Instant::now();
3356 let r = eval_script_with_context_full_inner(
3357 script,
3358 stack,
3359 flags,
3360 tx,
3361 input_index,
3362 prevout_values,
3363 prevout_script_pubkeys,
3364 block_height,
3365 median_time_past,
3366 network,
3367 sigversion,
3368 None,
3369 script_sig_for_sighash,
3370 taproot_annex_hash,
3371 #[cfg(feature = "production")]
3372 schnorr_collector,
3373 precomputed_bip143,
3374 #[cfg(feature = "production")]
3375 sighash_cache,
3376 );
3377 #[cfg(all(feature = "production", feature = "profile"))]
3378 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
3379 r
3380}
3381
3382fn eval_script_with_context_full_inner(
3384 script: &[u8],
3385 stack: &mut Vec<StackElement>,
3386 flags: u32,
3387 tx: &Transaction,
3388 input_index: usize,
3389 prevout_values: &[i64],
3390 prevout_script_pubkeys: &[&[u8]],
3391 block_height: Option<u64>,
3392 median_time_past: Option<u64>,
3393 network: crate::types::Network,
3394 sigversion: SigVersion,
3395 redeem_script_for_sighash: Option<&[u8]>,
3396 script_sig_for_sighash: Option<&ByteString>,
3397 taproot_annex_hash: Option<&Hash>,
3398 #[cfg(feature = "production")] schnorr_collector: Option<
3399 &crate::bip348::SchnorrSignatureCollector,
3400 >,
3401 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3402 #[cfg(feature = "production")] sighash_cache: Option<
3403 &crate::transaction_hash::SighashMidstateCache,
3404 >,
3405) -> Result<bool> {
3406 use crate::constants::MAX_SCRIPT_SIZE;
3409 use crate::error::{ConsensusError, ScriptErrorCode};
3410
3411 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
3413 && script.len() > MAX_SCRIPT_SIZE
3414 {
3415 return Err(ConsensusError::ScriptErrorWithCode {
3416 code: ScriptErrorCode::ScriptSize,
3417 message: "Script size exceeds maximum".into(),
3418 });
3419 }
3420 assert!(
3421 stack.len() <= 1000,
3422 "Stack size {} exceeds reasonable maximum at start",
3423 stack.len()
3424 );
3425
3426 if sigversion == SigVersion::Tapscript {
3431 use crate::script::flags::SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS;
3432 let mut pc = 0usize;
3433 while pc < script.len() {
3434 let opcode = script[pc];
3435 if is_op_success(opcode) {
3436 if flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS != 0 {
3437 return Err(ConsensusError::ScriptErrorWithCode {
3438 code: ScriptErrorCode::BadOpcode,
3439 message: format!("OP_SUCCESSx opcode 0x{opcode:02x} is discouraged").into(),
3440 });
3441 }
3442 return Ok(true);
3443 }
3444 pc += op_advance(script, pc);
3446 }
3447 }
3448
3449 if stack.capacity() < 20 {
3451 stack.reserve(20);
3452 }
3453 let mut op_count = 0;
3454 assert!(op_count == 0, "Op count must start at zero");
3456
3457 #[cfg(feature = "production")]
3459 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
3460 #[cfg(not(feature = "production"))]
3461 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
3462 assert!(control_stack.is_empty(), "Control stack must start empty");
3464
3465 #[cfg(feature = "production")]
3466 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
3467 #[cfg(not(feature = "production"))]
3468 let mut altstack: Vec<StackElement> = Vec::new();
3469
3470 let mut code_separator_pos: usize = 0;
3474 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
3475
3476 let mut i = 0;
3478 while i < script.len() {
3479 #[cfg(feature = "production")]
3480 {
3481 prefetch::prefetch_ahead(script, i, 64); }
3484 let opcode = {
3486 #[cfg(feature = "production")]
3487 {
3488 unsafe { *script.get_unchecked(i) }
3489 }
3490 #[cfg(not(feature = "production"))]
3491 {
3492 script[i]
3493 }
3494 };
3495
3496 let in_false_branch = control_flow::in_false_branch(&control_stack);
3498
3499 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
3501 op_count += 1;
3502 assert!(
3504 op_count <= MAX_SCRIPT_OPS + 1,
3505 "Op count {op_count} must not exceed MAX_SCRIPT_OPS + 1"
3506 );
3507 if op_count > MAX_SCRIPT_OPS {
3508 return Err(make_operation_limit_error());
3509 }
3510 }
3511
3512 if stack.len() + altstack.len() > MAX_STACK_SIZE {
3514 return Err(make_stack_overflow_error());
3515 }
3516
3517 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
3519 let (data, advance) = if opcode <= 0x4b {
3520 let len = opcode as usize;
3522 if i + 1 + len > script.len() {
3523 return Ok(false); }
3525 (&script[i + 1..i + 1 + len], 1 + len)
3526 } else if opcode == OP_PUSHDATA1 {
3527 if i + 1 >= script.len() {
3529 return Ok(false);
3530 }
3531 let len = script[i + 1] as usize;
3532 if i + 2 + len > script.len() {
3533 return Ok(false);
3534 }
3535 (&script[i + 2..i + 2 + len], 2 + len)
3536 } else if opcode == OP_PUSHDATA2 {
3537 if i + 2 >= script.len() {
3539 return Ok(false);
3540 }
3541 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
3542 if i + 3 + len > script.len() {
3543 return Ok(false);
3544 }
3545 (&script[i + 3..i + 3 + len], 3 + len)
3546 } else {
3547 if i + 4 >= script.len() {
3550 return Ok(false);
3551 }
3552 let len = u32::from_le_bytes([
3553 script[i + 1],
3554 script[i + 2],
3555 script[i + 3],
3556 script[i + 4],
3557 ]) as usize;
3558 let data_start = i.saturating_add(5);
3559 let data_end = data_start.saturating_add(len);
3560 let advance = 5usize.saturating_add(len);
3561 if advance < 5 || data_end > script.len() || data_end < data_start {
3562 return Ok(false); }
3564 (&script[data_start..data_end], advance)
3565 };
3566
3567 if !in_false_branch {
3569 stack.push(to_stack_element(data));
3570 }
3571 i += advance;
3572 continue;
3573 }
3574
3575 if opcode == OP_DUP {
3581 if !in_false_branch {
3582 if stack.is_empty() {
3583 return Err(ConsensusError::ScriptErrorWithCode {
3584 code: ScriptErrorCode::InvalidStackOperation,
3585 message: "OP_DUP: empty stack".into(),
3586 });
3587 }
3588 let len = stack.len();
3591 #[cfg(feature = "production")]
3592 {
3593 if stack.capacity() == stack.len() {
3595 stack.reserve(1);
3596 }
3597 let item = unsafe { stack.get_unchecked(len - 1).clone() };
3599 stack.push(item);
3600 }
3601 #[cfg(not(feature = "production"))]
3602 {
3603 let item = stack.last().unwrap();
3604 stack.push(item.clone());
3605 }
3606 }
3607 i += 1;
3608 continue;
3609 }
3610
3611 if opcode == OP_EQUALVERIFY {
3613 if !in_false_branch {
3614 if stack.len() < 2 {
3615 return Err(ConsensusError::ScriptErrorWithCode {
3616 code: ScriptErrorCode::InvalidStackOperation,
3617 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3618 });
3619 }
3620 let a = stack.pop().unwrap();
3621 let b = stack.pop().unwrap();
3622 if a != b {
3623 return Ok(false);
3624 }
3625 }
3626 i += 1;
3627 continue;
3628 }
3629
3630 if opcode == OP_HASH160 {
3632 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
3633 return Ok(false);
3634 }
3635 i += 1;
3636 continue;
3637 }
3638
3639 if opcode == OP_VERIFY {
3641 if !in_false_branch {
3642 if let Some(item) = stack.pop() {
3643 if !cast_to_bool(&item) {
3644 return Ok(false);
3645 }
3646 } else {
3647 return Ok(false);
3648 }
3649 }
3650 i += 1;
3651 continue;
3652 }
3653
3654 if opcode == OP_EQUAL {
3656 if !in_false_branch {
3657 if stack.len() < 2 {
3658 return Err(ConsensusError::ScriptErrorWithCode {
3659 code: ScriptErrorCode::InvalidStackOperation,
3660 message: "OP_EQUAL: insufficient stack items".into(),
3661 });
3662 }
3663 let a = stack.pop().unwrap();
3664 let b = stack.pop().unwrap();
3665 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3666 }
3667 i += 1;
3668 continue;
3669 }
3670
3671 if opcode == OP_CHECKSIG
3674 || opcode == OP_CHECKSIGVERIFY
3675 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
3676 {
3677 if !in_false_branch {
3678 let effective_script_code = Some(&script[code_separator_pos..]);
3679 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3680 (Some(script), Some(last_codesep_opcode_pos))
3681 } else {
3682 (None, None)
3683 };
3684 let ctx = context::ScriptContext {
3685 tx,
3686 input_index,
3687 prevout_values,
3688 prevout_script_pubkeys,
3689 block_height,
3690 median_time_past,
3691 network,
3692 sigversion,
3693 redeem_script_for_sighash,
3694 script_sig_for_sighash,
3695 tapscript_for_sighash: tapscript,
3696 tapscript_codesep_pos: codesep,
3697 taproot_annex_hash,
3698 #[cfg(feature = "production")]
3699 schnorr_collector,
3700 #[cfg(feature = "production")]
3701 precomputed_bip143,
3702 #[cfg(feature = "production")]
3703 sighash_cache,
3704 };
3705 if !execute_opcode_with_context_full(
3706 opcode,
3707 stack,
3708 flags,
3709 &ctx,
3710 effective_script_code,
3711 )? {
3712 return Ok(false);
3713 }
3714 }
3715 i += 1;
3716 continue;
3717 }
3718
3719 match opcode {
3720 OP_0 => {
3722 if !in_false_branch {
3723 stack.push(to_stack_element(&[]));
3724 }
3725 }
3726
3727 OP_1_RANGE_START..=OP_1_RANGE_END => {
3729 if !in_false_branch {
3730 let num = opcode - OP_N_BASE;
3731 stack.push(to_stack_element(&[num]));
3732 }
3733 }
3734
3735 OP_1NEGATE => {
3737 if !in_false_branch {
3738 stack.push(to_stack_element(&[0x81])); }
3740 }
3741
3742 OP_NOP => {
3744 }
3746
3747 OP_VER => {
3752 if !in_false_branch {
3753 return Err(ConsensusError::ScriptErrorWithCode {
3754 code: ScriptErrorCode::DisabledOpcode,
3755 message: "OP_VER is disabled".into(),
3756 });
3757 }
3758 }
3759
3760 OP_IF => {
3761 if in_false_branch {
3763 control_stack.push(control_flow::ControlBlock::If { executing: false });
3764 i += 1;
3765 continue;
3766 }
3767
3768 if stack.is_empty() {
3769 return Err(ConsensusError::ScriptErrorWithCode {
3770 code: ScriptErrorCode::InvalidStackOperation,
3771 message: "OP_IF: empty stack".into(),
3772 });
3773 }
3774 let condition_bytes = stack.pop().unwrap();
3775 let condition = cast_to_bool(&condition_bytes);
3776
3777 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3778 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3779 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3780 && !control_flow::is_minimal_if_condition(&condition_bytes)
3781 {
3782 return Err(ConsensusError::ScriptErrorWithCode {
3783 code: ScriptErrorCode::MinimalIf,
3784 message: "OP_IF condition must be minimally encoded".into(),
3785 });
3786 }
3787
3788 control_stack.push(control_flow::ControlBlock::If {
3789 executing: condition,
3790 });
3791 }
3792 OP_NOTIF => {
3793 if in_false_branch {
3795 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
3796 i += 1;
3797 continue;
3798 }
3799
3800 if stack.is_empty() {
3801 return Err(ConsensusError::ScriptErrorWithCode {
3802 code: ScriptErrorCode::InvalidStackOperation,
3803 message: "OP_NOTIF: empty stack".into(),
3804 });
3805 }
3806 let condition_bytes = stack.pop().unwrap();
3807 let condition = cast_to_bool(&condition_bytes);
3808
3809 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3810 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3811 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3812 && !control_flow::is_minimal_if_condition(&condition_bytes)
3813 {
3814 return Err(ConsensusError::ScriptErrorWithCode {
3815 code: ScriptErrorCode::MinimalIf,
3816 message: "OP_NOTIF condition must be minimally encoded".into(),
3817 });
3818 }
3819
3820 control_stack.push(control_flow::ControlBlock::NotIf {
3821 executing: !condition,
3822 });
3823 }
3824 OP_ELSE => {
3825 if let Some(block) = control_stack.last_mut() {
3827 match block {
3828 control_flow::ControlBlock::If { executing }
3829 | control_flow::ControlBlock::NotIf { executing } => {
3830 *executing = !*executing;
3831 }
3832 }
3833 } else {
3834 return Err(ConsensusError::ScriptErrorWithCode {
3835 code: ScriptErrorCode::UnbalancedConditional,
3836 message: "OP_ELSE without matching IF/NOTIF".into(),
3837 });
3838 }
3839 }
3840 OP_ENDIF => {
3841 if control_stack.pop().is_none() {
3843 return Err(ConsensusError::ScriptErrorWithCode {
3844 code: ScriptErrorCode::UnbalancedConditional,
3845 message: "OP_ENDIF without matching IF/NOTIF".into(),
3846 });
3847 }
3848 }
3849
3850 OP_TOALTSTACK => {
3855 if in_false_branch {
3856 i += 1;
3857 continue;
3858 }
3859 if stack.is_empty() {
3860 return Err(ConsensusError::ScriptErrorWithCode {
3861 code: ScriptErrorCode::InvalidStackOperation,
3862 message: "OP_TOALTSTACK: empty stack".into(),
3863 });
3864 }
3865 altstack.push(stack.pop().unwrap());
3866 }
3867 OP_FROMALTSTACK => {
3869 if in_false_branch {
3870 i += 1;
3871 continue;
3872 }
3873 if altstack.is_empty() {
3874 return Err(ConsensusError::ScriptErrorWithCode {
3875 code: ScriptErrorCode::InvalidAltstackOperation,
3876 message: "OP_FROMALTSTACK: empty altstack".into(),
3877 });
3878 }
3879 stack.push(altstack.pop().unwrap());
3880 }
3881 OP_CODESEPARATOR => {
3883 if in_false_branch {
3884 i += 1;
3885 continue;
3886 }
3887 code_separator_pos = i + 1;
3888 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
3889 }
3890 _ => {
3891 if in_false_branch {
3892 i += 1;
3893 continue;
3894 }
3895
3896 let subscript_for_sighash = if matches!(
3901 opcode,
3902 OP_CHECKSIG
3903 | OP_CHECKSIGVERIFY
3904 | OP_CHECKSIGADD
3905 | OP_CHECKMULTISIG
3906 | OP_CHECKMULTISIGVERIFY
3907 ) {
3908 Some(&script[code_separator_pos..])
3909 } else {
3910 None
3911 };
3912 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
3913 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3914 (Some(script), Some(last_codesep_opcode_pos))
3915 } else {
3916 (None, None)
3917 };
3918 let ctx = context::ScriptContext {
3919 tx,
3920 input_index,
3921 prevout_values,
3922 prevout_script_pubkeys,
3923 block_height,
3924 median_time_past,
3925 network,
3926 sigversion,
3927 redeem_script_for_sighash,
3928 script_sig_for_sighash,
3929 tapscript_for_sighash: tapscript,
3930 tapscript_codesep_pos: codesep,
3931 taproot_annex_hash,
3932 #[cfg(feature = "production")]
3933 schnorr_collector,
3934 #[cfg(feature = "production")]
3935 precomputed_bip143,
3936 #[cfg(feature = "production")]
3937 sighash_cache,
3938 };
3939 if !execute_opcode_with_context_full(
3940 opcode,
3941 stack,
3942 flags,
3943 &ctx,
3944 effective_script_code,
3945 )? {
3946 return Ok(false);
3947 }
3948 }
3949 }
3950 i += 1;
3951 }
3952
3953 if !control_stack.is_empty() {
3955 return Err(ConsensusError::ScriptErrorWithCode {
3956 code: ScriptErrorCode::UnbalancedConditional,
3957 message: "Unclosed IF/NOTIF block".into(),
3958 });
3959 }
3960
3961 Ok(true)
3965}
3966
3967#[spec_locked("5.4.5", "DecodeCScriptNum")]
3971#[blvm_spec_lock::axiom(result >= -549755813887)]
3972#[blvm_spec_lock::ensures(result >= -549755813887)]
3973#[cfg(feature = "production")]
3974#[inline(always)]
3975pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3976 if data.len() > max_num_size {
3977 return Err(ConsensusError::ScriptErrorWithCode {
3978 code: ScriptErrorCode::InvalidStackOperation,
3979 message: format!(
3980 "Script number overflow: {} > {} bytes",
3981 data.len(),
3982 max_num_size
3983 )
3984 .into(),
3985 });
3986 }
3987 if data.is_empty() {
3988 return Ok(0);
3989 }
3990
3991 let len = data.len();
3993 let result = match len {
3994 1 => {
3995 let byte = data[0];
3996 if byte & 0x80 != 0 {
3997 -((byte & 0x7f) as i64)
3999 } else {
4000 byte as i64
4001 }
4002 }
4003 2 => {
4004 let byte0 = data[0] as i64;
4005 let byte1 = data[1] as i64;
4006 let value = byte0 | (byte1 << 8);
4007 if byte1 & 0x80 != 0 {
4008 -(value & !(0x80i64 << 8))
4010 } else {
4011 value
4012 }
4013 }
4014 _ => {
4015 let mut result: i64 = 0;
4017 for (i, &byte) in data.iter().enumerate() {
4018 result |= (byte as i64) << (8 * i);
4019 }
4020 let last_idx = len - 1;
4022 if data[last_idx] & 0x80 != 0 {
4023 result &= !(0x80i64 << (8 * last_idx));
4025 result = -result;
4026 }
4027 result
4028 }
4029 };
4030
4031 Ok(result)
4032}
4033
4034#[cfg(not(feature = "production"))]
4035#[inline]
4036pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
4037 if data.len() > max_num_size {
4038 return Err(ConsensusError::ScriptErrorWithCode {
4039 code: ScriptErrorCode::InvalidStackOperation,
4040 message: format!(
4041 "Script number overflow: {} > {} bytes",
4042 data.len(),
4043 max_num_size
4044 )
4045 .into(),
4046 });
4047 }
4048 if data.is_empty() {
4049 return Ok(0);
4050 }
4051 let mut result: i64 = 0;
4053 for (i, &byte) in data.iter().enumerate() {
4054 result |= (byte as i64) << (8 * i);
4055 }
4056 if data.last().expect("Data is not empty") & 0x80 != 0 {
4058 result &= !(0x80i64 << (8 * (data.len() - 1)));
4060 result = -result;
4061 }
4062 Ok(result)
4063}
4064
4065#[cfg(feature = "production")]
4068pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
4069 match value {
4071 0 => return vec![],
4072 1 => return vec![1],
4073 -1 => return vec![0x81],
4074 _ => {}
4075 }
4076
4077 let neg = value < 0;
4078 let mut absvalue = if neg {
4079 (-(value as i128)) as u64
4080 } else {
4081 value as u64
4082 };
4083 let mut result = Vec::with_capacity(4);
4085 while absvalue > 0 {
4086 result.push((absvalue & 0xff) as u8);
4087 absvalue >>= 8;
4088 }
4089 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
4091 result.push(if neg { 0x80 } else { 0x00 });
4092 } else if neg {
4093 *result.last_mut().unwrap() |= 0x80;
4094 }
4095 result
4096}
4097
4098#[cfg(not(feature = "production"))]
4099pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
4100 if value == 0 {
4101 return vec![];
4102 }
4103 let neg = value < 0;
4104 let mut absvalue = if neg {
4105 (-(value as i128)) as u64
4106 } else {
4107 value as u64
4108 };
4109 let mut result = Vec::new();
4110 while absvalue > 0 {
4111 result.push((absvalue & 0xff) as u8);
4112 absvalue >>= 8;
4113 }
4114 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
4116 result.push(if neg { 0x80 } else { 0x00 });
4117 } else if neg {
4118 *result.last_mut().unwrap() |= 0x80;
4119 }
4120 result
4121}
4122
4123#[cfg(feature = "production")]
4125#[inline(always)]
4126fn execute_opcode(
4127 opcode: u8,
4128 stack: &mut Vec<StackElement>,
4129 flags: u32,
4130 _sigversion: SigVersion,
4131) -> Result<bool> {
4132 match opcode {
4133 OP_0 => {
4135 stack.push(to_stack_element(&[]));
4136 Ok(true)
4137 }
4138
4139 OP_1..=OP_16 => {
4141 let num = opcode - OP_N_BASE;
4142 stack.push(to_stack_element(&[num]));
4143 Ok(true)
4144 }
4145
4146 OP_NOP => Ok(true),
4148
4149 OP_VER => Ok(false),
4151
4152 OP_DEPTH => {
4154 let depth = stack.len() as i64;
4155 stack.push(to_stack_element(&script_num_encode(depth)));
4156 Ok(true)
4157 }
4158
4159 OP_DUP => {
4161 if let Some(item) = stack.last().cloned() {
4162 stack.push(item);
4163 Ok(true)
4164 } else {
4165 Ok(false)
4166 }
4167 }
4168
4169 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
4171
4172 OP_SHA1 => crypto_ops::op_sha1(stack),
4174
4175 OP_SHA256 => crypto_ops::op_sha256(stack),
4177
4178 OP_HASH160 => crypto_ops::op_hash160(stack),
4180
4181 OP_HASH256 => crypto_ops::op_hash256(stack),
4183
4184 OP_EQUAL => {
4187 if stack.len() < 2 {
4188 return Err(ConsensusError::ScriptErrorWithCode {
4189 code: ScriptErrorCode::InvalidStackOperation,
4190 message: "OP_EQUAL: insufficient stack items".into(),
4191 });
4192 }
4193 let a = stack.pop().unwrap();
4194 let b = stack.pop().unwrap();
4195 stack.push(to_stack_element(if a == b { &[1u8] } else { &[] }));
4196 Ok(true)
4197 }
4198
4199 OP_EQUALVERIFY => {
4202 if stack.len() < 2 {
4203 return Err(ConsensusError::ScriptErrorWithCode {
4204 code: ScriptErrorCode::InvalidStackOperation,
4205 message: "OP_EQUALVERIFY: insufficient stack items".into(),
4206 });
4207 }
4208 let a = stack.pop().unwrap();
4209 let b = stack.pop().unwrap();
4210 let f_equal = a == b;
4211 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
4213 if f_equal {
4214 stack.pop();
4216 Ok(true)
4217 } else {
4218 Err(ConsensusError::ScriptErrorWithCode {
4219 code: ScriptErrorCode::EqualVerify,
4220 message: "OP_EQUALVERIFY: stack items not equal".into(),
4221 })
4222 }
4223 }
4224
4225 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
4227
4228 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
4230
4231 OP_RETURN => Ok(false),
4233
4234 OP_VERIFY => {
4236 if let Some(item) = stack.pop() {
4237 Ok(cast_to_bool(&item))
4238 } else {
4239 Ok(false)
4240 }
4241 }
4242
4243 OP_CHECKLOCKTIMEVERIFY => {
4247 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
4248 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
4249 Ok(true)
4250 } else {
4251 Ok(false)
4252 }
4253 }
4254
4255 OP_CHECKSEQUENCEVERIFY => {
4259 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
4260 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
4261 Ok(true)
4262 } else {
4263 Ok(false)
4264 }
4265 }
4266
4267 OP_IFDUP => {
4269 if let Some(item) = stack.last().cloned() {
4270 if cast_to_bool(&item) {
4271 stack.push(item);
4272 }
4273 Ok(true)
4274 } else {
4275 Ok(false)
4276 }
4277 }
4278
4279 OP_DROP => {
4282 if stack.pop().is_some() {
4283 Ok(true)
4284 } else {
4285 Ok(false)
4286 }
4287 }
4288
4289 OP_NIP => {
4291 if stack.len() >= 2 {
4292 let top = stack.pop().unwrap();
4293 stack.pop(); stack.push(top);
4295 Ok(true)
4296 } else {
4297 Ok(false)
4298 }
4299 }
4300
4301 OP_OVER => {
4303 if stack.len() >= 2 {
4304 let len = stack.len();
4305 #[cfg(feature = "production")]
4306 {
4307 unsafe {
4309 let second = stack.get_unchecked(len - 2);
4310 stack.push(second.clone());
4311 }
4312 }
4313 #[cfg(not(feature = "production"))]
4314 {
4315 let second = stack[stack.len() - 2].clone();
4316 stack.push(second);
4317 }
4318 Ok(true)
4319 } else {
4320 Ok(false)
4321 }
4322 }
4323
4324 OP_PICK => {
4326 if let Some(n_bytes) = stack.pop() {
4327 let n_val = script_num_decode(&n_bytes, 4)?;
4330 if n_val < 0 || n_val as usize >= stack.len() {
4331 return Ok(false);
4332 }
4333 let n = n_val as usize;
4334 let len = stack.len();
4335 #[cfg(feature = "production")]
4336 {
4337 unsafe {
4339 let item = stack.get_unchecked(len - 1 - n);
4340 stack.push(item.clone());
4341 }
4342 }
4343 #[cfg(not(feature = "production"))]
4344 {
4345 let item = stack[stack.len() - 1 - n].clone();
4346 stack.push(item);
4347 }
4348 Ok(true)
4349 } else {
4350 Ok(false)
4351 }
4352 }
4353
4354 OP_ROLL => {
4356 if let Some(n_bytes) = stack.pop() {
4357 let n_val = script_num_decode(&n_bytes, 4)?;
4360 if n_val < 0 || n_val as usize >= stack.len() {
4361 return Ok(false);
4362 }
4363 let n = n_val as usize;
4364 let len = stack.len();
4365 #[cfg(feature = "production")]
4366 {
4367 let idx = len - 1 - n;
4369 let item = stack.remove(idx);
4370 stack.push(item);
4371 }
4372 #[cfg(not(feature = "production"))]
4373 {
4374 let item = stack.remove(stack.len() - 1 - n);
4375 stack.push(item);
4376 }
4377 Ok(true)
4378 } else {
4379 Ok(false)
4380 }
4381 }
4382
4383 OP_ROT => {
4385 if stack.len() >= 3 {
4386 let top = stack.pop().unwrap();
4387 let second = stack.pop().unwrap();
4388 let third = stack.pop().unwrap();
4389 stack.push(second);
4390 stack.push(top);
4391 stack.push(third);
4392 Ok(true)
4393 } else {
4394 Ok(false)
4395 }
4396 }
4397
4398 OP_SWAP => {
4400 if stack.len() >= 2 {
4401 let top = stack.pop().unwrap();
4402 let second = stack.pop().unwrap();
4403 stack.push(top);
4404 stack.push(second);
4405 Ok(true)
4406 } else {
4407 Ok(false)
4408 }
4409 }
4410
4411 OP_TUCK => {
4413 if stack.len() >= 2 {
4414 let top = stack.pop().unwrap();
4415 let second = stack.pop().unwrap();
4416 stack.push(top.clone());
4417 stack.push(second);
4418 stack.push(top);
4419 Ok(true)
4420 } else {
4421 Ok(false)
4422 }
4423 }
4424
4425 OP_2DROP => {
4427 if stack.len() >= 2 {
4428 stack.pop();
4429 stack.pop();
4430 Ok(true)
4431 } else {
4432 Ok(false)
4433 }
4434 }
4435
4436 OP_2DUP => {
4438 if stack.len() >= 2 {
4439 let top = stack[stack.len() - 1].clone();
4440 let second = stack[stack.len() - 2].clone();
4441 stack.push(second);
4442 stack.push(top);
4443 Ok(true)
4444 } else {
4445 Ok(false)
4446 }
4447 }
4448
4449 OP_3DUP => {
4451 if stack.len() >= 3 {
4452 let top = stack[stack.len() - 1].clone();
4453 let second = stack[stack.len() - 2].clone();
4454 let third = stack[stack.len() - 3].clone();
4455 stack.push(third);
4456 stack.push(second);
4457 stack.push(top);
4458 Ok(true)
4459 } else {
4460 Ok(false)
4461 }
4462 }
4463
4464 OP_2OVER => {
4466 if stack.len() >= 4 {
4467 let fourth = stack[stack.len() - 4].clone();
4468 let third = stack[stack.len() - 3].clone();
4469 stack.push(fourth);
4470 stack.push(third);
4471 Ok(true)
4472 } else {
4473 Ok(false)
4474 }
4475 }
4476
4477 OP_2ROT => {
4480 if stack.len() >= 6 {
4481 let sixth = stack.remove(stack.len() - 6); let fifth = stack.remove(stack.len() - 5); stack.push(sixth);
4487 stack.push(fifth);
4488 Ok(true)
4489 } else {
4490 Ok(false)
4491 }
4492 }
4493
4494 OP_2SWAP => {
4496 if stack.len() >= 4 {
4497 let top = stack.pop().unwrap();
4498 let second = stack.pop().unwrap();
4499 let third = stack.pop().unwrap();
4500 let fourth = stack.pop().unwrap();
4501 stack.push(second);
4502 stack.push(top);
4503 stack.push(fourth);
4504 stack.push(third);
4505 Ok(true)
4506 } else {
4507 Ok(false)
4508 }
4509 }
4510
4511 OP_SIZE => {
4514 if let Some(item) = stack.last() {
4515 let size = item.len() as i64;
4516 stack.push(to_stack_element(&script_num_encode(size)));
4517 Ok(true)
4518 } else {
4519 Ok(false)
4520 }
4521 }
4522
4523 OP_1ADD => {
4528 if let Some(item) = stack.pop() {
4529 let a = script_num_decode(&item, 4)?;
4530 stack.push(to_stack_element(&script_num_encode(a + 1)));
4531 Ok(true)
4532 } else {
4533 Ok(false)
4534 }
4535 }
4536 OP_1SUB => {
4538 if let Some(item) = stack.pop() {
4539 let a = script_num_decode(&item, 4)?;
4540 stack.push(to_stack_element(&script_num_encode(a - 1)));
4541 Ok(true)
4542 } else {
4543 Ok(false)
4544 }
4545 }
4546 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4548 code: ScriptErrorCode::DisabledOpcode,
4549 message: "OP_2MUL is disabled".into(),
4550 }),
4551 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4553 code: ScriptErrorCode::DisabledOpcode,
4554 message: "OP_2DIV is disabled".into(),
4555 }),
4556 OP_NEGATE => {
4558 if let Some(item) = stack.pop() {
4559 let a = script_num_decode(&item, 4)?;
4560 stack.push(to_stack_element(&script_num_encode(-a)));
4561 Ok(true)
4562 } else {
4563 Ok(false)
4564 }
4565 }
4566 OP_ABS => {
4568 if let Some(item) = stack.pop() {
4569 let a = script_num_decode(&item, 4)?;
4570 stack.push(to_stack_element(&script_num_encode(a.abs())));
4571 Ok(true)
4572 } else {
4573 Ok(false)
4574 }
4575 }
4576 OP_NOT => {
4578 if let Some(item) = stack.pop() {
4579 let a = script_num_decode(&item, 4)?;
4580 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4581 1
4582 } else {
4583 0
4584 })));
4585 Ok(true)
4586 } else {
4587 Ok(false)
4588 }
4589 }
4590 OP_0NOTEQUAL => {
4592 if let Some(item) = stack.pop() {
4593 let a = script_num_decode(&item, 4)?;
4594 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4595 1
4596 } else {
4597 0
4598 })));
4599 Ok(true)
4600 } else {
4601 Ok(false)
4602 }
4603 }
4604 OP_ADD => arithmetic::op_add(stack),
4605 OP_SUB => arithmetic::op_sub(stack),
4606 OP_MUL => arithmetic::op_mul_disabled(),
4607 OP_DIV => arithmetic::op_div_disabled(),
4608 OP_MOD => arithmetic::op_mod_disabled(),
4609 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4610 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4611 OP_BOOLAND => arithmetic::op_booland(stack),
4612 OP_BOOLOR => arithmetic::op_boolor(stack),
4613 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4614 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4615 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4616 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4617 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4618 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4619 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4620 OP_MIN => arithmetic::op_min(stack),
4621 OP_MAX => arithmetic::op_max(stack),
4622 OP_WITHIN => arithmetic::op_within(stack),
4623
4624 OP_CODESEPARATOR => Ok(true),
4626
4627 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4630
4631 OP_CHECKTEMPLATEVERIFY => {
4635 const SCRIPT_VERIFY_CHECKTEMPLATEVERIFY: u32 = 0x8000;
4636 #[cfg(feature = "ctv")]
4637 if (flags & SCRIPT_VERIFY_CHECKTEMPLATEVERIFY) != 0 {
4638 return Err(ConsensusError::ScriptErrorWithCode {
4639 code: ScriptErrorCode::TxInvalid,
4640 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4641 });
4642 }
4643 Ok(true)
4644 }
4645
4646 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4648 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4649 Err(ConsensusError::ScriptErrorWithCode {
4650 code: ScriptErrorCode::DisabledOpcode,
4651 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4652 })
4653 }
4654
4655 OP_1NEGATE => {
4657 stack.push(to_stack_element(&[0x81]));
4658 Ok(true)
4659 }
4660
4661 OP_CHECKMULTISIG => {
4666 if stack.is_empty() {
4667 return Ok(false);
4668 }
4669 let n_bytes = stack.pop().unwrap();
4670 let n = match script_num_decode(&n_bytes, 4) {
4671 Ok(v) if (0..=20).contains(&v) => v as usize,
4672 _ => return Ok(false),
4673 };
4674 if stack.len() < n {
4675 return Ok(false);
4676 }
4677 for _ in 0..n {
4678 stack.pop();
4679 }
4680 if stack.is_empty() {
4681 return Ok(false);
4682 }
4683 let m_bytes = stack.pop().unwrap();
4684 let m = match script_num_decode(&m_bytes, 4) {
4685 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4686 _ => return Ok(false),
4687 };
4688 if stack.len() < m {
4689 return Ok(false);
4690 }
4691 for _ in 0..m {
4692 stack.pop();
4693 }
4694 if stack.is_empty() {
4696 return Ok(false);
4697 }
4698 stack.pop();
4699 stack.push(to_stack_element(&[if m == 0 { 1 } else { 0 }]));
4701 Ok(true)
4702 }
4703
4704 OP_CHECKMULTISIGVERIFY => {
4706 if stack.is_empty() {
4707 return Ok(false);
4708 }
4709 let n_bytes = stack.pop().unwrap();
4710 let n = match script_num_decode(&n_bytes, 4) {
4711 Ok(v) if (0..=20).contains(&v) => v as usize,
4712 _ => return Ok(false),
4713 };
4714 if stack.len() < n {
4715 return Ok(false);
4716 }
4717 for _ in 0..n {
4718 stack.pop();
4719 }
4720 if stack.is_empty() {
4721 return Ok(false);
4722 }
4723 let m_bytes = stack.pop().unwrap();
4724 let m = match script_num_decode(&m_bytes, 4) {
4725 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4726 _ => return Ok(false),
4727 };
4728 if stack.len() < m {
4729 return Ok(false);
4730 }
4731 for _ in 0..m {
4732 stack.pop();
4733 }
4734 if stack.is_empty() {
4735 return Ok(false);
4736 }
4737 stack.pop();
4738 Ok(m == 0)
4740 }
4741
4742 _ => Ok(false),
4744 }
4745}
4746
4747#[allow(dead_code)]
4749fn execute_opcode_with_context(
4750 opcode: u8,
4751 stack: &mut Vec<StackElement>,
4752 flags: u32,
4753 tx: &Transaction,
4754 input_index: usize,
4755 prevouts: &[TransactionOutput],
4756 network: crate::types::Network,
4757) -> Result<bool> {
4758 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4760 let prevout_script_pubkeys: Vec<&[u8]> =
4761 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4762 let ctx = context::ScriptContext {
4763 tx,
4764 input_index,
4765 prevout_values: &prevout_values,
4766 prevout_script_pubkeys: &prevout_script_pubkeys,
4767 block_height: None,
4768 median_time_past: None,
4769 network,
4770 sigversion: SigVersion::Base,
4771 redeem_script_for_sighash: None,
4772 script_sig_for_sighash: None,
4773 tapscript_for_sighash: None,
4774 tapscript_codesep_pos: None,
4775 taproot_annex_hash: None,
4776 #[cfg(feature = "production")]
4777 schnorr_collector: None,
4778 #[cfg(feature = "production")]
4779 precomputed_bip143: None,
4780 #[cfg(feature = "production")]
4781 sighash_cache: None,
4782 };
4783 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4784}
4785
4786#[cfg(feature = "production")]
4790#[inline(always)]
4791pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4792 let mut i = 0;
4793 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4794 i += adv1;
4795 if i >= script_sig.len() {
4796 return None;
4797 }
4798 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4799 i += adv2;
4800 if i >= script_sig.len() {
4801 return None;
4802 }
4803 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4804 i += adv3;
4805 if i != script_sig.len() {
4806 return None;
4807 }
4808 let sig = &script_sig[s_start..s_end];
4809 let redeem = &script_sig[r_start..r_end];
4810 if sig.is_empty() || redeem.len() != 25 {
4811 return None;
4812 }
4813 if redeem[0] != OP_DUP
4814 || redeem[1] != OP_HASH160
4815 || redeem[2] != PUSH_20_BYTES
4816 || redeem[23] != OP_EQUALVERIFY
4817 || redeem[24] != OP_CHECKSIG
4818 {
4819 return None;
4820 }
4821 Some((sig[sig.len() - 1], redeem))
4822}
4823
4824#[inline(always)]
4828pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4829 let mut i = 0;
4830 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4831 i += adv1;
4832 if i >= script_sig.len() {
4833 return None;
4834 }
4835 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4836 i += adv2;
4837 if i != script_sig.len() {
4838 return None;
4839 }
4840 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4841}
4842
4843pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4846 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4847 if advance != script_sig.len() {
4848 return None;
4849 }
4850 Some(&script_sig[data_start..data_end])
4851}
4852
4853fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4855 if i >= script.len() {
4856 return None;
4857 }
4858 let opcode = script[i];
4859 let (advance, data_start, data_end) = if opcode == OP_0 {
4860 return None;
4861 } else if opcode <= 0x4b {
4862 let len = opcode as usize;
4863 if i + 1 + len > script.len() {
4864 return None;
4865 }
4866 (1 + len, i + 1, i + 1 + len)
4867 } else if opcode == OP_PUSHDATA1 {
4868 if i + 1 >= script.len() {
4869 return None;
4870 }
4871 let len = script[i + 1] as usize;
4872 if i + 2 + len > script.len() {
4873 return None;
4874 }
4875 (2 + len, i + 2, i + 2 + len)
4876 } else if opcode == OP_PUSHDATA2 {
4877 if i + 2 >= script.len() {
4878 return None;
4879 }
4880 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4881 if i + 3 + len > script.len() {
4882 return None;
4883 }
4884 (3 + len, i + 3, i + 3 + len)
4885 } else if opcode == OP_PUSHDATA4 {
4886 if i + 4 >= script.len() {
4887 return None;
4888 }
4889 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4890 as usize;
4891 if i + 5 + len > script.len() {
4892 return None;
4893 }
4894 (5 + len, i + 5, i + 5 + len)
4895 } else {
4896 return None;
4897 };
4898 Some((advance, data_start, data_end))
4899}
4900
4901#[spec_locked("5.2.1", "P2SHPushOnlyCheck")]
4904pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4905 parse_script_sig_push_only(script_sig).is_some()
4906}
4907
4908fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4912 let mut out = Vec::new();
4913 let mut i = 0;
4914 while i < script_sig.len() {
4915 let opcode = script_sig[i];
4916 if !is_push_opcode(opcode) {
4917 return None;
4918 }
4919 let (advance, data) = if opcode == OP_0 {
4920 (1, vec![])
4921 } else if opcode <= 0x4b {
4922 let len = opcode as usize;
4923 if i + 1 + len > script_sig.len() {
4924 return None;
4925 }
4926 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4927 } else if opcode == OP_PUSHDATA1 {
4928 if i + 1 >= script_sig.len() {
4929 return None;
4930 }
4931 let len = script_sig[i + 1] as usize;
4932 if i + 2 + len > script_sig.len() {
4933 return None;
4934 }
4935 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4936 } else if opcode == OP_PUSHDATA2 {
4937 if i + 2 >= script_sig.len() {
4938 return None;
4939 }
4940 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4941 if i + 3 + len > script_sig.len() {
4942 return None;
4943 }
4944 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4945 } else if opcode == OP_PUSHDATA4 {
4946 if i + 4 >= script_sig.len() {
4947 return None;
4948 }
4949 let len = u32::from_le_bytes([
4950 script_sig[i + 1],
4951 script_sig[i + 2],
4952 script_sig[i + 3],
4953 script_sig[i + 4],
4954 ]) as usize;
4955 if i + 5 + len > script_sig.len() {
4956 return None;
4957 }
4958 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4959 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4960 let n = script_num_from_opcode(opcode);
4962 (1, script_num_encode(n))
4963 } else {
4964 return None;
4965 };
4966 out.push(to_stack_element(&data));
4967 i += advance;
4968 }
4969 Some(out)
4970}
4971
4972fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4976 parse_script_sig_push_only(script_sig)
4977}
4978
4979fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4984 if redeem.len() < 4 {
4985 return None;
4986 }
4987 let n_op = redeem[0];
4988 if !(OP_1..=OP_16).contains(&n_op) {
4989 return None;
4990 }
4991 let n = (n_op - OP_1 + 1) as usize;
4992 let mut i = 1;
4993 let mut pubkeys = Vec::with_capacity(n);
4994 for _ in 0..n {
4995 if i >= redeem.len() {
4996 return None;
4997 }
4998 let first = redeem[i];
4999 let pk_len = if first == 0x02 || first == 0x03 {
5000 33
5001 } else if first == 0x04 {
5002 65
5003 } else {
5004 return None;
5005 };
5006 if i + pk_len > redeem.len() {
5007 return None;
5008 }
5009 pubkeys.push(&redeem[i..i + pk_len]);
5010 i += pk_len;
5011 }
5012 if i + 2 > redeem.len() {
5013 return None;
5014 }
5015 let m_op = redeem[i];
5016 if !(OP_1..=OP_16).contains(&m_op) {
5017 return None;
5018 }
5019 let m = m_op - OP_1 + 1;
5020 if redeem[i + 1] != OP_CHECKMULTISIG {
5021 return None;
5022 }
5023 Some((m, n as u8, pubkeys))
5024}
5025
5026fn script_num_from_opcode(opcode: u8) -> i64 {
5028 match opcode {
5029 OP_1NEGATE => -1,
5030 OP_1 => 1,
5031 OP_2 => 2,
5032 OP_3 => 3,
5033 OP_4 => 4,
5034 OP_5 => 5,
5035 OP_6 => 6,
5036 OP_7 => 7,
5037 OP_8 => 8,
5038 OP_9 => 9,
5039 OP_10 => 10,
5040 OP_11 => 11,
5041 OP_12 => 12,
5042 OP_13 => 13,
5043 OP_14 => 14,
5044 OP_15 => 15,
5045 OP_16 => 16,
5046 _ => 0,
5047 }
5048}
5049
5050pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
5054 let len = data.len();
5055 let mut result = Vec::with_capacity(len + 5);
5056 if len < 76 {
5057 result.push(len as u8);
5058 } else if len < 256 {
5059 result.push(OP_PUSHDATA1);
5060 result.push(len as u8);
5061 } else if len < 65536 {
5062 result.push(OP_PUSHDATA2);
5063 result.push((len & 0xff) as u8);
5064 result.push(((len >> 8) & 0xff) as u8);
5065 } else {
5066 result.push(OP_PUSHDATA4);
5067 result.push((len & 0xff) as u8);
5068 result.push(((len >> 8) & 0xff) as u8);
5069 result.push(((len >> 16) & 0xff) as u8);
5070 result.push(((len >> 24) & 0xff) as u8);
5071 }
5072 result.extend_from_slice(data);
5073 result
5074}
5075
5076#[inline]
5078fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
5079 if pc >= script.len() {
5080 return None;
5081 }
5082 let opcode = script[pc];
5083 let advance = if opcode <= 0x4b {
5084 1 + opcode as usize
5085 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
5086 2 + script[pc + 1] as usize
5087 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
5088 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
5089 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
5090 5 + ((script[pc + 1] as usize)
5091 | ((script[pc + 2] as usize) << 8)
5092 | ((script[pc + 3] as usize) << 16)
5093 | ((script[pc + 4] as usize) << 24))
5094 } else {
5095 1
5096 };
5097 let next = pc + advance;
5098 if next > script.len() {
5099 None
5100 } else {
5101 Some(next)
5102 }
5103}
5104
5105#[spec_locked("5.1.1", "FindAndDelete")]
5111#[inline]
5112pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
5113 if pattern.is_empty() {
5114 return std::borrow::Cow::Borrowed(script);
5115 }
5116 if pattern.len() > script.len() {
5117 return std::borrow::Cow::Borrowed(script);
5118 }
5119 if !script.windows(pattern.len()).any(|w| w == pattern) {
5124 return std::borrow::Cow::Borrowed(script);
5125 }
5126 let end = script.len();
5127 let mut n_found = 0usize;
5128 let mut result = Vec::new();
5129 let mut pc = 0usize;
5130 let mut pc2 = 0usize;
5131
5132 loop {
5133 result.extend_from_slice(&script[pc2..pc]);
5134 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
5135 pc += pattern.len();
5136 n_found += 1;
5137 }
5138 pc2 = pc;
5139 if pc >= end {
5140 break;
5141 }
5142 let Some(next_pc) = script_get_op_advance(script, pc) else {
5143 break;
5144 };
5145 pc = next_pc;
5146 }
5147
5148 if n_found > 0 {
5149 result.extend_from_slice(&script[pc2..end]);
5150 std::borrow::Cow::Owned(result)
5151 } else {
5152 std::borrow::Cow::Borrowed(script)
5153 }
5154}
5155
5156fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
5158 let mut pos = 0u32;
5159 let mut i = 0usize;
5160 while i < script.len() && i <= byte_index {
5161 let opcode = script[i];
5162 let advance = if opcode <= 0x4b {
5163 1 + opcode as usize
5164 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
5165 2 + script[i + 1] as usize
5166 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
5167 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
5168 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
5169 5 + ((script[i + 1] as usize)
5170 | ((script[i + 2] as usize) << 8)
5171 | ((script[i + 3] as usize) << 16)
5172 | ((script[i + 4] as usize) << 24))
5173 } else {
5174 1
5175 };
5176 if i == byte_index {
5177 return pos;
5178 }
5179 pos += 1;
5180 i = std::cmp::min(i + advance, script.len());
5181 }
5182 0xffff_ffff
5183}
5184
5185#[cfg_attr(feature = "production", inline(always))]
5187fn execute_opcode_with_context_full(
5188 opcode: u8,
5189 stack: &mut Vec<StackElement>,
5190 flags: u32,
5191 ctx: &context::ScriptContext<'_>,
5192 effective_script_code: Option<&[u8]>,
5193) -> Result<bool> {
5194 let tx = ctx.tx;
5195 let input_index = ctx.input_index;
5196 let prevout_values = ctx.prevout_values;
5197 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
5198 let block_height = ctx.block_height;
5199 let median_time_past = ctx.median_time_past;
5200 let network = ctx.network;
5201 let sigversion = ctx.sigversion;
5202 let script_sig_for_sighash = ctx.script_sig_for_sighash;
5203 let tapscript_for_sighash = ctx.tapscript_for_sighash;
5204 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
5205 let redeem_script_for_sighash = effective_script_code;
5206 #[cfg(feature = "production")]
5207 let schnorr_collector = ctx.schnorr_collector;
5208 #[cfg(feature = "production")]
5209 let precomputed_bip143 = ctx.precomputed_bip143;
5210 #[cfg(feature = "production")]
5211 let sighash_cache = ctx.sighash_cache;
5212
5213 match opcode {
5215 OP_CHECKSIG => {
5217 if stack.len() >= 2 {
5218 let pubkey_bytes = stack.pop().unwrap();
5219 let signature_bytes = stack.pop().unwrap();
5220
5221 if signature_bytes.is_empty() {
5223 stack.push(to_stack_element(&[0]));
5224 return Ok(true);
5225 }
5226
5227 if sigversion == SigVersion::Tapscript && pubkey_bytes.len() == 32 {
5229 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5230 if let Some((sig_bytes, sighash_byte)) =
5231 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5232 {
5233 let (tapscript, codesep_pos) = tapscript_for_sighash
5234 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5235 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5236 let sighash = if tapscript.is_empty() {
5237 crate::taproot::compute_taproot_signature_hash(
5238 tx,
5239 input_index,
5240 prevout_values,
5241 prevout_script_pubkeys,
5242 sighash_byte,
5243 None,
5244 )?
5245 } else {
5246 crate::taproot::compute_tapscript_signature_hash(
5247 tx,
5248 input_index,
5249 prevout_values,
5250 prevout_script_pubkeys,
5251 tapscript,
5252 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5253 codesep_pos,
5254 sighash_byte,
5255 ctx.taproot_annex_hash,
5256 )?
5257 };
5258
5259 #[cfg(feature = "production")]
5260 let is_valid = {
5261 use crate::bip348::verify_tapscript_schnorr_signature;
5262 verify_tapscript_schnorr_signature(
5263 &sighash,
5264 &pubkey_bytes,
5265 &sig_bytes,
5266 schnorr_collector,
5267 )
5268 .unwrap_or(false)
5269 };
5270
5271 #[cfg(not(feature = "production"))]
5272 let is_valid = {
5273 #[cfg(feature = "csfs")]
5274 let x = {
5275 use crate::bip348::verify_tapscript_schnorr_signature;
5276 verify_tapscript_schnorr_signature(
5277 &sighash,
5278 &pubkey_bytes,
5279 &sig_bytes,
5280 None,
5281 )
5282 .unwrap_or(false)
5283 };
5284 #[cfg(not(feature = "csfs"))]
5285 let x = false;
5286 x
5287 };
5288
5289 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5290 return Ok(true);
5291 }
5292 stack.push(to_stack_element(&[0]));
5294 return Ok(true);
5295 }
5296 if sigversion == SigVersion::Tapscript {
5297 stack.push(to_stack_element(&[1]));
5299 return Ok(true);
5300 }
5301
5302 let sig_len = signature_bytes.len();
5306 let sighash_byte = signature_bytes[sig_len - 1];
5307 let _der_sig = &signature_bytes[..sig_len - 1];
5308
5309 let sighash = if sigversion == SigVersion::WitnessV0 {
5313 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5315
5316 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5318 prevout_script_pubkeys
5319 .get(input_index)
5320 .copied()
5321 .unwrap_or(&[])
5322 });
5323
5324 crate::transaction_hash::calculate_bip143_sighash(
5325 tx,
5326 input_index,
5327 script_code,
5328 amount,
5329 sighash_byte,
5330 precomputed_bip143,
5331 )?
5332 } else {
5333 use crate::transaction_hash::{
5335 calculate_transaction_sighash_single_input, SighashType,
5336 };
5337 let sighash_type = SighashType::from_byte(sighash_byte);
5338
5339 let pattern = serialize_push_data(signature_bytes.as_ref());
5343
5344 let base_script = match (
5345 redeem_script_for_sighash,
5346 prevout_script_pubkeys.get(input_index),
5347 ) {
5348 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5349 (Some(redeem), _) => redeem,
5350 (None, Some(prevout)) => *prevout,
5351 (None, None) => &[],
5352 };
5353 let cleaned = find_and_delete(base_script, &pattern);
5354
5355 calculate_transaction_sighash_single_input(
5356 tx,
5357 input_index,
5358 cleaned.as_ref(),
5359 prevout_values[input_index],
5360 sighash_type,
5361 #[cfg(feature = "production")]
5362 sighash_cache,
5363 )?
5364 };
5365
5366 let height = block_height.unwrap_or(0);
5370 #[cfg(feature = "production")]
5371 let is_valid = signature::with_secp_context(|secp| {
5372 signature::verify_signature(
5373 secp,
5374 &pubkey_bytes,
5375 &signature_bytes, &sighash,
5377 flags,
5378 height,
5379 network,
5380 sigversion,
5381 )
5382 })?;
5383
5384 #[cfg(not(feature = "production"))]
5385 let is_valid = {
5386 let secp = signature::new_secp();
5387 signature::verify_signature(
5388 &secp,
5389 &pubkey_bytes,
5390 &signature_bytes, &sighash,
5392 flags,
5393 height,
5394 network,
5395 sigversion,
5396 )?
5397 };
5398
5399 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5400 Ok(true)
5401 } else {
5402 Ok(false)
5403 }
5404 }
5405
5406 OP_CHECKSIGVERIFY => {
5408 if stack.len() >= 2 {
5409 let pubkey_bytes = stack.pop().unwrap();
5410 let signature_bytes = stack.pop().unwrap();
5411
5412 if signature_bytes.is_empty() {
5414 return Ok(false);
5415 }
5416
5417 if sigversion == SigVersion::Tapscript {
5419 if pubkey_bytes.len() == 32 {
5420 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5421 if let Some((sig_bytes, sighash_byte)) =
5422 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5423 {
5424 let (tapscript, codesep_pos) = tapscript_for_sighash
5425 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5426 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5427 let sighash = if tapscript.is_empty() {
5428 crate::taproot::compute_taproot_signature_hash(
5429 tx,
5430 input_index,
5431 prevout_values,
5432 prevout_script_pubkeys,
5433 sighash_byte,
5434 None,
5435 )?
5436 } else {
5437 crate::taproot::compute_tapscript_signature_hash(
5438 tx,
5439 input_index,
5440 prevout_values,
5441 prevout_script_pubkeys,
5442 tapscript,
5443 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5444 codesep_pos,
5445 sighash_byte,
5446 ctx.taproot_annex_hash,
5447 )?
5448 };
5449 #[cfg(feature = "production")]
5450 let is_valid = {
5451 use crate::bip348::verify_tapscript_schnorr_signature;
5452 verify_tapscript_schnorr_signature(
5453 &sighash,
5454 &pubkey_bytes,
5455 &sig_bytes,
5456 schnorr_collector,
5457 )
5458 .unwrap_or(false)
5459 };
5460 #[cfg(not(feature = "production"))]
5461 let is_valid = {
5462 #[cfg(feature = "csfs")]
5463 let x = {
5464 use crate::bip348::verify_tapscript_schnorr_signature;
5465 verify_tapscript_schnorr_signature(
5466 &sighash,
5467 &pubkey_bytes,
5468 &sig_bytes,
5469 None,
5470 )
5471 .unwrap_or(false)
5472 };
5473 #[cfg(not(feature = "csfs"))]
5474 let x = false;
5475 x
5476 };
5477 if !is_valid {
5478 return Ok(false); }
5480 return Ok(true);
5481 }
5482 return Ok(false);
5484 }
5485 return Ok(true);
5487 }
5488
5489 let sig_len = signature_bytes.len();
5492 let sighash_byte = signature_bytes[sig_len - 1];
5493 let _der_sig = &signature_bytes[..sig_len - 1];
5494
5495 let sighash = if sigversion == SigVersion::WitnessV0 {
5499 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5501
5502 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5503 prevout_script_pubkeys
5504 .get(input_index)
5505 .copied()
5506 .unwrap_or(&[])
5507 });
5508
5509 crate::transaction_hash::calculate_bip143_sighash(
5510 tx,
5511 input_index,
5512 script_code,
5513 amount,
5514 sighash_byte,
5515 precomputed_bip143,
5516 )?
5517 } else {
5518 use crate::transaction_hash::{
5520 calculate_transaction_sighash_single_input, SighashType,
5521 };
5522 let sighash_type = SighashType::from_byte(sighash_byte);
5523
5524 let pattern = serialize_push_data(signature_bytes.as_ref());
5526
5527 let base_script = match (
5528 redeem_script_for_sighash,
5529 prevout_script_pubkeys.get(input_index),
5530 ) {
5531 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5532 (Some(redeem), _) => redeem,
5533 (None, Some(prevout)) => *prevout,
5534 (None, None) => &[],
5535 };
5536 let cleaned = find_and_delete(base_script, &pattern);
5537
5538 calculate_transaction_sighash_single_input(
5539 tx,
5540 input_index,
5541 cleaned.as_ref(),
5542 prevout_values[input_index],
5543 sighash_type,
5544 #[cfg(feature = "production")]
5545 sighash_cache,
5546 )?
5547 };
5548
5549 let height = block_height.unwrap_or(0);
5553 #[cfg(feature = "production")]
5554 let is_valid = signature::with_secp_context(|secp| {
5555 signature::verify_signature(
5556 secp,
5557 &pubkey_bytes,
5558 &signature_bytes, &sighash,
5560 flags,
5561 height,
5562 network,
5563 sigversion,
5564 )
5565 })?;
5566
5567 #[cfg(not(feature = "production"))]
5568 let is_valid = {
5569 let secp = signature::new_secp();
5570 signature::verify_signature(
5571 &secp,
5572 &pubkey_bytes,
5573 &signature_bytes, &sighash,
5575 flags,
5576 height,
5577 network,
5578 sigversion,
5579 )?
5580 };
5581
5582 if is_valid {
5583 Ok(true)
5584 } else {
5585 Ok(false)
5586 }
5587 } else {
5588 Ok(false)
5589 }
5590 }
5591
5592 OP_CHECKSIGADD => {
5594 if sigversion != SigVersion::Tapscript {
5595 return Err(ConsensusError::ScriptErrorWithCode {
5596 code: ScriptErrorCode::DisabledOpcode,
5597 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5598 });
5599 }
5600 if stack.len() < 3 {
5601 return Err(ConsensusError::ScriptErrorWithCode {
5602 code: ScriptErrorCode::InvalidStackOperation,
5603 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5604 });
5605 }
5606 let pubkey_bytes = stack.pop().unwrap();
5608 let n_bytes = stack.pop().unwrap();
5609 let signature_bytes = stack.pop().unwrap();
5610 let n = script_num_decode(&n_bytes, 4)?;
5611
5612 if signature_bytes.is_empty() {
5614 stack.push(to_stack_element(&script_num_encode(n)));
5615 return Ok(true);
5616 }
5617
5618 if pubkey_bytes.len() == 32 {
5620 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5621 if let Some((sig_bytes, sighash_byte)) =
5622 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5623 {
5624 let (tapscript, codesep_pos) = tapscript_for_sighash
5625 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5626 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5627 let sighash = if tapscript.is_empty() {
5628 crate::taproot::compute_taproot_signature_hash(
5629 tx,
5630 input_index,
5631 prevout_values,
5632 prevout_script_pubkeys,
5633 sighash_byte,
5634 None,
5635 )?
5636 } else {
5637 crate::taproot::compute_tapscript_signature_hash(
5638 tx,
5639 input_index,
5640 prevout_values,
5641 prevout_script_pubkeys,
5642 tapscript,
5643 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5644 codesep_pos,
5645 sighash_byte,
5646 ctx.taproot_annex_hash,
5647 )?
5648 };
5649
5650 #[cfg(feature = "production")]
5651 let is_valid = {
5652 use crate::bip348::verify_tapscript_schnorr_signature;
5653 verify_tapscript_schnorr_signature(
5654 &sighash,
5655 &pubkey_bytes,
5656 &sig_bytes,
5657 schnorr_collector,
5658 )
5659 .unwrap_or(false)
5660 };
5661
5662 #[cfg(not(feature = "production"))]
5663 let is_valid = {
5664 #[cfg(feature = "csfs")]
5665 let x = {
5666 use crate::bip348::verify_tapscript_schnorr_signature;
5667 verify_tapscript_schnorr_signature(
5668 &sighash,
5669 &pubkey_bytes,
5670 &sig_bytes,
5671 None,
5672 )
5673 .unwrap_or(false)
5674 };
5675 #[cfg(not(feature = "csfs"))]
5676 let x = false;
5677 x
5678 };
5679
5680 if !is_valid {
5681 return Ok(false); }
5683 stack.push(to_stack_element(&script_num_encode(n + 1)));
5684 return Ok(true);
5685 }
5686 return Ok(false); }
5688
5689 stack.push(to_stack_element(&script_num_encode(n + 1)));
5691 Ok(true)
5692 }
5693
5694 OP_CHECKMULTISIG => {
5696 if stack.len() < 2 {
5699 return Ok(false);
5700 }
5701
5702 let n_bytes = stack.pop().unwrap();
5704 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
5705 ConsensusError::ScriptErrorWithCode {
5706 code: ScriptErrorCode::InvalidStackOperation,
5707 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
5708 }
5709 })?;
5710 if !(0..=20).contains(&n_raw) {
5711 return Ok(false);
5712 }
5713 let n = n_raw as usize;
5714 if stack.len() < n + 1 {
5715 return Ok(false);
5716 }
5717
5718 let mut pubkeys = Vec::with_capacity(n);
5720 for _ in 0..n {
5721 pubkeys.push(stack.pop().unwrap());
5722 }
5723
5724 let m_bytes = stack.pop().unwrap();
5726 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
5727 ConsensusError::ScriptErrorWithCode {
5728 code: ScriptErrorCode::InvalidStackOperation,
5729 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
5730 }
5731 })?;
5732 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
5733 return Ok(false);
5734 }
5735 let m = m_raw as usize;
5736 if stack.len() < m + 1 {
5737 return Ok(false);
5738 }
5739
5740 let mut signatures = Vec::with_capacity(m);
5742 for _ in 0..m {
5743 signatures.push(stack.pop().unwrap());
5744 }
5745
5746 let dummy = stack.pop().unwrap();
5749 if flags & 0x10 != 0 {
5750 let height = block_height.unwrap_or(0);
5751 use crate::bip_validation::Bip147Network;
5753 let bip147_network = match network {
5754 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5755 crate::types::Network::Testnet => Bip147Network::Testnet,
5756 crate::types::Network::Regtest => Bip147Network::Regtest,
5757 };
5758
5759 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5763
5764 let bip147_active = height
5765 >= match bip147_network {
5766 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5767 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5768 Bip147Network::Regtest => 0,
5769 };
5770
5771 if bip147_active {
5772 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5776 if !is_empty {
5777 return Err(ConsensusError::ScriptErrorWithCode {
5778 code: ScriptErrorCode::SigNullDummy,
5779 message: format!(
5780 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5781 )
5782 .into(),
5783 });
5784 }
5785 }
5786 }
5787
5788 let height = block_height.unwrap_or(0);
5791
5792 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5795 let base_script = match (
5796 redeem_script_for_sighash,
5797 prevout_script_pubkeys.get(input_index),
5798 ) {
5799 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5800 (Some(redeem), _) => redeem,
5801 (None, Some(prevout)) => *prevout,
5802 (None, None) => &[],
5803 };
5804 let mut cleaned = base_script.to_vec();
5805 for sig in &signatures {
5806 if !sig.is_empty() {
5807 let pattern = serialize_push_data(sig.as_ref());
5808 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5809 }
5810 }
5811 cleaned
5812 } else {
5813 redeem_script_for_sighash
5815 .map(|s| s.to_vec())
5816 .unwrap_or_else(|| {
5817 prevout_script_pubkeys
5818 .get(input_index)
5819 .map(|p| p.to_vec())
5820 .unwrap_or_default()
5821 })
5822 };
5823
5824 use crate::transaction_hash::{
5825 calculate_transaction_sighash_single_input, SighashType,
5826 };
5827
5828 #[cfg(feature = "production")]
5830 let use_batch = pubkeys.len() * signatures.len() >= 4;
5831
5832 #[cfg(feature = "production")]
5833 let (valid_sigs, _) = if use_batch {
5834 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5836 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5837 if non_empty.is_empty() {
5838 vec![]
5839 } else {
5840 let specs: Vec<(usize, u8, &[u8])> = non_empty
5841 .iter()
5842 .map(|s| {
5843 (
5844 input_index,
5845 s.as_ref()[s.as_ref().len() - 1],
5846 cleaned_script_for_multisig.as_ref(),
5847 )
5848 })
5849 .collect();
5850 crate::transaction_hash::batch_compute_legacy_sighashes(
5851 tx,
5852 prevout_values,
5853 prevout_script_pubkeys,
5854 &specs,
5855 )?
5856 }
5857 } else {
5858 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5860 signatures
5861 .iter()
5862 .filter(|s| !s.is_empty())
5863 .map(|sig_bytes| {
5864 let sighash_byte = sig_bytes[sig_bytes.len() - 1];
5865 crate::transaction_hash::calculate_bip143_sighash(
5866 tx,
5867 input_index,
5868 &cleaned_script_for_multisig,
5869 amount,
5870 sighash_byte,
5871 precomputed_bip143,
5872 )
5873 })
5874 .collect::<Result<Vec<_>>>()?
5875 };
5876
5877 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5879 Vec::with_capacity(pubkeys.len() * signatures.len());
5880 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5881 let mut sighash_idx = 0usize;
5882 for (j, sig_bytes) in signatures.iter().enumerate() {
5883 if sig_bytes.is_empty() {
5884 sig_idx_to_sighash_idx.push(usize::MAX);
5885 } else {
5886 sig_idx_to_sighash_idx.push(sighash_idx);
5887 let sh = sighashes[sighash_idx];
5888 sighash_idx += 1;
5889 for pubkey_bytes in &pubkeys {
5890 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5891 }
5892 }
5893 }
5894
5895 let results = if tasks.is_empty() {
5896 vec![]
5897 } else {
5898 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
5899 };
5900
5901 let mut sig_index = 0;
5903 let mut valid_sigs = 0usize;
5904 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5905 if sig_index >= signatures.len() {
5906 break;
5907 }
5908 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5910 sig_index += 1;
5911 }
5912 if sig_index >= signatures.len() {
5913 break;
5914 }
5915 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5916 if sh_idx == usize::MAX {
5917 continue;
5918 }
5919 let task_idx = sh_idx * pubkeys.len() + i;
5920 if task_idx < results.len() && results[task_idx] {
5921 valid_sigs += 1;
5922 sig_index += 1;
5923 }
5924 }
5925
5926 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5928 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5929 for (j, sig_bytes) in signatures.iter().enumerate() {
5930 if sig_bytes.is_empty() {
5931 continue;
5932 }
5933 let sh_idx = sig_idx_to_sighash_idx[j];
5934 if sh_idx == usize::MAX {
5935 continue;
5936 }
5937 let sig_start = sh_idx * pubkeys.len();
5938 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5939 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5940 if !matched {
5941 return Err(ConsensusError::ScriptErrorWithCode {
5942 code: ScriptErrorCode::SigNullFail,
5943 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5944 });
5945 }
5946 }
5947 }
5948 (valid_sigs, ())
5949 } else {
5950 let mut sig_index = 0;
5951 let mut valid_sigs = 0;
5952 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5953
5954 for pubkey_bytes in &pubkeys {
5955 if sig_index >= signatures.len() {
5956 break;
5957 }
5958
5959 let signature_bytes = &signatures[sig_index];
5960
5961 if signature_bytes.is_empty() {
5962 continue;
5963 }
5964
5965 let sig_len = signature_bytes.len();
5966 let sighash_byte = signature_bytes[sig_len - 1];
5967
5968 let sighash = if sigversion == SigVersion::WitnessV0 {
5970 crate::transaction_hash::calculate_bip143_sighash(
5971 tx,
5972 input_index,
5973 &cleaned_script_for_multisig,
5974 amount,
5975 sighash_byte,
5976 #[cfg(feature = "production")]
5977 precomputed_bip143,
5978 #[cfg(not(feature = "production"))]
5979 None,
5980 )?
5981 } else {
5982 let sighash_type = SighashType::from_byte(sighash_byte);
5983 calculate_transaction_sighash_single_input(
5984 tx,
5985 input_index,
5986 &cleaned_script_for_multisig,
5987 prevout_values[input_index],
5988 sighash_type,
5989 #[cfg(feature = "production")]
5990 sighash_cache,
5991 )?
5992 };
5993
5994 #[cfg(feature = "production")]
5995 let is_valid = signature::with_secp_context(|secp| {
5996 signature::verify_signature(
5997 secp,
5998 pubkey_bytes,
5999 signature_bytes,
6000 &sighash,
6001 flags,
6002 height,
6003 network,
6004 sigversion,
6005 )
6006 })?;
6007
6008 #[cfg(not(feature = "production"))]
6009 let is_valid = {
6010 let secp = signature::new_secp();
6011 signature::verify_signature(
6012 &secp,
6013 pubkey_bytes,
6014 signature_bytes,
6015 &sighash,
6016 flags,
6017 height,
6018 network,
6019 sigversion,
6020 )?
6021 };
6022
6023 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6024 if !is_valid
6025 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6026 && !signature_bytes.is_empty()
6027 {
6028 return Err(ConsensusError::ScriptErrorWithCode {
6029 code: ScriptErrorCode::SigNullFail,
6030 message:
6031 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6032 .into(),
6033 });
6034 }
6035
6036 if is_valid {
6037 valid_sigs += 1;
6038 sig_index += 1;
6039 }
6040 }
6041 (valid_sigs, ())
6042 };
6043
6044 #[cfg(not(feature = "production"))]
6045 let (valid_sigs, _) = {
6046 let mut sig_index = 0;
6047 let mut valid_sigs = 0;
6048 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
6049
6050 for pubkey_bytes in &pubkeys {
6051 if sig_index >= signatures.len() {
6052 break;
6053 }
6054 let signature_bytes = &signatures[sig_index];
6055 if signature_bytes.is_empty() {
6056 continue;
6057 }
6058 let sig_len = signature_bytes.len();
6059 let sighash_byte = signature_bytes[sig_len - 1];
6060
6061 let sighash = if sigversion == SigVersion::WitnessV0 {
6063 crate::transaction_hash::calculate_bip143_sighash(
6064 tx,
6065 input_index,
6066 &cleaned_script_for_multisig,
6067 amount,
6068 sighash_byte,
6069 None,
6070 )?
6071 } else {
6072 let sighash_type = SighashType::from_byte(sighash_byte);
6073 calculate_transaction_sighash_single_input(
6074 tx,
6075 input_index,
6076 &cleaned_script_for_multisig,
6077 prevout_values[input_index],
6078 sighash_type,
6079 )?
6080 };
6081 let secp = signature::new_secp();
6082 let is_valid = signature::verify_signature(
6083 &secp,
6084 pubkey_bytes,
6085 signature_bytes,
6086 &sighash,
6087 flags,
6088 height,
6089 network,
6090 sigversion,
6091 )?;
6092 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6093 if !is_valid
6094 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6095 && !signature_bytes.is_empty()
6096 {
6097 return Err(ConsensusError::ScriptErrorWithCode {
6098 code: ScriptErrorCode::SigNullFail,
6099 message:
6100 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6101 .into(),
6102 });
6103 }
6104 if is_valid {
6105 valid_sigs += 1;
6106 sig_index += 1;
6107 }
6108 }
6109 (valid_sigs, ())
6110 };
6111
6112 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
6114 Ok(true)
6115 }
6116
6117 OP_CHECKMULTISIGVERIFY => {
6119 let ctx_checkmultisig = context::ScriptContext {
6121 tx,
6122 input_index,
6123 prevout_values,
6124 prevout_script_pubkeys,
6125 block_height,
6126 median_time_past,
6127 network,
6128 sigversion,
6129 redeem_script_for_sighash,
6130 script_sig_for_sighash,
6131 tapscript_for_sighash,
6132 tapscript_codesep_pos,
6133 taproot_annex_hash: None,
6134 #[cfg(feature = "production")]
6135 schnorr_collector: None,
6136 #[cfg(feature = "production")]
6137 precomputed_bip143,
6138 #[cfg(feature = "production")]
6139 sighash_cache,
6140 };
6141 let result = execute_opcode_with_context_full(
6142 OP_CHECKMULTISIG,
6143 stack,
6144 flags,
6145 &ctx_checkmultisig,
6146 redeem_script_for_sighash,
6147 )?;
6148 if !result {
6149 return Ok(false);
6150 }
6151 if let Some(top) = stack.pop() {
6153 if !cast_to_bool(&top) {
6154 return Ok(false);
6155 }
6156 Ok(true)
6157 } else {
6158 Ok(false)
6159 }
6160 }
6161
6162 OP_CHECKLOCKTIMEVERIFY => {
6167 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
6169 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
6170 return Ok(true);
6171 }
6172
6173 use crate::locktime::{check_bip65, decode_locktime_value};
6174
6175 if stack.is_empty() {
6176 return Err(ConsensusError::ScriptErrorWithCode {
6177 code: ScriptErrorCode::InvalidStackOperation,
6178 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
6179 });
6180 }
6181
6182 let locktime_bytes = stack.last().expect("Stack is not empty");
6184 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
6185 Some(v) => v,
6186 None => {
6187 return Err(ConsensusError::ScriptErrorWithCode {
6188 code: ScriptErrorCode::MinimalData,
6189 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
6190 })
6191 }
6192 };
6193
6194 let tx_locktime = tx.lock_time as u32;
6195
6196 if !check_bip65(tx_locktime, locktime_value) {
6198 return Ok(false);
6199 }
6200
6201 let input_seq = if input_index < tx.inputs.len() {
6203 tx.inputs[input_index].sequence
6204 } else {
6205 0xffffffff
6206 };
6207 if input_seq == 0xffffffff {
6208 return Ok(false);
6209 }
6210
6211 Ok(true)
6213 }
6214
6215 OP_CHECKSEQUENCEVERIFY => {
6224 use crate::locktime::{
6225 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
6226 is_sequence_disabled,
6227 };
6228
6229 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
6231 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
6232 return Ok(true);
6233 }
6234
6235 if stack.is_empty() {
6236 return Ok(false);
6237 }
6238
6239 let sequence_bytes = stack.last().expect("Stack is not empty");
6242 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
6243 Some(v) => v,
6244 None => return Ok(false), };
6246
6247 if input_index >= tx.inputs.len() {
6249 return Ok(false);
6250 }
6251 let input_sequence = tx.inputs[input_index].sequence as u32;
6252
6253 if is_sequence_disabled(input_sequence) {
6255 return Ok(true);
6256 }
6257
6258 let type_flag = extract_sequence_type_flag(sequence_value);
6260 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
6261
6262 let input_type_flag = extract_sequence_type_flag(input_sequence);
6264 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
6265
6266 if type_flag != input_type_flag {
6268 return Ok(false);
6269 }
6270
6271 if input_locktime < locktime_mask {
6273 return Ok(false);
6274 }
6275
6276 Ok(true)
6278 }
6279
6280 OP_CHECKTEMPLATEVERIFY => {
6289 #[cfg(not(feature = "ctv"))]
6290 {
6291 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6293 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6294 return Err(ConsensusError::ScriptErrorWithCode {
6295 code: ScriptErrorCode::BadOpcode,
6296 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
6297 });
6298 }
6299 Ok(true) }
6301
6302 #[cfg(feature = "ctv")]
6303 {
6304 use crate::constants::{
6305 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
6306 };
6307
6308 let ctv_activation = match network {
6310 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
6311 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
6312 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
6313 };
6314
6315 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
6316 if !ctv_active {
6317 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6319 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6320 return Err(ConsensusError::ScriptErrorWithCode {
6321 code: ScriptErrorCode::BadOpcode,
6322 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
6323 });
6324 }
6325 return Ok(true); }
6327
6328 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
6330 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
6331 return Ok(true);
6333 }
6334
6335 use crate::bip119::calculate_template_hash;
6336
6337 if stack.is_empty() {
6339 return Err(ConsensusError::ScriptErrorWithCode {
6340 code: ScriptErrorCode::InvalidStackOperation,
6341 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
6342 });
6343 }
6344
6345 let template_hash_bytes = stack.pop().unwrap();
6346
6347 if template_hash_bytes.len() != 32 {
6349 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6352 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6353 return Err(ConsensusError::ScriptErrorWithCode {
6354 code: ScriptErrorCode::InvalidStackOperation,
6355 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
6356 .into(),
6357 });
6358 }
6359 return Ok(true); }
6361
6362 let mut expected_hash = [0u8; 32];
6364 expected_hash.copy_from_slice(&template_hash_bytes);
6365
6366 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
6367 ConsensusError::ScriptErrorWithCode {
6368 code: ScriptErrorCode::TxInvalid,
6369 message: format!("CTV hash calculation failed: {e}").into(),
6370 }
6371 })?;
6372
6373 use crate::crypto::hash_compare::hash_eq;
6375 let matches = hash_eq(&expected_hash, &actual_hash);
6376
6377 if !matches {
6378 return Ok(false); }
6380
6381 Ok(true)
6383 }
6384 }
6385
6386 OP_CHECKSIGFROMSTACK => {
6397 #[cfg(not(feature = "csfs"))]
6398 {
6399 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6402 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6403 return Err(ConsensusError::ScriptErrorWithCode {
6404 code: ScriptErrorCode::BadOpcode,
6405 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
6406 });
6407 }
6408 Ok(true) }
6410
6411 #[cfg(feature = "csfs")]
6412 {
6413 use crate::constants::{
6414 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
6415 };
6416
6417 if sigversion != SigVersion::Tapscript {
6419 return Err(ConsensusError::ScriptErrorWithCode {
6420 code: ScriptErrorCode::BadOpcode,
6421 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
6422 });
6423 }
6424
6425 let csfs_activation = match network {
6427 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
6428 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
6429 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
6430 };
6431
6432 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
6433 if !csfs_active {
6434 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6436 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6437 return Err(ConsensusError::ScriptErrorWithCode {
6438 code: ScriptErrorCode::BadOpcode,
6439 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
6440 });
6441 }
6442 return Ok(true); }
6444
6445 use crate::bip348::verify_signature_from_stack;
6446
6447 if stack.len() < 3 {
6449 return Err(ConsensusError::ScriptErrorWithCode {
6450 code: ScriptErrorCode::InvalidStackOperation,
6451 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
6452 });
6453 }
6454
6455 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
6462 return Err(ConsensusError::ScriptErrorWithCode {
6463 code: ScriptErrorCode::PubkeyType,
6464 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
6465 });
6466 }
6467
6468 if signature_bytes.is_empty() {
6470 stack.push(to_stack_element(&[])); return Ok(true);
6472 }
6473
6474 #[cfg(feature = "production")]
6477 let is_valid = {
6478 verify_signature_from_stack(
6479 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6484 .unwrap_or(false)
6485 };
6486 #[cfg(not(feature = "production"))]
6487 let is_valid = verify_signature_from_stack(
6488 &message_bytes, &pubkey_bytes, &signature_bytes, )
6492 .unwrap_or(false);
6493
6494 if !is_valid {
6495 return Ok(false);
6497 }
6498
6499 stack.push(to_stack_element(&[0x01])); Ok(true)
6506 }
6507 }
6508
6509 _ => execute_opcode_cold(opcode, stack, flags),
6511 }
6512}
6513
6514#[cold]
6516fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6517 execute_opcode(opcode, stack, flags, SigVersion::Base)
6518}
6519
6520#[cfg(feature = "production")]
6535pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6536 (
6537 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6538 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6539 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6540 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6541 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6542 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6543 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6544 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6545 )
6546}
6547
6548#[cfg(all(feature = "production", feature = "benchmarking"))]
6555pub fn clear_script_cache() {
6556 if let Some(cache) = SCRIPT_CACHE.get() {
6557 let mut cache = cache.write().unwrap();
6558 cache.clear();
6559 }
6560}
6561
6562#[cfg(all(feature = "production", feature = "benchmarking"))]
6576pub fn clear_hash_cache() {
6577 crypto_ops::clear_hash_cache();
6578}
6579
6580#[cfg(all(feature = "production", feature = "benchmarking"))]
6593pub fn clear_all_caches() {
6594 clear_script_cache();
6595 clear_hash_cache();
6596}
6597
6598#[cfg(all(feature = "production", feature = "benchmarking"))]
6612pub fn clear_stack_pool() {
6613 STACK_POOL.with(|pool| {
6614 let mut pool = pool.borrow_mut();
6615 pool.clear();
6616 });
6617}
6618
6619#[cfg(all(feature = "production", feature = "benchmarking"))]
6633pub fn reset_benchmarking_state() {
6634 clear_all_caches();
6635 clear_stack_pool();
6636 disable_caching(false); #[cfg(feature = "benchmarking")]
6639 crate::transaction_hash::clear_sighash_templates();
6640}
6641
6642#[cfg(test)]
6643mod tests {
6644 use super::*;
6645
6646 #[test]
6647 fn test_eval_script_simple() {
6648 let script = vec![OP_1]; let mut stack = Vec::new();
6650
6651 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6652 assert_eq!(stack.len(), 1);
6653 assert_eq!(stack[0].as_ref(), &[1]);
6654 }
6655
6656 #[test]
6657 fn test_eval_script_overflow() {
6658 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6660
6661 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6662 }
6663
6664 #[test]
6665 fn test_verify_script_simple() {
6666 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());
6677 }
6678
6679 #[test]
6684 fn test_op_0() {
6685 let script = vec![OP_0]; let mut stack = Vec::new();
6687 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6688 assert!(result); assert_eq!(stack.len(), 1);
6690 assert!(stack[0].is_empty());
6691 }
6692
6693 #[test]
6694 fn test_op_1_to_op_16() {
6695 for i in 1..=16 {
6697 let opcode = 0x50 + i;
6698 let script = vec![opcode];
6699 let mut stack = Vec::new();
6700 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6701 assert!(result);
6702 assert_eq!(stack.len(), 1);
6703 assert_eq!(stack[0].as_ref(), &[i]);
6704 }
6705 }
6706
6707 #[test]
6708 fn test_op_dup() {
6709 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6711 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6712 assert!(result); assert_eq!(stack.len(), 2);
6714 assert_eq!(stack[0].as_ref(), &[1]);
6715 assert_eq!(stack[1].as_ref(), &[1]);
6716 }
6717
6718 #[test]
6719 fn test_op_dup_empty_stack() {
6720 let script = vec![OP_DUP]; let mut stack = Vec::new();
6722 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6723 assert!(!result);
6724 }
6725
6726 #[test]
6727 fn test_op_hash160() {
6728 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6730 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6731 assert!(result);
6732 assert_eq!(stack.len(), 1);
6733 assert_eq!(stack[0].len(), 20); }
6735
6736 #[test]
6737 fn test_op_hash160_empty_stack() {
6738 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6740 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6741 assert!(!result);
6742 }
6743
6744 #[test]
6745 fn test_op_hash256() {
6746 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6748 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6749 assert!(result);
6750 assert_eq!(stack.len(), 1);
6751 assert_eq!(stack[0].len(), 32); }
6753
6754 #[test]
6755 fn test_op_hash256_empty_stack() {
6756 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6758 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6759 assert!(!result);
6760 }
6761
6762 #[test]
6763 fn test_op_equal() {
6764 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6766 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6767 assert!(result);
6768 assert_eq!(stack.len(), 1);
6769 assert_eq!(stack[0].as_ref(), &[1]); }
6771
6772 #[test]
6773 fn test_op_equal_false() {
6774 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6776 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6777 assert!(result); assert_eq!(stack.len(), 1);
6779 assert!(stack[0].is_empty()); }
6781
6782 #[test]
6783 fn test_op_equal_insufficient_stack() {
6784 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6786 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6787 assert!(
6788 result.is_err(),
6789 "OP_EQUAL with insufficient stack should return error"
6790 );
6791 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6792 assert_eq!(
6793 code,
6794 crate::error::ScriptErrorCode::InvalidStackOperation,
6795 "Should return InvalidStackOperation"
6796 );
6797 }
6798 }
6799
6800 #[test]
6801 fn test_op_verify() {
6802 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6804 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6805 assert!(result); assert_eq!(stack.len(), 0); }
6808
6809 #[test]
6810 fn test_op_verify_false() {
6811 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6813 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6814 assert!(!result);
6815 }
6816
6817 #[test]
6818 fn test_op_verify_empty_stack() {
6819 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6821 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6822 assert!(!result);
6823 }
6824
6825 #[test]
6826 fn test_op_equalverify() {
6827 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6829 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6830 assert!(result); assert_eq!(stack.len(), 0); }
6833
6834 #[test]
6835 fn test_op_equalverify_false() {
6836 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6838 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6839 assert!(
6840 result.is_err(),
6841 "OP_EQUALVERIFY with false condition should return error"
6842 );
6843 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6844 assert_eq!(
6845 code,
6846 crate::error::ScriptErrorCode::EqualVerify,
6847 "Should return EqualVerify"
6848 );
6849 }
6850 }
6851
6852 #[test]
6853 fn test_op_checksig() {
6854 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6858 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6859 assert!(result); assert_eq!(stack.len(), 1);
6861 }
6863
6864 #[test]
6865 fn test_op_checksig_insufficient_stack() {
6866 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6868 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6869 assert!(
6870 result.is_err(),
6871 "OP_CHECKSIG with insufficient stack should return error"
6872 );
6873 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6874 assert_eq!(
6875 code,
6876 crate::error::ScriptErrorCode::InvalidStackOperation,
6877 "Should return InvalidStackOperation"
6878 );
6879 }
6880 }
6881
6882 #[test]
6883 fn test_unknown_opcode() {
6884 let script = vec![0xff]; let mut stack = Vec::new();
6886 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6887 assert!(!result);
6888 }
6889
6890 #[test]
6891 fn test_script_size_limit() {
6892 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6894 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6895 assert!(result.is_err());
6896 }
6897
6898 #[test]
6899 fn test_operation_count_limit() {
6900 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6903 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6904 assert!(result.is_err());
6905 }
6906
6907 #[test]
6908 fn test_stack_underflow_multiple_ops() {
6909 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6911 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6912 assert!(result.is_err(), "Stack underflow should return error");
6913 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6914 assert_eq!(
6915 code,
6916 crate::error::ScriptErrorCode::InvalidStackOperation,
6917 "Should return InvalidStackOperation"
6918 );
6919 }
6920 }
6921
6922 #[test]
6923 fn test_final_stack_empty() {
6924 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6927 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6928 assert!(result); assert_eq!(stack.len(), 2);
6930 }
6931
6932 #[test]
6933 fn test_final_stack_false() {
6934 let script = vec![OP_0]; let mut stack = Vec::new();
6937 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6938 assert!(result); }
6940
6941 #[test]
6942 fn test_verify_script_with_witness() {
6943 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6948
6949 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6950 assert!(result); }
6952
6953 #[test]
6954 fn test_verify_script_failure() {
6955 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_0]; let witness = None;
6959 let flags = 0;
6960
6961 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6962 assert!(!result); }
6964
6965 #[test]
6970 fn test_op_ifdup_true() {
6971 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6973 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6974 assert!(result); assert_eq!(stack.len(), 2);
6976 assert_eq!(stack[0].as_ref(), &[1]);
6977 assert_eq!(stack[1].as_ref(), &[1]);
6978 }
6979
6980 #[test]
6981 fn test_op_ifdup_false() {
6982 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6984 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6985 assert!(result); assert_eq!(stack.len(), 1);
6987 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6988 }
6989
6990 #[test]
6991 fn test_op_depth() {
6992 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6994 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6995 assert!(result); assert_eq!(stack.len(), 3);
6997 assert_eq!(stack[2].as_ref(), &[2]); }
6999
7000 #[test]
7001 fn test_op_drop() {
7002 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
7004 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7005 assert!(result); assert_eq!(stack.len(), 1);
7007 assert_eq!(stack[0].as_ref(), &[1]);
7008 }
7009
7010 #[test]
7011 fn test_op_drop_empty_stack() {
7012 let script = vec![OP_DROP]; let mut stack = Vec::new();
7014 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7015 assert!(!result);
7016 assert_eq!(stack.len(), 0);
7017 }
7018
7019 #[test]
7020 fn test_op_nip() {
7021 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
7023 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7024 assert!(result); assert_eq!(stack.len(), 1);
7026 assert_eq!(stack[0].as_ref(), &[2]);
7027 }
7028
7029 #[test]
7030 fn test_op_nip_insufficient_stack() {
7031 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
7033 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7034 assert!(!result);
7035 assert_eq!(stack.len(), 1);
7036 }
7037
7038 #[test]
7039 fn test_op_over() {
7040 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
7042 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7043 assert!(result); assert_eq!(stack.len(), 3);
7045 assert_eq!(stack[0].as_ref(), &[1]);
7046 assert_eq!(stack[1].as_ref(), &[2]);
7047 assert_eq!(stack[2].as_ref(), &[1]);
7048 }
7049
7050 #[test]
7051 fn test_op_over_insufficient_stack() {
7052 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
7054 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7055 assert!(!result);
7056 assert_eq!(stack.len(), 1);
7057 }
7058
7059 #[test]
7060 fn test_op_pick() {
7061 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
7063 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7064 assert!(result); assert_eq!(stack.len(), 4);
7066 assert_eq!(stack[3].as_ref(), &[2]); }
7068
7069 #[test]
7070 fn test_op_pick_empty_n() {
7071 let script = vec![OP_1, OP_0, OP_PICK];
7073 let mut stack = Vec::new();
7074 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7075 assert!(result); assert_eq!(stack.len(), 2);
7077 assert_eq!(stack[1].as_ref(), &[1]); }
7079
7080 #[test]
7081 fn test_op_pick_invalid_index() {
7082 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
7084 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7085 assert!(!result);
7086 assert_eq!(stack.len(), 1);
7087 }
7088
7089 #[test]
7090 fn test_op_roll() {
7091 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
7093 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7094 assert!(result); assert_eq!(stack.len(), 3);
7096 assert_eq!(stack[0].as_ref(), &[1]);
7097 assert_eq!(stack[1].as_ref(), &[3]);
7098 assert_eq!(stack[2].as_ref(), &[2]); }
7100
7101 #[test]
7102 fn test_op_roll_zero_n() {
7103 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
7106 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7107 assert!(result); assert_eq!(stack.len(), 1);
7109 assert_eq!(stack[0].as_ref(), &[1]);
7110 }
7111
7112 #[test]
7113 fn test_op_roll_invalid_index() {
7114 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
7116 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7117 assert!(!result);
7118 assert_eq!(stack.len(), 1);
7119 }
7120
7121 #[test]
7122 fn test_op_rot() {
7123 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
7125 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7126 assert!(result); assert_eq!(stack.len(), 3);
7128 assert_eq!(stack[0].as_ref(), &[2]);
7129 assert_eq!(stack[1].as_ref(), &[3]);
7130 assert_eq!(stack[2].as_ref(), &[1]);
7131 }
7132
7133 #[test]
7134 fn test_op_rot_insufficient_stack() {
7135 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
7137 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7138 assert!(!result);
7139 assert_eq!(stack.len(), 2);
7140 }
7141
7142 #[test]
7143 fn test_op_swap() {
7144 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
7146 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7147 assert!(result); assert_eq!(stack.len(), 2);
7149 assert_eq!(stack[0].as_ref(), &[2]);
7150 assert_eq!(stack[1].as_ref(), &[1]);
7151 }
7152
7153 #[test]
7154 fn test_op_swap_insufficient_stack() {
7155 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
7157 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7158 assert!(!result);
7159 assert_eq!(stack.len(), 1);
7160 }
7161
7162 #[test]
7163 fn test_op_tuck() {
7164 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
7166 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7167 assert!(result); assert_eq!(stack.len(), 3);
7169 assert_eq!(stack[0].as_ref(), &[2]);
7170 assert_eq!(stack[1].as_ref(), &[1]);
7171 assert_eq!(stack[2].as_ref(), &[2]);
7172 }
7173
7174 #[test]
7175 fn test_op_tuck_insufficient_stack() {
7176 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
7178 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7179 assert!(!result);
7180 assert_eq!(stack.len(), 1);
7181 }
7182
7183 #[test]
7184 fn test_op_2drop() {
7185 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
7187 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7188 assert!(result); assert_eq!(stack.len(), 1);
7190 assert_eq!(stack[0].as_ref(), &[1]);
7191 }
7192
7193 #[test]
7194 fn test_op_2drop_insufficient_stack() {
7195 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
7197 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7198 assert!(!result);
7199 assert_eq!(stack.len(), 1);
7200 }
7201
7202 #[test]
7203 fn test_op_2dup() {
7204 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
7206 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7207 assert!(result); assert_eq!(stack.len(), 4);
7209 assert_eq!(stack[0].as_ref(), &[1]);
7210 assert_eq!(stack[1].as_ref(), &[2]);
7211 assert_eq!(stack[2].as_ref(), &[1]);
7212 assert_eq!(stack[3].as_ref(), &[2]);
7213 }
7214
7215 #[test]
7216 fn test_op_2dup_insufficient_stack() {
7217 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
7219 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7220 assert!(!result);
7221 assert_eq!(stack.len(), 1);
7222 }
7223
7224 #[test]
7225 fn test_op_3dup() {
7226 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
7228 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7229 assert!(result); assert_eq!(stack.len(), 6);
7231 assert_eq!(stack[0].as_ref(), &[1]);
7232 assert_eq!(stack[1].as_ref(), &[2]);
7233 assert_eq!(stack[2].as_ref(), &[3]);
7234 assert_eq!(stack[3].as_ref(), &[1]);
7235 assert_eq!(stack[4].as_ref(), &[2]);
7236 assert_eq!(stack[5].as_ref(), &[3]);
7237 }
7238
7239 #[test]
7240 fn test_op_3dup_insufficient_stack() {
7241 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
7243 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7244 assert!(!result);
7245 assert_eq!(stack.len(), 2);
7246 }
7247
7248 #[test]
7249 fn test_op_2over() {
7250 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
7252 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7253 assert!(result); assert_eq!(stack.len(), 6);
7255 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
7257 }
7258
7259 #[test]
7260 fn test_op_2over_insufficient_stack() {
7261 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
7263 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7264 assert!(!result);
7265 assert_eq!(stack.len(), 3);
7266 }
7267
7268 #[test]
7269 fn test_op_2rot() {
7270 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
7275 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7276 assert!(result); assert_eq!(stack.len(), 6);
7278 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]); }
7281
7282 #[test]
7283 fn test_op_2rot_insufficient_stack() {
7284 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
7286 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7287 assert!(!result);
7288 assert_eq!(stack.len(), 4);
7289 }
7290
7291 #[test]
7292 fn test_op_2swap() {
7293 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
7295 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7296 assert!(result); assert_eq!(stack.len(), 4);
7298 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
7300 assert_eq!(stack[2].as_ref(), &[1]);
7301 assert_eq!(stack[3].as_ref(), &[2]);
7302 }
7303
7304 #[test]
7305 fn test_op_2swap_insufficient_stack() {
7306 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
7308 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7309 assert!(!result);
7310 assert_eq!(stack.len(), 3);
7311 }
7312
7313 #[test]
7314 fn test_op_size() {
7315 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
7317 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7318 assert!(result); assert_eq!(stack.len(), 2);
7320 assert_eq!(stack[0].as_ref(), &[1]);
7321 assert_eq!(stack[1].as_ref(), &[1]); }
7323
7324 #[test]
7325 fn test_op_size_empty_stack() {
7326 let script = vec![OP_SIZE]; let mut stack = Vec::new();
7328 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7329 assert!(!result);
7330 assert_eq!(stack.len(), 0);
7331 }
7332
7333 #[test]
7334 fn test_op_return() {
7335 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
7337 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7338 assert!(!result); assert_eq!(stack.len(), 1);
7340 }
7341
7342 #[test]
7343 fn test_op_checksigverify() {
7344 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7346 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7347 assert!(!result); assert_eq!(stack.len(), 0);
7349 }
7350
7351 #[test]
7352 fn test_op_checksigverify_insufficient_stack() {
7353 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7355 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7356 assert!(!result);
7357 assert_eq!(stack.len(), 1);
7358 }
7359
7360 #[test]
7361 fn test_unknown_opcode_comprehensive() {
7362 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
7364 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7365 assert!(!result); assert_eq!(stack.len(), 1);
7367 }
7368
7369 #[test]
7370 fn test_verify_signature_invalid_pubkey() {
7371 let secp = signature::new_secp();
7372 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
7375 let result = signature::verify_signature(
7376 &secp,
7377 &invalid_pubkey,
7378 &signature,
7379 &dummy_hash,
7380 0,
7381 0,
7382 crate::types::Network::Regtest,
7383 SigVersion::Base,
7384 );
7385 assert!(!result.unwrap_or(false));
7386 }
7387
7388 #[test]
7389 fn test_verify_signature_invalid_signature() {
7390 let secp = signature::new_secp();
7391 let pubkey = vec![
7392 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
7393 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
7394 0x5b, 0x16, 0xf8, 0x17, 0x98,
7395 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
7398 let result = signature::verify_signature(
7399 &secp,
7400 &pubkey,
7401 &invalid_signature,
7402 &dummy_hash,
7403 0,
7404 0,
7405 crate::types::Network::Regtest,
7406 SigVersion::Base,
7407 );
7408 assert!(!result.unwrap_or(false));
7409 }
7410
7411 fn minimal_tx_and_prevouts(
7417 script_sig: &[u8],
7418 script_pubkey: &[u8],
7419 ) -> (
7420 crate::types::Transaction,
7421 Vec<i64>,
7422 Vec<crate::types::ByteString>,
7423 ) {
7424 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
7425 let tx = Transaction {
7426 version: 1,
7427 inputs: vec![TransactionInput {
7428 prevout: OutPoint {
7429 hash: [0u8; 32],
7430 index: 0,
7431 },
7432 sequence: 0xffff_ffff,
7433 script_sig: script_sig.to_vec(),
7434 }]
7435 .into(),
7436 outputs: vec![TransactionOutput {
7437 value: 0,
7438 script_pubkey: script_pubkey.to_vec(),
7439 }]
7440 .into(),
7441 lock_time: 0,
7442 };
7443 let prevout_values = vec![0i64];
7444 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
7445 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
7446 (tx, prevout_values, prevout_script_pubkeys_vec)
7447 }
7448
7449 #[test]
7450 fn test_verify_with_context_p2pkh_hash_mismatch() {
7451 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
7455 script_sig.push(sig.len() as u8);
7456 script_sig.extend(&sig);
7457 script_sig.push(pubkey.len() as u8);
7458 script_sig.extend(&pubkey);
7459
7460 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
7461 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
7463 script_pubkey.push(OP_CHECKSIG);
7464
7465 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7466 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7467 let result = verify_script_with_context_full(
7468 &script_sig,
7469 &script_pubkey,
7470 None,
7471 0,
7472 &tx,
7473 0,
7474 &pv,
7475 &psp_refs,
7476 Some(500_000),
7477 None,
7478 crate::types::Network::Mainnet,
7479 SigVersion::Base,
7480 #[cfg(feature = "production")]
7481 None,
7482 None, #[cfg(feature = "production")]
7484 None,
7485 #[cfg(feature = "production")]
7486 None,
7487 #[cfg(feature = "production")]
7488 None,
7489 );
7490 assert!(result.is_ok());
7491 assert!(!result.unwrap());
7492 }
7493
7494 #[test]
7495 fn test_verify_with_context_p2sh_hash_mismatch() {
7496 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7499 script_sig.push(redeem.len() as u8);
7500 script_sig.extend(&redeem);
7501
7502 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7503 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7505
7506 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7507 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7508 let result = verify_script_with_context_full(
7509 &script_sig,
7510 &script_pubkey,
7511 None,
7512 0x01, &tx,
7514 0,
7515 &pv,
7516 &psp_refs,
7517 Some(500_000),
7518 None,
7519 crate::types::Network::Mainnet,
7520 SigVersion::Base,
7521 #[cfg(feature = "production")]
7522 None,
7523 None, #[cfg(feature = "production")]
7525 None,
7526 #[cfg(feature = "production")]
7527 None,
7528 #[cfg(feature = "production")]
7529 None,
7530 );
7531 assert!(result.is_ok());
7532 assert!(!result.unwrap());
7533 }
7534
7535 #[test]
7536 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7537 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7539 script_pubkey.extend(&[0u8; 20]);
7540 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7542 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7543 let empty: Vec<u8> = vec![];
7544 let result = verify_script_with_context_full(
7545 &empty,
7546 &script_pubkey,
7547 Some(&witness),
7548 0,
7549 &tx,
7550 0,
7551 &pv,
7552 &psp_refs,
7553 Some(500_000),
7554 None,
7555 crate::types::Network::Mainnet,
7556 SigVersion::Base,
7557 #[cfg(feature = "production")]
7558 None,
7559 None, #[cfg(feature = "production")]
7561 None,
7562 #[cfg(feature = "production")]
7563 None,
7564 #[cfg(feature = "production")]
7565 None,
7566 );
7567 assert!(result.is_ok());
7568 assert!(!result.unwrap());
7569 }
7570
7571 #[test]
7572 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7573 let witness_script = vec![OP_1];
7575 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7576 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7578 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7579 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7580 let empty: Vec<u8> = vec![];
7581 let result = verify_script_with_context_full(
7582 &empty,
7583 &script_pubkey,
7584 Some(&witness),
7585 0,
7586 &tx,
7587 0,
7588 &pv,
7589 &psp_refs,
7590 Some(500_000),
7591 None,
7592 crate::types::Network::Mainnet,
7593 SigVersion::Base,
7594 #[cfg(feature = "production")]
7595 None,
7596 None, #[cfg(feature = "production")]
7598 None,
7599 #[cfg(feature = "production")]
7600 None,
7601 #[cfg(feature = "production")]
7602 None,
7603 );
7604 assert!(result.is_ok());
7605 assert!(!result.unwrap());
7606 }
7607
7608 #[test]
7609 #[cfg(feature = "production")]
7610 fn test_p2wsh_multisig_fast_path() {
7611 use crate::constants::BIP147_ACTIVATION_MAINNET;
7613 use crate::crypto::OptimizedSha256;
7614
7615 let pk1 = [0x02u8; 33];
7616 let pk2 = [0x03u8; 33];
7617 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7619 witness_script.extend_from_slice(&pk2);
7620 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7624 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7625 script_pubkey.extend_from_slice(&wsh_hash);
7626
7627 let witness: Vec<Vec<u8>> = vec![
7628 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7632 ];
7633
7634 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7635 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7636 let empty: Vec<u8> = vec![];
7637 let result = verify_script_with_context_full(
7638 &empty,
7639 &script_pubkey,
7640 Some(&witness),
7641 0x810, &tx,
7643 0,
7644 &pv,
7645 &psp_refs,
7646 Some(BIP147_ACTIVATION_MAINNET + 1),
7647 None,
7648 crate::types::Network::Mainnet,
7649 SigVersion::Base,
7650 #[cfg(feature = "production")]
7651 None,
7652 None, #[cfg(feature = "production")]
7654 None,
7655 #[cfg(feature = "production")]
7656 None,
7657 #[cfg(feature = "production")]
7658 None,
7659 );
7660 assert!(result.is_ok());
7661 assert!(!result.unwrap());
7662 }
7663}
7664
7665#[cfg(test)]
7666#[allow(unused_doc_comments)]
7667mod property_tests {
7668 use super::*;
7669 use proptest::prelude::*;
7670
7671 proptest! {
7676 #[test]
7677 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7678 let mut stack = Vec::new();
7679 let flags = 0u32;
7680
7681 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7682
7683 if script.len() > MAX_SCRIPT_OPS * 2 {
7691 prop_assert!(result.is_err() || !result.unwrap(),
7694 "Very long scripts should fail or return false");
7695 }
7696 }
7698 }
7699
7700 proptest! {
7705 #[test]
7706 fn prop_verify_script_deterministic(
7707 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7708 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7709 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7710 flags in any::<u32>()
7711 ) {
7712 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7713 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7714
7715 assert_eq!(result1.is_ok(), result2.is_ok());
7716 if result1.is_ok() && result2.is_ok() {
7717 assert_eq!(result1.unwrap(), result2.unwrap());
7718 }
7719 }
7720 }
7721
7722 proptest! {
7727 #[test]
7728 fn prop_execute_opcode_no_panic(
7729 opcode in any::<u8>(),
7730 stack_items in prop::collection::vec(
7731 prop::collection::vec(any::<u8>(), 0..5),
7732 0..10
7733 ),
7734 flags in any::<u32>()
7735 ) {
7736 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7737 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7738
7739 match result {
7742 Ok(success) => {
7743 let _ = success;
7745 },
7746 Err(_) => {
7747 }
7750 }
7751
7752 assert!(stack.len() <= MAX_STACK_SIZE);
7754 }
7755 }
7756
7757 proptest! {
7764 #[test]
7765 fn prop_stack_operations_bounds(
7766 opcode in any::<u8>(),
7767 stack_items in prop::collection::vec(
7768 prop::collection::vec(any::<u8>(), 0..3),
7769 0..5
7770 ),
7771 flags in any::<u32>()
7772 ) {
7773 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7774 let initial_len = stack.len();
7775
7776 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7777
7778 assert!(stack.len() <= MAX_STACK_SIZE);
7780
7781 if result.is_ok() && result.unwrap() {
7783 match opcode {
7785 OP_0 | OP_1..=OP_16 => {
7786 assert!(stack.len() == initial_len + 1);
7788 },
7789 OP_DUP => {
7790 if initial_len > 0 {
7792 assert!(stack.len() == initial_len + 1);
7793 }
7794 },
7795 OP_3DUP => {
7796 if initial_len >= 3 {
7798 assert!(stack.len() == initial_len + 3);
7799 }
7800 },
7801 OP_2OVER => {
7802 if initial_len >= 4 {
7804 assert!(stack.len() == initial_len + 2);
7805 }
7806 },
7807 OP_DROP | OP_NIP | OP_2DROP => {
7808 assert!(stack.len() <= initial_len);
7810 },
7811 _ => {
7812 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7815 }
7816 }
7817 }
7818 }
7819 }
7820
7821 proptest! {
7826 #[test]
7827 fn prop_hash_operations_deterministic(
7828 input in prop::collection::vec(any::<u8>(), 0..10)
7829 ) {
7830 let elem = to_stack_element(&input);
7831 let mut stack1 = vec![elem.clone()];
7832 let mut stack2 = vec![elem];
7833
7834 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());
7838 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7839 assert_eq!(val1, val2);
7840 if val1 {
7841 assert_eq!(stack1, stack2);
7842 }
7843 }
7844 }
7845 }
7846
7847 proptest! {
7852 #[test]
7853 fn prop_equality_operations_symmetric(
7854 a in prop::collection::vec(any::<u8>(), 0..5),
7855 b in prop::collection::vec(any::<u8>(), 0..5)
7856 ) {
7857 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7858 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7859
7860 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());
7864 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7865 assert_eq!(val1, val2);
7866 if val1 {
7867 assert_eq!(stack1.len(), stack2.len());
7869 if !stack1.is_empty() && !stack2.is_empty() {
7870 assert_eq!(stack1[0], stack2[0]);
7871 }
7872 }
7873 }
7874 }
7875 }
7876
7877 proptest! {
7882 #[test]
7883 fn prop_script_execution_terminates(
7884 script in prop::collection::vec(any::<u8>(), 0..50)
7885 ) {
7886 let mut stack = Vec::new();
7887 let flags = 0u32;
7888
7889 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7891
7892 assert!(result.is_ok() || result.is_err());
7894
7895 assert!(stack.len() <= MAX_STACK_SIZE);
7897 }
7898 }
7899}