1#![allow(
5 clippy::declare_interior_mutable_const, clippy::type_complexity,
7 clippy::too_many_arguments,
8 clippy::needless_return, )]
10mod arithmetic;
23mod context;
24mod control_flow;
25mod crypto_ops;
26pub mod flags;
27mod signature;
28mod stack;
29
30pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
31pub use stack::{StackElement, cast_to_bool, to_stack_element};
32
33use crate::constants::*;
34use crate::crypto::OptimizedSha256;
35use crate::error::{ConsensusError, Result, ScriptErrorCode};
36use crate::opcodes::*;
37use crate::types::*;
38use blvm_spec_lock::spec_locked;
39use digest::Digest;
40use ripemd::Ripemd160;
41
42#[cfg(feature = "production")]
44use crate::optimizations::{precomputed_constants, prefetch};
45
46#[cold]
48#[allow(dead_code)]
49fn make_operation_limit_error() -> ConsensusError {
50 ConsensusError::ScriptErrorWithCode {
51 code: ScriptErrorCode::OpCount,
52 message: "Operation limit exceeded".into(),
53 }
54}
55
56#[cold]
57fn make_stack_overflow_error() -> ConsensusError {
58 ConsensusError::ScriptErrorWithCode {
59 code: ScriptErrorCode::StackSize,
60 message: "Stack overflow".into(),
61 }
62}
63
64#[inline]
65fn bip143_p2wpkh_script_code(pubkey_hash: &[u8]) -> [u8; 25] {
66 let mut hash = [0u8; 20];
67 hash.copy_from_slice(pubkey_hash);
68 crate::transaction_hash::derive_bip143_script_code_p2wpkh(&hash)
69}
70
71#[cfg(feature = "production")]
72use std::collections::VecDeque;
73#[cfg(feature = "production")]
74use std::sync::{
75 OnceLock, RwLock,
76 atomic::{AtomicBool, AtomicU64, Ordering},
77};
78#[cfg(feature = "production")]
79use std::thread_local;
80
81#[cfg(feature = "production")]
87static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
88
89#[cfg(feature = "production")]
92mod sig_cache {
93 #![allow(dead_code)]
94
95 use lru::LruCache;
96 use siphasher::sip::SipHasher24;
97 use std::hash::{Hash, Hasher};
98 use std::num::NonZeroUsize;
99 use std::sync::{OnceLock, RwLock};
100
101 const SIG_CACHE_SHARDS: usize = 32;
102 const SIG_CACHE_SHARD: OnceLock<RwLock<LruCache<[u8; 32], bool>>> = OnceLock::new();
103
104 static SIG_CACHE: [OnceLock<RwLock<LruCache<[u8; 32], bool>>>; SIG_CACHE_SHARDS] =
105 [SIG_CACHE_SHARD; SIG_CACHE_SHARDS];
106
107 fn sig_cache_size() -> usize {
108 std::env::var("BLVM_SIG_CACHE_ENTRIES")
109 .ok()
110 .and_then(|s| s.parse().ok())
111 .filter(|&n: &usize| n > 0 && n <= 1_000_000)
112 .unwrap_or(500_000)
113 }
114
115 fn sig_cache_shard_index(key: &[u8; 32]) -> usize {
116 let h = (key[0] as usize) | ((key[1] as usize) << 8) | ((key[2] as usize) << 16);
117 h % SIG_CACHE_SHARDS
118 }
119
120 fn get_sig_cache_shard(key: &[u8; 32]) -> &'static RwLock<LruCache<[u8; 32], bool>> {
121 let idx = sig_cache_shard_index(key);
122 SIG_CACHE[idx].get_or_init(|| {
123 let cap = (sig_cache_size() / SIG_CACHE_SHARDS).max(1);
124 RwLock::new(LruCache::new(NonZeroUsize::new(cap).unwrap()))
125 })
126 }
127
128 thread_local! {
129 static BATCH_PUT_SIG_CACHE_BY_SHARD: std::cell::RefCell<[Vec<([u8; 32], bool)>; SIG_CACHE_SHARDS]> =
130 std::cell::RefCell::new(std::array::from_fn(|_| Vec::new()));
131 }
132
133 fn batch_put_sig_cache(keys: &[[u8; 32]], results: &[bool]) {
134 BATCH_PUT_SIG_CACHE_BY_SHARD.with(|cell| {
135 let mut by_shard = cell.borrow_mut();
136 for v in by_shard.iter_mut() {
137 v.clear();
138 }
139 for (i, key) in keys.iter().enumerate() {
140 let result = results.get(i).copied().unwrap_or(false);
141 let idx = sig_cache_shard_index(key);
142 by_shard[idx].push((*key, result));
143 }
144 for shard_entries in by_shard.iter() {
145 if shard_entries.is_empty() {
146 continue;
147 }
148 let first_key = &shard_entries[0].0;
149 if let Ok(mut guard) = get_sig_cache_shard(first_key).write() {
150 for (k, v) in shard_entries.iter() {
151 guard.put(*k, *v);
152 }
153 }
154 }
155 });
156 }
157
158 fn sig_cache_at_collect_enabled() -> bool {
159 static CACHE: OnceLock<bool> = OnceLock::new();
160 *CACHE.get_or_init(|| {
161 std::env::var("BLVM_SIG_CACHE_AT_COLLECT")
162 .map(|s| s == "1" || s.eq_ignore_ascii_case("true"))
163 .unwrap_or(false)
164 })
165 }
166
167 #[inline(always)]
168 fn ecdsa_cache_key(
169 msg: &[u8; 32],
170 pk: &[u8; 33],
171 sig_compact: &[u8; 64],
172 flags: u32,
173 ) -> [u8; 32] {
174 let mut key_input = [0u8; 133];
175 key_input[..32].copy_from_slice(msg);
176 key_input[32..65].copy_from_slice(pk);
177 key_input[65..129].copy_from_slice(sig_compact);
178 key_input[129..133].copy_from_slice(&flags.to_le_bytes());
179 let mut hasher = SipHasher24::new();
180 key_input.hash(&mut hasher);
181 let h = hasher.finish();
182 let mut out = [0u8; 32];
183 out[..8].copy_from_slice(&h.to_le_bytes());
184 out
185 }
186}
187
188#[cfg(feature = "production")]
190thread_local! {
191 static SOA_BATCH_BUF: std::cell::RefCell<(
192 Vec<[u8; 64]>,
193 Vec<[u8; 32]>,
194 Vec<[u8; 33]>,
195 Vec<usize>,
196 Vec<[u8; 32]>,
197 )> = const { std::cell::RefCell::new((
198 Vec::new(),
199 Vec::new(),
200 Vec::new(),
201 Vec::new(),
202 Vec::new(),
203 )) };
204}
205
206#[cfg(feature = "production")]
209static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
210#[cfg(feature = "production")]
211static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
212#[cfg(feature = "production")]
213static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
214#[cfg(feature = "production")]
215static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
216#[cfg(feature = "production")]
217static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
218static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
219#[cfg(feature = "production")]
220static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
221#[cfg(feature = "production")]
222static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
223
224#[cfg(feature = "production")]
225fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
226 SCRIPT_CACHE.get_or_init(|| {
227 use lru::LruCache;
231 use std::num::NonZeroUsize;
232 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
233 })
234}
235
236#[cfg(feature = "production")]
241thread_local! {
242 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
243 std::cell::RefCell::new(VecDeque::with_capacity(10));
244}
245
246#[cfg(feature = "production")]
248fn get_pooled_stack() -> Vec<StackElement> {
249 STACK_POOL.with(|pool| {
250 let mut pool = pool.borrow_mut();
251 if let Some(mut stack) = pool.pop_front() {
252 stack.clear();
253 if stack.capacity() < 20 {
254 stack.reserve(20);
255 }
256 stack
257 } else {
258 Vec::with_capacity(20)
259 }
260 })
261}
262
263#[cfg(feature = "production")]
265struct PooledStackGuard(Vec<StackElement>);
266#[cfg(feature = "production")]
267impl Drop for PooledStackGuard {
268 fn drop(&mut self) {
269 return_pooled_stack(std::mem::take(&mut self.0));
270 }
271}
272
273#[cfg(feature = "production")]
275fn return_pooled_stack(mut stack: Vec<StackElement>) {
276 stack.clear();
278
279 STACK_POOL.with(|pool| {
280 let mut pool = pool.borrow_mut();
281 if pool.len() < 10 {
283 pool.push_back(stack);
284 }
285 });
287}
288
289#[cfg(feature = "production")]
294static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
295
296#[cfg(feature = "production")]
298static FAST_PATHS_DISABLED: AtomicBool = AtomicBool::new(false);
299
300#[cfg(feature = "production")]
316pub fn disable_caching(disabled: bool) {
317 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
318}
319
320#[cfg(feature = "production")]
322pub fn disable_fast_paths(disabled: bool) {
323 FAST_PATHS_DISABLED.store(disabled, Ordering::Relaxed);
324}
325
326#[cfg(feature = "production")]
328fn is_caching_disabled() -> bool {
329 CACHE_DISABLED.load(Ordering::Relaxed)
330}
331
332#[cfg(feature = "production")]
333fn fast_paths_disabled() -> bool {
334 FAST_PATHS_DISABLED.load(Ordering::Relaxed)
335}
336
337#[cfg(feature = "production")]
339fn compute_script_cache_key(
340 script_sig: &ByteString,
341 script_pubkey: &[u8],
342 witness: Option<&ByteString>,
343 flags: u32,
344) -> u64 {
345 use sha2::{Digest, Sha256};
346
347 let mut hasher = Sha256::new();
348 hasher.update(&script_sig[..]);
349 hasher.update(script_pubkey);
350 if let Some(w) = witness {
351 hasher.update(&w[..]);
352 }
353 hasher.update(flags.to_le_bytes());
354 let digest = hasher.finalize();
355 u64::from_le_bytes(digest[0..8].try_into().expect("sha256 prefix"))
356}
357
358#[derive(Debug, Clone, Copy, PartialEq, Eq)]
360pub enum SigVersion {
361 Base,
363 WitnessV0,
365 Tapscript,
367}
368
369#[spec_locked("5.2", "EvalScript")]
386#[cfg_attr(feature = "production", inline(always))]
387#[cfg_attr(not(feature = "production"), inline)]
388pub fn eval_script(
389 script: &[u8],
390 stack: &mut Vec<StackElement>,
391 flags: u32,
392 sigversion: SigVersion,
393) -> Result<bool> {
394 if stack.capacity() < 20 {
397 stack.reserve(20);
398 }
399 #[cfg(feature = "production")]
400 {
401 eval_script_impl(script, stack, flags, sigversion)
402 }
403 #[cfg(not(feature = "production"))]
404 {
405 eval_script_inner(script, stack, flags, sigversion)
406 }
407}
408#[cfg(feature = "production")]
409fn eval_script_impl(
410 script: &[u8],
411 stack: &mut Vec<StackElement>,
412 flags: u32,
413 sigversion: SigVersion,
414) -> Result<bool> {
415 eval_script_inner(script, stack, flags, sigversion)
416}
417
418#[cfg(not(feature = "production"))]
419#[allow(dead_code)]
420fn eval_script_impl(
421 script: &[u8],
422 stack: &mut Vec<StackElement>,
423 flags: u32,
424 sigversion: SigVersion,
425) -> Result<bool> {
426 eval_script_inner(script, stack, flags, sigversion)
427}
428
429#[inline(always)]
431fn is_push_opcode(opcode: u8) -> bool {
432 opcode <= 0x60
433}
434
435#[inline]
438fn is_op_success(opcode: u8) -> bool {
439 matches!(
440 opcode,
441 80 | 98
442 | 126..=129
443 | 131..=134
444 | 137..=138
445 | 141..=142
446 | 149..=153
447 | 187..=254
448 )
449}
450
451#[inline]
454fn op_advance(script: &[u8], pc: usize) -> usize {
455 let opcode = script[pc];
456 match opcode {
457 0x01..=0x4b => 1 + opcode as usize,
459 0x4c => {
461 if pc + 1 < script.len() {
462 2 + script[pc + 1] as usize
463 } else {
464 1
465 }
466 }
467 0x4d => {
469 if pc + 2 < script.len() {
470 3 + u16::from_le_bytes([script[pc + 1], script[pc + 2]]) as usize
471 } else {
472 1
473 }
474 }
475 0x4e => {
477 if pc + 4 < script.len() {
478 5 + u32::from_le_bytes([
479 script[pc + 1],
480 script[pc + 2],
481 script[pc + 3],
482 script[pc + 4],
483 ]) as usize
484 } else {
485 1
486 }
487 }
488 _ => 1,
489 }
490}
491
492fn eval_script_inner(
493 script: &[u8],
494 stack: &mut Vec<StackElement>,
495 flags: u32,
496 sigversion: SigVersion,
497) -> Result<bool> {
498 use crate::constants::MAX_SCRIPT_SIZE;
499 use crate::error::{ConsensusError, ScriptErrorCode};
500
501 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
502 && script.len() > MAX_SCRIPT_SIZE
503 {
504 return Err(ConsensusError::ScriptErrorWithCode {
505 code: ScriptErrorCode::ScriptSize,
506 message: "Script size exceeds maximum".into(),
507 });
508 }
509
510 let mut op_count = 0;
511 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
512 let mut altstack: Vec<StackElement> = Vec::new();
513
514 let mut i = 0;
515 while i < script.len() {
516 let opcode = script[i];
517 let in_false_branch = control_flow::in_false_branch(&control_stack);
518
519 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
522 op_count += 1;
523 if op_count > MAX_SCRIPT_OPS {
524 return Err(make_operation_limit_error());
525 }
526 debug_assert!(
527 op_count <= MAX_SCRIPT_OPS,
528 "Operation count ({op_count}) must not exceed MAX_SCRIPT_OPS ({MAX_SCRIPT_OPS})"
529 );
530 }
531
532 if stack.len() + altstack.len() > MAX_STACK_SIZE {
535 return Err(make_stack_overflow_error());
536 }
537
538 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
540 let (data, advance) = if opcode <= 0x4b {
541 let len = opcode as usize;
542 if i + 1 + len > script.len() {
543 return Ok(false);
544 }
545 (&script[i + 1..i + 1 + len], 1 + len)
546 } else if opcode == OP_PUSHDATA1 {
547 if i + 1 >= script.len() {
548 return Ok(false);
549 }
550 let len = script[i + 1] as usize;
551 if i + 2 + len > script.len() {
552 return Ok(false);
553 }
554 (&script[i + 2..i + 2 + len], 2 + len)
555 } else if opcode == OP_PUSHDATA2 {
556 if i + 2 >= script.len() {
557 return Ok(false);
558 }
559 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
560 if i + 3 + len > script.len() {
561 return Ok(false);
562 }
563 (&script[i + 3..i + 3 + len], 3 + len)
564 } else {
565 if i + 4 >= script.len() {
566 return Ok(false);
567 }
568 let len = u32::from_le_bytes([
569 script[i + 1],
570 script[i + 2],
571 script[i + 3],
572 script[i + 4],
573 ]) as usize;
574 let data_start = i.saturating_add(5);
575 let data_end = data_start.saturating_add(len);
576 let advance = 5usize.saturating_add(len);
577 if advance < 5 || data_end > script.len() || data_end < data_start {
578 return Ok(false);
579 }
580 (&script[data_start..data_end], advance)
581 };
582
583 if !in_false_branch {
584 stack.push(to_stack_element(data));
585 }
586 i += advance;
587 continue;
588 }
589
590 match opcode {
591 OP_IF => {
593 if in_false_branch {
594 control_stack.push(control_flow::ControlBlock::If { executing: false });
595 } else if stack.is_empty() {
596 return Err(ConsensusError::ScriptErrorWithCode {
597 code: ScriptErrorCode::InvalidStackOperation,
598 message: "OP_IF: empty stack".into(),
599 });
600 } else {
601 let condition_bytes = stack.pop().unwrap();
602 let condition = cast_to_bool(&condition_bytes);
603
604 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
605 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
606 && (sigversion == SigVersion::WitnessV0
607 || sigversion == SigVersion::Tapscript)
608 && !control_flow::is_minimal_if_condition(&condition_bytes)
609 {
610 return Err(ConsensusError::ScriptErrorWithCode {
611 code: ScriptErrorCode::MinimalIf,
612 message: "OP_IF condition must be minimally encoded".into(),
613 });
614 }
615
616 control_stack.push(control_flow::ControlBlock::If {
617 executing: condition,
618 });
619 }
620 }
621 OP_NOTIF => {
623 if in_false_branch {
624 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
625 } else if stack.is_empty() {
626 return Err(ConsensusError::ScriptErrorWithCode {
627 code: ScriptErrorCode::InvalidStackOperation,
628 message: "OP_NOTIF: empty stack".into(),
629 });
630 } else {
631 let condition_bytes = stack.pop().unwrap();
632 let condition = cast_to_bool(&condition_bytes);
633
634 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
635 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
636 && (sigversion == SigVersion::WitnessV0
637 || sigversion == SigVersion::Tapscript)
638 && !control_flow::is_minimal_if_condition(&condition_bytes)
639 {
640 return Err(ConsensusError::ScriptErrorWithCode {
641 code: ScriptErrorCode::MinimalIf,
642 message: "OP_NOTIF condition must be minimally encoded".into(),
643 });
644 }
645
646 control_stack.push(control_flow::ControlBlock::NotIf {
647 executing: !condition,
648 });
649 }
650 }
651 OP_ELSE => {
653 if let Some(block) = control_stack.last_mut() {
654 match block {
655 control_flow::ControlBlock::If { executing }
656 | control_flow::ControlBlock::NotIf { executing } => {
657 *executing = !*executing;
658 }
659 }
660 } else {
661 return Err(ConsensusError::ScriptErrorWithCode {
662 code: ScriptErrorCode::UnbalancedConditional,
663 message: "OP_ELSE without matching IF/NOTIF".into(),
664 });
665 }
666 }
667 OP_ENDIF => {
669 if control_stack.pop().is_none() {
670 return Err(ConsensusError::ScriptErrorWithCode {
671 code: ScriptErrorCode::UnbalancedConditional,
672 message: "OP_ENDIF without matching IF/NOTIF".into(),
673 });
674 }
675 }
676 OP_TOALTSTACK => {
678 if !in_false_branch {
679 if stack.is_empty() {
680 return Err(ConsensusError::ScriptErrorWithCode {
681 code: ScriptErrorCode::InvalidStackOperation,
682 message: "OP_TOALTSTACK: empty stack".into(),
683 });
684 }
685 altstack.push(stack.pop().unwrap());
686 }
687 }
688 OP_FROMALTSTACK => {
690 if !in_false_branch {
691 if altstack.is_empty() {
692 return Err(ConsensusError::ScriptErrorWithCode {
693 code: ScriptErrorCode::InvalidAltstackOperation,
694 message: "OP_FROMALTSTACK: empty altstack".into(),
695 });
696 }
697 stack.push(altstack.pop().unwrap());
698 }
699 }
700 _ => {
701 if in_false_branch {
702 i += 1;
703 continue;
704 }
705
706 if !execute_opcode(opcode, stack, flags, sigversion)? {
707 return Ok(false);
708 }
709
710 if stack.len() + altstack.len() > MAX_STACK_SIZE {
711 return Err(make_stack_overflow_error());
712 }
713 }
714 }
715 i += 1;
716 }
717
718 if !control_stack.is_empty() {
719 return Err(ConsensusError::ScriptErrorWithCode {
720 code: ScriptErrorCode::UnbalancedConditional,
721 message: "Unclosed IF/NOTIF block".into(),
722 });
723 }
724
725 Ok(true)
727}
728
729#[deprecated(
742 since = "0.1.33",
743 note = "Use verify_script_with_context for witness-aware script verification"
744)]
745#[spec_locked("5.2", "VerifyScript")]
746#[cfg_attr(feature = "production", inline(always))]
747#[cfg_attr(not(feature = "production"), inline)]
748pub fn verify_script(
749 script_sig: &ByteString,
750 script_pubkey: &[u8],
751 witness: Option<&ByteString>,
752 flags: u32,
753) -> Result<bool> {
754 let sigversion = SigVersion::Base;
756
757 #[cfg(feature = "production")]
758 {
759 if !is_caching_disabled() {
761 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
762 {
763 let cache = get_script_cache().read().unwrap_or_else(|e| e.into_inner());
764 if let Some(&cached_result) = cache.peek(&cache_key) {
765 return Ok(cached_result);
766 }
767 }
768 }
769
770 let mut stack = get_pooled_stack();
773 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
774 let result = {
775 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
776 if !is_caching_disabled() {
778 let mut cache = get_script_cache()
779 .write()
780 .unwrap_or_else(|e| e.into_inner());
781 cache.put(cache_key, false);
782 }
783 false
784 } else if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
785 if !is_caching_disabled() {
786 let mut cache = get_script_cache()
787 .write()
788 .unwrap_or_else(|e| e.into_inner());
789 cache.put(cache_key, false);
790 }
791 false
792 } else if let Some(w) = witness {
793 if !eval_script(w, &mut stack, flags, sigversion)? {
794 if !is_caching_disabled() {
795 let mut cache = get_script_cache()
796 .write()
797 .unwrap_or_else(|e| e.into_inner());
798 cache.put(cache_key, false);
799 }
800 false
801 } else {
802 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
803 if !is_caching_disabled() {
804 let mut cache = get_script_cache()
805 .write()
806 .unwrap_or_else(|e| e.into_inner());
807 cache.put(cache_key, res);
808 }
809 res
810 }
811 } else {
812 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
813 if !is_caching_disabled() {
814 let mut cache = get_script_cache()
815 .write()
816 .unwrap_or_else(|e| e.into_inner());
817 cache.put(cache_key, res);
818 }
819 res
820 }
821 };
822
823 return_pooled_stack(stack);
825
826 Ok(result)
827 }
828
829 #[cfg(not(feature = "production"))]
830 {
831 let mut stack = Vec::with_capacity(20);
833
834 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
836 return Ok(false);
837 }
838
839 if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
841 return Ok(false);
842 }
843
844 if let Some(w) = witness {
846 if !eval_script(w, &mut stack, flags, sigversion)? {
847 return Ok(false);
848 }
849 }
850
851 Ok(!stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]))
853 }
854}
855
856#[spec_locked("5.2", "VerifyScript")]
869#[cfg_attr(feature = "production", inline(always))]
870#[cfg_attr(not(feature = "production"), inline)]
871#[allow(clippy::too_many_arguments)]
872pub fn verify_script_with_context(
873 script_sig: &ByteString,
874 script_pubkey: &[u8],
875 witness: Option<&crate::witness::Witness>,
876 flags: u32,
877 tx: &Transaction,
878 input_index: usize,
879 prevouts: &[TransactionOutput],
880 block_height: Option<u64>,
881 network: crate::types::Network,
882) -> Result<bool> {
883 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
885 let prevout_script_pubkeys: Vec<&[u8]> =
886 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
887
888 verify_script_with_context_full(
889 script_sig,
890 script_pubkey,
891 witness,
892 flags,
893 tx,
894 input_index,
895 &prevout_values,
896 &prevout_script_pubkeys,
897 block_height,
898 None, network,
900 SigVersion::Base, #[cfg(feature = "production")]
902 None, None, #[cfg(feature = "production")]
905 None, #[cfg(feature = "production")]
907 None, #[cfg(feature = "production")]
909 None, )
911}
912
913#[cfg(feature = "production")]
920#[allow(clippy::too_many_arguments)]
921pub fn try_verify_p2pk_fast_path(
922 script_sig: &ByteString,
923 script_pubkey: &[u8],
924 flags: u32,
925 tx: &Transaction,
926 input_index: usize,
927 prevout_values: &[i64],
928 prevout_script_pubkeys: &[&[u8]],
929 block_height: Option<u64>,
930 network: crate::types::Network,
931 #[cfg(feature = "production")] sighash_cache: Option<
932 &crate::transaction_hash::SighashMidstateCache,
933 >,
934) -> Option<Result<bool>> {
935 let len = script_pubkey.len();
938 if len != 35 && len != 67 {
939 return None;
940 }
941 if script_pubkey[len - 1] != OP_CHECKSIG {
942 return None;
943 }
944 let pubkey_len = len - 2; if pubkey_len != 33 && pubkey_len != 65 {
946 return None;
947 }
948 if script_pubkey[0] != 0x21 && script_pubkey[0] != 0x41 {
949 return None; }
951 let pubkey_bytes = &script_pubkey[1..(len - 1)];
952
953 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
954 if signature_bytes.is_empty() {
955 return Some(Ok(false));
956 }
957
958 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
960 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
961 let sighash_type = SighashType::from_byte(sighash_byte);
962 let deleted_storage;
963 let script_code: &[u8] = if script_pubkey.len() < 71 {
964 script_pubkey
965 } else {
966 let pattern = serialize_push_data(signature_bytes);
967 deleted_storage = find_and_delete(script_pubkey, &pattern);
968 deleted_storage.as_ref()
969 };
970 let sighash = match calculate_transaction_sighash_single_input(
971 tx,
972 input_index,
973 script_code,
974 prevout_values[input_index],
975 sighash_type,
976 #[cfg(feature = "production")]
977 sighash_cache,
978 ) {
979 Ok(h) => h,
980 Err(e) => return Some(Err(e)),
981 };
982
983 let height = block_height.unwrap_or(0);
984 let is_valid = signature::with_secp_context(|secp| {
985 signature::verify_signature(
986 secp,
987 pubkey_bytes,
988 signature_bytes,
989 &sighash,
990 flags,
991 height,
992 network,
993 SigVersion::Base,
994 )
995 });
996 Some(is_valid)
997}
998
999#[cfg(feature = "production")]
1002#[allow(clippy::too_many_arguments)]
1003pub fn try_verify_p2pkh_fast_path(
1004 script_sig: &ByteString,
1005 script_pubkey: &[u8],
1006 flags: u32,
1007 tx: &Transaction,
1008 input_index: usize,
1009 prevout_values: &[i64],
1010 prevout_script_pubkeys: &[&[u8]],
1011 block_height: Option<u64>,
1012 network: crate::types::Network,
1013 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1014 #[cfg(feature = "production")] sighash_cache: Option<
1015 &crate::transaction_hash::SighashMidstateCache,
1016 >,
1017 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
1018) -> Option<Result<bool>> {
1019 #[cfg(all(feature = "production", feature = "profile"))]
1020 let _t_entry = std::time::Instant::now();
1021 if script_pubkey.len() != 25 {
1023 return None;
1024 }
1025 if script_pubkey[0] != OP_DUP
1026 || script_pubkey[1] != OP_HASH160
1027 || script_pubkey[2] != PUSH_20_BYTES
1028 || script_pubkey[23] != OP_EQUALVERIFY
1029 || script_pubkey[24] != OP_CHECKSIG
1030 {
1031 return None;
1032 }
1033 let expected_hash = &script_pubkey[3..23];
1034
1035 #[cfg(all(feature = "production", feature = "profile"))]
1036 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
1037 #[cfg(all(feature = "production", feature = "profile"))]
1038 let _t_parse = std::time::Instant::now();
1039 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
1040 #[cfg(all(feature = "production", feature = "profile"))]
1041 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
1042
1043 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1045 return Some(Ok(false));
1046 }
1047 if signature_bytes.is_empty() {
1049 return Some(Ok(false));
1050 }
1051
1052 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
1054 Some(h) => h,
1055 None => {
1056 #[cfg(all(feature = "production", feature = "profile"))]
1057 let _t_hash = std::time::Instant::now();
1058 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1059 let h = Ripemd160::digest(sha256_hash);
1060 #[cfg(all(feature = "production", feature = "profile"))]
1061 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1062 h.into()
1063 }
1064 };
1065 if &pubkey_hash[..] != expected_hash {
1066 return Some(Ok(false));
1067 }
1068
1069 use crate::transaction_hash::SighashType;
1072 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1073 let sighash_type = SighashType::from_byte(sighash_byte);
1074 let deleted_storage;
1075 let script_code: &[u8] = if script_pubkey.len() < 71 {
1076 script_pubkey
1077 } else {
1078 let pattern = serialize_push_data(signature_bytes);
1079 deleted_storage = find_and_delete(script_pubkey, &pattern);
1080 deleted_storage.as_ref()
1081 };
1082 let sighash = {
1083 #[cfg(feature = "production")]
1084 {
1085 if let Some(precomp) = precomputed_sighash_all {
1086 precomp
1087 } else {
1088 crate::transaction_hash::compute_legacy_sighash_nocache(
1089 tx,
1090 input_index,
1091 script_code,
1092 sighash_byte,
1093 )
1094 }
1095 }
1096 #[cfg(not(feature = "production"))]
1097 {
1098 match calculate_transaction_sighash_single_input(
1099 tx,
1100 input_index,
1101 script_code,
1102 prevout_values[input_index],
1103 sighash_type,
1104 ) {
1105 Ok(h) => h,
1106 Err(e) => return Some(Err(e)),
1107 }
1108 }
1109 };
1110
1111 #[cfg(all(feature = "production", feature = "profile"))]
1112 let _t_secp = std::time::Instant::now();
1113 let height = block_height.unwrap_or(0);
1114 let is_valid: Result<bool> = {
1115 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1116 if flags & 0x04 != 0
1117 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1118 .unwrap_or(false)
1119 {
1120 Ok(false)
1121 } else if flags & 0x02 != 0 {
1122 let base_sighash = sighash_byte & !0x80;
1123 if !(0x01..=0x03).contains(&base_sighash) {
1124 Ok(false)
1125 } else if pubkey_bytes.len() == 33 {
1126 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
1127 Ok(false)
1128 } else {
1129 let strict_der = flags & 0x04 != 0;
1130 let enforce_low_s = flags & 0x08 != 0;
1131 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1132 der_sig,
1133 pubkey_bytes,
1134 &sighash,
1135 strict_der,
1136 enforce_low_s,
1137 )
1138 .unwrap_or(false))
1139 }
1140 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1141 let strict_der = flags & 0x04 != 0;
1142 let enforce_low_s = flags & 0x08 != 0;
1143 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1144 der_sig,
1145 pubkey_bytes,
1146 &sighash,
1147 strict_der,
1148 enforce_low_s,
1149 )
1150 .unwrap_or(false))
1151 } else {
1152 Ok(false)
1153 }
1154 } else {
1155 let strict_der = flags & 0x04 != 0;
1156 let enforce_low_s = flags & 0x08 != 0;
1157 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1158 der_sig,
1159 pubkey_bytes,
1160 &sighash,
1161 strict_der,
1162 enforce_low_s,
1163 )
1164 .unwrap_or(false))
1165 }
1166 };
1167 #[cfg(all(feature = "production", feature = "profile"))]
1168 {
1169 let ns = _t_secp.elapsed().as_nanos() as u64;
1170 crate::script_profile::add_p2pkh_collect_ns(ns);
1171 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1172 }
1173 Some(is_valid)
1174}
1175
1176#[cfg(feature = "production")]
1182#[inline]
1183pub fn verify_p2pkh_inline(
1184 script_sig: &[u8],
1185 script_pubkey: &[u8],
1186 flags: u32,
1187 tx: &Transaction,
1188 input_index: usize,
1189 height: u64,
1190 network: crate::types::Network,
1191 precomputed_sighash_all: Option<[u8; 32]>,
1192) -> Result<bool> {
1193 #[cfg(feature = "profile")]
1194 let _t0 = std::time::Instant::now();
1195
1196 let expected_hash = &script_pubkey[3..23];
1197
1198 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1199 Some(pair) => pair,
1200 None => return Ok(false),
1201 };
1202
1203 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1204 return Ok(false);
1205 }
1206
1207 #[cfg(feature = "profile")]
1208 let _t_hash = std::time::Instant::now();
1209
1210 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1211 let pubkey_hash: [u8; 20] = Ripemd160::digest(sha256_hash).into();
1212 if &pubkey_hash[..] != expected_hash {
1213 return Ok(false);
1214 }
1215
1216 #[cfg(feature = "profile")]
1217 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1218
1219 #[cfg(feature = "profile")]
1220 let _t_sighash = std::time::Instant::now();
1221
1222 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1223 let sighash = if let Some(precomp) = precomputed_sighash_all {
1224 precomp
1225 } else {
1226 crate::transaction_hash::compute_legacy_sighash_buffered(
1227 tx,
1228 input_index,
1229 script_pubkey,
1230 sighash_byte,
1231 )
1232 };
1233
1234 #[cfg(feature = "profile")]
1235 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1236
1237 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1238 let strict_der = flags & 0x04 != 0;
1239 let enforce_low_s = flags & 0x08 != 0;
1240
1241 if strict_der
1242 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1243 .unwrap_or(false)
1244 {
1245 return Ok(false);
1246 }
1247
1248 if flags & 0x02 != 0 {
1249 let sighash_base = sighash_byte & !0x80;
1250 if !(0x01..=0x03).contains(&sighash_base) {
1251 return Ok(false);
1252 }
1253 match pubkey_bytes.len() {
1254 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1255 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1256 33 | 65 => {}
1257 _ => return Ok(false),
1258 }
1259 }
1260
1261 #[cfg(feature = "profile")]
1262 let _t_secp = std::time::Instant::now();
1263
1264 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1265 der_sig,
1266 pubkey_bytes,
1267 &sighash,
1268 strict_der,
1269 enforce_low_s,
1270 )
1271 .unwrap_or(false);
1272
1273 #[cfg(feature = "profile")]
1274 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1275
1276 #[cfg(feature = "profile")]
1277 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1278
1279 Ok(result)
1280}
1281
1282#[cfg(feature = "production")]
1284#[inline]
1285pub fn verify_p2pk_inline(
1286 script_sig: &[u8],
1287 script_pubkey: &[u8],
1288 flags: u32,
1289 tx: &Transaction,
1290 input_index: usize,
1291 height: u64,
1292 network: crate::types::Network,
1293) -> Result<bool> {
1294 let pk_len = script_pubkey.len() - 2; let pubkey_bytes = &script_pubkey[1..1 + pk_len];
1296
1297 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1298 Some(s) => s,
1299 None => return Ok(false),
1300 };
1301 if signature_bytes.is_empty() {
1302 return Ok(false);
1303 }
1304
1305 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1306 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_buffered(
1309 tx,
1310 input_index,
1311 script_code,
1312 sighash_byte,
1313 );
1314
1315 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1316 let strict_der = flags & 0x04 != 0;
1317 let enforce_low_s = flags & 0x08 != 0;
1318
1319 if strict_der
1320 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1321 .unwrap_or(false)
1322 {
1323 return Ok(false);
1324 }
1325
1326 if flags & 0x02 != 0 {
1327 let sighash_base = sighash_byte & !0x80;
1328 if !(0x01..=0x03).contains(&sighash_base) {
1329 return Ok(false);
1330 }
1331 match pubkey_bytes.len() {
1332 33 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 => return Ok(false),
1333 65 if pubkey_bytes[0] != 0x04 => return Ok(false),
1334 33 | 65 => {}
1335 _ => return Ok(false),
1336 }
1337 }
1338
1339 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1340 der_sig,
1341 pubkey_bytes,
1342 &sighash,
1343 strict_der,
1344 enforce_low_s,
1345 )
1346 .unwrap_or(false))
1347}
1348
1349#[allow(clippy::too_many_arguments)]
1353fn try_verify_p2sh_multisig_fast_path(
1354 script_sig: &ByteString,
1355 script_pubkey: &[u8],
1356 flags: u32,
1357 tx: &Transaction,
1358 input_index: usize,
1359 prevout_values: &[i64],
1360 prevout_script_pubkeys: &[&[u8]],
1361 block_height: Option<u64>,
1362 network: crate::types::Network,
1363 #[cfg(feature = "production")] sighash_cache: Option<
1364 &crate::transaction_hash::SighashMidstateCache,
1365 >,
1366) -> Option<Result<bool>> {
1367 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1368 if pushes.len() < 2 {
1369 return None;
1370 }
1371 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1372 let expected_hash = &script_pubkey[2..22];
1373 let sha256_hash = OptimizedSha256::new().hash(redeem);
1374 let redeem_hash = Ripemd160::digest(sha256_hash);
1375 if &redeem_hash[..] != expected_hash {
1376 return Some(Ok(false));
1377 }
1378 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1379 let signatures: Vec<&[u8]> = pushes
1380 .iter()
1381 .take(pushes.len() - 1)
1382 .skip(1)
1383 .map(|e| e.as_ref())
1384 .collect();
1385 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1386
1387 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1388 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1389 let height = block_height.unwrap_or(0);
1390 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1391 let activation = match network {
1392 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1393 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1394 crate::types::Network::Regtest | crate::types::Network::Signet => 0,
1395 };
1396 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1397 return Some(Ok(false));
1398 }
1399 }
1400
1401 let mut cleaned = redeem.to_vec();
1402 for sig in &signatures {
1403 if !sig.is_empty() {
1404 let pattern = serialize_push_data(sig);
1405 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1406 }
1407 }
1408
1409 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1410
1411 let mut sig_index = 0;
1412 let mut valid_sigs = 0u8;
1413
1414 for pubkey_bytes in pubkeys {
1415 if sig_index >= signatures.len() {
1416 break;
1417 }
1418 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1419 sig_index += 1;
1420 }
1421 if sig_index >= signatures.len() {
1422 break;
1423 }
1424 let signature_bytes = &signatures[sig_index];
1425 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1426 let sighash_type = SighashType::from_byte(sighash_byte);
1427 let sighash = match calculate_transaction_sighash_single_input(
1428 tx,
1429 input_index,
1430 &cleaned,
1431 prevout_values[input_index],
1432 sighash_type,
1433 #[cfg(feature = "production")]
1434 sighash_cache,
1435 ) {
1436 Ok(h) => h,
1437 Err(e) => return Some(Err(e)),
1438 };
1439
1440 #[cfg(feature = "production")]
1441 let is_valid = signature::with_secp_context(|secp| {
1442 signature::verify_signature(
1443 secp,
1444 pubkey_bytes,
1445 signature_bytes,
1446 &sighash,
1447 flags,
1448 height,
1449 network,
1450 SigVersion::Base,
1451 )
1452 });
1453
1454 #[cfg(not(feature = "production"))]
1455 let is_valid = {
1456 let secp = signature::new_secp();
1457 signature::verify_signature(
1458 &secp,
1459 pubkey_bytes,
1460 signature_bytes,
1461 &sighash,
1462 flags,
1463 height,
1464 network,
1465 SigVersion::Base,
1466 )
1467 };
1468
1469 let is_valid = match is_valid {
1470 Ok(v) => v,
1471 Err(e) => return Some(Err(e)),
1472 };
1473
1474 if is_valid {
1475 valid_sigs += 1;
1476 sig_index += 1;
1477 }
1478 }
1479
1480 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1481 for sig_bytes in &signatures[sig_index..] {
1482 if !sig_bytes.is_empty() {
1483 return Some(Err(ConsensusError::ScriptErrorWithCode {
1484 code: ScriptErrorCode::SigNullFail,
1485 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1486 .into(),
1487 }));
1488 }
1489 }
1490 }
1491
1492 Some(Ok(valid_sigs >= m))
1493}
1494
1495#[allow(clippy::too_many_arguments)]
1498fn try_verify_bare_multisig_fast_path(
1499 script_sig: &ByteString,
1500 script_pubkey: &[u8],
1501 flags: u32,
1502 tx: &Transaction,
1503 input_index: usize,
1504 prevout_values: &[i64],
1505 prevout_script_pubkeys: &[&[u8]],
1506 block_height: Option<u64>,
1507 network: crate::types::Network,
1508 #[cfg(feature = "production")] sighash_cache: Option<
1509 &crate::transaction_hash::SighashMidstateCache,
1510 >,
1511) -> Option<Result<bool>> {
1512 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1513 let pushes = parse_p2sh_script_sig_pushes(script_sig.as_ref())?;
1514 if pushes.len() < 2 {
1515 return None;
1516 }
1517 let dummy = pushes.first().expect("at least 2 pushes").as_ref();
1518 let signatures: Vec<&[u8]> = pushes[1..].iter().map(|e| e.as_ref()).collect();
1519
1520 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
1521 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
1522 let height = block_height.unwrap_or(0);
1523 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
1524 let activation = match network {
1525 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
1526 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
1527 crate::types::Network::Regtest | crate::types::Network::Signet => 0,
1528 };
1529 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
1530 return Some(Ok(false));
1531 }
1532 }
1533
1534 let mut cleaned = script_pubkey.to_vec();
1535 for sig in &signatures {
1536 if !sig.is_empty() {
1537 let pattern = serialize_push_data(sig);
1538 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
1539 }
1540 }
1541
1542 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1543
1544 let mut sig_index = 0;
1545 let mut valid_sigs = 0u8;
1546
1547 for pubkey_bytes in pubkeys {
1548 if sig_index >= signatures.len() {
1549 break;
1550 }
1551 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
1552 sig_index += 1;
1553 }
1554 if sig_index >= signatures.len() {
1555 break;
1556 }
1557 let signature_bytes = &signatures[sig_index];
1558 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1559 let sighash_type = SighashType::from_byte(sighash_byte);
1560 let sighash = match calculate_transaction_sighash_single_input(
1561 tx,
1562 input_index,
1563 &cleaned,
1564 prevout_values[input_index],
1565 sighash_type,
1566 #[cfg(feature = "production")]
1567 sighash_cache,
1568 ) {
1569 Ok(h) => h,
1570 Err(e) => return Some(Err(e)),
1571 };
1572
1573 #[cfg(feature = "production")]
1574 let is_valid = signature::with_secp_context(|secp| {
1575 signature::verify_signature(
1576 secp,
1577 pubkey_bytes,
1578 signature_bytes,
1579 &sighash,
1580 flags,
1581 height,
1582 network,
1583 SigVersion::Base,
1584 )
1585 });
1586
1587 #[cfg(not(feature = "production"))]
1588 let is_valid = {
1589 let secp = signature::new_secp();
1590 signature::verify_signature(
1591 &secp,
1592 pubkey_bytes,
1593 signature_bytes,
1594 &sighash,
1595 flags,
1596 height,
1597 network,
1598 SigVersion::Base,
1599 )
1600 };
1601
1602 let is_valid = match is_valid {
1603 Ok(v) => v,
1604 Err(e) => return Some(Err(e)),
1605 };
1606
1607 if is_valid {
1608 valid_sigs += 1;
1609 sig_index += 1;
1610 }
1611 }
1612
1613 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
1614 for sig_bytes in &signatures[sig_index..] {
1615 if !sig_bytes.is_empty() {
1616 return Some(Err(ConsensusError::ScriptErrorWithCode {
1617 code: ScriptErrorCode::SigNullFail,
1618 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
1619 .into(),
1620 }));
1621 }
1622 }
1623 }
1624
1625 Some(Ok(valid_sigs >= m))
1626}
1627
1628#[cfg(feature = "production")]
1632#[allow(clippy::too_many_arguments)]
1633fn try_verify_p2sh_fast_path(
1634 script_sig: &ByteString,
1635 script_pubkey: &[u8],
1636 flags: u32,
1637 tx: &Transaction,
1638 input_index: usize,
1639 prevout_values: &[i64],
1640 prevout_script_pubkeys: &[&[u8]],
1641 block_height: Option<u64>,
1642 median_time_past: Option<u64>,
1643 network: crate::types::Network,
1644 #[cfg(feature = "production")] sighash_cache: Option<
1645 &crate::transaction_hash::SighashMidstateCache,
1646 >,
1647 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1648) -> Option<Result<bool>> {
1649 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1650 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1651 return None;
1652 }
1653 if script_pubkey.len() != 23
1655 || script_pubkey[0] != OP_HASH160
1656 || script_pubkey[1] != PUSH_20_BYTES
1657 || script_pubkey[22] != OP_EQUAL
1658 {
1659 return None;
1660 }
1661 let expected_hash = &script_pubkey[2..22];
1662
1663 let mut pushes = parse_script_sig_push_only(script_sig.as_ref())?;
1664 if pushes.is_empty() {
1665 return None;
1666 }
1667 let redeem = pushes.pop().expect("at least one push");
1668 let mut stack = pushes;
1669
1670 if redeem.len() >= 3
1672 && redeem[0] == OP_0
1673 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
1674 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
1675 {
1676 return None;
1677 }
1678
1679 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
1681 let redeem_hash = Ripemd160::digest(sha256_hash);
1682 if &redeem_hash[..] != expected_hash {
1683 return Some(Ok(false));
1684 }
1685
1686 if redeem.len() == 25
1688 && redeem[0] == OP_DUP
1689 && redeem[1] == OP_HASH160
1690 && redeem[2] == PUSH_20_BYTES
1691 && redeem[23] == OP_EQUALVERIFY
1692 && redeem[24] == OP_CHECKSIG
1693 && stack.len() == 2
1694 {
1695 let signature_bytes = &stack[0];
1696 let pubkey_bytes = &stack[1];
1697 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
1698 let expected_pubkey_hash = &redeem[3..23];
1699 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1700 let pubkey_hash = Ripemd160::digest(sha256_hash);
1701 if &pubkey_hash[..] == expected_pubkey_hash {
1702 #[cfg(feature = "production")]
1703 let sighash = if let Some(precomp) = precomputed_sighash_all {
1704 precomp
1705 } else {
1706 use crate::transaction_hash::{
1707 SighashType, calculate_transaction_sighash_single_input,
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 sighash_cache,
1726 ) {
1727 Ok(h) => h,
1728 Err(e) => return Some(Err(e)),
1729 }
1730 };
1731 #[cfg(not(feature = "production"))]
1732 let sighash = {
1733 use crate::transaction_hash::{
1734 SighashType, calculate_transaction_sighash_single_input,
1735 };
1736 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1737 let sighash_type = SighashType::from_byte(sighash_byte);
1738 let deleted_storage;
1739 let script_code: &[u8] = if redeem.len() < 71 {
1740 redeem.as_ref()
1741 } else {
1742 let pattern = serialize_push_data(signature_bytes);
1743 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1744 deleted_storage.as_ref()
1745 };
1746 match calculate_transaction_sighash_single_input(
1747 tx,
1748 input_index,
1749 script_code,
1750 prevout_values[input_index],
1751 sighash_type,
1752 ) {
1753 Ok(h) => h,
1754 Err(e) => return Some(Err(e)),
1755 }
1756 };
1757 let height = block_height.unwrap_or(0);
1758 let is_valid = signature::with_secp_context(|secp| {
1759 signature::verify_signature(
1760 secp,
1761 pubkey_bytes,
1762 signature_bytes,
1763 &sighash,
1764 flags,
1765 height,
1766 network,
1767 SigVersion::Base,
1768 )
1769 });
1770 return Some(is_valid);
1771 }
1772 }
1773 }
1774
1775 if (redeem.len() == 35 || redeem.len() == 67)
1777 && redeem[redeem.len() - 1] == OP_CHECKSIG
1778 && (redeem[0] == 0x21 || redeem[0] == 0x41)
1779 && stack.len() == 1
1780 {
1781 let pubkey_len = redeem.len() - 2;
1782 if pubkey_len == 33 || pubkey_len == 65 {
1783 let pubkey_bytes = &redeem.as_ref()[1..(redeem.len() - 1)];
1784 let signature_bytes = &stack[0];
1785 if !signature_bytes.is_empty() {
1786 use crate::transaction_hash::{
1787 SighashType, calculate_transaction_sighash_single_input,
1788 };
1789 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1790 let sighash_type = SighashType::from_byte(sighash_byte);
1791 let deleted_storage;
1793 let script_code: &[u8] = if redeem.len() < 71 {
1794 redeem.as_ref()
1795 } else {
1796 let pattern = serialize_push_data(signature_bytes);
1797 deleted_storage = find_and_delete(redeem.as_ref(), &pattern);
1798 deleted_storage.as_ref()
1799 };
1800 match calculate_transaction_sighash_single_input(
1801 tx,
1802 input_index,
1803 script_code,
1804 prevout_values[input_index],
1805 sighash_type,
1806 #[cfg(feature = "production")]
1807 sighash_cache,
1808 ) {
1809 Ok(sighash) => {
1810 let height = block_height.unwrap_or(0);
1811 let is_valid = signature::with_secp_context(|secp| {
1812 signature::verify_signature(
1813 secp,
1814 pubkey_bytes,
1815 signature_bytes,
1816 &sighash,
1817 flags,
1818 height,
1819 network,
1820 SigVersion::Base,
1821 )
1822 });
1823 return Some(is_valid);
1824 }
1825 Err(e) => return Some(Err(e)),
1826 }
1827 }
1828 }
1829 }
1830
1831 let result = eval_script_with_context_full_inner(
1833 &redeem,
1834 &mut stack,
1835 flags,
1836 tx,
1837 input_index,
1838 prevout_values,
1839 prevout_script_pubkeys,
1840 block_height,
1841 median_time_past,
1842 network,
1843 SigVersion::Base,
1844 Some(redeem.as_ref()),
1845 None, None, #[cfg(feature = "production")]
1848 None, None, #[cfg(feature = "production")]
1851 sighash_cache,
1852 );
1853 Some(result)
1854}
1855
1856#[cfg(feature = "production")]
1859#[allow(clippy::too_many_arguments)]
1860fn try_verify_p2wpkh_fast_path(
1861 script_sig: &ByteString,
1862 script_pubkey: &[u8],
1863 witness: &crate::witness::Witness,
1864 flags: u32,
1865 tx: &Transaction,
1866 input_index: usize,
1867 prevout_values: &[i64],
1868 prevout_script_pubkeys: &[&[u8]],
1869 block_height: Option<u64>,
1870 network: crate::types::Network,
1871 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1872 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1873) -> Option<Result<bool>> {
1874 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
1876 return None;
1877 }
1878 if !script_sig.is_empty() {
1880 return None;
1881 }
1882 if witness.len() != 2 {
1883 return None;
1884 }
1885 let signature_bytes = &witness[0];
1886 let pubkey_bytes = &witness[1];
1887
1888 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1889 return Some(Ok(false));
1890 }
1891 if signature_bytes.is_empty() {
1892 return Some(Ok(false));
1893 }
1894
1895 let expected_hash = &script_pubkey[2..22];
1896 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1897 let pubkey_hash = Ripemd160::digest(sha256_hash);
1898 if &pubkey_hash[..] != expected_hash {
1899 return Some(Ok(false));
1900 }
1901
1902 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_hash);
1904
1905 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1906 let sighash = if sighash_byte == 0x01 {
1907 #[cfg(feature = "production")]
1909 if let Some(precomp) = precomputed_sighash_all {
1910 precomp
1911 } else {
1912 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1913 match crate::transaction_hash::calculate_bip143_sighash(
1914 tx,
1915 input_index,
1916 &p2pkh_script_code,
1917 amount,
1918 sighash_byte,
1919 precomputed_bip143,
1920 ) {
1921 Ok(h) => h,
1922 Err(e) => return Some(Err(e)),
1923 }
1924 }
1925 #[cfg(not(feature = "production"))]
1926 {
1927 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1928 match crate::transaction_hash::calculate_bip143_sighash(
1929 tx,
1930 input_index,
1931 &p2pkh_script_code,
1932 amount,
1933 sighash_byte,
1934 precomputed_bip143,
1935 ) {
1936 Ok(h) => h,
1937 Err(e) => return Some(Err(e)),
1938 }
1939 }
1940 } else {
1941 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
1942 match crate::transaction_hash::calculate_bip143_sighash(
1943 tx,
1944 input_index,
1945 &p2pkh_script_code,
1946 amount,
1947 sighash_byte,
1948 precomputed_bip143,
1949 ) {
1950 Ok(h) => h,
1951 Err(e) => return Some(Err(e)),
1952 }
1953 };
1954
1955 let height = block_height.unwrap_or(0);
1956 let is_valid = signature::with_secp_context(|secp| {
1957 signature::verify_signature(
1958 secp,
1959 pubkey_bytes,
1960 signature_bytes,
1961 &sighash,
1962 flags,
1963 height,
1964 network,
1965 SigVersion::WitnessV0,
1966 )
1967 });
1968 Some(is_valid)
1969}
1970
1971#[cfg(feature = "production")]
1973#[allow(clippy::too_many_arguments)]
1974fn try_verify_p2wpkh_in_p2sh_fast_path(
1975 script_sig: &ByteString,
1976 script_pubkey: &[u8],
1977 witness: &crate::witness::Witness,
1978 flags: u32,
1979 tx: &Transaction,
1980 input_index: usize,
1981 prevout_values: &[i64],
1982 prevout_script_pubkeys: &[&[u8]],
1983 block_height: Option<u64>,
1984 network: crate::types::Network,
1985 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
1986) -> Option<Result<bool>> {
1987 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
1988 if (flags & SCRIPT_VERIFY_P2SH) == 0 {
1989 return None;
1990 }
1991 if script_pubkey.len() != 23
1992 || script_pubkey[0] != OP_HASH160
1993 || script_pubkey[1] != PUSH_20_BYTES
1994 || script_pubkey[22] != OP_EQUAL
1995 {
1996 return None;
1997 }
1998 let expected_hash = &script_pubkey[2..22];
1999
2000 let pushes = parse_script_sig_push_only(script_sig.as_ref())?;
2001 if pushes.len() != 1 {
2002 return None;
2003 }
2004 let redeem = &pushes[0];
2005 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
2006 return None;
2007 }
2008 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
2009 let redeem_hash = Ripemd160::digest(sha256_hash);
2010 if &redeem_hash[..] != expected_hash {
2011 return Some(Ok(false));
2012 }
2013
2014 if witness.len() != 2 {
2015 return None;
2016 }
2017 let signature_bytes = &witness[0];
2018 let pubkey_bytes = &witness[1];
2019 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
2020 return Some(Ok(false));
2021 }
2022 let expected_pubkey_hash = &redeem[2..22];
2023 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2024 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2025 if &pubkey_hash[..] != expected_pubkey_hash {
2026 return Some(Ok(false));
2027 }
2028
2029 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_pubkey_hash);
2031
2032 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2033 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2034 let sighash = match crate::transaction_hash::calculate_bip143_sighash(
2035 tx,
2036 input_index,
2037 &p2pkh_script_code,
2038 amount,
2039 sighash_byte,
2040 precomputed_bip143,
2041 ) {
2042 Ok(h) => h,
2043 Err(e) => return Some(Err(e)),
2044 };
2045
2046 let height = block_height.unwrap_or(0);
2047 let is_valid = signature::with_secp_context(|secp| {
2048 signature::verify_signature(
2049 secp,
2050 pubkey_bytes,
2051 signature_bytes,
2052 &sighash,
2053 flags,
2054 height,
2055 network,
2056 SigVersion::WitnessV0,
2057 )
2058 });
2059 Some(is_valid)
2060}
2061
2062#[cfg(feature = "production")]
2065#[allow(clippy::too_many_arguments)]
2066fn try_verify_p2wsh_fast_path(
2067 script_sig: &ByteString,
2068 script_pubkey: &[u8],
2069 witness: &crate::witness::Witness,
2070 flags: u32,
2071 tx: &Transaction,
2072 input_index: usize,
2073 prevout_values: &[i64],
2074 prevout_script_pubkeys: &[&[u8]],
2075 block_height: Option<u64>,
2076 median_time_past: Option<u64>,
2077 network: crate::types::Network,
2078 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2079 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2080 #[cfg(feature = "production")] sighash_cache: Option<
2081 &crate::transaction_hash::SighashMidstateCache,
2082 >,
2083) -> Option<Result<bool>> {
2084 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
2086 return None;
2087 }
2088 if !script_sig.is_empty() {
2089 return None;
2090 }
2091 if witness.is_empty() {
2092 return None;
2093 }
2094 let witness_script = witness.last().expect("witness not empty").clone();
2095 let mut stack: Vec<StackElement> = witness
2096 .iter()
2097 .take(witness.len() - 1)
2098 .map(|w| to_stack_element(w))
2099 .collect();
2100
2101 let program_hash = &script_pubkey[2..34];
2102 if program_hash.len() != 32 {
2103 return None;
2104 }
2105 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2106 if &witness_script_hash[..] != program_hash {
2107 return Some(Ok(false));
2108 }
2109
2110 let witness_sigversion = SigVersion::WitnessV0;
2114
2115 if witness_sigversion == SigVersion::WitnessV0
2117 && witness_script.len() == 25
2118 && witness_script[0] == OP_DUP
2119 && witness_script[1] == OP_HASH160
2120 && witness_script[2] == PUSH_20_BYTES
2121 && witness_script[23] == OP_EQUALVERIFY
2122 && witness_script[24] == OP_CHECKSIG
2123 && stack.len() == 2
2124 {
2125 let signature_bytes = &stack[0];
2126 let pubkey_bytes = &stack[1];
2127 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2128 let expected_pubkey_hash = &witness_script[3..23];
2129 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2130 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2131 if &pubkey_hash[..] == expected_pubkey_hash {
2132 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2133 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2134 match crate::transaction_hash::calculate_bip143_sighash(
2135 tx,
2136 input_index,
2137 witness_script.as_ref(),
2138 amount,
2139 sighash_byte,
2140 precomputed_bip143,
2141 ) {
2142 Ok(sighash) => {
2143 let height = block_height.unwrap_or(0);
2144 let is_valid = signature::with_secp_context(|secp| {
2145 signature::verify_signature(
2146 secp,
2147 pubkey_bytes,
2148 signature_bytes,
2149 &sighash,
2150 flags,
2151 height,
2152 network,
2153 SigVersion::WitnessV0,
2154 )
2155 });
2156 return Some(is_valid);
2157 }
2158 Err(e) => return Some(Err(e)),
2159 }
2160 }
2161 }
2162 }
2163
2164 if witness_sigversion == SigVersion::WitnessV0
2166 && (witness_script.len() == 35 || witness_script.len() == 67)
2167 && witness_script[witness_script.len() - 1] == OP_CHECKSIG
2168 && (witness_script[0] == 0x21 || witness_script[0] == 0x41)
2169 && stack.len() == 1
2170 {
2171 let pubkey_len = witness_script.len() - 2;
2172 if (pubkey_len == 33 || pubkey_len == 65) && !stack[0].is_empty() {
2173 let pubkey_bytes = &witness_script[1..(witness_script.len() - 1)];
2174 let signature_bytes = &stack[0];
2175 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2176 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2177 match crate::transaction_hash::calculate_bip143_sighash(
2178 tx,
2179 input_index,
2180 witness_script.as_ref(),
2181 amount,
2182 sighash_byte,
2183 precomputed_bip143,
2184 ) {
2185 Ok(sighash) => {
2186 let height = block_height.unwrap_or(0);
2187 let is_valid = signature::with_secp_context(|secp| {
2188 signature::verify_signature(
2189 secp,
2190 pubkey_bytes,
2191 signature_bytes,
2192 &sighash,
2193 flags,
2194 height,
2195 network,
2196 SigVersion::WitnessV0,
2197 )
2198 });
2199 return Some(is_valid);
2200 }
2201 Err(e) => return Some(Err(e)),
2202 }
2203 }
2204 }
2205
2206 if witness_sigversion == SigVersion::WitnessV0 {
2208 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script.as_ref()) {
2209 if stack.len() < 2 {
2210 return Some(Ok(false));
2211 }
2212 let dummy = stack[0].as_ref();
2213 let signatures: Vec<&[u8]> = stack[1..].iter().map(|e| e.as_ref()).collect();
2214
2215 const SCRIPT_VERIFY_NULLDUMMY: u32 = 0x10;
2216 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
2217 let height = block_height.unwrap_or(0);
2218 if (flags & SCRIPT_VERIFY_NULLDUMMY) != 0 {
2219 let activation = match network {
2220 crate::types::Network::Mainnet => crate::constants::BIP147_ACTIVATION_MAINNET,
2221 crate::types::Network::Testnet => crate::constants::BIP147_ACTIVATION_TESTNET,
2222 crate::types::Network::Regtest | crate::types::Network::Signet => 0,
2223 };
2224 if height >= activation && !dummy.is_empty() && dummy != [0x00] {
2225 return Some(Ok(false));
2226 }
2227 }
2228
2229 let mut cleaned = witness_script.to_vec();
2230 for sig in &signatures {
2231 if !sig.is_empty() {
2232 let pattern = serialize_push_data(sig);
2233 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
2234 }
2235 }
2236
2237 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2238 let mut sig_index = 0;
2239 let mut valid_sigs = 0u8;
2240
2241 for pubkey_bytes in pubkeys {
2242 if sig_index >= signatures.len() {
2243 break;
2244 }
2245 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
2246 sig_index += 1;
2247 }
2248 if sig_index >= signatures.len() {
2249 break;
2250 }
2251 let signature_bytes = &signatures[sig_index];
2252 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2253 match crate::transaction_hash::calculate_bip143_sighash(
2254 tx,
2255 input_index,
2256 &cleaned,
2257 amount,
2258 sighash_byte,
2259 precomputed_bip143,
2260 ) {
2261 Ok(sighash) => {
2262 let is_valid = signature::with_secp_context(|secp| {
2263 signature::verify_signature(
2264 secp,
2265 pubkey_bytes,
2266 signature_bytes,
2267 &sighash,
2268 flags,
2269 height,
2270 network,
2271 SigVersion::WitnessV0,
2272 )
2273 });
2274 match is_valid {
2275 Ok(v) if v => {
2276 valid_sigs += 1;
2277 sig_index += 1;
2278 }
2279 Ok(_) => {}
2280 Err(e) => return Some(Err(e)),
2281 }
2282 }
2283 Err(e) => return Some(Err(e)),
2284 }
2285 }
2286
2287 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
2288 for sig_bytes in &signatures[sig_index..] {
2289 if !sig_bytes.is_empty() {
2290 return Some(Err(ConsensusError::ScriptErrorWithCode {
2291 code: ScriptErrorCode::SigNullFail,
2292 message:
2293 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
2294 .into(),
2295 }));
2296 }
2297 }
2298 }
2299
2300 return Some(Ok(valid_sigs >= m));
2301 }
2302 }
2303
2304 let result = eval_script_with_context_full_inner(
2307 &witness_script,
2308 &mut stack,
2309 flags,
2310 tx,
2311 input_index,
2312 prevout_values,
2313 prevout_script_pubkeys,
2314 block_height,
2315 median_time_past,
2316 network,
2317 witness_sigversion,
2318 Some(witness_script.as_ref()), None, None, schnorr_collector,
2322 precomputed_bip143,
2323 #[cfg(feature = "production")]
2324 sighash_cache,
2325 );
2326 Some(result)
2327}
2328
2329#[cfg(feature = "production")]
2331#[allow(clippy::too_many_arguments)]
2332fn try_verify_p2tr_scriptpath_p2pk_fast_path(
2333 script_sig: &ByteString,
2334 script_pubkey: &[u8],
2335 witness: &crate::witness::Witness,
2336 _flags: u32,
2337 tx: &Transaction,
2338 input_index: usize,
2339 prevout_values: &[i64],
2340 prevout_script_pubkeys: &[&[u8]],
2341 block_height: Option<u64>,
2342 network: crate::types::Network,
2343 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2344) -> Option<Result<bool>> {
2345 use crate::activation::taproot_active_at_height;
2346 use crate::taproot::parse_taproot_script_path_witness;
2347
2348 if !taproot_active_at_height(block_height, network) {
2349 return None;
2350 }
2351 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2352 return None;
2353 }
2354 if !script_sig.is_empty() {
2355 return None;
2356 }
2357 if witness.len() < 2 {
2358 return None;
2359 }
2360 let mut output_key = [0u8; 32];
2361 output_key.copy_from_slice(&script_pubkey[2..34]);
2362 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
2363 let parsed = match parse_taproot_script_path_witness(&witness_body, &output_key) {
2364 Ok(Some(p)) => p,
2365 Ok(None) | Err(_) => return None,
2366 };
2367 let (tapscript, stack_items, control_block) = parsed;
2368 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
2369 return None;
2370 }
2371 if stack_items.len() != 1 {
2372 return None;
2373 }
2374 let (sig_bytes, sighash_type) =
2375 crate::bip348::try_parse_taproot_schnorr_witness_sig(stack_items[0].as_ref())?;
2376 let pubkey_32 = &tapscript[1..33];
2377 let sighash = crate::taproot::compute_tapscript_signature_hash(
2378 tx,
2379 input_index,
2380 prevout_values,
2381 prevout_script_pubkeys,
2382 &tapscript,
2383 control_block.leaf_version,
2384 0xffff_ffff,
2385 sighash_type,
2386 annex_hash.as_ref(),
2387 )
2388 .ok()?;
2389 let result = crate::bip348::verify_tapscript_schnorr_signature(
2390 &sighash,
2391 pubkey_32,
2392 &sig_bytes,
2393 schnorr_collector,
2394 );
2395 Some(result)
2396}
2397
2398#[cfg(feature = "production")]
2401#[allow(clippy::too_many_arguments)]
2402fn verify_p2tr_keypath_witness(
2403 script_pubkey: &[u8],
2404 witness: &crate::witness::Witness,
2405 tx: &Transaction,
2406 input_index: usize,
2407 prevout_values: &[i64],
2408 prevout_script_pubkeys: &[&[u8]],
2409 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2410) -> Result<bool> {
2411 use crate::bip348::{
2412 try_parse_taproot_schnorr_witness_sig, verify_tapscript_schnorr_signature,
2413 };
2414
2415 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
2416 if witness_body.len() != 1 {
2417 return Ok(false);
2418 }
2419 let Some((sig_bytes, sighash_type)) = try_parse_taproot_schnorr_witness_sig(&witness_body[0])
2420 else {
2421 return Ok(false);
2422 };
2423 let output_key = &script_pubkey[2..34];
2424 let sighash = crate::taproot::compute_taproot_signature_hash(
2425 tx,
2426 input_index,
2427 prevout_values,
2428 prevout_script_pubkeys,
2429 sighash_type,
2430 annex_hash.as_ref(),
2431 )?;
2432 verify_tapscript_schnorr_signature(&sighash, output_key, &sig_bytes, schnorr_collector)
2433}
2434
2435#[cfg(feature = "production")]
2436#[allow(clippy::too_many_arguments)]
2437fn try_verify_p2tr_keypath_fast_path(
2438 script_sig: &ByteString,
2439 script_pubkey: &[u8],
2440 witness: &crate::witness::Witness,
2441 _flags: u32,
2442 tx: &Transaction,
2443 input_index: usize,
2444 prevout_values: &[i64],
2445 prevout_script_pubkeys: &[&[u8]],
2446 block_height: Option<u64>,
2447 network: crate::types::Network,
2448 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2449) -> Option<Result<bool>> {
2450 use crate::activation::taproot_active_at_height;
2451 if !taproot_active_at_height(block_height, network) {
2452 return None;
2453 }
2454 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
2456 return None;
2457 }
2458 if !script_sig.is_empty() {
2459 return None;
2460 }
2461 let (witness_body, _) = crate::taproot::strip_taproot_annex(witness);
2463 if witness_body.len() != 1 {
2464 return None;
2465 }
2466 crate::bip348::try_parse_taproot_schnorr_witness_sig(&witness_body[0])?;
2467 Some(verify_p2tr_keypath_witness(
2468 script_pubkey,
2469 witness,
2470 tx,
2471 input_index,
2472 prevout_values,
2473 prevout_script_pubkeys,
2474 schnorr_collector,
2475 ))
2476}
2477
2478#[spec_locked("5.2", "VerifyScript")]
2479pub fn verify_script_with_context_full(
2480 script_sig: &ByteString,
2481 script_pubkey: &[u8],
2482 witness: Option<&crate::witness::Witness>,
2483 flags: u32,
2484 tx: &Transaction,
2485 input_index: usize,
2486 prevout_values: &[i64],
2487 prevout_script_pubkeys: &[&[u8]],
2488 block_height: Option<u64>,
2489 median_time_past: Option<u64>,
2490 network: crate::types::Network,
2491 _sigversion: SigVersion,
2492 #[cfg(feature = "production")] schnorr_collector: Option<
2493 &crate::bip348::SchnorrSignatureCollector,
2494 >,
2495 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2496 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2497 #[cfg(feature = "production")] sighash_cache: Option<
2498 &crate::transaction_hash::SighashMidstateCache,
2499 >,
2500 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
2501) -> Result<bool> {
2502 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
2504 return Err(ConsensusError::ScriptErrorWithCode {
2505 code: ScriptErrorCode::TxInputInvalid,
2506 message: format!(
2507 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
2508 prevout_values.len(),
2509 prevout_script_pubkeys.len(),
2510 tx.inputs.len(),
2511 input_index,
2512 )
2513 .into(),
2514 });
2515 }
2516
2517 if input_index < prevout_values.len() {
2523 let prevout_value = prevout_values[input_index];
2524 if prevout_value < 0 {
2525 return Err(ConsensusError::ScriptErrorWithCode {
2526 code: ScriptErrorCode::ValueOverflow,
2527 message: "Prevout value cannot be negative".into(),
2528 });
2529 }
2530 #[cfg(feature = "production")]
2531 {
2532 use precomputed_constants::MAX_MONEY_U64;
2533 if (prevout_value as u64) > MAX_MONEY_U64 {
2534 return Err(ConsensusError::ScriptErrorWithCode {
2535 code: ScriptErrorCode::ValueOverflow,
2536 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2537 });
2538 }
2539 }
2540 #[cfg(not(feature = "production"))]
2541 {
2542 use crate::constants::MAX_MONEY;
2543 if prevout_value > MAX_MONEY {
2544 return Err(ConsensusError::ScriptErrorWithCode {
2545 code: ScriptErrorCode::ValueOverflow,
2546 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
2547 });
2548 }
2549 }
2550 }
2551
2552 if input_index >= tx.inputs.len() {
2554 return Err(ConsensusError::ScriptErrorWithCode {
2555 code: ScriptErrorCode::TxInputInvalid,
2556 message: format!(
2557 "Input index {} out of bounds (tx has {} inputs)",
2558 input_index,
2559 tx.inputs.len()
2560 )
2561 .into(),
2562 });
2563 }
2564
2565 #[cfg(feature = "production")]
2567 if !fast_paths_disabled() && witness.is_none() {
2568 if let Some(result) = try_verify_p2pk_fast_path(
2569 script_sig,
2570 script_pubkey,
2571 flags,
2572 tx,
2573 input_index,
2574 prevout_values,
2575 prevout_script_pubkeys,
2576 block_height,
2577 network,
2578 #[cfg(feature = "production")]
2579 sighash_cache,
2580 ) {
2581 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
2582 return result;
2583 }
2584 if let Some(result) = try_verify_p2pkh_fast_path(
2585 script_sig,
2586 script_pubkey,
2587 flags,
2588 tx,
2589 input_index,
2590 prevout_values,
2591 prevout_script_pubkeys,
2592 block_height,
2593 network,
2594 #[cfg(feature = "production")]
2595 precomputed_sighash_all,
2596 #[cfg(feature = "production")]
2597 sighash_cache,
2598 #[cfg(feature = "production")]
2599 precomputed_p2pkh_hash,
2600 ) {
2601 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
2602 return result;
2603 }
2604 if let Some(result) = try_verify_p2sh_fast_path(
2605 script_sig,
2606 script_pubkey,
2607 flags,
2608 tx,
2609 input_index,
2610 prevout_values,
2611 prevout_script_pubkeys,
2612 block_height,
2613 median_time_past,
2614 network,
2615 #[cfg(feature = "production")]
2616 sighash_cache,
2617 #[cfg(feature = "production")]
2618 precomputed_sighash_all,
2619 ) {
2620 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
2621 return result;
2622 }
2623 if let Some(result) = try_verify_bare_multisig_fast_path(
2624 script_sig,
2625 script_pubkey,
2626 flags,
2627 tx,
2628 input_index,
2629 prevout_values,
2630 prevout_script_pubkeys,
2631 block_height,
2632 network,
2633 #[cfg(feature = "production")]
2634 sighash_cache,
2635 ) {
2636 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
2637 return result;
2638 }
2639 }
2640 #[cfg(feature = "production")]
2642 if !fast_paths_disabled() {
2643 if let Some(wit) = witness {
2644 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
2645 script_sig,
2646 script_pubkey,
2647 wit,
2648 flags,
2649 tx,
2650 input_index,
2651 prevout_values,
2652 prevout_script_pubkeys,
2653 block_height,
2654 network,
2655 precomputed_bip143,
2656 ) {
2657 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2658 return result;
2659 }
2660 if let Some(result) = try_verify_p2wpkh_fast_path(
2661 script_sig,
2662 script_pubkey,
2663 wit,
2664 flags,
2665 tx,
2666 input_index,
2667 prevout_values,
2668 prevout_script_pubkeys,
2669 block_height,
2670 network,
2671 precomputed_bip143,
2672 precomputed_sighash_all,
2673 ) {
2674 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
2675 return result;
2676 }
2677 if let Some(result) = try_verify_p2wsh_fast_path(
2678 script_sig,
2679 script_pubkey,
2680 wit,
2681 flags,
2682 tx,
2683 input_index,
2684 prevout_values,
2685 prevout_script_pubkeys,
2686 block_height,
2687 median_time_past,
2688 network,
2689 schnorr_collector,
2690 precomputed_bip143,
2691 #[cfg(feature = "production")]
2692 sighash_cache,
2693 ) {
2694 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
2695 return result;
2696 }
2697 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
2698 script_sig,
2699 script_pubkey,
2700 wit,
2701 flags,
2702 tx,
2703 input_index,
2704 prevout_values,
2705 prevout_script_pubkeys,
2706 block_height,
2707 network,
2708 schnorr_collector,
2709 ) {
2710 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2711 return result;
2712 }
2713 if let Some(result) = try_verify_p2tr_keypath_fast_path(
2714 script_sig,
2715 script_pubkey,
2716 wit,
2717 flags,
2718 tx,
2719 input_index,
2720 prevout_values,
2721 prevout_script_pubkeys,
2722 block_height,
2723 network,
2724 schnorr_collector,
2725 ) {
2726 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
2727 return result;
2728 }
2729 }
2730 }
2731 #[cfg(feature = "production")]
2732 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
2733
2734 const SCRIPT_VERIFY_P2SH: u32 = 0x01;
2738 let is_p2sh = (flags & SCRIPT_VERIFY_P2SH) != 0
2739 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; if is_p2sh {
2750 let mut i = 0;
2751 while i < script_sig.len() {
2752 let opcode = script_sig[i];
2753 if !is_push_opcode(opcode) {
2754 return Ok(false);
2756 }
2757 if opcode == OP_0 {
2759 i += 1;
2761 } else if opcode <= 0x4b {
2762 let len = opcode as usize;
2764 if i + 1 + len > script_sig.len() {
2765 return Ok(false); }
2767 i += 1 + len;
2768 } else if opcode == OP_PUSHDATA1 {
2769 if i + 1 >= script_sig.len() {
2771 return Ok(false);
2772 }
2773 let len = script_sig[i + 1] as usize;
2774 if i + 2 + len > script_sig.len() {
2775 return Ok(false);
2776 }
2777 i += 2 + len;
2778 } else if opcode == OP_PUSHDATA2 {
2779 if i + 2 >= script_sig.len() {
2781 return Ok(false);
2782 }
2783 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
2784 if i + 3 + len > script_sig.len() {
2785 return Ok(false);
2786 }
2787 i += 3 + len;
2788 } else if opcode == OP_PUSHDATA4 {
2789 if i + 4 >= script_sig.len() {
2791 return Ok(false);
2792 }
2793 let len = u32::from_le_bytes([
2794 script_sig[i + 1],
2795 script_sig[i + 2],
2796 script_sig[i + 3],
2797 script_sig[i + 4],
2798 ]) as usize;
2799 if i + 5 + len > script_sig.len() {
2800 return Ok(false);
2801 }
2802 i += 5 + len;
2803 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
2804 i += 1;
2807 } else {
2808 return Ok(false);
2810 }
2811 }
2812 if !fast_paths_disabled() {
2813 if let Some(result) = try_verify_p2sh_multisig_fast_path(
2814 script_sig,
2815 script_pubkey,
2816 flags,
2817 tx,
2818 input_index,
2819 prevout_values,
2820 prevout_script_pubkeys,
2821 block_height,
2822 network,
2823 #[cfg(feature = "production")]
2824 sighash_cache,
2825 ) {
2826 return result;
2827 }
2828 }
2829 }
2830
2831 #[cfg(feature = "production")]
2832 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
2833 #[cfg(feature = "production")]
2834 let stack = &mut _stack_guard.0;
2835 #[cfg(not(feature = "production"))]
2836 let mut stack = Vec::with_capacity(20);
2837
2838 let script_sig_result = eval_script_with_context_full(
2842 script_sig,
2843 stack,
2844 flags,
2845 tx,
2846 input_index,
2847 prevout_values,
2848 prevout_script_pubkeys,
2849 block_height,
2850 median_time_past,
2851 network,
2852 SigVersion::Base,
2853 None, None, None, #[cfg(feature = "production")]
2857 schnorr_collector,
2858 None, #[cfg(feature = "production")]
2860 sighash_cache,
2861 )?;
2862 if !script_sig_result {
2863 return Ok(false);
2864 }
2865
2866 let redeem_script: Option<ByteString> = if is_p2sh && !stack.is_empty() {
2868 Some(stack.last().expect("Stack is not empty").as_ref().to_vec())
2869 } else {
2870 None
2871 };
2872 let nested_witness_program = redeem_script.as_ref().is_some_and(|redeem| {
2873 redeem.len() >= 3
2874 && redeem[0] == OP_0
2875 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
2876 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
2877 });
2878
2879 use crate::activation::taproot_active_at_height;
2883 let is_taproot = redeem_script.is_none() && taproot_active_at_height(block_height, network)
2885 && script_pubkey.len() == 34
2886 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES; if is_taproot && !script_sig.is_empty() {
2891 return Ok(false); }
2893
2894 let is_direct_witness_program = redeem_script.is_none() && !is_taproot && script_pubkey.len() >= 3
2901 && 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;
2907 if is_direct_witness_program {
2908 if let Some(witness_stack) = witness {
2909 if script_pubkey[1] == PUSH_32_BYTES {
2910 if witness_stack.is_empty() {
2913 return Ok(false); }
2915
2916 let witness_script = witness_stack.last().expect("Witness stack is not empty");
2918
2919 let program_bytes = &script_pubkey[2..];
2921 if program_bytes.len() != 32 {
2922 return Ok(false); }
2924
2925 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
2926 if &witness_script_hash[..] != program_bytes {
2927 return Ok(false); }
2929
2930 for element in witness_stack.iter().take(witness_stack.len() - 1) {
2932 stack.push(to_stack_element(element));
2933 }
2934
2935 witness_script_to_execute = Some(witness_script.clone());
2937 } else if script_pubkey[1] == PUSH_20_BYTES {
2938 if witness_stack.len() != 2 {
2941 return Ok(false); }
2943
2944 for element in witness_stack.iter() {
2945 stack.push(to_stack_element(element));
2946 }
2947 } else {
2948 return Ok(false); }
2950 } else {
2951 return Ok(false); }
2953 }
2954
2955 if is_taproot {
2956 let Some(witness_stack) = witness else {
2957 return Ok(false);
2958 };
2959 if witness_stack.is_empty() {
2960 return Ok(false);
2961 }
2962 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness_stack);
2964 if witness_body.is_empty() {
2965 return Ok(false);
2966 }
2967 if witness_body.len() == 1 {
2968 #[cfg(feature = "production")]
2969 {
2970 return verify_p2tr_keypath_witness(
2971 script_pubkey,
2972 witness_stack,
2973 tx,
2974 input_index,
2975 prevout_values,
2976 prevout_script_pubkeys,
2977 schnorr_collector,
2978 );
2979 }
2980 #[cfg(not(feature = "production"))]
2981 {
2982 return Ok(false);
2983 }
2984 }
2985 if witness_body.len() < 2 {
2986 return Ok(false);
2987 }
2988 let mut output_key = [0u8; 32];
2989 output_key.copy_from_slice(&script_pubkey[2..34]);
2990 match crate::taproot::parse_taproot_script_path_witness(&witness_body, &output_key)? {
2991 None => return Ok(false),
2992 Some((tapscript, stack_items, _control_block)) => {
2993 for item in &stack_items {
2994 stack.push(to_stack_element(item));
2995 }
2996 let tapscript_flags = flags | 0x8000;
2997 if !eval_script_with_context_full(
2998 &tapscript,
2999 stack,
3000 tapscript_flags,
3001 tx,
3002 input_index,
3003 prevout_values,
3004 prevout_script_pubkeys,
3005 block_height,
3006 median_time_past,
3007 network,
3008 SigVersion::Tapscript,
3009 None, None, annex_hash.as_ref(),
3012 #[cfg(feature = "production")]
3013 schnorr_collector,
3014 None,
3015 #[cfg(feature = "production")]
3016 sighash_cache,
3017 )? {
3018 return Ok(false);
3019 }
3020 return Ok(true);
3021 }
3022 }
3023 }
3024
3025 let script_pubkey_result = eval_script_with_context_full(
3032 script_pubkey,
3033 stack,
3034 flags,
3035 tx,
3036 input_index,
3037 prevout_values,
3038 prevout_script_pubkeys,
3039 block_height,
3040 median_time_past,
3041 network,
3042 SigVersion::Base,
3043 None, Some(script_sig),
3045 None, #[cfg(feature = "production")]
3047 schnorr_collector,
3048 None, #[cfg(feature = "production")]
3050 sighash_cache,
3051 )?;
3052 if !script_pubkey_result {
3053 return Ok(false);
3054 }
3055
3056 if let Some(witness_script) = witness_script_to_execute {
3058 let witness_sigversion = SigVersion::WitnessV0;
3061
3062 if !eval_script_with_context_full(
3065 &witness_script,
3066 stack,
3067 flags,
3068 tx,
3069 input_index,
3070 prevout_values,
3071 prevout_script_pubkeys,
3072 block_height,
3073 median_time_past,
3074 network,
3075 witness_sigversion,
3076 Some(witness_script.as_ref()), None, None, #[cfg(feature = "production")]
3080 schnorr_collector,
3081 precomputed_bip143, #[cfg(feature = "production")]
3083 sighash_cache,
3084 )? {
3085 return Ok(false);
3086 }
3087 }
3088
3089 if let Some(redeem) = redeem_script {
3094 if stack.is_empty() {
3096 return Ok(false); }
3098
3099 let top = stack.last().expect("Stack is not empty");
3101 if !cast_to_bool(top) {
3102 return Ok(false); }
3104
3105 stack.pop();
3107
3108 let is_witness_program = redeem.len() >= 3
3113 && 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() {
3118 let program_bytes = &redeem[2..];
3127
3128 if redeem[1] == PUSH_32_BYTES {
3129 if program_bytes.len() != 32 {
3132 return Ok(false); }
3134
3135 if let Some(witness_stack) = witness {
3140 if witness_stack.is_empty() {
3141 return Ok(false); }
3143
3144 let witness_script = witness_stack.last().expect("Witness stack is not empty");
3146 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
3147 if &witness_script_hash[..] != program_bytes {
3148 return Ok(false); }
3150
3151 stack.clear();
3154
3155 for element in witness_stack.iter().take(witness_stack.len() - 1) {
3158 stack.push(to_stack_element(element));
3159 }
3160
3161 let witness_sigversion = SigVersion::WitnessV0;
3165
3166 if !eval_script_with_context_full(
3168 witness_script,
3169 stack,
3170 flags,
3171 tx,
3172 input_index,
3173 prevout_values,
3174 prevout_script_pubkeys,
3175 block_height,
3176 median_time_past,
3177 network,
3178 witness_sigversion,
3179 Some(witness_script.as_ref()), None, None, #[cfg(feature = "production")]
3183 schnorr_collector,
3184 precomputed_bip143, #[cfg(feature = "production")]
3186 sighash_cache,
3187 )? {
3188 return Ok(false);
3189 }
3190 } else {
3191 return Ok(false); }
3193 } else if redeem[1] == PUSH_20_BYTES {
3194 let pubkey_hash = &redeem[2..22]; let witness_stack = match witness {
3200 Some(w) => w,
3201 None => return Ok(false), };
3203 if witness_stack.len() != 2 {
3204 return Ok(false); }
3206 let signature_bytes = &witness_stack[0];
3207 let pubkey_bytes = &witness_stack[1];
3208
3209 if signature_bytes.is_empty() {
3210 return Ok(false);
3211 }
3212 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
3213 return Ok(false);
3214 }
3215
3216 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
3218 let computed_hash = Ripemd160::digest(pubkey_sha256);
3219 if &computed_hash[..] != pubkey_hash {
3220 return Ok(false);
3221 }
3222
3223 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
3225 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
3226 let p2pkh_script_code = bip143_p2wpkh_script_code(pubkey_hash);
3227 let sighash = crate::transaction_hash::calculate_bip143_sighash(
3228 tx,
3229 input_index,
3230 &p2pkh_script_code,
3231 amount,
3232 sighash_byte,
3233 precomputed_bip143,
3234 )?;
3235
3236 let height = block_height.unwrap_or(0);
3237 return signature::with_secp_context(|secp| {
3238 signature::verify_signature(
3239 secp,
3240 pubkey_bytes,
3241 signature_bytes,
3242 &sighash,
3243 flags,
3244 height,
3245 network,
3246 SigVersion::WitnessV0,
3247 )
3248 });
3249 } else {
3250 return Ok(false); }
3252 } else {
3254 let redeem_result = eval_script_with_context_full_inner(
3258 &redeem,
3259 stack,
3260 flags,
3261 tx,
3262 input_index,
3263 prevout_values,
3264 prevout_script_pubkeys,
3265 block_height,
3266 median_time_past,
3267 network,
3268 SigVersion::Base,
3269 Some(redeem.as_ref()), Some(script_sig), None, #[cfg(feature = "production")]
3273 None, None, #[cfg(feature = "production")]
3276 sighash_cache,
3277 )?;
3278 if !redeem_result {
3279 return Ok(false);
3280 }
3281 }
3282 }
3283
3284 if stack.len() > MAX_STACK_SIZE {
3286 return Ok(false);
3287 }
3288
3289 let accepts_witness = is_direct_witness_program || is_taproot || nested_witness_program;
3300 if let Some(witness_stack) = witness {
3301 if !crate::witness::is_witness_empty(witness_stack) && !accepts_witness {
3302 return Ok(false);
3303 }
3304 }
3305
3306 const SCRIPT_VERIFY_CLEANSTACK: u32 = 0x100;
3312
3313 let final_result = if (flags & SCRIPT_VERIFY_CLEANSTACK) != 0 {
3314 stack.len() == 1 && cast_to_bool(&stack[0])
3316 } else {
3317 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
3319 };
3320 Ok(final_result)
3321}
3322
3323#[allow(dead_code)]
3325fn eval_script_with_context(
3326 script: &ByteString,
3327 stack: &mut Vec<StackElement>,
3328 flags: u32,
3329 tx: &Transaction,
3330 input_index: usize,
3331 prevouts: &[TransactionOutput],
3332 network: crate::types::Network,
3333) -> Result<bool> {
3334 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
3336 let prevout_script_pubkeys: Vec<&[u8]> =
3337 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
3338 eval_script_with_context_full(
3339 script,
3340 stack,
3341 flags,
3342 tx,
3343 input_index,
3344 &prevout_values,
3345 &prevout_script_pubkeys,
3346 None, None, network,
3349 SigVersion::Base,
3350 None, None, None, #[cfg(feature = "production")]
3354 None, None, #[cfg(feature = "production")]
3357 None, )
3359}
3360
3361#[allow(clippy::too_many_arguments)]
3363fn eval_script_with_context_full(
3364 script: &[u8],
3365 stack: &mut Vec<StackElement>,
3366 flags: u32,
3367 tx: &Transaction,
3368 input_index: usize,
3369 prevout_values: &[i64],
3370 prevout_script_pubkeys: &[&[u8]],
3371 block_height: Option<u64>,
3372 median_time_past: Option<u64>,
3373 network: crate::types::Network,
3374 sigversion: SigVersion,
3375 redeem_script_for_sighash: Option<&[u8]>,
3376 script_sig_for_sighash: Option<&ByteString>,
3377 taproot_annex_hash: Option<&Hash>,
3378 #[cfg(feature = "production")] schnorr_collector: Option<
3379 &crate::bip348::SchnorrSignatureCollector,
3380 >,
3381 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3382 #[cfg(feature = "production")] sighash_cache: Option<
3383 &crate::transaction_hash::SighashMidstateCache,
3384 >,
3385) -> Result<bool> {
3386 #[cfg(all(feature = "production", feature = "profile"))]
3387 let _t0 = std::time::Instant::now();
3388 let r = eval_script_with_context_full_inner(
3389 script,
3390 stack,
3391 flags,
3392 tx,
3393 input_index,
3394 prevout_values,
3395 prevout_script_pubkeys,
3396 block_height,
3397 median_time_past,
3398 network,
3399 sigversion,
3400 redeem_script_for_sighash,
3401 script_sig_for_sighash,
3402 taproot_annex_hash,
3403 #[cfg(feature = "production")]
3404 schnorr_collector,
3405 precomputed_bip143,
3406 #[cfg(feature = "production")]
3407 sighash_cache,
3408 );
3409 #[cfg(all(feature = "production", feature = "profile"))]
3410 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
3411 r
3412}
3413
3414fn eval_script_with_context_full_inner(
3416 script: &[u8],
3417 stack: &mut Vec<StackElement>,
3418 flags: u32,
3419 tx: &Transaction,
3420 input_index: usize,
3421 prevout_values: &[i64],
3422 prevout_script_pubkeys: &[&[u8]],
3423 block_height: Option<u64>,
3424 median_time_past: Option<u64>,
3425 network: crate::types::Network,
3426 sigversion: SigVersion,
3427 redeem_script_for_sighash: Option<&[u8]>,
3428 script_sig_for_sighash: Option<&ByteString>,
3429 taproot_annex_hash: Option<&Hash>,
3430 #[cfg(feature = "production")] schnorr_collector: Option<
3431 &crate::bip348::SchnorrSignatureCollector,
3432 >,
3433 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3434 #[cfg(feature = "production")] sighash_cache: Option<
3435 &crate::transaction_hash::SighashMidstateCache,
3436 >,
3437) -> Result<bool> {
3438 use crate::constants::{MAX_SCRIPT_SIZE, MAX_STACK_SIZE};
3441 use crate::error::{ConsensusError, ScriptErrorCode};
3442
3443 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
3445 && script.len() > MAX_SCRIPT_SIZE
3446 {
3447 return Err(ConsensusError::ScriptErrorWithCode {
3448 code: ScriptErrorCode::ScriptSize,
3449 message: "Script size exceeds maximum".into(),
3450 });
3451 }
3452 if stack.len() > MAX_STACK_SIZE {
3453 return Err(make_stack_overflow_error());
3454 }
3455
3456 if sigversion == SigVersion::Tapscript {
3461 use crate::script::flags::SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS;
3462 let mut pc = 0usize;
3463 while pc < script.len() {
3464 let opcode = script[pc];
3465 if is_op_success(opcode) {
3466 if flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS != 0 {
3467 return Err(ConsensusError::ScriptErrorWithCode {
3468 code: ScriptErrorCode::BadOpcode,
3469 message: format!("OP_SUCCESSx opcode 0x{opcode:02x} is discouraged").into(),
3470 });
3471 }
3472 return Ok(true);
3473 }
3474 pc += op_advance(script, pc);
3476 }
3477 }
3478
3479 if stack.capacity() < 20 {
3481 stack.reserve(20);
3482 }
3483 let mut op_count = 0;
3484
3485 #[cfg(feature = "production")]
3487 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
3488 #[cfg(not(feature = "production"))]
3489 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
3490
3491 #[cfg(feature = "production")]
3492 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
3493 #[cfg(not(feature = "production"))]
3494 let mut altstack: Vec<StackElement> = Vec::new();
3495
3496 let mut code_separator_pos: usize = 0;
3500 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
3501
3502 let mut i = 0;
3504 while i < script.len() {
3505 #[cfg(feature = "production")]
3506 {
3507 prefetch::prefetch_ahead(script, i, 64); }
3510 let opcode = {
3512 #[cfg(feature = "production")]
3513 {
3514 unsafe { *script.get_unchecked(i) }
3515 }
3516 #[cfg(not(feature = "production"))]
3517 {
3518 script[i]
3519 }
3520 };
3521
3522 let in_false_branch = control_flow::in_false_branch(&control_stack);
3524
3525 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
3527 op_count += 1;
3528 if op_count > MAX_SCRIPT_OPS {
3529 return Err(make_operation_limit_error());
3530 }
3531 }
3532
3533 if stack.len() + altstack.len() > MAX_STACK_SIZE {
3535 return Err(make_stack_overflow_error());
3536 }
3537
3538 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
3540 let (data, advance) = if opcode <= 0x4b {
3541 let len = opcode as usize;
3543 if i + 1 + len > script.len() {
3544 return Ok(false); }
3546 (&script[i + 1..i + 1 + len], 1 + len)
3547 } else if opcode == OP_PUSHDATA1 {
3548 if i + 1 >= script.len() {
3550 return Ok(false);
3551 }
3552 let len = script[i + 1] as usize;
3553 if i + 2 + len > script.len() {
3554 return Ok(false);
3555 }
3556 (&script[i + 2..i + 2 + len], 2 + len)
3557 } else if opcode == OP_PUSHDATA2 {
3558 if i + 2 >= script.len() {
3560 return Ok(false);
3561 }
3562 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
3563 if i + 3 + len > script.len() {
3564 return Ok(false);
3565 }
3566 (&script[i + 3..i + 3 + len], 3 + len)
3567 } else {
3568 if i + 4 >= script.len() {
3571 return Ok(false);
3572 }
3573 let len = u32::from_le_bytes([
3574 script[i + 1],
3575 script[i + 2],
3576 script[i + 3],
3577 script[i + 4],
3578 ]) as usize;
3579 let data_start = i.saturating_add(5);
3580 let data_end = data_start.saturating_add(len);
3581 let advance = 5usize.saturating_add(len);
3582 if advance < 5 || data_end > script.len() || data_end < data_start {
3583 return Ok(false); }
3585 (&script[data_start..data_end], advance)
3586 };
3587
3588 if !in_false_branch {
3590 stack.push(to_stack_element(data));
3591 }
3592 i += advance;
3593 continue;
3594 }
3595
3596 if opcode == OP_DUP {
3602 if !in_false_branch {
3603 if stack.is_empty() {
3604 return Err(ConsensusError::ScriptErrorWithCode {
3605 code: ScriptErrorCode::InvalidStackOperation,
3606 message: "OP_DUP: empty stack".into(),
3607 });
3608 }
3609 let len = stack.len();
3612 #[cfg(feature = "production")]
3613 {
3614 if stack.capacity() == stack.len() {
3616 stack.reserve(1);
3617 }
3618 let item = unsafe { stack.get_unchecked(len - 1).clone() };
3620 stack.push(item);
3621 }
3622 #[cfg(not(feature = "production"))]
3623 {
3624 let item = stack.last().unwrap();
3625 stack.push(item.clone());
3626 }
3627 }
3628 i += 1;
3629 continue;
3630 }
3631
3632 if opcode == OP_EQUALVERIFY {
3634 if !in_false_branch {
3635 if stack.len() < 2 {
3636 return Err(ConsensusError::ScriptErrorWithCode {
3637 code: ScriptErrorCode::InvalidStackOperation,
3638 message: "OP_EQUALVERIFY: insufficient stack items".into(),
3639 });
3640 }
3641 let a = stack.pop().unwrap();
3642 let b = stack.pop().unwrap();
3643 if a != b {
3644 return Ok(false);
3645 }
3646 }
3647 i += 1;
3648 continue;
3649 }
3650
3651 if opcode == OP_HASH160 {
3653 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
3654 return Ok(false);
3655 }
3656 i += 1;
3657 continue;
3658 }
3659
3660 if opcode == OP_VERIFY {
3662 if !in_false_branch {
3663 if let Some(item) = stack.pop() {
3664 if !cast_to_bool(&item) {
3665 return Ok(false);
3666 }
3667 } else {
3668 return Ok(false);
3669 }
3670 }
3671 i += 1;
3672 continue;
3673 }
3674
3675 if opcode == OP_EQUAL {
3677 if !in_false_branch {
3678 if stack.len() < 2 {
3679 return Err(ConsensusError::ScriptErrorWithCode {
3680 code: ScriptErrorCode::InvalidStackOperation,
3681 message: "OP_EQUAL: insufficient stack items".into(),
3682 });
3683 }
3684 let a = stack.pop().unwrap();
3685 let b = stack.pop().unwrap();
3686 stack.push(to_stack_element(&[if a == b { 1 } else { 0 }]));
3687 }
3688 i += 1;
3689 continue;
3690 }
3691
3692 if opcode == OP_CHECKSIG
3695 || opcode == OP_CHECKSIGVERIFY
3696 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
3697 {
3698 if !in_false_branch {
3699 let effective_script_code = Some(&script[code_separator_pos..]);
3700 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3701 (Some(script), Some(last_codesep_opcode_pos))
3702 } else {
3703 (None, None)
3704 };
3705 let ctx = context::ScriptContext {
3706 tx,
3707 input_index,
3708 prevout_values,
3709 prevout_script_pubkeys,
3710 block_height,
3711 median_time_past,
3712 network,
3713 sigversion,
3714 redeem_script_for_sighash,
3715 script_sig_for_sighash,
3716 tapscript_for_sighash: tapscript,
3717 tapscript_codesep_pos: codesep,
3718 taproot_annex_hash,
3719 #[cfg(feature = "production")]
3720 schnorr_collector,
3721 #[cfg(feature = "production")]
3722 precomputed_bip143,
3723 #[cfg(feature = "production")]
3724 sighash_cache,
3725 };
3726 if !execute_opcode_with_context_full(
3727 opcode,
3728 stack,
3729 flags,
3730 &ctx,
3731 effective_script_code,
3732 )? {
3733 return Ok(false);
3734 }
3735 }
3736 i += 1;
3737 continue;
3738 }
3739
3740 match opcode {
3741 OP_0 => {
3743 if !in_false_branch {
3744 stack.push(to_stack_element(&[]));
3745 }
3746 }
3747
3748 OP_1_RANGE_START..=OP_1_RANGE_END => {
3750 if !in_false_branch {
3751 let num = opcode - OP_N_BASE;
3752 stack.push(to_stack_element(&[num]));
3753 }
3754 }
3755
3756 OP_1NEGATE => {
3758 if !in_false_branch {
3759 stack.push(to_stack_element(&[0x81])); }
3761 }
3762
3763 OP_NOP => {
3765 }
3767
3768 OP_VER => {
3773 if !in_false_branch {
3774 return Err(ConsensusError::ScriptErrorWithCode {
3775 code: ScriptErrorCode::DisabledOpcode,
3776 message: "OP_VER is disabled".into(),
3777 });
3778 }
3779 }
3780
3781 OP_IF => {
3782 if in_false_branch {
3784 control_stack.push(control_flow::ControlBlock::If { executing: false });
3785 i += 1;
3786 continue;
3787 }
3788
3789 if stack.is_empty() {
3790 return Err(ConsensusError::ScriptErrorWithCode {
3791 code: ScriptErrorCode::InvalidStackOperation,
3792 message: "OP_IF: empty stack".into(),
3793 });
3794 }
3795 let condition_bytes = stack.pop().unwrap();
3796 let condition = cast_to_bool(&condition_bytes);
3797
3798 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3799 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3800 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3801 && !control_flow::is_minimal_if_condition(&condition_bytes)
3802 {
3803 return Err(ConsensusError::ScriptErrorWithCode {
3804 code: ScriptErrorCode::MinimalIf,
3805 message: "OP_IF condition must be minimally encoded".into(),
3806 });
3807 }
3808
3809 control_stack.push(control_flow::ControlBlock::If {
3810 executing: condition,
3811 });
3812 }
3813 OP_NOTIF => {
3814 if in_false_branch {
3816 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
3817 i += 1;
3818 continue;
3819 }
3820
3821 if stack.is_empty() {
3822 return Err(ConsensusError::ScriptErrorWithCode {
3823 code: ScriptErrorCode::InvalidStackOperation,
3824 message: "OP_NOTIF: empty stack".into(),
3825 });
3826 }
3827 let condition_bytes = stack.pop().unwrap();
3828 let condition = cast_to_bool(&condition_bytes);
3829
3830 const SCRIPT_VERIFY_MINIMALIF: u32 = 0x2000;
3831 if (flags & SCRIPT_VERIFY_MINIMALIF) != 0
3832 && (sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript)
3833 && !control_flow::is_minimal_if_condition(&condition_bytes)
3834 {
3835 return Err(ConsensusError::ScriptErrorWithCode {
3836 code: ScriptErrorCode::MinimalIf,
3837 message: "OP_NOTIF condition must be minimally encoded".into(),
3838 });
3839 }
3840
3841 control_stack.push(control_flow::ControlBlock::NotIf {
3842 executing: !condition,
3843 });
3844 }
3845 OP_ELSE => {
3846 if let Some(block) = control_stack.last_mut() {
3848 match block {
3849 control_flow::ControlBlock::If { executing }
3850 | control_flow::ControlBlock::NotIf { executing } => {
3851 *executing = !*executing;
3852 }
3853 }
3854 } else {
3855 return Err(ConsensusError::ScriptErrorWithCode {
3856 code: ScriptErrorCode::UnbalancedConditional,
3857 message: "OP_ELSE without matching IF/NOTIF".into(),
3858 });
3859 }
3860 }
3861 OP_ENDIF => {
3862 if control_stack.pop().is_none() {
3864 return Err(ConsensusError::ScriptErrorWithCode {
3865 code: ScriptErrorCode::UnbalancedConditional,
3866 message: "OP_ENDIF without matching IF/NOTIF".into(),
3867 });
3868 }
3869 }
3870
3871 OP_TOALTSTACK => {
3876 if in_false_branch {
3877 i += 1;
3878 continue;
3879 }
3880 if stack.is_empty() {
3881 return Err(ConsensusError::ScriptErrorWithCode {
3882 code: ScriptErrorCode::InvalidStackOperation,
3883 message: "OP_TOALTSTACK: empty stack".into(),
3884 });
3885 }
3886 altstack.push(stack.pop().unwrap());
3887 }
3888 OP_FROMALTSTACK => {
3890 if in_false_branch {
3891 i += 1;
3892 continue;
3893 }
3894 if altstack.is_empty() {
3895 return Err(ConsensusError::ScriptErrorWithCode {
3896 code: ScriptErrorCode::InvalidAltstackOperation,
3897 message: "OP_FROMALTSTACK: empty altstack".into(),
3898 });
3899 }
3900 stack.push(altstack.pop().unwrap());
3901 }
3902 OP_CODESEPARATOR => {
3904 if in_false_branch {
3905 i += 1;
3906 continue;
3907 }
3908 code_separator_pos = i + 1;
3909 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
3910 }
3911 _ => {
3912 if in_false_branch {
3913 i += 1;
3914 continue;
3915 }
3916
3917 let subscript_for_sighash = if matches!(
3922 opcode,
3923 OP_CHECKSIG
3924 | OP_CHECKSIGVERIFY
3925 | OP_CHECKSIGADD
3926 | OP_CHECKMULTISIG
3927 | OP_CHECKMULTISIGVERIFY
3928 ) {
3929 Some(&script[code_separator_pos..])
3930 } else {
3931 None
3932 };
3933 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
3934 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
3935 (Some(script), Some(last_codesep_opcode_pos))
3936 } else {
3937 (None, None)
3938 };
3939 let ctx = context::ScriptContext {
3940 tx,
3941 input_index,
3942 prevout_values,
3943 prevout_script_pubkeys,
3944 block_height,
3945 median_time_past,
3946 network,
3947 sigversion,
3948 redeem_script_for_sighash,
3949 script_sig_for_sighash,
3950 tapscript_for_sighash: tapscript,
3951 tapscript_codesep_pos: codesep,
3952 taproot_annex_hash,
3953 #[cfg(feature = "production")]
3954 schnorr_collector,
3955 #[cfg(feature = "production")]
3956 precomputed_bip143,
3957 #[cfg(feature = "production")]
3958 sighash_cache,
3959 };
3960 if !execute_opcode_with_context_full(
3961 opcode,
3962 stack,
3963 flags,
3964 &ctx,
3965 effective_script_code,
3966 )? {
3967 return Ok(false);
3968 }
3969 }
3970 }
3971 i += 1;
3972 }
3973
3974 if !control_stack.is_empty() {
3976 return Err(ConsensusError::ScriptErrorWithCode {
3977 code: ScriptErrorCode::UnbalancedConditional,
3978 message: "Unclosed IF/NOTIF block".into(),
3979 });
3980 }
3981
3982 Ok(true)
3986}
3987
3988#[spec_locked("5.4.5", "DecodeCScriptNum")]
3992#[blvm_spec_lock::axiom(result >= -549755813887)]
3993#[blvm_spec_lock::ensures(result >= -549755813887)]
3994#[cfg(feature = "production")]
3995#[inline(always)]
3996pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
3997 if data.len() > max_num_size {
3998 return Err(ConsensusError::ScriptErrorWithCode {
3999 code: ScriptErrorCode::InvalidStackOperation,
4000 message: format!(
4001 "Script number overflow: {} > {} bytes",
4002 data.len(),
4003 max_num_size
4004 )
4005 .into(),
4006 });
4007 }
4008 if data.is_empty() {
4009 return Ok(0);
4010 }
4011
4012 let len = data.len();
4014 let result = match len {
4015 1 => {
4016 let byte = data[0];
4017 if byte & 0x80 != 0 {
4018 -((byte & 0x7f) as i64)
4020 } else {
4021 byte as i64
4022 }
4023 }
4024 2 => {
4025 let byte0 = data[0] as i64;
4026 let byte1 = data[1] as i64;
4027 let value = byte0 | (byte1 << 8);
4028 if byte1 & 0x80 != 0 {
4029 -(value & !(0x80i64 << 8))
4031 } else {
4032 value
4033 }
4034 }
4035 _ => {
4036 let mut result: i64 = 0;
4038 for (i, &byte) in data.iter().enumerate() {
4039 result |= (byte as i64) << (8 * i);
4040 }
4041 let last_idx = len - 1;
4043 if data[last_idx] & 0x80 != 0 {
4044 result &= !(0x80i64 << (8 * last_idx));
4046 result = -result;
4047 }
4048 result
4049 }
4050 };
4051
4052 Ok(result)
4053}
4054
4055#[cfg(not(feature = "production"))]
4056#[inline]
4057pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
4058 if data.len() > max_num_size {
4059 return Err(ConsensusError::ScriptErrorWithCode {
4060 code: ScriptErrorCode::InvalidStackOperation,
4061 message: format!(
4062 "Script number overflow: {} > {} bytes",
4063 data.len(),
4064 max_num_size
4065 )
4066 .into(),
4067 });
4068 }
4069 if data.is_empty() {
4070 return Ok(0);
4071 }
4072 let mut result: i64 = 0;
4074 for (i, &byte) in data.iter().enumerate() {
4075 result |= (byte as i64) << (8 * i);
4076 }
4077 if data.last().expect("Data is not empty") & 0x80 != 0 {
4079 result &= !(0x80i64 << (8 * (data.len() - 1)));
4081 result = -result;
4082 }
4083 Ok(result)
4084}
4085
4086#[cfg(feature = "production")]
4089pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
4090 match value {
4092 0 => return vec![],
4093 1 => return vec![1],
4094 -1 => return vec![0x81],
4095 _ => {}
4096 }
4097
4098 let neg = value < 0;
4099 let mut absvalue = if neg {
4100 (-(value as i128)) as u64
4101 } else {
4102 value as u64
4103 };
4104 let mut result = Vec::with_capacity(4);
4106 while absvalue > 0 {
4107 result.push((absvalue & 0xff) as u8);
4108 absvalue >>= 8;
4109 }
4110 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
4112 result.push(if neg { 0x80 } else { 0x00 });
4113 } else if neg {
4114 *result.last_mut().unwrap() |= 0x80;
4115 }
4116 result
4117}
4118
4119#[cfg(not(feature = "production"))]
4120pub(crate) fn script_num_encode(value: i64) -> Vec<u8> {
4121 if value == 0 {
4122 return vec![];
4123 }
4124 let neg = value < 0;
4125 let mut absvalue = if neg {
4126 (-(value as i128)) as u64
4127 } else {
4128 value as u64
4129 };
4130 let mut result = Vec::new();
4131 while absvalue > 0 {
4132 result.push((absvalue & 0xff) as u8);
4133 absvalue >>= 8;
4134 }
4135 if result.last().expect("Result is not empty (absvalue > 0)") & 0x80 != 0 {
4137 result.push(if neg { 0x80 } else { 0x00 });
4138 } else if neg {
4139 *result.last_mut().unwrap() |= 0x80;
4140 }
4141 result
4142}
4143
4144#[cfg(feature = "production")]
4146#[inline(always)]
4147fn execute_opcode(
4148 opcode: u8,
4149 stack: &mut Vec<StackElement>,
4150 flags: u32,
4151 _sigversion: SigVersion,
4152) -> Result<bool> {
4153 match opcode {
4154 OP_0 => {
4156 stack.push(to_stack_element(&[]));
4157 Ok(true)
4158 }
4159
4160 OP_1..=OP_16 => {
4162 let num = opcode - OP_N_BASE;
4163 stack.push(to_stack_element(&[num]));
4164 Ok(true)
4165 }
4166
4167 OP_NOP => Ok(true),
4169
4170 OP_VER => Ok(false),
4172
4173 OP_DEPTH => {
4175 let depth = stack.len() as i64;
4176 stack.push(to_stack_element(&script_num_encode(depth)));
4177 Ok(true)
4178 }
4179
4180 OP_DUP => {
4182 if let Some(item) = stack.last().cloned() {
4183 stack.push(item);
4184 Ok(true)
4185 } else {
4186 Ok(false)
4187 }
4188 }
4189
4190 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
4192
4193 OP_SHA1 => crypto_ops::op_sha1(stack),
4195
4196 OP_SHA256 => crypto_ops::op_sha256(stack),
4198
4199 OP_HASH160 => crypto_ops::op_hash160(stack),
4201
4202 OP_HASH256 => crypto_ops::op_hash256(stack),
4204
4205 OP_EQUAL => {
4208 if stack.len() < 2 {
4209 return Err(ConsensusError::ScriptErrorWithCode {
4210 code: ScriptErrorCode::InvalidStackOperation,
4211 message: "OP_EQUAL: insufficient stack items".into(),
4212 });
4213 }
4214 let a = stack.pop().unwrap();
4215 let b = stack.pop().unwrap();
4216 stack.push(to_stack_element(if a == b { &[1u8] } else { &[] }));
4217 Ok(true)
4218 }
4219
4220 OP_EQUALVERIFY => {
4223 if stack.len() < 2 {
4224 return Err(ConsensusError::ScriptErrorWithCode {
4225 code: ScriptErrorCode::InvalidStackOperation,
4226 message: "OP_EQUALVERIFY: insufficient stack items".into(),
4227 });
4228 }
4229 let a = stack.pop().unwrap();
4230 let b = stack.pop().unwrap();
4231 let f_equal = a == b;
4232 stack.push(to_stack_element(&[if f_equal { 1 } else { 0 }]));
4234 if f_equal {
4235 stack.pop();
4237 Ok(true)
4238 } else {
4239 Err(ConsensusError::ScriptErrorWithCode {
4240 code: ScriptErrorCode::EqualVerify,
4241 message: "OP_EQUALVERIFY: stack items not equal".into(),
4242 })
4243 }
4244 }
4245
4246 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
4248
4249 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
4251
4252 OP_RETURN => Ok(false),
4254
4255 OP_VERIFY => {
4257 if let Some(item) = stack.pop() {
4258 Ok(cast_to_bool(&item))
4259 } else {
4260 Ok(false)
4261 }
4262 }
4263
4264 OP_CHECKLOCKTIMEVERIFY => {
4268 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
4269 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
4270 Ok(true)
4271 } else {
4272 Ok(false)
4273 }
4274 }
4275
4276 OP_CHECKSEQUENCEVERIFY => {
4280 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
4281 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
4282 Ok(true)
4283 } else {
4284 Ok(false)
4285 }
4286 }
4287
4288 OP_IFDUP => {
4290 if let Some(item) = stack.last().cloned() {
4291 if cast_to_bool(&item) {
4292 stack.push(item);
4293 }
4294 Ok(true)
4295 } else {
4296 Ok(false)
4297 }
4298 }
4299
4300 OP_DROP => {
4303 if stack.pop().is_some() {
4304 Ok(true)
4305 } else {
4306 Ok(false)
4307 }
4308 }
4309
4310 OP_NIP => {
4312 if stack.len() >= 2 {
4313 let top = stack.pop().unwrap();
4314 stack.pop(); stack.push(top);
4316 Ok(true)
4317 } else {
4318 Ok(false)
4319 }
4320 }
4321
4322 OP_OVER => {
4324 if stack.len() >= 2 {
4325 let len = stack.len();
4326 #[cfg(feature = "production")]
4327 {
4328 unsafe {
4330 let second = stack.get_unchecked(len - 2);
4331 stack.push(second.clone());
4332 }
4333 }
4334 #[cfg(not(feature = "production"))]
4335 {
4336 let second = stack[stack.len() - 2].clone();
4337 stack.push(second);
4338 }
4339 Ok(true)
4340 } else {
4341 Ok(false)
4342 }
4343 }
4344
4345 OP_PICK => {
4347 if let Some(n_bytes) = stack.pop() {
4348 let n_val = script_num_decode(&n_bytes, 4)?;
4351 if n_val < 0 || n_val as usize >= stack.len() {
4352 return Ok(false);
4353 }
4354 let n = n_val as usize;
4355 let len = stack.len();
4356 #[cfg(feature = "production")]
4357 {
4358 unsafe {
4360 let item = stack.get_unchecked(len - 1 - n);
4361 stack.push(item.clone());
4362 }
4363 }
4364 #[cfg(not(feature = "production"))]
4365 {
4366 let item = stack[stack.len() - 1 - n].clone();
4367 stack.push(item);
4368 }
4369 Ok(true)
4370 } else {
4371 Ok(false)
4372 }
4373 }
4374
4375 OP_ROLL => {
4377 if let Some(n_bytes) = stack.pop() {
4378 let n_val = script_num_decode(&n_bytes, 4)?;
4381 if n_val < 0 || n_val as usize >= stack.len() {
4382 return Ok(false);
4383 }
4384 let n = n_val as usize;
4385 let len = stack.len();
4386 #[cfg(feature = "production")]
4387 {
4388 let idx = len - 1 - n;
4390 let item = stack.remove(idx);
4391 stack.push(item);
4392 }
4393 #[cfg(not(feature = "production"))]
4394 {
4395 let item = stack.remove(stack.len() - 1 - n);
4396 stack.push(item);
4397 }
4398 Ok(true)
4399 } else {
4400 Ok(false)
4401 }
4402 }
4403
4404 OP_ROT => {
4406 if stack.len() >= 3 {
4407 let top = stack.pop().unwrap();
4408 let second = stack.pop().unwrap();
4409 let third = stack.pop().unwrap();
4410 stack.push(second);
4411 stack.push(top);
4412 stack.push(third);
4413 Ok(true)
4414 } else {
4415 Ok(false)
4416 }
4417 }
4418
4419 OP_SWAP => {
4421 if stack.len() >= 2 {
4422 let top = stack.pop().unwrap();
4423 let second = stack.pop().unwrap();
4424 stack.push(top);
4425 stack.push(second);
4426 Ok(true)
4427 } else {
4428 Ok(false)
4429 }
4430 }
4431
4432 OP_TUCK => {
4434 if stack.len() >= 2 {
4435 let top = stack.pop().unwrap();
4436 let second = stack.pop().unwrap();
4437 stack.push(top.clone());
4438 stack.push(second);
4439 stack.push(top);
4440 Ok(true)
4441 } else {
4442 Ok(false)
4443 }
4444 }
4445
4446 OP_2DROP => {
4448 if stack.len() >= 2 {
4449 stack.pop();
4450 stack.pop();
4451 Ok(true)
4452 } else {
4453 Ok(false)
4454 }
4455 }
4456
4457 OP_2DUP => {
4459 if stack.len() >= 2 {
4460 let top = stack[stack.len() - 1].clone();
4461 let second = stack[stack.len() - 2].clone();
4462 stack.push(second);
4463 stack.push(top);
4464 Ok(true)
4465 } else {
4466 Ok(false)
4467 }
4468 }
4469
4470 OP_3DUP => {
4472 if stack.len() >= 3 {
4473 let top = stack[stack.len() - 1].clone();
4474 let second = stack[stack.len() - 2].clone();
4475 let third = stack[stack.len() - 3].clone();
4476 stack.push(third);
4477 stack.push(second);
4478 stack.push(top);
4479 Ok(true)
4480 } else {
4481 Ok(false)
4482 }
4483 }
4484
4485 OP_2OVER => {
4487 if stack.len() >= 4 {
4488 let fourth = stack[stack.len() - 4].clone();
4489 let third = stack[stack.len() - 3].clone();
4490 stack.push(fourth);
4491 stack.push(third);
4492 Ok(true)
4493 } else {
4494 Ok(false)
4495 }
4496 }
4497
4498 OP_2ROT => {
4501 if stack.len() >= 6 {
4502 let sixth = stack.remove(stack.len() - 6); let fifth = stack.remove(stack.len() - 5); stack.push(sixth);
4508 stack.push(fifth);
4509 Ok(true)
4510 } else {
4511 Ok(false)
4512 }
4513 }
4514
4515 OP_2SWAP => {
4517 if stack.len() >= 4 {
4518 let top = stack.pop().unwrap();
4519 let second = stack.pop().unwrap();
4520 let third = stack.pop().unwrap();
4521 let fourth = stack.pop().unwrap();
4522 stack.push(second);
4523 stack.push(top);
4524 stack.push(fourth);
4525 stack.push(third);
4526 Ok(true)
4527 } else {
4528 Ok(false)
4529 }
4530 }
4531
4532 OP_SIZE => {
4535 if let Some(item) = stack.last() {
4536 let size = item.len() as i64;
4537 stack.push(to_stack_element(&script_num_encode(size)));
4538 Ok(true)
4539 } else {
4540 Ok(false)
4541 }
4542 }
4543
4544 OP_1ADD => {
4549 if let Some(item) = stack.pop() {
4550 let a = script_num_decode(&item, 4)?;
4551 stack.push(to_stack_element(&script_num_encode(a + 1)));
4552 Ok(true)
4553 } else {
4554 Ok(false)
4555 }
4556 }
4557 OP_1SUB => {
4559 if let Some(item) = stack.pop() {
4560 let a = script_num_decode(&item, 4)?;
4561 stack.push(to_stack_element(&script_num_encode(a - 1)));
4562 Ok(true)
4563 } else {
4564 Ok(false)
4565 }
4566 }
4567 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
4569 code: ScriptErrorCode::DisabledOpcode,
4570 message: "OP_2MUL is disabled".into(),
4571 }),
4572 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
4574 code: ScriptErrorCode::DisabledOpcode,
4575 message: "OP_2DIV is disabled".into(),
4576 }),
4577 OP_NEGATE => {
4579 if let Some(item) = stack.pop() {
4580 let a = script_num_decode(&item, 4)?;
4581 stack.push(to_stack_element(&script_num_encode(-a)));
4582 Ok(true)
4583 } else {
4584 Ok(false)
4585 }
4586 }
4587 OP_ABS => {
4589 if let Some(item) = stack.pop() {
4590 let a = script_num_decode(&item, 4)?;
4591 stack.push(to_stack_element(&script_num_encode(a.abs())));
4592 Ok(true)
4593 } else {
4594 Ok(false)
4595 }
4596 }
4597 OP_NOT => {
4599 if let Some(item) = stack.pop() {
4600 let a = script_num_decode(&item, 4)?;
4601 stack.push(to_stack_element(&script_num_encode(if a == 0 {
4602 1
4603 } else {
4604 0
4605 })));
4606 Ok(true)
4607 } else {
4608 Ok(false)
4609 }
4610 }
4611 OP_0NOTEQUAL => {
4613 if let Some(item) = stack.pop() {
4614 let a = script_num_decode(&item, 4)?;
4615 stack.push(to_stack_element(&script_num_encode(if a != 0 {
4616 1
4617 } else {
4618 0
4619 })));
4620 Ok(true)
4621 } else {
4622 Ok(false)
4623 }
4624 }
4625 OP_ADD => arithmetic::op_add(stack),
4626 OP_SUB => arithmetic::op_sub(stack),
4627 OP_MUL => arithmetic::op_mul_disabled(),
4628 OP_DIV => arithmetic::op_div_disabled(),
4629 OP_MOD => arithmetic::op_mod_disabled(),
4630 OP_LSHIFT => arithmetic::op_lshift_disabled(),
4631 OP_RSHIFT => arithmetic::op_rshift_disabled(),
4632 OP_BOOLAND => arithmetic::op_booland(stack),
4633 OP_BOOLOR => arithmetic::op_boolor(stack),
4634 OP_NUMEQUAL => arithmetic::op_numequal(stack),
4635 OP_NUMEQUALVERIFY => arithmetic::op_numequalverify(stack),
4636 OP_NUMNOTEQUAL => arithmetic::op_numnotequal(stack),
4637 OP_LESSTHAN => arithmetic::op_lessthan(stack),
4638 OP_GREATERTHAN => arithmetic::op_greaterthan(stack),
4639 OP_LESSTHANOREQUAL => arithmetic::op_lessthanorequal(stack),
4640 OP_GREATERTHANOREQUAL => arithmetic::op_greaterthanorequal(stack),
4641 OP_MIN => arithmetic::op_min(stack),
4642 OP_MAX => arithmetic::op_max(stack),
4643 OP_WITHIN => arithmetic::op_within(stack),
4644
4645 OP_CODESEPARATOR => Ok(true),
4647
4648 OP_NOP1 | OP_NOP5..=OP_NOP10 => Ok(true),
4651
4652 OP_CHECKTEMPLATEVERIFY => {
4656 #[cfg(feature = "ctv")]
4657 {
4658 const SCRIPT_VERIFY_CHECKTEMPLATEVERIFY: u32 = 0x8000;
4659 if (flags & SCRIPT_VERIFY_CHECKTEMPLATEVERIFY) != 0 {
4660 return Err(ConsensusError::ScriptErrorWithCode {
4661 code: ScriptErrorCode::TxInvalid,
4662 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
4663 });
4664 }
4665 }
4666 Ok(true)
4667 }
4668
4669 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
4671 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
4672 Err(ConsensusError::ScriptErrorWithCode {
4673 code: ScriptErrorCode::DisabledOpcode,
4674 message: format!("Disabled opcode 0x{opcode:02x}").into(),
4675 })
4676 }
4677
4678 OP_1NEGATE => {
4680 stack.push(to_stack_element(&[0x81]));
4681 Ok(true)
4682 }
4683
4684 OP_CHECKMULTISIG => {
4689 if stack.is_empty() {
4690 return Ok(false);
4691 }
4692 let n_bytes = stack.pop().unwrap();
4693 let n = match script_num_decode(&n_bytes, 4) {
4694 Ok(v) if (0..=20).contains(&v) => v as usize,
4695 _ => return Ok(false),
4696 };
4697 if stack.len() < n {
4698 return Ok(false);
4699 }
4700 for _ in 0..n {
4701 stack.pop();
4702 }
4703 if stack.is_empty() {
4704 return Ok(false);
4705 }
4706 let m_bytes = stack.pop().unwrap();
4707 let m = match script_num_decode(&m_bytes, 4) {
4708 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4709 _ => return Ok(false),
4710 };
4711 if stack.len() < m {
4712 return Ok(false);
4713 }
4714 for _ in 0..m {
4715 stack.pop();
4716 }
4717 if stack.is_empty() {
4719 return Ok(false);
4720 }
4721 stack.pop();
4722 stack.push(to_stack_element(&[if m == 0 { 1 } else { 0 }]));
4724 Ok(true)
4725 }
4726
4727 OP_CHECKMULTISIGVERIFY => {
4729 if stack.is_empty() {
4730 return Ok(false);
4731 }
4732 let n_bytes = stack.pop().unwrap();
4733 let n = match script_num_decode(&n_bytes, 4) {
4734 Ok(v) if (0..=20).contains(&v) => v as usize,
4735 _ => return Ok(false),
4736 };
4737 if stack.len() < n {
4738 return Ok(false);
4739 }
4740 for _ in 0..n {
4741 stack.pop();
4742 }
4743 if stack.is_empty() {
4744 return Ok(false);
4745 }
4746 let m_bytes = stack.pop().unwrap();
4747 let m = match script_num_decode(&m_bytes, 4) {
4748 Ok(v) if v >= 0 && v as usize <= n => v as usize,
4749 _ => return Ok(false),
4750 };
4751 if stack.len() < m {
4752 return Ok(false);
4753 }
4754 for _ in 0..m {
4755 stack.pop();
4756 }
4757 if stack.is_empty() {
4758 return Ok(false);
4759 }
4760 stack.pop();
4761 Ok(m == 0)
4763 }
4764
4765 _ => Ok(false),
4767 }
4768}
4769
4770#[allow(dead_code)]
4772fn execute_opcode_with_context(
4773 opcode: u8,
4774 stack: &mut Vec<StackElement>,
4775 flags: u32,
4776 tx: &Transaction,
4777 input_index: usize,
4778 prevouts: &[TransactionOutput],
4779 network: crate::types::Network,
4780) -> Result<bool> {
4781 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
4783 let prevout_script_pubkeys: Vec<&[u8]> =
4784 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
4785 let ctx = context::ScriptContext {
4786 tx,
4787 input_index,
4788 prevout_values: &prevout_values,
4789 prevout_script_pubkeys: &prevout_script_pubkeys,
4790 block_height: None,
4791 median_time_past: None,
4792 network,
4793 sigversion: SigVersion::Base,
4794 redeem_script_for_sighash: None,
4795 script_sig_for_sighash: None,
4796 tapscript_for_sighash: None,
4797 tapscript_codesep_pos: None,
4798 taproot_annex_hash: None,
4799 #[cfg(feature = "production")]
4800 schnorr_collector: None,
4801 #[cfg(feature = "production")]
4802 precomputed_bip143: None,
4803 #[cfg(feature = "production")]
4804 sighash_cache: None,
4805 };
4806 execute_opcode_with_context_full(opcode, stack, flags, &ctx, None)
4807}
4808
4809#[cfg(feature = "production")]
4813#[inline(always)]
4814pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
4815 let mut i = 0;
4816 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4817 i += adv1;
4818 if i >= script_sig.len() {
4819 return None;
4820 }
4821 let (adv2, _p_start, _p_end) = parse_one_data_push(script_sig, i)?;
4822 i += adv2;
4823 if i >= script_sig.len() {
4824 return None;
4825 }
4826 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
4827 i += adv3;
4828 if i != script_sig.len() {
4829 return None;
4830 }
4831 let sig = &script_sig[s_start..s_end];
4832 let redeem = &script_sig[r_start..r_end];
4833 if sig.is_empty() || redeem.len() != 25 {
4834 return None;
4835 }
4836 if redeem[0] != OP_DUP
4837 || redeem[1] != OP_HASH160
4838 || redeem[2] != PUSH_20_BYTES
4839 || redeem[23] != OP_EQUALVERIFY
4840 || redeem[24] != OP_CHECKSIG
4841 {
4842 return None;
4843 }
4844 Some((sig[sig.len() - 1], redeem))
4845}
4846
4847#[inline(always)]
4851pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
4852 let mut i = 0;
4853 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
4854 i += adv1;
4855 if i >= script_sig.len() {
4856 return None;
4857 }
4858 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
4859 i += adv2;
4860 if i != script_sig.len() {
4861 return None;
4862 }
4863 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
4864}
4865
4866pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
4869 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
4870 if advance != script_sig.len() {
4871 return None;
4872 }
4873 Some(&script_sig[data_start..data_end])
4874}
4875
4876fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
4878 if i >= script.len() {
4879 return None;
4880 }
4881 let opcode = script[i];
4882 let (advance, data_start, data_end) = if opcode == OP_0 {
4883 return None;
4884 } else if opcode <= 0x4b {
4885 let len = opcode as usize;
4886 if i + 1 + len > script.len() {
4887 return None;
4888 }
4889 (1 + len, i + 1, i + 1 + len)
4890 } else if opcode == OP_PUSHDATA1 {
4891 if i + 1 >= script.len() {
4892 return None;
4893 }
4894 let len = script[i + 1] as usize;
4895 if i + 2 + len > script.len() {
4896 return None;
4897 }
4898 (2 + len, i + 2, i + 2 + len)
4899 } else if opcode == OP_PUSHDATA2 {
4900 if i + 2 >= script.len() {
4901 return None;
4902 }
4903 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
4904 if i + 3 + len > script.len() {
4905 return None;
4906 }
4907 (3 + len, i + 3, i + 3 + len)
4908 } else if opcode == OP_PUSHDATA4 {
4909 if i + 4 >= script.len() {
4910 return None;
4911 }
4912 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
4913 as usize;
4914 if i + 5 + len > script.len() {
4915 return None;
4916 }
4917 (5 + len, i + 5, i + 5 + len)
4918 } else {
4919 return None;
4920 };
4921 Some((advance, data_start, data_end))
4922}
4923
4924#[spec_locked("5.2.1", "P2SHPushOnlyCheck")]
4927pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
4928 parse_script_sig_push_only(script_sig).is_some()
4929}
4930
4931fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4935 let mut out = Vec::new();
4936 let mut i = 0;
4937 while i < script_sig.len() {
4938 let opcode = script_sig[i];
4939 if !is_push_opcode(opcode) {
4940 return None;
4941 }
4942 let (advance, data) = if opcode == OP_0 {
4943 (1, vec![])
4944 } else if opcode <= 0x4b {
4945 let len = opcode as usize;
4946 if i + 1 + len > script_sig.len() {
4947 return None;
4948 }
4949 (1 + len, script_sig[i + 1..i + 1 + len].to_vec())
4950 } else if opcode == OP_PUSHDATA1 {
4951 if i + 1 >= script_sig.len() {
4952 return None;
4953 }
4954 let len = script_sig[i + 1] as usize;
4955 if i + 2 + len > script_sig.len() {
4956 return None;
4957 }
4958 (2 + len, script_sig[i + 2..i + 2 + len].to_vec())
4959 } else if opcode == OP_PUSHDATA2 {
4960 if i + 2 >= script_sig.len() {
4961 return None;
4962 }
4963 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
4964 if i + 3 + len > script_sig.len() {
4965 return None;
4966 }
4967 (3 + len, script_sig[i + 3..i + 3 + len].to_vec())
4968 } else if opcode == OP_PUSHDATA4 {
4969 if i + 4 >= script_sig.len() {
4970 return None;
4971 }
4972 let len = u32::from_le_bytes([
4973 script_sig[i + 1],
4974 script_sig[i + 2],
4975 script_sig[i + 3],
4976 script_sig[i + 4],
4977 ]) as usize;
4978 if i + 5 + len > script_sig.len() {
4979 return None;
4980 }
4981 (5 + len, script_sig[i + 5..i + 5 + len].to_vec())
4982 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
4983 let n = script_num_from_opcode(opcode);
4985 (1, script_num_encode(n))
4986 } else {
4987 return None;
4988 };
4989 out.push(to_stack_element(&data));
4990 i += advance;
4991 }
4992 Some(out)
4993}
4994
4995fn parse_p2sh_script_sig_pushes(script_sig: &[u8]) -> Option<Vec<StackElement>> {
4999 parse_script_sig_push_only(script_sig)
5000}
5001
5002fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
5007 if redeem.len() < 4 {
5008 return None;
5009 }
5010 let n_op = redeem[0];
5011 if !(OP_1..=OP_16).contains(&n_op) {
5012 return None;
5013 }
5014 let n = (n_op - OP_1 + 1) as usize;
5015 let mut i = 1;
5016 let mut pubkeys = Vec::with_capacity(n);
5017 for _ in 0..n {
5018 if i >= redeem.len() {
5019 return None;
5020 }
5021 let first = redeem[i];
5022 let pk_len = if first == 0x02 || first == 0x03 {
5023 33
5024 } else if first == 0x04 {
5025 65
5026 } else {
5027 return None;
5028 };
5029 if i + pk_len > redeem.len() {
5030 return None;
5031 }
5032 pubkeys.push(&redeem[i..i + pk_len]);
5033 i += pk_len;
5034 }
5035 if i + 2 > redeem.len() {
5036 return None;
5037 }
5038 let m_op = redeem[i];
5039 if !(OP_1..=OP_16).contains(&m_op) {
5040 return None;
5041 }
5042 let m = m_op - OP_1 + 1;
5043 if redeem[i + 1] != OP_CHECKMULTISIG {
5044 return None;
5045 }
5046 Some((m, n as u8, pubkeys))
5047}
5048
5049fn script_num_from_opcode(opcode: u8) -> i64 {
5051 match opcode {
5052 OP_1NEGATE => -1,
5053 OP_1 => 1,
5054 OP_2 => 2,
5055 OP_3 => 3,
5056 OP_4 => 4,
5057 OP_5 => 5,
5058 OP_6 => 6,
5059 OP_7 => 7,
5060 OP_8 => 8,
5061 OP_9 => 9,
5062 OP_10 => 10,
5063 OP_11 => 11,
5064 OP_12 => 12,
5065 OP_13 => 13,
5066 OP_14 => 14,
5067 OP_15 => 15,
5068 OP_16 => 16,
5069 _ => 0,
5070 }
5071}
5072
5073pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
5077 let len = data.len();
5078 let mut result = Vec::with_capacity(len + 5);
5079 if len < 76 {
5080 result.push(len as u8);
5081 } else if len < 256 {
5082 result.push(OP_PUSHDATA1);
5083 result.push(len as u8);
5084 } else if len < 65536 {
5085 result.push(OP_PUSHDATA2);
5086 result.push((len & 0xff) as u8);
5087 result.push(((len >> 8) & 0xff) as u8);
5088 } else {
5089 result.push(OP_PUSHDATA4);
5090 result.push((len & 0xff) as u8);
5091 result.push(((len >> 8) & 0xff) as u8);
5092 result.push(((len >> 16) & 0xff) as u8);
5093 result.push(((len >> 24) & 0xff) as u8);
5094 }
5095 result.extend_from_slice(data);
5096 result
5097}
5098
5099#[inline]
5101fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
5102 if pc >= script.len() {
5103 return None;
5104 }
5105 let opcode = script[pc];
5106 let advance = if opcode <= 0x4b {
5107 1 + opcode as usize
5108 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
5109 2 + script[pc + 1] as usize
5110 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
5111 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
5112 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
5113 5 + ((script[pc + 1] as usize)
5114 | ((script[pc + 2] as usize) << 8)
5115 | ((script[pc + 3] as usize) << 16)
5116 | ((script[pc + 4] as usize) << 24))
5117 } else {
5118 1
5119 };
5120 let next = pc + advance;
5121 if next > script.len() {
5122 None
5123 } else {
5124 Some(next)
5125 }
5126}
5127
5128#[spec_locked("5.1.1", "FindAndDelete")]
5134#[inline]
5135pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
5136 if pattern.is_empty() {
5137 return std::borrow::Cow::Borrowed(script);
5138 }
5139 if pattern.len() > script.len() {
5140 return std::borrow::Cow::Borrowed(script);
5141 }
5142 if !script.windows(pattern.len()).any(|w| w == pattern) {
5147 return std::borrow::Cow::Borrowed(script);
5148 }
5149 let end = script.len();
5150 let mut n_found = 0usize;
5151 let mut result = Vec::new();
5152 let mut pc = 0usize;
5153 let mut pc2 = 0usize;
5154
5155 loop {
5156 result.extend_from_slice(&script[pc2..pc]);
5157 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
5158 pc += pattern.len();
5159 n_found += 1;
5160 }
5161 pc2 = pc;
5162 if pc >= end {
5163 break;
5164 }
5165 let Some(next_pc) = script_get_op_advance(script, pc) else {
5166 break;
5167 };
5168 pc = next_pc;
5169 }
5170
5171 if n_found > 0 {
5172 result.extend_from_slice(&script[pc2..end]);
5173 std::borrow::Cow::Owned(result)
5174 } else {
5175 std::borrow::Cow::Borrowed(script)
5176 }
5177}
5178
5179fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
5181 let mut pos = 0u32;
5182 let mut i = 0usize;
5183 while i < script.len() && i <= byte_index {
5184 let opcode = script[i];
5185 let advance = if opcode <= 0x4b {
5186 1 + opcode as usize
5187 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
5188 2 + script[i + 1] as usize
5189 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
5190 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
5191 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
5192 5 + ((script[i + 1] as usize)
5193 | ((script[i + 2] as usize) << 8)
5194 | ((script[i + 3] as usize) << 16)
5195 | ((script[i + 4] as usize) << 24))
5196 } else {
5197 1
5198 };
5199 if i == byte_index {
5200 return pos;
5201 }
5202 pos += 1;
5203 i = std::cmp::min(i + advance, script.len());
5204 }
5205 0xffff_ffff
5206}
5207
5208#[cfg_attr(feature = "production", inline(always))]
5210fn execute_opcode_with_context_full(
5211 opcode: u8,
5212 stack: &mut Vec<StackElement>,
5213 flags: u32,
5214 ctx: &context::ScriptContext<'_>,
5215 effective_script_code: Option<&[u8]>,
5216) -> Result<bool> {
5217 let tx = ctx.tx;
5218 let input_index = ctx.input_index;
5219 let prevout_values = ctx.prevout_values;
5220 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
5221 let block_height = ctx.block_height;
5222 let median_time_past = ctx.median_time_past;
5223 let network = ctx.network;
5224 let sigversion = ctx.sigversion;
5225 let script_sig_for_sighash = ctx.script_sig_for_sighash;
5226 let tapscript_for_sighash = ctx.tapscript_for_sighash;
5227 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
5228 let redeem_script_for_sighash = effective_script_code;
5229 #[cfg(feature = "production")]
5230 let schnorr_collector = ctx.schnorr_collector;
5231 #[cfg(feature = "production")]
5232 let precomputed_bip143 = ctx.precomputed_bip143;
5233 #[cfg(feature = "production")]
5234 let sighash_cache = ctx.sighash_cache;
5235
5236 match opcode {
5238 OP_CHECKSIG => {
5240 if stack.len() >= 2 {
5241 let pubkey_bytes = stack.pop().unwrap();
5242 let signature_bytes = stack.pop().unwrap();
5243
5244 if signature_bytes.is_empty() {
5246 stack.push(to_stack_element(&[0]));
5247 return Ok(true);
5248 }
5249
5250 if sigversion == SigVersion::Tapscript && pubkey_bytes.len() == 32 {
5252 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5253 if let Some((sig_bytes, sighash_byte)) =
5254 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5255 {
5256 let (tapscript, codesep_pos) = tapscript_for_sighash
5257 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5258 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5259 let sighash = if tapscript.is_empty() {
5260 crate::taproot::compute_taproot_signature_hash(
5261 tx,
5262 input_index,
5263 prevout_values,
5264 prevout_script_pubkeys,
5265 sighash_byte,
5266 None,
5267 )?
5268 } else {
5269 crate::taproot::compute_tapscript_signature_hash(
5270 tx,
5271 input_index,
5272 prevout_values,
5273 prevout_script_pubkeys,
5274 tapscript,
5275 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5276 codesep_pos,
5277 sighash_byte,
5278 ctx.taproot_annex_hash,
5279 )?
5280 };
5281
5282 #[cfg(feature = "production")]
5283 let is_valid = {
5284 use crate::bip348::verify_tapscript_schnorr_signature;
5285 verify_tapscript_schnorr_signature(
5286 &sighash,
5287 &pubkey_bytes,
5288 &sig_bytes,
5289 schnorr_collector,
5290 )
5291 .unwrap_or(false)
5292 };
5293
5294 #[cfg(not(feature = "production"))]
5295 let is_valid = {
5296 #[cfg(feature = "csfs")]
5297 let x = {
5298 use crate::bip348::verify_tapscript_schnorr_signature;
5299 verify_tapscript_schnorr_signature(
5300 &sighash,
5301 &pubkey_bytes,
5302 &sig_bytes,
5303 None,
5304 )
5305 .unwrap_or(false)
5306 };
5307 #[cfg(not(feature = "csfs"))]
5308 let x = false;
5309 x
5310 };
5311
5312 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5313 return Ok(true);
5314 }
5315 stack.push(to_stack_element(&[0]));
5317 return Ok(true);
5318 }
5319 if sigversion == SigVersion::Tapscript {
5320 stack.push(to_stack_element(&[1]));
5322 return Ok(true);
5323 }
5324
5325 let sig_len = signature_bytes.len();
5329 let sighash_byte = signature_bytes[sig_len - 1];
5330 let _der_sig = &signature_bytes[..sig_len - 1];
5331
5332 let sighash = if sigversion == SigVersion::WitnessV0 {
5336 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5338
5339 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5341 prevout_script_pubkeys
5342 .get(input_index)
5343 .copied()
5344 .unwrap_or(&[])
5345 });
5346
5347 crate::transaction_hash::calculate_bip143_sighash(
5348 tx,
5349 input_index,
5350 script_code,
5351 amount,
5352 sighash_byte,
5353 precomputed_bip143,
5354 )?
5355 } else {
5356 use crate::transaction_hash::{
5358 SighashType, calculate_transaction_sighash_single_input,
5359 };
5360 let sighash_type = SighashType::from_byte(sighash_byte);
5361
5362 let pattern = serialize_push_data(signature_bytes.as_ref());
5366
5367 let base_script = match (
5368 redeem_script_for_sighash,
5369 prevout_script_pubkeys.get(input_index),
5370 ) {
5371 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5372 (Some(redeem), _) => redeem,
5373 (None, Some(prevout)) => *prevout,
5374 (None, None) => &[],
5375 };
5376 let cleaned = find_and_delete(base_script, &pattern);
5377
5378 calculate_transaction_sighash_single_input(
5379 tx,
5380 input_index,
5381 cleaned.as_ref(),
5382 prevout_values[input_index],
5383 sighash_type,
5384 #[cfg(feature = "production")]
5385 sighash_cache,
5386 )?
5387 };
5388
5389 let height = block_height.unwrap_or(0);
5393 #[cfg(feature = "production")]
5394 let is_valid = signature::with_secp_context(|secp| {
5395 signature::verify_signature(
5396 secp,
5397 &pubkey_bytes,
5398 &signature_bytes, &sighash,
5400 flags,
5401 height,
5402 network,
5403 sigversion,
5404 )
5405 })?;
5406
5407 #[cfg(not(feature = "production"))]
5408 let is_valid = {
5409 let secp = signature::new_secp();
5410 signature::verify_signature(
5411 &secp,
5412 &pubkey_bytes,
5413 &signature_bytes, &sighash,
5415 flags,
5416 height,
5417 network,
5418 sigversion,
5419 )?
5420 };
5421
5422 stack.push(to_stack_element(&[if is_valid { 1 } else { 0 }]));
5423 Ok(true)
5424 } else {
5425 Ok(false)
5426 }
5427 }
5428
5429 OP_CHECKSIGVERIFY => {
5431 if stack.len() >= 2 {
5432 let pubkey_bytes = stack.pop().unwrap();
5433 let signature_bytes = stack.pop().unwrap();
5434
5435 if signature_bytes.is_empty() {
5437 return Ok(false);
5438 }
5439
5440 if sigversion == SigVersion::Tapscript {
5442 if pubkey_bytes.len() == 32 {
5443 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5444 if let Some((sig_bytes, sighash_byte)) =
5445 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5446 {
5447 let (tapscript, codesep_pos) = tapscript_for_sighash
5448 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5449 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5450 let sighash = if tapscript.is_empty() {
5451 crate::taproot::compute_taproot_signature_hash(
5452 tx,
5453 input_index,
5454 prevout_values,
5455 prevout_script_pubkeys,
5456 sighash_byte,
5457 None,
5458 )?
5459 } else {
5460 crate::taproot::compute_tapscript_signature_hash(
5461 tx,
5462 input_index,
5463 prevout_values,
5464 prevout_script_pubkeys,
5465 tapscript,
5466 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5467 codesep_pos,
5468 sighash_byte,
5469 ctx.taproot_annex_hash,
5470 )?
5471 };
5472 #[cfg(feature = "production")]
5473 let is_valid = {
5474 use crate::bip348::verify_tapscript_schnorr_signature;
5475 verify_tapscript_schnorr_signature(
5476 &sighash,
5477 &pubkey_bytes,
5478 &sig_bytes,
5479 schnorr_collector,
5480 )
5481 .unwrap_or(false)
5482 };
5483 #[cfg(not(feature = "production"))]
5484 let is_valid = {
5485 #[cfg(feature = "csfs")]
5486 let x = {
5487 use crate::bip348::verify_tapscript_schnorr_signature;
5488 verify_tapscript_schnorr_signature(
5489 &sighash,
5490 &pubkey_bytes,
5491 &sig_bytes,
5492 None,
5493 )
5494 .unwrap_or(false)
5495 };
5496 #[cfg(not(feature = "csfs"))]
5497 let x = false;
5498 x
5499 };
5500 if !is_valid {
5501 return Ok(false); }
5503 return Ok(true);
5504 }
5505 return Ok(false);
5507 }
5508 return Ok(true);
5510 }
5511
5512 let sig_len = signature_bytes.len();
5515 let sighash_byte = signature_bytes[sig_len - 1];
5516 let _der_sig = &signature_bytes[..sig_len - 1];
5517
5518 let sighash = if sigversion == SigVersion::WitnessV0 {
5522 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5524
5525 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
5526 prevout_script_pubkeys
5527 .get(input_index)
5528 .copied()
5529 .unwrap_or(&[])
5530 });
5531
5532 crate::transaction_hash::calculate_bip143_sighash(
5533 tx,
5534 input_index,
5535 script_code,
5536 amount,
5537 sighash_byte,
5538 precomputed_bip143,
5539 )?
5540 } else {
5541 use crate::transaction_hash::{
5543 SighashType, calculate_transaction_sighash_single_input,
5544 };
5545 let sighash_type = SighashType::from_byte(sighash_byte);
5546
5547 let pattern = serialize_push_data(signature_bytes.as_ref());
5549
5550 let base_script = match (
5551 redeem_script_for_sighash,
5552 prevout_script_pubkeys.get(input_index),
5553 ) {
5554 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5555 (Some(redeem), _) => redeem,
5556 (None, Some(prevout)) => *prevout,
5557 (None, None) => &[],
5558 };
5559 let cleaned = find_and_delete(base_script, &pattern);
5560
5561 calculate_transaction_sighash_single_input(
5562 tx,
5563 input_index,
5564 cleaned.as_ref(),
5565 prevout_values[input_index],
5566 sighash_type,
5567 #[cfg(feature = "production")]
5568 sighash_cache,
5569 )?
5570 };
5571
5572 let height = block_height.unwrap_or(0);
5576 #[cfg(feature = "production")]
5577 let is_valid = signature::with_secp_context(|secp| {
5578 signature::verify_signature(
5579 secp,
5580 &pubkey_bytes,
5581 &signature_bytes, &sighash,
5583 flags,
5584 height,
5585 network,
5586 sigversion,
5587 )
5588 })?;
5589
5590 #[cfg(not(feature = "production"))]
5591 let is_valid = {
5592 let secp = signature::new_secp();
5593 signature::verify_signature(
5594 &secp,
5595 &pubkey_bytes,
5596 &signature_bytes, &sighash,
5598 flags,
5599 height,
5600 network,
5601 sigversion,
5602 )?
5603 };
5604
5605 if is_valid { Ok(true) } else { Ok(false) }
5606 } else {
5607 Ok(false)
5608 }
5609 }
5610
5611 OP_CHECKSIGADD => {
5613 if sigversion != SigVersion::Tapscript {
5614 return Err(ConsensusError::ScriptErrorWithCode {
5615 code: ScriptErrorCode::DisabledOpcode,
5616 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
5617 });
5618 }
5619 if stack.len() < 3 {
5620 return Err(ConsensusError::ScriptErrorWithCode {
5621 code: ScriptErrorCode::InvalidStackOperation,
5622 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
5623 });
5624 }
5625 let pubkey_bytes = stack.pop().unwrap();
5627 let n_bytes = stack.pop().unwrap();
5628 let signature_bytes = stack.pop().unwrap();
5629 let n = script_num_decode(&n_bytes, 4)?;
5630
5631 if signature_bytes.is_empty() {
5633 stack.push(to_stack_element(&script_num_encode(n)));
5634 return Ok(true);
5635 }
5636
5637 if pubkey_bytes.len() == 32 {
5639 use crate::bip348::try_parse_taproot_schnorr_witness_sig;
5640 if let Some((sig_bytes, sighash_byte)) =
5641 try_parse_taproot_schnorr_witness_sig(&signature_bytes)
5642 {
5643 let (tapscript, codesep_pos) = tapscript_for_sighash
5644 .map(|s| (s, tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
5645 .unwrap_or((&[] as &[u8], 0xffff_ffff));
5646 let sighash = if tapscript.is_empty() {
5647 crate::taproot::compute_taproot_signature_hash(
5648 tx,
5649 input_index,
5650 prevout_values,
5651 prevout_script_pubkeys,
5652 sighash_byte,
5653 None,
5654 )?
5655 } else {
5656 crate::taproot::compute_tapscript_signature_hash(
5657 tx,
5658 input_index,
5659 prevout_values,
5660 prevout_script_pubkeys,
5661 tapscript,
5662 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
5663 codesep_pos,
5664 sighash_byte,
5665 ctx.taproot_annex_hash,
5666 )?
5667 };
5668
5669 #[cfg(feature = "production")]
5670 let is_valid = {
5671 use crate::bip348::verify_tapscript_schnorr_signature;
5672 verify_tapscript_schnorr_signature(
5673 &sighash,
5674 &pubkey_bytes,
5675 &sig_bytes,
5676 schnorr_collector,
5677 )
5678 .unwrap_or(false)
5679 };
5680
5681 #[cfg(not(feature = "production"))]
5682 let is_valid = {
5683 #[cfg(feature = "csfs")]
5684 let x = {
5685 use crate::bip348::verify_tapscript_schnorr_signature;
5686 verify_tapscript_schnorr_signature(
5687 &sighash,
5688 &pubkey_bytes,
5689 &sig_bytes,
5690 None,
5691 )
5692 .unwrap_or(false)
5693 };
5694 #[cfg(not(feature = "csfs"))]
5695 let x = false;
5696 x
5697 };
5698
5699 if !is_valid {
5700 return Ok(false); }
5702 stack.push(to_stack_element(&script_num_encode(n + 1)));
5703 return Ok(true);
5704 }
5705 return Ok(false); }
5707
5708 stack.push(to_stack_element(&script_num_encode(n + 1)));
5710 Ok(true)
5711 }
5712
5713 OP_CHECKMULTISIG => {
5715 if stack.len() < 2 {
5718 return Ok(false);
5719 }
5720
5721 let n_bytes = stack.pop().unwrap();
5723 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
5724 ConsensusError::ScriptErrorWithCode {
5725 code: ScriptErrorCode::InvalidStackOperation,
5726 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
5727 }
5728 })?;
5729 if !(0..=20).contains(&n_raw) {
5730 return Ok(false);
5731 }
5732 let n = n_raw as usize;
5733 if stack.len() < n + 1 {
5734 return Ok(false);
5735 }
5736
5737 let mut pubkeys = Vec::with_capacity(n);
5739 for _ in 0..n {
5740 pubkeys.push(stack.pop().unwrap());
5741 }
5742
5743 let m_bytes = stack.pop().unwrap();
5745 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
5746 ConsensusError::ScriptErrorWithCode {
5747 code: ScriptErrorCode::InvalidStackOperation,
5748 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
5749 }
5750 })?;
5751 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
5752 return Ok(false);
5753 }
5754 let m = m_raw as usize;
5755 if stack.len() < m + 1 {
5756 return Ok(false);
5757 }
5758
5759 let mut signatures = Vec::with_capacity(m);
5761 for _ in 0..m {
5762 signatures.push(stack.pop().unwrap());
5763 }
5764
5765 let dummy = stack.pop().unwrap();
5768 if flags & 0x10 != 0 {
5769 let height = block_height.unwrap_or(0);
5770 use crate::bip_validation::Bip147Network;
5772 let bip147_network = match network {
5773 crate::types::Network::Mainnet => Bip147Network::Mainnet,
5774 crate::types::Network::Testnet => Bip147Network::Testnet,
5775 crate::types::Network::Regtest | crate::types::Network::Signet => {
5776 Bip147Network::Regtest
5777 }
5778 };
5779
5780 use crate::constants::{BIP147_ACTIVATION_MAINNET, BIP147_ACTIVATION_TESTNET};
5784
5785 let bip147_active = height
5786 >= match bip147_network {
5787 Bip147Network::Mainnet => BIP147_ACTIVATION_MAINNET,
5788 Bip147Network::Testnet => BIP147_ACTIVATION_TESTNET,
5789 Bip147Network::Regtest => 0,
5790 };
5791
5792 if bip147_active {
5793 let is_empty = dummy.is_empty() || dummy.as_ref() == [0x00];
5797 if !is_empty {
5798 return Err(ConsensusError::ScriptErrorWithCode {
5799 code: ScriptErrorCode::SigNullDummy,
5800 message: format!(
5801 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be empty: [] or [0x00])"
5802 )
5803 .into(),
5804 });
5805 }
5806 }
5807 }
5808
5809 let height = block_height.unwrap_or(0);
5812
5813 let cleaned_script_for_multisig: Vec<u8> = if sigversion == SigVersion::Base {
5816 let base_script = match (
5817 redeem_script_for_sighash,
5818 prevout_script_pubkeys.get(input_index),
5819 ) {
5820 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
5821 (Some(redeem), _) => redeem,
5822 (None, Some(prevout)) => *prevout,
5823 (None, None) => &[],
5824 };
5825 let mut cleaned = base_script.to_vec();
5826 for sig in &signatures {
5827 if !sig.is_empty() {
5828 let pattern = serialize_push_data(sig.as_ref());
5829 cleaned = find_and_delete(&cleaned, &pattern).into_owned();
5830 }
5831 }
5832 cleaned
5833 } else {
5834 redeem_script_for_sighash
5836 .map(|s| s.to_vec())
5837 .unwrap_or_else(|| {
5838 prevout_script_pubkeys
5839 .get(input_index)
5840 .map(|p| p.to_vec())
5841 .unwrap_or_default()
5842 })
5843 };
5844
5845 use crate::transaction_hash::{
5846 SighashType, calculate_transaction_sighash_single_input,
5847 };
5848
5849 #[cfg(feature = "production")]
5851 let use_batch = pubkeys.len() * signatures.len() >= 4;
5852
5853 #[cfg(feature = "production")]
5854 let (valid_sigs, _) = if use_batch {
5855 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
5857 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
5858 if non_empty.is_empty() {
5859 vec![]
5860 } else {
5861 let specs: Vec<(usize, u8, &[u8])> = non_empty
5862 .iter()
5863 .map(|s| {
5864 (
5865 input_index,
5866 s.as_ref()[s.as_ref().len() - 1],
5867 cleaned_script_for_multisig.as_ref(),
5868 )
5869 })
5870 .collect();
5871 crate::transaction_hash::batch_compute_legacy_sighashes(
5872 tx,
5873 prevout_values,
5874 prevout_script_pubkeys,
5875 &specs,
5876 )?
5877 }
5878 } else {
5879 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5881 signatures
5882 .iter()
5883 .filter(|s| !s.is_empty())
5884 .map(|sig_bytes| {
5885 let sighash_byte = sig_bytes[sig_bytes.len() - 1];
5886 crate::transaction_hash::calculate_bip143_sighash(
5887 tx,
5888 input_index,
5889 &cleaned_script_for_multisig,
5890 amount,
5891 sighash_byte,
5892 precomputed_bip143,
5893 )
5894 })
5895 .collect::<Result<Vec<_>>>()?
5896 };
5897
5898 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
5900 Vec::with_capacity(pubkeys.len() * signatures.len());
5901 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
5902 let mut sighash_idx = 0usize;
5903 for (j, sig_bytes) in signatures.iter().enumerate() {
5904 if sig_bytes.is_empty() {
5905 sig_idx_to_sighash_idx.push(usize::MAX);
5906 } else {
5907 sig_idx_to_sighash_idx.push(sighash_idx);
5908 let sh = sighashes[sighash_idx];
5909 sighash_idx += 1;
5910 for pubkey_bytes in &pubkeys {
5911 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
5912 }
5913 }
5914 }
5915
5916 let results = if tasks.is_empty() {
5917 vec![]
5918 } else {
5919 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
5920 };
5921
5922 let mut sig_index = 0;
5924 let mut valid_sigs = 0usize;
5925 for (i, _pubkey_bytes) in pubkeys.iter().enumerate() {
5926 if sig_index >= signatures.len() {
5927 break;
5928 }
5929 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
5931 sig_index += 1;
5932 }
5933 if sig_index >= signatures.len() {
5934 break;
5935 }
5936 let sh_idx = sig_idx_to_sighash_idx[sig_index];
5937 if sh_idx == usize::MAX {
5938 continue;
5939 }
5940 let task_idx = sh_idx * pubkeys.len() + i;
5941 if task_idx < results.len() && results[task_idx] {
5942 valid_sigs += 1;
5943 sig_index += 1;
5944 }
5945 }
5946
5947 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
5949 if (flags & SCRIPT_VERIFY_NULLFAIL) != 0 {
5950 for (j, sig_bytes) in signatures.iter().enumerate() {
5951 if sig_bytes.is_empty() {
5952 continue;
5953 }
5954 let sh_idx = sig_idx_to_sighash_idx[j];
5955 if sh_idx == usize::MAX {
5956 continue;
5957 }
5958 let sig_start = sh_idx * pubkeys.len();
5959 let sig_end = (sig_start + pubkeys.len()).min(results.len());
5960 let matched = results[sig_start..sig_end].iter().any(|&r| r);
5961 if !matched {
5962 return Err(ConsensusError::ScriptErrorWithCode {
5963 code: ScriptErrorCode::SigNullFail,
5964 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
5965 });
5966 }
5967 }
5968 }
5969 (valid_sigs, ())
5970 } else {
5971 let mut sig_index = 0;
5972 let mut valid_sigs = 0;
5973 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
5974
5975 for pubkey_bytes in &pubkeys {
5976 if sig_index >= signatures.len() {
5977 break;
5978 }
5979
5980 let signature_bytes = &signatures[sig_index];
5981
5982 if signature_bytes.is_empty() {
5983 continue;
5984 }
5985
5986 let sig_len = signature_bytes.len();
5987 let sighash_byte = signature_bytes[sig_len - 1];
5988
5989 let sighash = if sigversion == SigVersion::WitnessV0 {
5991 crate::transaction_hash::calculate_bip143_sighash(
5992 tx,
5993 input_index,
5994 &cleaned_script_for_multisig,
5995 amount,
5996 sighash_byte,
5997 #[cfg(feature = "production")]
5998 precomputed_bip143,
5999 #[cfg(not(feature = "production"))]
6000 None,
6001 )?
6002 } else {
6003 let sighash_type = SighashType::from_byte(sighash_byte);
6004 calculate_transaction_sighash_single_input(
6005 tx,
6006 input_index,
6007 &cleaned_script_for_multisig,
6008 prevout_values[input_index],
6009 sighash_type,
6010 #[cfg(feature = "production")]
6011 sighash_cache,
6012 )?
6013 };
6014
6015 #[cfg(feature = "production")]
6016 let is_valid = signature::with_secp_context(|secp| {
6017 signature::verify_signature(
6018 secp,
6019 pubkey_bytes,
6020 signature_bytes,
6021 &sighash,
6022 flags,
6023 height,
6024 network,
6025 sigversion,
6026 )
6027 })?;
6028
6029 #[cfg(not(feature = "production"))]
6030 let is_valid = {
6031 let secp = signature::new_secp();
6032 signature::verify_signature(
6033 &secp,
6034 pubkey_bytes,
6035 signature_bytes,
6036 &sighash,
6037 flags,
6038 height,
6039 network,
6040 sigversion,
6041 )?
6042 };
6043
6044 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6045 if !is_valid
6046 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6047 && !signature_bytes.is_empty()
6048 {
6049 return Err(ConsensusError::ScriptErrorWithCode {
6050 code: ScriptErrorCode::SigNullFail,
6051 message:
6052 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6053 .into(),
6054 });
6055 }
6056
6057 if is_valid {
6058 valid_sigs += 1;
6059 sig_index += 1;
6060 }
6061 }
6062 (valid_sigs, ())
6063 };
6064
6065 #[cfg(not(feature = "production"))]
6066 let (valid_sigs, _) = {
6067 let mut sig_index = 0;
6068 let mut valid_sigs = 0;
6069 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
6070
6071 for pubkey_bytes in &pubkeys {
6072 if sig_index >= signatures.len() {
6073 break;
6074 }
6075 let signature_bytes = &signatures[sig_index];
6076 if signature_bytes.is_empty() {
6077 continue;
6078 }
6079 let sig_len = signature_bytes.len();
6080 let sighash_byte = signature_bytes[sig_len - 1];
6081
6082 let sighash = if sigversion == SigVersion::WitnessV0 {
6084 crate::transaction_hash::calculate_bip143_sighash(
6085 tx,
6086 input_index,
6087 &cleaned_script_for_multisig,
6088 amount,
6089 sighash_byte,
6090 None,
6091 )?
6092 } else {
6093 let sighash_type = SighashType::from_byte(sighash_byte);
6094 calculate_transaction_sighash_single_input(
6095 tx,
6096 input_index,
6097 &cleaned_script_for_multisig,
6098 prevout_values[input_index],
6099 sighash_type,
6100 )?
6101 };
6102 let secp = signature::new_secp();
6103 let is_valid = signature::verify_signature(
6104 &secp,
6105 pubkey_bytes,
6106 signature_bytes,
6107 &sighash,
6108 flags,
6109 height,
6110 network,
6111 sigversion,
6112 )?;
6113 const SCRIPT_VERIFY_NULLFAIL: u32 = 0x4000;
6114 if !is_valid
6115 && (flags & SCRIPT_VERIFY_NULLFAIL) != 0
6116 && !signature_bytes.is_empty()
6117 {
6118 return Err(ConsensusError::ScriptErrorWithCode {
6119 code: ScriptErrorCode::SigNullFail,
6120 message:
6121 "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL"
6122 .into(),
6123 });
6124 }
6125 if is_valid {
6126 valid_sigs += 1;
6127 sig_index += 1;
6128 }
6129 }
6130 (valid_sigs, ())
6131 };
6132
6133 stack.push(to_stack_element(&[if valid_sigs >= m { 1 } else { 0 }]));
6135 Ok(true)
6136 }
6137
6138 OP_CHECKMULTISIGVERIFY => {
6140 let ctx_checkmultisig = context::ScriptContext {
6142 tx,
6143 input_index,
6144 prevout_values,
6145 prevout_script_pubkeys,
6146 block_height,
6147 median_time_past,
6148 network,
6149 sigversion,
6150 redeem_script_for_sighash,
6151 script_sig_for_sighash,
6152 tapscript_for_sighash,
6153 tapscript_codesep_pos,
6154 taproot_annex_hash: None,
6155 #[cfg(feature = "production")]
6156 schnorr_collector: None,
6157 #[cfg(feature = "production")]
6158 precomputed_bip143,
6159 #[cfg(feature = "production")]
6160 sighash_cache,
6161 };
6162 let result = execute_opcode_with_context_full(
6163 OP_CHECKMULTISIG,
6164 stack,
6165 flags,
6166 &ctx_checkmultisig,
6167 redeem_script_for_sighash,
6168 )?;
6169 if !result {
6170 return Ok(false);
6171 }
6172 if let Some(top) = stack.pop() {
6174 if !cast_to_bool(&top) {
6175 return Ok(false);
6176 }
6177 Ok(true)
6178 } else {
6179 Ok(false)
6180 }
6181 }
6182
6183 OP_CHECKLOCKTIMEVERIFY => {
6188 const SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY: u32 = 0x200;
6190 if (flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
6191 return Ok(true);
6192 }
6193
6194 use crate::locktime::{check_bip65, decode_locktime_value};
6195
6196 if stack.is_empty() {
6197 return Err(ConsensusError::ScriptErrorWithCode {
6198 code: ScriptErrorCode::InvalidStackOperation,
6199 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
6200 });
6201 }
6202
6203 let locktime_bytes = stack.last().expect("Stack is not empty");
6205 let locktime_value = match decode_locktime_value(locktime_bytes.as_ref()) {
6206 Some(v) => v,
6207 None => {
6208 return Err(ConsensusError::ScriptErrorWithCode {
6209 code: ScriptErrorCode::MinimalData,
6210 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
6211 });
6212 }
6213 };
6214
6215 let tx_locktime = tx.lock_time as u32;
6216
6217 if !check_bip65(tx_locktime, locktime_value) {
6219 return Ok(false);
6220 }
6221
6222 let input_seq = if input_index < tx.inputs.len() {
6224 tx.inputs[input_index].sequence
6225 } else {
6226 0xffffffff
6227 };
6228 if input_seq == 0xffffffff {
6229 return Ok(false);
6230 }
6231
6232 Ok(true)
6234 }
6235
6236 OP_CHECKSEQUENCEVERIFY => {
6245 use crate::locktime::{
6246 decode_locktime_value, extract_sequence_locktime_value, extract_sequence_type_flag,
6247 is_sequence_disabled,
6248 };
6249
6250 const SCRIPT_VERIFY_CHECKSEQUENCEVERIFY: u32 = 0x400;
6252 if (flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
6253 return Ok(true);
6254 }
6255
6256 if stack.is_empty() {
6257 return Ok(false);
6258 }
6259
6260 let sequence_bytes = stack.last().expect("Stack is not empty");
6263 let sequence_value = match decode_locktime_value(sequence_bytes.as_ref()) {
6264 Some(v) => v,
6265 None => return Ok(false), };
6267
6268 if input_index >= tx.inputs.len() {
6270 return Ok(false);
6271 }
6272 let input_sequence = tx.inputs[input_index].sequence as u32;
6273
6274 if is_sequence_disabled(input_sequence) {
6276 return Ok(true);
6277 }
6278
6279 let type_flag = extract_sequence_type_flag(sequence_value);
6281 let locktime_mask = extract_sequence_locktime_value(sequence_value) as u32;
6282
6283 let input_type_flag = extract_sequence_type_flag(input_sequence);
6285 let input_locktime = extract_sequence_locktime_value(input_sequence) as u32;
6286
6287 if type_flag != input_type_flag {
6289 return Ok(false);
6290 }
6291
6292 if input_locktime < locktime_mask {
6294 return Ok(false);
6295 }
6296
6297 Ok(true)
6299 }
6300
6301 OP_CHECKTEMPLATEVERIFY => {
6310 #[cfg(not(feature = "ctv"))]
6311 {
6312 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6314 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6315 return Err(ConsensusError::ScriptErrorWithCode {
6316 code: ScriptErrorCode::BadOpcode,
6317 message: "OP_CHECKTEMPLATEVERIFY requires --features ctv".into(),
6318 });
6319 }
6320 Ok(true) }
6322
6323 #[cfg(feature = "ctv")]
6324 {
6325 use crate::constants::{
6326 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
6327 };
6328
6329 let ctv_activation = match network {
6331 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
6332 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
6333 crate::types::Network::Regtest | crate::types::Network::Signet => {
6334 CTV_ACTIVATION_REGTEST
6335 }
6336 };
6337
6338 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
6339 if !ctv_active {
6340 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6342 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6343 return Err(ConsensusError::ScriptErrorWithCode {
6344 code: ScriptErrorCode::BadOpcode,
6345 message: "OP_CHECKTEMPLATEVERIFY not yet activated".into(),
6346 });
6347 }
6348 return Ok(true); }
6350
6351 const SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH: u32 = 0x80000000;
6353 if (flags & SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH) == 0 {
6354 return Ok(true);
6356 }
6357
6358 use crate::bip119::calculate_template_hash;
6359
6360 if stack.is_empty() {
6362 return Err(ConsensusError::ScriptErrorWithCode {
6363 code: ScriptErrorCode::InvalidStackOperation,
6364 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
6365 });
6366 }
6367
6368 let template_hash_bytes = stack.pop().unwrap();
6369
6370 if template_hash_bytes.len() != 32 {
6372 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6375 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6376 return Err(ConsensusError::ScriptErrorWithCode {
6377 code: ScriptErrorCode::InvalidStackOperation,
6378 message: "OP_CHECKTEMPLATEVERIFY: template hash must be 32 bytes"
6379 .into(),
6380 });
6381 }
6382 return Ok(true); }
6384
6385 let mut expected_hash = [0u8; 32];
6387 expected_hash.copy_from_slice(&template_hash_bytes);
6388
6389 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
6390 ConsensusError::ScriptErrorWithCode {
6391 code: ScriptErrorCode::TxInvalid,
6392 message: format!("CTV hash calculation failed: {e}").into(),
6393 }
6394 })?;
6395
6396 use crate::crypto::hash_compare::hash_eq;
6398 let matches = hash_eq(&expected_hash, &actual_hash);
6399
6400 if !matches {
6401 return Ok(false); }
6403
6404 Ok(true)
6406 }
6407 }
6408
6409 OP_CHECKSIGFROMSTACK => {
6420 #[cfg(not(feature = "csfs"))]
6421 {
6422 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6425 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6426 return Err(ConsensusError::ScriptErrorWithCode {
6427 code: ScriptErrorCode::BadOpcode,
6428 message: "OP_CHECKSIGFROMSTACK requires --features csfs".into(),
6429 });
6430 }
6431 Ok(true) }
6433
6434 #[cfg(feature = "csfs")]
6435 {
6436 use crate::constants::{
6437 CSFS_ACTIVATION_MAINNET, CSFS_ACTIVATION_REGTEST, CSFS_ACTIVATION_TESTNET,
6438 };
6439
6440 if sigversion != SigVersion::Tapscript {
6442 return Err(ConsensusError::ScriptErrorWithCode {
6443 code: ScriptErrorCode::BadOpcode,
6444 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
6445 });
6446 }
6447
6448 let csfs_activation = match network {
6450 crate::types::Network::Mainnet => CSFS_ACTIVATION_MAINNET,
6451 crate::types::Network::Testnet => CSFS_ACTIVATION_TESTNET,
6452 crate::types::Network::Regtest | crate::types::Network::Signet => {
6453 CSFS_ACTIVATION_REGTEST
6454 }
6455 };
6456
6457 let csfs_active = block_height.map(|h| h >= csfs_activation).unwrap_or(false);
6458 if !csfs_active {
6459 const SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS: u32 = 0x10000;
6461 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) != 0 {
6462 return Err(ConsensusError::ScriptErrorWithCode {
6463 code: ScriptErrorCode::BadOpcode,
6464 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
6465 });
6466 }
6467 return Ok(true); }
6469
6470 use crate::bip348::verify_signature_from_stack;
6471
6472 if stack.len() < 3 {
6474 return Err(ConsensusError::ScriptErrorWithCode {
6475 code: ScriptErrorCode::InvalidStackOperation,
6476 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
6477 });
6478 }
6479
6480 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
6487 return Err(ConsensusError::ScriptErrorWithCode {
6488 code: ScriptErrorCode::PubkeyType,
6489 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
6490 });
6491 }
6492
6493 if signature_bytes.is_empty() {
6495 stack.push(to_stack_element(&[])); return Ok(true);
6497 }
6498
6499 #[cfg(feature = "production")]
6502 let is_valid = {
6503 verify_signature_from_stack(
6504 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
6509 .unwrap_or(false)
6510 };
6511 #[cfg(not(feature = "production"))]
6512 let is_valid = verify_signature_from_stack(
6513 &message_bytes, &pubkey_bytes, &signature_bytes, )
6517 .unwrap_or(false);
6518
6519 if !is_valid {
6520 return Ok(false);
6522 }
6523
6524 stack.push(to_stack_element(&[0x01])); Ok(true)
6530 }
6531 }
6532
6533 _ => execute_opcode_cold(opcode, stack, flags),
6535 }
6536}
6537
6538#[cold]
6540fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
6541 execute_opcode(opcode, stack, flags, SigVersion::Base)
6542}
6543
6544#[cfg(all(feature = "production", feature = "profile"))]
6559pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64) {
6560 (
6561 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
6562 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
6563 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
6564 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
6565 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
6566 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
6567 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
6568 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
6569 )
6570}
6571
6572#[cfg(all(feature = "production", feature = "benchmarking"))]
6579pub fn clear_script_cache() {
6580 if let Some(cache) = SCRIPT_CACHE.get() {
6581 let mut cache = cache.write().unwrap_or_else(|e| e.into_inner());
6582 cache.clear();
6583 }
6584}
6585
6586#[cfg(all(feature = "production", feature = "benchmarking"))]
6600pub fn clear_hash_cache() {
6601 crypto_ops::clear_hash_cache();
6602}
6603
6604#[cfg(all(feature = "production", feature = "benchmarking"))]
6617pub fn clear_all_caches() {
6618 clear_script_cache();
6619 clear_hash_cache();
6620}
6621
6622#[cfg(all(feature = "production", feature = "benchmarking"))]
6636pub fn clear_stack_pool() {
6637 STACK_POOL.with(|pool| {
6638 let mut pool = pool.borrow_mut();
6639 pool.clear();
6640 });
6641}
6642
6643#[cfg(all(feature = "production", feature = "benchmarking"))]
6657pub fn reset_benchmarking_state() {
6658 clear_all_caches();
6659 clear_stack_pool();
6660 disable_caching(false); #[cfg(feature = "benchmarking")]
6663 crate::transaction_hash::clear_sighash_templates();
6664}
6665
6666#[cfg(test)]
6667mod tests {
6668 use super::*;
6669
6670 #[test]
6671 fn test_eval_script_simple() {
6672 let script = vec![OP_1]; let mut stack = Vec::new();
6674
6675 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
6676 assert_eq!(stack.len(), 1);
6677 assert_eq!(stack[0].as_ref(), &[1]);
6678 }
6679
6680 #[test]
6681 fn test_eval_script_overflow() {
6682 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
6684
6685 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
6686 }
6687
6688 #[test]
6689 fn test_verify_script_simple() {
6690 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());
6701 }
6702
6703 #[test]
6708 fn test_op_0() {
6709 let script = vec![OP_0]; let mut stack = Vec::new();
6711 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6712 assert!(result); assert_eq!(stack.len(), 1);
6714 assert!(stack[0].is_empty());
6715 }
6716
6717 #[test]
6718 fn test_op_1_to_op_16() {
6719 for i in 1..=16 {
6721 let opcode = 0x50 + i;
6722 let script = vec![opcode];
6723 let mut stack = Vec::new();
6724 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6725 assert!(result);
6726 assert_eq!(stack.len(), 1);
6727 assert_eq!(stack[0].as_ref(), &[i]);
6728 }
6729 }
6730
6731 #[test]
6732 fn test_op_dup() {
6733 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
6735 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6736 assert!(result); assert_eq!(stack.len(), 2);
6738 assert_eq!(stack[0].as_ref(), &[1]);
6739 assert_eq!(stack[1].as_ref(), &[1]);
6740 }
6741
6742 #[test]
6743 fn test_op_dup_empty_stack() {
6744 let script = vec![OP_DUP]; let mut stack = Vec::new();
6746 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6747 assert!(!result);
6748 }
6749
6750 #[test]
6751 fn test_op_hash160() {
6752 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
6754 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6755 assert!(result);
6756 assert_eq!(stack.len(), 1);
6757 assert_eq!(stack[0].len(), 20); }
6759
6760 #[test]
6761 fn test_op_hash160_empty_stack() {
6762 let script = vec![OP_HASH160]; let mut stack = Vec::new();
6764 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6765 assert!(!result);
6766 }
6767
6768 #[test]
6769 fn test_op_hash256() {
6770 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
6772 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6773 assert!(result);
6774 assert_eq!(stack.len(), 1);
6775 assert_eq!(stack[0].len(), 32); }
6777
6778 #[test]
6779 fn test_op_hash256_empty_stack() {
6780 let script = vec![OP_HASH256]; let mut stack = Vec::new();
6782 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6783 assert!(!result);
6784 }
6785
6786 #[test]
6787 fn test_op_equal() {
6788 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
6790 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6791 assert!(result);
6792 assert_eq!(stack.len(), 1);
6793 assert_eq!(stack[0].as_ref(), &[1]); }
6795
6796 #[test]
6797 fn test_op_equal_false() {
6798 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
6800 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6801 assert!(result); assert_eq!(stack.len(), 1);
6803 assert!(stack[0].is_empty()); }
6805
6806 #[test]
6807 fn test_op_equal_insufficient_stack() {
6808 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
6810 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6811 assert!(
6812 result.is_err(),
6813 "OP_EQUAL with insufficient stack should return error"
6814 );
6815 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6816 assert_eq!(
6817 code,
6818 crate::error::ScriptErrorCode::InvalidStackOperation,
6819 "Should return InvalidStackOperation"
6820 );
6821 }
6822 }
6823
6824 #[test]
6825 fn test_op_verify() {
6826 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
6828 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6829 assert!(result); assert_eq!(stack.len(), 0); }
6832
6833 #[test]
6834 fn test_op_verify_false() {
6835 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
6837 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6838 assert!(!result);
6839 }
6840
6841 #[test]
6842 fn test_op_verify_empty_stack() {
6843 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
6845 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6846 assert!(!result);
6847 }
6848
6849 #[test]
6850 fn test_op_equalverify() {
6851 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
6853 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6854 assert!(result); assert_eq!(stack.len(), 0); }
6857
6858 #[test]
6859 fn test_op_equalverify_false() {
6860 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
6862 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6863 assert!(
6864 result.is_err(),
6865 "OP_EQUALVERIFY with false condition should return error"
6866 );
6867 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6868 assert_eq!(
6869 code,
6870 crate::error::ScriptErrorCode::EqualVerify,
6871 "Should return EqualVerify"
6872 );
6873 }
6874 }
6875
6876 #[test]
6877 fn test_op_checksig() {
6878 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6882 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6883 assert!(result); assert_eq!(stack.len(), 1);
6885 }
6887
6888 #[test]
6889 fn test_op_checksig_insufficient_stack() {
6890 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
6892 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6893 assert!(
6894 result.is_err(),
6895 "OP_CHECKSIG with insufficient stack should return error"
6896 );
6897 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6898 assert_eq!(
6899 code,
6900 crate::error::ScriptErrorCode::InvalidStackOperation,
6901 "Should return InvalidStackOperation"
6902 );
6903 }
6904 }
6905
6906 #[test]
6907 fn test_unknown_opcode() {
6908 let script = vec![0xff]; let mut stack = Vec::new();
6910 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6911 assert!(!result);
6912 }
6913
6914 #[test]
6915 fn test_script_size_limit() {
6916 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
6918 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6919 assert!(result.is_err());
6920 }
6921
6922 #[test]
6923 fn test_operation_count_limit() {
6924 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
6927 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6928 assert!(result.is_err());
6929 }
6930
6931 #[test]
6932 fn test_stack_underflow_multiple_ops() {
6933 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
6935 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
6936 assert!(result.is_err(), "Stack underflow should return error");
6937 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
6938 assert_eq!(
6939 code,
6940 crate::error::ScriptErrorCode::InvalidStackOperation,
6941 "Should return InvalidStackOperation"
6942 );
6943 }
6944 }
6945
6946 #[test]
6947 fn test_final_stack_empty() {
6948 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
6951 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6952 assert!(result); assert_eq!(stack.len(), 2);
6954 }
6955
6956 #[test]
6957 fn test_final_stack_false() {
6958 let script = vec![OP_0]; let mut stack = Vec::new();
6961 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6962 assert!(result); }
6964
6965 #[test]
6966 fn test_verify_script_with_witness() {
6967 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
6972
6973 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
6974 assert!(result); }
6976
6977 #[test]
6978 fn test_verify_script_failure() {
6979 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_0]; let witness = None;
6983 let flags = 0;
6984
6985 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
6986 assert!(!result); }
6988
6989 #[test]
6994 fn test_op_ifdup_true() {
6995 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
6997 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
6998 assert!(result); assert_eq!(stack.len(), 2);
7000 assert_eq!(stack[0].as_ref(), &[1]);
7001 assert_eq!(stack[1].as_ref(), &[1]);
7002 }
7003
7004 #[test]
7005 fn test_op_ifdup_false() {
7006 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
7008 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7009 assert!(result); assert_eq!(stack.len(), 1);
7011 assert_eq!(stack[0].as_ref(), &[] as &[u8]);
7012 }
7013
7014 #[test]
7015 fn test_op_depth() {
7016 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
7018 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7019 assert!(result); assert_eq!(stack.len(), 3);
7021 assert_eq!(stack[2].as_ref(), &[2]); }
7023
7024 #[test]
7025 fn test_op_drop() {
7026 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
7028 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7029 assert!(result); assert_eq!(stack.len(), 1);
7031 assert_eq!(stack[0].as_ref(), &[1]);
7032 }
7033
7034 #[test]
7035 fn test_op_drop_empty_stack() {
7036 let script = vec![OP_DROP]; let mut stack = Vec::new();
7038 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7039 assert!(!result);
7040 assert_eq!(stack.len(), 0);
7041 }
7042
7043 #[test]
7044 fn test_op_nip() {
7045 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
7047 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7048 assert!(result); assert_eq!(stack.len(), 1);
7050 assert_eq!(stack[0].as_ref(), &[2]);
7051 }
7052
7053 #[test]
7054 fn test_op_nip_insufficient_stack() {
7055 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
7057 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7058 assert!(!result);
7059 assert_eq!(stack.len(), 1);
7060 }
7061
7062 #[test]
7063 fn test_op_over() {
7064 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
7066 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7067 assert!(result); assert_eq!(stack.len(), 3);
7069 assert_eq!(stack[0].as_ref(), &[1]);
7070 assert_eq!(stack[1].as_ref(), &[2]);
7071 assert_eq!(stack[2].as_ref(), &[1]);
7072 }
7073
7074 #[test]
7075 fn test_op_over_insufficient_stack() {
7076 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
7078 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7079 assert!(!result);
7080 assert_eq!(stack.len(), 1);
7081 }
7082
7083 #[test]
7084 fn test_op_pick() {
7085 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
7087 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7088 assert!(result); assert_eq!(stack.len(), 4);
7090 assert_eq!(stack[3].as_ref(), &[2]); }
7092
7093 #[test]
7094 fn test_op_pick_empty_n() {
7095 let script = vec![OP_1, OP_0, OP_PICK];
7097 let mut stack = Vec::new();
7098 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7099 assert!(result); assert_eq!(stack.len(), 2);
7101 assert_eq!(stack[1].as_ref(), &[1]); }
7103
7104 #[test]
7105 fn test_op_pick_invalid_index() {
7106 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
7108 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7109 assert!(!result);
7110 assert_eq!(stack.len(), 1);
7111 }
7112
7113 #[test]
7114 fn test_op_roll() {
7115 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
7117 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7118 assert!(result); assert_eq!(stack.len(), 3);
7120 assert_eq!(stack[0].as_ref(), &[1]);
7121 assert_eq!(stack[1].as_ref(), &[3]);
7122 assert_eq!(stack[2].as_ref(), &[2]); }
7124
7125 #[test]
7126 fn test_op_roll_zero_n() {
7127 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
7130 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7131 assert!(result); assert_eq!(stack.len(), 1);
7133 assert_eq!(stack[0].as_ref(), &[1]);
7134 }
7135
7136 #[test]
7137 fn test_op_roll_invalid_index() {
7138 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
7140 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7141 assert!(!result);
7142 assert_eq!(stack.len(), 1);
7143 }
7144
7145 #[test]
7146 fn test_op_rot() {
7147 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
7149 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7150 assert!(result); assert_eq!(stack.len(), 3);
7152 assert_eq!(stack[0].as_ref(), &[2]);
7153 assert_eq!(stack[1].as_ref(), &[3]);
7154 assert_eq!(stack[2].as_ref(), &[1]);
7155 }
7156
7157 #[test]
7158 fn test_op_rot_insufficient_stack() {
7159 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
7161 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7162 assert!(!result);
7163 assert_eq!(stack.len(), 2);
7164 }
7165
7166 #[test]
7167 fn test_op_swap() {
7168 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
7170 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7171 assert!(result); assert_eq!(stack.len(), 2);
7173 assert_eq!(stack[0].as_ref(), &[2]);
7174 assert_eq!(stack[1].as_ref(), &[1]);
7175 }
7176
7177 #[test]
7178 fn test_op_swap_insufficient_stack() {
7179 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
7181 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7182 assert!(!result);
7183 assert_eq!(stack.len(), 1);
7184 }
7185
7186 #[test]
7187 fn test_op_tuck() {
7188 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
7190 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7191 assert!(result); assert_eq!(stack.len(), 3);
7193 assert_eq!(stack[0].as_ref(), &[2]);
7194 assert_eq!(stack[1].as_ref(), &[1]);
7195 assert_eq!(stack[2].as_ref(), &[2]);
7196 }
7197
7198 #[test]
7199 fn test_op_tuck_insufficient_stack() {
7200 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
7202 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7203 assert!(!result);
7204 assert_eq!(stack.len(), 1);
7205 }
7206
7207 #[test]
7208 fn test_op_2drop() {
7209 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
7211 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7212 assert!(result); assert_eq!(stack.len(), 1);
7214 assert_eq!(stack[0].as_ref(), &[1]);
7215 }
7216
7217 #[test]
7218 fn test_op_2drop_insufficient_stack() {
7219 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
7221 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7222 assert!(!result);
7223 assert_eq!(stack.len(), 1);
7224 }
7225
7226 #[test]
7227 fn test_op_2dup() {
7228 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
7230 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7231 assert!(result); assert_eq!(stack.len(), 4);
7233 assert_eq!(stack[0].as_ref(), &[1]);
7234 assert_eq!(stack[1].as_ref(), &[2]);
7235 assert_eq!(stack[2].as_ref(), &[1]);
7236 assert_eq!(stack[3].as_ref(), &[2]);
7237 }
7238
7239 #[test]
7240 fn test_op_2dup_insufficient_stack() {
7241 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
7243 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7244 assert!(!result);
7245 assert_eq!(stack.len(), 1);
7246 }
7247
7248 #[test]
7249 fn test_op_3dup() {
7250 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
7252 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7253 assert!(result); assert_eq!(stack.len(), 6);
7255 assert_eq!(stack[0].as_ref(), &[1]);
7256 assert_eq!(stack[1].as_ref(), &[2]);
7257 assert_eq!(stack[2].as_ref(), &[3]);
7258 assert_eq!(stack[3].as_ref(), &[1]);
7259 assert_eq!(stack[4].as_ref(), &[2]);
7260 assert_eq!(stack[5].as_ref(), &[3]);
7261 }
7262
7263 #[test]
7264 fn test_op_3dup_insufficient_stack() {
7265 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
7267 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7268 assert!(!result);
7269 assert_eq!(stack.len(), 2);
7270 }
7271
7272 #[test]
7273 fn test_op_2over() {
7274 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
7276 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7277 assert!(result); assert_eq!(stack.len(), 6);
7279 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]);
7281 }
7282
7283 #[test]
7284 fn test_op_2over_insufficient_stack() {
7285 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
7287 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7288 assert!(!result);
7289 assert_eq!(stack.len(), 3);
7290 }
7291
7292 #[test]
7293 fn test_op_2rot() {
7294 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
7299 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7300 assert!(result); assert_eq!(stack.len(), 6);
7302 assert_eq!(stack[4].as_ref(), &[1]); assert_eq!(stack[5].as_ref(), &[2]); }
7305
7306 #[test]
7307 fn test_op_2rot_insufficient_stack() {
7308 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
7310 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7311 assert!(!result);
7312 assert_eq!(stack.len(), 4);
7313 }
7314
7315 #[test]
7316 fn test_op_2swap() {
7317 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
7319 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7320 assert!(result); assert_eq!(stack.len(), 4);
7322 assert_eq!(stack[0].as_ref(), &[3]); assert_eq!(stack[1].as_ref(), &[4]);
7324 assert_eq!(stack[2].as_ref(), &[1]);
7325 assert_eq!(stack[3].as_ref(), &[2]);
7326 }
7327
7328 #[test]
7329 fn test_op_2swap_insufficient_stack() {
7330 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
7332 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7333 assert!(!result);
7334 assert_eq!(stack.len(), 3);
7335 }
7336
7337 #[test]
7338 fn test_op_size() {
7339 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
7341 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7342 assert!(result); assert_eq!(stack.len(), 2);
7344 assert_eq!(stack[0].as_ref(), &[1]);
7345 assert_eq!(stack[1].as_ref(), &[1]); }
7347
7348 #[test]
7349 fn test_op_size_empty_stack() {
7350 let script = vec![OP_SIZE]; let mut stack = Vec::new();
7352 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7353 assert!(!result);
7354 assert_eq!(stack.len(), 0);
7355 }
7356
7357 #[test]
7358 fn test_op_return() {
7359 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
7361 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7362 assert!(!result); assert_eq!(stack.len(), 1);
7364 }
7365
7366 #[test]
7367 fn test_op_checksigverify() {
7368 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7370 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7371 assert!(!result); assert_eq!(stack.len(), 0);
7373 }
7374
7375 #[test]
7376 fn test_op_checksigverify_insufficient_stack() {
7377 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
7379 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7380 assert!(!result);
7381 assert_eq!(stack.len(), 1);
7382 }
7383
7384 #[test]
7385 fn test_unknown_opcode_comprehensive() {
7386 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
7388 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
7389 assert!(!result); assert_eq!(stack.len(), 1);
7391 }
7392
7393 #[test]
7394 fn test_verify_signature_invalid_pubkey() {
7395 let secp = signature::new_secp();
7396 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
7399 let result = signature::verify_signature(
7400 &secp,
7401 &invalid_pubkey,
7402 &signature,
7403 &dummy_hash,
7404 0,
7405 0,
7406 crate::types::Network::Regtest,
7407 SigVersion::Base,
7408 );
7409 assert!(!result.unwrap_or(false));
7410 }
7411
7412 #[test]
7413 fn test_verify_signature_invalid_signature() {
7414 let secp = signature::new_secp();
7415 let pubkey = vec![
7416 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
7417 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
7418 0x5b, 0x16, 0xf8, 0x17, 0x98,
7419 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
7422 let result = signature::verify_signature(
7423 &secp,
7424 &pubkey,
7425 &invalid_signature,
7426 &dummy_hash,
7427 0,
7428 0,
7429 crate::types::Network::Regtest,
7430 SigVersion::Base,
7431 );
7432 assert!(!result.unwrap_or(false));
7433 }
7434
7435 fn minimal_tx_and_prevouts(
7441 script_sig: &[u8],
7442 script_pubkey: &[u8],
7443 ) -> (
7444 crate::types::Transaction,
7445 Vec<i64>,
7446 Vec<crate::types::ByteString>,
7447 ) {
7448 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
7449 let tx = Transaction {
7450 version: 1,
7451 inputs: vec![TransactionInput {
7452 prevout: OutPoint {
7453 hash: [0u8; 32],
7454 index: 0,
7455 },
7456 sequence: 0xffff_ffff,
7457 script_sig: script_sig.to_vec(),
7458 }]
7459 .into(),
7460 outputs: vec![TransactionOutput {
7461 value: 0,
7462 script_pubkey: script_pubkey.to_vec(),
7463 }]
7464 .into(),
7465 lock_time: 0,
7466 };
7467 let prevout_values = vec![0i64];
7468 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
7469 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
7470 (tx, prevout_values, prevout_script_pubkeys_vec)
7471 }
7472
7473 #[test]
7474 fn test_verify_with_context_p2pkh_hash_mismatch() {
7475 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
7479 script_sig.push(sig.len() as u8);
7480 script_sig.extend(&sig);
7481 script_sig.push(pubkey.len() as u8);
7482 script_sig.extend(&pubkey);
7483
7484 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
7485 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
7487 script_pubkey.push(OP_CHECKSIG);
7488
7489 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7490 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7491 let result = verify_script_with_context_full(
7492 &script_sig,
7493 &script_pubkey,
7494 None,
7495 0,
7496 &tx,
7497 0,
7498 &pv,
7499 &psp_refs,
7500 Some(500_000),
7501 None,
7502 crate::types::Network::Mainnet,
7503 SigVersion::Base,
7504 #[cfg(feature = "production")]
7505 None,
7506 None, #[cfg(feature = "production")]
7508 None,
7509 #[cfg(feature = "production")]
7510 None,
7511 #[cfg(feature = "production")]
7512 None,
7513 );
7514 assert!(result.is_ok());
7515 assert!(!result.unwrap());
7516 }
7517
7518 #[test]
7519 fn test_verify_with_context_p2sh_hash_mismatch() {
7520 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
7523 script_sig.push(redeem.len() as u8);
7524 script_sig.extend(&redeem);
7525
7526 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
7527 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
7529
7530 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
7531 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7532 let result = verify_script_with_context_full(
7533 &script_sig,
7534 &script_pubkey,
7535 None,
7536 0x01, &tx,
7538 0,
7539 &pv,
7540 &psp_refs,
7541 Some(500_000),
7542 None,
7543 crate::types::Network::Mainnet,
7544 SigVersion::Base,
7545 #[cfg(feature = "production")]
7546 None,
7547 None, #[cfg(feature = "production")]
7549 None,
7550 #[cfg(feature = "production")]
7551 None,
7552 #[cfg(feature = "production")]
7553 None,
7554 );
7555 assert!(result.is_ok());
7556 assert!(!result.unwrap());
7557 }
7558
7559 #[test]
7560 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
7561 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
7563 script_pubkey.extend(&[0u8; 20]);
7564 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7566 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7567 let empty: Vec<u8> = vec![];
7568 let result = verify_script_with_context_full(
7569 &empty,
7570 &script_pubkey,
7571 Some(&witness),
7572 0,
7573 &tx,
7574 0,
7575 &pv,
7576 &psp_refs,
7577 Some(500_000),
7578 None,
7579 crate::types::Network::Mainnet,
7580 SigVersion::Base,
7581 #[cfg(feature = "production")]
7582 None,
7583 None, #[cfg(feature = "production")]
7585 None,
7586 #[cfg(feature = "production")]
7587 None,
7588 #[cfg(feature = "production")]
7589 None,
7590 );
7591 assert!(result.is_ok());
7592 assert!(!result.unwrap());
7593 }
7594
7595 #[test]
7596 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
7597 let witness_script = vec![OP_1];
7599 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7600 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
7602 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7603 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7604 let empty: Vec<u8> = vec![];
7605 let result = verify_script_with_context_full(
7606 &empty,
7607 &script_pubkey,
7608 Some(&witness),
7609 0,
7610 &tx,
7611 0,
7612 &pv,
7613 &psp_refs,
7614 Some(500_000),
7615 None,
7616 crate::types::Network::Mainnet,
7617 SigVersion::Base,
7618 #[cfg(feature = "production")]
7619 None,
7620 None, #[cfg(feature = "production")]
7622 None,
7623 #[cfg(feature = "production")]
7624 None,
7625 #[cfg(feature = "production")]
7626 None,
7627 );
7628 assert!(result.is_ok());
7629 assert!(!result.unwrap());
7630 }
7631
7632 #[test]
7633 #[cfg(feature = "production")]
7634 fn test_p2wsh_multisig_fast_path() {
7635 use crate::constants::BIP147_ACTIVATION_MAINNET;
7637 use crate::crypto::OptimizedSha256;
7638
7639 let pk1 = [0x02u8; 33];
7640 let pk2 = [0x03u8; 33];
7641 let mut witness_script = vec![0x52]; witness_script.extend_from_slice(&pk1);
7643 witness_script.extend_from_slice(&pk2);
7644 witness_script.push(0x52); witness_script.push(0xae); let wsh_hash = OptimizedSha256::new().hash(&witness_script);
7648 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
7649 script_pubkey.extend_from_slice(&wsh_hash);
7650
7651 let witness: Vec<Vec<u8>> = vec![
7652 vec![0x00], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
7656 ];
7657
7658 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
7659 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
7660 let empty: Vec<u8> = vec![];
7661 let result = verify_script_with_context_full(
7662 &empty,
7663 &script_pubkey,
7664 Some(&witness),
7665 0x810, &tx,
7667 0,
7668 &pv,
7669 &psp_refs,
7670 Some(BIP147_ACTIVATION_MAINNET + 1),
7671 None,
7672 crate::types::Network::Mainnet,
7673 SigVersion::Base,
7674 #[cfg(feature = "production")]
7675 None,
7676 None, #[cfg(feature = "production")]
7678 None,
7679 #[cfg(feature = "production")]
7680 None,
7681 #[cfg(feature = "production")]
7682 None,
7683 );
7684 assert!(result.is_ok());
7685 assert!(!result.unwrap());
7686 }
7687}
7688
7689#[cfg(test)]
7690#[allow(unused_doc_comments)]
7691mod property_tests {
7692 use super::*;
7693 use proptest::prelude::*;
7694
7695 proptest! {
7700 #[test]
7701 fn prop_eval_script_operation_limit(script in prop::collection::vec(any::<u8>(), 0..300)) {
7702 let mut stack = Vec::new();
7703 let flags = 0u32;
7704
7705 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7706
7707 if script.len() > MAX_SCRIPT_OPS * 2 {
7715 prop_assert!(result.is_err() || !result.unwrap(),
7718 "Very long scripts should fail or return false");
7719 }
7720 }
7722 }
7723
7724 proptest! {
7729 #[test]
7730 fn prop_verify_script_deterministic(
7731 script_sig in prop::collection::vec(any::<u8>(), 0..20),
7732 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
7733 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
7734 flags in any::<u32>()
7735 ) {
7736 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7737 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
7738
7739 assert_eq!(result1.is_ok(), result2.is_ok());
7740 if result1.is_ok() && result2.is_ok() {
7741 assert_eq!(result1.unwrap(), result2.unwrap());
7742 }
7743 }
7744 }
7745
7746 proptest! {
7751 #[test]
7752 fn prop_execute_opcode_no_panic(
7753 opcode in any::<u8>(),
7754 stack_items in prop::collection::vec(
7755 prop::collection::vec(any::<u8>(), 0..5),
7756 0..10
7757 ),
7758 flags in any::<u32>()
7759 ) {
7760 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7761 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7762
7763 match result {
7766 Ok(success) => {
7767 let _ = success;
7769 },
7770 Err(_) => {
7771 }
7774 }
7775
7776 assert!(stack.len() <= MAX_STACK_SIZE);
7778 }
7779 }
7780
7781 proptest! {
7788 #[test]
7789 fn prop_stack_operations_bounds(
7790 opcode in any::<u8>(),
7791 stack_items in prop::collection::vec(
7792 prop::collection::vec(any::<u8>(), 0..3),
7793 0..5
7794 ),
7795 flags in any::<u32>()
7796 ) {
7797 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
7798 let initial_len = stack.len();
7799
7800 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
7801
7802 assert!(stack.len() <= MAX_STACK_SIZE);
7804
7805 if result.is_ok() && result.unwrap() {
7807 match opcode {
7809 OP_0 | OP_1..=OP_16 => {
7810 assert!(stack.len() == initial_len + 1);
7812 },
7813 OP_DUP => {
7814 if initial_len > 0 {
7816 assert!(stack.len() == initial_len + 1);
7817 }
7818 },
7819 OP_3DUP => {
7820 if initial_len >= 3 {
7822 assert!(stack.len() == initial_len + 3);
7823 }
7824 },
7825 OP_2OVER => {
7826 if initial_len >= 4 {
7828 assert!(stack.len() == initial_len + 2);
7829 }
7830 },
7831 OP_DROP | OP_NIP | OP_2DROP => {
7832 assert!(stack.len() <= initial_len);
7834 },
7835 _ => {
7836 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
7839 }
7840 }
7841 }
7842 }
7843 }
7844
7845 proptest! {
7850 #[test]
7851 fn prop_hash_operations_deterministic(
7852 input in prop::collection::vec(any::<u8>(), 0..10)
7853 ) {
7854 let elem = to_stack_element(&input);
7855 let mut stack1 = vec![elem.clone()];
7856 let mut stack2 = vec![elem];
7857
7858 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());
7862 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7863 assert_eq!(val1, val2);
7864 if val1 {
7865 assert_eq!(stack1, stack2);
7866 }
7867 }
7868 }
7869 }
7870
7871 proptest! {
7876 #[test]
7877 fn prop_equality_operations_symmetric(
7878 a in prop::collection::vec(any::<u8>(), 0..5),
7879 b in prop::collection::vec(any::<u8>(), 0..5)
7880 ) {
7881 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
7882 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
7883
7884 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());
7888 if let (Ok(val1), Ok(val2)) = (result1, result2) {
7889 assert_eq!(val1, val2);
7890 if val1 {
7891 assert_eq!(stack1.len(), stack2.len());
7893 if !stack1.is_empty() && !stack2.is_empty() {
7894 assert_eq!(stack1[0], stack2[0]);
7895 }
7896 }
7897 }
7898 }
7899 }
7900
7901 proptest! {
7906 #[test]
7907 fn prop_script_execution_terminates(
7908 script in prop::collection::vec(any::<u8>(), 0..50)
7909 ) {
7910 let mut stack = Vec::new();
7911 let flags = 0u32;
7912
7913 let result = eval_script(&script, &mut stack, flags, SigVersion::Base);
7915
7916 assert!(result.is_ok() || result.is_err());
7918
7919 assert!(stack.len() <= MAX_STACK_SIZE);
7921 }
7922 }
7923}