1#![allow(
5 clippy::declare_interior_mutable_const, clippy::type_complexity,
7 clippy::too_many_arguments,
8 clippy::needless_return, )]
10mod arithmetic;
17mod context;
18mod control_flow;
19mod crypto_ops;
20pub mod flags;
21mod signature;
22mod stack;
23
24pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
25pub use stack::{cast_to_bool, to_stack_element, StackElement};
26
27use crate::constants::*;
28use crate::crypto::OptimizedSha256;
29use crate::error::{ConsensusError, Result, ScriptErrorCode};
30use crate::opcodes::*;
31use crate::types::*;
32use blvm_spec_lock::spec_locked;
33use digest::Digest;
34use ripemd::Ripemd160;
35
36#[cfg(feature = "production")]
38use crate::optimizations::{precomputed_constants, prefetch};
39
40#[cold]
42#[allow(dead_code)]
43fn make_operation_limit_error() -> ConsensusError {
44 ConsensusError::ScriptErrorWithCode {
45 code: ScriptErrorCode::OpCount,
46 message: "Operation limit exceeded".into(),
47 }
48}
49
50#[cold]
51fn make_stack_overflow_error() -> ConsensusError {
52 ConsensusError::ScriptErrorWithCode {
53 code: ScriptErrorCode::StackSize,
54 message: "Stack overflow".into(),
55 }
56}
57
58#[cfg(feature = "production")]
59use std::collections::VecDeque;
60#[cfg(feature = "production")]
61use std::sync::{
62 atomic::{AtomicBool, AtomicU64, Ordering},
63 OnceLock, RwLock,
64};
65#[cfg(feature = "production")]
66use std::thread_local;
67
68#[cfg(feature = "production")]
74static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
75
76#[cfg(feature = "production")]
79const SIG_CACHE_SHARDS: usize = 32;
80
81#[cfg(feature = "production")]
82const SIG_CACHE_SHARD: OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>> = OnceLock::new();
83
84#[cfg(feature = "production")]
85static SIG_CACHE: [OnceLock<RwLock<lru::LruCache<[u8; 32], bool>>>; SIG_CACHE_SHARDS] =
86 [SIG_CACHE_SHARD; SIG_CACHE_SHARDS];
87
88#[cfg(feature = "production")]
90fn sig_cache_size() -> usize {
91 std::env::var("BLVM_SIG_CACHE_ENTRIES")
92 .ok()
93 .and_then(|s| s.parse().ok())
94 .filter(|&n: &usize| n > 0 && n <= 1_000_000)
95 .unwrap_or(500_000)
96}
97
98#[cfg(feature = "production")]
99fn sig_cache_shard_index(key: &[u8; 32]) -> usize {
100 let h = (key[0] as usize) | ((key[1] as usize) << 8) | ((key[2] as usize) << 16);
101 h % SIG_CACHE_SHARDS
102}
103
104#[cfg(feature = "production")]
105fn get_sig_cache_shard(key: &[u8; 32]) -> &'static RwLock<lru::LruCache<[u8; 32], bool>> {
106 let idx = sig_cache_shard_index(key);
107 SIG_CACHE[idx].get_or_init(|| {
108 use lru::LruCache;
109 use std::num::NonZeroUsize;
110 let cap = (sig_cache_size() / SIG_CACHE_SHARDS).max(1);
111 RwLock::new(LruCache::new(NonZeroUsize::new(cap).unwrap()))
112 })
113}
114
115#[cfg(feature = "production")]
116thread_local! {
117 static BATCH_PUT_SIG_CACHE_BY_SHARD: std::cell::RefCell<[Vec<([u8; 32], bool)>; SIG_CACHE_SHARDS]> =
118 std::cell::RefCell::new(std::array::from_fn(|_| Vec::new()));
119}
120
121#[cfg(feature = "production")]
123thread_local! {
124 static SOA_BATCH_BUF: std::cell::RefCell<(
125 Vec<[u8; 64]>,
126 Vec<[u8; 32]>,
127 Vec<[u8; 33]>,
128 Vec<usize>,
129 Vec<[u8; 32]>,
130 )> = const { std::cell::RefCell::new((
131 Vec::new(),
132 Vec::new(),
133 Vec::new(),
134 Vec::new(),
135 Vec::new(),
136 )) };
137}
138
139#[cfg(feature = "production")]
140fn batch_put_sig_cache(keys: &[[u8; 32]], results: &[bool]) {
141 BATCH_PUT_SIG_CACHE_BY_SHARD.with(|cell| {
142 let mut by_shard = cell.borrow_mut();
143 for v in by_shard.iter_mut() {
144 v.clear();
145 }
146 for (i, key) in keys.iter().enumerate() {
147 let result = results.get(i).copied().unwrap_or(false);
148 let idx = sig_cache_shard_index(key);
149 by_shard[idx].push((*key, result));
150 }
151 for shard_entries in by_shard.iter() {
152 if shard_entries.is_empty() {
153 continue;
154 }
155 let first_key = &shard_entries[0].0;
156 if let Ok(mut guard) = get_sig_cache_shard(first_key).write() {
157 for (k, v) in shard_entries.iter() {
158 guard.put(*k, *v);
159 }
160 }
161 }
162 });
163}
164
165#[cfg(feature = "production")]
171fn sig_cache_at_collect_enabled() -> bool {
172 use std::sync::OnceLock;
173 static CACHE: OnceLock<bool> = OnceLock::new();
174 *CACHE.get_or_init(|| {
175 std::env::var("BLVM_SIG_CACHE_AT_COLLECT")
176 .map(|s| s == "1" || s.eq_ignore_ascii_case("true"))
177 .unwrap_or(false)
178 })
179}
180
181#[cfg(feature = "production")]
184#[inline(always)]
185fn ecdsa_cache_key(msg: &[u8; 32], pk: &[u8; 33], sig_compact: &[u8; 64], flags: u32) -> [u8; 32] {
186 use siphasher::sip::SipHasher24;
187 use std::hash::{Hash, Hasher};
188 let mut key_input = [0u8; 133];
189 key_input[..32].copy_from_slice(msg);
190 key_input[32..65].copy_from_slice(pk);
191 key_input[65..129].copy_from_slice(sig_compact);
192 key_input[129..133].copy_from_slice(&flags.to_le_bytes());
193 let mut hasher = SipHasher24::new();
194 key_input.hash(&mut hasher);
195 let h = hasher.finish();
196 let mut out = [0u8; 32];
197 out[..8].copy_from_slice(&h.to_le_bytes());
198 out
199}
200
201#[cfg(feature = "production")]
204static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
205#[cfg(feature = "production")]
206static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
207#[cfg(feature = "production")]
208static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
209#[cfg(feature = "production")]
210static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
211#[cfg(feature = "production")]
212static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
213static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
214#[cfg(feature = "production")]
215static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
216#[cfg(feature = "production")]
217static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
218
219#[cfg(feature = "production")]
220fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
221 SCRIPT_CACHE.get_or_init(|| {
222 use lru::LruCache;
226 use std::num::NonZeroUsize;
227 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
228 })
229}
230
231#[cfg(feature = "production")]
236thread_local! {
237 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
238 std::cell::RefCell::new(VecDeque::with_capacity(10));
239}
240
241#[cfg(feature = "production")]
243fn get_pooled_stack() -> Vec<StackElement> {
244 STACK_POOL.with(|pool| {
245 let mut pool = pool.borrow_mut();
246 if let Some(mut stack) = pool.pop_front() {
247 stack.clear();
248 if stack.capacity() < 20 {
249 stack.reserve(20);
250 }
251 stack
252 } else {
253 Vec::with_capacity(20)
254 }
255 })
256}
257
258#[cfg(feature = "production")]
260struct PooledStackGuard(Vec<StackElement>);
261#[cfg(feature = "production")]
262impl Drop for PooledStackGuard {
263 fn drop(&mut self) {
264 return_pooled_stack(std::mem::take(&mut self.0));
265 }
266}
267
268#[cfg(feature = "production")]
270fn return_pooled_stack(mut stack: Vec<StackElement>) {
271 stack.clear();
273
274 STACK_POOL.with(|pool| {
275 let mut pool = pool.borrow_mut();
276 if pool.len() < 10 {
278 pool.push_back(stack);
279 }
280 });
282}
283
284#[cfg(feature = "production")]
289static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
290
291#[cfg(feature = "production")]
307pub fn disable_caching(disabled: bool) {
308 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
309}
310
311#[cfg(feature = "production")]
313fn is_caching_disabled() -> bool {
314 CACHE_DISABLED.load(Ordering::Relaxed)
315}
316
317#[cfg(feature = "production")]
322fn compute_script_cache_key(
323 script_sig: &ByteString,
324 script_pubkey: &[u8],
325 witness: Option<&ByteString>,
326 flags: u32,
327) -> u64 {
328 use std::collections::hash_map::DefaultHasher;
329 use std::hash::{Hash, Hasher};
330
331 let mut hasher = DefaultHasher::new();
332 script_sig.hash(&mut hasher);
333 script_pubkey.hash(&mut hasher);
334 if let Some(w) = witness {
335 w.hash(&mut hasher);
336 }
337 flags.hash(&mut hasher);
338 hasher.finish()
339}
340
341#[derive(Debug, Clone, Copy, PartialEq, Eq)]
343pub enum SigVersion {
344 Base,
346 WitnessV0,
348 Tapscript,
350}
351
352#[spec_locked("5.2", "EvalScript")]
369#[cfg_attr(feature = "production", inline(always))]
370#[cfg_attr(not(feature = "production"), inline)]
371pub fn eval_script(
372 script: &[u8],
373 stack: &mut Vec<StackElement>,
374 flags: u32,
375 sigversion: SigVersion,
376) -> Result<bool> {
377 if stack.capacity() < 20 {
380 stack.reserve(20);
381 }
382 #[cfg(feature = "production")]
383 {
384 eval_script_impl(script, stack, flags, sigversion)
385 }
386 #[cfg(not(feature = "production"))]
387 {
388 eval_script_inner(script, stack, flags, sigversion)
389 }
390}
391#[cfg(feature = "production")]
392fn eval_script_impl(
393 script: &[u8],
394 stack: &mut Vec<StackElement>,
395 flags: u32,
396 sigversion: SigVersion,
397) -> Result<bool> {
398 eval_script_inner(script, stack, flags, sigversion)
399}
400
401#[cfg(not(feature = "production"))]
402#[allow(dead_code)]
403fn eval_script_impl(
404 script: &[u8],
405 stack: &mut Vec<StackElement>,
406 flags: u32,
407 sigversion: SigVersion,
408) -> Result<bool> {
409 eval_script_inner(script, stack, flags, sigversion)
410}
411
412#[inline(always)]
414fn is_push_opcode(opcode: u8) -> bool {
415 opcode <= 0x60
416}
417
418#[inline]
421fn is_op_success(opcode: u8) -> bool {
422 matches!(
423 opcode,
424 80 | 98
425 | 126..=129
426 | 131..=134
427 | 137..=138
428 | 141..=142
429 | 149..=153
430 | 187..=254
431 )
432}
433
434#[inline]
437fn op_advance(script: &[u8], pc: usize) -> usize {
438 let opcode = script[pc];
439 match opcode {
440 0x01..=0x4b => 1 + opcode as usize,
442 0x4c => {
444 if pc + 1 < script.len() {
445 2 + script[pc + 1] as usize
446 } else {
447 1
448 }
449 }
450 0x4d => {
452 if pc + 2 < script.len() {
453 3 + u16::from_le_bytes([script[pc + 1], script[pc + 2]]) as usize
454 } else {
455 1
456 }
457 }
458 0x4e => {
460 if pc + 4 < script.len() {
461 5 + u32::from_le_bytes([
462 script[pc + 1],
463 script[pc + 2],
464 script[pc + 3],
465 script[pc + 4],
466 ]) as usize
467 } else {
468 1
469 }
470 }
471 _ => 1,
472 }
473}
474
475fn eval_script_inner(
476 script: &[u8],
477 stack: &mut Vec<StackElement>,
478 flags: u32,
479 sigversion: SigVersion,
480) -> Result<bool> {
481 use crate::constants::MAX_SCRIPT_SIZE;
482 use crate::error::{ConsensusError, ScriptErrorCode};
483
484 if script.len() > MAX_SCRIPT_SIZE {
485 return Err(ConsensusError::ScriptErrorWithCode {
486 code: ScriptErrorCode::ScriptSize,
487 message: "Script size exceeds maximum".into(),
488 });
489 }
490
491 let mut op_count = 0;
492 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
493 let mut altstack: Vec<StackElement> = Vec::new();
494
495 let mut i = 0;
496 while i < script.len() {
497 let opcode = script[i];
498 let in_false_branch = control_flow::in_false_branch(&control_stack);
499
500 if !is_push_opcode(opcode) {
502 op_count += 1;
503 if op_count > MAX_SCRIPT_OPS {
504 return Err(make_operation_limit_error());
505 }
506 debug_assert!(
507 op_count <= MAX_SCRIPT_OPS,
508 "Operation count ({op_count}) must not exceed MAX_SCRIPT_OPS ({MAX_SCRIPT_OPS})"
509 );
510 }
511
512 if stack.len() + altstack.len() > MAX_STACK_SIZE {
515 return Err(make_stack_overflow_error());
516 }
517
518 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
520 let (data, advance) = if opcode <= 0x4b {
521 let len = opcode as usize;
522 if i + 1 + len > script.len() {
523 return Ok(false);
524 }
525 (&script[i + 1..i + 1 + len], 1 + len)
526 } else if opcode == OP_PUSHDATA1 {
527 if i + 1 >= script.len() {
528 return Ok(false);
529 }
530 let len = script[i + 1] as usize;
531 if i + 2 + len > script.len() {
532 return Ok(false);
533 }
534 (&script[i + 2..i + 2 + len], 2 + len)
535 } else if opcode == OP_PUSHDATA2 {
536 if i + 2 >= script.len() {
537 return Ok(false);
538 }
539 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
540 if i + 3 + len > script.len() {
541 return Ok(false);
542 }
543 (&script[i + 3..i + 3 + len], 3 + len)
544 } else {
545 if i + 4 >= script.len() {
546 return Ok(false);
547 }
548 let len = u32::from_le_bytes([
549 script[i + 1],
550 script[i + 2],
551 script[i + 3],
552 script[i + 4],
553 ]) as usize;
554 let data_start = i.saturating_add(5);
555 let data_end = data_start.saturating_add(len);
556 let advance = 5usize.saturating_add(len);
557 if advance < 5 || data_end > script.len() || data_end < data_start {
558 return Ok(false);
559 }
560 (&script[data_start..data_end], advance)
561 };
562
563 if !in_false_branch {
564 stack.push(to_stack_element(data));
565 }
566 i += advance;
567 continue;
568 }
569
570 match opcode {
571 OP_IF => {
573 if in_false_branch {
574 control_stack.push(control_flow::ControlBlock::If { executing: false });
575 } else if stack.is_empty() {
576 return Err(ConsensusError::ScriptErrorWithCode {
577 code: ScriptErrorCode::InvalidStackOperation,
578 message: "OP_IF: empty stack".into(),
579 });
580 } else {
581 let condition_bytes = stack.pop().unwrap();
582 let condition = cast_to_bool(&condition_bytes);
583
584 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
585 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
586 && (sigversion == SigVersion::WitnessV0
587 || sigversion == SigVersion::Tapscript)
588 && !control_flow::is_minimal_if_condition(&condition_bytes)
589 {
590 return Err(ConsensusError::ScriptErrorWithCode {
591 code: ScriptErrorCode::MinimalIf,
592 message: "OP_IF condition must be minimally encoded".into(),
593 });
594 }
595
596 control_stack.push(control_flow::ControlBlock::If {
597 executing: condition,
598 });
599 }
600 }
601 OP_NOTIF => {
603 if in_false_branch {
604 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
605 } else if stack.is_empty() {
606 return Err(ConsensusError::ScriptErrorWithCode {
607 code: ScriptErrorCode::InvalidStackOperation,
608 message: "OP_NOTIF: empty stack".into(),
609 });
610 } else {
611 let condition_bytes = stack.pop().unwrap();
612 let condition = cast_to_bool(&condition_bytes);
613
614 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
615 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
616 && (sigversion == SigVersion::WitnessV0
617 || sigversion == SigVersion::Tapscript)
618 && !control_flow::is_minimal_if_condition(&condition_bytes)
619 {
620 return Err(ConsensusError::ScriptErrorWithCode {
621 code: ScriptErrorCode::MinimalIf,
622 message: "OP_NOTIF condition must be minimally encoded".into(),
623 });
624 }
625
626 control_stack.push(control_flow::ControlBlock::NotIf {
627 executing: !condition,
628 });
629 }
630 }
631 OP_ELSE => {
633 if let Some(block) = control_stack.last_mut() {
634 match block {
635 control_flow::ControlBlock::If { executing }
636 | control_flow::ControlBlock::NotIf { executing } => {
637 *executing = !*executing;
638 }
639 }
640 } else {
641 return Err(ConsensusError::ScriptErrorWithCode {
642 code: ScriptErrorCode::UnbalancedConditional,
643 message: "OP_ELSE without matching IF/NOTIF".into(),
644 });
645 }
646 }
647 OP_ENDIF => {
649 if control_stack.pop().is_none() {
650 return Err(ConsensusError::ScriptErrorWithCode {
651 code: ScriptErrorCode::UnbalancedConditional,
652 message: "OP_ENDIF without matching IF/NOTIF".into(),
653 });
654 }
655 }
656 OP_TOALTSTACK => {
658 if !in_false_branch {
659 if stack.is_empty() {
660 return Err(ConsensusError::ScriptErrorWithCode {
661 code: ScriptErrorCode::InvalidStackOperation,
662 message: "OP_TOALTSTACK: empty stack".into(),
663 });
664 }
665 altstack.push(stack.pop().unwrap());
666 }
667 }
668 OP_FROMALTSTACK => {
670 if !in_false_branch {
671 if altstack.is_empty() {
672 return Err(ConsensusError::ScriptErrorWithCode {
673 code: ScriptErrorCode::InvalidAltstackOperation,
674 message: "OP_FROMALTSTACK: empty altstack".into(),
675 });
676 }
677 stack.push(altstack.pop().unwrap());
678 }
679 }
680 _ => {
681 if in_false_branch {
682 i += 1;
683 continue;
684 }
685
686 if !execute_opcode(opcode, stack, flags, sigversion)? {
687 return Ok(false);
688 }
689
690 if stack.len() + altstack.len() > MAX_STACK_SIZE {
691 return Err(make_stack_overflow_error());
692 }
693 }
694 }
695 i += 1;
696 }
697
698 if !control_stack.is_empty() {
699 return Err(ConsensusError::ScriptErrorWithCode {
700 code: ScriptErrorCode::UnbalancedConditional,
701 message: "Unclosed IF/NOTIF block".into(),
702 });
703 }
704
705 Ok(true)
707}
708
709#[spec_locked("5.2", "VerifyScript")]
719#[cfg_attr(feature = "production", inline(always))]
720#[cfg_attr(not(feature = "production"), inline)]
721pub fn verify_script(
722 script_sig: &ByteString,
723 script_pubkey: &[u8],
724 witness: Option<&ByteString>,
725 flags: u32,
726) -> Result<bool> {
727 let sigversion = SigVersion::Base;
729
730 #[cfg(feature = "production")]
731 {
732 if !is_caching_disabled() {
734 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
735 {
736 let cache = get_script_cache().read().unwrap_or_else(|e| e.into_inner());
737 if let Some(&cached_result) = cache.peek(&cache_key) {
738 return Ok(cached_result);
739 }
740 }
741 }
742
743 let mut stack = get_pooled_stack();
746 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
747 let result = {
748 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
749 if !is_caching_disabled() {
751 let mut cache = get_script_cache()
752 .write()
753 .unwrap_or_else(|e| e.into_inner());
754 cache.put(cache_key, false);
755 }
756 false
757 } else if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
758 if !is_caching_disabled() {
759 let mut cache = get_script_cache()
760 .write()
761 .unwrap_or_else(|e| e.into_inner());
762 cache.put(cache_key, false);
763 }
764 false
765 } else if let Some(w) = witness {
766 if !eval_script(w, &mut stack, flags, sigversion)? {
767 if !is_caching_disabled() {
768 let mut cache = get_script_cache()
769 .write()
770 .unwrap_or_else(|e| e.into_inner());
771 cache.put(cache_key, false);
772 }
773 false
774 } else {
775 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
776 if !is_caching_disabled() {
777 let mut cache = get_script_cache()
778 .write()
779 .unwrap_or_else(|e| e.into_inner());
780 cache.put(cache_key, res);
781 }
782 res
783 }
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 };
795
796 return_pooled_stack(stack);
798
799 Ok(result)
800 }
801
802 #[cfg(not(feature = "production"))]
803 {
804 let mut stack = Vec::with_capacity(20);
806
807 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
809 return Ok(false);
810 }
811
812 if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
814 return Ok(false);
815 }
816
817 if let Some(w) = witness {
819 if !eval_script(w, &mut stack, flags, sigversion)? {
820 return Ok(false);
821 }
822 }
823
824 Ok(!stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]))
826 }
827}
828
829#[spec_locked("5.2", "VerifyScript")]
842#[cfg_attr(feature = "production", inline(always))]
843#[cfg_attr(not(feature = "production"), inline)]
844#[allow(clippy::too_many_arguments)]
845pub fn verify_script_with_context(
846 script_sig: &ByteString,
847 script_pubkey: &[u8],
848 witness: Option<&crate::witness::Witness>,
849 flags: u32,
850 tx: &Transaction,
851 input_index: usize,
852 prevouts: &[TransactionOutput],
853 block_height: Option<u64>,
854 network: crate::types::Network,
855) -> Result<bool> {
856 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
858 let prevout_script_pubkeys: Vec<&[u8]> =
859 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
860
861 verify_script_with_context_full(
862 script_sig,
863 script_pubkey,
864 witness,
865 flags,
866 tx,
867 input_index,
868 &prevout_values,
869 &prevout_script_pubkeys,
870 block_height,
871 None, network,
873 SigVersion::Base, #[cfg(feature = "production")]
875 None, None, #[cfg(feature = "production")]
878 None, #[cfg(feature = "production")]
880 None, #[cfg(feature = "production")]
882 None, )
884}
885
886#[cfg(feature = "production")]
893#[allow(clippy::too_many_arguments)]
894pub fn try_verify_p2pk_fast_path(
895 script_sig: &ByteString,
896 script_pubkey: &[u8],
897 flags: u32,
898 tx: &Transaction,
899 input_index: usize,
900 prevout_values: &[i64],
901 prevout_script_pubkeys: &[&[u8]],
902 block_height: Option<u64>,
903 network: crate::types::Network,
904 #[cfg(feature = "production")] sighash_cache: Option<
905 &crate::transaction_hash::SighashMidstateCache,
906 >,
907) -> Option<Result<bool>> {
908 let len = script_pubkey.len();
911 if len != 35 && len != 67 {
912 return None;
913 }
914 if script_pubkey[len - 1] != OP_CHECKSIG {
915 return None;
916 }
917 let pubkey_len = len - 2; if pubkey_len != 33 && pubkey_len != 65 {
919 return None;
920 }
921 if script_pubkey[0] != 0x21 && script_pubkey[0] != 0x41 {
922 return None; }
924 let pubkey_bytes = &script_pubkey[1..(len - 1)];
925
926 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
927 if signature_bytes.is_empty() {
928 return Some(Ok(false));
929 }
930
931 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
933 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
934 let sighash_type = SighashType::from_byte(sighash_byte);
935 let deleted_storage;
936 let script_code: &[u8] = if script_pubkey.len() < 71 {
937 script_pubkey
938 } else {
939 let pattern = serialize_push_data(signature_bytes);
940 deleted_storage = find_and_delete(script_pubkey, &pattern);
941 deleted_storage.as_ref()
942 };
943 let sighash = match calculate_transaction_sighash_single_input(
944 tx,
945 input_index,
946 script_code,
947 prevout_values[input_index],
948 sighash_type,
949 #[cfg(feature = "production")]
950 sighash_cache,
951 ) {
952 Ok(h) => h,
953 Err(e) => return Some(Err(e)),
954 };
955
956 let height = block_height.unwrap_or(0);
957 let is_valid = signature::with_secp_context(|secp| {
958 signature::verify_signature(
959 secp,
960 pubkey_bytes,
961 signature_bytes,
962 &sighash,
963 flags,
964 height,
965 network,
966 SigVersion::Base,
967 )
968 });
969 Some(is_valid)
970}
971
972#[cfg(feature = "production")]
975#[allow(clippy::too_many_arguments)]
976pub fn try_verify_p2pkh_fast_path(
977 script_sig: &ByteString,
978 script_pubkey: &[u8],
979 flags: u32,
980 tx: &Transaction,
981 input_index: usize,
982 prevout_values: &[i64],
983 prevout_script_pubkeys: &[&[u8]],
984 block_height: Option<u64>,
985 network: crate::types::Network,
986 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
987 #[cfg(feature = "production")] sighash_cache: Option<
988 &crate::transaction_hash::SighashMidstateCache,
989 >,
990 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
991) -> Option<Result<bool>> {
992 #[cfg(all(feature = "production", feature = "profile"))]
993 let _t_entry = std::time::Instant::now();
994 if script_pubkey.len() != 25 {
996 return None;
997 }
998 if script_pubkey[0] != OP_DUP
999 || script_pubkey[1] != OP_HASH160
1000 || script_pubkey[2] != PUSH_20_BYTES
1001 || script_pubkey[23] != OP_EQUALVERIFY
1002 || script_pubkey[24] != OP_CHECKSIG
1003 {
1004 return None;
1005 }
1006 let expected_hash = &script_pubkey[3..23];
1007
1008 #[cfg(all(feature = "production", feature = "profile"))]
1009 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
1010 #[cfg(all(feature = "production", feature = "profile"))]
1011 let _t_parse = std::time::Instant::now();
1012 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
1013 #[cfg(all(feature = "production", feature = "profile"))]
1014 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
1015
1016 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1018 return Some(Ok(false));
1019 }
1020 if signature_bytes.is_empty() {
1022 return Some(Ok(false));
1023 }
1024
1025 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
1027 Some(h) => h,
1028 None => {
1029 #[cfg(all(feature = "production", feature = "profile"))]
1030 let _t_hash = std::time::Instant::now();
1031 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1032 let h = Ripemd160::digest(sha256_hash);
1033 #[cfg(all(feature = "production", feature = "profile"))]
1034 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1035 h.into()
1036 }
1037 };
1038 if &pubkey_hash[..] != expected_hash {
1039 return Some(Ok(false));
1040 }
1041
1042 use crate::transaction_hash::SighashType;
1045 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1046 let sighash_type = SighashType::from_byte(sighash_byte);
1047 let deleted_storage;
1048 let script_code: &[u8] = if script_pubkey.len() < 71 {
1049 script_pubkey
1050 } else {
1051 let pattern = serialize_push_data(signature_bytes);
1052 deleted_storage = find_and_delete(script_pubkey, &pattern);
1053 deleted_storage.as_ref()
1054 };
1055 let sighash = {
1056 #[cfg(feature = "production")]
1057 {
1058 if let Some(precomp) = precomputed_sighash_all {
1059 precomp
1060 } else {
1061 crate::transaction_hash::compute_legacy_sighash_nocache(
1062 tx,
1063 input_index,
1064 script_code,
1065 sighash_byte,
1066 )
1067 }
1068 }
1069 #[cfg(not(feature = "production"))]
1070 {
1071 match calculate_transaction_sighash_single_input(
1072 tx,
1073 input_index,
1074 script_code,
1075 prevout_values[input_index],
1076 sighash_type,
1077 ) {
1078 Ok(h) => h,
1079 Err(e) => return Some(Err(e)),
1080 }
1081 }
1082 };
1083
1084 #[cfg(all(feature = "production", feature = "profile"))]
1085 let _t_secp = std::time::Instant::now();
1086 let height = block_height.unwrap_or(0);
1087 let is_valid: Result<bool> = {
1088 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1089 if flags & 0x04 != 0
1090 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1091 .unwrap_or(false)
1092 {
1093 Ok(false)
1094 } else if flags & 0x02 != 0 {
1095 let base_sighash = sighash_byte & !0x80;
1096 if !(0x01..=0x03).contains(&base_sighash) {
1097 Ok(false)
1098 } else if pubkey_bytes.len() == 33 {
1099 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
1100 Ok(false)
1101 } else {
1102 let strict_der = flags & 0x04 != 0;
1103 let enforce_low_s = flags & 0x08 != 0;
1104 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1105 der_sig,
1106 pubkey_bytes,
1107 &sighash,
1108 strict_der,
1109 enforce_low_s,
1110 )
1111 .unwrap_or(false))
1112 }
1113 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1114 let strict_der = flags & 0x04 != 0;
1115 let enforce_low_s = flags & 0x08 != 0;
1116 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1117 der_sig,
1118 pubkey_bytes,
1119 &sighash,
1120 strict_der,
1121 enforce_low_s,
1122 )
1123 .unwrap_or(false))
1124 } else {
1125 Ok(false)
1126 }
1127 } else {
1128 let strict_der = flags & 0x04 != 0;
1129 let enforce_low_s = flags & 0x08 != 0;
1130 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1131 der_sig,
1132 pubkey_bytes,
1133 &sighash,
1134 strict_der,
1135 enforce_low_s,
1136 )
1137 .unwrap_or(false))
1138 }
1139 };
1140 #[cfg(all(feature = "production", feature = "profile"))]
1141 {
1142 let ns = _t_secp.elapsed().as_nanos() as u64;
1143 crate::script_profile::add_p2pkh_collect_ns(ns);
1144 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1145 }
1146 Some(is_valid)
1147}
1148
1149#[cfg(feature = "production")]
1155#[inline]
1156pub fn verify_p2pkh_inline(
1157 script_sig: &[u8],
1158 script_pubkey: &[u8],
1159 flags: u32,
1160 tx: &Transaction,
1161 input_index: usize,
1162 height: u64,
1163 network: crate::types::Network,
1164 precomputed_sighash_all: Option<[u8; 32]>,
1165) -> Result<bool> {
1166 #[cfg(feature = "profile")]
1167 let _t0 = std::time::Instant::now();
1168
1169 let expected_hash = &script_pubkey[3..23];
1170
1171 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1172 Some(pair) => pair,
1173 None => return Ok(false),
1174 };
1175
1176 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1177 return Ok(false);
1178 }
1179
1180 #[cfg(feature = "profile")]
1181 let _t_hash = std::time::Instant::now();
1182
1183 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1184 let pubkey_hash: [u8; 20] = Ripemd160::digest(sha256_hash).into();
1185 if &pubkey_hash[..] != expected_hash {
1186 return Ok(false);
1187 }
1188
1189 #[cfg(feature = "profile")]
1190 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1191
1192 #[cfg(feature = "profile")]
1193 let _t_sighash = std::time::Instant::now();
1194
1195 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1196 let sighash = if let Some(precomp) = precomputed_sighash_all {
1197 precomp
1198 } else {
1199 crate::transaction_hash::compute_legacy_sighash_buffered(
1200 tx,
1201 input_index,
1202 script_pubkey,
1203 sighash_byte,
1204 )
1205 };
1206
1207 #[cfg(feature = "profile")]
1208 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1209
1210 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1211 let strict_der = flags & 0x04 != 0;
1212 let enforce_low_s = flags & 0x08 != 0;
1213
1214 if strict_der
1215 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1216 .unwrap_or(false)
1217 {
1218 return Ok(false);
1219 }
1220
1221 if flags & 0x02 != 0 {
1222 let sighash_base = sighash_byte & !0x80;
1223 if !(0x01..=0x03).contains(&sighash_base) {
1224 return Ok(false);
1225 }
1226 match pubkey_bytes.len() {
1227 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1228 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1229 33 | 65 => {}
1230 _ => return Ok(false),
1231 }
1232 }
1233
1234 #[cfg(feature = "profile")]
1235 let _t_secp = std::time::Instant::now();
1236
1237 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1238 der_sig,
1239 pubkey_bytes,
1240 &sighash,
1241 strict_der,
1242 enforce_low_s,
1243 )
1244 .unwrap_or(false);
1245
1246 #[cfg(feature = "profile")]
1247 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1248
1249 #[cfg(feature = "profile")]
1250 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1251
1252 Ok(result)
1253}
1254
1255#[cfg(feature = "production")]
1257#[inline]
1258pub fn verify_p2pk_inline(
1259 script_sig: &[u8],
1260 script_pubkey: &[u8],
1261 flags: u32,
1262 tx: &Transaction,
1263 input_index: usize,
1264 height: u64,
1265 network: crate::types::Network,
1266) -> Result<bool> {
1267 let pk_len = script_pubkey.len() - 2; let pubkey_bytes = &script_pubkey[1..1 + pk_len];
1269
1270 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1271 Some(s) => s,
1272 None => return Ok(false),
1273 };
1274 if signature_bytes.is_empty() {
1275 return Ok(false);
1276 }
1277
1278 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1279 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_buffered(
1282 tx,
1283 input_index,
1284 script_code,
1285 sighash_byte,
1286 );
1287
1288 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1289 let strict_der = flags & 0x04 != 0;
1290 let enforce_low_s = flags & 0x08 != 0;
1291
1292 if strict_der
1293 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1294 .unwrap_or(false)
1295 {
1296 return Ok(false);
1297 }
1298
1299 if flags & 0x02 != 0 {
1300 let sighash_base = sighash_byte & !0x80;
1301 if !(0x01..=0x03).contains(&sighash_base) {
1302 return Ok(false);
1303 }
1304 match pubkey_bytes.len() {
1305 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1306 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1307 33 | 65 => {}
1308 _ => return Ok(false),
1309 }
1310 }
1311
1312 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1313 der_sig,
1314 pubkey_bytes,
1315 &sighash,
1316 strict_der,
1317 enforce_low_s,
1318 )
1319 .unwrap_or(false))
1320}
1321
1322#[allow(clippy::too_many_arguments)]
1326fn try_verify_p2sh_multisig_fast_path(
1327 script_sig: &ByteString,
1328 script_pubkey: &[u8],
1329 flags: u32,
1330 tx: &Transaction,
1331 input_index: usize,
1332 prevout_values: &[i64],
1333 prevout_script_pubkeys: &[&[u8]],
1334 block_height: Option<u64>,
1335 network: crate::types::Network,
1336 #[cfg(feature = "production")] sighash_cache: Option<
1337 &crate::transaction_hash::SighashMidstateCache,
1338 >,
1339) -> Option<Result<bool>> {
1340 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1341 if pushes.len() < 2 {
1342 return None;
1343 }
1344 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1345 let expected_hash = &script_pubkey[2..22];
1346 let sha256_hash = OptimizedSha256::new().hash(redeem);
1347 let redeem_hash = Ripemd160::digest(sha256_hash);
1348 if &redeem_hash[..] != expected_hash {
1349 return Some(Ok(false));
1350 }
1351 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1352 let signatures: Vec<&[u8]> = pushes
1353 .iter()
1354 .take(pushes.len() - 1)
1355 .skip(1)
1356 .map(|e| e.as_ref())
1357 .collect();
1358 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1359
1360 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1361 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1362 let height = block_height.unwrap_or(0);
1363 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1364 let activation = match network {
1365 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1366 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1367 crate::types::Network::Regtest => 0,
1368 };
1369 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1370 return Some(Ok(false));
1371 }
1372 }
1373
1374 let mut cleaned = redeem.to_vec();
1375 for sig in &signatures {
1376 if !sig.is_empty() {
1377 let pattern = serialize_push_data(sig);
1378 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1379 }
1380 }
1381
1382 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1383
1384 let mut sig_index = 0;
1385 let mut valid_sigs = 0u8;
1386
1387 for pubkey_bytes in pubkeys {
1388 if sig_index >= signatures.len() {
1389 break;
1390 }
1391 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1392 sig_index += 1;
1393 }
1394 if sig_index >= signatures.len() {
1395 break;
1396 }
1397 let signature_bytes = &signatures[sig_index];
1398 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1399 let sighash_type = SighashType::from_byte(sighash_byte);
1400 let sighash = match calculate_transaction_sighash_single_input(
1401 tx,
1402 input_index,
1403 &cleaned,
1404 prevout_values[input_index],
1405 sighash_type,
1406 #[cfg(feature = "production")]
1407 sighash_cache,
1408 ) {
1409 Ok(h) => h,
1410 Err(e) => return Some(Err(e)),
1411 };
1412
1413 #[cfg(feature = "production")]
1414 let is_valid = signature::with_secp_context(|secp| {
1415 signature::verify_signature(
1416 secp,
1417 pubkey_bytes,
1418 signature_bytes,
1419 &sighash,
1420 flags,
1421 height,
1422 network,
1423 SigVersion::Base,
1424 )
1425 });
1426
1427 #[cfg(not(feature = "production"))]
1428 let is_valid = {
1429 let secp = signature::new_secp();
1430 signature::verify_signature(
1431 &secp,
1432 pubkey_bytes,
1433 signature_bytes,
1434 &sighash,
1435 flags,
1436 height,
1437 network,
1438 SigVersion::Base,
1439 )
1440 };
1441
1442 let is_valid = match is_valid {
1443 Ok(v) => v,
1444 Err(e) => return Some(Err(e)),
1445 };
1446
1447 if is_valid {
1448 valid_sigs += 1;
1449 sig_index += 1;
1450 }
1451 }
1452
1453 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1454 for sig_bytes in &signatures[sig_index..] {
1455 if !sig_bytes.is_empty() {
1456 return Some(Err(ConsensusError::ScriptErrorWithCode {
1457 code: ScriptErrorCode::SigNullFail,
1458 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1459 .into(),
1460 }));
1461 }
1462 }
1463 }
1464
1465 Some(Ok(valid_sigs >= m))
1466}
1467
1468#[allow(clippy::too_many_arguments)]
1471fn try_verify_bare_multisig_fast_path(
1472 script_sig: &ByteString,
1473 script_pubkey: &[u8],
1474 flags: u32,
1475 tx: &Transaction,
1476 input_index: usize,
1477 prevout_values: &[i64],
1478 prevout_script_pubkeys: &[&[u8]],
1479 block_height: Option<u64>,
1480 network: crate::types::Network,
1481 #[cfg(feature = "production")] sighash_cache: Option<
1482 &crate::transaction_hash::SighashMidstateCache,
1483 >,
1484) -> Option<Result<bool>> {
1485 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1486 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1487 if pushes.len() < 2 {
1488 return None;
1489 }
1490 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1491 let signatures: Vec<&[u8]> = pushes[1..].iter().map(|e| e.as_ref()).collect();
1492
1493 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1494 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1495 let height = block_height.unwrap_or(0);
1496 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1497 let activation = match network {
1498 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1499 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1500 crate::types::Network::Regtest => 0,
1501 };
1502 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1503 return Some(Ok(false));
1504 }
1505 }
1506
1507 let mut cleaned = script_pubkey.to_vec();
1508 for sig in &signatures {
1509 if !sig.is_empty() {
1510 let pattern = serialize_push_data(sig);
1511 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1512 }
1513 }
1514
1515 use crate::transaction_hash::{calculate_transaction_sighash_single_input, SighashType};
1516
1517 let mut sig_index = 0;
1518 let mut valid_sigs = 0u8;
1519
1520 for pubkey_bytes in pubkeys {
1521 if sig_index >= signatures.len() {
1522 break;
1523 }
1524 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1525 sig_index += 1;
1526 }
1527 if sig_index >= signatures.len() {
1528 break;
1529 }
1530 let signature_bytes = &signatures[sig_index];
1531 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1532 let sighash_type = SighashType::from_byte(sighash_byte);
1533 let sighash = match calculate_transaction_sighash_single_input(
1534 tx,
1535 input_index,
1536 &cleaned,
1537 prevout_values[input_index],
1538 sighash_type,
1539 #[cfg(feature = "production")]
1540 sighash_cache,
1541 ) {
1542 Ok(h) => h,
1543 Err(e) => return Some(Err(e)),
1544 };
1545
1546 #[cfg(feature = "production")]
1547 let is_valid = signature::with_secp_context(|secp| {
1548 signature::verify_signature(
1549 secp,
1550 pubkey_bytes,
1551 signature_bytes,
1552 &sighash,
1553 flags,
1554 height,
1555 network,
1556 SigVersion::Base,
1557 )
1558 });
1559
1560 #[cfg(not(feature = "production"))]
1561 let is_valid = {
1562 let secp = signature::new_secp();
1563 signature::verify_signature(
1564 &secp,
1565 pubkey_bytes,
1566 signature_bytes,
1567 &sighash,
1568 flags,
1569 height,
1570 network,
1571 SigVersion::Base,
1572 )
1573 };
1574
1575 let is_valid = match is_valid {
1576 Ok(v) => v,
1577 Err(e) => return Some(Err(e)),
1578 };
1579
1580 if is_valid {
1581 valid_sigs += 1;
1582 sig_index += 1;
1583 }
1584 }
1585
1586 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1587 for sig_bytes in &signatures[sig_index..] {
1588 if !sig_bytes.is_empty() {
1589 return Some(Err(ConsensusError::ScriptErrorWithCode {
1590 code: ScriptErrorCode::SigNullFail,
1591 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1592 .into(),
1593 }));
1594 }
1595 }
1596 }
1597
1598 Some(Ok(valid_sigs >= m))
1599}
1600
1601#[cfg(feature = "production")]
1605#[allow(clippy::too_many_arguments)]
1606fn try_verify_p2sh_fast_path(
1607 script_sig: &ByteString,
1608 script_pubkey: &[u8],
1609 flags: u32,
1610 tx: &Transaction,
1611 input_index: usize,
1612 prevout_values: &[i64],
1613 prevout_script_pubkeys: &[&[u8]],
1614 block_height: Option<u64>,
1615 median_time_past: Option<u64>,
1616 network: crate::types::Network,
1617 #[cfg(feature = "production")] sighash_cache: Option<
1618 &crate::transaction_hash::SighashMidstateCache,
1619 >,
1620 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1621) -> Option<Result<bool>> {
1622 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1623 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1624 return None;
1625 }
1626 if script_pubkey.len() != 23
1628 || script_pubkey[0] != OP_HASH160
1629 || script_pubkey[1] != PUSH_20_BYTES
1630 || script_pubkey[22] != OP_EQUAL
1631 {
1632 return None;
1633 }
1634 let expected_hash = &script_pubkey[2..22];
1635
1636 let mut pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1637 if pushes.is_empty() {
1638 return None;
1639 }
1640 let redeem = pushes.pop().expect("at least one push");
1641 let mut stack = pushes;
1642
1643 if redeem.len() >= 3
1645 && redeem[0] == OP_0
1646 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
1647 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
1648 {
1649 return None;
1650 }
1651
1652 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1654 let redeem_hash = Ripemd160::digest(sha256_hash);
1655 if &redeem_hash[..] != expected_hash {
1656 return Some(Ok(false));
1657 }
1658
1659 if redeem.len() == 25
1661 && redeem[0] == OP_DUP
1662 && redeem[1] == OP_HASH160
1663 && redeem[2] == PUSH_20_BYTES
1664 && redeem[23] == OP_EQUALVERIFY
1665 && redeem[24] == OP_CHECKSIG
1666 && stack.len() == 2
1667 {
1668 let signature_bytes = &stack[0];
1669 let pubkey_bytes = &stack[1];
1670 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1671 let expected_pubkey_hash = &redeem[3..23];
1672 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1673 let pubkey_hash = Ripemd160::digest(sha256_hash);
1674 if &pubkey_hash[..] == expected_pubkey_hash {
1675 #[cfg(feature = "production")]
1676 let sighash = if let Some(precomp) = precomputed_sighash_all {
1677 precomp
1678 } else {
1679 use crate::transaction_hash::{
1680 calculate_transaction_sighash_single_input, SighashType,
1681 };
1682 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1683 let sighash_type = SighashType::from_byte(sighash_byte);
1684 let deleted_storage;
1685 let script_code: &[u8] = if redeem.len() < 71 {
1686 redeem.as_ref()
1687 } else {
1688 let pattern = serialize_push_data(signature_bytes);
1689 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1690 deleted_storage.as_ref()
1691 };
1692 match calculate_transaction_sighash_single_input(
1693 tx,
1694 input_index,
1695 script_code,
1696 prevout_values[input_index],
1697 sighash_type,
1698 sighash_cache,
1699 ) {
1700 Ok(h) => h,
1701 Err(e) => return Some(Err(e)),
1702 }
1703 };
1704 #[cfg(not(feature = "production"))]
1705 let sighash = {
1706 use crate::transaction_hash::{
1707 calculate_transaction_sighash_single_input, SighashType,
1708 };
1709 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1710 let sighash_type = SighashType::from_byte(sighash_byte);
1711 let deleted_storage;
1712 let script_code: &[u8] = if redeem.len() < 71 {
1713 redeem.as_ref()
1714 } else {
1715 let pattern = serialize_push_data(signature_bytes);
1716 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1717 deleted_storage.as_ref()
1718 };
1719 match calculate_transaction_sighash_single_input(
1720 tx,
1721 input_index,
1722 script_code,
1723 prevout_values[input_index],
1724 sighash_type,
1725 ) {
1726 Ok(h) => h,
1727 Err(e) => return Some(Err(e)),
1728 }
1729 };
1730 let height = block_height.unwrap_or(0);
1731 let is_valid = signature::with_secp_context(|secp| {
1732 signature::verify_signature(
1733 secp,
1734 pubkey_bytes,
1735 signature_bytes,
1736 &sighash,
1737 flags,
1738 height,
1739 network,
1740 SigVersion::Base,
1741 )
1742 });
1743 return Some(is_valid);
1744 }
1745 }
1746 }
1747
1748 if (redeem.len() == 35 || redeem.len() == 67)
1750 && redeem[redeem.len() - 1] == OP_CHECKSIG
1751 && (redeem[0] == 0x21 || redeem[0] == 0x41)
1752 && stack.len() == 1
1753 {
1754 let pubkey_len = redeem.len() - 2;
1755 if pubkey_len == 33 || pubkey_len == 65 {
1756 let pubkey_bytes = &redeem.as_ref()[1..(redeem.len() - 1)];
1757 let signature_bytes = &stack[0];
1758 if !signature_bytes.is_empty() {
1759 use crate::transaction_hash::{
1760 calculate_transaction_sighash_single_input, SighashType,
1761 };
1762 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1763 let sighash_type = SighashType::from_byte(sighash_byte);
1764 let deleted_storage;
1766 let script_code: &[u8] = if redeem.len() < 71 {
1767 redeem.as_ref()
1768 } else {
1769 let pattern = serialize_push_data(signature_bytes);
1770 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1771 deleted_storage.as_ref()
1772 };
1773 match calculate_transaction_sighash_single_input(
1774 tx,
1775 input_index,
1776 script_code,
1777 prevout_values[input_index],
1778 sighash_type,
1779 #[cfg(feature = "production")]
1780 sighash_cache,
1781 ) {
1782 Ok(sighash) => {
1783 let height = block_height.unwrap_or(0);
1784 let is_valid = signature::with_secp_context(|secp| {
1785 signature::verify_signature(
1786 secp,
1787 pubkey_bytes,
1788 signature_bytes,
1789 &sighash,
1790 flags,
1791 height,
1792 network,
1793 SigVersion::Base,
1794 )
1795 });
1796 return Some(is_valid);
1797 }
1798 Err(e) => return Some(Err(e)),
1799 }
1800 }
1801 }
1802 }
1803
1804 let result = eval_script_with_context_full_inner(
1806 &redeem,
1807 &mut stack,
1808 flags,
1809 tx,
1810 input_index,
1811 prevout_values,
1812 prevout_script_pubkeys,
1813 block_height,
1814 median_time_past,
1815 network,
1816 SigVersion::Base,
1817 Some(redeem.as_ref()),
1818 None, #[cfg(feature = "production")]
1820 None, None, #[cfg(feature = "production")]
1823 sighash_cache,
1824 );
1825 Some(result)
1826}
1827
1828#[cfg(feature = "production")]
1831#[allow(clippy::too_many_arguments)]
1832fn try_verify_p2wpkh_fast_path(
1833 script_sig: &ByteString,
1834 script_pubkey: &[u8],
1835 witness: &crate::witness::Witness,
1836 flags: u32,
1837 tx: &Transaction,
1838 input_index: usize,
1839 prevout_values: &[i64],
1840 prevout_script_pubkeys: &[&[u8]],
1841 block_height: Option<u64>,
1842 network: crate::types::Network,
1843 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1844 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1845) -> Option<Result<bool>> {
1846 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
1848 return None;
1849 }
1850 if !script_sig.is_empty() {
1852 return None;
1853 }
1854 if witness.len() != 2 {
1855 return None;
1856 }
1857 let signature_bytes = &witness[0];
1858 let pubkey_bytes = &witness[1];
1859
1860 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1861 return Some(Ok(false));
1862 }
1863 if signature_bytes.is_empty() {
1864 return Some(Ok(false));
1865 }
1866
1867 let expected_hash = &script_pubkey[2..22];
1868 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1869 let pubkey_hash = Ripemd160::digest(sha256_hash);
1870 if &pubkey_hash[..] != expected_hash {
1871 return Some(Ok(false));
1872 }
1873
1874 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1875 let sighash = if sighash_byte == 0x01 {
1876 #[cfg(feature = "production")]
1878 if let Some(precomp) = precomputed_sighash_all {
1879 precomp
1880 } else {
1881 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1882 match crate::transaction_hash::calculate_bip143_sighash(
1883 tx,
1884 input_index,
1885 script_pubkey,
1886 amount,
1887 sighash_byte,
1888 precomputed_bip143,
1889 ) {
1890 Ok(h) => h,
1891 Err(e) => return Some(Err(e)),
1892 }
1893 }
1894 #[cfg(not(feature = "production"))]
1895 {
1896 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1897 match crate::transaction_hash::calculate_bip143_sighash(
1898 tx,
1899 input_index,
1900 script_pubkey,
1901 amount,
1902 sighash_byte,
1903 precomputed_bip143,
1904 ) {
1905 Ok(h) => h,
1906 Err(e) => return Some(Err(e)),
1907 }
1908 }
1909 } else {
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 script_pubkey,
1915 amount,
1916 sighash_byte,
1917 precomputed_bip143,
1918 ) {
1919 Ok(h) => h,
1920 Err(e) => return Some(Err(e)),
1921 }
1922 };
1923
1924 let height = block_height.unwrap_or(0);
1925 let is_valid = signature::with_secp_context(|secp| {
1926 signature::verify_signature(
1927 secp,
1928 pubkey_bytes,
1929 signature_bytes,
1930 &sighash,
1931 flags,
1932 height,
1933 network,
1934 SigVersion::WitnessV0,
1935 )
1936 });
1937 Some(is_valid)
1938}
1939
1940#[cfg(feature = "production")]
1942#[allow(clippy::too_many_arguments)]
1943fn try_verify_p2wpkh_in_p2sh_fast_path(
1944 script_sig: &ByteString,
1945 script_pubkey: &[u8],
1946 witness: &crate::witness::Witness,
1947 flags: u32,
1948 tx: &Transaction,
1949 input_index: usize,
1950 prevout_values: &[i64],
1951 prevout_script_pubkeys: &[&[u8]],
1952 block_height: Option<u64>,
1953 network: crate::types::Network,
1954 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1955) -> Option<Result<bool>> {
1956 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1957 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1958 return None;
1959 }
1960 if script_pubkey.len() != 23
1961 || script_pubkey[0] != OP_HASH160
1962 || script_pubkey[1] != PUSH_20_BYTES
1963 || script_pubkey[22] != OP_EQUAL
1964 {
1965 return None;
1966 }
1967 let expected_hash = &script_pubkey[2..22];
1968
1969 let pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1970 if pushes.len() != 1 {
1971 return None;
1972 }
1973 let redeem = &pushes[0];
1974 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
1975 return None;
1976 }
1977 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1978 let redeem_hash = Ripemd160::digest(sha256_hash);
1979 if &redeem_hash[..] != expected_hash {
1980 return Some(Ok(false));
1981 }
1982
1983 if witness.len() != 2 {
1984 return None;
1985 }
1986 let signature_bytes = &witness[0];
1987 let pubkey_bytes = &witness[1];
1988 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1989 return Some(Ok(false));
1990 }
1991 let expected_pubkey_hash = &redeem[2..22];
1992 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
1993 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
1994 if &pubkey_hash[..] != expected_pubkey_hash {
1995 return Some(Ok(false));
1996 }
1997
1998 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1999 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2000 let sighash = match crate::transaction_hash::calculate_bip143_sighash(
2001 tx,
2002 input_index,
2003 redeem.as_ref(),
2004 amount,
2005 sighash_byte,
2006 precomputed_bip143,
2007 ) {
2008 Ok(h) => h,
2009 Err(e) => return Some(Err(e)),
2010 };
2011
2012 let height = block_height.unwrap_or(0);
2013 let is_valid = signature::with_secp_context(|secp| {
2014 signature::verify_signature(
2015 secp,
2016 pubkey_bytes,
2017 signature_bytes,
2018 &sighash,
2019 flags,
2020 height,
2021 network,
2022 SigVersion::WitnessV0,
2023 )
2024 });
2025 Some(is_valid)
2026}
2027
2028#[cfg(feature = "production")]
2031#[allow(clippy::too_many_arguments)]
2032fn try_verify_p2wsh_fast_path(
2033 script_sig: &ByteString,
2034 script_pubkey: &[u8],
2035 witness: &crate::witness::Witness,
2036 flags: u32,
2037 tx: &Transaction,
2038 input_index: usize,
2039 prevout_values: &[i64],
2040 prevout_script_pubkeys: &[&[u8]],
2041 block_height: Option<u64>,
2042 median_time_past: Option<u64>,
2043 network: crate::types::Network,
2044 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2045 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2046 #[cfg(feature = "production")] sighash_cache: Option<
2047 &crate::transaction_hash::SighashMidstateCache,
2048 >,
2049) -> Option<Result<bool>> {
2050 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
2052 return None;
2053 }
2054 if !script_sig.is_empty() {
2055 return None;
2056 }
2057 if witness.is_empty() {
2058 return None;
2059 }
2060 let witness_script = witness.last().expect("witness not empty").clone();
2061 let mut stack: Vec<StackElement> = witness
2062 .iter()
2063 .take(witness.len() - 1)
2064 .map(|w| to_stack_element(w))
2065 .collect();
2066
2067 let program_hash = &script_pubkey[2..34];
2068 if program_hash.len() != 32 {
2069 return None;
2070 }
2071 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2072 if &witness_script_hash[..] != program_hash {
2073 return Some(Ok(false));
2074 }
2075
2076 let witness_sigversion = SigVersion::WitnessV0;
2080
2081 if witness_sigversion == SigVersion::WitnessV0
2083 && witness_script.len() == 25
2084 && witness_script[0] == OP_DUP
2085 && witness_script[1] == OP_HASH160
2086 && witness_script[2] == PUSH_20_BYTES
2087 && witness_script[23] == OP_EQUALVERIFY
2088 && witness_script[24] == OP_CHECKSIG
2089 && stack.len() == 2
2090 {
2091 let signature_bytes = &stack[0];
2092 let pubkey_bytes = &stack[1];
2093 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2094 let expected_pubkey_hash = &witness_script[3..23];
2095 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2096 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2097 if &pubkey_hash[..] == expected_pubkey_hash {
2098 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2099 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2100 match crate::transaction_hash::calculate_bip143_sighash(
2101 tx,
2102 input_index,
2103 witness_script.as_ref(),
2104 amount,
2105 sighash_byte,
2106 precomputed_bip143,
2107 ) {
2108 Ok(sighash) => {
2109 let height = block_height.unwrap_or(0);
2110 let is_valid = signature::with_secp_context(|secp| {
2111 signature::verify_signature(
2112 secp,
2113 pubkey_bytes,
2114 signature_bytes,
2115 &sighash,
2116 flags,
2117 height,
2118 network,
2119 SigVersion::WitnessV0,
2120 )
2121 });
2122 return Some(is_valid);
2123 }
2124 Err(e) => return Some(Err(e)),
2125 }
2126 }
2127 }
2128 }
2129
2130 if witness_sigversion == SigVersion::WitnessV0
2132 && (witness_script.len() == 35 || witness_script.len() == 67)
2133 && witness_script[witness_script.len() - 1] == OP_CHECKSIG
2134 && (witness_script[0] == 0x21 || witness_script[0] == 0x41)
2135 && stack.len() == 1
2136 {
2137 let pubkey_len = witness_script.len() - 2;
2138 if (pubkey_len == 33 || pubkey_len == 65) && !stack[0].is_empty() {
2139 let pubkey_bytes = &witness_script[1..(witness_script.len() - 1)];
2140 let signature_bytes = &stack[0];
2141 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2142 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2143 match crate::transaction_hash::calculate_bip143_sighash(
2144 tx,
2145 input_index,
2146 witness_script.as_ref(),
2147 amount,
2148 sighash_byte,
2149 precomputed_bip143,
2150 ) {
2151 Ok(sighash) => {
2152 let height = block_height.unwrap_or(0);
2153 let is_valid = signature::with_secp_context(|secp| {
2154 signature::verify_signature(
2155 secp,
2156 pubkey_bytes,
2157 signature_bytes,
2158 &sighash,
2159 flags,
2160 height,
2161 network,
2162 SigVersion::WitnessV0,
2163 )
2164 });
2165 return Some(is_valid);
2166 }
2167 Err(e) => return Some(Err(e)),
2168 }
2169 }
2170 }
2171
2172 if witness_sigversion == SigVersion::WitnessV0 {
2174 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script.as_ref()) {
2175 if stack.len() < 2 {
2176 return Some(Ok(false));
2177 }
2178 let dummy = stack[0].as_ref();
2179 let signatures: Vec<&[u8]> = stack[1..].iter().map(|e| e.as_ref()).collect();
2180
2181 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
2182 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
2183 let height = block_height.unwrap_or(0);
2184 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
2185 let activation = match network {
2186 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
2187 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
2188 crate::types::Network::Regtest => 0,
2189 };
2190 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
2191 return Some(Ok(false));
2192 }
2193 }
2194
2195 let mut cleaned = witness_script.to_vec();
2196 for sig in &signatures {
2197 if !sig.is_empty() {
2198 let pattern = serialize_push_data(sig);
2199 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
2200 }
2201 }
2202
2203 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2204 let mut sig_index = 0;
2205 let mut valid_sigs = 0u8;
2206
2207 for pubkey_bytes in pubkeys {
2208 if sig_index >= signatures.len() {
2209 break;
2210 }
2211 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
2212 sig_index += 1;
2213 }
2214 if sig_index >= signatures.len() {
2215 break;
2216 }
2217 let signature_bytes = &signatures[sig_index];
2218 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2219 match crate::transaction_hash::calculate_bip143_sighash(
2220 tx,
2221 input_index,
2222 &cleaned,
2223 amount,
2224 sighash_byte,
2225 precomputed_bip143,
2226 ) {
2227 Ok(sighash) => {
2228 let is_valid = signature::with_secp_context(|secp| {
2229 signature::verify_signature(
2230 secp,
2231 pubkey_bytes,
2232 signature_bytes,
2233 &sighash,
2234 flags,
2235 height,
2236 network,
2237 SigVersion::WitnessV0,
2238 )
2239 });
2240 match is_valid {
2241 Ok(v) if v => {
2242 valid_sigs += 1;
2243 sig_index += 1;
2244 }
2245 Ok(_) => {}
2246 Err(e) => return Some(Err(e)),
2247 }
2248 }
2249 Err(e) => return Some(Err(e)),
2250 }
2251 }
2252
2253 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
2254 for sig_bytes in &signatures[sig_index..] {
2255 if !sig_bytes.is_empty() {
2256 return Some(Err(ConsensusError::ScriptErrorWithCode {
2257 code: ScriptErrorCode::SigNullFail,
2258 message:
2259 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
2260 .into(),
2261 }));
2262 }
2263 }
2264 }
2265
2266 return Some(Ok(valid_sigs >= m));
2267 }
2268 }
2269
2270 let result = eval_script_with_context_full_inner(
2273 &witness_script,
2274 &mut stack,
2275 flags,
2276 tx,
2277 input_index,
2278 prevout_values,
2279 prevout_script_pubkeys,
2280 block_height,
2281 median_time_past,
2282 network,
2283 witness_sigversion,
2284 None, None, schnorr_collector,
2287 precomputed_bip143,
2288 #[cfg(feature = "production")]
2289 sighash_cache,
2290 );
2291 Some(result)
2292}
2293
2294#[cfg(feature = "production")]
2296#[allow(clippy::too_many_arguments)]
2297fn try_verify_p2tr_scriptpath_p2pk_fast_path(
2298 script_sig: &ByteString,
2299 script_pubkey: &[u8],
2300 witness: &crate::witness::Witness,
2301 _flags: u32,
2302 tx: &Transaction,
2303 input_index: usize,
2304 prevout_values: &[i64],
2305 prevout_script_pubkeys: &[&[u8]],
2306 block_height: Option<u64>,
2307 network: crate::types::Network,
2308 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2309) -> Option<Result<bool>> {
2310 use crate::activation::taproot_activation_height;
2311 use crate::taproot::parse_taproot_script_path_witness;
2312
2313 let tap_h = taproot_activation_height(network);
2314 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2315 return None;
2316 }
2317 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2318 return None;
2319 }
2320 if !script_sig.is_empty() {
2321 return None;
2322 }
2323 if witness.len() < 2 {
2324 return None;
2325 }
2326 let mut output_key = [0u8; 32];
2327 output_key.copy_from_slice(&script_pubkey[2..34]);
2328 let parsed = match parse_taproot_script_path_witness(witness, &output_key) {
2329 Ok(Some(p)) => p,
2330 Ok(None) | Err(_) => return None,
2331 };
2332 let (tapscript, stack_items, control_block) = parsed;
2333 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
2334 return None;
2335 }
2336 if stack_items.len() != 1 || stack_items[0].len() != 64 {
2337 return None;
2338 }
2339 let sig = stack_items[0].as_ref();
2340 let pubkey_32 = &tapscript[1..33];
2341 let sighash = crate::taproot::compute_tapscript_signature_hash(
2342 tx,
2343 input_index,
2344 prevout_values,
2345 prevout_script_pubkeys,
2346 &tapscript,
2347 control_block.leaf_version,
2348 0xffff_ffff,
2349 0x00,
2350 )
2351 .ok()?;
2352 let result = crate::bip348::verify_tapscript_schnorr_signature(
2353 &sighash,
2354 pubkey_32,
2355 sig,
2356 schnorr_collector,
2357 );
2358 Some(result)
2359}
2360
2361#[cfg(feature = "production")]
2364#[allow(clippy::too_many_arguments)]
2365fn try_verify_p2tr_keypath_fast_path(
2366 script_sig: &ByteString,
2367 script_pubkey: &[u8],
2368 witness: &crate::witness::Witness,
2369 _flags: u32,
2370 tx: &Transaction,
2371 input_index: usize,
2372 prevout_values: &[i64],
2373 prevout_script_pubkeys: &[&[u8]],
2374 block_height: Option<u64>,
2375 network: crate::types::Network,
2376 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2377) -> Option<Result<bool>> {
2378 use crate::activation::taproot_activation_height;
2379 let tap_h = taproot_activation_height(network);
2380 if block_height.map(|h| h < tap_h).unwrap_or(true) {
2381 return None;
2382 }
2383 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2385 return None;
2386 }
2387 if !script_sig.is_empty() {
2388 return None;
2389 }
2390 if witness.len() != 1 || witness[0].len() != 64 {
2392 return None;
2393 }
2394 let output_key = &script_pubkey[2..34];
2395 let sig = &witness[0];
2396 let sighash = crate::taproot::compute_taproot_signature_hash(
2397 tx,
2398 input_index,
2399 prevout_values,
2400 prevout_script_pubkeys,
2401 0x00, )
2403 .ok()?;
2404 let result = crate::bip348::verify_tapscript_schnorr_signature(
2405 &sighash,
2406 output_key,
2407 sig,
2408 schnorr_collector,
2409 );
2410 Some(result)
2411}
2412
2413#[spec_locked("5.2", "VerifyScript")]
2414pub fn verify_script_with_context_full(
2415 script_sig: &ByteString,
2416 script_pubkey: &[u8],
2417 witness: Option<&crate::witness::Witness>,
2418 flags: u32,
2419 tx: &Transaction,
2420 input_index: usize,
2421 prevout_values: &[i64],
2422 prevout_script_pubkeys: &[&[u8]],
2423 block_height: Option<u64>,
2424 median_time_past: Option<u64>,
2425 network: crate::types::Network,
2426 _sigversion: SigVersion,
2427 #[cfg(feature = "production")] schnorr_collector: Option<
2428 &crate::bip348::SchnorrSignatureCollector,
2429 >,
2430 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2431 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2432 #[cfg(feature = "production")] sighash_cache: Option<
2433 &crate::transaction_hash::SighashMidstateCache,
2434 >,
2435 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
2436) -> Result<bool> {
2437 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
2439 return Err(ConsensusError::ScriptErrorWithCode {
2440 code: ScriptErrorCode::TxInputInvalid,
2441 message: format!(
2442 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
2443 prevout_values.len(),
2444 prevout_script_pubkeys.len(),
2445 tx.inputs.len(),
2446 input_index,
2447 )
2448 .into(),
2449 });
2450 }
2451
2452 if input_index < prevout_values.len() {
2458 let prevout_value = prevout_values[input_index];
2459 if prevout_value < 0 {
2460 return Err(ConsensusError::ScriptErrorWithCode {
2461 code: ScriptErrorCode::ValueOverflow,
2462 message: "Prevout value cannot be negative".into(),
2463 });
2464 }
2465 #[cfg(feature = "production")]
2466 {
2467 use precomputed_constants::MAX_MONEY_U64;
2468 if (prevout_value as u64) > MAX_MONEY_U64 {
2469 return Err(ConsensusError::ScriptErrorWithCode {
2470 code: ScriptErrorCode::ValueOverflow,
2471 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2472 });
2473 }
2474 }
2475 #[cfg(not(feature = "production"))]
2476 {
2477 use crate::constants::MAX_MONEY;
2478 if prevout_value > MAX_MONEY {
2479 return Err(ConsensusError::ScriptErrorWithCode {
2480 code: ScriptErrorCode::ValueOverflow,
2481 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2482 });
2483 }
2484 }
2485 }
2486
2487 if input_index >= tx.inputs.len() {
2489 return Err(ConsensusError::ScriptErrorWithCode {
2490 code: ScriptErrorCode::TxInputInvalid,
2491 message: format!(
2492 "Input index {} out of bounds (tx has {} inputs)",
2493 input_index,
2494 tx.inputs.len()
2495 )
2496 .into(),
2497 });
2498 }
2499
2500 #[cfg(feature = "production")]
2502 if witness.is_none() {
2503 if let Some(result) = try_verify_p2pk_fast_path(
2504 script_sig,
2505 script_pubkey,
2506 flags,
2507 tx,
2508 input_index,
2509 prevout_values,
2510 prevout_script_pubkeys,
2511 block_height,
2512 network,
2513 #[cfg(feature = "production")]
2514 sighash_cache,
2515 ) {
2516 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
2517 return result;
2518 }
2519 if let Some(result) = try_verify_p2pkh_fast_path(
2520 script_sig,
2521 script_pubkey,
2522 flags,
2523 tx,
2524 input_index,
2525 prevout_values,
2526 prevout_script_pubkeys,
2527 block_height,
2528 network,
2529 #[cfg(feature = "production")]
2530 precomputed_sighash_all,
2531 #[cfg(feature = "production")]
2532 sighash_cache,
2533 #[cfg(feature = "production")]
2534 precomputed_p2pkh_hash,
2535 ) {
2536 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
2537 return result;
2538 }
2539 if let Some(result) = try_verify_p2sh_fast_path(
2540 script_sig,
2541 script_pubkey,
2542 flags,
2543 tx,
2544 input_index,
2545 prevout_values,
2546 prevout_script_pubkeys,
2547 block_height,
2548 median_time_past,
2549 network,
2550 #[cfg(feature = "production")]
2551 sighash_cache,
2552 #[cfg(feature = "production")]
2553 precomputed_sighash_all,
2554 ) {
2555 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
2556 return result;
2557 }
2558 if let Some(result) = try_verify_bare_multisig_fast_path(
2559 script_sig,
2560 script_pubkey,
2561 flags,
2562 tx,
2563 input_index,
2564 prevout_values,
2565 prevout_script_pubkeys,
2566 block_height,
2567 network,
2568 #[cfg(feature = "production")]
2569 sighash_cache,
2570 ) {
2571 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
2572 return result;
2573 }
2574 }
2575 #[cfg(feature = "production")]
2577 if let Some(wit) = witness {
2578 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
2579 script_sig,
2580 script_pubkey,
2581 wit,
2582 flags,
2583 tx,
2584 input_index,
2585 prevout_values,
2586 prevout_script_pubkeys,
2587 block_height,
2588 network,
2589 precomputed_bip143,
2590 ) {
2591 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2592 return result;
2593 }
2594 if let Some(result) = try_verify_p2wpkh_fast_path(
2595 script_sig,
2596 script_pubkey,
2597 wit,
2598 flags,
2599 tx,
2600 input_index,
2601 prevout_values,
2602 prevout_script_pubkeys,
2603 block_height,
2604 network,
2605 precomputed_bip143,
2606 precomputed_sighash_all,
2607 ) {
2608 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2609 return result;
2610 }
2611 if let Some(result) = try_verify_p2wsh_fast_path(
2612 script_sig,
2613 script_pubkey,
2614 wit,
2615 flags,
2616 tx,
2617 input_index,
2618 prevout_values,
2619 prevout_script_pubkeys,
2620 block_height,
2621 median_time_past,
2622 network,
2623 schnorr_collector,
2624 precomputed_bip143,
2625 #[cfg(feature = "production")]
2626 sighash_cache,
2627 ) {
2628 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
2629 return result;
2630 }
2631 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
2632 script_sig,
2633 script_pubkey,
2634 wit,
2635 flags,
2636 tx,
2637 input_index,
2638 prevout_values,
2639 prevout_script_pubkeys,
2640 block_height,
2641 network,
2642 schnorr_collector,
2643 ) {
2644 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2645 return result;
2646 }
2647 if let Some(result) = try_verify_p2tr_keypath_fast_path(
2648 script_sig,
2649 script_pubkey,
2650 wit,
2651 flags,
2652 tx,
2653 input_index,
2654 prevout_values,
2655 prevout_script_pubkeys,
2656 block_height,
2657 network,
2658 schnorr_collector,
2659 ) {
2660 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2661 return result;
2662 }
2663 }
2664 #[cfg(feature = "production")]
2665 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
2666
2667 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
2671 let is_p2sh = (flags & SCRIPT_VERIFY_P2SH) != 0
2672 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; if is_p2sh {
2683 let mut i = 0;
2684 while i < script_sig.len() {
2685 let opcode = script_sig[i];
2686 if !is_push_opcode(opcode) {
2687 return Ok(false);
2689 }
2690 if opcode == OP_0 {
2692 i += 1;
2694 } else if opcode <= 0x4b {
2695 let len = opcode as usize;
2697 if i + 1 + len > script_sig.len() {
2698 return Ok(false); }
2700 i += 1 + len;
2701 } else if opcode == OP_PUSHDATA1 {
2702 if i + 1 >= script_sig.len() {
2704 return Ok(false);
2705 }
2706 let len = script_sig[i + 1] as usize;
2707 if i + 2 + len > script_sig.len() {
2708 return Ok(false);
2709 }
2710 i += 2 + len;
2711 } else if opcode == OP_PUSHDATA2 {
2712 if i + 2 >= script_sig.len() {
2714 return Ok(false);
2715 }
2716 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
2717 if i + 3 + len > script_sig.len() {
2718 return Ok(false);
2719 }
2720 i += 3 + len;
2721 } else if opcode == OP_PUSHDATA4 {
2722 if i + 4 >= script_sig.len() {
2724 return Ok(false);
2725 }
2726 let len = u32::from_le_bytes([
2727 script_sig[i + 1],
2728 script_sig[i + 2],
2729 script_sig[i + 3],
2730 script_sig[i + 4],
2731 ]) as usize;
2732 if i + 5 + len > script_sig.len() {
2733 return Ok(false);
2734 }
2735 i += 5 + len;
2736 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
2737 i += 1;
2740 } else {
2741 return Ok(false);
2743 }
2744 }
2745 if let Some(result) = try_verify_p2sh_multisig_fast_path(
2746 script_sig,
2747 script_pubkey,
2748 flags,
2749 tx,
2750 input_index,
2751 prevout_values,
2752 prevout_script_pubkeys,
2753 block_height,
2754 network,
2755 #[cfg(feature = "production")]
2756 sighash_cache,
2757 ) {
2758 return result;
2759 }
2760 }
2761
2762 #[cfg(feature = "production")]
2763 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
2764 #[cfg(feature = "production")]
2765 let stack = &mut _stack_guard.0;
2766 #[cfg(not(feature = "production"))]
2767 let mut stack = Vec::with_capacity(20);
2768
2769 let script_sig_result = eval_script_with_context_full(
2773 script_sig,
2774 stack,
2775 flags,
2776 tx,
2777 input_index,
2778 prevout_values,
2779 prevout_script_pubkeys,
2780 block_height,
2781 median_time_past,
2782 network,
2783 SigVersion::Base,
2784 None, #[cfg(feature = "production")]
2786 schnorr_collector,
2787 None, #[cfg(feature = "production")]
2789 sighash_cache,
2790 )?;
2791 if !script_sig_result {
2792 return Ok(false);
2793 }
2794
2795 let redeem_script: Option<ByteString> = if is_p2sh && !stack.is_empty() {
2797 Some(stack.last().expect("Stack is not empty").as_ref().to_vec())
2798 } else {
2799 None
2800 };
2801
2802 use crate::activation::taproot_activation_height;
2806 let tap_h = taproot_activation_height(network);
2807 let is_taproot = redeem_script.is_none() && block_height.is_some() && block_height.unwrap() >= tap_h
2809 && script_pubkey.len() == 34
2810 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES; if is_taproot && !script_sig.is_empty() {
2815 return Ok(false); }
2817
2818 let is_direct_witness_program = redeem_script.is_none() && !is_taproot && script_pubkey.len() >= 3
2825 && 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;
2831 if is_direct_witness_program {
2832 if let Some(witness_stack) = witness {
2833 if script_pubkey[1] == PUSH_32_BYTES {
2834 if witness_stack.is_empty() {
2837 return Ok(false); }
2839
2840 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2842
2843 let program_bytes = &script_pubkey[2..];
2845 if program_bytes.len() != 32 {
2846 return Ok(false); }
2848
2849 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2850 if &witness_script_hash[..] != program_bytes {
2851 return Ok(false); }
2853
2854 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2856 stack.push(to_stack_element(element));
2857 }
2858
2859 witness_script_to_execute = Some(witness_script.clone());
2861 } else if script_pubkey[1] == PUSH_20_BYTES {
2862 if witness_stack.len() != 2 {
2865 return Ok(false); }
2867
2868 for element in witness_stack.iter() {
2869 stack.push(to_stack_element(element));
2870 }
2871 } else {
2872 return Ok(false); }
2874 } else {
2875 return Ok(false); }
2877 }
2878
2879 if is_taproot {
2880 let Some(witness_stack) = witness else {
2881 return Ok(false);
2882 };
2883 if witness_stack.len() < 2 {
2884 return Ok(false);
2885 }
2886 let mut output_key = [0u8; 32];
2887 output_key.copy_from_slice(&script_pubkey[2..34]);
2888 match crate::taproot::parse_taproot_script_path_witness(witness_stack, &output_key)? {
2889 None => return Ok(false),
2890 Some((tapscript, stack_items, _control_block)) => {
2891 for item in &stack_items {
2892 stack.push(to_stack_element(item));
2893 }
2894 let tapscript_flags = flags | 0x8000;
2895 if !eval_script_with_context_full(
2896 &tapscript,
2897 stack,
2898 tapscript_flags,
2899 tx,
2900 input_index,
2901 prevout_values,
2902 prevout_script_pubkeys,
2903 block_height,
2904 median_time_past,
2905 network,
2906 SigVersion::Tapscript,
2907 None,
2908 #[cfg(feature = "production")]
2909 schnorr_collector,
2910 None,
2911 #[cfg(feature = "production")]
2912 sighash_cache,
2913 )? {
2914 return Ok(false);
2915 }
2916 return Ok(true);
2917 }
2918 }
2919 }
2920
2921 let script_pubkey_result = eval_script_with_context_full(
2928 script_pubkey,
2929 stack,
2930 flags,
2931 tx,
2932 input_index,
2933 prevout_values,
2934 prevout_script_pubkeys,
2935 block_height,
2936 median_time_past,
2937 network,
2938 SigVersion::Base,
2939 Some(script_sig),
2940 #[cfg(feature = "production")]
2941 schnorr_collector,
2942 None, #[cfg(feature = "production")]
2944 sighash_cache,
2945 )?;
2946 if !script_pubkey_result {
2947 return Ok(false);
2948 }
2949
2950 if let Some(witness_script) = witness_script_to_execute {
2952 let witness_sigversion = SigVersion::WitnessV0;
2955
2956 if !eval_script_with_context_full(
2959 &witness_script,
2960 stack,
2961 flags,
2962 tx,
2963 input_index,
2964 prevout_values,
2965 prevout_script_pubkeys,
2966 block_height,
2967 median_time_past,
2968 network,
2969 witness_sigversion,
2970 None, #[cfg(feature = "production")]
2972 schnorr_collector,
2973 precomputed_bip143, #[cfg(feature = "production")]
2975 sighash_cache,
2976 )? {
2977 return Ok(false);
2978 }
2979 }
2980
2981 if let Some(redeem) = redeem_script {
2986 if stack.is_empty() {
2988 return Ok(false); }
2990
2991 let top = stack.last().expect("Stack is not empty");
2993 if !cast_to_bool(top) {
2994 return Ok(false); }
2996
2997 stack.pop();
2999
3000 let is_witness_program = redeem.len() >= 3
3005 && 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() {
3010 let program_bytes = &redeem[2..];
3019
3020 if redeem[1] == PUSH_32_BYTES {
3021 if program_bytes.len() != 32 {
3024 return Ok(false); }
3026
3027 if let Some(witness_stack) = witness {
3032 if witness_stack.is_empty() {
3033 return Ok(false); }
3035
3036 let witness_script = witness_stack.last().expect("Witness stack is not empty");
3038 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
3039 if &witness_script_hash[..] != program_bytes {
3040 return Ok(false); }
3042
3043 stack.clear();
3046
3047 for element in witness_stack.iter().take(witness_stack.len() - 1) {
3050 stack.push(to_stack_element(element));
3051 }
3052
3053 let witness_sigversion = if flags & 0x8000 != 0 {
3055 SigVersion::Tapscript
3056 } else {
3057 SigVersion::WitnessV0 };
3059
3060 if !eval_script_with_context_full(
3062 witness_script,
3063 stack,
3064 flags,
3065 tx,
3066 input_index,
3067 prevout_values,
3068 prevout_script_pubkeys,
3069 block_height,
3070 median_time_past,
3071 network,
3072 witness_sigversion,
3073 None, #[cfg(feature = "production")]
3075 schnorr_collector,
3076 precomputed_bip143, #[cfg(feature = "production")]
3078 sighash_cache,
3079 )? {
3080 return Ok(false);
3081 }
3082 } else {
3083 return Ok(false); }
3085 } else if redeem[1] == PUSH_20_BYTES {
3086 stack.clear();
3090 } else {
3091 return Ok(false); }
3093 } else {
3095 let redeem_result = eval_script_with_context_full_inner(
3099 &redeem,
3100 stack,
3101 flags,
3102 tx,
3103 input_index,
3104 prevout_values,
3105 prevout_script_pubkeys,
3106 block_height,
3107 median_time_past,
3108 network,
3109 SigVersion::Base,
3110 Some(redeem.as_ref()), Some(script_sig), #[cfg(feature = "production")]
3113 None, None, #[cfg(feature = "production")]
3116 sighash_cache,
3117 )?;
3118 if !redeem_result {
3119 return Ok(false);
3120 }
3121 }
3122 }
3123
3124 assert!(
3126 stack.len() <= 1000,
3127 "Stack size {} exceeds reasonable maximum after scriptPubkey",
3128 stack.len()
3129 );
3130
3131 if let Some(_witness_stack) = witness {
3140 }
3144
3145 const SCRIPT_VERIFY_CLEANSTACK: u32 = 0x100;
3151
3152 let final_result = if (flags & SCRIPT_VERIFY_CLEANSTACK) != 0 {
3153 stack.len() == 1 && cast_to_bool(&stack[0])
3155 } else {
3156 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
3158 };
3159 Ok(final_result)
3160}
3161
3162#[allow(dead_code)]
3164fn eval_script_with_context(
3165 script: &ByteString,
3166 stack: &mut Vec<StackElement>,
3167 flags: u32,
3168 tx: &Transaction,
3169 input_index: usize,
3170 prevouts: &[TransactionOutput],
3171 network: crate::types::Network,
3172) -> Result<bool> {
3173 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
3175 let prevout_script_pubkeys: Vec<&[u8]> =
3176 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
3177 eval_script_with_context_full(
3178 script,
3179 stack,
3180 flags,
3181 tx,
3182 input_index,
3183 &prevout_values,
3184 &prevout_script_pubkeys,
3185 None, None, network,
3188 SigVersion::Base,
3189 None, #[cfg(feature = "production")]
3191 None, None, #[cfg(feature = "production")]
3194 None, )
3196}
3197
3198#[allow(clippy::too_many_arguments)]
3200fn eval_script_with_context_full(
3201 script: &[u8],
3202 stack: &mut Vec<StackElement>,
3203 flags: u32,
3204 tx: &Transaction,
3205 input_index: usize,
3206 prevout_values: &[i64],
3207 prevout_script_pubkeys: &[&[u8]],
3208 block_height: Option<u64>,
3209 median_time_past: Option<u64>,
3210 network: crate::types::Network,
3211 sigversion: SigVersion,
3212 script_sig_for_sighash: Option<&ByteString>,
3213 #[cfg(feature = "production")] schnorr_collector: Option<
3214 &crate::bip348::SchnorrSignatureCollector,
3215 >,
3216 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3217 #[cfg(feature = "production")] sighash_cache: Option<
3218 &crate::transaction_hash::SighashMidstateCache,
3219 >,
3220) -> Result<bool> {
3221 #[cfg(all(feature = "production", feature = "profile"))]
3222 let _t0 = std::time::Instant::now();
3223 let r = eval_script_with_context_full_inner(
3224 script,
3225 stack,
3226 flags,
3227 tx,
3228 input_index,
3229 prevout_values,
3230 prevout_script_pubkeys,
3231 block_height,
3232 median_time_past,
3233 network,
3234 sigversion,
3235 None,
3236 script_sig_for_sighash,
3237 #[cfg(feature = "production")]
3238 schnorr_collector,
3239 precomputed_bip143,
3240 #[cfg(feature = "production")]
3241 sighash_cache,
3242 );
3243 #[cfg(all(feature = "production", feature = "profile"))]
3244 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
3245 r
3246}
3247
3248fn eval_script_with_context_full_inner(
3250 script: &[u8],
3251 stack: &mut Vec<StackElement>,
3252 flags: u32,
3253 tx: &Transaction,
3254 input_index: usize,
3255 prevout_values: &[i64],
3256 prevout_script_pubkeys: &[&[u8]],
3257 block_height: Option<u64>,
3258 median_time_past: Option<u64>,
3259 network: crate::types::Network,
3260 sigversion: SigVersion,
3261 redeem_script_for_sighash: Option<&[u8]>,
3262 script_sig_for_sighash: Option<&ByteString>,
3263 #[cfg(feature = "production")] schnorr_collector: Option<
3264 &crate::bip348::SchnorrSignatureCollector,
3265 >,
3266 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3267 #[cfg(feature = "production")] sighash_cache: Option<
3268 &crate::transaction_hash::SighashMidstateCache,
3269 >,
3270) -> Result<bool> {
3271 assert!(
3274 script.len() <= 10000,
3275 "Script length {} exceeds reasonable maximum",
3276 script.len()
3277 );
3278 assert!(
3279 stack.len() <= 1000,
3280 "Stack size {} exceeds reasonable maximum at start",
3281 stack.len()
3282 );
3283
3284 use crate::error::{ConsensusError, ScriptErrorCode};
3285
3286 if sigversion == SigVersion::Tapscript {
3291 const SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS: u32 = 1 << 17;
3292 let mut pc = 0usize;
3293 while pc < script.len() {
3294 let opcode = script[pc];
3295 if is_op_success(opcode) {
3296 if flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS != 0 {
3297 return Err(ConsensusError::ScriptErrorWithCode {
3298 code: ScriptErrorCode::BadOpcode,
3299 message: format!("OP_SUCCESSx opcode 0x{opcode:02x} is discouraged").into(),
3300 });
3301 }
3302 return Ok(true);
3303 }
3304 pc += op_advance(script, pc);
3306 }
3307 }
3308
3309 if stack.capacity() < 20 {
3311 stack.reserve(20);
3312 }
3313 let mut op_count = 0;
3314 assert!(op_count == 0, "Op count must start at zero");
3316
3317 #[cfg(feature = "production")]
3319 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
3320 #[cfg(not(feature = "production"))]
3321 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
3322 assert!(control_stack.is_empty(), "Control stack must start empty");
3324
3325 #[cfg(feature = "production")]
3326 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
3327 #[cfg(not(feature = "production"))]
3328 let mut altstack: Vec<StackElement> = Vec::new();
3329
3330 let mut code_separator_pos: usize = 0;
3334 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
3335
3336 let mut i = 0;
3338 while i < script.len() {
3339 #[cfg(feature = "production")]
3340 {
3341 prefetch::prefetch_ahead(script, i, 64); }
3344 let opcode = {
3346 #[cfg(feature = "production")]
3347 {
3348 unsafe { *script.get_unchecked(i) }
3349 }
3350 #[cfg(not(feature = "production"))]
3351 {
3352 script[i]
3353 }
3354 };
3355
3356 let in_false_branch = control_flow::in_false_branch(&control_stack);
3358
3359 if !is_push_opcode(opcode) {
3361 op_count += 1;
3362 assert!(
3364 op_count <= MAX_SCRIPT_OPS + 1,
3365 "Op count {op_count} must not exceed MAX_SCRIPT_OPS + 1"
3366 );
3367 if op_count > MAX_SCRIPT_OPS {
3368 return Err(make_operation_limit_error());
3369 }
3370 }
3371
3372 if stack.len() + altstack.len() > MAX_STACK_SIZE {
3374 return Err(make_stack_overflow_error());
3375 }
3376
3377 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
3379 let (data, advance) = if opcode <= 0x4b {
3380 let len = opcode as usize;
3382 if i + 1 + len > script.len() {
3383 return Ok(false); }
3385 (&script[i + 1..i + 1 + len], 1 + len)
3386 } else if opcode == OP_PUSHDATA1 {
3387 if i + 1 >= script.len() {
3389 return Ok(false);
3390 }
3391 let len = script[i + 1] as usize;
3392 if i + 2 + len > script.len() {
3393 return Ok(false);
3394 }
3395 (&script[i + 2..i + 2 + len], 2 + len)
3396 } else if opcode == OP_PUSHDATA2 {
3397 if i + 2 >= script.len() {
3399 return Ok(false);
3400 }
3401 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
3402 if i + 3 + len > script.len() {
3403 return Ok(false);
3404 }
3405 (&script[i + 3..i + 3 + len], 3 + len)
3406 } else {
3407 if i + 4 >= script.len() {
3410 return Ok(false);
3411 }
3412 let len = u32::from_le_bytes([
3413 script[i + 1],
3414 script[i + 2],
3415 script[i + 3],
3416 script[i + 4],
3417 ]) as usize;
3418 let data_start = i.saturating_add(5);
3419 let data_end = data_start.saturating_add(len);
3420 let advance = 5usize.saturating_add(len);
3421 if advance < 5 || data_end > script.len() || data_end < data_start {
3422 return Ok(false); }
3424 (&script[data_start..data_end], advance)
3425 };
3426
3427 if !in_false_branch {
3429 stack.push(to_stack_element(data));
3430 }
3431 i += advance;
3432 continue;
3433 }
3434
3435 if opcode == OP_DUP {
3441 if !in_false_branch {
3442 if stack.is_empty() {
3443 return Err(ConsensusError::ScriptErrorWithCode {
3444 code: ScriptErrorCode::InvalidStackOperation,
3445 message: "OP_DUP: empty stack".into(),
3446 });
3447 }
3448 let len = stack.len();
3451 #[cfg(feature = "production")]
3452 {
3453 if stack.capacity() == stack.len() {
3455 stack.reserve(1);
3456 }
3457 let item = unsafe { stack.get_unchecked(len - 1).clone() };
3459 stack.push(item);
3460 }
3461 #[cfg(not(feature = "production"))]
3462 {
3463 let item = stack.last().unwrap();
3464 stack.push(item.clone());
3465 }
3466 }
3467 i += 1;
3468 continue;
3469 }
3470
3471 if opcode == OP_EQUALVERIFY {
3473 if !in_false_branch {
3474 if stack.len() < 2 {
3475 return Err(ConsensusError::ScriptErrorWithCode {
3476 code: ScriptErrorCode::InvalidStackOperation,
3477 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3478 });
3479 }
3480 let a = stack.pop().unwrap();
3481 let b = stack.pop().unwrap();
3482 if a != b {
3483 return Ok(false);
3484 }
3485 }
3486 i += 1;
3487 continue;
3488 }
3489
3490 if opcode == OP_HASH160 {
3492 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
3493 return Ok(false);
3494 }
3495 i += 1;
3496 continue;
3497 }
3498
3499 if opcode == OP_VERIFY {
3501 if !in_false_branch {
3502 if let Some(item) = stack.pop() {
3503 if !cast_to_bool(&item) {
3504 return Ok(false);
3505 }
3506 } else {
3507 return Ok(false);
3508 }
3509 }
3510 i += 1;
3511 continue;
3512 }
3513
3514 if opcode == OP_EQUAL {
3516 if !in_false_branch {
3517 if stack.len() < 2 {
3518 return Err(ConsensusError::ScriptErrorWithCode {
3519 code: ScriptErrorCode::InvalidStackOperation,
3520 message: "OP_EQUAL: insufficient stack items".into(),
3521 });
3522 }
3523 let a = stack.pop().unwrap();
3524 let b = stack.pop().unwrap();
3525 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3526 }
3527 i += 1;
3528 continue;
3529 }
3530
3531 if opcode == OP_CHECKSIG
3534 || opcode == OP_CHECKSIGVERIFY
3535 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
3536 {
3537 if !in_false_branch {
3538 let effective_script_code = Some(&script[code_separator_pos..]);
3539 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3540 (Some(script), Some(last_codesep_opcode_pos))
3541 } else {
3542 (None, None)
3543 };
3544 let ctx = context::ScriptContext {
3545 tx,
3546 input_index,
3547 prevout_values,
3548 prevout_script_pubkeys,
3549 block_height,
3550 median_time_past,
3551 network,
3552 sigversion,
3553 redeem_script_for_sighash,
3554 script_sig_for_sighash,
3555 tapscript_for_sighash: tapscript,
3556 tapscript_codesep_pos: codesep,
3557 #[cfg(feature = "production")]
3558 schnorr_collector,
3559 #[cfg(feature = "production")]
3560 precomputed_bip143,
3561 #[cfg(feature = "production")]
3562 sighash_cache,
3563 };
3564 if !execute_opcode_with_context_full(
3565 opcode,
3566 stack,
3567 flags,
3568 &ctx,
3569 effective_script_code,
3570 )? {
3571 return Ok(false);
3572 }
3573 }
3574 i += 1;
3575 continue;
3576 }
3577
3578 match opcode {
3579 OP_0 => {
3581 if !in_false_branch {
3582 stack.push(to_stack_element(&[]));
3583 }
3584 }
3585
3586 OP_1_RANGE_START..=OP_1_RANGE_END => {
3588 if !in_false_branch {
3589 let num = opcode - OP_N_BASE;
3590 stack.push(to_stack_element(&[num]));
3591 }
3592 }
3593
3594 OP_1NEGATE => {
3596 if !in_false_branch {
3597 stack.push(to_stack_element(&[0x81])); }
3599 }
3600
3601 OP_NOP => {
3603 }
3605
3606 OP_VER => {
3611 if !in_false_branch {
3612 return Err(ConsensusError::ScriptErrorWithCode {
3613 code: ScriptErrorCode::DisabledOpcode,
3614 message: "OP_VER is disabled".into(),
3615 });
3616 }
3617 }
3618
3619 OP_IF => {
3620 if in_false_branch {
3622 control_stack.push(control_flow::ControlBlock::If { executing: false });
3623 i += 1;
3624 continue;
3625 }
3626
3627 if stack.is_empty() {
3628 return Err(ConsensusError::ScriptErrorWithCode {
3629 code: ScriptErrorCode::InvalidStackOperation,
3630 message: "OP_IF: empty stack".into(),
3631 });
3632 }
3633 let condition_bytes = stack.pop().unwrap();
3634 let condition = cast_to_bool(&condition_bytes);
3635
3636 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3637 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3638 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3639 && !control_flow::is_minimal_if_condition(&condition_bytes)
3640 {
3641 return Err(ConsensusError::ScriptErrorWithCode {
3642 code: ScriptErrorCode::MinimalIf,
3643 message: "OP_IF condition must be minimally encoded".into(),
3644 });
3645 }
3646
3647 control_stack.push(control_flow::ControlBlock::If {
3648 executing: condition,
3649 });
3650 }
3651 OP_NOTIF => {
3652 if in_false_branch {
3654 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
3655 i += 1;
3656 continue;
3657 }
3658
3659 if stack.is_empty() {
3660 return Err(ConsensusError::ScriptErrorWithCode {
3661 code: ScriptErrorCode::InvalidStackOperation,
3662 message: "OP_NOTIF: empty stack".into(),
3663 });
3664 }
3665 let condition_bytes = stack.pop().unwrap();
3666 let condition = cast_to_bool(&condition_bytes);
3667
3668 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3669 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3670 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3671 && !control_flow::is_minimal_if_condition(&condition_bytes)
3672 {
3673 return Err(ConsensusError::ScriptErrorWithCode {
3674 code: ScriptErrorCode::MinimalIf,
3675 message: "OP_NOTIF condition must be minimally encoded".into(),
3676 });
3677 }
3678
3679 control_stack.push(control_flow::ControlBlock::NotIf {
3680 executing: !condition,
3681 });
3682 }
3683 OP_ELSE => {
3684 if let Some(block) = control_stack.last_mut() {
3686 match block {
3687 control_flow::ControlBlock::If { executing }
3688 | control_flow::ControlBlock::NotIf { executing } => {
3689 *executing = !*executing;
3690 }
3691 }
3692 } else {
3693 return Err(ConsensusError::ScriptErrorWithCode {
3694 code: ScriptErrorCode::UnbalancedConditional,
3695 message: "OP_ELSE without matching IF/NOTIF".into(),
3696 });
3697 }
3698 }
3699 OP_ENDIF => {
3700 if control_stack.pop().is_none() {
3702 return Err(ConsensusError::ScriptErrorWithCode {
3703 code: ScriptErrorCode::UnbalancedConditional,
3704 message: "OP_ENDIF without matching IF/NOTIF".into(),
3705 });
3706 }
3707 }
3708
3709 OP_TOALTSTACK => {
3714 if in_false_branch {
3715 i += 1;
3716 continue;
3717 }
3718 if stack.is_empty() {
3719 return Err(ConsensusError::ScriptErrorWithCode {
3720 code: ScriptErrorCode::InvalidStackOperation,
3721 message: "OP_TOALTSTACK: empty stack".into(),
3722 });
3723 }
3724 altstack.push(stack.pop().unwrap());
3725 }
3726 OP_FROMALTSTACK => {
3728 if in_false_branch {
3729 i += 1;
3730 continue;
3731 }
3732 if altstack.is_empty() {
3733 return Err(ConsensusError::ScriptErrorWithCode {
3734 code: ScriptErrorCode::InvalidAltstackOperation,
3735 message: "OP_FROMALTSTACK: empty altstack".into(),
3736 });
3737 }
3738 stack.push(altstack.pop().unwrap());
3739 }
3740 OP_CODESEPARATOR => {
3742 if in_false_branch {
3743 i += 1;
3744 continue;
3745 }
3746 code_separator_pos = i + 1;
3747 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
3748 }
3749 _ => {
3750 if in_false_branch {
3751 i += 1;
3752 continue;
3753 }
3754
3755 let subscript_for_sighash = if matches!(
3760 opcode,
3761 OP_CHECKSIG
3762 | OP_CHECKSIGVERIFY
3763 | OP_CHECKSIGADD
3764 | OP_CHECKMULTISIG
3765 | OP_CHECKMULTISIGVERIFY
3766 ) {
3767 Some(&script[code_separator_pos..])
3768 } else {
3769 None
3770 };
3771 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
3772 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3773 (Some(script), Some(last_codesep_opcode_pos))
3774 } else {
3775 (None, None)
3776 };
3777 let ctx = context::ScriptContext {
3778 tx,
3779 input_index,
3780 prevout_values,
3781 prevout_script_pubkeys,
3782 block_height,
3783 median_time_past,
3784 network,
3785 sigversion,
3786 redeem_script_for_sighash,
3787 script_sig_for_sighash,
3788 tapscript_for_sighash: tapscript,
3789 tapscript_codesep_pos: codesep,
3790 #[cfg(feature = "production")]
3791 schnorr_collector,
3792 #[cfg(feature = "production")]
3793 precomputed_bip143,
3794 #[cfg(feature = "production")]
3795 sighash_cache,
3796 };
3797 if !execute_opcode_with_context_full(
3798 opcode,
3799 stack,
3800 flags,
3801 &ctx,
3802 effective_script_code,
3803 )? {
3804 return Ok(false);
3805 }
3806 }
3807 }
3808 i += 1;
3809 }
3810
3811 if !control_stack.is_empty() {
3813 return Err(ConsensusError::ScriptErrorWithCode {
3814 code: ScriptErrorCode::UnbalancedConditional,
3815 message: "Unclosed IF/NOTIF block".into(),
3816 });
3817 }
3818
3819 Ok(true)
3823}
3824
3825#[spec_locked("5.4.5", "DecodeCScriptNum")]
3829#[blvm_spec_lock::axiom(result >= -549755813887)]
3830#[blvm_spec_lock::ensures(result >= -549755813887)]
3831#[cfg(feature = "production")]
3832#[inline(always)]
3833pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3834 if data.len() > max_num_size {
3835 return Err(ConsensusError::ScriptErrorWithCode {
3836 code: ScriptErrorCode::InvalidStackOperation,
3837 message: format!(
3838 "Script number overflow: {} > {} bytes",
3839 data.len(),
3840 max_num_size
3841 )
3842 .into(),
3843 });
3844 }
3845 if data.is_empty() {
3846 return Ok(0);
3847 }
3848
3849 let len = data.len();
3851 let result = match len {
3852 1 => {
3853 let byte = data[0];
3854 if byte & 0x80 != 0 {
3855 -((byte & 0x7f) as i64)
3857 } else {
3858 byte as i64
3859 }
3860 }
3861 2 => {
3862 let byte0 = data[0] as i64;
3863 let byte1 = data[1] as i64;
3864 let value = byte0 | (byte1 << 8);
3865 if byte1 & 0x80 != 0 {
3866 -(value & !(0x80i64 << 8))
3868 } else {
3869 value
3870 }
3871 }
3872 _ => {
3873 let mut result: i64 = 0;
3875 for (i, &byte) in data.iter().enumerate() {
3876 result |= (byte as i64) << (8 * i);
3877 }
3878 let last_idx = len - 1;
3880 if data[last_idx] & 0x80 != 0 {
3881 result &= !(0x80i64 << (8 * last_idx));
3883 result = -result;
3884 }
3885 result
3886 }
3887 };
3888
3889 Ok(result)
3890}
3891
3892#[cfg(not(feature = "production"))]
3893#[inline]
3894pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3895 if data.len() > max_num_size {
3896 return Err(ConsensusError::ScriptErrorWithCode {
3897 code: ScriptErrorCode::InvalidStackOperation,
3898 message: format!(
3899 "Script number overflow: {} > {} bytes",
3900 data.len(),
3901 max_num_size
3902 )
3903 .into(),
3904 });
3905 }
3906 if data.is_empty() {
3907 return Ok(0);
3908 }
3909 let mut result: i64 = 0;
3911 for (i, &byte) in data.iter().enumerate() {
3912 result |= (byte as i64) << (8 * i);
3913 }
3914 if data.last().expect("Data is not empty") & 0x80 != 0 {
3916 result &= !(0x80i64 << (8 * (data.len() - 1)));
3918 result = -result;
3919 }
3920 Ok(result)
3921}
3922
3923#[cfg(feature = "production")]
3926pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3927 match value {
3929 0 => return vec![],
3930 1 => return vec![1],
3931 -1 => return vec![0x81],
3932 _ => {}
3933 }
3934
3935 let neg = value < 0;
3936 let mut absvalue = if neg {
3937 (-(value as i128)) as u64
3938 } else {
3939 value as u64
3940 };
3941 let mut result = Vec::with_capacity(4);
3943 while absvalue > 0 {
3944 result.push((absvalue & 0xff) as u8);
3945 absvalue >>= 8;
3946 }
3947 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3949 result.push(if neg { 0x80 } else { 0x00 });
3950 } else if neg {
3951 *result.last_mut().unwrap() |= 0x80;
3952 }
3953 result
3954}
3955
3956#[cfg(not(feature = "production"))]
3957pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
3958 if value == 0 {
3959 return vec![];
3960 }
3961 let neg = value < 0;
3962 let mut absvalue = if neg {
3963 (-(value as i128)) as u64
3964 } else {
3965 value as u64
3966 };
3967 let mut result = Vec::new();
3968 while absvalue > 0 {
3969 result.push((absvalue & 0xff) as u8);
3970 absvalue >>= 8;
3971 }
3972 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
3974 result.push(if neg { 0x80 } else { 0x00 });
3975 } else if neg {
3976 *result.last_mut().unwrap() |= 0x80;
3977 }
3978 result
3979}
3980
3981#[cfg(feature = "production")]
3983#[inline(always)]
3984fn execute_opcode(
3985 opcode: u8,
3986 stack: &mut Vec<StackElement>,
3987 flags: u32,
3988 _sigversion: SigVersion,
3989) -> Result<bool> {
3990 match opcode {
3991 OP_0 => {
3993 stack.push(to_stack_element(&[]));
3994 Ok(true)
3995 }
3996
3997 OP_1..=OP_16 => {
3999 let num = opcode - OP_N_BASE;
4000 stack.push(to_stack_element(&[num]));
4001 Ok(true)
4002 }
4003
4004 OP_NOP => Ok(true),
4006
4007 OP_VER => Ok(false),
4009
4010 OP_DEPTH => {
4012 let depth = stack.len() as i64;
4013 stack.push(to_stack_element(&script_num_encode(depth)));
4014 Ok(true)
4015 }
4016
4017 OP_DUP => {
4019 if let Some(item) = stack.last().cloned() {
4020 stack.push(item);
4021 Ok(true)
4022 } else {
4023 Ok(false)
4024 }
4025 }
4026
4027 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
4029
4030 OP_SHA1 => crypto_ops::op_sha1(stack),
4032
4033 OP_SHA256 => crypto_ops::op_sha256(stack),
4035
4036 OP_HASH160 => crypto_ops::op_hash160(stack),
4038
4039 OP_HASH256 => crypto_ops::op_hash256(stack),
4041
4042 OP_EQUAL => {
4045 if stack.len() < 2 {
4046 return Err(ConsensusError::ScriptErrorWithCode {
4047 code: ScriptErrorCode::InvalidStackOperation,
4048 message: "OP_EQUAL: insufficient stack items".into(),
4049 });
4050 }
4051 let a = stack.pop().unwrap();
4052 let b = stack.pop().unwrap();
4053 stack.push(to_stack_element(if a == b { &[1u8] } else { &[] }));
4054 Ok(true)
4055 }
4056
4057 OP_EQUALVERIFY => {
4060 if stack.len() < 2 {
4061 return Err(ConsensusError::ScriptErrorWithCode {
4062 code: ScriptErrorCode::InvalidStackOperation,
4063 message: "OP_EQUALVERIFY: insufficient stack items".into(),
4064 });
4065 }
4066 let a = stack.pop().unwrap();
4067 let b = stack.pop().unwrap();
4068 let f_equal = a == b;
4069 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
4071 if f_equal {
4072 stack.pop();
4074 Ok(true)
4075 } else {
4076 Err(ConsensusError::ScriptErrorWithCode {
4077 code: ScriptErrorCode::EqualVerify,
4078 message: "OP_EQUALVERIFY: stack items not equal".into(),
4079 })
4080 }
4081 }
4082
4083 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
4085
4086 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
4088
4089 OP_RETURN => Ok(false),
4091
4092 OP_VERIFY => {
4094 if let Some(item) = stack.pop() {
4095 Ok(cast_to_bool(&item))
4096 } else {
4097 Ok(false)
4098 }
4099 }
4100
4101 OP_CHECKLOCKTIMEVERIFY => {
4105 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
4106 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
4107 Ok(true)
4108 } else {
4109 Ok(false)
4110 }
4111 }
4112
4113 OP_CHECKSEQUENCEVERIFY => {
4117 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
4118 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
4119 Ok(true)
4120 } else {
4121 Ok(false)
4122 }
4123 }
4124
4125 OP_IFDUP => {
4127 if let Some(item) = stack.last().cloned() {
4128 if cast_to_bool(&item) {
4129 stack.push(item);
4130 }
4131 Ok(true)
4132 } else {
4133 Ok(false)
4134 }
4135 }
4136
4137 OP_DROP => {
4140 if stack.pop().is_some() {
4141 Ok(true)
4142 } else {
4143 Ok(false)
4144 }
4145 }
4146
4147 OP_NIP => {
4149 if stack.len() >= 2 {
4150 let top = stack.pop().unwrap();
4151 stack.pop(); stack.push(top);
4153 Ok(true)
4154 } else {
4155 Ok(false)
4156 }
4157 }
4158
4159 OP_OVER => {
4161 if stack.len() >= 2 {
4162 let len = stack.len();
4163 #[cfg(feature = "production")]
4164 {
4165 unsafe {
4167 let second = stack.get_unchecked(len - 2);
4168 stack.push(second.clone());
4169 }
4170 }
4171 #[cfg(not(feature = "production"))]
4172 {
4173 let second = stack[stack.len() - 2].clone();
4174 stack.push(second);
4175 }
4176 Ok(true)
4177 } else {
4178 Ok(false)
4179 }
4180 }
4181
4182 OP_PICK => {
4184 if let Some(n_bytes) = stack.pop() {
4185 let n_val = script_num_decode(&n_bytes, 4)?;
4188 if n_val < 0 || n_val as usize >= stack.len() {
4189 return Ok(false);
4190 }
4191 let n = n_val as usize;
4192 let len = stack.len();
4193 #[cfg(feature = "production")]
4194 {
4195 unsafe {
4197 let item = stack.get_unchecked(len - 1 - n);
4198 stack.push(item.clone());
4199 }
4200 }
4201 #[cfg(not(feature = "production"))]
4202 {
4203 let item = stack[stack.len() - 1 - n].clone();
4204 stack.push(item);
4205 }
4206 Ok(true)
4207 } else {
4208 Ok(false)
4209 }
4210 }
4211
4212 OP_ROLL => {
4214 if let Some(n_bytes) = stack.pop() {
4215 let n_val = script_num_decode(&n_bytes, 4)?;
4218 if n_val < 0 || n_val as usize >= stack.len() {
4219 return Ok(false);
4220 }
4221 let n = n_val as usize;
4222 let len = stack.len();
4223 #[cfg(feature = "production")]
4224 {
4225 let idx = len - 1 - n;
4227 let item = stack.remove(idx);
4228 stack.push(item);
4229 }
4230 #[cfg(not(feature = "production"))]
4231 {
4232 let item = stack.remove(stack.len() - 1 - n);
4233 stack.push(item);
4234 }
4235 Ok(true)
4236 } else {
4237 Ok(false)
4238 }
4239 }
4240
4241 OP_ROT => {
4243 if stack.len() >= 3 {
4244 let top = stack.pop().unwrap();
4245 let second = stack.pop().unwrap();
4246 let third = stack.pop().unwrap();
4247 stack.push(second);
4248 stack.push(top);
4249 stack.push(third);
4250 Ok(true)
4251 } else {
4252 Ok(false)
4253 }
4254 }
4255
4256 OP_SWAP => {
4258 if stack.len() >= 2 {
4259 let top = stack.pop().unwrap();
4260 let second = stack.pop().unwrap();
4261 stack.push(top);
4262 stack.push(second);
4263 Ok(true)
4264 } else {
4265 Ok(false)
4266 }
4267 }
4268
4269 OP_TUCK => {
4271 if stack.len() >= 2 {
4272 let top = stack.pop().unwrap();
4273 let second = stack.pop().unwrap();
4274 stack.push(top.clone());
4275 stack.push(second);
4276 stack.push(top);
4277 Ok(true)
4278 } else {
4279 Ok(false)
4280 }
4281 }
4282
4283 OP_2DROP => {
4285 if stack.len() >= 2 {
4286 stack.pop();
4287 stack.pop();
4288 Ok(true)
4289 } else {
4290 Ok(false)
4291 }
4292 }
4293
4294 OP_2DUP => {
4296 if stack.len() >= 2 {
4297 let top = stack[stack.len() - 1].clone();
4298 let second = stack[stack.len() - 2].clone();
4299 stack.push(second);
4300 stack.push(top);
4301 Ok(true)
4302 } else {
4303 Ok(false)
4304 }
4305 }
4306
4307 OP_3DUP => {
4309 if stack.len() >= 3 {
4310 let top = stack[stack.len() - 1].clone();
4311 let second = stack[stack.len() - 2].clone();
4312 let third = stack[stack.len() - 3].clone();
4313 stack.push(third);
4314 stack.push(second);
4315 stack.push(top);
4316 Ok(true)
4317 } else {
4318 Ok(false)
4319 }
4320 }
4321
4322 OP_2OVER => {
4324 if stack.len() >= 4 {
4325 let fourth = stack[stack.len() - 4].clone();
4326 let third = stack[stack.len() - 3].clone();
4327 stack.push(fourth);
4328 stack.push(third);
4329 Ok(true)
4330 } else {
4331 Ok(false)
4332 }
4333 }
4334
4335 OP_2ROT => {
4338 if stack.len() >= 6 {
4339 let sixth = stack.remove(stack.len() - 6); let fifth = stack.remove(stack.len() - 5); stack.push(sixth);
4345 stack.push(fifth);
4346 Ok(true)
4347 } else {
4348 Ok(false)
4349 }
4350 }
4351
4352 OP_2SWAP => {
4354 if stack.len() >= 4 {
4355 let top = stack.pop().unwrap();
4356 let second = stack.pop().unwrap();
4357 let third = stack.pop().unwrap();
4358 let fourth = stack.pop().unwrap();
4359 stack.push(second);
4360 stack.push(top);
4361 stack.push(fourth);
4362 stack.push(third);
4363 Ok(true)
4364 } else {
4365 Ok(false)
4366 }
4367 }
4368
4369 OP_SIZE => {
4372 if let Some(item) = stack.last() {
4373 let size = item.len() as i64;
4374 stack.push(to_stack_element(&script_num_encode(size)));
4375 Ok(true)
4376 } else {
4377 Ok(false)
4378 }
4379 }
4380
4381 OP_1ADD => {
4386 if let Some(item) = stack.pop() {
4387 let a = script_num_decode(&item, 4)?;
4388 stack.push(to_stack_element(&script_num_encode(a + 1)));
4389 Ok(true)
4390 } else {
4391 Ok(false)
4392 }
4393 }
4394 OP_1SUB => {
4396 if let Some(item) = stack.pop() {
4397 let a = script_num_decode(&item, 4)?;
4398 stack.push(to_stack_element(&script_num_encode(a - 1)));
4399 Ok(true)
4400 } else {
4401 Ok(false)
4402 }
4403 }
4404 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4406 code: ScriptErrorCode::DisabledOpcode,
4407 message: "OP_2MUL is disabled".into(),
4408 }),
4409 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4411 code: ScriptErrorCode::DisabledOpcode,
4412 message: "OP_2DIV is disabled".into(),
4413 }),
4414 OP_NEGATE => {
4416 if let Some(item) = stack.pop() {
4417 let a = script_num_decode(&item, 4)?;
4418 stack.push(to_stack_element(&script_num_encode(-a)));
4419 Ok(true)
4420 } else {
4421 Ok(false)
4422 }
4423 }
4424 OP_ABS => {
4426 if let Some(item) = stack.pop() {
4427 let a = script_num_decode(&item, 4)?;
4428 stack.push(to_stack_element(&script_num_encode(a.abs())));
4429 Ok(true)
4430 } else {
4431 Ok(false)
4432 }
4433 }
4434 OP_NOT => {
4436 if let Some(item) = stack.pop() {
4437 let a = script_num_decode(&item, 4)?;
4438 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4439 1
4440 } else {
4441 0
4442 })));
4443 Ok(true)
4444 } else {
4445 Ok(false)
4446 }
4447 }
4448 OP_0NOTEQUAL => {
4450 if let Some(item) = stack.pop() {
4451 let a = script_num_decode(&item, 4)?;
4452 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4453 1
4454 } else {
4455 0
4456 })));
4457 Ok(true)
4458 } else {
4459 Ok(false)
4460 }
4461 }
4462 OP_ADD => arithmetic::op_add(stack),
4463 OP_SUB => arithmetic::op_sub(stack),
4464 OP_MUL => arithmetic::op_mul_disabled(),
4465 OP_DIV => arithmetic::op_div_disabled(),
4466 OP_MOD => arithmetic::op_mod_disabled(),
4467 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4468 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4469 OP_BOOLAND => arithmetic::op_booland(stack),
4470 OP_BOOLOR => arithmetic::op_boolor(stack),
4471 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4472 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4473 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4474 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4475 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4476 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4477 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4478 OP_MIN => arithmetic::op_min(stack),
4479 OP_MAX => arithmetic::op_max(stack),
4480 OP_WITHIN => arithmetic::op_within(stack),
4481
4482 OP_CODESEPARATOR => Ok(true),
4484
4485 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4488
4489 OP_CHECKTEMPLATEVERIFY => {
4493 const SCRIPT_VERIFY_CHECKTEMPLATEVERIFY: u32 = 0x8000;
4494 #[cfg(feature = "ctv")]
4495 if (flags & SCRIPT_VERIFY_CHECKTEMPLATEVERIFY) != 0 {
4496 return Err(ConsensusError::ScriptErrorWithCode {
4497 code: ScriptErrorCode::TxInvalid,
4498 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4499 });
4500 }
4501 Ok(true)
4502 }
4503
4504 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4506 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4507 Err(ConsensusError::ScriptErrorWithCode {
4508 code: ScriptErrorCode::DisabledOpcode,
4509 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4510 })
4511 }
4512
4513 OP_1NEGATE => {
4515 stack.push(to_stack_element(&[0x81]));
4516 Ok(true)
4517 }
4518
4519 OP_CHECKMULTISIG => {
4524 if stack.is_empty() {
4525 return Ok(false);
4526 }
4527 let n_bytes = stack.pop().unwrap();
4528 let n = match script_num_decode(&n_bytes, 4) {
4529 Ok(v) if (0..=20).contains(&v) => v as usize,
4530 _ => return Ok(false),
4531 };
4532 if stack.len() < n {
4533 return Ok(false);
4534 }
4535 for _ in 0..n {
4536 stack.pop();
4537 }
4538 if stack.is_empty() {
4539 return Ok(false);
4540 }
4541 let m_bytes = stack.pop().unwrap();
4542 let m = match script_num_decode(&m_bytes, 4) {
4543 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4544 _ => return Ok(false),
4545 };
4546 if stack.len() < m {
4547 return Ok(false);
4548 }
4549 for _ in 0..m {
4550 stack.pop();
4551 }
4552 if stack.is_empty() {
4554 return Ok(false);
4555 }
4556 stack.pop();
4557 stack.push(to_stack_element(&[if m == 0 { 1 } else { 0 }]));
4559 Ok(true)
4560 }
4561
4562 OP_CHECKMULTISIGVERIFY => {
4564 if stack.is_empty() {
4565 return Ok(false);
4566 }
4567 let n_bytes = stack.pop().unwrap();
4568 let n = match script_num_decode(&n_bytes, 4) {
4569 Ok(v) if (0..=20).contains(&v) => v as usize,
4570 _ => return Ok(false),
4571 };
4572 if stack.len() < n {
4573 return Ok(false);
4574 }
4575 for _ in 0..n {
4576 stack.pop();
4577 }
4578 if stack.is_empty() {
4579 return Ok(false);
4580 }
4581 let m_bytes = stack.pop().unwrap();
4582 let m = match script_num_decode(&m_bytes, 4) {
4583 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4584 _ => return Ok(false),
4585 };
4586 if stack.len() < m {
4587 return Ok(false);
4588 }
4589 for _ in 0..m {
4590 stack.pop();
4591 }
4592 if stack.is_empty() {
4593 return Ok(false);
4594 }
4595 stack.pop();
4596 Ok(m == 0)
4598 }
4599
4600 _ => Ok(false),
4602 }
4603}
4604
4605#[allow(dead_code)]
4607fn execute_opcode_with_context(
4608 opcode: u8,
4609 stack: &mut Vec<StackElement>,
4610 flags: u32,
4611 tx: &Transaction,
4612 input_index: usize,
4613 prevouts: &[TransactionOutput],
4614 network: crate::types::Network,
4615) -> Result<bool> {
4616 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4618 let prevout_script_pubkeys: Vec<&[u8]> =
4619 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4620 let ctx = context::ScriptContext {
4621 tx,
4622 input_index,
4623 prevout_values: &prevout_values,
4624 prevout_script_pubkeys: &prevout_script_pubkeys,
4625 block_height: None,
4626 median_time_past: None,
4627 network,
4628 sigversion: SigVersion::Base,
4629 redeem_script_for_sighash: None,
4630 script_sig_for_sighash: None,
4631 tapscript_for_sighash: None,
4632 tapscript_codesep_pos: None,
4633 #[cfg(feature = "production")]
4634 schnorr_collector: None,
4635 #[cfg(feature = "production")]
4636 precomputed_bip143: None,
4637 #[cfg(feature = "production")]
4638 sighash_cache: None,
4639 };
4640 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4641}
4642
4643#[cfg(feature = "production")]
4647#[inline(always)]
4648pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4649 let mut i = 0;
4650 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4651 i += adv1;
4652 if i >= script_sig.len() {
4653 return None;
4654 }
4655 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4656 i += adv2;
4657 if i >= script_sig.len() {
4658 return None;
4659 }
4660 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4661 i += adv3;
4662 if i != script_sig.len() {
4663 return None;
4664 }
4665 let sig = &script_sig[s_start..s_end];
4666 let redeem = &script_sig[r_start..r_end];
4667 if sig.is_empty() || redeem.len() != 25 {
4668 return None;
4669 }
4670 if redeem[0] != OP_DUP
4671 || redeem[1] != OP_HASH160
4672 || redeem[2] != PUSH_20_BYTES
4673 || redeem[23] != OP_EQUALVERIFY
4674 || redeem[24] != OP_CHECKSIG
4675 {
4676 return None;
4677 }
4678 Some((sig[sig.len() - 1], redeem))
4679}
4680
4681#[inline(always)]
4685pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4686 let mut i = 0;
4687 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4688 i += adv1;
4689 if i >= script_sig.len() {
4690 return None;
4691 }
4692 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4693 i += adv2;
4694 if i != script_sig.len() {
4695 return None;
4696 }
4697 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4698}
4699
4700pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4703 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4704 if advance != script_sig.len() {
4705 return None;
4706 }
4707 Some(&script_sig[data_start..data_end])
4708}
4709
4710fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4712 if i >= script.len() {
4713 return None;
4714 }
4715 let opcode = script[i];
4716 let (advance, data_start, data_end) = if opcode == OP_0 {
4717 return None;
4718 } else if opcode <= 0x4b {
4719 let len = opcode as usize;
4720 if i + 1 + len > script.len() {
4721 return None;
4722 }
4723 (1 + len, i + 1, i + 1 + len)
4724 } else if opcode == OP_PUSHDATA1 {
4725 if i + 1 >= script.len() {
4726 return None;
4727 }
4728 let len = script[i + 1] as usize;
4729 if i + 2 + len > script.len() {
4730 return None;
4731 }
4732 (2 + len, i + 2, i + 2 + len)
4733 } else if opcode == OP_PUSHDATA2 {
4734 if i + 2 >= script.len() {
4735 return None;
4736 }
4737 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4738 if i + 3 + len > script.len() {
4739 return None;
4740 }
4741 (3 + len, i + 3, i + 3 + len)
4742 } else if opcode == OP_PUSHDATA4 {
4743 if i + 4 >= script.len() {
4744 return None;
4745 }
4746 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4747 as usize;
4748 if i + 5 + len > script.len() {
4749 return None;
4750 }
4751 (5 + len, i + 5, i + 5 + len)
4752 } else {
4753 return None;
4754 };
4755 Some((advance, data_start, data_end))
4756}
4757
4758#[spec_locked("5.2.1", "P2SHPushOnlyCheck")]
4761pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4762 parse_script_sig_push_only(script_sig).is_some()
4763}
4764
4765fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4769 let mut out = Vec::new();
4770 let mut i = 0;
4771 while i < script_sig.len() {
4772 let opcode = script_sig[i];
4773 if !is_push_opcode(opcode) {
4774 return None;
4775 }
4776 let (advance, data) = if opcode == OP_0 {
4777 (1, vec![])
4778 } else if opcode <= 0x4b {
4779 let len = opcode as usize;
4780 if i + 1 + len > script_sig.len() {
4781 return None;
4782 }
4783 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4784 } else if opcode == OP_PUSHDATA1 {
4785 if i + 1 >= script_sig.len() {
4786 return None;
4787 }
4788 let len = script_sig[i + 1] as usize;
4789 if i + 2 + len > script_sig.len() {
4790 return None;
4791 }
4792 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4793 } else if opcode == OP_PUSHDATA2 {
4794 if i + 2 >= script_sig.len() {
4795 return None;
4796 }
4797 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4798 if i + 3 + len > script_sig.len() {
4799 return None;
4800 }
4801 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4802 } else if opcode == OP_PUSHDATA4 {
4803 if i + 4 >= script_sig.len() {
4804 return None;
4805 }
4806 let len = u32::from_le_bytes([
4807 script_sig[i + 1],
4808 script_sig[i + 2],
4809 script_sig[i + 3],
4810 script_sig[i + 4],
4811 ]) as usize;
4812 if i + 5 + len > script_sig.len() {
4813 return None;
4814 }
4815 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4816 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4817 let n = script_num_from_opcode(opcode);
4819 (1, script_num_encode(n))
4820 } else {
4821 return None;
4822 };
4823 out.push(to_stack_element(&data));
4824 i += advance;
4825 }
4826 Some(out)
4827}
4828
4829fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4833 parse_script_sig_push_only(script_sig)
4834}
4835
4836fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
4841 if redeem.len() < 4 {
4842 return None;
4843 }
4844 let n_op = redeem[0];
4845 if !(OP_1..=OP_16).contains(&n_op) {
4846 return None;
4847 }
4848 let n = (n_op - OP_1 + 1) as usize;
4849 let mut i = 1;
4850 let mut pubkeys = Vec::with_capacity(n);
4851 for _ in 0..n {
4852 if i >= redeem.len() {
4853 return None;
4854 }
4855 let first = redeem[i];
4856 let pk_len = if first == 0x02 || first == 0x03 {
4857 33
4858 } else if first == 0x04 {
4859 65
4860 } else {
4861 return None;
4862 };
4863 if i + pk_len > redeem.len() {
4864 return None;
4865 }
4866 pubkeys.push(&redeem[i..i + pk_len]);
4867 i += pk_len;
4868 }
4869 if i + 2 > redeem.len() {
4870 return None;
4871 }
4872 let m_op = redeem[i];
4873 if !(OP_1..=OP_16).contains(&m_op) {
4874 return None;
4875 }
4876 let m = m_op - OP_1 + 1;
4877 if redeem[i + 1] != OP_CHECKMULTISIG {
4878 return None;
4879 }
4880 Some((m, n as u8, pubkeys))
4881}
4882
4883fn script_num_from_opcode(opcode: u8) -> i64 {
4885 match opcode {
4886 OP_1NEGATE => -1,
4887 OP_1 => 1,
4888 OP_2 => 2,
4889 OP_3 => 3,
4890 OP_4 => 4,
4891 OP_5 => 5,
4892 OP_6 => 6,
4893 OP_7 => 7,
4894 OP_8 => 8,
4895 OP_9 => 9,
4896 OP_10 => 10,
4897 OP_11 => 11,
4898 OP_12 => 12,
4899 OP_13 => 13,
4900 OP_14 => 14,
4901 OP_15 => 15,
4902 OP_16 => 16,
4903 _ => 0,
4904 }
4905}
4906
4907pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
4911 let len = data.len();
4912 let mut result = Vec::with_capacity(len + 5);
4913 if len < 76 {
4914 result.push(len as u8);
4915 } else if len < 256 {
4916 result.push(OP_PUSHDATA1);
4917 result.push(len as u8);
4918 } else if len < 65536 {
4919 result.push(OP_PUSHDATA2);
4920 result.push((len & 0xff) as u8);
4921 result.push(((len >> 8) & 0xff) as u8);
4922 } else {
4923 result.push(OP_PUSHDATA4);
4924 result.push((len & 0xff) as u8);
4925 result.push(((len >> 8) & 0xff) as u8);
4926 result.push(((len >> 16) & 0xff) as u8);
4927 result.push(((len >> 24) & 0xff) as u8);
4928 }
4929 result.extend_from_slice(data);
4930 result
4931}
4932
4933#[inline]
4935fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
4936 if pc >= script.len() {
4937 return None;
4938 }
4939 let opcode = script[pc];
4940 let advance = if opcode <= 0x4b {
4941 1 + opcode as usize
4942 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
4943 2 + script[pc + 1] as usize
4944 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
4945 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
4946 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
4947 5 + ((script[pc + 1] as usize)
4948 | ((script[pc + 2] as usize) << 8)
4949 | ((script[pc + 3] as usize) << 16)
4950 | ((script[pc + 4] as usize) << 24))
4951 } else {
4952 1
4953 };
4954 let next = pc + advance;
4955 if next > script.len() {
4956 None
4957 } else {
4958 Some(next)
4959 }
4960}
4961
4962#[spec_locked("5.1.1", "FindAndDelete")]
4968#[inline]
4969pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
4970 if pattern.is_empty() {
4971 return std::borrow::Cow::Borrowed(script);
4972 }
4973 if pattern.len() > script.len() {
4974 return std::borrow::Cow::Borrowed(script);
4975 }
4976 if !script.windows(pattern.len()).any(|w| w == pattern) {
4981 return std::borrow::Cow::Borrowed(script);
4982 }
4983 let end = script.len();
4984 let mut n_found = 0usize;
4985 let mut result = Vec::new();
4986 let mut pc = 0usize;
4987 let mut pc2 = 0usize;
4988
4989 loop {
4990 result.extend_from_slice(&script[pc2..pc]);
4991 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
4992 pc += pattern.len();
4993 n_found += 1;
4994 }
4995 pc2 = pc;
4996 if pc >= end {
4997 break;
4998 }
4999 let Some(next_pc) = script_get_op_advance(script, pc) else {
5000 break;
5001 };
5002 pc = next_pc;
5003 }
5004
5005 if n_found > 0 {
5006 result.extend_from_slice(&script[pc2..end]);
5007 std::borrow::Cow::Owned(result)
5008 } else {
5009 std::borrow::Cow::Borrowed(script)
5010 }
5011}
5012
5013fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
5015 let mut pos = 0u32;
5016 let mut i = 0usize;
5017 while i < script.len() && i <= byte_index {
5018 let opcode = script[i];
5019 let advance = if opcode <= 0x4b {
5020 1 + opcode as usize
5021 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
5022 2 + script[i + 1] as usize
5023 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
5024 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
5025 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
5026 5 + ((script[i + 1] as usize)
5027 | ((script[i + 2] as usize) << 8)
5028 | ((script[i + 3] as usize) << 16)
5029 | ((script[i + 4] as usize) << 24))
5030 } else {
5031 1
5032 };
5033 if i == byte_index {
5034 return pos;
5035 }
5036 pos += 1;
5037 i = std::cmp::min(i + advance, script.len());
5038 }
5039 0xffff_ffff
5040}
5041
5042#[cfg_attr(feature = "production", inline(always))]
5044fn execute_opcode_with_context_full(
5045 opcode: u8,
5046 stack: &mut Vec<StackElement>,
5047 flags: u32,
5048 ctx: &context::ScriptContext<'_>,
5049 effective_script_code: Option<&[u8]>,
5050) -> Result<bool> {
5051 let tx = ctx.tx;
5052 let input_index = ctx.input_index;
5053 let prevout_values = ctx.prevout_values;
5054 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
5055 let block_height = ctx.block_height;
5056 let median_time_past = ctx.median_time_past;
5057 let network = ctx.network;
5058 let sigversion = ctx.sigversion;
5059 let script_sig_for_sighash = ctx.script_sig_for_sighash;
5060 let tapscript_for_sighash = ctx.tapscript_for_sighash;
5061 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
5062 let redeem_script_for_sighash = effective_script_code;
5063 #[cfg(feature = "production")]
5064 let schnorr_collector = ctx.schnorr_collector;
5065 #[cfg(feature = "production")]
5066 let precomputed_bip143 = ctx.precomputed_bip143;
5067 #[cfg(feature = "production")]
5068 let sighash_cache = ctx.sighash_cache;
5069
5070 match opcode {
5072 OP_CHECKSIG => {
5074 if stack.len() >= 2 {
5075 let pubkey_bytes = stack.pop().unwrap();
5076 let signature_bytes = stack.pop().unwrap();
5077
5078 if signature_bytes.is_empty() {
5080 stack.push(to_stack_element(&[0]));
5081 return Ok(true);
5082 }
5083
5084 if sigversion == SigVersion::Tapscript {
5087 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
5089 let sighash_byte = 0x00;
5090 let (tapscript, codesep_pos) = tapscript_for_sighash
5091 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5092 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5093 let sighash = if tapscript.is_empty() {
5094 crate::taproot::compute_taproot_signature_hash(
5095 tx,
5096 input_index,
5097 prevout_values,
5098 prevout_script_pubkeys,
5099 sighash_byte,
5100 )?
5101 } else {
5102 crate::taproot::compute_tapscript_signature_hash(
5103 tx,
5104 input_index,
5105 prevout_values,
5106 prevout_script_pubkeys,
5107 tapscript,
5108 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5109 codesep_pos,
5110 sighash_byte,
5111 )?
5112 };
5113
5114 #[cfg(feature = "production")]
5116 let is_valid = {
5117 use crate::bip348::verify_tapscript_schnorr_signature;
5118 verify_tapscript_schnorr_signature(
5119 &sighash,
5120 &pubkey_bytes,
5121 &signature_bytes,
5122 schnorr_collector,
5123 )
5124 .unwrap_or(false)
5125 };
5126
5127 #[cfg(not(feature = "production"))]
5128 let is_valid = {
5129 #[cfg(feature = "csfs")]
5130 let x = {
5131 use crate::bip348::verify_tapscript_schnorr_signature;
5132 verify_tapscript_schnorr_signature(
5133 &sighash,
5134 &pubkey_bytes,
5135 &signature_bytes,
5136 None,
5137 )
5138 .unwrap_or(false)
5139 };
5140 #[cfg(not(feature = "csfs"))]
5141 let x = false;
5142 x
5143 };
5144
5145 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5146 return Ok(true);
5147 }
5148 }
5150
5151 let sig_len = signature_bytes.len();
5155 let sighash_byte = signature_bytes[sig_len - 1];
5156 let _der_sig = &signature_bytes[..sig_len - 1];
5157
5158 let sighash = if sigversion == SigVersion::WitnessV0 {
5162 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5164
5165 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5167 prevout_script_pubkeys
5168 .get(input_index)
5169 .copied()
5170 .unwrap_or(&[])
5171 });
5172
5173 crate::transaction_hash::calculate_bip143_sighash(
5174 tx,
5175 input_index,
5176 script_code,
5177 amount,
5178 sighash_byte,
5179 precomputed_bip143,
5180 )?
5181 } else {
5182 use crate::transaction_hash::{
5184 calculate_transaction_sighash_single_input, SighashType,
5185 };
5186 let sighash_type = SighashType::from_byte(sighash_byte);
5187
5188 let pattern = serialize_push_data(signature_bytes.as_ref());
5192
5193 let base_script = match (
5194 redeem_script_for_sighash,
5195 prevout_script_pubkeys.get(input_index),
5196 ) {
5197 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5198 (Some(redeem), _) => redeem,
5199 (None, Some(prevout)) => *prevout,
5200 (None, None) => &[],
5201 };
5202 let cleaned = find_and_delete(base_script, &pattern);
5203
5204 calculate_transaction_sighash_single_input(
5205 tx,
5206 input_index,
5207 cleaned.as_ref(),
5208 prevout_values[input_index],
5209 sighash_type,
5210 #[cfg(feature = "production")]
5211 sighash_cache,
5212 )?
5213 };
5214
5215 let height = block_height.unwrap_or(0);
5219 #[cfg(feature = "production")]
5220 let is_valid = signature::with_secp_context(|secp| {
5221 signature::verify_signature(
5222 secp,
5223 &pubkey_bytes,
5224 &signature_bytes, &sighash,
5226 flags,
5227 height,
5228 network,
5229 sigversion,
5230 )
5231 })?;
5232
5233 #[cfg(not(feature = "production"))]
5234 let is_valid = {
5235 let secp = signature::new_secp();
5236 signature::verify_signature(
5237 &secp,
5238 &pubkey_bytes,
5239 &signature_bytes, &sighash,
5241 flags,
5242 height,
5243 network,
5244 sigversion,
5245 )?
5246 };
5247
5248 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5249 Ok(true)
5250 } else {
5251 Ok(false)
5252 }
5253 }
5254
5255 OP_CHECKSIGVERIFY => {
5257 if stack.len() >= 2 {
5258 let pubkey_bytes = stack.pop().unwrap();
5259 let signature_bytes = stack.pop().unwrap();
5260
5261 if signature_bytes.is_empty() {
5263 return Ok(false);
5264 }
5265
5266 if sigversion == SigVersion::Tapscript {
5268 if signature_bytes.len() == 64 && pubkey_bytes.len() == 32 {
5269 let sighash_byte = 0x00u8;
5270 let (tapscript, codesep_pos) = tapscript_for_sighash
5271 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5272 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5273 let sighash = if tapscript.is_empty() {
5274 crate::taproot::compute_taproot_signature_hash(
5275 tx,
5276 input_index,
5277 prevout_values,
5278 prevout_script_pubkeys,
5279 sighash_byte,
5280 )?
5281 } else {
5282 crate::taproot::compute_tapscript_signature_hash(
5283 tx,
5284 input_index,
5285 prevout_values,
5286 prevout_script_pubkeys,
5287 tapscript,
5288 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5289 codesep_pos,
5290 sighash_byte,
5291 )?
5292 };
5293 #[cfg(feature = "production")]
5294 let is_valid = {
5295 use crate::bip348::verify_tapscript_schnorr_signature;
5296 verify_tapscript_schnorr_signature(
5297 &sighash,
5298 &pubkey_bytes,
5299 &signature_bytes,
5300 schnorr_collector,
5301 )
5302 .unwrap_or(false)
5303 };
5304 #[cfg(not(feature = "production"))]
5305 let is_valid = {
5306 #[cfg(feature = "csfs")]
5307 let x = {
5308 use crate::bip348::verify_tapscript_schnorr_signature;
5309 verify_tapscript_schnorr_signature(
5310 &sighash,
5311 &pubkey_bytes,
5312 &signature_bytes,
5313 None,
5314 )
5315 .unwrap_or(false)
5316 };
5317 #[cfg(not(feature = "csfs"))]
5318 let x = false;
5319 x
5320 };
5321 if !is_valid {
5322 return Ok(false); }
5324 return Ok(true);
5325 }
5326 return Ok(false);
5328 }
5329
5330 let sig_len = signature_bytes.len();
5333 let sighash_byte = signature_bytes[sig_len - 1];
5334 let _der_sig = &signature_bytes[..sig_len - 1];
5335
5336 let sighash = if sigversion == SigVersion::WitnessV0 {
5340 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5342
5343 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5344 prevout_script_pubkeys
5345 .get(input_index)
5346 .copied()
5347 .unwrap_or(&[])
5348 });
5349
5350 crate::transaction_hash::calculate_bip143_sighash(
5351 tx,
5352 input_index,
5353 script_code,
5354 amount,
5355 sighash_byte,
5356 precomputed_bip143,
5357 )?
5358 } else {
5359 use crate::transaction_hash::{
5361 calculate_transaction_sighash_single_input, SighashType,
5362 };
5363 let sighash_type = SighashType::from_byte(sighash_byte);
5364
5365 let pattern = serialize_push_data(signature_bytes.as_ref());
5367
5368 let base_script = match (
5369 redeem_script_for_sighash,
5370 prevout_script_pubkeys.get(input_index),
5371 ) {
5372 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5373 (Some(redeem), _) => redeem,
5374 (None, Some(prevout)) => *prevout,
5375 (None, None) => &[],
5376 };
5377 let cleaned = find_and_delete(base_script, &pattern);
5378
5379 calculate_transaction_sighash_single_input(
5380 tx,
5381 input_index,
5382 cleaned.as_ref(),
5383 prevout_values[input_index],
5384 sighash_type,
5385 #[cfg(feature = "production")]
5386 sighash_cache,
5387 )?
5388 };
5389
5390 let height = block_height.unwrap_or(0);
5394 #[cfg(feature = "production")]
5395 let is_valid = signature::with_secp_context(|secp| {
5396 signature::verify_signature(
5397 secp,
5398 &pubkey_bytes,
5399 &signature_bytes, &sighash,
5401 flags,
5402 height,
5403 network,
5404 sigversion,
5405 )
5406 })?;
5407
5408 #[cfg(not(feature = "production"))]
5409 let is_valid = {
5410 let secp = signature::new_secp();
5411 signature::verify_signature(
5412 &secp,
5413 &pubkey_bytes,
5414 &signature_bytes, &sighash,
5416 flags,
5417 height,
5418 network,
5419 sigversion,
5420 )?
5421 };
5422
5423 if is_valid {
5424 Ok(true)
5425 } else {
5426 Ok(false)
5427 }
5428 } else {
5429 Ok(false)
5430 }
5431 }
5432
5433 OP_CHECKSIGADD => {
5435 if sigversion != SigVersion::Tapscript {
5436 return Err(ConsensusError::ScriptErrorWithCode {
5437 code: ScriptErrorCode::DisabledOpcode,
5438 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5439 });
5440 }
5441 if stack.len() < 3 {
5442 return Err(ConsensusError::ScriptErrorWithCode {
5443 code: ScriptErrorCode::InvalidStackOperation,
5444 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5445 });
5446 }
5447 let pubkey_bytes = stack.pop().unwrap();
5449 let n_bytes = stack.pop().unwrap();
5450 let signature_bytes = stack.pop().unwrap();
5451 let n = script_num_decode(&n_bytes, 4)?;
5452
5453 if signature_bytes.is_empty() {
5455 stack.push(to_stack_element(&script_num_encode(n)));
5456 return Ok(true);
5457 }
5458
5459 if pubkey_bytes.len() == 32 && signature_bytes.len() == 64 {
5461 let sighash_byte = 0x00;
5462 let (tapscript, codesep_pos) = tapscript_for_sighash
5463 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5464 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5465 let sighash = if tapscript.is_empty() {
5466 crate::taproot::compute_taproot_signature_hash(
5467 tx,
5468 input_index,
5469 prevout_values,
5470 prevout_script_pubkeys,
5471 sighash_byte,
5472 )?
5473 } else {
5474 crate::taproot::compute_tapscript_signature_hash(
5475 tx,
5476 input_index,
5477 prevout_values,
5478 prevout_script_pubkeys,
5479 tapscript,
5480 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5481 codesep_pos,
5482 sighash_byte,
5483 )?
5484 };
5485
5486 #[cfg(feature = "production")]
5487 let is_valid = {
5488 use crate::bip348::verify_tapscript_schnorr_signature;
5489 verify_tapscript_schnorr_signature(
5490 &sighash,
5491 &pubkey_bytes,
5492 &signature_bytes,
5493 schnorr_collector,
5494 )
5495 .unwrap_or(false)
5496 };
5497
5498 #[cfg(not(feature = "production"))]
5499 let is_valid = {
5500 #[cfg(feature = "csfs")]
5501 let x = {
5502 use crate::bip348::verify_tapscript_schnorr_signature;
5503 verify_tapscript_schnorr_signature(
5504 &sighash,
5505 &pubkey_bytes,
5506 &signature_bytes,
5507 None,
5508 )
5509 .unwrap_or(false)
5510 };
5511 #[cfg(not(feature = "csfs"))]
5512 let x = false;
5513 x
5514 };
5515
5516 if !is_valid {
5517 return Ok(false); }
5519 stack.push(to_stack_element(&script_num_encode(n + 1)));
5520 return Ok(true);
5521 }
5522
5523 stack.push(to_stack_element(&script_num_encode(n + 1)));
5525 Ok(true)
5526 }
5527
5528 OP_CHECKMULTISIG => {
5530 if stack.len() < 2 {
5533 return Ok(false);
5534 }
5535
5536 let n_bytes = stack.pop().unwrap();
5538 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
5539 ConsensusError::ScriptErrorWithCode {
5540 code: ScriptErrorCode::InvalidStackOperation,
5541 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
5542 }
5543 })?;
5544 if !(0..=20).contains(&n_raw) {
5545 return Ok(false);
5546 }
5547 let n = n_raw as usize;
5548 if stack.len() < n + 1 {
5549 return Ok(false);
5550 }
5551
5552 let mut pubkeys = Vec::with_capacity(n);
5554 for _ in 0..n {
5555 pubkeys.push(stack.pop().unwrap());
5556 }
5557
5558 let m_bytes = stack.pop().unwrap();
5560 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
5561 ConsensusError::ScriptErrorWithCode {
5562 code: ScriptErrorCode::InvalidStackOperation,
5563 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
5564 }
5565 })?;
5566 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
5567 return Ok(false);
5568 }
5569 let m = m_raw as usize;
5570 if stack.len() < m + 1 {
5571 return Ok(false);
5572 }
5573
5574 let mut signatures = Vec::with_capacity(m);
5576 for _ in 0..m {
5577 signatures.push(stack.pop().unwrap());
5578 }
5579
5580 let dummy = stack.pop().unwrap();
5583 if flags & 0x10 != 0 {
5584 let height = block_height.unwrap_or(0);
5585 use crate::bip_validation::Bip147Network;
5587 let bip147_network = match network {
5588 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5589 crate::types::Network::Testnet => Bip147Network::Testnet,
5590 crate::types::Network::Regtest => Bip147Network::Regtest,
5591 };
5592
5593 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5597
5598 let bip147_active = height
5599 >= match bip147_network {
5600 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5601 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5602 Bip147Network::Regtest => 0,
5603 };
5604
5605 if bip147_active {
5606 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5610 if !is_empty {
5611 return Err(ConsensusError::ScriptErrorWithCode {
5612 code: ScriptErrorCode::SigNullDummy,
5613 message: format!(
5614 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5615 )
5616 .into(),
5617 });
5618 }
5619 }
5620 }
5621
5622 let height = block_height.unwrap_or(0);
5625
5626 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5629 let base_script = match (
5630 redeem_script_for_sighash,
5631 prevout_script_pubkeys.get(input_index),
5632 ) {
5633 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5634 (Some(redeem), _) => redeem,
5635 (None, Some(prevout)) => *prevout,
5636 (None, None) => &[],
5637 };
5638 let mut cleaned = base_script.to_vec();
5639 for sig in &signatures {
5640 if !sig.is_empty() {
5641 let pattern = serialize_push_data(sig.as_ref());
5642 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5643 }
5644 }
5645 cleaned
5646 } else {
5647 redeem_script_for_sighash
5649 .map(|s| s.to_vec())
5650 .unwrap_or_else(|| {
5651 prevout_script_pubkeys
5652 .get(input_index)
5653 .map(|p| p.to_vec())
5654 .unwrap_or_default()
5655 })
5656 };
5657
5658 use crate::transaction_hash::{
5659 calculate_transaction_sighash_single_input, SighashType,
5660 };
5661
5662 #[cfg(feature = "production")]
5664 let use_batch = pubkeys.len() * signatures.len() >= 4;
5665
5666 #[cfg(feature = "production")]
5667 let (valid_sigs, _) = if use_batch {
5668 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5670 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5671 if non_empty.is_empty() {
5672 vec![]
5673 } else {
5674 let specs: Vec<(usize, u8, &[u8])> = non_empty
5675 .iter()
5676 .map(|s| {
5677 (
5678 input_index,
5679 s.as_ref()[s.as_ref().len() - 1],
5680 cleaned_script_for_multisig.as_ref(),
5681 )
5682 })
5683 .collect();
5684 crate::transaction_hash::batch_compute_legacy_sighashes(
5685 tx,
5686 prevout_values,
5687 prevout_script_pubkeys,
5688 &specs,
5689 )?
5690 }
5691 } else {
5692 signatures
5693 .iter()
5694 .filter(|s| !s.is_empty())
5695 .map(|sig_bytes| {
5696 let sighash_type =
5697 SighashType::from_byte(sig_bytes[sig_bytes.len() - 1]);
5698 calculate_transaction_sighash_single_input(
5699 tx,
5700 input_index,
5701 &cleaned_script_for_multisig,
5702 prevout_values[input_index],
5703 sighash_type,
5704 sighash_cache,
5705 )
5706 })
5707 .collect::<Result<Vec<_>>>()?
5708 };
5709
5710 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5712 Vec::with_capacity(pubkeys.len() * signatures.len());
5713 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5714 let mut sighash_idx = 0usize;
5715 for (j, sig_bytes) in signatures.iter().enumerate() {
5716 if sig_bytes.is_empty() {
5717 sig_idx_to_sighash_idx.push(usize::MAX);
5718 } else {
5719 sig_idx_to_sighash_idx.push(sighash_idx);
5720 let sh = sighashes[sighash_idx];
5721 sighash_idx += 1;
5722 for pubkey_bytes in &pubkeys {
5723 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5724 }
5725 }
5726 }
5727
5728 let results = if tasks.is_empty() {
5729 vec![]
5730 } else {
5731 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
5732 };
5733
5734 let mut sig_index = 0;
5736 let mut valid_sigs = 0usize;
5737 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5738 if sig_index >= signatures.len() {
5739 break;
5740 }
5741 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5743 sig_index += 1;
5744 }
5745 if sig_index >= signatures.len() {
5746 break;
5747 }
5748 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5749 if sh_idx == usize::MAX {
5750 continue;
5751 }
5752 let task_idx = sh_idx * pubkeys.len() + i;
5753 if task_idx < results.len() && results[task_idx] {
5754 valid_sigs += 1;
5755 sig_index += 1;
5756 }
5757 }
5758
5759 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5761 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5762 for (j, sig_bytes) in signatures.iter().enumerate() {
5763 if sig_bytes.is_empty() {
5764 continue;
5765 }
5766 let sh_idx = sig_idx_to_sighash_idx[j];
5767 if sh_idx == usize::MAX {
5768 continue;
5769 }
5770 let sig_start = sh_idx * pubkeys.len();
5771 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5772 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5773 if !matched {
5774 return Err(ConsensusError::ScriptErrorWithCode {
5775 code: ScriptErrorCode::SigNullFail,
5776 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5777 });
5778 }
5779 }
5780 }
5781 (valid_sigs, ())
5782 } else {
5783 let mut sig_index = 0;
5784 let mut valid_sigs = 0;
5785
5786 for pubkey_bytes in &pubkeys {
5787 if sig_index >= signatures.len() {
5788 break;
5789 }
5790
5791 let signature_bytes = &signatures[sig_index];
5792
5793 if signature_bytes.is_empty() {
5794 continue;
5795 }
5796
5797 let sig_len = signature_bytes.len();
5798 let sighash_byte = signature_bytes[sig_len - 1];
5799 let sighash_type = SighashType::from_byte(sighash_byte);
5800
5801 let sighash = calculate_transaction_sighash_single_input(
5802 tx,
5803 input_index,
5804 &cleaned_script_for_multisig,
5805 prevout_values[input_index],
5806 sighash_type,
5807 #[cfg(feature = "production")]
5808 sighash_cache,
5809 )?;
5810
5811 #[cfg(feature = "production")]
5812 let is_valid = signature::with_secp_context(|secp| {
5813 signature::verify_signature(
5814 secp,
5815 pubkey_bytes,
5816 signature_bytes,
5817 &sighash,
5818 flags,
5819 height,
5820 network,
5821 sigversion,
5822 )
5823 })?;
5824
5825 #[cfg(not(feature = "production"))]
5826 let is_valid = {
5827 let secp = signature::new_secp();
5828 signature::verify_signature(
5829 &secp,
5830 pubkey_bytes,
5831 signature_bytes,
5832 &sighash,
5833 flags,
5834 height,
5835 network,
5836 sigversion,
5837 )?
5838 };
5839
5840 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5841 if !is_valid
5842 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5843 && !signature_bytes.is_empty()
5844 {
5845 return Err(ConsensusError::ScriptErrorWithCode {
5846 code: ScriptErrorCode::SigNullFail,
5847 message:
5848 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5849 .into(),
5850 });
5851 }
5852
5853 if is_valid {
5854 valid_sigs += 1;
5855 sig_index += 1;
5856 }
5857 }
5858 (valid_sigs, ())
5859 };
5860
5861 #[cfg(not(feature = "production"))]
5862 let (valid_sigs, _) = {
5863 let mut sig_index = 0;
5864 let mut valid_sigs = 0;
5865
5866 for pubkey_bytes in &pubkeys {
5867 if sig_index >= signatures.len() {
5868 break;
5869 }
5870 let signature_bytes = &signatures[sig_index];
5871 if signature_bytes.is_empty() {
5872 continue;
5873 }
5874 let sig_len = signature_bytes.len();
5875 let sighash_type = SighashType::from_byte(signature_bytes[sig_len - 1]);
5876 let sighash = calculate_transaction_sighash_single_input(
5877 tx,
5878 input_index,
5879 &cleaned_script_for_multisig,
5880 prevout_values[input_index],
5881 sighash_type,
5882 #[cfg(feature = "production")]
5883 sighash_cache,
5884 )?;
5885 let secp = signature::new_secp();
5886 let is_valid = signature::verify_signature(
5887 &secp,
5888 pubkey_bytes,
5889 signature_bytes,
5890 &sighash,
5891 flags,
5892 height,
5893 network,
5894 sigversion,
5895 )?;
5896 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5897 if !is_valid
5898 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
5899 && !signature_bytes.is_empty()
5900 {
5901 return Err(ConsensusError::ScriptErrorWithCode {
5902 code: ScriptErrorCode::SigNullFail,
5903 message:
5904 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
5905 .into(),
5906 });
5907 }
5908 if is_valid {
5909 valid_sigs += 1;
5910 sig_index += 1;
5911 }
5912 }
5913 (valid_sigs, ())
5914 };
5915
5916 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
5918 Ok(true)
5919 }
5920
5921 OP_CHECKMULTISIGVERIFY => {
5923 let ctx_checkmultisig = context::ScriptContext {
5925 tx,
5926 input_index,
5927 prevout_values,
5928 prevout_script_pubkeys,
5929 block_height,
5930 median_time_past,
5931 network,
5932 sigversion,
5933 redeem_script_for_sighash,
5934 script_sig_for_sighash,
5935 tapscript_for_sighash,
5936 tapscript_codesep_pos,
5937 #[cfg(feature = "production")]
5938 schnorr_collector: None,
5939 #[cfg(feature = "production")]
5940 precomputed_bip143,
5941 #[cfg(feature = "production")]
5942 sighash_cache,
5943 };
5944 let result = execute_opcode_with_context_full(
5945 OP_CHECKMULTISIG,
5946 stack,
5947 flags,
5948 &ctx_checkmultisig,
5949 redeem_script_for_sighash,
5950 )?;
5951 if !result {
5952 return Ok(false);
5953 }
5954 if let Some(top) = stack.pop() {
5956 if !cast_to_bool(&top) {
5957 return Ok(false);
5958 }
5959 Ok(true)
5960 } else {
5961 Ok(false)
5962 }
5963 }
5964
5965 OP_CHECKLOCKTIMEVERIFY => {
5970 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
5972 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5973 return Ok(true);
5974 }
5975
5976 use crate::locktime::{check_bip65, decode_locktime_value};
5977
5978 if stack.is_empty() {
5979 return Err(ConsensusError::ScriptErrorWithCode {
5980 code: ScriptErrorCode::InvalidStackOperation,
5981 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
5982 });
5983 }
5984
5985 let locktime_bytes = stack.last().expect("Stack is not empty");
5987 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
5988 Some(v) => v,
5989 None => {
5990 return Err(ConsensusError::ScriptErrorWithCode {
5991 code: ScriptErrorCode::MinimalData,
5992 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
5993 })
5994 }
5995 };
5996
5997 let tx_locktime = tx.lock_time as u32;
5998
5999 if !check_bip65(tx_locktime, locktime_value) {
6001 return Ok(false);
6002 }
6003
6004 let input_seq = if input_index < tx.inputs.len() {
6006 tx.inputs[input_index].sequence
6007 } else {
6008 0xffffffff
6009 };
6010 if input_seq == 0xffffffff {
6011 return Ok(false);
6012 }
6013
6014 Ok(true)
6016 }
6017
6018 OP_CHECKSEQUENCEVERIFY => {
6027 use crate::locktime::{
6028 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
6029 is_sequence_disabled,
6030 };
6031
6032 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
6034 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
6035 return Ok(true);
6036 }
6037
6038 if stack.is_empty() {
6039 return Ok(false);
6040 }
6041
6042 let sequence_bytes = stack.last().expect("Stack is not empty");
6045 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
6046 Some(v) => v,
6047 None => return Ok(false), };
6049
6050 if input_index >= tx.inputs.len() {
6052 return Ok(false);
6053 }
6054 let input_sequence = tx.inputs[input_index].sequence as u32;
6055
6056 if is_sequence_disabled(input_sequence) {
6058 return Ok(true);
6059 }
6060
6061 let type_flag = extract_sequence_type_flag(sequence_value);
6063 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
6064
6065 let input_type_flag = extract_sequence_type_flag(input_sequence);
6067 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
6068
6069 if type_flag != input_type_flag {
6071 return Ok(false);
6072 }
6073
6074 if input_locktime < locktime_mask {
6076 return Ok(false);
6077 }
6078
6079 Ok(true)
6081 }
6082
6083 OP_CHECKTEMPLATEVERIFY => {
6092 #[cfg(not(feature = "ctv"))]
6093 {
6094 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6096 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6097 return Err(ConsensusError::ScriptErrorWithCode {
6098 code: ScriptErrorCode::BadOpcode,
6099 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
6100 });
6101 }
6102 Ok(true) }
6104
6105 #[cfg(feature = "ctv")]
6106 {
6107 use crate::constants::{
6108 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
6109 };
6110
6111 let ctv_activation = match network {
6113 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
6114 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
6115 crate::types::Network::Regtest => CTV_ACTIVATION_REGTEST,
6116 };
6117
6118 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
6119 if !ctv_active {
6120 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6122 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6123 return Err(ConsensusError::ScriptErrorWithCode {
6124 code: ScriptErrorCode::BadOpcode,
6125 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
6126 });
6127 }
6128 return Ok(true); }
6130
6131 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
6133 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
6134 return Ok(true);
6136 }
6137
6138 use crate::bip119::calculate_template_hash;
6139
6140 if stack.is_empty() {
6142 return Err(ConsensusError::ScriptErrorWithCode {
6143 code: ScriptErrorCode::InvalidStackOperation,
6144 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
6145 });
6146 }
6147
6148 let template_hash_bytes = stack.pop().unwrap();
6149
6150 if template_hash_bytes.len() != 32 {
6152 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6155 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6156 return Err(ConsensusError::ScriptErrorWithCode {
6157 code: ScriptErrorCode::InvalidStackOperation,
6158 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
6159 .into(),
6160 });
6161 }
6162 return Ok(true); }
6164
6165 let mut expected_hash = [0u8; 32];
6167 expected_hash.copy_from_slice(&template_hash_bytes);
6168
6169 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
6170 ConsensusError::ScriptErrorWithCode {
6171 code: ScriptErrorCode::TxInvalid,
6172 message: format!("CTV hash calculation failed: {e}").into(),
6173 }
6174 })?;
6175
6176 use crate::crypto::hash_compare::hash_eq;
6178 let matches = hash_eq(&expected_hash, &actual_hash);
6179
6180 if !matches {
6181 return Ok(false); }
6183
6184 Ok(true)
6186 }
6187 }
6188
6189 OP_CHECKSIGFROMSTACK => {
6200 #[cfg(not(feature = "csfs"))]
6201 {
6202 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6205 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6206 return Err(ConsensusError::ScriptErrorWithCode {
6207 code: ScriptErrorCode::BadOpcode,
6208 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
6209 });
6210 }
6211 Ok(true) }
6213
6214 #[cfg(feature = "csfs")]
6215 {
6216 use crate::constants::{
6217 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
6218 };
6219
6220 if sigversion != SigVersion::Tapscript {
6222 return Err(ConsensusError::ScriptErrorWithCode {
6223 code: ScriptErrorCode::BadOpcode,
6224 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
6225 });
6226 }
6227
6228 let csfs_activation = match network {
6230 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
6231 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
6232 crate::types::Network::Regtest => CSFS_ACTIVATION_REGTEST,
6233 };
6234
6235 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
6236 if !csfs_active {
6237 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6239 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6240 return Err(ConsensusError::ScriptErrorWithCode {
6241 code: ScriptErrorCode::BadOpcode,
6242 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
6243 });
6244 }
6245 return Ok(true); }
6247
6248 use crate::bip348::verify_signature_from_stack;
6249
6250 if stack.len() < 3 {
6252 return Err(ConsensusError::ScriptErrorWithCode {
6253 code: ScriptErrorCode::InvalidStackOperation,
6254 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
6255 });
6256 }
6257
6258 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
6265 return Err(ConsensusError::ScriptErrorWithCode {
6266 code: ScriptErrorCode::PubkeyType,
6267 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
6268 });
6269 }
6270
6271 if signature_bytes.is_empty() {
6273 stack.push(to_stack_element(&[])); return Ok(true);
6275 }
6276
6277 #[cfg(feature = "production")]
6280 let is_valid = {
6281 verify_signature_from_stack(
6282 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6287 .unwrap_or(false)
6288 };
6289 #[cfg(not(feature = "production"))]
6290 let is_valid = verify_signature_from_stack(
6291 &message_bytes, &pubkey_bytes, &signature_bytes, )
6295 .unwrap_or(false);
6296
6297 if !is_valid {
6298 return Ok(false);
6300 }
6301
6302 stack.push(to_stack_element(&[0x01])); Ok(true)
6309 }
6310 }
6311
6312 _ => execute_opcode_cold(opcode, stack, flags),
6314 }
6315}
6316
6317#[cold]
6319fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6320 execute_opcode(opcode, stack, flags, SigVersion::Base)
6321}
6322
6323#[cfg(feature = "production")]
6338pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6339 (
6340 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6341 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6342 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6343 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6344 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6345 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6346 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6347 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6348 )
6349}
6350
6351#[cfg(all(feature = "production", feature = "benchmarking"))]
6358pub fn clear_script_cache() {
6359 if let Some(cache) = SCRIPT_CACHE.get() {
6360 let mut cache = cache.write().unwrap();
6361 cache.clear();
6362 }
6363}
6364
6365#[cfg(all(feature = "production", feature = "benchmarking"))]
6379pub fn clear_hash_cache() {
6380 crypto_ops::clear_hash_cache();
6381}
6382
6383#[cfg(all(feature = "production", feature = "benchmarking"))]
6396pub fn clear_all_caches() {
6397 clear_script_cache();
6398 clear_hash_cache();
6399}
6400
6401#[cfg(all(feature = "production", feature = "benchmarking"))]
6415pub fn clear_stack_pool() {
6416 STACK_POOL.with(|pool| {
6417 let mut pool = pool.borrow_mut();
6418 pool.clear();
6419 });
6420}
6421
6422#[cfg(all(feature = "production", feature = "benchmarking"))]
6436pub fn reset_benchmarking_state() {
6437 clear_all_caches();
6438 clear_stack_pool();
6439 disable_caching(false); #[cfg(feature = "benchmarking")]
6442 crate::transaction_hash::clear_sighash_templates();
6443}
6444
6445#[cfg(test)]
6446mod tests {
6447 use super::*;
6448
6449 #[test]
6450 fn test_eval_script_simple() {
6451 let script = vec![OP_1]; let mut stack = Vec::new();
6453
6454 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6455 assert_eq!(stack.len(), 1);
6456 assert_eq!(stack[0].as_ref(), &[1]);
6457 }
6458
6459 #[test]
6460 fn test_eval_script_overflow() {
6461 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6463
6464 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6465 }
6466
6467 #[test]
6468 fn test_verify_script_simple() {
6469 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());
6480 }
6481
6482 #[test]
6487 fn test_op_0() {
6488 let script = vec![OP_0]; let mut stack = Vec::new();
6490 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6491 assert!(result); assert_eq!(stack.len(), 1);
6493 assert!(stack[0].is_empty());
6494 }
6495
6496 #[test]
6497 fn test_op_1_to_op_16() {
6498 for i in 1..=16 {
6500 let opcode = 0x50 + i;
6501 let script = vec![opcode];
6502 let mut stack = Vec::new();
6503 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6504 assert!(result);
6505 assert_eq!(stack.len(), 1);
6506 assert_eq!(stack[0].as_ref(), &[i]);
6507 }
6508 }
6509
6510 #[test]
6511 fn test_op_dup() {
6512 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6514 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6515 assert!(result); assert_eq!(stack.len(), 2);
6517 assert_eq!(stack[0].as_ref(), &[1]);
6518 assert_eq!(stack[1].as_ref(), &[1]);
6519 }
6520
6521 #[test]
6522 fn test_op_dup_empty_stack() {
6523 let script = vec![OP_DUP]; let mut stack = Vec::new();
6525 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6526 assert!(!result);
6527 }
6528
6529 #[test]
6530 fn test_op_hash160() {
6531 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6533 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6534 assert!(result);
6535 assert_eq!(stack.len(), 1);
6536 assert_eq!(stack[0].len(), 20); }
6538
6539 #[test]
6540 fn test_op_hash160_empty_stack() {
6541 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6543 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6544 assert!(!result);
6545 }
6546
6547 #[test]
6548 fn test_op_hash256() {
6549 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6551 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6552 assert!(result);
6553 assert_eq!(stack.len(), 1);
6554 assert_eq!(stack[0].len(), 32); }
6556
6557 #[test]
6558 fn test_op_hash256_empty_stack() {
6559 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6561 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6562 assert!(!result);
6563 }
6564
6565 #[test]
6566 fn test_op_equal() {
6567 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6569 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6570 assert!(result);
6571 assert_eq!(stack.len(), 1);
6572 assert_eq!(stack[0].as_ref(), &[1]); }
6574
6575 #[test]
6576 fn test_op_equal_false() {
6577 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6579 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6580 assert!(result); assert_eq!(stack.len(), 1);
6582 assert!(stack[0].is_empty()); }
6584
6585 #[test]
6586 fn test_op_equal_insufficient_stack() {
6587 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6589 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6590 assert!(
6591 result.is_err(),
6592 "OP_EQUAL with insufficient stack should return error"
6593 );
6594 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6595 assert_eq!(
6596 code,
6597 crate::error::ScriptErrorCode::InvalidStackOperation,
6598 "Should return InvalidStackOperation"
6599 );
6600 }
6601 }
6602
6603 #[test]
6604 fn test_op_verify() {
6605 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6607 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6608 assert!(result); assert_eq!(stack.len(), 0); }
6611
6612 #[test]
6613 fn test_op_verify_false() {
6614 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6616 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6617 assert!(!result);
6618 }
6619
6620 #[test]
6621 fn test_op_verify_empty_stack() {
6622 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6624 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6625 assert!(!result);
6626 }
6627
6628 #[test]
6629 fn test_op_equalverify() {
6630 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6632 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6633 assert!(result); assert_eq!(stack.len(), 0); }
6636
6637 #[test]
6638 fn test_op_equalverify_false() {
6639 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6641 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6642 assert!(
6643 result.is_err(),
6644 "OP_EQUALVERIFY with false condition should return error"
6645 );
6646 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6647 assert_eq!(
6648 code,
6649 crate::error::ScriptErrorCode::EqualVerify,
6650 "Should return EqualVerify"
6651 );
6652 }
6653 }
6654
6655 #[test]
6656 fn test_op_checksig() {
6657 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6661 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6662 assert!(result); assert_eq!(stack.len(), 1);
6664 }
6666
6667 #[test]
6668 fn test_op_checksig_insufficient_stack() {
6669 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6671 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6672 assert!(
6673 result.is_err(),
6674 "OP_CHECKSIG with insufficient stack should return error"
6675 );
6676 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6677 assert_eq!(
6678 code,
6679 crate::error::ScriptErrorCode::InvalidStackOperation,
6680 "Should return InvalidStackOperation"
6681 );
6682 }
6683 }
6684
6685 #[test]
6686 fn test_unknown_opcode() {
6687 let script = vec![0xff]; let mut stack = Vec::new();
6689 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6690 assert!(!result);
6691 }
6692
6693 #[test]
6694 fn test_script_size_limit() {
6695 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6697 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6698 assert!(result.is_err());
6699 }
6700
6701 #[test]
6702 fn test_operation_count_limit() {
6703 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6706 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6707 assert!(result.is_err());
6708 }
6709
6710 #[test]
6711 fn test_stack_underflow_multiple_ops() {
6712 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6714 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6715 assert!(result.is_err(), "Stack underflow should return error");
6716 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6717 assert_eq!(
6718 code,
6719 crate::error::ScriptErrorCode::InvalidStackOperation,
6720 "Should return InvalidStackOperation"
6721 );
6722 }
6723 }
6724
6725 #[test]
6726 fn test_final_stack_empty() {
6727 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6730 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6731 assert!(result); assert_eq!(stack.len(), 2);
6733 }
6734
6735 #[test]
6736 fn test_final_stack_false() {
6737 let script = vec![OP_0]; let mut stack = Vec::new();
6740 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6741 assert!(result); }
6743
6744 #[test]
6745 fn test_verify_script_with_witness() {
6746 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6751
6752 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6753 assert!(result); }
6755
6756 #[test]
6757 fn test_verify_script_failure() {
6758 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_0]; let witness = None;
6762 let flags = 0;
6763
6764 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6765 assert!(!result); }
6767
6768 #[test]
6773 fn test_op_ifdup_true() {
6774 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6776 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6777 assert!(result); assert_eq!(stack.len(), 2);
6779 assert_eq!(stack[0].as_ref(), &[1]);
6780 assert_eq!(stack[1].as_ref(), &[1]);
6781 }
6782
6783 #[test]
6784 fn test_op_ifdup_false() {
6785 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
6787 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6788 assert!(result); assert_eq!(stack.len(), 1);
6790 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
6791 }
6792
6793 #[test]
6794 fn test_op_depth() {
6795 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
6797 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6798 assert!(result); assert_eq!(stack.len(), 3);
6800 assert_eq!(stack[2].as_ref(), &[2]); }
6802
6803 #[test]
6804 fn test_op_drop() {
6805 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
6807 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6808 assert!(result); assert_eq!(stack.len(), 1);
6810 assert_eq!(stack[0].as_ref(), &[1]);
6811 }
6812
6813 #[test]
6814 fn test_op_drop_empty_stack() {
6815 let script = vec![OP_DROP]; let mut stack = Vec::new();
6817 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6818 assert!(!result);
6819 assert_eq!(stack.len(), 0);
6820 }
6821
6822 #[test]
6823 fn test_op_nip() {
6824 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
6826 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6827 assert!(result); assert_eq!(stack.len(), 1);
6829 assert_eq!(stack[0].as_ref(), &[2]);
6830 }
6831
6832 #[test]
6833 fn test_op_nip_insufficient_stack() {
6834 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
6836 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6837 assert!(!result);
6838 assert_eq!(stack.len(), 1);
6839 }
6840
6841 #[test]
6842 fn test_op_over() {
6843 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
6845 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6846 assert!(result); assert_eq!(stack.len(), 3);
6848 assert_eq!(stack[0].as_ref(), &[1]);
6849 assert_eq!(stack[1].as_ref(), &[2]);
6850 assert_eq!(stack[2].as_ref(), &[1]);
6851 }
6852
6853 #[test]
6854 fn test_op_over_insufficient_stack() {
6855 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
6857 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6858 assert!(!result);
6859 assert_eq!(stack.len(), 1);
6860 }
6861
6862 #[test]
6863 fn test_op_pick() {
6864 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
6866 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6867 assert!(result); assert_eq!(stack.len(), 4);
6869 assert_eq!(stack[3].as_ref(), &[2]); }
6871
6872 #[test]
6873 fn test_op_pick_empty_n() {
6874 let script = vec![OP_1, OP_0, OP_PICK];
6876 let mut stack = Vec::new();
6877 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6878 assert!(result); assert_eq!(stack.len(), 2);
6880 assert_eq!(stack[1].as_ref(), &[1]); }
6882
6883 #[test]
6884 fn test_op_pick_invalid_index() {
6885 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
6887 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6888 assert!(!result);
6889 assert_eq!(stack.len(), 1);
6890 }
6891
6892 #[test]
6893 fn test_op_roll() {
6894 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
6896 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6897 assert!(result); assert_eq!(stack.len(), 3);
6899 assert_eq!(stack[0].as_ref(), &[1]);
6900 assert_eq!(stack[1].as_ref(), &[3]);
6901 assert_eq!(stack[2].as_ref(), &[2]); }
6903
6904 #[test]
6905 fn test_op_roll_zero_n() {
6906 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
6909 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6910 assert!(result); assert_eq!(stack.len(), 1);
6912 assert_eq!(stack[0].as_ref(), &[1]);
6913 }
6914
6915 #[test]
6916 fn test_op_roll_invalid_index() {
6917 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
6919 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6920 assert!(!result);
6921 assert_eq!(stack.len(), 1);
6922 }
6923
6924 #[test]
6925 fn test_op_rot() {
6926 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
6928 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6929 assert!(result); assert_eq!(stack.len(), 3);
6931 assert_eq!(stack[0].as_ref(), &[2]);
6932 assert_eq!(stack[1].as_ref(), &[3]);
6933 assert_eq!(stack[2].as_ref(), &[1]);
6934 }
6935
6936 #[test]
6937 fn test_op_rot_insufficient_stack() {
6938 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
6940 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6941 assert!(!result);
6942 assert_eq!(stack.len(), 2);
6943 }
6944
6945 #[test]
6946 fn test_op_swap() {
6947 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
6949 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6950 assert!(result); assert_eq!(stack.len(), 2);
6952 assert_eq!(stack[0].as_ref(), &[2]);
6953 assert_eq!(stack[1].as_ref(), &[1]);
6954 }
6955
6956 #[test]
6957 fn test_op_swap_insufficient_stack() {
6958 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
6960 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6961 assert!(!result);
6962 assert_eq!(stack.len(), 1);
6963 }
6964
6965 #[test]
6966 fn test_op_tuck() {
6967 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
6969 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6970 assert!(result); assert_eq!(stack.len(), 3);
6972 assert_eq!(stack[0].as_ref(), &[2]);
6973 assert_eq!(stack[1].as_ref(), &[1]);
6974 assert_eq!(stack[2].as_ref(), &[2]);
6975 }
6976
6977 #[test]
6978 fn test_op_tuck_insufficient_stack() {
6979 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
6981 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6982 assert!(!result);
6983 assert_eq!(stack.len(), 1);
6984 }
6985
6986 #[test]
6987 fn test_op_2drop() {
6988 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
6990 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6991 assert!(result); assert_eq!(stack.len(), 1);
6993 assert_eq!(stack[0].as_ref(), &[1]);
6994 }
6995
6996 #[test]
6997 fn test_op_2drop_insufficient_stack() {
6998 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
7000 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7001 assert!(!result);
7002 assert_eq!(stack.len(), 1);
7003 }
7004
7005 #[test]
7006 fn test_op_2dup() {
7007 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
7009 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7010 assert!(result); assert_eq!(stack.len(), 4);
7012 assert_eq!(stack[0].as_ref(), &[1]);
7013 assert_eq!(stack[1].as_ref(), &[2]);
7014 assert_eq!(stack[2].as_ref(), &[1]);
7015 assert_eq!(stack[3].as_ref(), &[2]);
7016 }
7017
7018 #[test]
7019 fn test_op_2dup_insufficient_stack() {
7020 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
7022 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7023 assert!(!result);
7024 assert_eq!(stack.len(), 1);
7025 }
7026
7027 #[test]
7028 fn test_op_3dup() {
7029 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
7031 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7032 assert!(result); assert_eq!(stack.len(), 6);
7034 assert_eq!(stack[0].as_ref(), &[1]);
7035 assert_eq!(stack[1].as_ref(), &[2]);
7036 assert_eq!(stack[2].as_ref(), &[3]);
7037 assert_eq!(stack[3].as_ref(), &[1]);
7038 assert_eq!(stack[4].as_ref(), &[2]);
7039 assert_eq!(stack[5].as_ref(), &[3]);
7040 }
7041
7042 #[test]
7043 fn test_op_3dup_insufficient_stack() {
7044 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
7046 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7047 assert!(!result);
7048 assert_eq!(stack.len(), 2);
7049 }
7050
7051 #[test]
7052 fn test_op_2over() {
7053 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
7055 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7056 assert!(result); assert_eq!(stack.len(), 6);
7058 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
7060 }
7061
7062 #[test]
7063 fn test_op_2over_insufficient_stack() {
7064 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
7066 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7067 assert!(!result);
7068 assert_eq!(stack.len(), 3);
7069 }
7070
7071 #[test]
7072 fn test_op_2rot() {
7073 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
7078 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7079 assert!(result); assert_eq!(stack.len(), 6);
7081 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]); }
7084
7085 #[test]
7086 fn test_op_2rot_insufficient_stack() {
7087 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
7089 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7090 assert!(!result);
7091 assert_eq!(stack.len(), 4);
7092 }
7093
7094 #[test]
7095 fn test_op_2swap() {
7096 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
7098 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7099 assert!(result); assert_eq!(stack.len(), 4);
7101 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
7103 assert_eq!(stack[2].as_ref(), &[1]);
7104 assert_eq!(stack[3].as_ref(), &[2]);
7105 }
7106
7107 #[test]
7108 fn test_op_2swap_insufficient_stack() {
7109 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
7111 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7112 assert!(!result);
7113 assert_eq!(stack.len(), 3);
7114 }
7115
7116 #[test]
7117 fn test_op_size() {
7118 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
7120 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7121 assert!(result); assert_eq!(stack.len(), 2);
7123 assert_eq!(stack[0].as_ref(), &[1]);
7124 assert_eq!(stack[1].as_ref(), &[1]); }
7126
7127 #[test]
7128 fn test_op_size_empty_stack() {
7129 let script = vec![OP_SIZE]; let mut stack = Vec::new();
7131 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7132 assert!(!result);
7133 assert_eq!(stack.len(), 0);
7134 }
7135
7136 #[test]
7137 fn test_op_return() {
7138 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
7140 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7141 assert!(!result); assert_eq!(stack.len(), 1);
7143 }
7144
7145 #[test]
7146 fn test_op_checksigverify() {
7147 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7149 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7150 assert!(!result); assert_eq!(stack.len(), 0);
7152 }
7153
7154 #[test]
7155 fn test_op_checksigverify_insufficient_stack() {
7156 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7158 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7159 assert!(!result);
7160 assert_eq!(stack.len(), 1);
7161 }
7162
7163 #[test]
7164 fn test_unknown_opcode_comprehensive() {
7165 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
7167 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7168 assert!(!result); assert_eq!(stack.len(), 1);
7170 }
7171
7172 #[test]
7173 fn test_verify_signature_invalid_pubkey() {
7174 let secp = signature::new_secp();
7175 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
7178 let result = signature::verify_signature(
7179 &secp,
7180 &invalid_pubkey,
7181 &signature,
7182 &dummy_hash,
7183 0,
7184 0,
7185 crate::types::Network::Regtest,
7186 SigVersion::Base,
7187 );
7188 assert!(!result.unwrap_or(false));
7189 }
7190
7191 #[test]
7192 fn test_verify_signature_invalid_signature() {
7193 let secp = signature::new_secp();
7194 let pubkey = vec![
7195 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
7196 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
7197 0x5b, 0x16, 0xf8, 0x17, 0x98,
7198 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
7201 let result = signature::verify_signature(
7202 &secp,
7203 &pubkey,
7204 &invalid_signature,
7205 &dummy_hash,
7206 0,
7207 0,
7208 crate::types::Network::Regtest,
7209 SigVersion::Base,
7210 );
7211 assert!(!result.unwrap_or(false));
7212 }
7213
7214 fn minimal_tx_and_prevouts(
7220 script_sig: &[u8],
7221 script_pubkey: &[u8],
7222 ) -> (
7223 crate::types::Transaction,
7224 Vec<i64>,
7225 Vec<crate::types::ByteString>,
7226 ) {
7227 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
7228 let tx = Transaction {
7229 version: 1,
7230 inputs: vec![TransactionInput {
7231 prevout: OutPoint {
7232 hash: [0u8; 32],
7233 index: 0,
7234 },
7235 sequence: 0xffff_ffff,
7236 script_sig: script_sig.to_vec(),
7237 }]
7238 .into(),
7239 outputs: vec![TransactionOutput {
7240 value: 0,
7241 script_pubkey: script_pubkey.to_vec(),
7242 }]
7243 .into(),
7244 lock_time: 0,
7245 };
7246 let prevout_values = vec![0i64];
7247 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
7248 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
7249 (tx, prevout_values, prevout_script_pubkeys_vec)
7250 }
7251
7252 #[test]
7253 fn test_verify_with_context_p2pkh_hash_mismatch() {
7254 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
7258 script_sig.push(sig.len() as u8);
7259 script_sig.extend(&sig);
7260 script_sig.push(pubkey.len() as u8);
7261 script_sig.extend(&pubkey);
7262
7263 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
7264 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
7266 script_pubkey.push(OP_CHECKSIG);
7267
7268 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7269 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7270 let result = verify_script_with_context_full(
7271 &script_sig,
7272 &script_pubkey,
7273 None,
7274 0,
7275 &tx,
7276 0,
7277 &pv,
7278 &psp_refs,
7279 Some(500_000),
7280 None,
7281 crate::types::Network::Mainnet,
7282 SigVersion::Base,
7283 #[cfg(feature = "production")]
7284 None,
7285 None, #[cfg(feature = "production")]
7287 None,
7288 #[cfg(feature = "production")]
7289 None,
7290 #[cfg(feature = "production")]
7291 None,
7292 );
7293 assert!(result.is_ok());
7294 assert!(!result.unwrap());
7295 }
7296
7297 #[test]
7298 fn test_verify_with_context_p2sh_hash_mismatch() {
7299 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7302 script_sig.push(redeem.len() as u8);
7303 script_sig.extend(&redeem);
7304
7305 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7306 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7308
7309 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7310 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7311 let result = verify_script_with_context_full(
7312 &script_sig,
7313 &script_pubkey,
7314 None,
7315 0x01, &tx,
7317 0,
7318 &pv,
7319 &psp_refs,
7320 Some(500_000),
7321 None,
7322 crate::types::Network::Mainnet,
7323 SigVersion::Base,
7324 #[cfg(feature = "production")]
7325 None,
7326 None, #[cfg(feature = "production")]
7328 None,
7329 #[cfg(feature = "production")]
7330 None,
7331 #[cfg(feature = "production")]
7332 None,
7333 );
7334 assert!(result.is_ok());
7335 assert!(!result.unwrap());
7336 }
7337
7338 #[test]
7339 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7340 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7342 script_pubkey.extend(&[0u8; 20]);
7343 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7345 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7346 let empty: Vec<u8> = vec![];
7347 let result = verify_script_with_context_full(
7348 &empty,
7349 &script_pubkey,
7350 Some(&witness),
7351 0,
7352 &tx,
7353 0,
7354 &pv,
7355 &psp_refs,
7356 Some(500_000),
7357 None,
7358 crate::types::Network::Mainnet,
7359 SigVersion::Base,
7360 #[cfg(feature = "production")]
7361 None,
7362 None, #[cfg(feature = "production")]
7364 None,
7365 #[cfg(feature = "production")]
7366 None,
7367 #[cfg(feature = "production")]
7368 None,
7369 );
7370 assert!(result.is_ok());
7371 assert!(!result.unwrap());
7372 }
7373
7374 #[test]
7375 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7376 let witness_script = vec![OP_1];
7378 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7379 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7381 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7382 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7383 let empty: Vec<u8> = vec![];
7384 let result = verify_script_with_context_full(
7385 &empty,
7386 &script_pubkey,
7387 Some(&witness),
7388 0,
7389 &tx,
7390 0,
7391 &pv,
7392 &psp_refs,
7393 Some(500_000),
7394 None,
7395 crate::types::Network::Mainnet,
7396 SigVersion::Base,
7397 #[cfg(feature = "production")]
7398 None,
7399 None, #[cfg(feature = "production")]
7401 None,
7402 #[cfg(feature = "production")]
7403 None,
7404 #[cfg(feature = "production")]
7405 None,
7406 );
7407 assert!(result.is_ok());
7408 assert!(!result.unwrap());
7409 }
7410
7411 #[test]
7412 #[cfg(feature = "production")]
7413 fn test_p2wsh_multisig_fast_path() {
7414 use crate::constants::BIP147_ACTIVATION_MAINNET;
7416 use crate::crypto::OptimizedSha256;
7417
7418 let pk1 = [0x02u8; 33];
7419 let pk2 = [0x03u8; 33];
7420 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7422 witness_script.extend_from_slice(&pk2);
7423 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7427 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7428 script_pubkey.extend_from_slice(&wsh_hash);
7429
7430 let witness: Vec<Vec<u8>> = vec![
7431 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7435 ];
7436
7437 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7438 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7439 let empty: Vec<u8> = vec![];
7440 let result = verify_script_with_context_full(
7441 &empty,
7442 &script_pubkey,
7443 Some(&witness),
7444 0x810, &tx,
7446 0,
7447 &pv,
7448 &psp_refs,
7449 Some(BIP147_ACTIVATION_MAINNET + 1),
7450 None,
7451 crate::types::Network::Mainnet,
7452 SigVersion::Base,
7453 #[cfg(feature = "production")]
7454 None,
7455 None, #[cfg(feature = "production")]
7457 None,
7458 #[cfg(feature = "production")]
7459 None,
7460 #[cfg(feature = "production")]
7461 None,
7462 );
7463 assert!(result.is_ok());
7464 assert!(!result.unwrap());
7465 }
7466}
7467
7468#[cfg(test)]
7469#[allow(unused_doc_comments)]
7470mod property_tests {
7471 use super::*;
7472 use proptest::prelude::*;
7473
7474 proptest! {
7479 #[test]
7480 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7481 let mut stack = Vec::new();
7482 let flags = 0u32;
7483
7484 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7485
7486 if script.len() > MAX_SCRIPT_OPS * 2 {
7494 prop_assert!(result.is_err() || !result.unwrap(),
7497 "Very long scripts should fail or return false");
7498 }
7499 }
7501 }
7502
7503 proptest! {
7508 #[test]
7509 fn prop_verify_script_deterministic(
7510 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7511 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7512 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7513 flags in any::<u32>()
7514 ) {
7515 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7516 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7517
7518 assert_eq!(result1.is_ok(), result2.is_ok());
7519 if result1.is_ok() && result2.is_ok() {
7520 assert_eq!(result1.unwrap(), result2.unwrap());
7521 }
7522 }
7523 }
7524
7525 proptest! {
7530 #[test]
7531 fn prop_execute_opcode_no_panic(
7532 opcode in any::<u8>(),
7533 stack_items in prop::collection::vec(
7534 prop::collection::vec(any::<u8>(), 0..5),
7535 0..10
7536 ),
7537 flags in any::<u32>()
7538 ) {
7539 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7540 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7541
7542 match result {
7545 Ok(success) => {
7546 let _ = success;
7548 },
7549 Err(_) => {
7550 }
7553 }
7554
7555 assert!(stack.len() <= MAX_STACK_SIZE);
7557 }
7558 }
7559
7560 proptest! {
7567 #[test]
7568 fn prop_stack_operations_bounds(
7569 opcode in any::<u8>(),
7570 stack_items in prop::collection::vec(
7571 prop::collection::vec(any::<u8>(), 0..3),
7572 0..5
7573 ),
7574 flags in any::<u32>()
7575 ) {
7576 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7577 let initial_len = stack.len();
7578
7579 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7580
7581 assert!(stack.len() <= MAX_STACK_SIZE);
7583
7584 if result.is_ok() && result.unwrap() {
7586 match opcode {
7588 OP_0 | OP_1..=OP_16 => {
7589 assert!(stack.len() == initial_len + 1);
7591 },
7592 OP_DUP => {
7593 if initial_len > 0 {
7595 assert!(stack.len() == initial_len + 1);
7596 }
7597 },
7598 OP_3DUP => {
7599 if initial_len >= 3 {
7601 assert!(stack.len() == initial_len + 3);
7602 }
7603 },
7604 OP_2OVER => {
7605 if initial_len >= 4 {
7607 assert!(stack.len() == initial_len + 2);
7608 }
7609 },
7610 OP_DROP | OP_NIP | OP_2DROP => {
7611 assert!(stack.len() <= initial_len);
7613 },
7614 _ => {
7615 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7618 }
7619 }
7620 }
7621 }
7622 }
7623
7624 proptest! {
7629 #[test]
7630 fn prop_hash_operations_deterministic(
7631 input in prop::collection::vec(any::<u8>(), 0..10)
7632 ) {
7633 let elem = to_stack_element(&input);
7634 let mut stack1 = vec![elem.clone()];
7635 let mut stack2 = vec![elem];
7636
7637 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());
7641 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7642 assert_eq!(val1, val2);
7643 if val1 {
7644 assert_eq!(stack1, stack2);
7645 }
7646 }
7647 }
7648 }
7649
7650 proptest! {
7655 #[test]
7656 fn prop_equality_operations_symmetric(
7657 a in prop::collection::vec(any::<u8>(), 0..5),
7658 b in prop::collection::vec(any::<u8>(), 0..5)
7659 ) {
7660 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7661 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7662
7663 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());
7667 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7668 assert_eq!(val1, val2);
7669 if val1 {
7670 assert_eq!(stack1.len(), stack2.len());
7672 if !stack1.is_empty() && !stack2.is_empty() {
7673 assert_eq!(stack1[0], stack2[0]);
7674 }
7675 }
7676 }
7677 }
7678 }
7679
7680 proptest! {
7685 #[test]
7686 fn prop_script_execution_terminates(
7687 script in prop::collection::vec(any::<u8>(), 0..50)
7688 ) {
7689 let mut stack = Vec::new();
7690 let flags = 0u32;
7691
7692 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7694
7695 assert!(result.is_ok() || result.is_err());
7697
7698 assert!(stack.len() <= MAX_STACK_SIZE);
7700 }
7701 }
7702}