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::{StackElement, cast_to_bool, to_stack_element};
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 OnceLock, RwLock,
70 atomic::{AtomicBool, AtomicU64, Ordering},
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::{SighashType, calculate_transaction_sighash_single_input};
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::{SighashType, calculate_transaction_sighash_single_input};
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::{SighashType, calculate_transaction_sighash_single_input};
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 SighashType, calculate_transaction_sighash_single_input,
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 SighashType, calculate_transaction_sighash_single_input,
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 SighashType, calculate_transaction_sighash_single_input,
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 SighashType, calculate_transaction_sighash_single_input,
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 SighashType, calculate_transaction_sighash_single_input,
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 { Ok(true) } else { Ok(false) }
5583 } else {
5584 Ok(false)
5585 }
5586 }
5587
5588 OP_CHECKSIGADD => {
5590 if sigversion != SigVersion::Tapscript {
5591 return Err(ConsensusError::ScriptErrorWithCode {
5592 code: ScriptErrorCode::DisabledOpcode,
5593 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5594 });
5595 }
5596 if stack.len() < 3 {
5597 return Err(ConsensusError::ScriptErrorWithCode {
5598 code: ScriptErrorCode::InvalidStackOperation,
5599 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5600 });
5601 }
5602 let pubkey_bytes = stack.pop().unwrap();
5604 let n_bytes = stack.pop().unwrap();
5605 let signature_bytes = stack.pop().unwrap();
5606 let n = script_num_decode(&n_bytes, 4)?;
5607
5608 if signature_bytes.is_empty() {
5610 stack.push(to_stack_element(&script_num_encode(n)));
5611 return Ok(true);
5612 }
5613
5614 if pubkey_bytes.len() == 32 {
5616 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5617 if let Some((sig_bytes, sighash_byte)) =
5618 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5619 {
5620 let (tapscript, codesep_pos) = tapscript_for_sighash
5621 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5622 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5623 let sighash = if tapscript.is_empty() {
5624 crate::taproot::compute_taproot_signature_hash(
5625 tx,
5626 input_index,
5627 prevout_values,
5628 prevout_script_pubkeys,
5629 sighash_byte,
5630 None,
5631 )?
5632 } else {
5633 crate::taproot::compute_tapscript_signature_hash(
5634 tx,
5635 input_index,
5636 prevout_values,
5637 prevout_script_pubkeys,
5638 tapscript,
5639 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5640 codesep_pos,
5641 sighash_byte,
5642 ctx.taproot_annex_hash,
5643 )?
5644 };
5645
5646 #[cfg(feature = "production")]
5647 let is_valid = {
5648 use crate::bip348::verify_tapscript_schnorr_signature;
5649 verify_tapscript_schnorr_signature(
5650 &sighash,
5651 &pubkey_bytes,
5652 &sig_bytes,
5653 schnorr_collector,
5654 )
5655 .unwrap_or(false)
5656 };
5657
5658 #[cfg(not(feature = "production"))]
5659 let is_valid = {
5660 #[cfg(feature = "csfs")]
5661 let x = {
5662 use crate::bip348::verify_tapscript_schnorr_signature;
5663 verify_tapscript_schnorr_signature(
5664 &sighash,
5665 &pubkey_bytes,
5666 &sig_bytes,
5667 None,
5668 )
5669 .unwrap_or(false)
5670 };
5671 #[cfg(not(feature = "csfs"))]
5672 let x = false;
5673 x
5674 };
5675
5676 if !is_valid {
5677 return Ok(false); }
5679 stack.push(to_stack_element(&script_num_encode(n + 1)));
5680 return Ok(true);
5681 }
5682 return Ok(false); }
5684
5685 stack.push(to_stack_element(&script_num_encode(n + 1)));
5687 Ok(true)
5688 }
5689
5690 OP_CHECKMULTISIG => {
5692 if stack.len() < 2 {
5695 return Ok(false);
5696 }
5697
5698 let n_bytes = stack.pop().unwrap();
5700 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
5701 ConsensusError::ScriptErrorWithCode {
5702 code: ScriptErrorCode::InvalidStackOperation,
5703 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
5704 }
5705 })?;
5706 if !(0..=20).contains(&n_raw) {
5707 return Ok(false);
5708 }
5709 let n = n_raw as usize;
5710 if stack.len() < n + 1 {
5711 return Ok(false);
5712 }
5713
5714 let mut pubkeys = Vec::with_capacity(n);
5716 for _ in 0..n {
5717 pubkeys.push(stack.pop().unwrap());
5718 }
5719
5720 let m_bytes = stack.pop().unwrap();
5722 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
5723 ConsensusError::ScriptErrorWithCode {
5724 code: ScriptErrorCode::InvalidStackOperation,
5725 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
5726 }
5727 })?;
5728 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
5729 return Ok(false);
5730 }
5731 let m = m_raw as usize;
5732 if stack.len() < m + 1 {
5733 return Ok(false);
5734 }
5735
5736 let mut signatures = Vec::with_capacity(m);
5738 for _ in 0..m {
5739 signatures.push(stack.pop().unwrap());
5740 }
5741
5742 let dummy = stack.pop().unwrap();
5745 if flags & 0x10 != 0 {
5746 let height = block_height.unwrap_or(0);
5747 use crate::bip_validation::Bip147Network;
5749 let bip147_network = match network {
5750 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5751 crate::types::Network::Testnet => Bip147Network::Testnet,
5752 crate::types::Network::Regtest => Bip147Network::Regtest,
5753 };
5754
5755 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5759
5760 let bip147_active = height
5761 >= match bip147_network {
5762 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5763 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5764 Bip147Network::Regtest => 0,
5765 };
5766
5767 if bip147_active {
5768 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5772 if !is_empty {
5773 return Err(ConsensusError::ScriptErrorWithCode {
5774 code: ScriptErrorCode::SigNullDummy,
5775 message: format!(
5776 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5777 )
5778 .into(),
5779 });
5780 }
5781 }
5782 }
5783
5784 let height = block_height.unwrap_or(0);
5787
5788 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5791 let base_script = match (
5792 redeem_script_for_sighash,
5793 prevout_script_pubkeys.get(input_index),
5794 ) {
5795 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5796 (Some(redeem), _) => redeem,
5797 (None, Some(prevout)) => *prevout,
5798 (None, None) => &[],
5799 };
5800 let mut cleaned = base_script.to_vec();
5801 for sig in &signatures {
5802 if !sig.is_empty() {
5803 let pattern = serialize_push_data(sig.as_ref());
5804 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5805 }
5806 }
5807 cleaned
5808 } else {
5809 redeem_script_for_sighash
5811 .map(|s| s.to_vec())
5812 .unwrap_or_else(|| {
5813 prevout_script_pubkeys
5814 .get(input_index)
5815 .map(|p| p.to_vec())
5816 .unwrap_or_default()
5817 })
5818 };
5819
5820 use crate::transaction_hash::{
5821 SighashType, calculate_transaction_sighash_single_input,
5822 };
5823
5824 #[cfg(feature = "production")]
5826 let use_batch = pubkeys.len() * signatures.len() >= 4;
5827
5828 #[cfg(feature = "production")]
5829 let (valid_sigs, _) = if use_batch {
5830 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5832 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5833 if non_empty.is_empty() {
5834 vec![]
5835 } else {
5836 let specs: Vec<(usize, u8, &[u8])> = non_empty
5837 .iter()
5838 .map(|s| {
5839 (
5840 input_index,
5841 s.as_ref()[s.as_ref().len() - 1],
5842 cleaned_script_for_multisig.as_ref(),
5843 )
5844 })
5845 .collect();
5846 crate::transaction_hash::batch_compute_legacy_sighashes(
5847 tx,
5848 prevout_values,
5849 prevout_script_pubkeys,
5850 &specs,
5851 )?
5852 }
5853 } else {
5854 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5856 signatures
5857 .iter()
5858 .filter(|s| !s.is_empty())
5859 .map(|sig_bytes| {
5860 let sighash_byte = sig_bytes[sig_bytes.len() - 1];
5861 crate::transaction_hash::calculate_bip143_sighash(
5862 tx,
5863 input_index,
5864 &cleaned_script_for_multisig,
5865 amount,
5866 sighash_byte,
5867 precomputed_bip143,
5868 )
5869 })
5870 .collect::<Result<Vec<_>>>()?
5871 };
5872
5873 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5875 Vec::with_capacity(pubkeys.len() * signatures.len());
5876 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5877 let mut sighash_idx = 0usize;
5878 for (j, sig_bytes) in signatures.iter().enumerate() {
5879 if sig_bytes.is_empty() {
5880 sig_idx_to_sighash_idx.push(usize::MAX);
5881 } else {
5882 sig_idx_to_sighash_idx.push(sighash_idx);
5883 let sh = sighashes[sighash_idx];
5884 sighash_idx += 1;
5885 for pubkey_bytes in &pubkeys {
5886 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5887 }
5888 }
5889 }
5890
5891 let results = if tasks.is_empty() {
5892 vec![]
5893 } else {
5894 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
5895 };
5896
5897 let mut sig_index = 0;
5899 let mut valid_sigs = 0usize;
5900 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5901 if sig_index >= signatures.len() {
5902 break;
5903 }
5904 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5906 sig_index += 1;
5907 }
5908 if sig_index >= signatures.len() {
5909 break;
5910 }
5911 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5912 if sh_idx == usize::MAX {
5913 continue;
5914 }
5915 let task_idx = sh_idx * pubkeys.len() + i;
5916 if task_idx < results.len() && results[task_idx] {
5917 valid_sigs += 1;
5918 sig_index += 1;
5919 }
5920 }
5921
5922 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5924 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5925 for (j, sig_bytes) in signatures.iter().enumerate() {
5926 if sig_bytes.is_empty() {
5927 continue;
5928 }
5929 let sh_idx = sig_idx_to_sighash_idx[j];
5930 if sh_idx == usize::MAX {
5931 continue;
5932 }
5933 let sig_start = sh_idx * pubkeys.len();
5934 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5935 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5936 if !matched {
5937 return Err(ConsensusError::ScriptErrorWithCode {
5938 code: ScriptErrorCode::SigNullFail,
5939 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5940 });
5941 }
5942 }
5943 }
5944 (valid_sigs, ())
5945 } else {
5946 let mut sig_index = 0;
5947 let mut valid_sigs = 0;
5948 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5949
5950 for pubkey_bytes in &pubkeys {
5951 if sig_index >= signatures.len() {
5952 break;
5953 }
5954
5955 let signature_bytes = &signatures[sig_index];
5956
5957 if signature_bytes.is_empty() {
5958 continue;
5959 }
5960
5961 let sig_len = signature_bytes.len();
5962 let sighash_byte = signature_bytes[sig_len - 1];
5963
5964 let sighash = if sigversion == SigVersion::WitnessV0 {
5966 crate::transaction_hash::calculate_bip143_sighash(
5967 tx,
5968 input_index,
5969 &cleaned_script_for_multisig,
5970 amount,
5971 sighash_byte,
5972 #[cfg(feature = "production")]
5973 precomputed_bip143,
5974 #[cfg(not(feature = "production"))]
5975 None,
5976 )?
5977 } else {
5978 let sighash_type = SighashType::from_byte(sighash_byte);
5979 calculate_transaction_sighash_single_input(
5980 tx,
5981 input_index,
5982 &cleaned_script_for_multisig,
5983 prevout_values[input_index],
5984 sighash_type,
5985 #[cfg(feature = "production")]
5986 sighash_cache,
5987 )?
5988 };
5989
5990 #[cfg(feature = "production")]
5991 let is_valid = signature::with_secp_context(|secp| {
5992 signature::verify_signature(
5993 secp,
5994 pubkey_bytes,
5995 signature_bytes,
5996 &sighash,
5997 flags,
5998 height,
5999 network,
6000 sigversion,
6001 )
6002 })?;
6003
6004 #[cfg(not(feature = "production"))]
6005 let is_valid = {
6006 let secp = signature::new_secp();
6007 signature::verify_signature(
6008 &secp,
6009 pubkey_bytes,
6010 signature_bytes,
6011 &sighash,
6012 flags,
6013 height,
6014 network,
6015 sigversion,
6016 )?
6017 };
6018
6019 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6020 if !is_valid
6021 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6022 && !signature_bytes.is_empty()
6023 {
6024 return Err(ConsensusError::ScriptErrorWithCode {
6025 code: ScriptErrorCode::SigNullFail,
6026 message:
6027 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6028 .into(),
6029 });
6030 }
6031
6032 if is_valid {
6033 valid_sigs += 1;
6034 sig_index += 1;
6035 }
6036 }
6037 (valid_sigs, ())
6038 };
6039
6040 #[cfg(not(feature = "production"))]
6041 let (valid_sigs, _) = {
6042 let mut sig_index = 0;
6043 let mut valid_sigs = 0;
6044 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
6045
6046 for pubkey_bytes in &pubkeys {
6047 if sig_index >= signatures.len() {
6048 break;
6049 }
6050 let signature_bytes = &signatures[sig_index];
6051 if signature_bytes.is_empty() {
6052 continue;
6053 }
6054 let sig_len = signature_bytes.len();
6055 let sighash_byte = signature_bytes[sig_len - 1];
6056
6057 let sighash = if sigversion == SigVersion::WitnessV0 {
6059 crate::transaction_hash::calculate_bip143_sighash(
6060 tx,
6061 input_index,
6062 &cleaned_script_for_multisig,
6063 amount,
6064 sighash_byte,
6065 None,
6066 )?
6067 } else {
6068 let sighash_type = SighashType::from_byte(sighash_byte);
6069 calculate_transaction_sighash_single_input(
6070 tx,
6071 input_index,
6072 &cleaned_script_for_multisig,
6073 prevout_values[input_index],
6074 sighash_type,
6075 )?
6076 };
6077 let secp = signature::new_secp();
6078 let is_valid = signature::verify_signature(
6079 &secp,
6080 pubkey_bytes,
6081 signature_bytes,
6082 &sighash,
6083 flags,
6084 height,
6085 network,
6086 sigversion,
6087 )?;
6088 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6089 if !is_valid
6090 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6091 && !signature_bytes.is_empty()
6092 {
6093 return Err(ConsensusError::ScriptErrorWithCode {
6094 code: ScriptErrorCode::SigNullFail,
6095 message:
6096 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6097 .into(),
6098 });
6099 }
6100 if is_valid {
6101 valid_sigs += 1;
6102 sig_index += 1;
6103 }
6104 }
6105 (valid_sigs, ())
6106 };
6107
6108 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
6110 Ok(true)
6111 }
6112
6113 OP_CHECKMULTISIGVERIFY => {
6115 let ctx_checkmultisig = context::ScriptContext {
6117 tx,
6118 input_index,
6119 prevout_values,
6120 prevout_script_pubkeys,
6121 block_height,
6122 median_time_past,
6123 network,
6124 sigversion,
6125 redeem_script_for_sighash,
6126 script_sig_for_sighash,
6127 tapscript_for_sighash,
6128 tapscript_codesep_pos,
6129 taproot_annex_hash: None,
6130 #[cfg(feature = "production")]
6131 schnorr_collector: None,
6132 #[cfg(feature = "production")]
6133 precomputed_bip143,
6134 #[cfg(feature = "production")]
6135 sighash_cache,
6136 };
6137 let result = execute_opcode_with_context_full(
6138 OP_CHECKMULTISIG,
6139 stack,
6140 flags,
6141 &ctx_checkmultisig,
6142 redeem_script_for_sighash,
6143 )?;
6144 if !result {
6145 return Ok(false);
6146 }
6147 if let Some(top) = stack.pop() {
6149 if !cast_to_bool(&top) {
6150 return Ok(false);
6151 }
6152 Ok(true)
6153 } else {
6154 Ok(false)
6155 }
6156 }
6157
6158 OP_CHECKLOCKTIMEVERIFY => {
6163 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
6165 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
6166 return Ok(true);
6167 }
6168
6169 use crate::locktime::{check_bip65, decode_locktime_value};
6170
6171 if stack.is_empty() {
6172 return Err(ConsensusError::ScriptErrorWithCode {
6173 code: ScriptErrorCode::InvalidStackOperation,
6174 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
6175 });
6176 }
6177
6178 let locktime_bytes = stack.last().expect("Stack is not empty");
6180 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
6181 Some(v) => v,
6182 None => {
6183 return Err(ConsensusError::ScriptErrorWithCode {
6184 code: ScriptErrorCode::MinimalData,
6185 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
6186 });
6187 }
6188 };
6189
6190 let tx_locktime = tx.lock_time as u32;
6191
6192 if !check_bip65(tx_locktime, locktime_value) {
6194 return Ok(false);
6195 }
6196
6197 let input_seq = if input_index < tx.inputs.len() {
6199 tx.inputs[input_index].sequence
6200 } else {
6201 0xffffffff
6202 };
6203 if input_seq == 0xffffffff {
6204 return Ok(false);
6205 }
6206
6207 Ok(true)
6209 }
6210
6211 OP_CHECKSEQUENCEVERIFY => {
6220 use crate::locktime::{
6221 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
6222 is_sequence_disabled,
6223 };
6224
6225 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
6227 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
6228 return Ok(true);
6229 }
6230
6231 if stack.is_empty() {
6232 return Ok(false);
6233 }
6234
6235 let sequence_bytes = stack.last().expect("Stack is not empty");
6238 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
6239 Some(v) => v,
6240 None => return Ok(false), };
6242
6243 if input_index >= tx.inputs.len() {
6245 return Ok(false);
6246 }
6247 let input_sequence = tx.inputs[input_index].sequence as u32;
6248
6249 if is_sequence_disabled(input_sequence) {
6251 return Ok(true);
6252 }
6253
6254 let type_flag = extract_sequence_type_flag(sequence_value);
6256 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
6257
6258 let input_type_flag = extract_sequence_type_flag(input_sequence);
6260 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
6261
6262 if type_flag != input_type_flag {
6264 return Ok(false);
6265 }
6266
6267 if input_locktime < locktime_mask {
6269 return Ok(false);
6270 }
6271
6272 Ok(true)
6274 }
6275
6276 OP_CHECKTEMPLATEVERIFY => {
6285 #[cfg(not(feature = "ctv"))]
6286 {
6287 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6289 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6290 return Err(ConsensusError::ScriptErrorWithCode {
6291 code: ScriptErrorCode::BadOpcode,
6292 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
6293 });
6294 }
6295 Ok(true) }
6297
6298 #[cfg(feature = "ctv")]
6299 {
6300 use crate::constants::{
6301 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
6302 };
6303
6304 let ctv_activation = match network {
6306 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
6307 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
6308 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
6309 };
6310
6311 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
6312 if !ctv_active {
6313 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6315 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6316 return Err(ConsensusError::ScriptErrorWithCode {
6317 code: ScriptErrorCode::BadOpcode,
6318 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
6319 });
6320 }
6321 return Ok(true); }
6323
6324 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
6326 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
6327 return Ok(true);
6329 }
6330
6331 use crate::bip119::calculate_template_hash;
6332
6333 if stack.is_empty() {
6335 return Err(ConsensusError::ScriptErrorWithCode {
6336 code: ScriptErrorCode::InvalidStackOperation,
6337 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
6338 });
6339 }
6340
6341 let template_hash_bytes = stack.pop().unwrap();
6342
6343 if template_hash_bytes.len() != 32 {
6345 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6348 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6349 return Err(ConsensusError::ScriptErrorWithCode {
6350 code: ScriptErrorCode::InvalidStackOperation,
6351 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
6352 .into(),
6353 });
6354 }
6355 return Ok(true); }
6357
6358 let mut expected_hash = [0u8; 32];
6360 expected_hash.copy_from_slice(&template_hash_bytes);
6361
6362 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
6363 ConsensusError::ScriptErrorWithCode {
6364 code: ScriptErrorCode::TxInvalid,
6365 message: format!("CTV hash calculation failed: {e}").into(),
6366 }
6367 })?;
6368
6369 use crate::crypto::hash_compare::hash_eq;
6371 let matches = hash_eq(&expected_hash, &actual_hash);
6372
6373 if !matches {
6374 return Ok(false); }
6376
6377 Ok(true)
6379 }
6380 }
6381
6382 OP_CHECKSIGFROMSTACK => {
6393 #[cfg(not(feature = "csfs"))]
6394 {
6395 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6398 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6399 return Err(ConsensusError::ScriptErrorWithCode {
6400 code: ScriptErrorCode::BadOpcode,
6401 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
6402 });
6403 }
6404 Ok(true) }
6406
6407 #[cfg(feature = "csfs")]
6408 {
6409 use crate::constants::{
6410 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
6411 };
6412
6413 if sigversion != SigVersion::Tapscript {
6415 return Err(ConsensusError::ScriptErrorWithCode {
6416 code: ScriptErrorCode::BadOpcode,
6417 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
6418 });
6419 }
6420
6421 let csfs_activation = match network {
6423 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
6424 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
6425 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
6426 };
6427
6428 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
6429 if !csfs_active {
6430 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6432 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6433 return Err(ConsensusError::ScriptErrorWithCode {
6434 code: ScriptErrorCode::BadOpcode,
6435 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
6436 });
6437 }
6438 return Ok(true); }
6440
6441 use crate::bip348::verify_signature_from_stack;
6442
6443 if stack.len() < 3 {
6445 return Err(ConsensusError::ScriptErrorWithCode {
6446 code: ScriptErrorCode::InvalidStackOperation,
6447 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
6448 });
6449 }
6450
6451 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
6458 return Err(ConsensusError::ScriptErrorWithCode {
6459 code: ScriptErrorCode::PubkeyType,
6460 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
6461 });
6462 }
6463
6464 if signature_bytes.is_empty() {
6466 stack.push(to_stack_element(&[])); return Ok(true);
6468 }
6469
6470 #[cfg(feature = "production")]
6473 let is_valid = {
6474 verify_signature_from_stack(
6475 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6480 .unwrap_or(false)
6481 };
6482 #[cfg(not(feature = "production"))]
6483 let is_valid = verify_signature_from_stack(
6484 &message_bytes, &pubkey_bytes, &signature_bytes, )
6488 .unwrap_or(false);
6489
6490 if !is_valid {
6491 return Ok(false);
6493 }
6494
6495 stack.push(to_stack_element(&[0x01])); Ok(true)
6502 }
6503 }
6504
6505 _ => execute_opcode_cold(opcode, stack, flags),
6507 }
6508}
6509
6510#[cold]
6512fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6513 execute_opcode(opcode, stack, flags, SigVersion::Base)
6514}
6515
6516#[cfg(feature = "production")]
6531pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6532 (
6533 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6534 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6535 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6536 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6537 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6538 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6539 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6540 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6541 )
6542}
6543
6544#[cfg(all(feature = "production", feature = "benchmarking"))]
6551pub fn clear_script_cache() {
6552 if let Some(cache) = SCRIPT_CACHE.get() {
6553 let mut cache = cache.write().unwrap();
6554 cache.clear();
6555 }
6556}
6557
6558#[cfg(all(feature = "production", feature = "benchmarking"))]
6572pub fn clear_hash_cache() {
6573 crypto_ops::clear_hash_cache();
6574}
6575
6576#[cfg(all(feature = "production", feature = "benchmarking"))]
6589pub fn clear_all_caches() {
6590 clear_script_cache();
6591 clear_hash_cache();
6592}
6593
6594#[cfg(all(feature = "production", feature = "benchmarking"))]
6608pub fn clear_stack_pool() {
6609 STACK_POOL.with(|pool| {
6610 let mut pool = pool.borrow_mut();
6611 pool.clear();
6612 });
6613}
6614
6615#[cfg(all(feature = "production", feature = "benchmarking"))]
6629pub fn reset_benchmarking_state() {
6630 clear_all_caches();
6631 clear_stack_pool();
6632 disable_caching(false); #[cfg(feature = "benchmarking")]
6635 crate::transaction_hash::clear_sighash_templates();
6636}
6637
6638#[cfg(test)]
6639mod tests {
6640 use super::*;
6641
6642 #[test]
6643 fn test_eval_script_simple() {
6644 let script = vec![OP_1]; let mut stack = Vec::new();
6646
6647 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6648 assert_eq!(stack.len(), 1);
6649 assert_eq!(stack[0].as_ref(), &[1]);
6650 }
6651
6652 #[test]
6653 fn test_eval_script_overflow() {
6654 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6656
6657 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6658 }
6659
6660 #[test]
6661 fn test_verify_script_simple() {
6662 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());
6673 }
6674
6675 #[test]
6680 fn test_op_0() {
6681 let script = vec![OP_0]; let mut stack = Vec::new();
6683 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6684 assert!(result); assert_eq!(stack.len(), 1);
6686 assert!(stack[0].is_empty());
6687 }
6688
6689 #[test]
6690 fn test_op_1_to_op_16() {
6691 for i in 1..=16 {
6693 let opcode = 0x50 + i;
6694 let script = vec![opcode];
6695 let mut stack = Vec::new();
6696 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6697 assert!(result);
6698 assert_eq!(stack.len(), 1);
6699 assert_eq!(stack[0].as_ref(), &[i]);
6700 }
6701 }
6702
6703 #[test]
6704 fn test_op_dup() {
6705 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6707 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6708 assert!(result); assert_eq!(stack.len(), 2);
6710 assert_eq!(stack[0].as_ref(), &[1]);
6711 assert_eq!(stack[1].as_ref(), &[1]);
6712 }
6713
6714 #[test]
6715 fn test_op_dup_empty_stack() {
6716 let script = vec![OP_DUP]; let mut stack = Vec::new();
6718 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6719 assert!(!result);
6720 }
6721
6722 #[test]
6723 fn test_op_hash160() {
6724 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6726 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6727 assert!(result);
6728 assert_eq!(stack.len(), 1);
6729 assert_eq!(stack[0].len(), 20); }
6731
6732 #[test]
6733 fn test_op_hash160_empty_stack() {
6734 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6736 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6737 assert!(!result);
6738 }
6739
6740 #[test]
6741 fn test_op_hash256() {
6742 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6744 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6745 assert!(result);
6746 assert_eq!(stack.len(), 1);
6747 assert_eq!(stack[0].len(), 32); }
6749
6750 #[test]
6751 fn test_op_hash256_empty_stack() {
6752 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6754 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6755 assert!(!result);
6756 }
6757
6758 #[test]
6759 fn test_op_equal() {
6760 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6762 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6763 assert!(result);
6764 assert_eq!(stack.len(), 1);
6765 assert_eq!(stack[0].as_ref(), &[1]); }
6767
6768 #[test]
6769 fn test_op_equal_false() {
6770 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6772 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6773 assert!(result); assert_eq!(stack.len(), 1);
6775 assert!(stack[0].is_empty()); }
6777
6778 #[test]
6779 fn test_op_equal_insufficient_stack() {
6780 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6782 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6783 assert!(
6784 result.is_err(),
6785 "OP_EQUAL with insufficient stack should return error"
6786 );
6787 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6788 assert_eq!(
6789 code,
6790 crate::error::ScriptErrorCode::InvalidStackOperation,
6791 "Should return InvalidStackOperation"
6792 );
6793 }
6794 }
6795
6796 #[test]
6797 fn test_op_verify() {
6798 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6800 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6801 assert!(result); assert_eq!(stack.len(), 0); }
6804
6805 #[test]
6806 fn test_op_verify_false() {
6807 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6809 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6810 assert!(!result);
6811 }
6812
6813 #[test]
6814 fn test_op_verify_empty_stack() {
6815 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6817 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6818 assert!(!result);
6819 }
6820
6821 #[test]
6822 fn test_op_equalverify() {
6823 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6825 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6826 assert!(result); assert_eq!(stack.len(), 0); }
6829
6830 #[test]
6831 fn test_op_equalverify_false() {
6832 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6834 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6835 assert!(
6836 result.is_err(),
6837 "OP_EQUALVERIFY with false condition should return error"
6838 );
6839 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6840 assert_eq!(
6841 code,
6842 crate::error::ScriptErrorCode::EqualVerify,
6843 "Should return EqualVerify"
6844 );
6845 }
6846 }
6847
6848 #[test]
6849 fn test_op_checksig() {
6850 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6854 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6855 assert!(result); assert_eq!(stack.len(), 1);
6857 }
6859
6860 #[test]
6861 fn test_op_checksig_insufficient_stack() {
6862 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6864 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6865 assert!(
6866 result.is_err(),
6867 "OP_CHECKSIG with insufficient stack should return error"
6868 );
6869 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6870 assert_eq!(
6871 code,
6872 crate::error::ScriptErrorCode::InvalidStackOperation,
6873 "Should return InvalidStackOperation"
6874 );
6875 }
6876 }
6877
6878 #[test]
6879 fn test_unknown_opcode() {
6880 let script = vec![0xff]; let mut stack = Vec::new();
6882 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6883 assert!(!result);
6884 }
6885
6886 #[test]
6887 fn test_script_size_limit() {
6888 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6890 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6891 assert!(result.is_err());
6892 }
6893
6894 #[test]
6895 fn test_operation_count_limit() {
6896 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6899 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6900 assert!(result.is_err());
6901 }
6902
6903 #[test]
6904 fn test_stack_underflow_multiple_ops() {
6905 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6907 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6908 assert!(result.is_err(), "Stack underflow should return error");
6909 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6910 assert_eq!(
6911 code,
6912 crate::error::ScriptErrorCode::InvalidStackOperation,
6913 "Should return InvalidStackOperation"
6914 );
6915 }
6916 }
6917
6918 #[test]
6919 fn test_final_stack_empty() {
6920 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6923 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6924 assert!(result); assert_eq!(stack.len(), 2);
6926 }
6927
6928 #[test]
6929 fn test_final_stack_false() {
6930 let script = vec![OP_0]; let mut stack = Vec::new();
6933 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6934 assert!(result); }
6936
6937 #[test]
6938 fn test_verify_script_with_witness() {
6939 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6944
6945 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6946 assert!(result); }
6948
6949 #[test]
6950 fn test_verify_script_failure() {
6951 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_0]; let witness = None;
6955 let flags = 0;
6956
6957 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6958 assert!(!result); }
6960
6961 #[test]
6966 fn test_op_ifdup_true() {
6967 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6969 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6970 assert!(result); assert_eq!(stack.len(), 2);
6972 assert_eq!(stack[0].as_ref(), &[1]);
6973 assert_eq!(stack[1].as_ref(), &[1]);
6974 }
6975
6976 #[test]
6977 fn test_op_ifdup_false() {
6978 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6980 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6981 assert!(result); assert_eq!(stack.len(), 1);
6983 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6984 }
6985
6986 #[test]
6987 fn test_op_depth() {
6988 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6990 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6991 assert!(result); assert_eq!(stack.len(), 3);
6993 assert_eq!(stack[2].as_ref(), &[2]); }
6995
6996 #[test]
6997 fn test_op_drop() {
6998 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
7000 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7001 assert!(result); assert_eq!(stack.len(), 1);
7003 assert_eq!(stack[0].as_ref(), &[1]);
7004 }
7005
7006 #[test]
7007 fn test_op_drop_empty_stack() {
7008 let script = vec![OP_DROP]; let mut stack = Vec::new();
7010 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7011 assert!(!result);
7012 assert_eq!(stack.len(), 0);
7013 }
7014
7015 #[test]
7016 fn test_op_nip() {
7017 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
7019 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7020 assert!(result); assert_eq!(stack.len(), 1);
7022 assert_eq!(stack[0].as_ref(), &[2]);
7023 }
7024
7025 #[test]
7026 fn test_op_nip_insufficient_stack() {
7027 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
7029 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7030 assert!(!result);
7031 assert_eq!(stack.len(), 1);
7032 }
7033
7034 #[test]
7035 fn test_op_over() {
7036 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
7038 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7039 assert!(result); assert_eq!(stack.len(), 3);
7041 assert_eq!(stack[0].as_ref(), &[1]);
7042 assert_eq!(stack[1].as_ref(), &[2]);
7043 assert_eq!(stack[2].as_ref(), &[1]);
7044 }
7045
7046 #[test]
7047 fn test_op_over_insufficient_stack() {
7048 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
7050 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7051 assert!(!result);
7052 assert_eq!(stack.len(), 1);
7053 }
7054
7055 #[test]
7056 fn test_op_pick() {
7057 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
7059 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7060 assert!(result); assert_eq!(stack.len(), 4);
7062 assert_eq!(stack[3].as_ref(), &[2]); }
7064
7065 #[test]
7066 fn test_op_pick_empty_n() {
7067 let script = vec![OP_1, OP_0, OP_PICK];
7069 let mut stack = Vec::new();
7070 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7071 assert!(result); assert_eq!(stack.len(), 2);
7073 assert_eq!(stack[1].as_ref(), &[1]); }
7075
7076 #[test]
7077 fn test_op_pick_invalid_index() {
7078 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
7080 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7081 assert!(!result);
7082 assert_eq!(stack.len(), 1);
7083 }
7084
7085 #[test]
7086 fn test_op_roll() {
7087 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
7089 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7090 assert!(result); assert_eq!(stack.len(), 3);
7092 assert_eq!(stack[0].as_ref(), &[1]);
7093 assert_eq!(stack[1].as_ref(), &[3]);
7094 assert_eq!(stack[2].as_ref(), &[2]); }
7096
7097 #[test]
7098 fn test_op_roll_zero_n() {
7099 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
7102 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7103 assert!(result); assert_eq!(stack.len(), 1);
7105 assert_eq!(stack[0].as_ref(), &[1]);
7106 }
7107
7108 #[test]
7109 fn test_op_roll_invalid_index() {
7110 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
7112 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7113 assert!(!result);
7114 assert_eq!(stack.len(), 1);
7115 }
7116
7117 #[test]
7118 fn test_op_rot() {
7119 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
7121 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7122 assert!(result); assert_eq!(stack.len(), 3);
7124 assert_eq!(stack[0].as_ref(), &[2]);
7125 assert_eq!(stack[1].as_ref(), &[3]);
7126 assert_eq!(stack[2].as_ref(), &[1]);
7127 }
7128
7129 #[test]
7130 fn test_op_rot_insufficient_stack() {
7131 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
7133 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7134 assert!(!result);
7135 assert_eq!(stack.len(), 2);
7136 }
7137
7138 #[test]
7139 fn test_op_swap() {
7140 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
7142 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7143 assert!(result); assert_eq!(stack.len(), 2);
7145 assert_eq!(stack[0].as_ref(), &[2]);
7146 assert_eq!(stack[1].as_ref(), &[1]);
7147 }
7148
7149 #[test]
7150 fn test_op_swap_insufficient_stack() {
7151 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
7153 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7154 assert!(!result);
7155 assert_eq!(stack.len(), 1);
7156 }
7157
7158 #[test]
7159 fn test_op_tuck() {
7160 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
7162 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7163 assert!(result); assert_eq!(stack.len(), 3);
7165 assert_eq!(stack[0].as_ref(), &[2]);
7166 assert_eq!(stack[1].as_ref(), &[1]);
7167 assert_eq!(stack[2].as_ref(), &[2]);
7168 }
7169
7170 #[test]
7171 fn test_op_tuck_insufficient_stack() {
7172 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
7174 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7175 assert!(!result);
7176 assert_eq!(stack.len(), 1);
7177 }
7178
7179 #[test]
7180 fn test_op_2drop() {
7181 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
7183 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7184 assert!(result); assert_eq!(stack.len(), 1);
7186 assert_eq!(stack[0].as_ref(), &[1]);
7187 }
7188
7189 #[test]
7190 fn test_op_2drop_insufficient_stack() {
7191 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
7193 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7194 assert!(!result);
7195 assert_eq!(stack.len(), 1);
7196 }
7197
7198 #[test]
7199 fn test_op_2dup() {
7200 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
7202 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7203 assert!(result); assert_eq!(stack.len(), 4);
7205 assert_eq!(stack[0].as_ref(), &[1]);
7206 assert_eq!(stack[1].as_ref(), &[2]);
7207 assert_eq!(stack[2].as_ref(), &[1]);
7208 assert_eq!(stack[3].as_ref(), &[2]);
7209 }
7210
7211 #[test]
7212 fn test_op_2dup_insufficient_stack() {
7213 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
7215 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7216 assert!(!result);
7217 assert_eq!(stack.len(), 1);
7218 }
7219
7220 #[test]
7221 fn test_op_3dup() {
7222 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
7224 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7225 assert!(result); assert_eq!(stack.len(), 6);
7227 assert_eq!(stack[0].as_ref(), &[1]);
7228 assert_eq!(stack[1].as_ref(), &[2]);
7229 assert_eq!(stack[2].as_ref(), &[3]);
7230 assert_eq!(stack[3].as_ref(), &[1]);
7231 assert_eq!(stack[4].as_ref(), &[2]);
7232 assert_eq!(stack[5].as_ref(), &[3]);
7233 }
7234
7235 #[test]
7236 fn test_op_3dup_insufficient_stack() {
7237 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
7239 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7240 assert!(!result);
7241 assert_eq!(stack.len(), 2);
7242 }
7243
7244 #[test]
7245 fn test_op_2over() {
7246 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
7248 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7249 assert!(result); assert_eq!(stack.len(), 6);
7251 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
7253 }
7254
7255 #[test]
7256 fn test_op_2over_insufficient_stack() {
7257 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
7259 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7260 assert!(!result);
7261 assert_eq!(stack.len(), 3);
7262 }
7263
7264 #[test]
7265 fn test_op_2rot() {
7266 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
7271 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7272 assert!(result); assert_eq!(stack.len(), 6);
7274 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]); }
7277
7278 #[test]
7279 fn test_op_2rot_insufficient_stack() {
7280 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
7282 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7283 assert!(!result);
7284 assert_eq!(stack.len(), 4);
7285 }
7286
7287 #[test]
7288 fn test_op_2swap() {
7289 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
7291 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7292 assert!(result); assert_eq!(stack.len(), 4);
7294 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
7296 assert_eq!(stack[2].as_ref(), &[1]);
7297 assert_eq!(stack[3].as_ref(), &[2]);
7298 }
7299
7300 #[test]
7301 fn test_op_2swap_insufficient_stack() {
7302 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
7304 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7305 assert!(!result);
7306 assert_eq!(stack.len(), 3);
7307 }
7308
7309 #[test]
7310 fn test_op_size() {
7311 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
7313 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7314 assert!(result); assert_eq!(stack.len(), 2);
7316 assert_eq!(stack[0].as_ref(), &[1]);
7317 assert_eq!(stack[1].as_ref(), &[1]); }
7319
7320 #[test]
7321 fn test_op_size_empty_stack() {
7322 let script = vec![OP_SIZE]; let mut stack = Vec::new();
7324 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7325 assert!(!result);
7326 assert_eq!(stack.len(), 0);
7327 }
7328
7329 #[test]
7330 fn test_op_return() {
7331 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
7333 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7334 assert!(!result); assert_eq!(stack.len(), 1);
7336 }
7337
7338 #[test]
7339 fn test_op_checksigverify() {
7340 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7342 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7343 assert!(!result); assert_eq!(stack.len(), 0);
7345 }
7346
7347 #[test]
7348 fn test_op_checksigverify_insufficient_stack() {
7349 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7351 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7352 assert!(!result);
7353 assert_eq!(stack.len(), 1);
7354 }
7355
7356 #[test]
7357 fn test_unknown_opcode_comprehensive() {
7358 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
7360 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7361 assert!(!result); assert_eq!(stack.len(), 1);
7363 }
7364
7365 #[test]
7366 fn test_verify_signature_invalid_pubkey() {
7367 let secp = signature::new_secp();
7368 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
7371 let result = signature::verify_signature(
7372 &secp,
7373 &invalid_pubkey,
7374 &signature,
7375 &dummy_hash,
7376 0,
7377 0,
7378 crate::types::Network::Regtest,
7379 SigVersion::Base,
7380 );
7381 assert!(!result.unwrap_or(false));
7382 }
7383
7384 #[test]
7385 fn test_verify_signature_invalid_signature() {
7386 let secp = signature::new_secp();
7387 let pubkey = vec![
7388 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
7389 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
7390 0x5b, 0x16, 0xf8, 0x17, 0x98,
7391 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
7394 let result = signature::verify_signature(
7395 &secp,
7396 &pubkey,
7397 &invalid_signature,
7398 &dummy_hash,
7399 0,
7400 0,
7401 crate::types::Network::Regtest,
7402 SigVersion::Base,
7403 );
7404 assert!(!result.unwrap_or(false));
7405 }
7406
7407 fn minimal_tx_and_prevouts(
7413 script_sig: &[u8],
7414 script_pubkey: &[u8],
7415 ) -> (
7416 crate::types::Transaction,
7417 Vec<i64>,
7418 Vec<crate::types::ByteString>,
7419 ) {
7420 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
7421 let tx = Transaction {
7422 version: 1,
7423 inputs: vec![TransactionInput {
7424 prevout: OutPoint {
7425 hash: [0u8; 32],
7426 index: 0,
7427 },
7428 sequence: 0xffff_ffff,
7429 script_sig: script_sig.to_vec(),
7430 }]
7431 .into(),
7432 outputs: vec![TransactionOutput {
7433 value: 0,
7434 script_pubkey: script_pubkey.to_vec(),
7435 }]
7436 .into(),
7437 lock_time: 0,
7438 };
7439 let prevout_values = vec![0i64];
7440 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
7441 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
7442 (tx, prevout_values, prevout_script_pubkeys_vec)
7443 }
7444
7445 #[test]
7446 fn test_verify_with_context_p2pkh_hash_mismatch() {
7447 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
7451 script_sig.push(sig.len() as u8);
7452 script_sig.extend(&sig);
7453 script_sig.push(pubkey.len() as u8);
7454 script_sig.extend(&pubkey);
7455
7456 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
7457 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
7459 script_pubkey.push(OP_CHECKSIG);
7460
7461 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7462 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7463 let result = verify_script_with_context_full(
7464 &script_sig,
7465 &script_pubkey,
7466 None,
7467 0,
7468 &tx,
7469 0,
7470 &pv,
7471 &psp_refs,
7472 Some(500_000),
7473 None,
7474 crate::types::Network::Mainnet,
7475 SigVersion::Base,
7476 #[cfg(feature = "production")]
7477 None,
7478 None, #[cfg(feature = "production")]
7480 None,
7481 #[cfg(feature = "production")]
7482 None,
7483 #[cfg(feature = "production")]
7484 None,
7485 );
7486 assert!(result.is_ok());
7487 assert!(!result.unwrap());
7488 }
7489
7490 #[test]
7491 fn test_verify_with_context_p2sh_hash_mismatch() {
7492 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7495 script_sig.push(redeem.len() as u8);
7496 script_sig.extend(&redeem);
7497
7498 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7499 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7501
7502 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7503 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7504 let result = verify_script_with_context_full(
7505 &script_sig,
7506 &script_pubkey,
7507 None,
7508 0x01, &tx,
7510 0,
7511 &pv,
7512 &psp_refs,
7513 Some(500_000),
7514 None,
7515 crate::types::Network::Mainnet,
7516 SigVersion::Base,
7517 #[cfg(feature = "production")]
7518 None,
7519 None, #[cfg(feature = "production")]
7521 None,
7522 #[cfg(feature = "production")]
7523 None,
7524 #[cfg(feature = "production")]
7525 None,
7526 );
7527 assert!(result.is_ok());
7528 assert!(!result.unwrap());
7529 }
7530
7531 #[test]
7532 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7533 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7535 script_pubkey.extend(&[0u8; 20]);
7536 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7538 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7539 let empty: Vec<u8> = vec![];
7540 let result = verify_script_with_context_full(
7541 &empty,
7542 &script_pubkey,
7543 Some(&witness),
7544 0,
7545 &tx,
7546 0,
7547 &pv,
7548 &psp_refs,
7549 Some(500_000),
7550 None,
7551 crate::types::Network::Mainnet,
7552 SigVersion::Base,
7553 #[cfg(feature = "production")]
7554 None,
7555 None, #[cfg(feature = "production")]
7557 None,
7558 #[cfg(feature = "production")]
7559 None,
7560 #[cfg(feature = "production")]
7561 None,
7562 );
7563 assert!(result.is_ok());
7564 assert!(!result.unwrap());
7565 }
7566
7567 #[test]
7568 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7569 let witness_script = vec![OP_1];
7571 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7572 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7574 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7575 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7576 let empty: Vec<u8> = vec![];
7577 let result = verify_script_with_context_full(
7578 &empty,
7579 &script_pubkey,
7580 Some(&witness),
7581 0,
7582 &tx,
7583 0,
7584 &pv,
7585 &psp_refs,
7586 Some(500_000),
7587 None,
7588 crate::types::Network::Mainnet,
7589 SigVersion::Base,
7590 #[cfg(feature = "production")]
7591 None,
7592 None, #[cfg(feature = "production")]
7594 None,
7595 #[cfg(feature = "production")]
7596 None,
7597 #[cfg(feature = "production")]
7598 None,
7599 );
7600 assert!(result.is_ok());
7601 assert!(!result.unwrap());
7602 }
7603
7604 #[test]
7605 #[cfg(feature = "production")]
7606 fn test_p2wsh_multisig_fast_path() {
7607 use crate::constants::BIP147_ACTIVATION_MAINNET;
7609 use crate::crypto::OptimizedSha256;
7610
7611 let pk1 = [0x02u8; 33];
7612 let pk2 = [0x03u8; 33];
7613 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7615 witness_script.extend_from_slice(&pk2);
7616 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7620 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7621 script_pubkey.extend_from_slice(&wsh_hash);
7622
7623 let witness: Vec<Vec<u8>> = vec![
7624 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7628 ];
7629
7630 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7631 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7632 let empty: Vec<u8> = vec![];
7633 let result = verify_script_with_context_full(
7634 &empty,
7635 &script_pubkey,
7636 Some(&witness),
7637 0x810, &tx,
7639 0,
7640 &pv,
7641 &psp_refs,
7642 Some(BIP147_ACTIVATION_MAINNET + 1),
7643 None,
7644 crate::types::Network::Mainnet,
7645 SigVersion::Base,
7646 #[cfg(feature = "production")]
7647 None,
7648 None, #[cfg(feature = "production")]
7650 None,
7651 #[cfg(feature = "production")]
7652 None,
7653 #[cfg(feature = "production")]
7654 None,
7655 );
7656 assert!(result.is_ok());
7657 assert!(!result.unwrap());
7658 }
7659}
7660
7661#[cfg(test)]
7662#[allow(unused_doc_comments)]
7663mod property_tests {
7664 use super::*;
7665 use proptest::prelude::*;
7666
7667 proptest! {
7672 #[test]
7673 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7674 let mut stack = Vec::new();
7675 let flags = 0u32;
7676
7677 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7678
7679 if script.len() > MAX_SCRIPT_OPS * 2 {
7687 prop_assert!(result.is_err() || !result.unwrap(),
7690 "Very long scripts should fail or return false");
7691 }
7692 }
7694 }
7695
7696 proptest! {
7701 #[test]
7702 fn prop_verify_script_deterministic(
7703 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7704 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7705 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7706 flags in any::<u32>()
7707 ) {
7708 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7709 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7710
7711 assert_eq!(result1.is_ok(), result2.is_ok());
7712 if result1.is_ok() && result2.is_ok() {
7713 assert_eq!(result1.unwrap(), result2.unwrap());
7714 }
7715 }
7716 }
7717
7718 proptest! {
7723 #[test]
7724 fn prop_execute_opcode_no_panic(
7725 opcode in any::<u8>(),
7726 stack_items in prop::collection::vec(
7727 prop::collection::vec(any::<u8>(), 0..5),
7728 0..10
7729 ),
7730 flags in any::<u32>()
7731 ) {
7732 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7733 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7734
7735 match result {
7738 Ok(success) => {
7739 let _ = success;
7741 },
7742 Err(_) => {
7743 }
7746 }
7747
7748 assert!(stack.len() <= MAX_STACK_SIZE);
7750 }
7751 }
7752
7753 proptest! {
7760 #[test]
7761 fn prop_stack_operations_bounds(
7762 opcode in any::<u8>(),
7763 stack_items in prop::collection::vec(
7764 prop::collection::vec(any::<u8>(), 0..3),
7765 0..5
7766 ),
7767 flags in any::<u32>()
7768 ) {
7769 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7770 let initial_len = stack.len();
7771
7772 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7773
7774 assert!(stack.len() <= MAX_STACK_SIZE);
7776
7777 if result.is_ok() && result.unwrap() {
7779 match opcode {
7781 OP_0 | OP_1..=OP_16 => {
7782 assert!(stack.len() == initial_len + 1);
7784 },
7785 OP_DUP => {
7786 if initial_len > 0 {
7788 assert!(stack.len() == initial_len + 1);
7789 }
7790 },
7791 OP_3DUP => {
7792 if initial_len >= 3 {
7794 assert!(stack.len() == initial_len + 3);
7795 }
7796 },
7797 OP_2OVER => {
7798 if initial_len >= 4 {
7800 assert!(stack.len() == initial_len + 2);
7801 }
7802 },
7803 OP_DROP | OP_NIP | OP_2DROP => {
7804 assert!(stack.len() <= initial_len);
7806 },
7807 _ => {
7808 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7811 }
7812 }
7813 }
7814 }
7815 }
7816
7817 proptest! {
7822 #[test]
7823 fn prop_hash_operations_deterministic(
7824 input in prop::collection::vec(any::<u8>(), 0..10)
7825 ) {
7826 let elem = to_stack_element(&input);
7827 let mut stack1 = vec![elem.clone()];
7828 let mut stack2 = vec![elem];
7829
7830 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());
7834 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7835 assert_eq!(val1, val2);
7836 if val1 {
7837 assert_eq!(stack1, stack2);
7838 }
7839 }
7840 }
7841 }
7842
7843 proptest! {
7848 #[test]
7849 fn prop_equality_operations_symmetric(
7850 a in prop::collection::vec(any::<u8>(), 0..5),
7851 b in prop::collection::vec(any::<u8>(), 0..5)
7852 ) {
7853 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7854 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7855
7856 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());
7860 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7861 assert_eq!(val1, val2);
7862 if val1 {
7863 assert_eq!(stack1.len(), stack2.len());
7865 if !stack1.is_empty() && !stack2.is_empty() {
7866 assert_eq!(stack1[0], stack2[0]);
7867 }
7868 }
7869 }
7870 }
7871 }
7872
7873 proptest! {
7878 #[test]
7879 fn prop_script_execution_terminates(
7880 script in prop::collection::vec(any::<u8>(), 0..50)
7881 ) {
7882 let mut stack = Vec::new();
7883 let flags = 0u32;
7884
7885 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7887
7888 assert!(result.is_ok() || result.is_err());
7890
7891 assert!(stack.len() <= MAX_STACK_SIZE);
7893 }
7894 }
7895}