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;
29pub mod templates;
30
31#[cfg(feature = "production")]
32pub use signature::{batch_verify_signatures, verify_pre_extracted_ecdsa};
33pub use stack::{StackElement, cast_to_bool, to_stack_element};
34
35use crate::constants::*;
36use crate::crypto::OptimizedSha256;
37use crate::error::{ConsensusError, Result, ScriptErrorCode};
38use crate::opcodes::*;
39use crate::types::*;
40#[cfg(feature = "spec-lock")]
41use blvm_spec_lock::spec_locked;
42use digest::Digest;
43use ripemd::Ripemd160;
44
45#[cfg(feature = "production")]
47use crate::optimizations::{precomputed_constants, prefetch};
48
49#[cold]
51#[allow(dead_code)]
52fn make_operation_limit_error() -> ConsensusError {
53 ConsensusError::ScriptErrorWithCode {
54 code: ScriptErrorCode::OpCount,
55 message: "Operation limit exceeded".into(),
56 }
57}
58
59#[inline]
65fn charge_checkmultisig_pubkeys(stack: &[StackElement], op_count: usize) -> Result<usize> {
66 let Some(n_bytes) = stack.last() else {
67 return Ok(op_count);
68 };
69 let Ok(n_raw) = script_num_decode(n_bytes, 4) else {
70 return Ok(op_count);
71 };
72 if !(0..=20).contains(&n_raw) {
73 return Ok(op_count);
74 }
75 let next = op_count.saturating_add(n_raw as usize);
76 if next > MAX_SCRIPT_OPS {
77 return Err(make_operation_limit_error());
78 }
79 Ok(next)
80}
81
82#[inline]
83fn script_bool_bytes(value: bool) -> &'static [u8] {
84 if value { &[1] } else { &[] }
85}
86
87#[cold]
88fn make_stack_overflow_error() -> ConsensusError {
89 ConsensusError::ScriptErrorWithCode {
90 code: ScriptErrorCode::StackSize,
91 message: "Stack overflow".into(),
92 }
93}
94
95#[inline]
96fn bip143_p2wpkh_script_code(pubkey_hash: &[u8]) -> [u8; 25] {
97 let mut hash = [0u8; 20];
98 hash.copy_from_slice(pubkey_hash);
99 crate::transaction_hash::derive_bip143_script_code_p2wpkh(&hash)
100}
101
102#[cfg(feature = "production")]
103use std::collections::VecDeque;
104#[cfg(feature = "production")]
105use std::sync::{
106 OnceLock, RwLock,
107 atomic::{AtomicBool, AtomicU64, Ordering},
108};
109#[cfg(feature = "production")]
110use std::thread_local;
111
112#[cfg(feature = "production")]
118static SCRIPT_CACHE: OnceLock<RwLock<lru::LruCache<u64, bool>>> = OnceLock::new();
119
120#[cfg(feature = "production")]
122thread_local! {
123 static SOA_BATCH_BUF: std::cell::RefCell<(
124 Vec<[u8; 64]>,
125 Vec<[u8; 32]>,
126 Vec<[u8; 33]>,
127 Vec<usize>,
128 Vec<[u8; 32]>,
129 )> = const { std::cell::RefCell::new((
130 Vec::new(),
131 Vec::new(),
132 Vec::new(),
133 Vec::new(),
134 Vec::new(),
135 )) };
136}
137
138#[cfg(feature = "production")]
141static FAST_PATH_P2PK: AtomicU64 = AtomicU64::new(0);
142#[cfg(feature = "production")]
143static FAST_PATH_P2PKH: AtomicU64 = AtomicU64::new(0);
144#[cfg(feature = "production")]
145static FAST_PATH_P2SH: AtomicU64 = AtomicU64::new(0);
146#[cfg(feature = "production")]
147static FAST_PATH_P2WPKH: AtomicU64 = AtomicU64::new(0);
148#[cfg(feature = "production")]
149static FAST_PATH_P2WSH: AtomicU64 = AtomicU64::new(0);
150#[cfg(feature = "production")]
151static FAST_PATH_P2TR: AtomicU64 = AtomicU64::new(0);
152#[cfg(feature = "production")]
153static FAST_PATH_UNEXEC_IF: AtomicU64 = AtomicU64::new(0);
154#[cfg(feature = "production")]
155static FAST_PATH_BARE_MULTISIG: AtomicU64 = AtomicU64::new(0);
156#[cfg(feature = "production")]
157static FAST_PATH_INTERPRETER: AtomicU64 = AtomicU64::new(0);
158
159#[cfg(feature = "production")]
160fn get_script_cache() -> &'static RwLock<lru::LruCache<u64, bool>> {
161 SCRIPT_CACHE.get_or_init(|| {
162 use lru::LruCache;
166 use std::num::NonZeroUsize;
167 RwLock::new(LruCache::new(NonZeroUsize::new(100_000).unwrap()))
168 })
169}
170
171#[cfg(feature = "production")]
176thread_local! {
177 static STACK_POOL: std::cell::RefCell<VecDeque<Vec<StackElement>>> =
178 std::cell::RefCell::new(VecDeque::with_capacity(10));
179}
180
181#[cfg(feature = "production")]
183fn get_pooled_stack() -> Vec<StackElement> {
184 STACK_POOL.with(|pool| {
185 let mut pool = pool.borrow_mut();
186 if let Some(mut stack) = pool.pop_front() {
187 stack.clear();
188 if stack.capacity() < 20 {
189 stack.reserve(20);
190 }
191 stack
192 } else {
193 Vec::with_capacity(20)
194 }
195 })
196}
197
198#[cfg(feature = "production")]
200struct PooledStackGuard(Vec<StackElement>);
201#[cfg(feature = "production")]
202impl Drop for PooledStackGuard {
203 fn drop(&mut self) {
204 return_pooled_stack(std::mem::take(&mut self.0));
205 }
206}
207
208#[cfg(feature = "production")]
210fn return_pooled_stack(mut stack: Vec<StackElement>) {
211 stack.clear();
213
214 STACK_POOL.with(|pool| {
215 let mut pool = pool.borrow_mut();
216 if pool.len() < 10 {
218 pool.push_back(stack);
219 }
220 });
222}
223
224#[cfg(feature = "production")]
229static CACHE_DISABLED: AtomicBool = AtomicBool::new(false);
230
231#[cfg(feature = "production")]
233static FAST_PATHS_DISABLED: AtomicBool = AtomicBool::new(false);
234
235#[cfg(feature = "production")]
251pub fn disable_caching(disabled: bool) {
252 CACHE_DISABLED.store(disabled, Ordering::Relaxed);
253}
254
255#[cfg(feature = "production")]
257pub fn disable_fast_paths(disabled: bool) {
258 FAST_PATHS_DISABLED.store(disabled, Ordering::Relaxed);
259}
260
261#[cfg(feature = "production")]
263fn is_caching_disabled() -> bool {
264 CACHE_DISABLED.load(Ordering::Relaxed)
265}
266
267#[cfg(feature = "production")]
268fn fast_paths_disabled() -> bool {
269 FAST_PATHS_DISABLED.load(Ordering::Relaxed)
270}
271
272#[cfg(feature = "production")]
274fn compute_script_cache_key(
275 script_sig: &ByteString,
276 script_pubkey: &[u8],
277 witness: Option<&ByteString>,
278 flags: u32,
279) -> u64 {
280 use sha2::{Digest, Sha256};
281
282 let mut hasher = Sha256::new();
283 hasher.update((script_sig.len() as u64).to_le_bytes());
284 hasher.update(&script_sig[..]);
285 hasher.update((script_pubkey.len() as u64).to_le_bytes());
286 hasher.update(script_pubkey);
287 if let Some(w) = witness {
288 hasher.update((w.len() as u64).to_le_bytes());
289 hasher.update(&w[..]);
290 } else {
291 hasher.update(0u64.to_le_bytes());
292 }
293 hasher.update(flags.to_le_bytes());
294 let digest = hasher.finalize();
295 u64::from_le_bytes(digest[0..8].try_into().expect("sha256 prefix"))
296}
297
298#[derive(Debug, Clone, Copy, PartialEq, Eq)]
300pub enum SigVersion {
301 Base,
303 WitnessV0,
305 Tapscript,
307}
308
309#[cfg_attr(feature = "spec-lock", spec_locked("5.2", "EvalScript"))]
326#[cfg_attr(feature = "production", inline(always))]
327#[cfg_attr(not(feature = "production"), inline)]
328pub fn eval_script(
329 script: &[u8],
330 stack: &mut Vec<StackElement>,
331 flags: u32,
332 sigversion: SigVersion,
333) -> Result<bool> {
334 if stack.capacity() < 20 {
337 stack.reserve(20);
338 }
339 #[cfg(feature = "production")]
340 {
341 eval_script_impl(script, stack, flags, sigversion)
342 }
343 #[cfg(not(feature = "production"))]
344 {
345 eval_script_inner(script, stack, flags, sigversion)
346 }
347}
348#[cfg(feature = "production")]
349fn eval_script_impl(
350 script: &[u8],
351 stack: &mut Vec<StackElement>,
352 flags: u32,
353 sigversion: SigVersion,
354) -> Result<bool> {
355 eval_script_inner(script, stack, flags, sigversion)
356}
357
358#[inline(always)]
360pub(crate) fn is_push_opcode(opcode: u8) -> bool {
361 opcode <= 0x60
362}
363
364#[inline]
367pub(crate) fn is_op_success(opcode: u8) -> bool {
368 matches!(
369 opcode,
370 80 | 98
371 | 126..=129
372 | 131..=134
373 | 137..=138
374 | 141..=142
375 | 149..=153
376 | 187..=254
377 )
378}
379
380fn dead_branch_opcode_error(opcode: u8) -> Option<ScriptErrorCode> {
385 let disabled = matches!(
386 opcode,
387 OP_CAT..=OP_RIGHT
388 | OP_INVERT..=OP_XOR
389 | OP_2MUL
390 | OP_2DIV
391 | OP_MUL
392 | OP_DIV
393 | OP_MOD
394 | OP_LSHIFT
395 | OP_RSHIFT
396 );
397 if disabled {
398 return Some(ScriptErrorCode::DisabledOpcode);
399 }
400 if opcode == OP_VERIF || opcode == OP_VERNOTIF {
401 return Some(ScriptErrorCode::BadOpcode);
402 }
403 None
404}
405
406#[inline]
409pub(crate) fn op_advance(script: &[u8], pc: usize) -> usize {
410 let opcode = script[pc];
411 match opcode {
412 0x01..=0x4b => 1 + opcode as usize,
414 0x4c => {
416 if pc + 1 < script.len() {
417 2 + script[pc + 1] as usize
418 } else {
419 1
420 }
421 }
422 0x4d => {
424 if pc + 2 < script.len() {
425 3 + u16::from_le_bytes([script[pc + 1], script[pc + 2]]) as usize
426 } else {
427 1
428 }
429 }
430 0x4e => {
432 if pc + 4 < script.len() {
433 5 + u32::from_le_bytes([
434 script[pc + 1],
435 script[pc + 2],
436 script[pc + 3],
437 script[pc + 4],
438 ]) as usize
439 } else {
440 1
441 }
442 }
443 _ => 1,
444 }
445}
446
447fn tapscript_opcode_end(script: &[u8], pc: usize) -> Option<usize> {
452 let opcode = *script.get(pc)?;
453 let end = if opcode == 0 {
454 pc.checked_add(1)?
455 } else if opcode <= 0x4b {
456 pc.checked_add(1)?.checked_add(opcode as usize)?
457 } else if opcode == OP_PUSHDATA1 {
458 let len = *script.get(pc + 1)? as usize;
459 pc.checked_add(2)?.checked_add(len)?
460 } else if opcode == OP_PUSHDATA2 {
461 if pc + 2 >= script.len() {
462 return None;
463 }
464 let len = u16::from_le_bytes([script[pc + 1], script[pc + 2]]) as usize;
465 pc.checked_add(3)?.checked_add(len)?
466 } else if opcode == OP_PUSHDATA4 {
467 if pc + 4 >= script.len() {
468 return None;
469 }
470 let len = u32::from_le_bytes([
471 script[pc + 1],
472 script[pc + 2],
473 script[pc + 3],
474 script[pc + 4],
475 ]) as usize;
476 pc.checked_add(5)?.checked_add(len)?
477 } else {
478 pc.checked_add(1)?
479 };
480 (end <= script.len()).then_some(end)
481}
482
483fn push_encoding_is_minimal(opcode: u8, data: &[u8]) -> bool {
485 if data.is_empty() {
486 return opcode == OP_0;
487 }
488 if data.len() == 1 {
489 let byte = data[0];
490 if (1..=16).contains(&byte) {
491 return opcode == OP_1 + (byte - 1);
492 }
493 if byte == 0x81 {
494 return opcode == OP_1NEGATE;
495 }
496 }
497 if data.len() <= 75 {
498 return opcode == data.len() as u8;
499 }
500 if data.len() <= 255 {
501 return opcode == OP_PUSHDATA1;
502 }
503 if data.len() <= 65535 {
504 return opcode == OP_PUSHDATA2;
505 }
506 true
507}
508
509fn pop_if_condition(
513 stack: &mut Vec<StackElement>,
514 flags: u32,
515 sigversion: SigVersion,
516 minimal_message: &'static str,
517) -> Result<bool> {
518 let condition_bytes = stack.pop().unwrap();
519 let condition = cast_to_bool(&condition_bytes);
520 let enforce_minimal_if = sigversion == SigVersion::Tapscript
521 || (sigversion == SigVersion::WitnessV0 && flags & flags::SCRIPT_VERIFY_MINIMALIF != 0);
522 if enforce_minimal_if && !control_flow::is_minimal_if_condition(&condition_bytes) {
523 return Err(ConsensusError::ScriptErrorWithCode {
524 code: ScriptErrorCode::MinimalIf,
525 message: minimal_message.into(),
526 });
527 }
528 Ok(condition)
529}
530
531fn apply_data_push(
536 script: &[u8],
537 i: usize,
538 opcode: u8,
539 stack: &mut Vec<StackElement>,
540 flags: u32,
541 in_false_branch: bool,
542) -> Result<Option<usize>> {
543 let (data, advance) = if opcode <= 0x4b {
544 let len = opcode as usize;
545 if i + 1 + len > script.len() {
546 return Ok(None);
547 }
548 (&script[i + 1..i + 1 + len], 1 + len)
549 } else if opcode == OP_PUSHDATA1 {
550 if i + 1 >= script.len() {
551 return Ok(None);
552 }
553 let len = script[i + 1] as usize;
554 if i + 2 + len > script.len() {
555 return Ok(None);
556 }
557 (&script[i + 2..i + 2 + len], 2 + len)
558 } else if opcode == OP_PUSHDATA2 {
559 if i + 2 >= script.len() {
560 return Ok(None);
561 }
562 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
563 if i + 3 + len > script.len() {
564 return Ok(None);
565 }
566 (&script[i + 3..i + 3 + len], 3 + len)
567 } else {
568 if i + 4 >= script.len() {
569 return Ok(None);
570 }
571 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
572 as usize;
573 let data_start = i.saturating_add(5);
574 let data_end = data_start.saturating_add(len);
575 let advance = 5usize.saturating_add(len);
576 if advance < 5 || data_end > script.len() || data_end < data_start {
577 return Ok(None);
578 }
579 (&script[data_start..data_end], advance)
580 };
581
582 if data.len() > MAX_SCRIPT_ELEMENT_SIZE {
583 return Err(ConsensusError::ScriptErrorWithCode {
584 code: ScriptErrorCode::PushSize,
585 message: format!(
586 "Push data size {} exceeds maximum {}",
587 data.len(),
588 MAX_SCRIPT_ELEMENT_SIZE
589 )
590 .into(),
591 });
592 }
593 if !in_false_branch
594 && (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
595 && !push_encoding_is_minimal(opcode, data)
596 {
597 return Ok(None);
598 }
599 if !in_false_branch {
600 stack.push(to_stack_element(data));
601 }
602 Ok(Some(advance))
603}
604
605fn eval_script_inner(
606 script: &[u8],
607 stack: &mut Vec<StackElement>,
608 flags: u32,
609 sigversion: SigVersion,
610) -> Result<bool> {
611 use crate::constants::MAX_SCRIPT_SIZE;
612 use crate::error::{ConsensusError, ScriptErrorCode};
613
614 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
615 && script.len() > MAX_SCRIPT_SIZE
616 {
617 return Err(ConsensusError::ScriptErrorWithCode {
618 code: ScriptErrorCode::ScriptSize,
619 message: "Script size exceeds maximum".into(),
620 });
621 }
622
623 let mut op_count = 0;
624 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
625 let mut altstack: Vec<StackElement> = Vec::new();
626
627 let mut i = 0;
628 let mut finished_opcode = false;
630 while i < script.len() {
631 if finished_opcode && stack.len() + altstack.len() > MAX_STACK_SIZE {
632 return Err(make_stack_overflow_error());
633 }
634 finished_opcode = true;
635 let opcode = script[i];
636 let in_false_branch = control_flow::in_false_branch(&control_stack);
637
638 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
641 op_count += 1;
642 if op_count > MAX_SCRIPT_OPS {
643 return Err(make_operation_limit_error());
644 }
645 debug_assert!(
646 op_count <= MAX_SCRIPT_OPS,
647 "Operation count ({op_count}) must not exceed MAX_SCRIPT_OPS ({MAX_SCRIPT_OPS})"
648 );
649 }
650
651 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
653 let Some(advance) = apply_data_push(script, i, opcode, stack, flags, in_false_branch)?
654 else {
655 return Ok(false);
656 };
657 i += advance;
658 continue;
659 }
660
661 match opcode {
662 OP_IF => {
664 if in_false_branch {
665 control_stack.push(control_flow::ControlBlock::If { executing: false });
666 } else if stack.is_empty() {
667 return Err(ConsensusError::ScriptErrorWithCode {
668 code: ScriptErrorCode::InvalidStackOperation,
669 message: "OP_IF: empty stack".into(),
670 });
671 } else {
672 let condition = pop_if_condition(
673 stack,
674 flags,
675 sigversion,
676 "OP_IF condition must be minimally encoded",
677 )?;
678 control_stack.push(control_flow::ControlBlock::If {
679 executing: condition,
680 });
681 }
682 }
683 OP_NOTIF => {
685 if in_false_branch {
686 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
687 } else if stack.is_empty() {
688 return Err(ConsensusError::ScriptErrorWithCode {
689 code: ScriptErrorCode::InvalidStackOperation,
690 message: "OP_NOTIF: empty stack".into(),
691 });
692 } else {
693 let condition = pop_if_condition(
694 stack,
695 flags,
696 sigversion,
697 "OP_NOTIF condition must be minimally encoded",
698 )?;
699 control_stack.push(control_flow::ControlBlock::NotIf {
700 executing: !condition,
701 });
702 }
703 }
704 OP_ELSE => {
706 if let Some(block) = control_stack.last_mut() {
707 match block {
708 control_flow::ControlBlock::If { executing }
709 | control_flow::ControlBlock::NotIf { executing } => {
710 *executing = !*executing;
711 }
712 }
713 } else {
714 return Err(ConsensusError::ScriptErrorWithCode {
715 code: ScriptErrorCode::UnbalancedConditional,
716 message: "OP_ELSE without matching IF/NOTIF".into(),
717 });
718 }
719 }
720 OP_ENDIF => {
722 if control_stack.pop().is_none() {
723 return Err(ConsensusError::ScriptErrorWithCode {
724 code: ScriptErrorCode::UnbalancedConditional,
725 message: "OP_ENDIF without matching IF/NOTIF".into(),
726 });
727 }
728 }
729 OP_TOALTSTACK => {
731 if !in_false_branch {
732 if stack.is_empty() {
733 return Err(ConsensusError::ScriptErrorWithCode {
734 code: ScriptErrorCode::InvalidStackOperation,
735 message: "OP_TOALTSTACK: empty stack".into(),
736 });
737 }
738 altstack.push(stack.pop().unwrap());
739 }
740 }
741 OP_FROMALTSTACK => {
743 if !in_false_branch {
744 if altstack.is_empty() {
745 return Err(ConsensusError::ScriptErrorWithCode {
746 code: ScriptErrorCode::InvalidAltstackOperation,
747 message: "OP_FROMALTSTACK: empty altstack".into(),
748 });
749 }
750 stack.push(altstack.pop().unwrap());
751 }
752 }
753 _ => {
754 if in_false_branch {
755 if let Some(code) = dead_branch_opcode_error(opcode) {
756 return Err(ConsensusError::ScriptErrorWithCode {
757 code,
758 message: format!(
759 "opcode 0x{opcode:02x} is invalid in an unexecuted branch"
760 )
761 .into(),
762 });
763 }
764 i += 1;
765 continue;
766 }
767
768 if sigversion != SigVersion::Tapscript
769 && (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
770 {
771 op_count = charge_checkmultisig_pubkeys(stack, op_count)?;
772 }
773 if !execute_opcode(opcode, stack, flags, sigversion)? {
774 return Ok(false);
775 }
776 }
777 }
778 i += 1;
779 }
780
781 if finished_opcode && stack.len() + altstack.len() > MAX_STACK_SIZE {
782 return Err(make_stack_overflow_error());
783 }
784
785 if !control_stack.is_empty() {
786 return Err(ConsensusError::ScriptErrorWithCode {
787 code: ScriptErrorCode::UnbalancedConditional,
788 message: "Unclosed IF/NOTIF block".into(),
789 });
790 }
791
792 Ok(true)
793}
794
795fn apply_p2sh_redeem(
807 script_sig: &[u8],
808 script_pubkey: &[u8],
809 flags: u32,
810 sigversion: SigVersion,
811 stack: &mut Vec<StackElement>,
812) -> Result<bool> {
813 let is_p2sh = (flags & flags::SCRIPT_VERIFY_P2SH) != 0
814 && script_pubkey.len() == 23
815 && script_pubkey[0] == OP_HASH160
816 && script_pubkey[1] == PUSH_20_BYTES
817 && script_pubkey[22] == OP_EQUAL;
818 if !is_p2sh {
819 return Ok(true);
820 }
821 if stack.is_empty() || !cast_to_bool(&stack[stack.len() - 1]) {
822 return Ok(false);
823 }
824 stack.pop();
825 let Some(pushes) = parse_borrowed_pushes(script_sig) else {
826 return Ok(false);
827 };
828 let Some(redeem) = pushes.last() else {
829 return Ok(false);
830 };
831 eval_script(redeem.as_ref(), stack, flags, sigversion)
832}
833
834#[deprecated(
839 since = "0.1.33",
840 note = "Use verify_script_with_context for witness-aware script verification"
841)]
842#[cfg_attr(feature = "spec-lock", spec_locked("5.2", "VerifyScript"))]
843#[cfg_attr(feature = "production", inline(always))]
844#[cfg_attr(not(feature = "production"), inline)]
845pub fn verify_script(
846 script_sig: &ByteString,
847 script_pubkey: &[u8],
848 witness: Option<&ByteString>,
849 flags: u32,
850) -> Result<bool> {
851 if flags & flags::SCRIPT_VERIFY_P2SH != 0
853 && script_pubkey.len() == 23
854 && script_pubkey[0] == OP_HASH160
855 && script_pubkey[1] == PUSH_20_BYTES
856 && script_pubkey[22] == OP_EQUAL
857 && !p2sh_push_only_check(script_sig)
858 {
859 return Ok(false);
860 }
861
862 let sigversion = SigVersion::Base;
864
865 #[cfg(feature = "production")]
866 {
867 if !is_caching_disabled() {
869 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
870 {
871 let cache = get_script_cache().read().unwrap_or_else(|e| e.into_inner());
872 if let Some(&cached_result) = cache.peek(&cache_key) {
873 return Ok(cached_result);
874 }
875 }
876 }
877
878 let mut stack = get_pooled_stack();
881 let cache_key = compute_script_cache_key(script_sig, script_pubkey, witness, flags);
882 let result = {
883 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
884 if !is_caching_disabled() {
886 let mut cache = get_script_cache()
887 .write()
888 .unwrap_or_else(|e| e.into_inner());
889 cache.put(cache_key, false);
890 }
891 false
892 } else if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
893 if !is_caching_disabled() {
894 let mut cache = get_script_cache()
895 .write()
896 .unwrap_or_else(|e| e.into_inner());
897 cache.put(cache_key, false);
898 }
899 false
900 } else if !apply_p2sh_redeem(script_sig, script_pubkey, flags, sigversion, &mut stack)?
901 {
902 if !is_caching_disabled() {
903 let mut cache = get_script_cache()
904 .write()
905 .unwrap_or_else(|e| e.into_inner());
906 cache.put(cache_key, false);
907 }
908 false
909 } else if let Some(w) = witness {
910 if !eval_script(w, &mut stack, flags, sigversion)? {
911 if !is_caching_disabled() {
912 let mut cache = get_script_cache()
913 .write()
914 .unwrap_or_else(|e| e.into_inner());
915 cache.put(cache_key, false);
916 }
917 false
918 } else {
919 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
920 if !is_caching_disabled() {
921 let mut cache = get_script_cache()
922 .write()
923 .unwrap_or_else(|e| e.into_inner());
924 cache.put(cache_key, res);
925 }
926 res
927 }
928 } else {
929 let res = !stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]);
930 if !is_caching_disabled() {
931 let mut cache = get_script_cache()
932 .write()
933 .unwrap_or_else(|e| e.into_inner());
934 cache.put(cache_key, res);
935 }
936 res
937 }
938 };
939
940 return_pooled_stack(stack);
942
943 Ok(result)
944 }
945
946 #[cfg(not(feature = "production"))]
947 {
948 let mut stack = Vec::with_capacity(20);
950
951 if !eval_script(script_sig, &mut stack, flags, sigversion)? {
953 return Ok(false);
954 }
955
956 if !eval_script(script_pubkey, &mut stack, flags, sigversion)? {
958 return Ok(false);
959 }
960 if !apply_p2sh_redeem(script_sig, script_pubkey, flags, sigversion, &mut stack)? {
961 return Ok(false);
962 }
963
964 if let Some(w) = witness {
966 if !eval_script(w, &mut stack, flags, sigversion)? {
967 return Ok(false);
968 }
969 }
970
971 Ok(!stack.is_empty() && cast_to_bool(&stack[stack.len() - 1]))
973 }
974}
975
976#[cfg_attr(feature = "spec-lock", spec_locked("5.2", "VerifyScript"))]
989#[cfg_attr(feature = "production", inline(always))]
990#[cfg_attr(not(feature = "production"), inline)]
991#[allow(clippy::too_many_arguments)]
992pub fn verify_script_with_context(
993 script_sig: &ByteString,
994 script_pubkey: &[u8],
995 witness: Option<&crate::witness::Witness>,
996 flags: u32,
997 tx: &Transaction,
998 input_index: usize,
999 prevouts: &[TransactionOutput],
1000 block_height: Option<u64>,
1001 network: crate::types::Network,
1002) -> Result<bool> {
1003 let prevout_values: Vec<i64> = prevouts.iter().map(|p| p.value).collect();
1005 let prevout_script_pubkeys: Vec<&[u8]> =
1006 prevouts.iter().map(|p| p.script_pubkey.as_ref()).collect();
1007
1008 verify_script_with_context_full(
1009 script_sig,
1010 script_pubkey,
1011 witness,
1012 flags,
1013 tx,
1014 input_index,
1015 &prevout_values,
1016 &prevout_script_pubkeys,
1017 block_height,
1018 None, network,
1020 SigVersion::Base, #[cfg(feature = "production")]
1022 None, None, #[cfg(feature = "production")]
1025 None, #[cfg(feature = "production")]
1027 None, #[cfg(feature = "production")]
1029 None, #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
1031 None, )
1033}
1034
1035pub(crate) fn canonical_p2pk_pubkey(script: &[u8]) -> Option<&[u8]> {
1040 let key_len = match script.first().copied()? {
1041 PUSH_33_BYTES => PUSH_33_BYTES as usize,
1042 PUSH_65_BYTES => PUSH_65_BYTES as usize,
1043 _ => return None,
1044 };
1045 if script.len() != key_len + 2 || script[script.len() - 1] != OP_CHECKSIG {
1046 return None;
1047 }
1048 Some(&script[1..1 + key_len])
1049}
1050
1051#[cfg(feature = "production")]
1058#[allow(clippy::too_many_arguments)]
1059pub fn try_verify_p2pk_fast_path(
1060 script_sig: &ByteString,
1061 script_pubkey: &[u8],
1062 flags: u32,
1063 tx: &Transaction,
1064 input_index: usize,
1065 prevout_values: &[i64],
1066 prevout_script_pubkeys: &[&[u8]],
1067 block_height: Option<u64>,
1068 network: crate::types::Network,
1069 #[cfg(feature = "production")] sighash_cache: Option<
1070 &crate::transaction_hash::SighashMidstateCache,
1071 >,
1072) -> Option<Result<bool>> {
1073 let pubkey_bytes = canonical_p2pk_pubkey(script_pubkey)?;
1074
1075 let signature_bytes = parse_p2pk_script_sig(script_sig.as_ref())?;
1076 if signature_bytes.is_empty() {
1077 return Some(Ok(false));
1078 }
1079
1080 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1082 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1083 let sighash_type = SighashType::from_byte(sighash_byte);
1084 let deleted_storage;
1085 let script_code: &[u8] = if script_pubkey.len() < 71 {
1086 script_pubkey
1087 } else {
1088 deleted_storage = with_push_pattern(signature_bytes, |pattern| {
1089 find_and_delete(script_pubkey, pattern)
1090 });
1091 deleted_storage.as_ref()
1092 };
1093 let sighash = match calculate_transaction_sighash_single_input(
1094 tx,
1095 input_index,
1096 script_code,
1097 prevout_values[input_index],
1098 sighash_type,
1099 #[cfg(feature = "production")]
1100 sighash_cache,
1101 ) {
1102 Ok(h) => h,
1103 Err(e) => return Some(Err(e)),
1104 };
1105
1106 let height = block_height.unwrap_or(0);
1107 let is_valid = signature::with_secp_context(|secp| {
1108 signature::verify_signature(
1109 secp,
1110 pubkey_bytes,
1111 signature_bytes,
1112 &sighash,
1113 flags,
1114 height,
1115 network,
1116 SigVersion::Base,
1117 )
1118 });
1119 Some(is_valid)
1120}
1121
1122#[cfg(feature = "production")]
1125#[allow(clippy::too_many_arguments)]
1126pub fn try_verify_p2pkh_fast_path(
1127 script_sig: &ByteString,
1128 script_pubkey: &[u8],
1129 flags: u32,
1130 tx: &Transaction,
1131 input_index: usize,
1132 prevout_values: &[i64],
1133 prevout_script_pubkeys: &[&[u8]],
1134 block_height: Option<u64>,
1135 network: crate::types::Network,
1136 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1137 #[cfg(feature = "production")] sighash_cache: Option<
1138 &crate::transaction_hash::SighashMidstateCache,
1139 >,
1140 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
1141) -> Option<Result<bool>> {
1142 #[cfg(all(feature = "production", feature = "profile"))]
1143 let _t_entry = std::time::Instant::now();
1144 if script_pubkey.len() != 25 {
1146 return None;
1147 }
1148 if script_pubkey[0] != OP_DUP
1149 || script_pubkey[1] != OP_HASH160
1150 || script_pubkey[2] != PUSH_20_BYTES
1151 || script_pubkey[23] != OP_EQUALVERIFY
1152 || script_pubkey[24] != OP_CHECKSIG
1153 {
1154 return None;
1155 }
1156 let expected_hash = &script_pubkey[3..23];
1157
1158 #[cfg(all(feature = "production", feature = "profile"))]
1159 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t_entry.elapsed().as_nanos() as u64);
1160 #[cfg(all(feature = "production", feature = "profile"))]
1161 let _t_parse = std::time::Instant::now();
1162 let (signature_bytes, pubkey_bytes) = parse_p2pkh_script_sig(script_sig.as_ref())?;
1163 #[cfg(all(feature = "production", feature = "profile"))]
1164 crate::script_profile::add_p2pkh_parse_ns(_t_parse.elapsed().as_nanos() as u64);
1165
1166 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
1168 return Some(Ok(false));
1169 }
1170 if signature_bytes.is_empty() {
1172 return Some(Ok(false));
1173 }
1174
1175 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
1177 Some(h) => h,
1178 None => {
1179 #[cfg(all(feature = "production", feature = "profile"))]
1180 let _t_hash = std::time::Instant::now();
1181 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1182 let h = Ripemd160::digest(sha256_hash);
1183 #[cfg(all(feature = "production", feature = "profile"))]
1184 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1185 h.into()
1186 }
1187 };
1188 if &pubkey_hash[..] != expected_hash {
1189 return Some(Ok(false));
1190 }
1191
1192 use crate::transaction_hash::SighashType;
1195 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1196 let sighash_type = SighashType::from_byte(sighash_byte);
1197 let deleted_storage;
1198 let script_code: &[u8] = if script_pubkey.len() < 71 {
1199 script_pubkey
1200 } else {
1201 deleted_storage = with_push_pattern(signature_bytes, |pattern| {
1202 find_and_delete(script_pubkey, pattern)
1203 });
1204 deleted_storage.as_ref()
1205 };
1206 let sighash = {
1207 #[cfg(feature = "production")]
1208 {
1209 if let Some(precomp) = precomputed_sighash_all {
1210 precomp
1211 } else {
1212 crate::transaction_hash::compute_legacy_sighash_nocache(
1213 tx,
1214 input_index,
1215 script_code,
1216 sighash_byte,
1217 )
1218 }
1219 }
1220 #[cfg(not(feature = "production"))]
1221 {
1222 match calculate_transaction_sighash_single_input(
1223 tx,
1224 input_index,
1225 script_code,
1226 prevout_values[input_index],
1227 sighash_type,
1228 ) {
1229 Ok(h) => h,
1230 Err(e) => return Some(Err(e)),
1231 }
1232 }
1233 };
1234
1235 #[cfg(all(feature = "production", feature = "profile"))]
1236 let _t_secp = std::time::Instant::now();
1237 let height = block_height.unwrap_or(0);
1238 let is_valid: Result<bool> = {
1239 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1240 if flags & 0x04 != 0
1241 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1242 .unwrap_or(false)
1243 {
1244 Ok(false)
1245 } else if flags & 0x02 != 0 {
1246 let base_sighash = sighash_byte & !0x80;
1247 if !(0x01..=0x03).contains(&base_sighash) {
1248 Ok(false)
1249 } else if pubkey_bytes.len() == 33 {
1250 if pubkey_bytes[0] != 0x02 && pubkey_bytes[0] != 0x03 {
1251 Ok(false)
1252 } else {
1253 let strict_der = flags & 0x04 != 0;
1254 let enforce_low_s = flags & 0x08 != 0;
1255 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1256 der_sig,
1257 pubkey_bytes,
1258 &sighash,
1259 strict_der,
1260 enforce_low_s,
1261 )
1262 .unwrap_or(false))
1263 }
1264 } else if pubkey_bytes.len() == 65 && pubkey_bytes[0] == 0x04 {
1265 let strict_der = flags & 0x04 != 0;
1266 let enforce_low_s = flags & 0x08 != 0;
1267 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1268 der_sig,
1269 pubkey_bytes,
1270 &sighash,
1271 strict_der,
1272 enforce_low_s,
1273 )
1274 .unwrap_or(false))
1275 } else {
1276 Ok(false)
1277 }
1278 } else {
1279 let strict_der = flags & 0x04 != 0;
1280 let enforce_low_s = flags & 0x08 != 0;
1281 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1282 der_sig,
1283 pubkey_bytes,
1284 &sighash,
1285 strict_der,
1286 enforce_low_s,
1287 )
1288 .unwrap_or(false))
1289 }
1290 };
1291 #[cfg(all(feature = "production", feature = "profile"))]
1292 {
1293 let ns = _t_secp.elapsed().as_nanos() as u64;
1294 crate::script_profile::add_p2pkh_collect_ns(ns);
1295 crate::script_profile::add_p2pkh_secp_context_ns(ns);
1296 }
1297 Some(is_valid)
1298}
1299
1300#[cfg(feature = "production")]
1306#[inline]
1307pub fn verify_p2pkh_inline(
1308 script_sig: &[u8],
1309 script_pubkey: &[u8],
1310 flags: u32,
1311 tx: &Transaction,
1312 input_index: usize,
1313 height: u64,
1314 network: crate::types::Network,
1315 precomputed_sighash_all: Option<[u8; 32]>,
1316 precomputed_p2pkh_hash: Option<[u8; 20]>,
1317 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
1318 &crate::ecdsa_batch::EcdsaSignatureCollector,
1319 usize,
1320 )>,
1321) -> Result<bool> {
1322 let (signature_bytes, pubkey_bytes) = match parse_p2pkh_script_sig(script_sig) {
1323 Some(pair) => pair,
1324 None => return Ok(false),
1325 };
1326 verify_p2pkh_inline_parsed(
1327 signature_bytes,
1328 pubkey_bytes,
1329 script_pubkey,
1330 flags,
1331 tx,
1332 input_index,
1333 height,
1334 network,
1335 precomputed_sighash_all,
1336 precomputed_p2pkh_hash,
1337 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
1338 ecdsa_collect,
1339 )
1340}
1341
1342#[cfg(feature = "production")]
1345#[inline]
1346pub fn verify_p2pkh_inline_parsed(
1347 signature_bytes: &[u8],
1348 pubkey_bytes: &[u8],
1349 script_pubkey: &[u8],
1350 flags: u32,
1351 tx: &Transaction,
1352 input_index: usize,
1353 height: u64,
1354 network: crate::types::Network,
1355 precomputed_sighash_all: Option<[u8; 32]>,
1356 precomputed_p2pkh_hash: Option<[u8; 20]>,
1357 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
1358 &crate::ecdsa_batch::EcdsaSignatureCollector,
1359 usize,
1360 )>,
1361) -> Result<bool> {
1362 #[cfg(feature = "profile")]
1363 let _t0 = std::time::Instant::now();
1364
1365 let expected_hash = &script_pubkey[3..23];
1366
1367 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
1368 return Ok(false);
1369 }
1370
1371 #[cfg(feature = "profile")]
1372 let _t_hash = std::time::Instant::now();
1373
1374 let pubkey_hash: [u8; 20] = match precomputed_p2pkh_hash {
1375 Some(h) => h,
1376 None => {
1377 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
1378 Ripemd160::digest(sha256_hash).into()
1379 }
1380 };
1381 if &pubkey_hash[..] != expected_hash {
1382 return Ok(false);
1383 }
1384
1385 #[cfg(feature = "profile")]
1386 crate::script_profile::add_p2pkh_hash160_ns(_t_hash.elapsed().as_nanos() as u64);
1387
1388 #[cfg(feature = "profile")]
1389 let _t_sighash = std::time::Instant::now();
1390
1391 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1392 let sighash = if let Some(precomp) = precomputed_sighash_all {
1393 precomp
1394 } else {
1395 crate::transaction_hash::compute_legacy_sighash_nocache(
1397 tx,
1398 input_index,
1399 script_pubkey,
1400 sighash_byte,
1401 )
1402 };
1403
1404 #[cfg(feature = "profile")]
1405 crate::script_profile::add_sighash_ns(_t_sighash.elapsed().as_nanos() as u64);
1406
1407 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1408 let strict_der = flags & 0x04 != 0;
1409 let enforce_low_s = flags & 0x08 != 0;
1410
1411 if strict_der
1412 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1413 .unwrap_or(false)
1414 {
1415 return Ok(false);
1416 }
1417
1418 crate::script::signature::reject_strictenc(flags, sighash_byte, pubkey_bytes)?;
1419
1420 #[cfg(feature = "profile")]
1421 let _t_secp = std::time::Instant::now();
1422
1423 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
1424 if let Some((collector, global_idx)) = ecdsa_collect {
1425 let compact =
1427 match blvm_secp256k1::ecdsa::ecdsa_der_to_compact(der_sig, strict_der, enforce_low_s) {
1428 Some(c) => c,
1429 None => return Ok(false),
1430 };
1431 let pk33 = match pubkey_bytes.len() {
1432 33 => {
1433 let mut a = [0u8; 33];
1434 a.copy_from_slice(pubkey_bytes);
1435 a
1436 }
1437 65 => match blvm_secp256k1::ecdsa::ge_from_pubkey_bytes(pubkey_bytes) {
1438 Some(ge) => blvm_secp256k1::ecdsa::ge_to_compressed(&ge),
1439 None => return Ok(false),
1440 },
1441 _ => return Ok(false),
1442 };
1443 #[cfg(feature = "profile")]
1444 {
1445 crate::script_profile::add_p2pkh_collect_ns(_t_secp.elapsed().as_nanos() as u64);
1446 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1447 }
1448 collector.collect_with_index(global_idx, &sighash, &pk33, &compact);
1449 return Ok(true);
1450 }
1451
1452 let result = crate::secp256k1_backend::verify_ecdsa_direct(
1453 der_sig,
1454 pubkey_bytes,
1455 &sighash,
1456 strict_der,
1457 enforce_low_s,
1458 )
1459 .unwrap_or(false);
1460
1461 #[cfg(feature = "profile")]
1462 crate::script_profile::add_p2pkh_secp_context_ns(_t_secp.elapsed().as_nanos() as u64);
1463
1464 #[cfg(feature = "profile")]
1465 crate::script_profile::add_p2pkh_fast_path_entry_ns(_t0.elapsed().as_nanos() as u64);
1466
1467 Ok(result)
1468}
1469
1470#[cfg(feature = "production")]
1472#[inline]
1473pub fn verify_p2pk_inline(
1474 script_sig: &[u8],
1475 script_pubkey: &[u8],
1476 flags: u32,
1477 tx: &Transaction,
1478 input_index: usize,
1479 height: u64,
1480 network: crate::types::Network,
1481 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
1482 &crate::ecdsa_batch::EcdsaSignatureCollector,
1483 usize,
1484 )>,
1485) -> Result<bool> {
1486 let Some(pubkey_bytes) = canonical_p2pk_pubkey(script_pubkey) else {
1487 return Ok(false);
1488 };
1489
1490 let signature_bytes = match parse_p2pk_script_sig(script_sig) {
1491 Some(s) => s,
1492 None => return Ok(false),
1493 };
1494 if signature_bytes.is_empty() {
1495 return Ok(false);
1496 }
1497
1498 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1499 let script_code: &[u8] = script_pubkey; let sighash = crate::transaction_hash::compute_legacy_sighash_nocache(
1502 tx,
1503 input_index,
1504 script_code,
1505 sighash_byte,
1506 );
1507
1508 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1509 let strict_der = flags & flags::SCRIPT_VERIFY_DERSIG != 0;
1510 let enforce_low_s = flags & flags::SCRIPT_VERIFY_LOW_S != 0;
1511
1512 if strict_der
1513 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1514 .unwrap_or(false)
1515 {
1516 return Ok(false);
1517 }
1518
1519 crate::script::signature::reject_strictenc(flags, sighash_byte, pubkey_bytes)?;
1520
1521 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
1522 if let Some((collector, global_idx)) = ecdsa_collect {
1523 let compact =
1524 match blvm_secp256k1::ecdsa::ecdsa_der_to_compact(der_sig, strict_der, enforce_low_s) {
1525 Some(c) => c,
1526 None => return Ok(false),
1527 };
1528 let pk33 = match pubkey_bytes.len() {
1529 33 => {
1530 let mut a = [0u8; 33];
1531 a.copy_from_slice(pubkey_bytes);
1532 a
1533 }
1534 65 => match blvm_secp256k1::ecdsa::ge_from_pubkey_bytes(pubkey_bytes) {
1535 Some(ge) => blvm_secp256k1::ecdsa::ge_to_compressed(&ge),
1536 None => return Ok(false),
1537 },
1538 _ => return Ok(false),
1539 };
1540 collector.collect_with_index(global_idx, &sighash, &pk33, &compact);
1541 return Ok(true);
1542 }
1543
1544 Ok(crate::secp256k1_backend::verify_ecdsa_direct(
1545 der_sig,
1546 pubkey_bytes,
1547 &sighash,
1548 strict_der,
1549 enforce_low_s,
1550 )
1551 .unwrap_or(false))
1552}
1553
1554fn failed_multisig_nullfail(flags: u32, success: bool, any_nonempty_signature: bool) -> Result<()> {
1556 if !success && flags & flags::SCRIPT_VERIFY_NULLFAIL != 0 && any_nonempty_signature {
1557 return Err(ConsensusError::ScriptErrorWithCode {
1558 code: ScriptErrorCode::SigNullFail,
1559 message: "OP_CHECKMULTISIG: non-null signature must not fail under NULLFAIL".into(),
1560 });
1561 }
1562 Ok(())
1563}
1564
1565#[allow(clippy::too_many_arguments)]
1569fn try_verify_p2sh_multisig_fast_path(
1570 script_sig: &ByteString,
1571 script_pubkey: &[u8],
1572 flags: u32,
1573 tx: &Transaction,
1574 input_index: usize,
1575 prevout_values: &[i64],
1576 prevout_script_pubkeys: &[&[u8]],
1577 block_height: Option<u64>,
1578 network: crate::types::Network,
1579 #[cfg(feature = "production")] sighash_cache: Option<
1580 &crate::transaction_hash::SighashMidstateCache,
1581 >,
1582 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collector: Option<
1583 &crate::ecdsa_batch::EcdsaSignatureCollector,
1584 >,
1585) -> Option<Result<bool>> {
1586 let _ = prevout_script_pubkeys;
1587 if script_pubkey.len() != 23
1589 || script_pubkey[0] != OP_HASH160
1590 || script_pubkey[1] != PUSH_20_BYTES
1591 || script_pubkey[22] != OP_EQUAL
1592 {
1593 return None;
1594 }
1595 let pushes = parse_borrowed_pushes(script_sig.as_ref())?;
1596 if pushes.len() < 2 {
1597 return None;
1598 }
1599 let redeem = pushes.last().expect("at least 2 pushes").as_ref();
1600 let expected_hash = &script_pubkey[2..22];
1601 let sha256_hash = OptimizedSha256::new().hash(redeem);
1602 let redeem_hash = Ripemd160::digest(sha256_hash);
1603 if &redeem_hash[..] != expected_hash {
1604 return Some(Ok(false));
1605 }
1606 let (m, _n, pubkeys) = parse_redeem_multisig(redeem)?;
1607 let stack = &pushes[..pushes.len() - 1];
1609 let Some((dummy, signatures)) = checkmultisig_window(stack, m, false) else {
1610 return Some(Ok(false));
1611 };
1612
1613 let height = block_height.unwrap_or(0);
1614 if (flags & flags::SCRIPT_VERIFY_NULLDUMMY) != 0 && !dummy.is_empty() {
1615 return Some(Ok(false));
1616 }
1617
1618 let cleaned = multisig_script_code(redeem, &signatures);
1619
1620 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1621
1622 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
1624 if let Some(collector) = ecdsa_collector {
1625 let nullfail = (flags & flags::SCRIPT_VERIFY_NULLFAIL) != 0;
1626 let enforce_low_s = (flags & flags::SCRIPT_VERIFY_LOW_S) != 0;
1627 let strict_der = (flags & flags::SCRIPT_VERIFY_DERSIG) != 0
1628 || (flags & flags::SCRIPT_VERIFY_STRICTENC) != 0
1629 || (flags & flags::SCRIPT_VERIFY_LOW_S) != 0;
1630 let mut trial_indices = Vec::new();
1631 let mut sig_empty = Vec::with_capacity(signatures.len());
1632 let mut sighash_by_type: Vec<(u8, [u8; 32])> = Vec::new();
1634 for sig_bytes in &signatures {
1635 if sig_bytes.is_empty() {
1636 sig_empty.push(true);
1637 continue;
1638 }
1639 sig_empty.push(false);
1640 let sighash_byte = sig_bytes[sig_bytes.len() - 1];
1641 let sighash =
1642 if let Some((_, h)) = sighash_by_type.iter().find(|(b, _)| *b == sighash_byte) {
1643 *h
1644 } else {
1645 let sighash_type = SighashType::from_byte(sighash_byte);
1646 let h = match calculate_transaction_sighash_single_input(
1647 tx,
1648 input_index,
1649 &cleaned,
1650 prevout_values[input_index],
1651 sighash_type,
1652 sighash_cache,
1653 ) {
1654 Ok(h) => h,
1655 Err(e) => return Some(Err(e)),
1656 };
1657 sighash_by_type.push((sighash_byte, h));
1658 h
1659 };
1660 let der_sig = &sig_bytes[..sig_bytes.len() - 1];
1661 let compact =
1664 blvm_secp256k1::ecdsa::ecdsa_der_to_compact(der_sig, strict_der, enforce_low_s);
1665 for pubkey_bytes in &pubkeys {
1666 let gidx = collector.alloc_multisig_trial_index();
1667 trial_indices.push(gidx);
1668 let Some(compact) = compact.as_ref() else {
1669 continue;
1671 };
1672 let pk33 = match pubkey_bytes.len() {
1675 33 => {
1676 let mut a = [0u8; 33];
1677 a.copy_from_slice(pubkey_bytes);
1678 a
1679 }
1680 65 => match blvm_secp256k1::ecdsa::ge_from_pubkey_bytes(pubkey_bytes) {
1681 Some(ge) => blvm_secp256k1::ecdsa::ge_to_compressed(&ge),
1682 None => continue,
1683 },
1684 _ => continue,
1685 };
1686 collector.collect_with_index(gidx, &sighash, &pk33, compact);
1687 }
1688 }
1689 collector.push_multisig_pending(crate::ecdsa_batch::MultisigPending {
1690 m,
1691 n_pubs: pubkeys.len(),
1692 trial_indices,
1693 sig_empty,
1694 nullfail,
1695 });
1696 #[cfg(feature = "profile")]
1697 crate::script_profile::note_arm_p2sh_multisig(0);
1698 return Some(Ok(true));
1699 }
1700
1701 let mut sig_index = 0;
1702 let mut valid_sigs = 0u8;
1703
1704 for pubkey_bytes in pubkeys {
1705 if sig_index >= signatures.len() {
1706 break;
1707 }
1708 if signatures[sig_index].is_empty() {
1709 continue;
1710 }
1711 let signature_bytes = &signatures[sig_index];
1712 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1713 let sighash_type = SighashType::from_byte(sighash_byte);
1714 let sighash = match calculate_transaction_sighash_single_input(
1715 tx,
1716 input_index,
1717 &cleaned,
1718 prevout_values[input_index],
1719 sighash_type,
1720 #[cfg(feature = "production")]
1721 sighash_cache,
1722 ) {
1723 Ok(h) => h,
1724 Err(e) => return Some(Err(e)),
1725 };
1726
1727 #[cfg(feature = "production")]
1728 let is_valid = signature::with_secp_context(|secp| {
1729 signature::verify_signature(
1730 secp,
1731 pubkey_bytes,
1732 signature_bytes,
1733 &sighash,
1734 flags,
1735 height,
1736 network,
1737 SigVersion::Base,
1738 )
1739 });
1740
1741 #[cfg(not(feature = "production"))]
1742 let is_valid = {
1743 let secp = signature::new_secp();
1744 signature::verify_signature(
1745 &secp,
1746 pubkey_bytes,
1747 signature_bytes,
1748 &sighash,
1749 flags,
1750 height,
1751 network,
1752 SigVersion::Base,
1753 )
1754 };
1755
1756 let is_valid = match is_valid {
1757 Ok(v) => v,
1758 Err(e) => return Some(Err(e)),
1759 };
1760
1761 if is_valid {
1762 valid_sigs += 1;
1763 sig_index += 1;
1764 }
1765 }
1766
1767 let success = signatures.len() == usize::from(m) && valid_sigs == m;
1768 if let Err(e) =
1769 failed_multisig_nullfail(flags, success, signatures.iter().any(|sig| !sig.is_empty()))
1770 {
1771 return Some(Err(e));
1772 }
1773 Some(Ok(success))
1774}
1775
1776#[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
1778#[allow(clippy::too_many_arguments)]
1779pub(crate) fn try_verify_p2sh_multisig_ibd(
1780 script_sig: &ByteString,
1781 script_pubkey: &[u8],
1782 flags: u32,
1783 tx: &Transaction,
1784 input_index: usize,
1785 prevout_values: &[i64],
1786 prevout_script_pubkeys: &[&[u8]],
1787 block_height: Option<u64>,
1788 network: crate::types::Network,
1789 sighash_cache: Option<&crate::transaction_hash::SighashMidstateCache>,
1790 ecdsa_collector: Option<&crate::ecdsa_batch::EcdsaSignatureCollector>,
1791) -> Option<Result<bool>> {
1792 try_verify_p2sh_multisig_fast_path(
1793 script_sig,
1794 script_pubkey,
1795 flags,
1796 tx,
1797 input_index,
1798 prevout_values,
1799 prevout_script_pubkeys,
1800 block_height,
1801 network,
1802 sighash_cache,
1803 ecdsa_collector,
1804 )
1805}
1806
1807#[allow(clippy::too_many_arguments)]
1810fn try_verify_bare_multisig_fast_path(
1811 script_sig: &ByteString,
1812 script_pubkey: &[u8],
1813 flags: u32,
1814 tx: &Transaction,
1815 input_index: usize,
1816 prevout_values: &[i64],
1817 prevout_script_pubkeys: &[&[u8]],
1818 block_height: Option<u64>,
1819 network: crate::types::Network,
1820 #[cfg(feature = "production")] sighash_cache: Option<
1821 &crate::transaction_hash::SighashMidstateCache,
1822 >,
1823) -> Option<Result<bool>> {
1824 let (m, _n, pubkeys) = parse_redeem_multisig(script_pubkey)?;
1825 let pushes = parse_borrowed_pushes(script_sig.as_ref())?;
1826 let Some((dummy, signatures)) = checkmultisig_window(&pushes, m, false) else {
1827 return Some(Ok(false));
1828 };
1829
1830 let height = block_height.unwrap_or(0);
1831 if (flags & flags::SCRIPT_VERIFY_NULLDUMMY) != 0 && !dummy.is_empty() {
1832 return Some(Ok(false));
1833 }
1834
1835 let cleaned = multisig_script_code(script_pubkey, &signatures);
1836
1837 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1838
1839 let mut sig_index = 0;
1840 let mut valid_sigs = 0u8;
1841
1842 for pubkey_bytes in pubkeys {
1843 if sig_index >= signatures.len() {
1844 break;
1845 }
1846 if signatures[sig_index].is_empty() {
1847 continue;
1848 }
1849 let signature_bytes = &signatures[sig_index];
1850 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1851 let sighash_type = SighashType::from_byte(sighash_byte);
1852 let sighash = match calculate_transaction_sighash_single_input(
1853 tx,
1854 input_index,
1855 &cleaned,
1856 prevout_values[input_index],
1857 sighash_type,
1858 #[cfg(feature = "production")]
1859 sighash_cache,
1860 ) {
1861 Ok(h) => h,
1862 Err(e) => return Some(Err(e)),
1863 };
1864
1865 #[cfg(feature = "production")]
1866 let is_valid = signature::with_secp_context(|secp| {
1867 signature::verify_signature(
1868 secp,
1869 pubkey_bytes,
1870 signature_bytes,
1871 &sighash,
1872 flags,
1873 height,
1874 network,
1875 SigVersion::Base,
1876 )
1877 });
1878
1879 #[cfg(not(feature = "production"))]
1880 let is_valid = {
1881 let secp = signature::new_secp();
1882 signature::verify_signature(
1883 &secp,
1884 pubkey_bytes,
1885 signature_bytes,
1886 &sighash,
1887 flags,
1888 height,
1889 network,
1890 SigVersion::Base,
1891 )
1892 };
1893
1894 let is_valid = match is_valid {
1895 Ok(v) => v,
1896 Err(e) => return Some(Err(e)),
1897 };
1898
1899 if is_valid {
1900 valid_sigs += 1;
1901 sig_index += 1;
1902 }
1903 }
1904
1905 let success = signatures.len() == usize::from(m) && valid_sigs == m;
1906 if let Err(e) =
1907 failed_multisig_nullfail(flags, success, signatures.iter().any(|sig| !sig.is_empty()))
1908 {
1909 return Some(Err(e));
1910 }
1911 Some(Ok(success))
1912}
1913
1914#[cfg(feature = "production")]
1916#[allow(clippy::too_many_arguments)]
1917fn verify_p2sh_p2pkh_redeem(
1918 signature_bytes: &[u8],
1919 pubkey_bytes: &[u8],
1920 redeem: &[u8],
1921 flags: u32,
1922 tx: &Transaction,
1923 input_index: usize,
1924 prevout_values: &[i64],
1925 block_height: Option<u64>,
1926 network: crate::types::Network,
1927 #[cfg(feature = "production")] sighash_cache: Option<
1928 &crate::transaction_hash::SighashMidstateCache,
1929 >,
1930 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
1931 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
1932 &crate::ecdsa_batch::EcdsaSignatureCollector,
1933 usize,
1934 )>,
1935) -> Result<bool> {
1936 #[cfg(feature = "production")]
1937 let sighash = if let Some(precomp) = precomputed_sighash_all {
1938 precomp
1939 } else {
1940 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1941 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1942 let sighash_type = SighashType::from_byte(sighash_byte);
1943 let deleted_storage;
1944 let script_code: &[u8] = if redeem.len() < 71 {
1945 redeem
1946 } else {
1947 deleted_storage =
1948 with_push_pattern(signature_bytes, |pattern| find_and_delete(redeem, pattern));
1949 deleted_storage.as_ref()
1950 };
1951 calculate_transaction_sighash_single_input(
1952 tx,
1953 input_index,
1954 script_code,
1955 prevout_values[input_index],
1956 sighash_type,
1957 sighash_cache,
1958 )?
1959 };
1960 #[cfg(not(feature = "production"))]
1961 let sighash = {
1962 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
1963 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
1964 let sighash_type = SighashType::from_byte(sighash_byte);
1965 let deleted_storage;
1966 let script_code: &[u8] = if redeem.len() < 71 {
1967 redeem
1968 } else {
1969 deleted_storage =
1970 with_push_pattern(signature_bytes, |pattern| find_and_delete(redeem, pattern));
1971 deleted_storage.as_ref()
1972 };
1973 calculate_transaction_sighash_single_input(
1974 tx,
1975 input_index,
1976 script_code,
1977 prevout_values[input_index],
1978 sighash_type,
1979 )?
1980 };
1981 let height = block_height.unwrap_or(0);
1982 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
1983 let strict_der = flags & 0x04 != 0;
1984 let enforce_low_s = flags & 0x08 != 0;
1985 if strict_der
1986 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
1987 .unwrap_or(false)
1988 {
1989 return Ok(false);
1990 }
1991 crate::script::signature::reject_strictenc(
1992 flags,
1993 signature_bytes[signature_bytes.len() - 1],
1994 pubkey_bytes,
1995 )?;
1996 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
1997 if let Some((collector, global_idx)) = ecdsa_collect {
1998 if std::env::var_os("BLVM_P2SH_P2PKH_SOA").is_none_or(|v| v != "0") {
2000 let compact = match blvm_secp256k1::ecdsa::ecdsa_der_to_compact(
2001 der_sig,
2002 strict_der,
2003 enforce_low_s,
2004 ) {
2005 Some(c) => c,
2006 None => return Ok(false),
2007 };
2008 let pk33 = match pubkey_bytes.len() {
2009 33 => {
2010 let mut a = [0u8; 33];
2011 a.copy_from_slice(pubkey_bytes);
2012 a
2013 }
2014 65 => match blvm_secp256k1::ecdsa::ge_from_pubkey_bytes(pubkey_bytes) {
2015 Some(ge) => blvm_secp256k1::ecdsa::ge_to_compressed(&ge),
2016 None => return Ok(false),
2017 },
2018 _ => return Ok(false),
2019 };
2020 collector.collect_with_index(global_idx, &sighash, &pk33, &compact);
2021 return Ok(true);
2022 }
2023 }
2024 signature::with_secp_context(|secp| {
2025 signature::verify_signature(
2026 secp,
2027 pubkey_bytes,
2028 signature_bytes,
2029 &sighash,
2030 flags,
2031 height,
2032 network,
2033 SigVersion::Base,
2034 )
2035 })
2036}
2037
2038#[cfg(feature = "production")]
2040#[allow(clippy::too_many_arguments)]
2041fn verify_p2sh_p2pk_redeem(
2042 signature_bytes: &[u8],
2043 pubkey_bytes: &[u8],
2044 redeem: &[u8],
2045 flags: u32,
2046 tx: &Transaction,
2047 input_index: usize,
2048 prevout_values: &[i64],
2049 block_height: Option<u64>,
2050 network: crate::types::Network,
2051 #[cfg(feature = "production")] sighash_cache: Option<
2052 &crate::transaction_hash::SighashMidstateCache,
2053 >,
2054) -> Result<bool> {
2055 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
2056 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2057 let sighash_type = SighashType::from_byte(sighash_byte);
2058 let deleted_storage;
2060 let script_code: &[u8] = if redeem.len() < 71 {
2061 redeem
2062 } else {
2063 deleted_storage =
2064 with_push_pattern(signature_bytes, |pattern| find_and_delete(redeem, pattern));
2065 deleted_storage.as_ref()
2066 };
2067 let sighash = calculate_transaction_sighash_single_input(
2068 tx,
2069 input_index,
2070 script_code,
2071 prevout_values[input_index],
2072 sighash_type,
2073 #[cfg(feature = "production")]
2074 sighash_cache,
2075 )?;
2076 let height = block_height.unwrap_or(0);
2077 signature::with_secp_context(|secp| {
2078 signature::verify_signature(
2079 secp,
2080 pubkey_bytes,
2081 signature_bytes,
2082 &sighash,
2083 flags,
2084 height,
2085 network,
2086 SigVersion::Base,
2087 )
2088 })
2089}
2090
2091#[cfg(feature = "production")]
2095#[allow(clippy::too_many_arguments)]
2096fn try_verify_p2sh_fast_path(
2097 script_sig: &ByteString,
2098 script_pubkey: &[u8],
2099 flags: u32,
2100 tx: &Transaction,
2101 input_index: usize,
2102 prevout_values: &[i64],
2103 prevout_script_pubkeys: &[&[u8]],
2104 block_height: Option<u64>,
2105 median_time_past: Option<u64>,
2106 network: crate::types::Network,
2107 #[cfg(feature = "production")] sighash_cache: Option<
2108 &crate::transaction_hash::SighashMidstateCache,
2109 >,
2110 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2111 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2112 &crate::ecdsa_batch::EcdsaSignatureCollector,
2113 usize,
2114 )>,
2115) -> Option<Result<bool>> {
2116 if (flags & flags::SCRIPT_VERIFY_P2SH) == 0 {
2117 return None;
2118 }
2119 if script_pubkey.len() != 23
2121 || script_pubkey[0] != OP_HASH160
2122 || script_pubkey[1] != PUSH_20_BYTES
2123 || script_pubkey[22] != OP_EQUAL
2124 {
2125 return None;
2126 }
2127 let expected_hash = &script_pubkey[2..22];
2128
2129 if let Some((signature_bytes, pubkey_bytes, redeem)) =
2132 parse_p2sh_p2pkh_pushes(script_sig.as_ref())
2133 {
2134 let redeem_sha = OptimizedSha256::new().hash(redeem);
2135 let redeem_hash = Ripemd160::digest(redeem_sha);
2136 if &redeem_hash[..] != expected_hash {
2137 return Some(Ok(false));
2138 }
2139 if pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65 {
2140 let pubkey_sha = OptimizedSha256::new().hash(pubkey_bytes);
2141 let pubkey_hash = Ripemd160::digest(pubkey_sha);
2142 if pubkey_hash[..] == redeem[3..23] {
2143 return Some(verify_p2sh_p2pkh_redeem(
2144 signature_bytes,
2145 pubkey_bytes,
2146 redeem,
2147 flags,
2148 tx,
2149 input_index,
2150 prevout_values,
2151 block_height,
2152 network,
2153 #[cfg(feature = "production")]
2154 sighash_cache,
2155 #[cfg(feature = "production")]
2156 precomputed_sighash_all,
2157 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2158 ecdsa_collect,
2159 ));
2160 }
2161 }
2162 }
2163
2164 if let Some((signature_bytes, pubkey_bytes, redeem)) =
2166 parse_p2sh_p2pk_pushes(script_sig.as_ref())
2167 {
2168 let redeem_sha = OptimizedSha256::new().hash(redeem);
2169 let redeem_hash = Ripemd160::digest(redeem_sha);
2170 if &redeem_hash[..] != expected_hash {
2171 return Some(Ok(false));
2172 }
2173 return Some(verify_p2sh_p2pk_redeem(
2174 signature_bytes,
2175 pubkey_bytes,
2176 redeem,
2177 flags,
2178 tx,
2179 input_index,
2180 prevout_values,
2181 block_height,
2182 network,
2183 #[cfg(feature = "production")]
2184 sighash_cache,
2185 ));
2186 }
2187
2188 let pushes = parse_borrowed_pushes(script_sig.as_ref())?;
2191 if pushes.is_empty() {
2192 return None;
2193 }
2194 let redeem = pushes.last().expect("at least one push").as_ref();
2195 let mut stack: Vec<StackElement> = pushes[..pushes.len() - 1]
2196 .iter()
2197 .map(|push| to_stack_element(push.as_ref()))
2198 .collect();
2199
2200 if crate::witness::is_any_witness_program(redeem) {
2205 return None;
2206 }
2207
2208 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
2210 let redeem_hash = Ripemd160::digest(sha256_hash);
2211 if &redeem_hash[..] != expected_hash {
2212 return Some(Ok(false));
2213 }
2214
2215 if redeem.len() == 25
2217 && redeem[0] == OP_DUP
2218 && redeem[1] == OP_HASH160
2219 && redeem[2] == PUSH_20_BYTES
2220 && redeem[23] == OP_EQUALVERIFY
2221 && redeem[24] == OP_CHECKSIG
2222 && stack.len() == 2
2223 {
2224 let signature_bytes = &stack[0];
2225 let pubkey_bytes = &stack[1];
2226 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2227 let expected_pubkey_hash = &redeem[3..23];
2228 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
2229 let pubkey_hash = Ripemd160::digest(sha256_hash);
2230 if &pubkey_hash[..] == expected_pubkey_hash {
2231 return Some(verify_p2sh_p2pkh_redeem(
2232 signature_bytes,
2233 pubkey_bytes,
2234 redeem,
2235 flags,
2236 tx,
2237 input_index,
2238 prevout_values,
2239 block_height,
2240 network,
2241 #[cfg(feature = "production")]
2242 sighash_cache,
2243 #[cfg(feature = "production")]
2244 precomputed_sighash_all,
2245 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2246 ecdsa_collect,
2247 ));
2248 }
2249 }
2250 }
2251
2252 if stack.len() == 1 {
2254 if let Some(pubkey_bytes) = canonical_p2pk_pubkey(redeem) {
2255 let signature_bytes = &stack[0];
2256 if !signature_bytes.is_empty() {
2257 return Some(verify_p2sh_p2pk_redeem(
2258 signature_bytes,
2259 pubkey_bytes,
2260 redeem,
2261 flags,
2262 tx,
2263 input_index,
2264 prevout_values,
2265 block_height,
2266 network,
2267 #[cfg(feature = "production")]
2268 sighash_cache,
2269 ));
2270 }
2271 }
2272 }
2273
2274 let result = eval_script_with_context_full_inner(
2276 redeem,
2277 &mut stack,
2278 flags,
2279 tx,
2280 input_index,
2281 prevout_values,
2282 prevout_script_pubkeys,
2283 block_height,
2284 median_time_past,
2285 network,
2286 SigVersion::Base,
2287 Some(redeem),
2288 Some(script_sig), None, None, #[cfg(feature = "production")]
2292 None, None, #[cfg(feature = "production")]
2295 sighash_cache,
2296 );
2297 let result = match result {
2301 Ok(true) => {
2302 let top_true = !stack.is_empty() && cast_to_bool(stack.last().expect("redeem stack"));
2303 let ok = if flags & flags::SCRIPT_VERIFY_CLEANSTACK != 0 {
2304 stack.len() == 1 && top_true
2305 } else {
2306 top_true
2307 };
2308 Ok(ok)
2309 }
2310 other => other,
2311 };
2312 Some(result)
2313}
2314
2315#[cfg(feature = "production")]
2320fn finish_p2wpkh_ecdsa(
2321 signature_bytes: &[u8],
2322 pubkey_bytes: &[u8],
2323 sighash: &[u8; 32],
2324 flags: u32,
2325 height: u64,
2326 network: crate::types::Network,
2327 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2328 &crate::ecdsa_batch::EcdsaSignatureCollector,
2329 usize,
2330 )>,
2331) -> Result<bool> {
2332 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
2333 let strict_der = flags & 0x04 != 0;
2334 let enforce_low_s = flags & 0x08 != 0;
2335 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2336
2337 if strict_der
2338 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
2339 .unwrap_or(false)
2340 {
2341 return Ok(false);
2342 }
2343
2344 crate::script::signature::reject_strictenc(flags, sighash_byte, pubkey_bytes)?;
2345
2346 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2347 if let Some((collector, global_idx)) = ecdsa_collect {
2348 if std::env::var_os("BLVM_P2WPKH_SOA").is_none_or(|v| v != "0") {
2349 let compact = match blvm_secp256k1::ecdsa::ecdsa_der_to_compact(
2350 der_sig,
2351 strict_der,
2352 enforce_low_s,
2353 ) {
2354 Some(c) => c,
2355 None => return Ok(false),
2356 };
2357 let pk33 = match pubkey_bytes.len() {
2358 33 => {
2359 let mut a = [0u8; 33];
2360 a.copy_from_slice(pubkey_bytes);
2361 a
2362 }
2363 65 => match blvm_secp256k1::ecdsa::ge_from_pubkey_bytes(pubkey_bytes) {
2364 Some(ge) => blvm_secp256k1::ecdsa::ge_to_compressed(&ge),
2365 None => return Ok(false),
2366 },
2367 _ => return Ok(false),
2368 };
2369 collector.collect_with_index(global_idx, sighash, &pk33, &compact);
2370 return Ok(true);
2371 }
2372 }
2373
2374 Ok(signature::with_secp_context(|secp| {
2375 signature::verify_signature(
2376 secp,
2377 pubkey_bytes,
2378 signature_bytes,
2379 sighash,
2380 flags,
2381 height,
2382 network,
2383 SigVersion::WitnessV0,
2384 )
2385 })
2386 .unwrap_or(false))
2387}
2388
2389#[cfg(feature = "production")]
2391#[allow(clippy::too_many_arguments)]
2392#[inline]
2393pub fn verify_p2wpkh_inline(
2394 witness: &crate::witness::Witness,
2395 script_pubkey: &[u8],
2396 flags: u32,
2397 tx: &Transaction,
2398 input_index: usize,
2399 prevout_value: i64,
2400 height: u64,
2401 network: crate::types::Network,
2402 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2403 precomputed_sighash_all: Option<[u8; 32]>,
2404 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2405 &crate::ecdsa_batch::EcdsaSignatureCollector,
2406 usize,
2407 )>,
2408) -> Result<bool> {
2409 let signature_bytes = &witness[0];
2410 let pubkey_bytes = &witness[1];
2411 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
2412 return Ok(false);
2413 }
2414
2415 let expected_hash = &script_pubkey[2..22];
2416 let sha256_hash = OptimizedSha256::new().hash(pubkey_bytes);
2417 let pubkey_hash = Ripemd160::digest(sha256_hash);
2418 if &pubkey_hash[..] != expected_hash {
2419 return Ok(false);
2420 }
2421
2422 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_hash);
2423 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2424 let sighash = if sighash_byte == 0x01 {
2425 if let Some(precomp) = precomputed_sighash_all {
2426 precomp
2427 } else {
2428 crate::transaction_hash::calculate_bip143_sighash(
2429 tx,
2430 input_index,
2431 &p2pkh_script_code,
2432 prevout_value,
2433 sighash_byte,
2434 precomputed_bip143,
2435 )?
2436 }
2437 } else {
2438 crate::transaction_hash::calculate_bip143_sighash(
2439 tx,
2440 input_index,
2441 &p2pkh_script_code,
2442 prevout_value,
2443 sighash_byte,
2444 precomputed_bip143,
2445 )?
2446 };
2447
2448 finish_p2wpkh_ecdsa(
2449 signature_bytes,
2450 pubkey_bytes,
2451 &sighash,
2452 flags,
2453 height,
2454 network,
2455 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2456 ecdsa_collect,
2457 )
2458}
2459
2460#[cfg(feature = "production")]
2462#[inline(always)]
2463fn single_data_push(script: &[u8]) -> Option<&[u8]> {
2464 let (advance, start, end) = parse_one_data_push(script, 0)?;
2465 if advance != script.len() {
2466 return None;
2467 }
2468 Some(&script[start..end])
2469}
2470
2471#[cfg(feature = "production")]
2473#[allow(clippy::too_many_arguments)]
2474#[inline]
2475pub fn verify_p2wpkh_in_p2sh_inline(
2476 script_sig: &[u8],
2477 witness: &crate::witness::Witness,
2478 script_pubkey: &[u8],
2479 flags: u32,
2480 tx: &Transaction,
2481 input_index: usize,
2482 prevout_value: i64,
2483 height: u64,
2484 network: crate::types::Network,
2485 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2486 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2487 &crate::ecdsa_batch::EcdsaSignatureCollector,
2488 usize,
2489 )>,
2490) -> Result<bool> {
2491 let expected_hash = &script_pubkey[2..22];
2492 let Some(redeem) = single_data_push(script_sig) else {
2493 return Ok(false);
2494 };
2495 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
2496 return Ok(false);
2497 }
2498 if !redeem_push_is_canonical(script_sig, redeem) {
2499 return Ok(false);
2500 }
2501 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
2502 let redeem_hash = Ripemd160::digest(sha256_hash);
2503 if &redeem_hash[..] != expected_hash {
2504 return Ok(false);
2505 }
2506
2507 if witness.len() != 2 {
2508 return Ok(false);
2509 }
2510 let signature_bytes = &witness[0];
2511 let pubkey_bytes = &witness[1];
2512 if (pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65) || signature_bytes.is_empty() {
2513 return Ok(false);
2514 }
2515 let expected_pubkey_hash = &redeem[2..22];
2516 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2517 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2518 if &pubkey_hash[..] != expected_pubkey_hash {
2519 return Ok(false);
2520 }
2521
2522 let p2pkh_script_code = bip143_p2wpkh_script_code(expected_pubkey_hash);
2523 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2524 let sighash = crate::transaction_hash::calculate_bip143_sighash(
2525 tx,
2526 input_index,
2527 &p2pkh_script_code,
2528 prevout_value,
2529 sighash_byte,
2530 precomputed_bip143,
2531 )?;
2532
2533 finish_p2wpkh_ecdsa(
2534 signature_bytes,
2535 pubkey_bytes,
2536 &sighash,
2537 flags,
2538 height,
2539 network,
2540 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2541 ecdsa_collect,
2542 )
2543}
2544
2545#[cfg(feature = "production")]
2548#[allow(clippy::too_many_arguments)]
2549fn try_verify_p2wpkh_fast_path(
2550 script_sig: &ByteString,
2551 script_pubkey: &[u8],
2552 witness: &crate::witness::Witness,
2553 flags: u32,
2554 tx: &Transaction,
2555 input_index: usize,
2556 prevout_values: &[i64],
2557 prevout_script_pubkeys: &[&[u8]],
2558 block_height: Option<u64>,
2559 network: crate::types::Network,
2560 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2561 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
2562 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2563 &crate::ecdsa_batch::EcdsaSignatureCollector,
2564 usize,
2565 )>,
2566) -> Option<Result<bool>> {
2567 let _ = prevout_script_pubkeys;
2568 if flags & crate::script::flags::SCRIPT_VERIFY_WITNESS == 0 {
2569 return None;
2570 }
2571 if script_pubkey.len() != 22 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_20_BYTES {
2573 return None;
2574 }
2575 if !script_sig.is_empty() {
2577 return None;
2578 }
2579 if witness.len() != 2 {
2580 return None;
2581 }
2582 let height = block_height.unwrap_or(0);
2583 let prevout_value = prevout_values.get(input_index).copied().unwrap_or(0);
2584 Some(verify_p2wpkh_inline(
2585 witness,
2586 script_pubkey,
2587 flags,
2588 tx,
2589 input_index,
2590 prevout_value,
2591 height,
2592 network,
2593 precomputed_bip143,
2594 precomputed_sighash_all,
2595 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2596 ecdsa_collect,
2597 ))
2598}
2599
2600#[cfg(feature = "production")]
2602#[allow(clippy::too_many_arguments)]
2603fn try_verify_p2wpkh_in_p2sh_fast_path(
2604 script_sig: &ByteString,
2605 script_pubkey: &[u8],
2606 witness: &crate::witness::Witness,
2607 flags: u32,
2608 tx: &Transaction,
2609 input_index: usize,
2610 prevout_values: &[i64],
2611 prevout_script_pubkeys: &[&[u8]],
2612 block_height: Option<u64>,
2613 network: crate::types::Network,
2614 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2615 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2616 &crate::ecdsa_batch::EcdsaSignatureCollector,
2617 usize,
2618 )>,
2619) -> Option<Result<bool>> {
2620 let _ = prevout_script_pubkeys;
2621 if flags & crate::script::flags::SCRIPT_VERIFY_WITNESS == 0 {
2622 return None;
2623 }
2624 if (flags & flags::SCRIPT_VERIFY_P2SH) == 0 {
2625 return None;
2626 }
2627 if script_pubkey.len() != 23
2628 || script_pubkey[0] != OP_HASH160
2629 || script_pubkey[1] != PUSH_20_BYTES
2630 || script_pubkey[22] != OP_EQUAL
2631 {
2632 return None;
2633 }
2634 if witness.len() != 2 {
2638 return None;
2639 }
2640 let redeem = single_data_push(script_sig.as_ref())?;
2641 if redeem.len() != 22 || redeem[0] != OP_0 || redeem[1] != PUSH_20_BYTES {
2642 return None;
2643 }
2644 if !redeem_push_is_canonical(script_sig.as_ref(), redeem) {
2645 return Some(Ok(false));
2646 }
2647 let height = block_height.unwrap_or(0);
2648 let prevout_value = prevout_values.get(input_index).copied().unwrap_or(0);
2649 Some(verify_p2wpkh_in_p2sh_inline(
2650 script_sig.as_ref(),
2651 witness,
2652 script_pubkey,
2653 flags,
2654 tx,
2655 input_index,
2656 prevout_value,
2657 height,
2658 network,
2659 precomputed_bip143,
2660 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2661 ecdsa_collect,
2662 ))
2663}
2664
2665#[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2668fn try_collect_witness_ecdsa(
2669 collector: &crate::ecdsa_batch::EcdsaSignatureCollector,
2670 global_idx: usize,
2671 signature_bytes: &[u8],
2672 pubkey_bytes: &[u8],
2673 sighash: &[u8; 32],
2674 flags: u32,
2675 height: u64,
2676 network: crate::types::Network,
2677) -> Option<Result<bool>> {
2678 if std::env::var_os("BLVM_P2WPKH_SOA").is_some_and(|v| v == "0") {
2679 return None;
2680 }
2681 let der_sig = &signature_bytes[..signature_bytes.len() - 1];
2682 let strict_der = flags & 0x04 != 0;
2683 let enforce_low_s = flags & 0x08 != 0;
2684 if strict_der
2685 && !crate::bip_validation::check_bip66_network(signature_bytes, height, network)
2686 .unwrap_or(false)
2687 {
2688 return Some(Ok(false));
2689 }
2690 if let Err(err) = crate::script::signature::reject_strictenc(
2691 flags,
2692 signature_bytes[signature_bytes.len() - 1],
2693 pubkey_bytes,
2694 ) {
2695 return Some(Err(err));
2696 }
2697 let compact =
2698 match blvm_secp256k1::ecdsa::ecdsa_der_to_compact(der_sig, strict_der, enforce_low_s) {
2699 Some(c) => c,
2700 None => return Some(Ok(false)),
2701 };
2702 let pk33 = match pubkey_bytes.len() {
2703 33 => {
2704 let mut a = [0u8; 33];
2705 a.copy_from_slice(pubkey_bytes);
2706 a
2707 }
2708 65 => match blvm_secp256k1::ecdsa::ge_from_pubkey_bytes(pubkey_bytes) {
2709 Some(ge) => blvm_secp256k1::ecdsa::ge_to_compressed(&ge),
2710 None => return Some(Ok(false)),
2711 },
2712 _ => return Some(Ok(false)),
2713 };
2714 collector.collect_with_index(global_idx, sighash, &pk33, &compact);
2715 Some(Ok(true))
2716}
2717
2718#[cfg(feature = "production")]
2721#[allow(clippy::too_many_arguments)]
2722pub(crate) fn try_verify_p2wsh_in_p2sh_fast_path(
2723 script_sig: &ByteString,
2724 script_pubkey: &[u8],
2725 witness: &crate::witness::Witness,
2726 flags: u32,
2727 tx: &Transaction,
2728 input_index: usize,
2729 prevout_values: &[i64],
2730 prevout_script_pubkeys: &[&[u8]],
2731 block_height: Option<u64>,
2732 median_time_past: Option<u64>,
2733 network: crate::types::Network,
2734 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2735 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2736 #[cfg(feature = "production")] sighash_cache: Option<
2737 &crate::transaction_hash::SighashMidstateCache,
2738 >,
2739 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2740 &crate::ecdsa_batch::EcdsaSignatureCollector,
2741 usize,
2742 )>,
2743) -> Option<Result<bool>> {
2744 if flags & crate::script::flags::SCRIPT_VERIFY_WITNESS == 0 {
2745 return None;
2746 }
2747 if (flags & flags::SCRIPT_VERIFY_P2SH) == 0 {
2748 return None;
2749 }
2750 if script_pubkey.len() != 23
2751 || script_pubkey[0] != OP_HASH160
2752 || script_pubkey[1] != PUSH_20_BYTES
2753 || script_pubkey[22] != OP_EQUAL
2754 {
2755 return None;
2756 }
2757 let redeem = single_data_push(script_sig.as_ref())?;
2758 if redeem.len() != 34 || redeem[0] != OP_0 || redeem[1] != PUSH_32_BYTES {
2759 return None;
2760 }
2761 if !redeem_push_is_canonical(script_sig.as_ref(), redeem) {
2762 return Some(Ok(false));
2763 }
2764 let expected_hash = &script_pubkey[2..22];
2765 let sha256_hash = OptimizedSha256::new().hash(redeem.as_ref());
2766 let redeem_hash = Ripemd160::digest(sha256_hash);
2767 if &redeem_hash[..] != expected_hash {
2768 return Some(Ok(false));
2769 }
2770 try_verify_p2wsh_fast_path(
2772 &[],
2773 redeem,
2774 witness,
2775 flags,
2776 tx,
2777 input_index,
2778 prevout_values,
2779 prevout_script_pubkeys,
2780 block_height,
2781 median_time_past,
2782 network,
2783 schnorr_collector,
2784 precomputed_bip143,
2785 #[cfg(feature = "production")]
2786 sighash_cache,
2787 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2788 ecdsa_collect,
2789 )
2790}
2791
2792#[cfg(feature = "production")]
2795#[allow(clippy::too_many_arguments)]
2796pub(crate) fn try_verify_p2wsh_fast_path(
2797 script_sig: &[u8],
2798 script_pubkey: &[u8],
2799 witness: &crate::witness::Witness,
2800 flags: u32,
2801 tx: &Transaction,
2802 input_index: usize,
2803 prevout_values: &[i64],
2804 prevout_script_pubkeys: &[&[u8]],
2805 block_height: Option<u64>,
2806 median_time_past: Option<u64>,
2807 network: crate::types::Network,
2808 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
2809 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
2810 #[cfg(feature = "production")] sighash_cache: Option<
2811 &crate::transaction_hash::SighashMidstateCache,
2812 >,
2813 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
2814 &crate::ecdsa_batch::EcdsaSignatureCollector,
2815 usize,
2816 )>,
2817) -> Option<Result<bool>> {
2818 if flags & crate::script::flags::SCRIPT_VERIFY_WITNESS == 0 {
2819 return None;
2820 }
2821 if script_pubkey.len() != 34 || script_pubkey[0] != OP_0 || script_pubkey[1] != PUSH_32_BYTES {
2823 return None;
2824 }
2825 if !script_sig.is_empty() {
2826 return None;
2827 }
2828 if witness.is_empty() {
2829 return None;
2830 }
2831 let max_witness_elem = MAX_SCRIPT_ELEMENT_SIZE;
2832 for element in witness.iter().take(witness.len().saturating_sub(1)) {
2833 if element.len() > max_witness_elem {
2834 return Some(Ok(false));
2835 }
2836 }
2837 let witness_script: &[u8] = witness.last().expect("witness not empty").as_ref();
2839 let program_hash = &script_pubkey[2..34];
2840 let witness_script_hash = OptimizedSha256::new().hash(witness_script);
2841 if &witness_script_hash[..] != program_hash {
2842 return Some(Ok(false));
2843 }
2844
2845 let witness_sigversion = SigVersion::WitnessV0;
2849
2850 if witness_sigversion == SigVersion::WitnessV0
2852 && witness_script.len() == 25
2853 && witness_script[0] == OP_DUP
2854 && witness_script[1] == OP_HASH160
2855 && witness_script[2] == PUSH_20_BYTES
2856 && witness_script[23] == OP_EQUALVERIFY
2857 && witness_script[24] == OP_CHECKSIG
2858 && witness.len() == 3
2859 {
2860 let signature_bytes: &[u8] = witness[0].as_ref();
2861 let pubkey_bytes: &[u8] = witness[1].as_ref();
2862 if (pubkey_bytes.len() == 33 || pubkey_bytes.len() == 65) && !signature_bytes.is_empty() {
2863 let expected_pubkey_hash = &witness_script[3..23];
2864 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
2865 let pubkey_hash = Ripemd160::digest(pubkey_sha256);
2866 if &pubkey_hash[..] == expected_pubkey_hash {
2867 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2868 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2869 match crate::transaction_hash::calculate_bip143_sighash(
2870 tx,
2871 input_index,
2872 witness_script,
2873 amount,
2874 sighash_byte,
2875 precomputed_bip143,
2876 ) {
2877 Ok(sighash) => {
2878 let height = block_height.unwrap_or(0);
2879 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2880 if let Some((collector, global_idx)) = ecdsa_collect {
2881 if let Some(verdict) = try_collect_witness_ecdsa(
2882 collector,
2883 global_idx,
2884 signature_bytes,
2885 pubkey_bytes,
2886 &sighash,
2887 flags,
2888 height,
2889 network,
2890 ) {
2891 return Some(verdict);
2892 }
2893 }
2894 let is_valid = signature::with_secp_context(|secp| {
2895 signature::verify_signature(
2896 secp,
2897 pubkey_bytes,
2898 signature_bytes,
2899 &sighash,
2900 flags,
2901 height,
2902 network,
2903 SigVersion::WitnessV0,
2904 )
2905 });
2906 return Some(is_valid);
2907 }
2908 Err(e) => return Some(Err(e)),
2909 }
2910 }
2911 }
2912 }
2913
2914 if witness_sigversion == SigVersion::WitnessV0 && witness.len() == 2 {
2916 if let Some(pubkey_bytes) = canonical_p2pk_pubkey(witness_script) {
2917 let signature_bytes: &[u8] = witness[0].as_ref();
2918 if !signature_bytes.is_empty() {
2919 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
2920 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2921 match crate::transaction_hash::calculate_bip143_sighash(
2922 tx,
2923 input_index,
2924 witness_script,
2925 amount,
2926 sighash_byte,
2927 precomputed_bip143,
2928 ) {
2929 Ok(sighash) => {
2930 let height = block_height.unwrap_or(0);
2931 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2932 if let Some((collector, global_idx)) = ecdsa_collect {
2933 if let Some(verdict) = try_collect_witness_ecdsa(
2934 collector,
2935 global_idx,
2936 signature_bytes,
2937 pubkey_bytes,
2938 &sighash,
2939 flags,
2940 height,
2941 network,
2942 ) {
2943 return Some(verdict);
2944 }
2945 }
2946 let is_valid = signature::with_secp_context(|secp| {
2947 signature::verify_signature(
2948 secp,
2949 pubkey_bytes,
2950 signature_bytes,
2951 &sighash,
2952 flags,
2953 height,
2954 network,
2955 SigVersion::WitnessV0,
2956 )
2957 });
2958 return Some(is_valid);
2959 }
2960 Err(e) => return Some(Err(e)),
2961 }
2962 }
2963 }
2964 }
2965
2966 if witness_sigversion == SigVersion::WitnessV0 {
2970 if let Some((m, _n, pubkeys)) = parse_redeem_multisig(witness_script) {
2971 let items = &witness[..witness.len() - 1];
2972 let Some((dummy, signatures)) = checkmultisig_window(items, m, true) else {
2973 return Some(Ok(false));
2974 };
2975
2976 let height = block_height.unwrap_or(0);
2977 if (flags & flags::SCRIPT_VERIFY_NULLDUMMY) != 0 && !dummy.is_empty() {
2978 return Some(Ok(false));
2979 }
2980
2981 let script_code = witness_script;
2983 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
2984
2985 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
2987 if let Some((collector, _)) = ecdsa_collect {
2988 let nullfail = (flags & flags::SCRIPT_VERIFY_NULLFAIL) != 0;
2989 let enforce_low_s = (flags & flags::SCRIPT_VERIFY_LOW_S) != 0;
2990 let strict_der = (flags & flags::SCRIPT_VERIFY_DERSIG) != 0
2991 || (flags & flags::SCRIPT_VERIFY_STRICTENC) != 0
2992 || (flags & flags::SCRIPT_VERIFY_LOW_S) != 0;
2993 let mut trial_indices = Vec::new();
2994 let mut sig_empty = Vec::with_capacity(signatures.len());
2995 let mut sighash_by_type: Vec<(u8, [u8; 32])> = Vec::new();
2997 for sig_bytes in &signatures {
2998 if sig_bytes.is_empty() {
2999 sig_empty.push(true);
3000 continue;
3001 }
3002 sig_empty.push(false);
3003 let sighash_byte = sig_bytes[sig_bytes.len() - 1];
3004 let sighash = if let Some((_, h)) =
3005 sighash_by_type.iter().find(|(b, _)| *b == sighash_byte)
3006 {
3007 *h
3008 } else {
3009 let h = match crate::transaction_hash::calculate_bip143_sighash(
3010 tx,
3011 input_index,
3012 script_code,
3013 amount,
3014 sighash_byte,
3015 precomputed_bip143,
3016 ) {
3017 Ok(h) => h,
3018 Err(e) => return Some(Err(e)),
3019 };
3020 sighash_by_type.push((sighash_byte, h));
3021 h
3022 };
3023 let der_sig = &sig_bytes[..sig_bytes.len() - 1];
3024 let compact = blvm_secp256k1::ecdsa::ecdsa_der_to_compact(
3025 der_sig,
3026 strict_der,
3027 enforce_low_s,
3028 );
3029 for pubkey_bytes in &pubkeys {
3030 let gidx = collector.alloc_multisig_trial_index();
3031 trial_indices.push(gidx);
3032 let Some(compact) = compact.as_ref() else {
3033 continue;
3034 };
3035 let pk33 = match pubkey_bytes.len() {
3036 33 => {
3037 let mut a = [0u8; 33];
3038 a.copy_from_slice(pubkey_bytes);
3039 a
3040 }
3041 65 => match blvm_secp256k1::ecdsa::ge_from_pubkey_bytes(pubkey_bytes) {
3042 Some(ge) => blvm_secp256k1::ecdsa::ge_to_compressed(&ge),
3043 None => continue,
3044 },
3045 _ => continue,
3046 };
3047 collector.collect_with_index(gidx, &sighash, &pk33, compact);
3048 }
3049 }
3050 collector.push_multisig_pending(crate::ecdsa_batch::MultisigPending {
3051 m,
3052 n_pubs: pubkeys.len(),
3053 trial_indices,
3054 sig_empty,
3055 nullfail,
3056 });
3057 #[cfg(feature = "profile")]
3058 crate::script_profile::note_arm_p2sh_multisig(0);
3059 return Some(Ok(true));
3060 }
3061
3062 let mut sig_index = 0;
3063 let mut valid_sigs = 0u8;
3064
3065 for pubkey_bytes in pubkeys.iter().rev() {
3068 if sig_index >= signatures.len() {
3069 break;
3070 }
3071 let signature_bytes = &signatures[signatures.len() - 1 - sig_index];
3072 if signature_bytes.is_empty() {
3073 continue;
3074 }
3075 if flags & crate::script::flags::SCRIPT_VERIFY_WITNESS_PUBKEYTYPE != 0
3076 && !(pubkey_bytes.len() == 33
3077 && (pubkey_bytes[0] == 0x02 || pubkey_bytes[0] == 0x03))
3078 {
3079 return Some(Err(ConsensusError::ScriptErrorWithCode {
3080 code: ScriptErrorCode::WitnessPubkeyType,
3081 message: "witness v0 public key must be compressed".into(),
3082 }));
3083 }
3084 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
3085 match crate::transaction_hash::calculate_bip143_sighash(
3086 tx,
3087 input_index,
3088 script_code,
3089 amount,
3090 sighash_byte,
3091 precomputed_bip143,
3092 ) {
3093 Ok(sighash) => {
3094 let is_valid = signature::with_secp_context(|secp| {
3095 signature::verify_signature(
3096 secp,
3097 pubkey_bytes,
3098 signature_bytes,
3099 &sighash,
3100 flags,
3101 height,
3102 network,
3103 SigVersion::WitnessV0,
3104 )
3105 });
3106 match is_valid {
3107 Ok(v) if v => {
3108 valid_sigs += 1;
3109 sig_index += 1;
3110 }
3111 Ok(_) => {}
3112 Err(e) => return Some(Err(e)),
3113 }
3114 }
3115 Err(e) => return Some(Err(e)),
3116 }
3117 }
3118
3119 let success = signatures.len() == usize::from(m) && valid_sigs == m;
3120 if let Err(e) = failed_multisig_nullfail(
3121 flags,
3122 success,
3123 signatures.iter().any(|sig| !sig.is_empty()),
3124 ) {
3125 return Some(Err(e));
3126 }
3127 return Some(Ok(success));
3128 }
3129 }
3130
3131 let mut stack: Vec<StackElement> = witness
3134 .iter()
3135 .take(witness.len() - 1)
3136 .map(|w| to_stack_element(w))
3137 .collect();
3138 let result = eval_script_with_context_full_inner(
3139 witness_script,
3140 &mut stack,
3141 flags,
3142 tx,
3143 input_index,
3144 prevout_values,
3145 prevout_script_pubkeys,
3146 block_height,
3147 median_time_past,
3148 network,
3149 witness_sigversion,
3150 Some(witness_script), None, None, None, schnorr_collector,
3155 precomputed_bip143,
3156 #[cfg(feature = "production")]
3157 sighash_cache,
3158 );
3159 Some(result)
3160}
3161
3162#[cfg(feature = "production")]
3164#[allow(clippy::too_many_arguments)]
3165fn try_verify_p2tr_scriptpath_p2pk_fast_path(
3166 script_sig: &ByteString,
3167 script_pubkey: &[u8],
3168 witness: &crate::witness::Witness,
3169 _flags: u32,
3170 tx: &Transaction,
3171 input_index: usize,
3172 prevout_values: &[i64],
3173 prevout_script_pubkeys: &[&[u8]],
3174 block_height: Option<u64>,
3175 network: crate::types::Network,
3176 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
3177) -> Option<Result<bool>> {
3178 use crate::activation::taproot_active_at_height;
3179 use crate::taproot::parse_taproot_script_path_witness;
3180
3181 if !taproot_active_at_height(block_height, network) {
3182 return None;
3183 }
3184 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
3185 return None;
3186 }
3187 if !script_sig.is_empty() {
3188 return None;
3189 }
3190 if witness.len() < 2 {
3191 return None;
3192 }
3193 let mut output_key = [0u8; 32];
3194 output_key.copy_from_slice(&script_pubkey[2..34]);
3195 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
3196 let parsed = match parse_taproot_script_path_witness(&witness_body, &output_key) {
3197 Ok(Some(p)) => p,
3198 Ok(None) | Err(_) => return None,
3199 };
3200 let (tapscript, stack_items, control_block) = parsed;
3201 if control_block.leaf_version != crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT {
3202 return None;
3203 }
3204 if tapscript.len() != 34 || tapscript[0] != PUSH_32_BYTES || tapscript[33] != OP_CHECKSIG {
3205 return None;
3206 }
3207 if stack_items.len() != 1 {
3208 return None;
3209 }
3210 let (sig_bytes, sighash_type) =
3211 crate::bip348::try_parse_taproot_schnorr_witness_sig(stack_items[0].as_ref())?;
3212 let pubkey_32 = &tapscript[1..33];
3213 let sighash = crate::taproot::compute_tapscript_signature_hash(
3214 tx,
3215 input_index,
3216 prevout_values,
3217 prevout_script_pubkeys,
3218 &tapscript,
3219 control_block.leaf_version,
3220 0xffff_ffff,
3221 sighash_type,
3222 annex_hash.as_ref(),
3223 )
3224 .ok()?;
3225 let result = crate::bip348::verify_tapscript_schnorr_signature(
3226 &sighash,
3227 pubkey_32,
3228 &sig_bytes,
3229 schnorr_collector,
3230 );
3231 Some(result)
3232}
3233
3234fn parse_taproot_keypath_sig(sig_bytes: &[u8]) -> Option<([u8; 64], u8)> {
3236 match sig_bytes.len() {
3237 64 => {
3238 let mut sig = [0u8; 64];
3239 sig.copy_from_slice(sig_bytes);
3240 Some((sig, 0x00))
3241 }
3242 65 => {
3243 let hashtype = sig_bytes[64];
3244 if hashtype == 0x00 {
3245 return None;
3246 }
3247 let mut sig = [0u8; 64];
3248 sig.copy_from_slice(&sig_bytes[..64]);
3249 Some((sig, hashtype))
3250 }
3251 _ => None,
3252 }
3253}
3254
3255#[cfg(feature = "production")]
3258#[allow(clippy::too_many_arguments)]
3259fn verify_p2tr_keypath_witness(
3260 script_pubkey: &[u8],
3261 witness: &crate::witness::Witness,
3262 tx: &Transaction,
3263 input_index: usize,
3264 prevout_values: &[i64],
3265 prevout_script_pubkeys: &[&[u8]],
3266 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
3267) -> Result<bool> {
3268 use crate::bip348::{
3269 try_parse_taproot_schnorr_witness_sig, verify_tapscript_schnorr_signature,
3270 };
3271
3272 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness);
3273 if witness_body.len() != 1 {
3274 return Ok(false);
3275 }
3276 let Some((sig_bytes, sighash_type)) = try_parse_taproot_schnorr_witness_sig(&witness_body[0])
3277 else {
3278 return Ok(false);
3279 };
3280 let output_key = &script_pubkey[2..34];
3281 let sighash = crate::taproot::compute_taproot_signature_hash(
3282 tx,
3283 input_index,
3284 prevout_values,
3285 prevout_script_pubkeys,
3286 sighash_type,
3287 annex_hash.as_ref(),
3288 )?;
3289 verify_tapscript_schnorr_signature(&sighash, output_key, &sig_bytes, schnorr_collector)
3290}
3291
3292#[cfg(feature = "production")]
3293#[allow(clippy::too_many_arguments)]
3294fn try_verify_p2tr_keypath_fast_path(
3295 script_sig: &ByteString,
3296 script_pubkey: &[u8],
3297 witness: &crate::witness::Witness,
3298 _flags: u32,
3299 tx: &Transaction,
3300 input_index: usize,
3301 prevout_values: &[i64],
3302 prevout_script_pubkeys: &[&[u8]],
3303 block_height: Option<u64>,
3304 network: crate::types::Network,
3305 schnorr_collector: Option<&crate::bip348::SchnorrSignatureCollector>,
3306) -> Option<Result<bool>> {
3307 use crate::activation::taproot_active_at_height;
3308 if !taproot_active_at_height(block_height, network) {
3309 return None;
3310 }
3311 if script_pubkey.len() != 34 || script_pubkey[0] != OP_1 || script_pubkey[1] != PUSH_32_BYTES {
3313 return None;
3314 }
3315 if !script_sig.is_empty() {
3316 return None;
3317 }
3318 let (witness_body, _) = crate::taproot::strip_taproot_annex(witness);
3320 if witness_body.len() != 1 {
3321 return None;
3322 }
3323 crate::bip348::try_parse_taproot_schnorr_witness_sig(&witness_body[0])?;
3324 Some(verify_p2tr_keypath_witness(
3325 script_pubkey,
3326 witness,
3327 tx,
3328 input_index,
3329 prevout_values,
3330 prevout_script_pubkeys,
3331 schnorr_collector,
3332 ))
3333}
3334
3335#[cfg_attr(feature = "spec-lock", spec_locked("5.2", "VerifyScript"))]
3336pub fn verify_script_with_context_full(
3337 script_sig: &ByteString,
3338 script_pubkey: &[u8],
3339 witness: Option<&crate::witness::Witness>,
3340 flags: u32,
3341 tx: &Transaction,
3342 input_index: usize,
3343 prevout_values: &[i64],
3344 prevout_script_pubkeys: &[&[u8]],
3345 block_height: Option<u64>,
3346 median_time_past: Option<u64>,
3347 network: crate::types::Network,
3348 _sigversion: SigVersion,
3349 #[cfg(feature = "production")] schnorr_collector: Option<
3350 &crate::bip348::SchnorrSignatureCollector,
3351 >,
3352 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
3353 #[cfg(feature = "production")] precomputed_sighash_all: Option<[u8; 32]>,
3354 #[cfg(feature = "production")] sighash_cache: Option<
3355 &crate::transaction_hash::SighashMidstateCache,
3356 >,
3357 #[cfg(feature = "production")] precomputed_p2pkh_hash: Option<[u8; 20]>,
3358 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))] ecdsa_collect: Option<(
3359 &crate::ecdsa_batch::EcdsaSignatureCollector,
3360 usize,
3361 )>,
3362) -> Result<bool> {
3363 if prevout_values.len() != tx.inputs.len() || prevout_script_pubkeys.len() != tx.inputs.len() {
3365 return Err(ConsensusError::ScriptErrorWithCode {
3366 code: ScriptErrorCode::TxInputInvalid,
3367 message: format!(
3368 "Prevout slices: values={}, script_pubkeys={}, input_count={} (input_idx={})",
3369 prevout_values.len(),
3370 prevout_script_pubkeys.len(),
3371 tx.inputs.len(),
3372 input_index,
3373 )
3374 .into(),
3375 });
3376 }
3377
3378 if input_index < prevout_values.len() {
3384 let prevout_value = prevout_values[input_index];
3385 if prevout_value < 0 {
3386 return Err(ConsensusError::ScriptErrorWithCode {
3387 code: ScriptErrorCode::ValueOverflow,
3388 message: "Prevout value cannot be negative".into(),
3389 });
3390 }
3391 #[cfg(feature = "production")]
3392 {
3393 use precomputed_constants::MAX_MONEY_U64;
3394 if (prevout_value as u64) > MAX_MONEY_U64 {
3395 return Err(ConsensusError::ScriptErrorWithCode {
3396 code: ScriptErrorCode::ValueOverflow,
3397 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
3398 });
3399 }
3400 }
3401 #[cfg(not(feature = "production"))]
3402 {
3403 use crate::constants::MAX_MONEY;
3404 if prevout_value > MAX_MONEY {
3405 return Err(ConsensusError::ScriptErrorWithCode {
3406 code: ScriptErrorCode::ValueOverflow,
3407 message: format!("Prevout value {prevout_value} exceeds MAX_MONEY").into(),
3408 });
3409 }
3410 }
3411 }
3412
3413 if input_index >= tx.inputs.len() {
3415 return Err(ConsensusError::ScriptErrorWithCode {
3416 code: ScriptErrorCode::TxInputInvalid,
3417 message: format!(
3418 "Input index {} out of bounds (tx has {} inputs)",
3419 input_index,
3420 tx.inputs.len()
3421 )
3422 .into(),
3423 });
3424 }
3425
3426 #[cfg(feature = "production")]
3428 if !fast_paths_disabled() && witness.is_none() {
3429 if let Some(result) = try_verify_p2pk_fast_path(
3430 script_sig,
3431 script_pubkey,
3432 flags,
3433 tx,
3434 input_index,
3435 prevout_values,
3436 prevout_script_pubkeys,
3437 block_height,
3438 network,
3439 #[cfg(feature = "production")]
3440 sighash_cache,
3441 ) {
3442 FAST_PATH_P2PK.fetch_add(1, Ordering::Relaxed);
3443 return result;
3444 }
3445 if let Some(result) = try_verify_p2pkh_fast_path(
3446 script_sig,
3447 script_pubkey,
3448 flags,
3449 tx,
3450 input_index,
3451 prevout_values,
3452 prevout_script_pubkeys,
3453 block_height,
3454 network,
3455 #[cfg(feature = "production")]
3456 precomputed_sighash_all,
3457 #[cfg(feature = "production")]
3458 sighash_cache,
3459 #[cfg(feature = "production")]
3460 precomputed_p2pkh_hash,
3461 ) {
3462 FAST_PATH_P2PKH.fetch_add(1, Ordering::Relaxed);
3463 return result;
3464 }
3465 if let Some(result) = try_verify_p2sh_fast_path(
3466 script_sig,
3467 script_pubkey,
3468 flags,
3469 tx,
3470 input_index,
3471 prevout_values,
3472 prevout_script_pubkeys,
3473 block_height,
3474 median_time_past,
3475 network,
3476 #[cfg(feature = "production")]
3477 sighash_cache,
3478 #[cfg(feature = "production")]
3479 precomputed_sighash_all,
3480 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
3481 ecdsa_collect,
3482 ) {
3483 FAST_PATH_P2SH.fetch_add(1, Ordering::Relaxed);
3484 return result;
3485 }
3486 if let Some(result) = try_verify_bare_multisig_fast_path(
3487 script_sig,
3488 script_pubkey,
3489 flags,
3490 tx,
3491 input_index,
3492 prevout_values,
3493 prevout_script_pubkeys,
3494 block_height,
3495 network,
3496 #[cfg(feature = "production")]
3497 sighash_cache,
3498 ) {
3499 FAST_PATH_BARE_MULTISIG.fetch_add(1, Ordering::Relaxed);
3500 return result;
3501 }
3502 }
3503 #[cfg(feature = "production")]
3505 if !fast_paths_disabled() {
3506 if let Some(wit) = witness {
3507 if let Some(result) = try_verify_p2wpkh_in_p2sh_fast_path(
3508 script_sig,
3509 script_pubkey,
3510 wit,
3511 flags,
3512 tx,
3513 input_index,
3514 prevout_values,
3515 prevout_script_pubkeys,
3516 block_height,
3517 network,
3518 precomputed_bip143,
3519 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
3520 ecdsa_collect,
3521 ) {
3522 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
3523 return result;
3524 }
3525 if let Some(result) = try_verify_p2wsh_in_p2sh_fast_path(
3526 script_sig,
3527 script_pubkey,
3528 wit,
3529 flags,
3530 tx,
3531 input_index,
3532 prevout_values,
3533 prevout_script_pubkeys,
3534 block_height,
3535 median_time_past,
3536 network,
3537 schnorr_collector,
3538 precomputed_bip143,
3539 #[cfg(feature = "production")]
3540 sighash_cache,
3541 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
3542 ecdsa_collect,
3543 ) {
3544 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
3545 return result;
3546 }
3547 if let Some(result) = try_verify_p2wpkh_fast_path(
3548 script_sig,
3549 script_pubkey,
3550 wit,
3551 flags,
3552 tx,
3553 input_index,
3554 prevout_values,
3555 prevout_script_pubkeys,
3556 block_height,
3557 network,
3558 precomputed_bip143,
3559 precomputed_sighash_all,
3560 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
3561 ecdsa_collect,
3562 ) {
3563 FAST_PATH_P2WPKH.fetch_add(1, Ordering::Relaxed);
3564 return result;
3565 }
3566 if let Some(result) = try_verify_p2wsh_fast_path(
3567 script_sig,
3568 script_pubkey,
3569 wit,
3570 flags,
3571 tx,
3572 input_index,
3573 prevout_values,
3574 prevout_script_pubkeys,
3575 block_height,
3576 median_time_past,
3577 network,
3578 schnorr_collector,
3579 precomputed_bip143,
3580 #[cfg(feature = "production")]
3581 sighash_cache,
3582 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
3583 ecdsa_collect,
3584 ) {
3585 FAST_PATH_P2WSH.fetch_add(1, Ordering::Relaxed);
3586 return result;
3587 }
3588 if let Some(result) = try_verify_p2tr_scriptpath_p2pk_fast_path(
3589 script_sig,
3590 script_pubkey,
3591 wit,
3592 flags,
3593 tx,
3594 input_index,
3595 prevout_values,
3596 prevout_script_pubkeys,
3597 block_height,
3598 network,
3599 schnorr_collector,
3600 ) {
3601 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
3602 return result;
3603 }
3604 if let Some(result) = crate::script::templates::try_verify_p2tr_unexec_if_fast_path(
3605 script_sig,
3606 script_pubkey,
3607 wit,
3608 flags,
3609 tx,
3610 input_index,
3611 prevout_values,
3612 prevout_script_pubkeys,
3613 block_height,
3614 network,
3615 schnorr_collector,
3616 ) {
3617 FAST_PATH_UNEXEC_IF.fetch_add(1, Ordering::Relaxed);
3618 return result;
3619 }
3620 if let Some(result) = try_verify_p2tr_keypath_fast_path(
3621 script_sig,
3622 script_pubkey,
3623 wit,
3624 flags,
3625 tx,
3626 input_index,
3627 prevout_values,
3628 prevout_script_pubkeys,
3629 block_height,
3630 network,
3631 schnorr_collector,
3632 ) {
3633 FAST_PATH_P2TR.fetch_add(1, Ordering::Relaxed);
3634 return result;
3635 }
3636 }
3637 }
3638 #[cfg(feature = "production")]
3639 FAST_PATH_INTERPRETER.fetch_add(1, Ordering::Relaxed);
3640
3641 let is_p2sh = (flags & flags::SCRIPT_VERIFY_P2SH) != 0
3645 && script_pubkey.len() == 23 && script_pubkey[0] == OP_HASH160 && script_pubkey[1] == PUSH_20_BYTES && script_pubkey[22] == OP_EQUAL; enum RedeemSource {
3652 Absent,
3653 Empty,
3654 Slice(usize, usize),
3655 Number(i64),
3656 StackCopy,
3657 }
3658 let mut redeem_source = RedeemSource::Absent;
3659
3660 if is_p2sh {
3666 let mut i = 0;
3667 while i < script_sig.len() {
3668 let opcode = script_sig[i];
3669 if !is_push_opcode(opcode) {
3670 return Ok(false);
3672 }
3673 if opcode == OP_0 {
3675 redeem_source = RedeemSource::Empty;
3677 i += 1;
3678 } else if opcode <= 0x4b {
3679 let len = opcode as usize;
3681 if i + 1 + len > script_sig.len() {
3682 return Ok(false); }
3684 redeem_source = RedeemSource::Slice(i + 1, i + 1 + len);
3685 i += 1 + len;
3686 } else if opcode == OP_PUSHDATA1 {
3687 if i + 1 >= script_sig.len() {
3689 return Ok(false);
3690 }
3691 let len = script_sig[i + 1] as usize;
3692 if i + 2 + len > script_sig.len() {
3693 return Ok(false);
3694 }
3695 redeem_source = RedeemSource::Slice(i + 2, i + 2 + len);
3696 i += 2 + len;
3697 } else if opcode == OP_PUSHDATA2 {
3698 if i + 2 >= script_sig.len() {
3700 return Ok(false);
3701 }
3702 let len = u16::from_le_bytes([script_sig[i + 1], script_sig[i + 2]]) as usize;
3703 if i + 3 + len > script_sig.len() {
3704 return Ok(false);
3705 }
3706 redeem_source = RedeemSource::Slice(i + 3, i + 3 + len);
3707 i += 3 + len;
3708 } else if opcode == OP_PUSHDATA4 {
3709 if i + 4 >= script_sig.len() {
3711 return Ok(false);
3712 }
3713 let len = u32::from_le_bytes([
3714 script_sig[i + 1],
3715 script_sig[i + 2],
3716 script_sig[i + 3],
3717 script_sig[i + 4],
3718 ]) as usize;
3719 if i + 5 + len > script_sig.len() {
3720 return Ok(false);
3721 }
3722 redeem_source = RedeemSource::Slice(i + 5, i + 5 + len);
3723 i += 5 + len;
3724 } else if opcode == OP_1NEGATE || (OP_1..=OP_16).contains(&opcode) {
3725 redeem_source = RedeemSource::Number(script_num_from_opcode(opcode));
3727 i += 1;
3728 } else if (OP_1NEGATE..=OP_16).contains(&opcode) {
3729 redeem_source = RedeemSource::StackCopy;
3731 i += 1;
3732 } else {
3733 return Ok(false);
3735 }
3736 }
3737 #[cfg(feature = "production")]
3738 let run_fast_paths = !fast_paths_disabled();
3739 #[cfg(not(feature = "production"))]
3740 let run_fast_paths = true;
3741 if run_fast_paths {
3742 if let Some(result) = try_verify_p2sh_multisig_fast_path(
3743 script_sig,
3744 script_pubkey,
3745 flags,
3746 tx,
3747 input_index,
3748 prevout_values,
3749 prevout_script_pubkeys,
3750 block_height,
3751 network,
3752 #[cfg(feature = "production")]
3753 sighash_cache,
3754 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
3755 ecdsa_collect.map(|(c, _)| c),
3756 ) {
3757 return result;
3758 }
3759 }
3760 }
3761
3762 #[cfg(feature = "production")]
3763 let mut _stack_guard = PooledStackGuard(get_pooled_stack());
3764 #[cfg(feature = "production")]
3765 let stack = &mut _stack_guard.0;
3766 #[cfg(not(feature = "production"))]
3767 let mut stack_buf: Vec<StackElement> = Vec::with_capacity(20);
3768 #[cfg(not(feature = "production"))]
3769 let stack = &mut stack_buf;
3770
3771 let script_sig_result = eval_script_with_context_full(
3775 script_sig,
3776 stack,
3777 flags,
3778 tx,
3779 input_index,
3780 prevout_values,
3781 prevout_script_pubkeys,
3782 block_height,
3783 median_time_past,
3784 network,
3785 SigVersion::Base,
3786 None, None, None, None, #[cfg(feature = "production")]
3791 schnorr_collector,
3792 None, #[cfg(feature = "production")]
3794 sighash_cache,
3795 )?;
3796 if !script_sig_result {
3797 return Ok(false);
3798 }
3799
3800 let mut numeric_redeem = script_num_encode(0);
3803 let mut copied_redeem: Option<ByteString> = None;
3804 if is_p2sh && !stack.is_empty() {
3805 match redeem_source {
3806 RedeemSource::Number(n) => numeric_redeem = script_num_encode(n),
3807 RedeemSource::StackCopy | RedeemSource::Absent => {
3808 copied_redeem = Some(
3809 stack
3810 .last()
3811 .expect("Stack is not empty")
3812 .as_slice()
3813 .to_vec(),
3814 );
3815 }
3816 RedeemSource::Empty | RedeemSource::Slice(_, _) => {}
3817 }
3818 }
3819 let redeem_script: Option<&[u8]> = if is_p2sh && !stack.is_empty() {
3820 match redeem_source {
3821 RedeemSource::Slice(start, end) => Some(&script_sig[start..end]),
3822 RedeemSource::Empty => Some(&[]),
3823 RedeemSource::Number(_) => Some(&numeric_redeem[..]),
3824 RedeemSource::StackCopy | RedeemSource::Absent => copied_redeem.as_deref(),
3825 }
3826 } else {
3827 None
3828 };
3829 let nested_witness_program = redeem_script.as_ref().is_some_and(|redeem| {
3830 redeem.len() >= 3
3831 && redeem[0] == OP_0
3832 && ((redeem[1] == PUSH_20_BYTES && redeem.len() == 22)
3833 || (redeem[1] == PUSH_32_BYTES && redeem.len() == 34))
3834 });
3835 if nested_witness_program
3837 && !redeem_push_is_canonical(
3838 script_sig.as_ref(),
3839 redeem_script.as_ref().expect("nested redeem"),
3840 )
3841 {
3842 return Ok(false);
3843 }
3844
3845 use crate::activation::taproot_active_at_height;
3848 use crate::script::flags::{
3849 SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM, SCRIPT_VERIFY_WITNESS,
3850 };
3851 let witness_flag = flags & SCRIPT_VERIFY_WITNESS != 0;
3852 let v1_32 =
3853 script_pubkey.len() == 34 && script_pubkey[0] == OP_1 && script_pubkey[1] == PUSH_32_BYTES;
3854 let is_taproot =
3855 redeem_script.is_none() && v1_32 && taproot_active_at_height(block_height, network);
3856
3857 if is_taproot && !script_sig.is_empty() {
3859 return Ok(false); }
3861
3862 let untaproot_v1 = witness_flag && !is_taproot && v1_32;
3865 if redeem_script.is_none()
3866 && !is_taproot
3867 && (untaproot_v1 || crate::witness::is_upgradable_witness_program(script_pubkey))
3868 {
3869 if !script_sig.is_empty() {
3870 return Ok(false);
3871 }
3872 if !witness_flag {
3873 return Ok(false);
3874 }
3875 if crate::witness::is_pay_to_anchor(script_pubkey) {
3878 return Ok(true);
3879 }
3880 if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM) != 0 {
3881 return Ok(false);
3882 }
3883 if !cast_to_bool(&script_pubkey[2..]) {
3886 return Ok(false);
3887 }
3888 return Ok(true);
3889 }
3890
3891 if witness_flag
3897 && redeem_script.is_none()
3898 && crate::witness::is_invalid_v0_witness_program(script_pubkey)
3899 {
3900 return Ok(false);
3901 }
3902 let is_direct_witness_program = witness_flag
3903 && redeem_script.is_none()
3904 && !is_taproot
3905 && crate::witness::is_standard_witness_program(script_pubkey)
3906 && script_pubkey[0] == OP_0;
3907
3908 if is_direct_witness_program {
3909 if !cast_to_bool(&script_pubkey[2..]) {
3912 return Ok(false);
3913 }
3914 if !script_sig.is_empty() {
3916 return Ok(false);
3917 }
3918 let Some(witness_stack) = witness else {
3919 return Ok(false);
3920 };
3921 if script_pubkey[1] == PUSH_32_BYTES {
3922 if witness_stack.is_empty() {
3923 return Ok(false);
3924 }
3925 let witness_script = witness_stack.last().expect("Witness stack is not empty");
3926 let program_bytes = &script_pubkey[2..];
3927 if program_bytes.len() != 32 {
3928 return Ok(false);
3929 }
3930 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
3931 if &witness_script_hash[..] != program_bytes {
3932 return Ok(false);
3933 }
3934 let max_witness_elem = MAX_SCRIPT_ELEMENT_SIZE;
3935 for element in witness_stack.iter().take(witness_stack.len() - 1) {
3936 if element.len() > max_witness_elem {
3937 return Ok(false);
3938 }
3939 }
3940 stack.clear();
3942 for element in witness_stack.iter().take(witness_stack.len() - 1) {
3943 stack.push(to_stack_element(element));
3944 }
3945 return eval_script_with_context_full(
3946 witness_script,
3947 stack,
3948 flags,
3949 tx,
3950 input_index,
3951 prevout_values,
3952 prevout_script_pubkeys,
3953 block_height,
3954 median_time_past,
3955 network,
3956 SigVersion::WitnessV0,
3957 Some(witness_script.as_ref()),
3958 None,
3959 None,
3960 None, #[cfg(feature = "production")]
3962 schnorr_collector,
3963 precomputed_bip143,
3964 #[cfg(feature = "production")]
3965 sighash_cache,
3966 );
3967 } else if script_pubkey[1] == PUSH_20_BYTES {
3968 if witness_stack.len() != 2 {
3969 return Ok(false);
3970 }
3971 let signature_bytes = &witness_stack[0];
3972 let pubkey_bytes = &witness_stack[1];
3973 if signature_bytes.is_empty() {
3974 return Ok(false);
3975 }
3976 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
3977 return Ok(false);
3978 }
3979 let max_witness_elem = MAX_SCRIPT_ELEMENT_SIZE;
3980 if signature_bytes.len() > max_witness_elem || pubkey_bytes.len() > max_witness_elem {
3981 return Ok(false);
3982 }
3983 let pubkey_hash = &script_pubkey[2..22];
3984 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
3985 let computed_hash = Ripemd160::digest(pubkey_sha256);
3986 if &computed_hash[..] != pubkey_hash {
3987 return Ok(false);
3988 }
3989 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
3990 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
3991 let p2pkh_script_code = bip143_p2wpkh_script_code(pubkey_hash);
3992 let sighash = crate::transaction_hash::calculate_bip143_sighash(
3993 tx,
3994 input_index,
3995 &p2pkh_script_code,
3996 amount,
3997 sighash_byte,
3998 precomputed_bip143,
3999 )?;
4000 let height = block_height.unwrap_or(0);
4001 return signature::with_secp_context(|secp| {
4002 signature::verify_signature(
4003 secp,
4004 pubkey_bytes,
4005 signature_bytes,
4006 &sighash,
4007 flags,
4008 height,
4009 network,
4010 SigVersion::WitnessV0,
4011 )
4012 });
4013 } else {
4014 return Ok(false);
4015 }
4016 }
4017
4018 if is_taproot {
4019 let Some(witness_stack) = witness else {
4020 return Ok(false);
4021 };
4022 if witness_stack.is_empty() {
4023 return Ok(false);
4024 }
4025 let (witness_body, annex_hash) = crate::taproot::strip_taproot_annex(witness_stack);
4027 if witness_body.is_empty() {
4028 return Ok(false);
4029 }
4030 if witness_body.len() == 1 {
4031 #[cfg(feature = "production")]
4032 {
4033 return verify_p2tr_keypath_witness(
4034 script_pubkey,
4035 witness_stack,
4036 tx,
4037 input_index,
4038 prevout_values,
4039 prevout_script_pubkeys,
4040 schnorr_collector,
4041 );
4042 }
4043 #[cfg(not(feature = "production"))]
4044 {
4045 if witness_body.len() != 1 {
4046 return Ok(false);
4047 }
4048 let Some((sig_bytes, sighash_type)) =
4049 parse_taproot_keypath_sig(witness_body[0].as_ref())
4050 else {
4051 return Ok(false);
4052 };
4053 let output_key = &script_pubkey[2..34];
4054 let sighash = crate::taproot::compute_taproot_signature_hash(
4055 tx,
4056 input_index,
4057 prevout_values,
4058 prevout_script_pubkeys,
4059 sighash_type,
4060 annex_hash.as_ref(),
4061 )?;
4062 let mut pubkey = [0u8; 32];
4063 pubkey.copy_from_slice(output_key);
4064 return crate::secp256k1_backend::verify_schnorr(&sig_bytes, &sighash, &pubkey);
4065 }
4066 }
4067 if witness_body.len() < 2 {
4068 return Ok(false);
4069 }
4070 let mut output_key = [0u8; 32];
4071 output_key.copy_from_slice(&script_pubkey[2..34]);
4072 match crate::taproot::parse_taproot_script_path_witness(&witness_body, &output_key)? {
4073 None => return Ok(false),
4074 Some((tapscript, stack_items, control_block)) => {
4075 if control_block.leaf_version != crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT {
4076 use crate::script::flags::SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION;
4077 if flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION != 0 {
4078 return Ok(false);
4079 }
4080 return Ok(true);
4081 }
4082 for item in &stack_items {
4083 stack.push(to_stack_element(item));
4084 }
4085 if !eval_script_with_context_full(
4086 &tapscript,
4087 stack,
4088 flags,
4089 tx,
4090 input_index,
4091 prevout_values,
4092 prevout_script_pubkeys,
4093 block_height,
4094 median_time_past,
4095 network,
4096 SigVersion::Tapscript,
4097 None, None, annex_hash.as_ref(),
4100 Some(crate::taproot::witness_stack_serialize_size(witness_stack) + 50),
4101 #[cfg(feature = "production")]
4102 schnorr_collector,
4103 None,
4104 #[cfg(feature = "production")]
4105 sighash_cache,
4106 )? {
4107 return Ok(false);
4108 }
4109 return Ok(true);
4110 }
4111 }
4112 }
4113
4114 let script_pubkey_result = eval_script_with_context_full(
4121 script_pubkey,
4122 stack,
4123 flags,
4124 tx,
4125 input_index,
4126 prevout_values,
4127 prevout_script_pubkeys,
4128 block_height,
4129 median_time_past,
4130 network,
4131 SigVersion::Base,
4132 None, Some(script_sig),
4134 None, None, #[cfg(feature = "production")]
4137 schnorr_collector,
4138 None, #[cfg(feature = "production")]
4140 sighash_cache,
4141 )?;
4142 if !script_pubkey_result {
4143 return Ok(false);
4144 }
4145
4146 if let Some(redeem) = redeem_script {
4151 if stack.is_empty() {
4153 return Ok(false); }
4155
4156 let top = stack.last().expect("Stack is not empty");
4158 if !cast_to_bool(top) {
4159 return Ok(false); }
4161
4162 stack.pop();
4164
4165 let is_witness_program =
4170 crate::witness::is_standard_witness_program(redeem) && redeem[0] == OP_0;
4171
4172 if witness_flag && crate::witness::is_invalid_v0_witness_program(redeem) {
4173 return Ok(false);
4174 }
4175
4176 if witness_flag && is_witness_program {
4177 if !cast_to_bool(&redeem[2..]) {
4178 return Ok(false);
4179 }
4180 let program_bytes = &redeem[2..];
4189
4190 if redeem[1] == PUSH_32_BYTES {
4191 if program_bytes.len() != 32 {
4194 return Ok(false); }
4196
4197 if let Some(witness_stack) = witness {
4202 if witness_stack.is_empty() {
4203 return Ok(false); }
4205
4206 let witness_script = witness_stack.last().expect("Witness stack is not empty");
4208 let witness_script_hash = OptimizedSha256::new().hash(witness_script.as_ref());
4209 if &witness_script_hash[..] != program_bytes {
4210 return Ok(false); }
4212
4213 stack.clear();
4216
4217 let max_witness_elem = MAX_SCRIPT_ELEMENT_SIZE;
4220 for element in witness_stack.iter().take(witness_stack.len() - 1) {
4221 if element.len() > max_witness_elem {
4222 return Ok(false);
4223 }
4224 stack.push(to_stack_element(element));
4225 }
4226
4227 let witness_sigversion = SigVersion::WitnessV0;
4231
4232 if !eval_script_with_context_full(
4234 witness_script,
4235 stack,
4236 flags,
4237 tx,
4238 input_index,
4239 prevout_values,
4240 prevout_script_pubkeys,
4241 block_height,
4242 median_time_past,
4243 network,
4244 witness_sigversion,
4245 Some(witness_script.as_ref()), None, None, None, #[cfg(feature = "production")]
4250 schnorr_collector,
4251 precomputed_bip143, #[cfg(feature = "production")]
4253 sighash_cache,
4254 )? {
4255 return Ok(false);
4256 }
4257 } else {
4258 return Ok(false); }
4260 } else if redeem[1] == PUSH_20_BYTES {
4261 let pubkey_hash = &redeem[2..22]; let witness_stack = match witness {
4267 Some(w) => w,
4268 None => return Ok(false), };
4270 if witness_stack.len() != 2 {
4271 return Ok(false); }
4273 let signature_bytes = &witness_stack[0];
4274 let pubkey_bytes = &witness_stack[1];
4275
4276 if signature_bytes.is_empty() {
4277 return Ok(false);
4278 }
4279 if pubkey_bytes.len() != 33 && pubkey_bytes.len() != 65 {
4280 return Ok(false);
4281 }
4282
4283 let pubkey_sha256 = OptimizedSha256::new().hash(pubkey_bytes);
4285 let computed_hash = Ripemd160::digest(pubkey_sha256);
4286 if &computed_hash[..] != pubkey_hash {
4287 return Ok(false);
4288 }
4289
4290 let sighash_byte = signature_bytes[signature_bytes.len() - 1];
4292 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
4293 let p2pkh_script_code = bip143_p2wpkh_script_code(pubkey_hash);
4294 let sighash = crate::transaction_hash::calculate_bip143_sighash(
4295 tx,
4296 input_index,
4297 &p2pkh_script_code,
4298 amount,
4299 sighash_byte,
4300 precomputed_bip143,
4301 )?;
4302
4303 let height = block_height.unwrap_or(0);
4304 return signature::with_secp_context(|secp| {
4305 signature::verify_signature(
4306 secp,
4307 pubkey_bytes,
4308 signature_bytes,
4309 &sighash,
4310 flags,
4311 height,
4312 network,
4313 SigVersion::WitnessV0,
4314 )
4315 });
4316 } else {
4317 return Ok(false); }
4319 } else if witness_flag && crate::witness::is_any_witness_program(redeem) {
4321 if !redeem_push_is_canonical(script_sig.as_ref(), redeem) {
4325 return Ok(false);
4326 }
4327 if flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM != 0 {
4328 return Ok(false);
4329 }
4330 if !cast_to_bool(&redeem[2..]) {
4331 return Ok(false);
4332 }
4333 return Ok(true);
4334 } else {
4335 let redeem_result = eval_script_with_context_full_inner(
4339 redeem,
4340 stack,
4341 flags,
4342 tx,
4343 input_index,
4344 prevout_values,
4345 prevout_script_pubkeys,
4346 block_height,
4347 median_time_past,
4348 network,
4349 SigVersion::Base,
4350 Some(redeem), Some(script_sig), None, None, #[cfg(feature = "production")]
4355 None, None, #[cfg(feature = "production")]
4358 sighash_cache,
4359 )?;
4360 if !redeem_result {
4361 return Ok(false);
4362 }
4363 }
4364 }
4365
4366 if stack.len() > MAX_STACK_SIZE {
4368 return Ok(false);
4369 }
4370
4371 let accepts_witness = is_direct_witness_program || is_taproot || nested_witness_program;
4382 if witness_flag {
4383 if let Some(witness_stack) = witness {
4384 if !crate::witness::witness_stack_is_null(witness_stack) && !accepts_witness {
4385 return Ok(false);
4386 }
4387 }
4388 }
4389
4390 let final_result = if (flags & flags::SCRIPT_VERIFY_CLEANSTACK) != 0 {
4396 stack.len() == 1 && cast_to_bool(&stack[0])
4398 } else {
4399 !stack.is_empty() && cast_to_bool(stack.last().expect("Stack is not empty"))
4401 };
4402 Ok(final_result)
4403}
4404
4405#[allow(clippy::too_many_arguments)]
4407fn eval_script_with_context_full(
4408 script: &[u8],
4409 stack: &mut Vec<StackElement>,
4410 flags: u32,
4411 tx: &Transaction,
4412 input_index: usize,
4413 prevout_values: &[i64],
4414 prevout_script_pubkeys: &[&[u8]],
4415 block_height: Option<u64>,
4416 median_time_past: Option<u64>,
4417 network: crate::types::Network,
4418 sigversion: SigVersion,
4419 redeem_script_for_sighash: Option<&[u8]>,
4420 script_sig_for_sighash: Option<&ByteString>,
4421 taproot_annex_hash: Option<&Hash>,
4422 tapscript_validation_weight: Option<i64>,
4423 #[cfg(feature = "production")] schnorr_collector: Option<
4424 &crate::bip348::SchnorrSignatureCollector,
4425 >,
4426 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
4427 #[cfg(feature = "production")] sighash_cache: Option<
4428 &crate::transaction_hash::SighashMidstateCache,
4429 >,
4430) -> Result<bool> {
4431 #[cfg(all(feature = "production", feature = "profile"))]
4432 let _t0 = std::time::Instant::now();
4433 let r = eval_script_with_context_full_inner(
4434 script,
4435 stack,
4436 flags,
4437 tx,
4438 input_index,
4439 prevout_values,
4440 prevout_script_pubkeys,
4441 block_height,
4442 median_time_past,
4443 network,
4444 sigversion,
4445 redeem_script_for_sighash,
4446 script_sig_for_sighash,
4447 taproot_annex_hash,
4448 tapscript_validation_weight,
4449 #[cfg(feature = "production")]
4450 schnorr_collector,
4451 precomputed_bip143,
4452 #[cfg(feature = "production")]
4453 sighash_cache,
4454 );
4455 #[cfg(all(feature = "production", feature = "profile"))]
4456 crate::script_profile::add_interpreter_ns(_t0.elapsed().as_nanos() as u64);
4457 r
4458}
4459
4460fn eval_script_with_context_full_inner(
4462 script: &[u8],
4463 stack: &mut Vec<StackElement>,
4464 flags: u32,
4465 tx: &Transaction,
4466 input_index: usize,
4467 prevout_values: &[i64],
4468 prevout_script_pubkeys: &[&[u8]],
4469 block_height: Option<u64>,
4470 median_time_past: Option<u64>,
4471 network: crate::types::Network,
4472 sigversion: SigVersion,
4473 redeem_script_for_sighash: Option<&[u8]>,
4474 script_sig_for_sighash: Option<&ByteString>,
4475 taproot_annex_hash: Option<&Hash>,
4476 tapscript_validation_weight: Option<i64>,
4477 #[cfg(feature = "production")] schnorr_collector: Option<
4478 &crate::bip348::SchnorrSignatureCollector,
4479 >,
4480 precomputed_bip143: Option<&crate::transaction_hash::Bip143PrecomputedHashes>,
4481 #[cfg(feature = "production")] sighash_cache: Option<
4482 &crate::transaction_hash::SighashMidstateCache,
4483 >,
4484) -> Result<bool> {
4485 use crate::constants::{MAX_SCRIPT_ELEMENT_SIZE, MAX_SCRIPT_SIZE, MAX_STACK_SIZE};
4488 use crate::error::{ConsensusError, ScriptErrorCode};
4489 let weight_cell = tapscript_validation_weight.map(std::cell::Cell::new);
4490
4491 if (sigversion == SigVersion::Base || sigversion == SigVersion::WitnessV0)
4493 && script.len() > MAX_SCRIPT_SIZE
4494 {
4495 return Err(ConsensusError::ScriptErrorWithCode {
4496 code: ScriptErrorCode::ScriptSize,
4497 message: "Script size exceeds maximum".into(),
4498 });
4499 }
4500 if sigversion == SigVersion::Tapscript {
4505 use crate::activation::IsForkActive;
4506 use crate::script::flags::SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS;
4507 let csfs_active = cfg!(feature = "csfs")
4508 && block_height.is_some_and(|height| {
4509 crate::activation::ForkActivationTable::from_network(network)
4510 .is_fork_active(crate::types::ForkId::Csfs, height)
4511 });
4512 let mut pc = 0usize;
4513 while pc < script.len() {
4514 let opcode = script[pc];
4515 if is_op_success(opcode)
4517 && !(csfs_active && opcode == crate::opcodes::OP_CHECKSIGFROMSTACK)
4518 {
4519 if flags & SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS != 0 {
4520 return Err(ConsensusError::ScriptErrorWithCode {
4521 code: ScriptErrorCode::BadOpcode,
4522 message: format!("OP_SUCCESSx opcode 0x{opcode:02x} is discouraged").into(),
4523 });
4524 }
4525 return Ok(true);
4526 }
4527 let Some(next) = tapscript_opcode_end(script, pc) else {
4529 break;
4530 };
4531 pc = next;
4532 }
4533 if stack.len() > MAX_STACK_SIZE {
4534 return Err(make_stack_overflow_error());
4535 }
4536 if stack
4537 .iter()
4538 .any(|item| item.len() > MAX_SCRIPT_ELEMENT_SIZE)
4539 {
4540 return Ok(false);
4541 }
4542 }
4543
4544 if stack.capacity() < 20 {
4546 stack.reserve(20);
4547 }
4548 let mut op_count = 0;
4549
4550 #[cfg(feature = "production")]
4552 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::with_capacity(4);
4553 #[cfg(not(feature = "production"))]
4554 let mut control_stack: Vec<control_flow::ControlBlock> = Vec::new();
4555
4556 #[cfg(feature = "production")]
4557 let mut altstack: Vec<StackElement> = Vec::with_capacity(8);
4558 #[cfg(not(feature = "production"))]
4559 let mut altstack: Vec<StackElement> = Vec::new();
4560
4561 let mut code_separator_pos: usize = 0;
4565 let mut last_codesep_opcode_pos: u32 = 0xffff_ffff;
4566
4567 let mut i = 0;
4570 let mut finished_opcode = false;
4571 while i < script.len() {
4572 if finished_opcode && stack.len() + altstack.len() > MAX_STACK_SIZE {
4573 return Err(make_stack_overflow_error());
4574 }
4575 finished_opcode = true;
4576 #[cfg(feature = "production")]
4577 {
4578 prefetch::prefetch_ahead(script, i, 64); }
4581 let opcode = {
4583 #[cfg(feature = "production")]
4584 {
4585 unsafe { *script.get_unchecked(i) }
4586 }
4587 #[cfg(not(feature = "production"))]
4588 {
4589 script[i]
4590 }
4591 };
4592
4593 let in_false_branch = control_flow::in_false_branch(&control_stack);
4595
4596 if sigversion != SigVersion::Tapscript && !is_push_opcode(opcode) {
4598 op_count += 1;
4599 if op_count > MAX_SCRIPT_OPS {
4600 return Err(make_operation_limit_error());
4601 }
4602 }
4603
4604 if (0x01..=OP_PUSHDATA4).contains(&opcode) {
4606 let Some(advance) = apply_data_push(script, i, opcode, stack, flags, in_false_branch)?
4607 else {
4608 return Ok(false);
4609 };
4610 i += advance;
4611 continue;
4612 }
4613
4614 if opcode == OP_DUP {
4620 if !in_false_branch {
4621 if stack.is_empty() {
4622 return Err(ConsensusError::ScriptErrorWithCode {
4623 code: ScriptErrorCode::InvalidStackOperation,
4624 message: "OP_DUP: empty stack".into(),
4625 });
4626 }
4627 let len = stack.len();
4630 #[cfg(feature = "production")]
4631 {
4632 if stack.capacity() == stack.len() {
4634 stack.reserve(1);
4635 }
4636 let item = unsafe { stack.get_unchecked(len - 1).clone() };
4638 stack.push(item);
4639 }
4640 #[cfg(not(feature = "production"))]
4641 {
4642 let item = stack.last().unwrap();
4643 stack.push(item.clone());
4644 }
4645 }
4646 i += 1;
4647 continue;
4648 }
4649
4650 if opcode == OP_EQUALVERIFY {
4652 if !in_false_branch {
4653 if stack.len() < 2 {
4654 return Err(ConsensusError::ScriptErrorWithCode {
4655 code: ScriptErrorCode::InvalidStackOperation,
4656 message: "OP_EQUALVERIFY: insufficient stack items".into(),
4657 });
4658 }
4659 let a = stack.pop().unwrap();
4660 let b = stack.pop().unwrap();
4661 if a != b {
4662 return Ok(false);
4663 }
4664 }
4665 i += 1;
4666 continue;
4667 }
4668
4669 if opcode == OP_HASH160 {
4671 if !in_false_branch && !crypto_ops::op_hash160(stack)? {
4672 return Ok(false);
4673 }
4674 i += 1;
4675 continue;
4676 }
4677
4678 if opcode == OP_VERIFY {
4680 if !in_false_branch {
4681 if let Some(item) = stack.pop() {
4682 if !cast_to_bool(&item) {
4683 return Ok(false);
4684 }
4685 } else {
4686 return Ok(false);
4687 }
4688 }
4689 i += 1;
4690 continue;
4691 }
4692
4693 if opcode == OP_EQUAL {
4695 if !in_false_branch {
4696 if stack.len() < 2 {
4697 return Err(ConsensusError::ScriptErrorWithCode {
4698 code: ScriptErrorCode::InvalidStackOperation,
4699 message: "OP_EQUAL: insufficient stack items".into(),
4700 });
4701 }
4702 let a = stack.pop().unwrap();
4703 let b = stack.pop().unwrap();
4704 stack.push(to_stack_element(script_bool_bytes(a == b)));
4705 }
4706 i += 1;
4707 continue;
4708 }
4709
4710 if opcode == OP_CHECKSIG
4713 || opcode == OP_CHECKSIGVERIFY
4714 || (opcode == OP_CHECKSIGADD && sigversion == SigVersion::Tapscript)
4715 {
4716 if !in_false_branch {
4717 let effective_script_code = Some(&script[code_separator_pos..]);
4718 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
4719 (Some(script), Some(last_codesep_opcode_pos))
4720 } else {
4721 (None, None)
4722 };
4723 let ctx = context::ScriptContext {
4724 tx,
4725 input_index,
4726 prevout_values,
4727 prevout_script_pubkeys,
4728 block_height,
4729 median_time_past,
4730 network,
4731 sigversion,
4732 redeem_script_for_sighash,
4733 script_sig_for_sighash,
4734 tapscript_for_sighash: tapscript,
4735 tapscript_codesep_pos: codesep,
4736 taproot_annex_hash,
4737 tapscript_validation_weight: weight_cell.as_ref(),
4738 #[cfg(feature = "production")]
4739 schnorr_collector,
4740 precomputed_bip143,
4741 #[cfg(feature = "production")]
4742 sighash_cache,
4743 };
4744 if !execute_opcode_with_context_full(
4745 opcode,
4746 stack,
4747 flags,
4748 &ctx,
4749 effective_script_code,
4750 )? {
4751 return Ok(false);
4752 }
4753 }
4754 i += 1;
4755 continue;
4756 }
4757
4758 match opcode {
4759 OP_0 => {
4761 if !in_false_branch {
4762 stack.push(to_stack_element(&[]));
4763 }
4764 }
4765
4766 OP_1_RANGE_START..=OP_1_RANGE_END => {
4768 if !in_false_branch {
4769 let num = opcode - OP_N_BASE;
4770 stack.push(to_stack_element(&[num]));
4771 }
4772 }
4773
4774 OP_1NEGATE => {
4776 if !in_false_branch {
4777 stack.push(to_stack_element(&[0x81])); }
4779 }
4780
4781 OP_NOP => {
4783 }
4785
4786 OP_VER => {
4791 if !in_false_branch {
4792 return Err(ConsensusError::ScriptErrorWithCode {
4793 code: ScriptErrorCode::DisabledOpcode,
4794 message: "OP_VER is disabled".into(),
4795 });
4796 }
4797 }
4798
4799 OP_IF => {
4800 if in_false_branch {
4802 control_stack.push(control_flow::ControlBlock::If { executing: false });
4803 i += 1;
4804 continue;
4805 }
4806
4807 if stack.is_empty() {
4808 return Err(ConsensusError::ScriptErrorWithCode {
4809 code: ScriptErrorCode::InvalidStackOperation,
4810 message: "OP_IF: empty stack".into(),
4811 });
4812 }
4813 let condition = pop_if_condition(
4814 stack,
4815 flags,
4816 sigversion,
4817 "OP_IF condition must be minimally encoded",
4818 )?;
4819 control_stack.push(control_flow::ControlBlock::If {
4820 executing: condition,
4821 });
4822 }
4823 OP_NOTIF => {
4824 if in_false_branch {
4826 control_stack.push(control_flow::ControlBlock::NotIf { executing: false });
4827 i += 1;
4828 continue;
4829 }
4830
4831 if stack.is_empty() {
4832 return Err(ConsensusError::ScriptErrorWithCode {
4833 code: ScriptErrorCode::InvalidStackOperation,
4834 message: "OP_NOTIF: empty stack".into(),
4835 });
4836 }
4837 let condition = pop_if_condition(
4838 stack,
4839 flags,
4840 sigversion,
4841 "OP_NOTIF condition must be minimally encoded",
4842 )?;
4843 control_stack.push(control_flow::ControlBlock::NotIf {
4844 executing: !condition,
4845 });
4846 }
4847 OP_ELSE => {
4848 if let Some(block) = control_stack.last_mut() {
4850 match block {
4851 control_flow::ControlBlock::If { executing }
4852 | control_flow::ControlBlock::NotIf { executing } => {
4853 *executing = !*executing;
4854 }
4855 }
4856 } else {
4857 return Err(ConsensusError::ScriptErrorWithCode {
4858 code: ScriptErrorCode::UnbalancedConditional,
4859 message: "OP_ELSE without matching IF/NOTIF".into(),
4860 });
4861 }
4862 }
4863 OP_ENDIF => {
4864 if control_stack.pop().is_none() {
4866 return Err(ConsensusError::ScriptErrorWithCode {
4867 code: ScriptErrorCode::UnbalancedConditional,
4868 message: "OP_ENDIF without matching IF/NOTIF".into(),
4869 });
4870 }
4871 }
4872
4873 OP_TOALTSTACK => {
4878 if in_false_branch {
4879 i += 1;
4880 continue;
4881 }
4882 if stack.is_empty() {
4883 return Err(ConsensusError::ScriptErrorWithCode {
4884 code: ScriptErrorCode::InvalidStackOperation,
4885 message: "OP_TOALTSTACK: empty stack".into(),
4886 });
4887 }
4888 altstack.push(stack.pop().unwrap());
4889 }
4890 OP_FROMALTSTACK => {
4892 if in_false_branch {
4893 i += 1;
4894 continue;
4895 }
4896 if altstack.is_empty() {
4897 return Err(ConsensusError::ScriptErrorWithCode {
4898 code: ScriptErrorCode::InvalidAltstackOperation,
4899 message: "OP_FROMALTSTACK: empty altstack".into(),
4900 });
4901 }
4902 stack.push(altstack.pop().unwrap());
4903 }
4904 OP_CODESEPARATOR => {
4907 if sigversion == SigVersion::Base
4908 && flags & crate::script::flags::SCRIPT_VERIFY_CONST_SCRIPTCODE != 0
4909 {
4910 return Err(ConsensusError::ScriptErrorWithCode {
4911 code: ScriptErrorCode::BadOpcode,
4912 message: "OP_CODESEPARATOR is non-standard in a non-segwit script".into(),
4913 });
4914 }
4915 if in_false_branch {
4916 i += 1;
4917 continue;
4918 }
4919 code_separator_pos = i + 1;
4920 last_codesep_opcode_pos = opcode_position_at_byte(script, i);
4921 }
4922 _ => {
4923 if in_false_branch {
4924 if let Some(code) = dead_branch_opcode_error(opcode) {
4925 return Err(ConsensusError::ScriptErrorWithCode {
4926 code,
4927 message: format!(
4928 "opcode 0x{opcode:02x} is invalid in an unexecuted branch"
4929 )
4930 .into(),
4931 });
4932 }
4933 i += 1;
4934 continue;
4935 }
4936
4937 if sigversion != SigVersion::Tapscript
4942 && (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
4943 {
4944 op_count = charge_checkmultisig_pubkeys(stack, op_count)?;
4945 }
4946 let subscript_for_sighash = if matches!(
4947 opcode,
4948 OP_CHECKSIG
4949 | OP_CHECKSIGVERIFY
4950 | OP_CHECKSIGADD
4951 | OP_CHECKMULTISIG
4952 | OP_CHECKMULTISIGVERIFY
4953 ) {
4954 Some(&script[code_separator_pos..])
4955 } else {
4956 None
4957 };
4958 let effective_script_code = subscript_for_sighash.or(redeem_script_for_sighash);
4959 let (tapscript, codesep) = if sigversion == SigVersion::Tapscript {
4960 (Some(script), Some(last_codesep_opcode_pos))
4961 } else {
4962 (None, None)
4963 };
4964 let ctx = context::ScriptContext {
4965 tx,
4966 input_index,
4967 prevout_values,
4968 prevout_script_pubkeys,
4969 block_height,
4970 median_time_past,
4971 network,
4972 sigversion,
4973 redeem_script_for_sighash,
4974 script_sig_for_sighash,
4975 tapscript_for_sighash: tapscript,
4976 tapscript_codesep_pos: codesep,
4977 taproot_annex_hash,
4978 tapscript_validation_weight: weight_cell.as_ref(),
4979 #[cfg(feature = "production")]
4980 schnorr_collector,
4981 precomputed_bip143,
4982 #[cfg(feature = "production")]
4983 sighash_cache,
4984 };
4985 if !execute_opcode_with_context_full(
4986 opcode,
4987 stack,
4988 flags,
4989 &ctx,
4990 effective_script_code,
4991 )? {
4992 return Ok(false);
4993 }
4994 }
4995 }
4996 i += 1;
4997 }
4998
4999 if finished_opcode && stack.len() + altstack.len() > MAX_STACK_SIZE {
5000 return Err(make_stack_overflow_error());
5001 }
5002
5003 if !control_stack.is_empty() {
5005 return Err(ConsensusError::ScriptErrorWithCode {
5006 code: ScriptErrorCode::UnbalancedConditional,
5007 message: "Unclosed IF/NOTIF block".into(),
5008 });
5009 }
5010
5011 if sigversion == SigVersion::WitnessV0 || sigversion == SigVersion::Tapscript {
5014 let clean = stack.len() == 1 && cast_to_bool(&stack[0]);
5015 return Ok(clean);
5016 }
5017 Ok(true)
5018}
5019
5020pub(crate) fn script_num_is_minimally_encoded(data: &[u8]) -> bool {
5023 if let Some(&last) = data.last() {
5024 if last & 0x7f == 0 && (data.len() <= 1 || data[data.len() - 2] & 0x80 == 0) {
5025 return false;
5026 }
5027 }
5028 true
5029}
5030
5031#[cfg_attr(feature = "spec-lock", spec_locked("5.4.5", "DecodeCScriptNum"))]
5035#[cfg_attr(feature = "spec-lock", blvm_spec_lock::axiom(result >= -549755813887))]
5036#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result >= -549755813887))]
5037#[cfg(feature = "production")]
5038#[inline(always)]
5039pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
5040 if data.len() > max_num_size {
5041 return Err(ConsensusError::ScriptErrorWithCode {
5042 code: ScriptErrorCode::InvalidStackOperation,
5043 message: format!(
5044 "Script number overflow: {} > {} bytes",
5045 data.len(),
5046 max_num_size
5047 )
5048 .into(),
5049 });
5050 }
5051 if data.is_empty() {
5052 return Ok(0);
5053 }
5054
5055 let len = data.len();
5057 let result = match len {
5058 1 => {
5059 let byte = data[0];
5060 if byte & 0x80 != 0 {
5061 -((byte & 0x7f) as i64)
5063 } else {
5064 byte as i64
5065 }
5066 }
5067 2 => {
5068 let byte0 = data[0] as i64;
5069 let byte1 = data[1] as i64;
5070 let value = byte0 | (byte1 << 8);
5071 if byte1 & 0x80 != 0 {
5072 -(value & !(0x80i64 << 8))
5074 } else {
5075 value
5076 }
5077 }
5078 _ => {
5079 let mut result: i64 = 0;
5081 for (i, &byte) in data.iter().enumerate() {
5082 result |= (byte as i64) << (8 * i);
5083 }
5084 let last_idx = len - 1;
5086 if data[last_idx] & 0x80 != 0 {
5087 result &= !(0x80i64 << (8 * last_idx));
5089 result = -result;
5090 }
5091 result
5092 }
5093 };
5094
5095 Ok(result)
5096}
5097
5098#[cfg(not(feature = "production"))]
5099#[inline]
5100pub(crate) fn script_num_decode(data: &[u8], max_num_size: usize) -> Result<i64> {
5101 if data.len() > max_num_size {
5102 return Err(ConsensusError::ScriptErrorWithCode {
5103 code: ScriptErrorCode::InvalidStackOperation,
5104 message: format!(
5105 "Script number overflow: {} > {} bytes",
5106 data.len(),
5107 max_num_size
5108 )
5109 .into(),
5110 });
5111 }
5112 if data.is_empty() {
5113 return Ok(0);
5114 }
5115 let mut result: i64 = 0;
5117 for (i, &byte) in data.iter().enumerate() {
5118 result |= (byte as i64) << (8 * i);
5119 }
5120 if data.last().expect("Data is not empty") & 0x80 != 0 {
5122 result &= !(0x80i64 << (8 * (data.len() - 1)));
5124 result = -result;
5125 }
5126 Ok(result)
5127}
5128
5129pub(crate) struct ScriptNumBytes {
5131 buf: [u8; 9],
5132 len: u8,
5133}
5134
5135impl ScriptNumBytes {
5136 fn new(buf: [u8; 9], len: u8) -> Self {
5137 Self { buf, len }
5138 }
5139}
5140
5141impl std::ops::Deref for ScriptNumBytes {
5142 type Target = [u8];
5143 fn deref(&self) -> &[u8] {
5144 &self.buf[..self.len as usize]
5145 }
5146}
5147
5148pub(crate) fn script_num_encode(value: i64) -> ScriptNumBytes {
5151 match value {
5152 0 => return ScriptNumBytes::new([0; 9], 0),
5153 1 => {
5154 let mut buf = [0u8; 9];
5155 buf[0] = 1;
5156 return ScriptNumBytes::new(buf, 1);
5157 }
5158 -1 => {
5159 let mut buf = [0u8; 9];
5160 buf[0] = 0x81;
5161 return ScriptNumBytes::new(buf, 1);
5162 }
5163 _ => {}
5164 }
5165
5166 let neg = value < 0;
5167 let mut absvalue = if neg {
5168 (-(value as i128)) as u64
5169 } else {
5170 value as u64
5171 };
5172 let mut buf = [0u8; 9];
5173 let mut len = 0u8;
5174 while absvalue > 0 {
5175 buf[len as usize] = (absvalue & 0xff) as u8;
5176 len += 1;
5177 absvalue >>= 8;
5178 }
5179 if buf[len as usize - 1] & 0x80 != 0 {
5181 buf[len as usize] = if neg { 0x80 } else { 0x00 };
5182 len += 1;
5183 } else if neg {
5184 buf[len as usize - 1] |= 0x80;
5185 }
5186 ScriptNumBytes::new(buf, len)
5187}
5188
5189fn upgradable_nop(flags: u32) -> Result<bool> {
5191 if flags & flags::SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS != 0 {
5192 return Err(ConsensusError::ScriptErrorWithCode {
5193 code: ScriptErrorCode::DiscourageUpgradableNops,
5194 message: "reserved NOP is discouraged".into(),
5195 });
5196 }
5197 Ok(true)
5198}
5199
5200fn strictenc_nocheck_multisig(stack: &[StackElement], flags: u32) -> Result<()> {
5204 if flags & 0x02 == 0 || stack.is_empty() {
5205 return Ok(());
5206 }
5207 let n = match script_num_decode(stack.last().unwrap(), 4) {
5208 Ok(v) if (0..=20).contains(&v) => v as usize,
5209 _ => return Ok(()),
5210 };
5211 if stack.len() < n + 2 {
5212 return Ok(());
5213 }
5214 let n_at = stack.len() - 1;
5215 let m_at = n_at - n - 1;
5216 let m = match script_num_decode(&stack[m_at], 4) {
5217 Ok(v) if v >= 0 && v as usize <= n => v as usize,
5218 _ => return Ok(()),
5219 };
5220 if m == 0 {
5223 return Ok(());
5224 }
5225 for pubkey in &stack[n_at - n..n_at] {
5226 crate::script::signature::reject_strictenc_pubkey(flags, pubkey)?;
5227 }
5228 if m_at < m {
5229 return Ok(());
5230 }
5231 for signature in &stack[m_at - m..m_at] {
5232 crate::script::signature::reject_strictenc_signature(flags, signature)?;
5233 }
5234 Ok(())
5235}
5236
5237fn pop_nocheck_multisig(stack: &mut Vec<StackElement>) -> Option<usize> {
5240 if stack.is_empty() {
5241 return None;
5242 }
5243 let n_bytes = stack.pop().unwrap();
5244 let n = match script_num_decode(&n_bytes, 4) {
5245 Ok(v) if (0..=20).contains(&v) => v as usize,
5246 _ => return None,
5247 };
5248 if stack.len() < n {
5249 return None;
5250 }
5251 for _ in 0..n {
5252 stack.pop();
5253 }
5254 if stack.is_empty() {
5255 return None;
5256 }
5257 let m_bytes = stack.pop().unwrap();
5258 let m = match script_num_decode(&m_bytes, 4) {
5259 Ok(v) if v >= 0 && v as usize <= n => v as usize,
5260 _ => return None,
5261 };
5262 if stack.len() < m {
5263 return None;
5264 }
5265 for _ in 0..m {
5266 stack.pop();
5267 }
5268 if stack.is_empty() {
5269 return None;
5270 }
5271 stack.pop();
5272 Some(m)
5273}
5274
5275#[cfg_attr(feature = "production", inline(always))]
5277fn execute_opcode(
5278 opcode: u8,
5279 stack: &mut Vec<StackElement>,
5280 flags: u32,
5281 _sigversion: SigVersion,
5282) -> Result<bool> {
5283 match opcode {
5284 OP_0 => {
5286 stack.push(to_stack_element(&[]));
5287 Ok(true)
5288 }
5289
5290 OP_1..=OP_16 => {
5292 let num = opcode - OP_N_BASE;
5293 stack.push(to_stack_element(&[num]));
5294 Ok(true)
5295 }
5296
5297 OP_NOP => Ok(true),
5299
5300 OP_VER => Ok(false),
5302
5303 OP_DEPTH => {
5305 let depth = stack.len() as i64;
5306 stack.push(to_stack_element(&script_num_encode(depth)));
5307 Ok(true)
5308 }
5309
5310 OP_DUP => {
5312 if let Some(item) = stack.last().cloned() {
5313 stack.push(item);
5314 Ok(true)
5315 } else {
5316 Ok(false)
5317 }
5318 }
5319
5320 OP_RIPEMD160 => crypto_ops::op_ripemd160(stack),
5322
5323 OP_SHA1 => crypto_ops::op_sha1(stack),
5325
5326 OP_SHA256 => crypto_ops::op_sha256(stack),
5328
5329 OP_HASH160 => crypto_ops::op_hash160(stack),
5331
5332 OP_HASH256 => crypto_ops::op_hash256(stack),
5334
5335 OP_EQUAL => {
5338 if stack.len() < 2 {
5339 return Err(ConsensusError::ScriptErrorWithCode {
5340 code: ScriptErrorCode::InvalidStackOperation,
5341 message: "OP_EQUAL: insufficient stack items".into(),
5342 });
5343 }
5344 let a = stack.pop().unwrap();
5345 let b = stack.pop().unwrap();
5346 stack.push(to_stack_element(if a == b { &[1u8] } else { &[] }));
5347 Ok(true)
5348 }
5349
5350 OP_EQUALVERIFY => {
5353 if stack.len() < 2 {
5354 return Err(ConsensusError::ScriptErrorWithCode {
5355 code: ScriptErrorCode::InvalidStackOperation,
5356 message: "OP_EQUALVERIFY: insufficient stack items".into(),
5357 });
5358 }
5359 let a = stack.pop().unwrap();
5360 let b = stack.pop().unwrap();
5361 let f_equal = a == b;
5362 stack.push(to_stack_element(script_bool_bytes(f_equal)));
5364 if f_equal {
5365 stack.pop();
5367 Ok(true)
5368 } else {
5369 Err(ConsensusError::ScriptErrorWithCode {
5370 code: ScriptErrorCode::EqualVerify,
5371 message: "OP_EQUALVERIFY: stack items not equal".into(),
5372 })
5373 }
5374 }
5375
5376 OP_CHECKSIG => crypto_ops::op_checksig_simple(stack, flags),
5378
5379 OP_CHECKSIGVERIFY => crypto_ops::op_checksigverify_simple(stack, flags),
5381
5382 OP_RETURN => Ok(false),
5384
5385 OP_VERIFY => {
5387 if let Some(item) = stack.pop() {
5388 Ok(cast_to_bool(&item))
5389 } else {
5390 Ok(false)
5391 }
5392 }
5393
5394 OP_CHECKLOCKTIMEVERIFY => {
5398 if (flags & flags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
5399 Ok(true)
5400 } else {
5401 Ok(false)
5402 }
5403 }
5404
5405 OP_CHECKSEQUENCEVERIFY => {
5409 if (flags & flags::SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
5410 Ok(true)
5411 } else {
5412 Ok(false)
5413 }
5414 }
5415
5416 OP_IFDUP => {
5418 if let Some(item) = stack.last().cloned() {
5419 if cast_to_bool(&item) {
5420 stack.push(item);
5421 }
5422 Ok(true)
5423 } else {
5424 Ok(false)
5425 }
5426 }
5427
5428 OP_DROP => {
5431 if stack.pop().is_some() {
5432 Ok(true)
5433 } else {
5434 Ok(false)
5435 }
5436 }
5437
5438 OP_NIP => {
5440 if stack.len() >= 2 {
5441 let top = stack.pop().unwrap();
5442 stack.pop(); stack.push(top);
5444 Ok(true)
5445 } else {
5446 Ok(false)
5447 }
5448 }
5449
5450 OP_OVER => {
5452 if stack.len() >= 2 {
5453 let len = stack.len();
5454 #[cfg(feature = "production")]
5455 {
5456 unsafe {
5458 let second = stack.get_unchecked(len - 2);
5459 stack.push(second.clone());
5460 }
5461 }
5462 #[cfg(not(feature = "production"))]
5463 {
5464 let second = stack[stack.len() - 2].clone();
5465 stack.push(second);
5466 }
5467 Ok(true)
5468 } else {
5469 Ok(false)
5470 }
5471 }
5472
5473 OP_PICK => {
5475 if let Some(n_bytes) = stack.pop() {
5476 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5477 && !script_num_is_minimally_encoded(&n_bytes)
5478 {
5479 return Err(ConsensusError::ScriptErrorWithCode {
5480 code: ScriptErrorCode::MinimalData,
5481 message: "OP_PICK: non-minimal script number".into(),
5482 });
5483 }
5484 let n_val = script_num_decode(&n_bytes, 4)?;
5487 if n_val < 0 || n_val as usize >= stack.len() {
5488 return Ok(false);
5489 }
5490 let n = n_val as usize;
5491 let len = stack.len();
5492 #[cfg(feature = "production")]
5493 {
5494 unsafe {
5496 let item = stack.get_unchecked(len - 1 - n);
5497 stack.push(item.clone());
5498 }
5499 }
5500 #[cfg(not(feature = "production"))]
5501 {
5502 let item = stack[stack.len() - 1 - n].clone();
5503 stack.push(item);
5504 }
5505 Ok(true)
5506 } else {
5507 Ok(false)
5508 }
5509 }
5510
5511 OP_ROLL => {
5513 if let Some(n_bytes) = stack.pop() {
5514 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5515 && !script_num_is_minimally_encoded(&n_bytes)
5516 {
5517 return Err(ConsensusError::ScriptErrorWithCode {
5518 code: ScriptErrorCode::MinimalData,
5519 message: "OP_ROLL: non-minimal script number".into(),
5520 });
5521 }
5522 let n_val = script_num_decode(&n_bytes, 4)?;
5525 if n_val < 0 || n_val as usize >= stack.len() {
5526 return Ok(false);
5527 }
5528 let n = n_val as usize;
5529 let len = stack.len();
5530 #[cfg(feature = "production")]
5531 {
5532 let idx = len - 1 - n;
5534 let item = stack.remove(idx);
5535 stack.push(item);
5536 }
5537 #[cfg(not(feature = "production"))]
5538 {
5539 let item = stack.remove(stack.len() - 1 - n);
5540 stack.push(item);
5541 }
5542 Ok(true)
5543 } else {
5544 Ok(false)
5545 }
5546 }
5547
5548 OP_ROT => {
5550 if stack.len() >= 3 {
5551 let top = stack.pop().unwrap();
5552 let second = stack.pop().unwrap();
5553 let third = stack.pop().unwrap();
5554 stack.push(second);
5555 stack.push(top);
5556 stack.push(third);
5557 Ok(true)
5558 } else {
5559 Ok(false)
5560 }
5561 }
5562
5563 OP_SWAP => {
5565 if stack.len() >= 2 {
5566 let top = stack.pop().unwrap();
5567 let second = stack.pop().unwrap();
5568 stack.push(top);
5569 stack.push(second);
5570 Ok(true)
5571 } else {
5572 Ok(false)
5573 }
5574 }
5575
5576 OP_TUCK => {
5578 if stack.len() >= 2 {
5579 let top = stack.pop().unwrap();
5580 let second = stack.pop().unwrap();
5581 stack.push(top.clone());
5582 stack.push(second);
5583 stack.push(top);
5584 Ok(true)
5585 } else {
5586 Ok(false)
5587 }
5588 }
5589
5590 OP_2DROP => {
5592 if stack.len() >= 2 {
5593 stack.pop();
5594 stack.pop();
5595 Ok(true)
5596 } else {
5597 Ok(false)
5598 }
5599 }
5600
5601 OP_2DUP => {
5603 if stack.len() >= 2 {
5604 let top = stack[stack.len() - 1].clone();
5605 let second = stack[stack.len() - 2].clone();
5606 stack.push(second);
5607 stack.push(top);
5608 Ok(true)
5609 } else {
5610 Ok(false)
5611 }
5612 }
5613
5614 OP_3DUP => {
5616 if stack.len() >= 3 {
5617 let top = stack[stack.len() - 1].clone();
5618 let second = stack[stack.len() - 2].clone();
5619 let third = stack[stack.len() - 3].clone();
5620 stack.push(third);
5621 stack.push(second);
5622 stack.push(top);
5623 Ok(true)
5624 } else {
5625 Ok(false)
5626 }
5627 }
5628
5629 OP_2OVER => {
5631 if stack.len() >= 4 {
5632 let fourth = stack[stack.len() - 4].clone();
5633 let third = stack[stack.len() - 3].clone();
5634 stack.push(fourth);
5635 stack.push(third);
5636 Ok(true)
5637 } else {
5638 Ok(false)
5639 }
5640 }
5641
5642 OP_2ROT => {
5645 if stack.len() >= 6 {
5646 let sixth = stack.remove(stack.len() - 6); let fifth = stack.remove(stack.len() - 5); stack.push(sixth);
5652 stack.push(fifth);
5653 Ok(true)
5654 } else {
5655 Ok(false)
5656 }
5657 }
5658
5659 OP_2SWAP => {
5661 if stack.len() >= 4 {
5662 let top = stack.pop().unwrap();
5663 let second = stack.pop().unwrap();
5664 let third = stack.pop().unwrap();
5665 let fourth = stack.pop().unwrap();
5666 stack.push(second);
5667 stack.push(top);
5668 stack.push(fourth);
5669 stack.push(third);
5670 Ok(true)
5671 } else {
5672 Ok(false)
5673 }
5674 }
5675
5676 OP_SIZE => {
5679 if let Some(item) = stack.last() {
5680 let size = item.len() as i64;
5681 stack.push(to_stack_element(&script_num_encode(size)));
5682 Ok(true)
5683 } else {
5684 Ok(false)
5685 }
5686 }
5687
5688 OP_1ADD => {
5693 if let Some(item) = stack.pop() {
5694 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5695 && !script_num_is_minimally_encoded(&item)
5696 {
5697 return Err(ConsensusError::ScriptErrorWithCode {
5698 code: ScriptErrorCode::MinimalData,
5699 message: "OP_1ADD: non-minimal script number".into(),
5700 });
5701 }
5702 let a = script_num_decode(&item, 4)?;
5703 stack.push(to_stack_element(&script_num_encode(a + 1)));
5704 Ok(true)
5705 } else {
5706 Ok(false)
5707 }
5708 }
5709 OP_1SUB => {
5711 if let Some(item) = stack.pop() {
5712 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5713 && !script_num_is_minimally_encoded(&item)
5714 {
5715 return Err(ConsensusError::ScriptErrorWithCode {
5716 code: ScriptErrorCode::MinimalData,
5717 message: "OP_1SUB: non-minimal script number".into(),
5718 });
5719 }
5720 let a = script_num_decode(&item, 4)?;
5721 stack.push(to_stack_element(&script_num_encode(a - 1)));
5722 Ok(true)
5723 } else {
5724 Ok(false)
5725 }
5726 }
5727 OP_2MUL => Err(ConsensusError::ScriptErrorWithCode {
5729 code: ScriptErrorCode::DisabledOpcode,
5730 message: "OP_2MUL is disabled".into(),
5731 }),
5732 OP_2DIV => Err(ConsensusError::ScriptErrorWithCode {
5734 code: ScriptErrorCode::DisabledOpcode,
5735 message: "OP_2DIV is disabled".into(),
5736 }),
5737 OP_NEGATE => {
5739 if let Some(item) = stack.pop() {
5740 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5741 && !script_num_is_minimally_encoded(&item)
5742 {
5743 return Err(ConsensusError::ScriptErrorWithCode {
5744 code: ScriptErrorCode::MinimalData,
5745 message: "OP_NEGATE: non-minimal script number".into(),
5746 });
5747 }
5748 let a = script_num_decode(&item, 4)?;
5749 stack.push(to_stack_element(&script_num_encode(-a)));
5750 Ok(true)
5751 } else {
5752 Ok(false)
5753 }
5754 }
5755 OP_ABS => {
5757 if let Some(item) = stack.pop() {
5758 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5759 && !script_num_is_minimally_encoded(&item)
5760 {
5761 return Err(ConsensusError::ScriptErrorWithCode {
5762 code: ScriptErrorCode::MinimalData,
5763 message: "OP_ABS: non-minimal script number".into(),
5764 });
5765 }
5766 let a = script_num_decode(&item, 4)?;
5767 stack.push(to_stack_element(&script_num_encode(a.abs())));
5768 Ok(true)
5769 } else {
5770 Ok(false)
5771 }
5772 }
5773 OP_NOT => {
5775 if let Some(item) = stack.pop() {
5776 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5777 && !script_num_is_minimally_encoded(&item)
5778 {
5779 return Err(ConsensusError::ScriptErrorWithCode {
5780 code: ScriptErrorCode::MinimalData,
5781 message: "OP_NOT: non-minimal script number".into(),
5782 });
5783 }
5784 let a = script_num_decode(&item, 4)?;
5785 stack.push(to_stack_element(&script_num_encode(if a == 0 {
5786 1
5787 } else {
5788 0
5789 })));
5790 Ok(true)
5791 } else {
5792 Ok(false)
5793 }
5794 }
5795 OP_0NOTEQUAL => {
5797 if let Some(item) = stack.pop() {
5798 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
5799 && !script_num_is_minimally_encoded(&item)
5800 {
5801 return Err(ConsensusError::ScriptErrorWithCode {
5802 code: ScriptErrorCode::MinimalData,
5803 message: "OP_0NOTEQUAL: non-minimal script number".into(),
5804 });
5805 }
5806 let a = script_num_decode(&item, 4)?;
5807 stack.push(to_stack_element(&script_num_encode(if a != 0 {
5808 1
5809 } else {
5810 0
5811 })));
5812 Ok(true)
5813 } else {
5814 Ok(false)
5815 }
5816 }
5817 OP_ADD => {
5818 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5819 let len = stack.len();
5820 if !script_num_is_minimally_encoded(&stack[len - 1])
5821 || !script_num_is_minimally_encoded(&stack[len - 2])
5822 {
5823 return Err(ConsensusError::ScriptErrorWithCode {
5824 code: ScriptErrorCode::MinimalData,
5825 message: "OP_ADD: non-minimal script number".into(),
5826 });
5827 }
5828 }
5829 arithmetic::op_add(stack)
5830 }
5831 OP_SUB => {
5832 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5833 let len = stack.len();
5834 if !script_num_is_minimally_encoded(&stack[len - 1])
5835 || !script_num_is_minimally_encoded(&stack[len - 2])
5836 {
5837 return Err(ConsensusError::ScriptErrorWithCode {
5838 code: ScriptErrorCode::MinimalData,
5839 message: "OP_SUB: non-minimal script number".into(),
5840 });
5841 }
5842 }
5843 arithmetic::op_sub(stack)
5844 }
5845 OP_MUL => arithmetic::op_mul_disabled(),
5846 OP_DIV => arithmetic::op_div_disabled(),
5847 OP_MOD => arithmetic::op_mod_disabled(),
5848 OP_LSHIFT => arithmetic::op_lshift_disabled(),
5849 OP_RSHIFT => arithmetic::op_rshift_disabled(),
5850 OP_BOOLAND => {
5851 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5852 let len = stack.len();
5853 if !script_num_is_minimally_encoded(&stack[len - 1])
5854 || !script_num_is_minimally_encoded(&stack[len - 2])
5855 {
5856 return Err(ConsensusError::ScriptErrorWithCode {
5857 code: ScriptErrorCode::MinimalData,
5858 message: "OP_BOOLAND: non-minimal script number".into(),
5859 });
5860 }
5861 }
5862 arithmetic::op_booland(stack)
5863 }
5864 OP_BOOLOR => {
5865 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5866 let len = stack.len();
5867 if !script_num_is_minimally_encoded(&stack[len - 1])
5868 || !script_num_is_minimally_encoded(&stack[len - 2])
5869 {
5870 return Err(ConsensusError::ScriptErrorWithCode {
5871 code: ScriptErrorCode::MinimalData,
5872 message: "OP_BOOLOR: non-minimal script number".into(),
5873 });
5874 }
5875 }
5876 arithmetic::op_boolor(stack)
5877 }
5878 OP_NUMEQUAL => {
5879 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5880 let len = stack.len();
5881 if !script_num_is_minimally_encoded(&stack[len - 1])
5882 || !script_num_is_minimally_encoded(&stack[len - 2])
5883 {
5884 return Err(ConsensusError::ScriptErrorWithCode {
5885 code: ScriptErrorCode::MinimalData,
5886 message: "OP_NUMEQUAL: non-minimal script number".into(),
5887 });
5888 }
5889 }
5890 arithmetic::op_numequal(stack)
5891 }
5892 OP_NUMEQUALVERIFY => {
5893 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5894 let len = stack.len();
5895 if !script_num_is_minimally_encoded(&stack[len - 1])
5896 || !script_num_is_minimally_encoded(&stack[len - 2])
5897 {
5898 return Err(ConsensusError::ScriptErrorWithCode {
5899 code: ScriptErrorCode::MinimalData,
5900 message: "OP_NUMEQUALVERIFY: non-minimal script number".into(),
5901 });
5902 }
5903 }
5904 arithmetic::op_numequalverify(stack)
5905 }
5906 OP_NUMNOTEQUAL => {
5907 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5908 let len = stack.len();
5909 if !script_num_is_minimally_encoded(&stack[len - 1])
5910 || !script_num_is_minimally_encoded(&stack[len - 2])
5911 {
5912 return Err(ConsensusError::ScriptErrorWithCode {
5913 code: ScriptErrorCode::MinimalData,
5914 message: "OP_NUMNOTEQUAL: non-minimal script number".into(),
5915 });
5916 }
5917 }
5918 arithmetic::op_numnotequal(stack)
5919 }
5920 OP_LESSTHAN => {
5921 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5922 let len = stack.len();
5923 if !script_num_is_minimally_encoded(&stack[len - 1])
5924 || !script_num_is_minimally_encoded(&stack[len - 2])
5925 {
5926 return Err(ConsensusError::ScriptErrorWithCode {
5927 code: ScriptErrorCode::MinimalData,
5928 message: "OP_LESSTHAN: non-minimal script number".into(),
5929 });
5930 }
5931 }
5932 arithmetic::op_lessthan(stack)
5933 }
5934 OP_GREATERTHAN => {
5935 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5936 let len = stack.len();
5937 if !script_num_is_minimally_encoded(&stack[len - 1])
5938 || !script_num_is_minimally_encoded(&stack[len - 2])
5939 {
5940 return Err(ConsensusError::ScriptErrorWithCode {
5941 code: ScriptErrorCode::MinimalData,
5942 message: "OP_GREATERTHAN: non-minimal script number".into(),
5943 });
5944 }
5945 }
5946 arithmetic::op_greaterthan(stack)
5947 }
5948 OP_LESSTHANOREQUAL => {
5949 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5950 let len = stack.len();
5951 if !script_num_is_minimally_encoded(&stack[len - 1])
5952 || !script_num_is_minimally_encoded(&stack[len - 2])
5953 {
5954 return Err(ConsensusError::ScriptErrorWithCode {
5955 code: ScriptErrorCode::MinimalData,
5956 message: "OP_LESSTHANOREQUAL: non-minimal script number".into(),
5957 });
5958 }
5959 }
5960 arithmetic::op_lessthanorequal(stack)
5961 }
5962 OP_GREATERTHANOREQUAL => {
5963 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5964 let len = stack.len();
5965 if !script_num_is_minimally_encoded(&stack[len - 1])
5966 || !script_num_is_minimally_encoded(&stack[len - 2])
5967 {
5968 return Err(ConsensusError::ScriptErrorWithCode {
5969 code: ScriptErrorCode::MinimalData,
5970 message: "OP_GREATERTHANOREQUAL: non-minimal script number".into(),
5971 });
5972 }
5973 }
5974 arithmetic::op_greaterthanorequal(stack)
5975 }
5976 OP_MIN => {
5977 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5978 let len = stack.len();
5979 if !script_num_is_minimally_encoded(&stack[len - 1])
5980 || !script_num_is_minimally_encoded(&stack[len - 2])
5981 {
5982 return Err(ConsensusError::ScriptErrorWithCode {
5983 code: ScriptErrorCode::MinimalData,
5984 message: "OP_MIN: non-minimal script number".into(),
5985 });
5986 }
5987 }
5988 arithmetic::op_min(stack)
5989 }
5990 OP_MAX => {
5991 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 2 {
5992 let len = stack.len();
5993 if !script_num_is_minimally_encoded(&stack[len - 1])
5994 || !script_num_is_minimally_encoded(&stack[len - 2])
5995 {
5996 return Err(ConsensusError::ScriptErrorWithCode {
5997 code: ScriptErrorCode::MinimalData,
5998 message: "OP_MAX: non-minimal script number".into(),
5999 });
6000 }
6001 }
6002 arithmetic::op_max(stack)
6003 }
6004 OP_WITHIN => {
6005 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0 && stack.len() >= 3 {
6006 let len = stack.len();
6007 if !script_num_is_minimally_encoded(&stack[len - 1])
6008 || !script_num_is_minimally_encoded(&stack[len - 2])
6009 || !script_num_is_minimally_encoded(&stack[len - 3])
6010 {
6011 return Err(ConsensusError::ScriptErrorWithCode {
6012 code: ScriptErrorCode::MinimalData,
6013 message: "OP_WITHIN: non-minimal script number".into(),
6014 });
6015 }
6016 }
6017 arithmetic::op_within(stack)
6018 }
6019
6020 OP_CODESEPARATOR => Ok(true),
6022
6023 OP_NOP1 | OP_NOP5..=OP_NOP10 => upgradable_nop(flags),
6025
6026 OP_CHECKTEMPLATEVERIFY => {
6029 #[cfg(feature = "ctv")]
6030 if flags & flags::SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH != 0 {
6031 return Err(ConsensusError::ScriptErrorWithCode {
6032 code: ScriptErrorCode::TxInvalid,
6033 message: "OP_CHECKTEMPLATEVERIFY requires transaction context".into(),
6034 });
6035 }
6036 upgradable_nop(flags)
6037 }
6038
6039 OP_DISABLED_STRING_RANGE_START..=OP_DISABLED_STRING_RANGE_END
6041 | OP_DISABLED_BITWISE_RANGE_START..=OP_DISABLED_BITWISE_RANGE_END => {
6042 Err(ConsensusError::ScriptErrorWithCode {
6043 code: ScriptErrorCode::DisabledOpcode,
6044 message: format!("Disabled opcode 0x{opcode:02x}").into(),
6045 })
6046 }
6047
6048 OP_1NEGATE => {
6050 stack.push(to_stack_element(&[0x81]));
6051 Ok(true)
6052 }
6053
6054 OP_CHECKMULTISIG => {
6059 strictenc_nocheck_multisig(stack, flags)?;
6060 let Some(m) = pop_nocheck_multisig(stack) else {
6061 return Ok(false);
6062 };
6063 stack.push(to_stack_element(script_bool_bytes(m == 0)));
6065 Ok(true)
6066 }
6067
6068 OP_CHECKMULTISIGVERIFY => {
6070 strictenc_nocheck_multisig(stack, flags)?;
6071 let Some(m) = pop_nocheck_multisig(stack) else {
6072 return Ok(false);
6073 };
6074 Ok(m == 0)
6075 }
6076
6077 _ => Ok(false),
6079 }
6080}
6081
6082#[inline(always)]
6085fn parse_p2sh_p2pkh_pushes(script_sig: &[u8]) -> Option<(&[u8], &[u8], &[u8])> {
6086 let mut i = 0;
6087 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
6088 i += adv1;
6089 if i >= script_sig.len() {
6090 return None;
6091 }
6092 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
6093 i += adv2;
6094 if i >= script_sig.len() {
6095 return None;
6096 }
6097 let (adv3, r_start, r_end) = parse_one_data_push(script_sig, i)?;
6098 i += adv3;
6099 if i != script_sig.len() {
6100 return None;
6101 }
6102 let sig = &script_sig[s_start..s_end];
6103 let pubkey = &script_sig[p_start..p_end];
6104 let redeem = &script_sig[r_start..r_end];
6105 if sig.is_empty() || redeem.len() != 25 {
6106 return None;
6107 }
6108 if redeem[0] != OP_DUP
6109 || redeem[1] != OP_HASH160
6110 || redeem[2] != PUSH_20_BYTES
6111 || redeem[23] != OP_EQUALVERIFY
6112 || redeem[24] != OP_CHECKSIG
6113 {
6114 return None;
6115 }
6116 Some((sig, pubkey, redeem))
6117}
6118
6119#[inline(always)]
6122fn parse_p2sh_p2pk_pushes(script_sig: &[u8]) -> Option<(&[u8], &[u8], &[u8])> {
6123 let mut i = 0;
6124 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
6125 i += adv1;
6126 if i >= script_sig.len() {
6127 return None;
6128 }
6129 let (adv2, r_start, r_end) = parse_one_data_push(script_sig, i)?;
6130 i += adv2;
6131 if i != script_sig.len() {
6132 return None;
6133 }
6134 let sig = &script_sig[s_start..s_end];
6135 let redeem = &script_sig[r_start..r_end];
6136 if sig.is_empty() {
6137 return None;
6138 }
6139 let pubkey = canonical_p2pk_pubkey(redeem)?;
6140 Some((sig, pubkey, redeem))
6141}
6142
6143#[cfg(feature = "production")]
6147#[inline(always)]
6148pub(crate) fn parse_p2sh_p2pkh_for_precompute(script_sig: &[u8]) -> Option<(u8, &[u8])> {
6149 let (sig, _pubkey, redeem) = parse_p2sh_p2pkh_pushes(script_sig)?;
6150 Some((sig[sig.len() - 1], redeem))
6151}
6152
6153#[inline(always)]
6157pub(crate) fn parse_p2pkh_script_sig(script_sig: &[u8]) -> Option<(&[u8], &[u8])> {
6158 let mut i = 0;
6159 let (adv1, s_start, s_end) = parse_one_data_push(script_sig, i)?;
6160 i += adv1;
6161 if i >= script_sig.len() {
6162 return None;
6163 }
6164 let (adv2, p_start, p_end) = parse_one_data_push(script_sig, i)?;
6165 i += adv2;
6166 if i != script_sig.len() {
6167 return None;
6168 }
6169 Some((&script_sig[s_start..s_end], &script_sig[p_start..p_end]))
6170}
6171
6172pub(crate) fn parse_p2pk_script_sig(script_sig: &[u8]) -> Option<&[u8]> {
6175 let (advance, data_start, data_end) = parse_one_data_push(script_sig, 0)?;
6176 if advance != script_sig.len() {
6177 return None;
6178 }
6179 Some(&script_sig[data_start..data_end])
6180}
6181
6182fn parse_one_data_push(script: &[u8], i: usize) -> Option<(usize, usize, usize)> {
6184 if i >= script.len() {
6185 return None;
6186 }
6187 let opcode = script[i];
6188 let (advance, data_start, data_end) = if opcode == OP_0 {
6189 return None;
6190 } else if opcode <= 0x4b {
6191 let len = opcode as usize;
6192 if i + 1 + len > script.len() {
6193 return None;
6194 }
6195 (1 + len, i + 1, i + 1 + len)
6196 } else if opcode == OP_PUSHDATA1 {
6197 if i + 1 >= script.len() {
6198 return None;
6199 }
6200 let len = script[i + 1] as usize;
6201 if i + 2 + len > script.len() {
6202 return None;
6203 }
6204 (2 + len, i + 2, i + 2 + len)
6205 } else if opcode == OP_PUSHDATA2 {
6206 if i + 2 >= script.len() {
6207 return None;
6208 }
6209 let len = u16::from_le_bytes([script[i + 1], script[i + 2]]) as usize;
6210 if i + 3 + len > script.len() {
6211 return None;
6212 }
6213 (3 + len, i + 3, i + 3 + len)
6214 } else if opcode == OP_PUSHDATA4 {
6215 if i + 4 >= script.len() {
6216 return None;
6217 }
6218 let len = u32::from_le_bytes([script[i + 1], script[i + 2], script[i + 3], script[i + 4]])
6219 as usize;
6220 if i + 5 + len > script.len() {
6221 return None;
6222 }
6223 (5 + len, i + 5, i + 5 + len)
6224 } else {
6225 return None;
6226 };
6227 Some((advance, data_start, data_end))
6228}
6229
6230#[cfg_attr(feature = "spec-lock", spec_locked("5.2.1", "P2SHPushOnlyCheck"))]
6233pub fn p2sh_push_only_check(script_sig: &[u8]) -> bool {
6234 let mut i = 0;
6235 while i < script_sig.len() {
6236 let opcode = script_sig[i];
6237 if !is_push_opcode(opcode) {
6238 return false;
6239 }
6240 if opcode == OP_0 || opcode == OP_1NEGATE || (OP_1..=OP_16).contains(&opcode) {
6241 i += 1;
6242 continue;
6243 }
6244 let Some((advance, _, _)) = parse_one_data_push(script_sig, i) else {
6245 return false;
6246 };
6247 i += advance;
6248 }
6249 true
6250}
6251
6252#[allow(dead_code)]
6254fn parse_script_sig_push_only(script_sig: &[u8]) -> Option<Vec<StackElement>> {
6255 let mut out = Vec::new();
6256 let mut i = 0;
6257 while i < script_sig.len() {
6258 let opcode = script_sig[i];
6259 if !is_push_opcode(opcode) {
6260 return None;
6261 }
6262 if opcode == OP_0 {
6263 out.push(to_stack_element(&[]));
6264 i += 1;
6265 continue;
6266 }
6267 if opcode == OP_1NEGATE || (OP_1..=OP_16).contains(&opcode) {
6268 out.push(to_stack_element(&script_num_encode(
6270 script_num_from_opcode(opcode),
6271 )));
6272 i += 1;
6273 continue;
6274 }
6275 let (advance, data_start, data_end) = parse_one_data_push(script_sig, i)?;
6276 out.push(to_stack_element(&script_sig[data_start..data_end]));
6277 i += advance;
6278 }
6279 Some(out)
6280}
6281
6282enum BorrowedPush<'a> {
6285 Borrowed(&'a [u8]),
6286 Number(ScriptNumBytes),
6287}
6288
6289impl AsRef<[u8]> for BorrowedPush<'_> {
6290 fn as_ref(&self) -> &[u8] {
6291 match self {
6292 BorrowedPush::Borrowed(bytes) => bytes,
6293 BorrowedPush::Number(encoded) => &encoded[..],
6294 }
6295 }
6296}
6297
6298fn parse_borrowed_pushes(script_sig: &[u8]) -> Option<Vec<BorrowedPush<'_>>> {
6300 let mut out = Vec::new();
6301 let mut i = 0;
6302 while i < script_sig.len() {
6303 let opcode = script_sig[i];
6304 if !is_push_opcode(opcode) {
6305 return None;
6306 }
6307 if opcode == OP_0 {
6308 out.push(BorrowedPush::Borrowed(&[]));
6309 i += 1;
6310 continue;
6311 }
6312 if opcode == OP_1NEGATE || (OP_1..=OP_16).contains(&opcode) {
6313 out.push(BorrowedPush::Number(script_num_encode(
6314 script_num_from_opcode(opcode),
6315 )));
6316 i += 1;
6317 continue;
6318 }
6319 let (advance, data_start, data_end) = parse_one_data_push(script_sig, i)?;
6320 out.push(BorrowedPush::Borrowed(&script_sig[data_start..data_end]));
6321 i += advance;
6322 }
6323 Some(out)
6324}
6325
6326fn checkmultisig_window<T: AsRef<[u8]>>(
6332 items: &[T],
6333 m: u8,
6334 exact: bool,
6335) -> Option<(&[u8], Vec<&[u8]>)> {
6336 let m = m as usize;
6337 let need = m + 1;
6338 if m == 0 || items.len() < need {
6339 return None;
6340 }
6341 if exact && items.len() != need {
6342 return None;
6343 }
6344 let sig_at = items.len() - m;
6345 let dummy = items[sig_at - 1].as_ref();
6346 let signatures = items[sig_at..].iter().map(|item| item.as_ref()).collect();
6347 Some((dummy, signatures))
6348}
6349
6350fn parse_redeem_multisig(redeem: &[u8]) -> Option<(u8, u8, Vec<&[u8]>)> {
6358 if redeem.len() < 4 {
6359 return None;
6360 }
6361 if redeem[redeem.len() - 1] != OP_CHECKMULTISIG {
6363 return None;
6364 }
6365 let n_op = redeem[redeem.len() - 2];
6366 if !(OP_1..=OP_16).contains(&n_op) {
6367 return None;
6368 }
6369 let n = (n_op - OP_1 + 1) as usize;
6370 let m_op = redeem[0];
6371 if !(OP_1..=OP_16).contains(&m_op) {
6372 return None;
6373 }
6374 let m = m_op - OP_1 + 1;
6375 if (m as usize) > n || m == 0 {
6376 return None;
6377 }
6378 let mut i = 1;
6379 let mut pubkeys = Vec::with_capacity(n);
6380 for _ in 0..n {
6381 if i >= redeem.len().saturating_sub(2) {
6382 return None;
6383 }
6384 let first = redeem[i];
6385 let (pk_start, pk_len) = if first == PUSH_33_BYTES {
6386 (i + 1, PUSH_33_BYTES as usize)
6387 } else if first == PUSH_65_BYTES {
6388 (i + 1, PUSH_65_BYTES as usize)
6389 } else {
6390 return None;
6391 };
6392 if pk_start + pk_len > redeem.len().saturating_sub(2) {
6393 return None;
6394 }
6395 let pk = &redeem[pk_start..pk_start + pk_len];
6396 let hdr = pk[0];
6397 if !(hdr == 0x02 || hdr == 0x03 || hdr == 0x04) {
6398 return None;
6399 }
6400 if (hdr == 0x02 || hdr == 0x03) && pk_len != 33 {
6401 return None;
6402 }
6403 if hdr == 0x04 && pk_len != 65 {
6404 return None;
6405 }
6406 pubkeys.push(pk);
6407 i = pk_start + pk_len;
6408 }
6409 if i != redeem.len() - 2 {
6411 return None;
6412 }
6413 Some((m, n as u8, pubkeys))
6414}
6415
6416#[cfg(test)]
6417mod parse_redeem_multisig_tests {
6418 use super::*;
6419
6420 #[test]
6421 fn accepts_push_encoded_compressed_2of3() {
6422 let mut redeem = vec![OP_2];
6424 for i in 0..3u8 {
6425 redeem.push(PUSH_33_BYTES);
6426 let mut pk = [0u8; 33];
6427 pk[0] = 0x02;
6428 pk[1] = i + 1;
6429 redeem.extend_from_slice(&pk);
6430 }
6431 redeem.push(OP_3);
6432 redeem.push(OP_CHECKMULTISIG);
6433 let (m, n, pks) = parse_redeem_multisig(&redeem).expect("push-encoded redeem");
6434 assert_eq!(m, 2);
6435 assert_eq!(n, 3);
6436 assert_eq!(pks.len(), 3);
6437 assert_eq!(pks[0][0], 0x02);
6438 }
6439
6440 #[test]
6441 fn rejects_raw_key_without_a_push_opcode() {
6442 let mut compressed = vec![OP_1];
6443 let mut pk33 = [0u8; PUSH_33_BYTES as usize];
6444 pk33[0] = 3;
6445 compressed.extend_from_slice(&pk33);
6446 compressed.push(OP_1);
6447 compressed.push(OP_CHECKMULTISIG);
6448 assert!(parse_redeem_multisig(&compressed).is_none());
6449
6450 let mut uncompressed = vec![OP_1];
6451 let pk65 = [4u8; PUSH_65_BYTES as usize];
6452 uncompressed.extend_from_slice(&pk65);
6453 uncompressed.push(OP_1);
6454 uncompressed.push(OP_CHECKMULTISIG);
6455 assert!(parse_redeem_multisig(&uncompressed).is_none());
6456 }
6457
6458 #[test]
6459 fn rejects_trailing_opcodes() {
6460 let mut redeem = vec![OP_1, PUSH_33_BYTES];
6461 let mut pk = [0u8; 33];
6462 pk[0] = 0x02;
6463 redeem.extend_from_slice(&pk);
6464 redeem.push(OP_1);
6465 redeem.push(OP_CHECKMULTISIG);
6466 redeem.push(OP_DROP);
6467 assert!(parse_redeem_multisig(&redeem).is_none());
6468 }
6469
6470 #[test]
6471 fn checkmultisig_window_is_the_top_m_signatures() {
6472 let items = vec![
6473 to_stack_element(&[]),
6474 to_stack_element(&[0x11]),
6475 to_stack_element(&[0x22]),
6476 ];
6477 let (dummy, sigs) = checkmultisig_window(&items, 1, false).expect("legacy window");
6478 assert_eq!(dummy, &[0x11]);
6479 assert_eq!(sigs, vec![&[0x22][..]]);
6480 assert!(checkmultisig_window(&items, 1, true).is_none());
6481
6482 let exact = vec![to_stack_element(&[]), to_stack_element(&[0x22])];
6483 let (dummy, sigs) = checkmultisig_window(&exact, 1, true).expect("witness window");
6484 assert!(dummy.is_empty());
6485 assert_eq!(sigs, vec![&[0x22][..]]);
6486 assert!(checkmultisig_window(&exact, 2, false).is_none());
6487 }
6488
6489 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
6490 #[test]
6491 fn p2sh_multisig_fast_path_rejects_a_signature_above_the_window() {
6492 use crate::script::flags::{
6493 SCRIPT_VERIFY_DERSIG, SCRIPT_VERIFY_P2SH, SCRIPT_VERIFY_WITNESS,
6494 };
6495 use crate::transaction_hash::compute_legacy_sighash_nocache;
6496 use crate::types::{Network, OutPoint, Transaction, TransactionInput, TransactionOutput};
6497 use secp256k1::{Message, PublicKey, Secp256k1, SecretKey};
6498
6499 let secp = Secp256k1::new();
6500 let sk = SecretKey::from_slice(&[0x41; 32]).expect("secret");
6501 let pk1 = PublicKey::from_secret_key(&secp, &sk).serialize();
6502 let pk2 =
6503 PublicKey::from_secret_key(&secp, &SecretKey::from_slice(&[0x42; 32]).expect("secret"))
6504 .serialize();
6505 let mut redeem = vec![OP_1, PUSH_33_BYTES];
6506 redeem.extend_from_slice(&pk1);
6507 redeem.push(PUSH_33_BYTES);
6508 redeem.extend_from_slice(&pk2);
6509 redeem.push(OP_2);
6510 redeem.push(OP_CHECKMULTISIG);
6511
6512 let hash160 = Ripemd160::digest(OptimizedSha256::new().hash(&redeem));
6513 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
6514 script_pubkey.extend_from_slice(&hash160);
6515 script_pubkey.push(OP_EQUAL);
6516
6517 let mut tx = Transaction {
6518 version: 1,
6519 inputs: vec![TransactionInput {
6520 prevout: OutPoint {
6521 hash: [0x11; 32],
6522 index: 0,
6523 },
6524 script_sig: Vec::new().into(),
6525 sequence: 0xffff_ffff,
6526 }]
6527 .into(),
6528 outputs: vec![TransactionOutput {
6529 value: 1_000,
6530 script_pubkey: vec![OP_1].into(),
6531 }]
6532 .into(),
6533 lock_time: 0,
6534 };
6535 let sighash = compute_legacy_sighash_nocache(&tx, 0, &redeem, 0x01);
6536 let mut sig = secp
6537 .sign_ecdsa(&Message::from_digest_slice(&sighash).expect("digest"), &sk)
6538 .serialize_der()
6539 .to_vec();
6540 sig.push(0x01);
6541
6542 let mut exact = vec![OP_0];
6543 exact.push(sig.len() as u8);
6544 exact.extend_from_slice(&sig);
6545 exact.push(redeem.len() as u8);
6546 exact.extend_from_slice(&redeem);
6547 tx.inputs[0].script_sig = exact.into();
6548
6549 let flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS | SCRIPT_VERIFY_DERSIG;
6551 let values = [50_000_000i64];
6552 let prevouts: [&[u8]; 1] = [&script_pubkey];
6553 let height = Some(crate::constants::BIP147_ACTIVATION_MAINNET);
6554 let verdict = |tx: &Transaction| {
6555 try_verify_p2sh_multisig_fast_path(
6556 &tx.inputs[0].script_sig,
6557 &script_pubkey,
6558 flags,
6559 tx,
6560 0,
6561 &values,
6562 &prevouts,
6563 height,
6564 Network::Mainnet,
6565 None,
6566 None,
6567 )
6568 };
6569 assert_eq!(
6570 verdict(&tx).expect("handled").expect("no script error"),
6571 true,
6572 "dummy plus one signature"
6573 );
6574
6575 let garbage = [0x22u8; 9];
6576 let mut extra = vec![OP_0];
6577 extra.push(sig.len() as u8);
6578 extra.extend_from_slice(&sig);
6579 extra.push(garbage.len() as u8);
6580 extra.extend_from_slice(&garbage);
6581 extra.push(redeem.len() as u8);
6582 extra.extend_from_slice(&redeem);
6583 tx.inputs[0].script_sig = extra.into();
6584 assert!(
6585 !matches!(verdict(&tx), Some(Ok(true))),
6586 "a non-matching push above the real signature is not in the window"
6587 );
6588 }
6589
6590 #[cfg(feature = "production")]
6593 #[test]
6594 fn nested_p2wsh_not_claimed_as_p2wpkh_in_p2sh() {
6595 use crate::types::{OutPoint, Transaction, TransactionInput};
6596 let mut program = [0u8; 32];
6598 program[0] = 0x50;
6599 let mut script_sig = vec![34u8, OP_0, PUSH_32_BYTES];
6600 script_sig.extend_from_slice(&program);
6601 let script_pubkey = {
6602 let h = Ripemd160::digest(OptimizedSha256::new().hash(&script_sig[1..]));
6603 let mut spk = vec![OP_HASH160, PUSH_20_BYTES];
6604 spk.extend_from_slice(&h);
6605 spk.push(OP_EQUAL);
6606 spk
6607 };
6608 let witness: crate::witness::Witness = vec![vec![0u8; 72], vec![OP_1, OP_1]];
6611 let tx = Transaction {
6612 version: 1,
6613 inputs: vec![TransactionInput {
6614 prevout: OutPoint {
6615 hash: [0u8; 32],
6616 index: 0,
6617 },
6618 sequence: 0xffff_ffff,
6619 script_sig: script_sig.clone(),
6620 }]
6621 .into(),
6622 outputs: vec![].into(),
6623 lock_time: 0,
6624 };
6625 let result = try_verify_p2wpkh_in_p2sh_fast_path(
6626 &script_sig,
6627 &script_pubkey,
6628 &witness,
6629 0x01, &tx,
6631 0,
6632 &[0i64],
6633 &[],
6634 Some(497_110),
6635 crate::types::Network::Mainnet,
6636 None,
6637 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
6638 None,
6639 );
6640 assert!(
6641 result.is_none(),
6642 "nested P2WSH must fall through, got {:?}",
6643 result
6644 );
6645 }
6646}
6647
6648fn script_num_from_opcode(opcode: u8) -> i64 {
6650 match opcode {
6651 OP_1NEGATE => -1,
6652 OP_1 => 1,
6653 OP_2 => 2,
6654 OP_3 => 3,
6655 OP_4 => 4,
6656 OP_5 => 5,
6657 OP_6 => 6,
6658 OP_7 => 7,
6659 OP_8 => 8,
6660 OP_9 => 9,
6661 OP_10 => 10,
6662 OP_11 => 11,
6663 OP_12 => 12,
6664 OP_13 => 13,
6665 OP_14 => 14,
6666 OP_15 => 15,
6667 OP_16 => 16,
6668 _ => 0,
6669 }
6670}
6671
6672#[inline]
6676fn redeem_push_is_canonical(script_sig: &[u8], redeem: &[u8]) -> bool {
6677 let len = redeem.len();
6678 if len < 76 {
6679 return script_sig.len() == len + 1
6680 && script_sig[0] as usize == len
6681 && &script_sig[1..] == redeem;
6682 }
6683 script_sig == serialize_push_data(redeem).as_slice()
6684}
6685
6686pub(crate) fn serialize_push_data(data: &[u8]) -> Vec<u8> {
6687 let len = data.len();
6688 let mut result = Vec::with_capacity(len + 5);
6689 if len < 76 {
6690 result.push(len as u8);
6691 } else if len < 256 {
6692 result.push(OP_PUSHDATA1);
6693 result.push(len as u8);
6694 } else if len < 65536 {
6695 result.push(OP_PUSHDATA2);
6696 result.push((len & 0xff) as u8);
6697 result.push(((len >> 8) & 0xff) as u8);
6698 } else {
6699 result.push(OP_PUSHDATA4);
6700 result.push((len & 0xff) as u8);
6701 result.push(((len >> 8) & 0xff) as u8);
6702 result.push(((len >> 16) & 0xff) as u8);
6703 result.push(((len >> 24) & 0xff) as u8);
6704 }
6705 result.extend_from_slice(data);
6706 result
6707}
6708
6709fn with_push_pattern<R>(data: &[u8], f: impl FnOnce(&[u8]) -> R) -> R {
6711 let len = data.len();
6712 if len < 76 {
6713 let mut buf = [0u8; 76];
6714 buf[0] = len as u8;
6715 buf[1..1 + len].copy_from_slice(data);
6716 f(&buf[..1 + len])
6717 } else {
6718 f(serialize_push_data(data).as_slice())
6719 }
6720}
6721
6722#[inline]
6724fn script_get_op_advance(script: &[u8], pc: usize) -> Option<usize> {
6725 if pc >= script.len() {
6726 return None;
6727 }
6728 let opcode = script[pc];
6729 let advance = if opcode <= 0x4b {
6730 1 + opcode as usize
6731 } else if opcode == OP_PUSHDATA1 && pc + 1 < script.len() {
6732 2 + script[pc + 1] as usize
6733 } else if opcode == OP_PUSHDATA2 && pc + 2 < script.len() {
6734 3 + ((script[pc + 1] as usize) | ((script[pc + 2] as usize) << 8))
6735 } else if opcode == OP_PUSHDATA4 && pc + 4 < script.len() {
6736 5 + ((script[pc + 1] as usize)
6737 | ((script[pc + 2] as usize) << 8)
6738 | ((script[pc + 3] as usize) << 16)
6739 | ((script[pc + 4] as usize) << 24))
6740 } else {
6741 1
6742 };
6743 let next = pc + advance;
6744 if next > script.len() {
6745 None
6746 } else {
6747 Some(next)
6748 }
6749}
6750
6751fn multisig_script_code<'a, S: AsRef<[u8]>>(
6753 script: &'a [u8],
6754 signatures: &[S],
6755) -> std::borrow::Cow<'a, [u8]> {
6756 let mut cleaned = std::borrow::Cow::Borrowed(script);
6757 for sig in signatures {
6758 let sig = sig.as_ref();
6759 if sig.is_empty() {
6760 continue;
6761 }
6762 if sig.len().saturating_add(1) > cleaned.len() {
6764 continue;
6765 }
6766 let next = with_push_pattern(sig, |pattern| {
6767 match find_and_delete(cleaned.as_ref(), pattern) {
6768 std::borrow::Cow::Owned(next) => Some(next),
6769 std::borrow::Cow::Borrowed(_) => None,
6770 }
6771 });
6772 if let Some(next) = next {
6773 cleaned = std::borrow::Cow::Owned(next);
6774 }
6775 }
6776 cleaned
6777}
6778
6779#[cfg_attr(feature = "spec-lock", spec_locked("5.1.1", "FindAndDelete"))]
6785#[inline]
6786pub(crate) fn find_and_delete<'a>(script: &'a [u8], pattern: &[u8]) -> std::borrow::Cow<'a, [u8]> {
6787 if pattern.is_empty() {
6788 return std::borrow::Cow::Borrowed(script);
6789 }
6790 if pattern.len() > script.len() {
6791 return std::borrow::Cow::Borrowed(script);
6792 }
6793 if !script.windows(pattern.len()).any(|w| w == pattern) {
6798 return std::borrow::Cow::Borrowed(script);
6799 }
6800 let end = script.len();
6801 let mut n_found = 0usize;
6802 let mut result = Vec::new();
6803 let mut pc = 0usize;
6804 let mut pc2 = 0usize;
6805
6806 loop {
6807 result.extend_from_slice(&script[pc2..pc]);
6808 while end - pc >= pattern.len() && script[pc..pc + pattern.len()] == *pattern {
6809 pc += pattern.len();
6810 n_found += 1;
6811 }
6812 pc2 = pc;
6813 if pc >= end {
6814 break;
6815 }
6816 let Some(next_pc) = script_get_op_advance(script, pc) else {
6817 break;
6818 };
6819 pc = next_pc;
6820 }
6821
6822 if n_found > 0 {
6823 result.extend_from_slice(&script[pc2..end]);
6824 std::borrow::Cow::Owned(result)
6825 } else {
6826 std::borrow::Cow::Borrowed(script)
6827 }
6828}
6829
6830fn opcode_position_at_byte(script: &[u8], byte_index: usize) -> u32 {
6832 let mut pos = 0u32;
6833 let mut i = 0usize;
6834 while i < script.len() && i <= byte_index {
6835 let opcode = script[i];
6836 let advance = if opcode <= 0x4b {
6837 1 + opcode as usize
6838 } else if opcode == OP_PUSHDATA1 && i + 1 < script.len() {
6839 2 + script[i + 1] as usize
6840 } else if opcode == OP_PUSHDATA2 && i + 2 < script.len() {
6841 3 + ((script[i + 1] as usize) | ((script[i + 2] as usize) << 8))
6842 } else if opcode == OP_PUSHDATA4 && i + 4 < script.len() {
6843 5 + ((script[i + 1] as usize)
6844 | ((script[i + 2] as usize) << 8)
6845 | ((script[i + 3] as usize) << 16)
6846 | ((script[i + 4] as usize) << 24))
6847 } else {
6848 1
6849 };
6850 if i == byte_index {
6851 return pos;
6852 }
6853 pos += 1;
6854 i = std::cmp::min(i + advance, script.len());
6855 }
6856 0xffff_ffff
6857}
6858
6859fn eval_checksig_tapscript(
6862 ctx: &context::ScriptContext<'_>,
6863 flags: u32,
6864 signature_bytes: &[u8],
6865 pubkey_bytes: &[u8],
6866) -> Result<Option<bool>> {
6867 const VALIDATION_WEIGHT_PER_SIGOP: i64 = 50;
6868 let success = !signature_bytes.is_empty();
6869 if success {
6870 if let Some(weight) = ctx.tapscript_validation_weight {
6871 let left = weight.get() - VALIDATION_WEIGHT_PER_SIGOP;
6872 weight.set(left);
6873 if left < 0 {
6874 return Ok(None);
6875 }
6876 }
6877 }
6878 if pubkey_bytes.is_empty() {
6879 return Ok(None);
6880 }
6881 if pubkey_bytes.len() == 32 {
6882 if !success {
6883 return Ok(Some(false));
6884 }
6885 let Some((sig_bytes, sighash_byte)) = parse_taproot_keypath_sig(signature_bytes) else {
6886 return Ok(None);
6887 };
6888 let (tapscript, codesep_pos) = ctx
6889 .tapscript_for_sighash
6890 .map(|s| (s, ctx.tapscript_codesep_pos.unwrap_or(0xffff_ffff)))
6891 .unwrap_or((&[] as &[u8], 0xffff_ffff));
6892 let sighash = if tapscript.is_empty() {
6893 crate::taproot::compute_taproot_signature_hash(
6894 ctx.tx,
6895 ctx.input_index,
6896 ctx.prevout_values,
6897 ctx.prevout_script_pubkeys,
6898 sighash_byte,
6899 None,
6900 )?
6901 } else {
6902 crate::taproot::compute_tapscript_signature_hash(
6903 ctx.tx,
6904 ctx.input_index,
6905 ctx.prevout_values,
6906 ctx.prevout_script_pubkeys,
6907 tapscript,
6908 crate::taproot::TAPROOT_LEAF_VERSION_TAPSCRIPT,
6909 codesep_pos,
6910 sighash_byte,
6911 ctx.taproot_annex_hash,
6912 )?
6913 };
6914 #[cfg(feature = "production")]
6915 let is_valid = {
6916 use crate::bip348::verify_tapscript_schnorr_signature;
6917 verify_tapscript_schnorr_signature(
6918 &sighash,
6919 pubkey_bytes,
6920 &sig_bytes,
6921 ctx.schnorr_collector,
6922 )
6923 .unwrap_or(false)
6924 };
6925 #[cfg(not(feature = "production"))]
6926 let is_valid = {
6927 let mut pk = [0u8; 32];
6928 pk.copy_from_slice(pubkey_bytes);
6929 crate::secp256k1_backend::verify_schnorr(&sig_bytes, &sighash, &pk).unwrap_or(false)
6930 };
6931 if !is_valid {
6932 return Ok(None);
6933 }
6934 return Ok(Some(true));
6935 }
6936 if flags & crate::script::flags::SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE != 0 {
6937 return Ok(None);
6938 }
6939 Ok(Some(success))
6940}
6941
6942#[cfg_attr(feature = "production", inline(always))]
6948fn eval_checksig_ecdsa(
6949 ctx: &context::ScriptContext<'_>,
6950 flags: u32,
6951 signature_bytes: &[u8],
6952 pubkey_bytes: &[u8],
6953 redeem_script_for_sighash: Option<&[u8]>,
6954) -> Result<bool> {
6955 let tx = ctx.tx;
6956 let input_index = ctx.input_index;
6957 let prevout_values = ctx.prevout_values;
6958 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
6959 let block_height = ctx.block_height;
6960 let network = ctx.network;
6961 let sigversion = ctx.sigversion;
6962 let precomputed_bip143 = ctx.precomputed_bip143;
6963 #[cfg(feature = "production")]
6964 let sighash_cache = ctx.sighash_cache;
6965
6966 let sig_len = signature_bytes.len();
6967 let sighash_byte = signature_bytes[sig_len - 1];
6968 let _der_sig = &signature_bytes[..sig_len - 1];
6969
6970 let sighash = if sigversion == SigVersion::WitnessV0 {
6971 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
6972 let script_code = redeem_script_for_sighash.unwrap_or_else(|| {
6973 prevout_script_pubkeys
6974 .get(input_index)
6975 .copied()
6976 .unwrap_or(&[])
6977 });
6978 crate::transaction_hash::calculate_bip143_sighash(
6979 tx,
6980 input_index,
6981 script_code,
6982 amount,
6983 sighash_byte,
6984 precomputed_bip143,
6985 )?
6986 } else {
6987 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
6988 let sighash_type = SighashType::from_byte(sighash_byte);
6989 let sig = signature_bytes;
6990 let base_script = match (
6991 redeem_script_for_sighash,
6992 prevout_script_pubkeys.get(input_index),
6993 ) {
6994 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
6995 (Some(redeem), _) => redeem,
6996 (None, Some(prevout)) => *prevout,
6997 (None, None) => &[],
6998 };
6999 let cleaned = if sig.len().saturating_add(1) > base_script.len() {
7000 std::borrow::Cow::Borrowed(base_script)
7001 } else {
7002 with_push_pattern(sig, |pattern| find_and_delete(base_script, pattern))
7003 };
7004 if sigversion == SigVersion::Base
7007 && flags & crate::script::flags::SCRIPT_VERIFY_CONST_SCRIPTCODE != 0
7008 && matches!(cleaned, std::borrow::Cow::Owned(_))
7009 {
7010 return Err(ConsensusError::ScriptErrorWithCode {
7011 code: ScriptErrorCode::SigFindAndDelete,
7012 message: "signature is in the non-segwit script code".into(),
7013 });
7014 }
7015 calculate_transaction_sighash_single_input(
7016 tx,
7017 input_index,
7018 cleaned.as_ref(),
7019 prevout_values[input_index],
7020 sighash_type,
7021 #[cfg(feature = "production")]
7022 sighash_cache,
7023 )?
7024 };
7025
7026 let height = block_height.unwrap_or(0);
7027 #[cfg(feature = "production")]
7028 let is_valid = signature::with_secp_context(|secp| {
7029 signature::verify_signature(
7030 secp,
7031 pubkey_bytes,
7032 signature_bytes,
7033 &sighash,
7034 flags,
7035 height,
7036 network,
7037 sigversion,
7038 )
7039 })?;
7040 #[cfg(not(feature = "production"))]
7041 let is_valid = {
7042 let secp = signature::new_secp();
7043 signature::verify_signature(
7044 &secp,
7045 pubkey_bytes,
7046 signature_bytes,
7047 &sighash,
7048 flags,
7049 height,
7050 network,
7051 sigversion,
7052 )?
7053 };
7054 Ok(is_valid)
7055}
7056
7057#[cfg_attr(feature = "production", inline(always))]
7059fn execute_opcode_with_context_full(
7060 opcode: u8,
7061 stack: &mut Vec<StackElement>,
7062 flags: u32,
7063 ctx: &context::ScriptContext<'_>,
7064 effective_script_code: Option<&[u8]>,
7065) -> Result<bool> {
7066 let tx = ctx.tx;
7067 let input_index = ctx.input_index;
7068 let prevout_values = ctx.prevout_values;
7069 let prevout_script_pubkeys = ctx.prevout_script_pubkeys;
7070 let block_height = ctx.block_height;
7071 let median_time_past = ctx.median_time_past;
7072 let network = ctx.network;
7073 let sigversion = ctx.sigversion;
7074 let script_sig_for_sighash = ctx.script_sig_for_sighash;
7075 let tapscript_for_sighash = ctx.tapscript_for_sighash;
7076 let tapscript_codesep_pos = ctx.tapscript_codesep_pos;
7077 let redeem_script_for_sighash = effective_script_code;
7078 #[cfg(feature = "production")]
7079 let schnorr_collector = ctx.schnorr_collector;
7080 let precomputed_bip143 = ctx.precomputed_bip143;
7081 #[cfg(feature = "production")]
7082 let sighash_cache = ctx.sighash_cache;
7083
7084 match opcode {
7086 OP_CHECKSIG => {
7088 if stack.len() >= 2 {
7089 let pubkey_bytes = stack.pop().unwrap();
7090 let signature_bytes = stack.pop().unwrap();
7091
7092 if sigversion == SigVersion::Tapscript {
7093 return match eval_checksig_tapscript(
7094 ctx,
7095 flags,
7096 &signature_bytes,
7097 &pubkey_bytes,
7098 )? {
7099 None => Ok(false),
7100 Some(ok) => {
7101 stack.push(to_stack_element(script_bool_bytes(ok)));
7102 Ok(true)
7103 }
7104 };
7105 }
7106
7107 if signature_bytes.is_empty() {
7111 let compressed_or_uncompressed = matches!(
7112 (pubkey_bytes.first(), pubkey_bytes.len()),
7113 (Some(0x04), 65) | (Some(0x02 | 0x03), 33)
7114 );
7115 if flags & flags::SCRIPT_VERIFY_STRICTENC != 0 && !compressed_or_uncompressed {
7116 return Err(ConsensusError::ScriptErrorWithCode {
7117 code: ScriptErrorCode::PubkeyType,
7118 message: "public key must be compressed or uncompressed".into(),
7119 });
7120 }
7121 if sigversion == SigVersion::WitnessV0
7122 && flags & flags::SCRIPT_VERIFY_WITNESS_PUBKEYTYPE != 0
7123 && !(pubkey_bytes.len() == 33
7124 && (pubkey_bytes[0] == 0x02 || pubkey_bytes[0] == 0x03))
7125 {
7126 return Err(ConsensusError::ScriptErrorWithCode {
7127 code: ScriptErrorCode::WitnessPubkeyType,
7128 message: "witness v0 pubkey must be compressed".into(),
7129 });
7130 }
7131 stack.push(to_stack_element(&[]));
7132 return Ok(true);
7133 }
7134
7135 let is_valid = eval_checksig_ecdsa(
7136 ctx,
7137 flags,
7138 &signature_bytes,
7139 &pubkey_bytes,
7140 redeem_script_for_sighash,
7141 )?;
7142
7143 if !is_valid && flags & flags::SCRIPT_VERIFY_NULLFAIL != 0 {
7144 return Err(ConsensusError::ScriptErrorWithCode {
7145 code: ScriptErrorCode::SigNullFail,
7146 message: "OP_CHECKSIG: non-null signature must not fail under NULLFAIL"
7147 .into(),
7148 });
7149 }
7150 stack.push(to_stack_element(script_bool_bytes(is_valid)));
7151 Ok(true)
7152 } else {
7153 Ok(false)
7154 }
7155 }
7156
7157 OP_CHECKSIGVERIFY => {
7159 if stack.len() >= 2 {
7160 let pubkey_bytes = stack.pop().unwrap();
7161 let signature_bytes = stack.pop().unwrap();
7162
7163 if sigversion == SigVersion::Tapscript {
7164 return match eval_checksig_tapscript(
7165 ctx,
7166 flags,
7167 &signature_bytes,
7168 &pubkey_bytes,
7169 )? {
7170 Some(true) => Ok(true),
7171 _ => Ok(false),
7172 };
7173 }
7174
7175 if signature_bytes.is_empty() {
7177 return Ok(false);
7178 }
7179
7180 let is_valid = eval_checksig_ecdsa(
7181 ctx,
7182 flags,
7183 &signature_bytes,
7184 &pubkey_bytes,
7185 redeem_script_for_sighash,
7186 )?;
7187 Ok(is_valid)
7188 } else {
7189 Ok(false)
7190 }
7191 }
7192
7193 OP_CHECKSIGADD => {
7195 if sigversion != SigVersion::Tapscript {
7196 return Err(ConsensusError::ScriptErrorWithCode {
7197 code: ScriptErrorCode::DisabledOpcode,
7198 message: "OP_CHECKSIGADD is only available in Tapscript".into(),
7199 });
7200 }
7201 if stack.len() < 3 {
7202 return Err(ConsensusError::ScriptErrorWithCode {
7203 code: ScriptErrorCode::InvalidStackOperation,
7204 message: "OP_CHECKSIGADD: insufficient stack items (need 3)".into(),
7205 });
7206 }
7207 let pubkey_bytes = stack.pop().unwrap();
7209 let n_bytes = stack.pop().unwrap();
7210 let signature_bytes = stack.pop().unwrap();
7211 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
7212 && !script_num_is_minimally_encoded(&n_bytes)
7213 {
7214 return Err(ConsensusError::ScriptErrorWithCode {
7215 code: ScriptErrorCode::MinimalData,
7216 message: "OP_CHECKSIGADD: non-minimal script number".into(),
7217 });
7218 }
7219 let n = script_num_decode(&n_bytes, 4)?;
7220
7221 match eval_checksig_tapscript(ctx, flags, &signature_bytes, &pubkey_bytes)? {
7222 None => return Ok(false),
7223 Some(ok) => {
7224 let pushed = if ok { n + 1 } else { n };
7225 stack.push(to_stack_element(&script_num_encode(pushed)));
7226 return Ok(true);
7227 }
7228 }
7229 }
7230
7231 OP_CHECKMULTISIG => {
7233 if sigversion == SigVersion::Tapscript {
7234 return Ok(false);
7235 }
7236 if stack.len() < 2 {
7239 return Ok(false);
7240 }
7241
7242 let n_bytes = stack.pop().unwrap();
7244 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
7245 && !script_num_is_minimally_encoded(&n_bytes)
7246 {
7247 return Err(ConsensusError::ScriptErrorWithCode {
7248 code: ScriptErrorCode::MinimalData,
7249 message: "OP_CHECKMULTISIG: non-minimal key count".into(),
7250 });
7251 }
7252 let n_raw = script_num_decode(&n_bytes, 4).map_err(|_| {
7253 ConsensusError::ScriptErrorWithCode {
7254 code: ScriptErrorCode::InvalidStackOperation,
7255 message: "OP_CHECKMULTISIG: invalid n encoding".into(),
7256 }
7257 })?;
7258 if !(0..=20).contains(&n_raw) {
7259 return Ok(false);
7260 }
7261 let n = n_raw as usize;
7262 if stack.len() < n + 1 {
7263 return Ok(false);
7264 }
7265
7266 let mut pubkeys = Vec::with_capacity(n);
7268 for _ in 0..n {
7269 pubkeys.push(stack.pop().unwrap());
7270 }
7271
7272 let m_bytes = stack.pop().unwrap();
7274 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
7275 && !script_num_is_minimally_encoded(&m_bytes)
7276 {
7277 return Err(ConsensusError::ScriptErrorWithCode {
7278 code: ScriptErrorCode::MinimalData,
7279 message: "OP_CHECKMULTISIG: non-minimal script number".into(),
7280 });
7281 }
7282 let m_raw = script_num_decode(&m_bytes, 4).map_err(|_| {
7283 ConsensusError::ScriptErrorWithCode {
7284 code: ScriptErrorCode::InvalidStackOperation,
7285 message: "OP_CHECKMULTISIG: invalid m encoding".into(),
7286 }
7287 })?;
7288 if m_raw < 0 || m_raw as usize > n || m_raw > 20 {
7289 return Ok(false);
7290 }
7291 let m = m_raw as usize;
7292 if stack.len() < m + 1 {
7293 return Ok(false);
7294 }
7295
7296 let mut signatures = Vec::with_capacity(m);
7298 for _ in 0..m {
7299 signatures.push(stack.pop().unwrap());
7300 }
7301
7302 let dummy = stack.pop().unwrap();
7306 if (flags & flags::SCRIPT_VERIFY_NULLDUMMY) != 0 && !dummy.is_empty() {
7307 return Err(ConsensusError::ScriptErrorWithCode {
7308 code: ScriptErrorCode::SigNullDummy,
7309 message: format!(
7310 "OP_CHECKMULTISIG: dummy element {dummy:?} violates BIP147 NULLDUMMY (must be zero-length)"
7311 )
7312 .into(),
7313 });
7314 }
7315
7316 let height = block_height.unwrap_or(0);
7319 if flags & 0x02 != 0 {
7320 for pubkey in &pubkeys {
7321 crate::script::signature::reject_strictenc_pubkey(flags, pubkey)?;
7322 }
7323 for sig_bytes in &signatures {
7324 crate::script::signature::reject_strictenc_signature(flags, sig_bytes)?;
7325 }
7326 }
7327
7328 let cleaned_script_for_multisig: std::borrow::Cow<[u8]> =
7331 if sigversion == SigVersion::Base {
7332 let base_script = match (
7333 redeem_script_for_sighash,
7334 prevout_script_pubkeys.get(input_index),
7335 ) {
7336 (Some(redeem), Some(prevout)) if redeem == *prevout => *prevout,
7337 (Some(redeem), _) => redeem,
7338 (None, Some(prevout)) => *prevout,
7339 (None, None) => &[],
7340 };
7341 multisig_script_code(base_script, &signatures)
7342 } else {
7343 std::borrow::Cow::Borrowed(redeem_script_for_sighash.unwrap_or_else(|| {
7345 prevout_script_pubkeys
7346 .get(input_index)
7347 .copied()
7348 .unwrap_or(&[])
7349 }))
7350 };
7351 if sigversion == SigVersion::Base
7354 && flags & crate::script::flags::SCRIPT_VERIFY_CONST_SCRIPTCODE != 0
7355 && matches!(cleaned_script_for_multisig, std::borrow::Cow::Owned(_))
7356 {
7357 return Err(ConsensusError::ScriptErrorWithCode {
7358 code: ScriptErrorCode::SigFindAndDelete,
7359 message: "signature is in the non-segwit script code".into(),
7360 });
7361 }
7362
7363 use crate::transaction_hash::{
7364 SighashType, calculate_transaction_sighash_single_input,
7365 };
7366
7367 #[cfg(feature = "production")]
7369 let use_batch = pubkeys.len() * signatures.len() >= 4;
7370
7371 #[cfg(feature = "production")]
7372 let (valid_sigs, _) = if use_batch {
7373 let sighashes: Vec<[u8; 32]> = if sigversion == SigVersion::Base {
7375 let non_empty: Vec<_> = signatures.iter().filter(|s| !s.is_empty()).collect();
7376 if non_empty.is_empty() {
7377 vec![]
7378 } else {
7379 let specs: Vec<(usize, u8, &[u8])> = non_empty
7380 .iter()
7381 .map(|s| {
7382 (
7383 input_index,
7384 s.as_ref()[s.as_ref().len() - 1],
7385 cleaned_script_for_multisig.as_ref(),
7386 )
7387 })
7388 .collect();
7389 crate::transaction_hash::batch_compute_legacy_sighashes(
7390 tx,
7391 prevout_values,
7392 prevout_script_pubkeys,
7393 &specs,
7394 )?
7395 }
7396 } else {
7397 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
7399 signatures
7400 .iter()
7401 .filter(|s| !s.is_empty())
7402 .map(|sig_bytes| {
7403 let sighash_byte = sig_bytes[sig_bytes.len() - 1];
7404 crate::transaction_hash::calculate_bip143_sighash(
7405 tx,
7406 input_index,
7407 &cleaned_script_for_multisig,
7408 amount,
7409 sighash_byte,
7410 precomputed_bip143,
7411 )
7412 })
7413 .collect::<Result<Vec<_>>>()?
7414 };
7415
7416 let mut tasks: Vec<(&[u8], &[u8], [u8; 32])> =
7418 Vec::with_capacity(pubkeys.len() * signatures.len());
7419 let mut sig_idx_to_sighash_idx = Vec::with_capacity(signatures.len());
7420 let mut sighash_idx = 0usize;
7421 for (j, sig_bytes) in signatures.iter().enumerate() {
7422 if sig_bytes.is_empty() {
7423 sig_idx_to_sighash_idx.push(usize::MAX);
7424 } else {
7425 sig_idx_to_sighash_idx.push(sighash_idx);
7426 let sh = sighashes[sighash_idx];
7427 sighash_idx += 1;
7428 for pubkey_bytes in &pubkeys {
7429 tasks.push((pubkey_bytes.as_ref(), sig_bytes.as_ref(), sh));
7430 }
7431 }
7432 }
7433
7434 let results = if tasks.is_empty() {
7435 vec![]
7436 } else {
7437 batch_verify_signatures(&tasks, flags, height, network, sigversion)?
7438 };
7439
7440 let mut sig_index = 0;
7442 let mut valid_sigs = 0usize;
7443 for (i, pubkey_bytes) in pubkeys.iter().enumerate() {
7444 if sig_index >= signatures.len() {
7445 break;
7446 }
7447 if sigversion == SigVersion::WitnessV0
7448 && flags & crate::script::flags::SCRIPT_VERIFY_WITNESS_PUBKEYTYPE != 0
7449 && !(pubkey_bytes.len() == 33
7450 && (pubkey_bytes[0] == 0x02 || pubkey_bytes[0] == 0x03))
7451 {
7452 return Err(ConsensusError::ScriptErrorWithCode {
7453 code: ScriptErrorCode::WitnessPubkeyType,
7454 message: "witness v0 public key must be compressed".into(),
7455 });
7456 }
7457 while sig_index < signatures.len() && signatures[sig_index].is_empty() {
7459 sig_index += 1;
7460 }
7461 if sig_index >= signatures.len() {
7462 break;
7463 }
7464 let sh_idx = sig_idx_to_sighash_idx[sig_index];
7465 if sh_idx == usize::MAX {
7466 continue;
7467 }
7468 let task_idx = sh_idx * pubkeys.len() + i;
7469 if task_idx < results.len() && results[task_idx] {
7470 valid_sigs += 1;
7471 sig_index += 1;
7472 }
7473 }
7474
7475 (valid_sigs, ())
7476 } else {
7477 let mut sig_index = 0;
7478 let mut valid_sigs = 0;
7479 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
7480
7481 for pubkey_bytes in &pubkeys {
7482 if sig_index >= signatures.len() {
7483 break;
7484 }
7485
7486 let signature_bytes = &signatures[sig_index];
7487
7488 if signature_bytes.is_empty() {
7489 continue;
7490 }
7491 if sigversion == SigVersion::WitnessV0
7493 && flags & crate::script::flags::SCRIPT_VERIFY_WITNESS_PUBKEYTYPE != 0
7494 && !(pubkey_bytes.len() == 33
7495 && (pubkey_bytes[0] == 0x02 || pubkey_bytes[0] == 0x03))
7496 {
7497 return Err(ConsensusError::ScriptErrorWithCode {
7498 code: ScriptErrorCode::WitnessPubkeyType,
7499 message: "witness v0 public key must be compressed".into(),
7500 });
7501 }
7502
7503 let sig_len = signature_bytes.len();
7504 let sighash_byte = signature_bytes[sig_len - 1];
7505
7506 let sighash = if sigversion == SigVersion::WitnessV0 {
7508 crate::transaction_hash::calculate_bip143_sighash(
7509 tx,
7510 input_index,
7511 &cleaned_script_for_multisig,
7512 amount,
7513 sighash_byte,
7514 #[cfg(feature = "production")]
7515 precomputed_bip143,
7516 #[cfg(not(feature = "production"))]
7517 None,
7518 )?
7519 } else {
7520 let sighash_type = SighashType::from_byte(sighash_byte);
7521 calculate_transaction_sighash_single_input(
7522 tx,
7523 input_index,
7524 &cleaned_script_for_multisig,
7525 prevout_values[input_index],
7526 sighash_type,
7527 #[cfg(feature = "production")]
7528 sighash_cache,
7529 )?
7530 };
7531
7532 #[cfg(feature = "production")]
7533 let is_valid = signature::with_secp_context(|secp| {
7534 signature::verify_signature(
7535 secp,
7536 pubkey_bytes,
7537 signature_bytes,
7538 &sighash,
7539 flags,
7540 height,
7541 network,
7542 sigversion,
7543 )
7544 })?;
7545
7546 #[cfg(not(feature = "production"))]
7547 let is_valid = {
7548 let secp = signature::new_secp();
7549 signature::verify_signature(
7550 &secp,
7551 pubkey_bytes,
7552 signature_bytes,
7553 &sighash,
7554 flags,
7555 height,
7556 network,
7557 sigversion,
7558 )?
7559 };
7560
7561 if is_valid {
7562 valid_sigs += 1;
7563 sig_index += 1;
7564 }
7565 }
7566 (valid_sigs, ())
7567 };
7568
7569 #[cfg(not(feature = "production"))]
7570 let (valid_sigs, _) = {
7571 let mut sig_index = 0;
7572 let mut valid_sigs = 0;
7573 let amount = prevout_values.get(input_index).copied().unwrap_or(0);
7574
7575 for pubkey_bytes in &pubkeys {
7576 if sig_index >= signatures.len() {
7577 break;
7578 }
7579 let signature_bytes = &signatures[sig_index];
7580 if signature_bytes.is_empty() {
7581 continue;
7582 }
7583 let sig_len = signature_bytes.len();
7584 let sighash_byte = signature_bytes[sig_len - 1];
7585
7586 let sighash = if sigversion == SigVersion::WitnessV0 {
7588 crate::transaction_hash::calculate_bip143_sighash(
7589 tx,
7590 input_index,
7591 &cleaned_script_for_multisig,
7592 amount,
7593 sighash_byte,
7594 None,
7595 )?
7596 } else {
7597 let sighash_type = SighashType::from_byte(sighash_byte);
7598 calculate_transaction_sighash_single_input(
7599 tx,
7600 input_index,
7601 &cleaned_script_for_multisig,
7602 prevout_values[input_index],
7603 sighash_type,
7604 )?
7605 };
7606 let secp = signature::new_secp();
7607 let is_valid = signature::verify_signature(
7608 &secp,
7609 pubkey_bytes,
7610 signature_bytes,
7611 &sighash,
7612 flags,
7613 height,
7614 network,
7615 sigversion,
7616 )?;
7617 if is_valid {
7618 valid_sigs += 1;
7619 sig_index += 1;
7620 }
7621 }
7622 (valid_sigs, ())
7623 };
7624
7625 let success = valid_sigs >= m;
7626 failed_multisig_nullfail(flags, success, signatures.iter().any(|sig| !sig.is_empty()))?;
7627 stack.push(to_stack_element(script_bool_bytes(success)));
7628 Ok(true)
7629 }
7630
7631 OP_CHECKMULTISIGVERIFY => {
7633 let ctx_checkmultisig = context::ScriptContext {
7635 tx,
7636 input_index,
7637 prevout_values,
7638 prevout_script_pubkeys,
7639 block_height,
7640 median_time_past,
7641 network,
7642 sigversion,
7643 redeem_script_for_sighash,
7644 script_sig_for_sighash,
7645 tapscript_for_sighash,
7646 tapscript_codesep_pos,
7647 taproot_annex_hash: None,
7648 tapscript_validation_weight: ctx.tapscript_validation_weight,
7649 #[cfg(feature = "production")]
7650 schnorr_collector: None,
7651 precomputed_bip143,
7652 #[cfg(feature = "production")]
7653 sighash_cache,
7654 };
7655 let result = execute_opcode_with_context_full(
7656 OP_CHECKMULTISIG,
7657 stack,
7658 flags,
7659 &ctx_checkmultisig,
7660 redeem_script_for_sighash,
7661 )?;
7662 if !result {
7663 return Ok(false);
7664 }
7665 if let Some(top) = stack.pop() {
7667 if !cast_to_bool(&top) {
7668 return Ok(false);
7669 }
7670 Ok(true)
7671 } else {
7672 Ok(false)
7673 }
7674 }
7675
7676 OP_CHECKLOCKTIMEVERIFY => {
7681 if (flags & flags::SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY) == 0 {
7683 return Ok(true);
7684 }
7685
7686 use crate::locktime::{check_bip65, decode_locktime_value};
7687
7688 if stack.is_empty() {
7689 return Err(ConsensusError::ScriptErrorWithCode {
7690 code: ScriptErrorCode::InvalidStackOperation,
7691 message: "OP_CHECKLOCKTIMEVERIFY: empty stack".into(),
7692 });
7693 }
7694
7695 let locktime_bytes = stack.last().expect("Stack is not empty");
7697 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
7698 && !script_num_is_minimally_encoded(locktime_bytes.as_ref())
7699 {
7700 return Err(ConsensusError::ScriptErrorWithCode {
7701 code: ScriptErrorCode::MinimalData,
7702 message: "OP_CHECKLOCKTIMEVERIFY: non-minimal script number".into(),
7703 });
7704 }
7705 let locktime_number = match decode_locktime_value(locktime_bytes.as_ref()) {
7706 Some(v) => v,
7707 None => {
7708 return Err(ConsensusError::ScriptErrorWithCode {
7709 code: ScriptErrorCode::MinimalData,
7710 message: "OP_CHECKLOCKTIMEVERIFY: invalid locktime encoding".into(),
7711 });
7712 }
7713 };
7714 if locktime_number < 0 {
7715 return Err(ConsensusError::ScriptErrorWithCode {
7716 code: ScriptErrorCode::NegativeLocktime,
7717 message: "OP_CHECKLOCKTIMEVERIFY: negative locktime".into(),
7718 });
7719 }
7720 if locktime_number > u32::MAX as i64 {
7722 return Ok(false);
7723 }
7724 let locktime_value = locktime_number as u32;
7725
7726 let tx_locktime = tx.lock_time as u32;
7727
7728 if !check_bip65(tx_locktime, locktime_value) {
7730 return Ok(false);
7731 }
7732
7733 let input_seq = if input_index < tx.inputs.len() {
7735 tx.inputs[input_index].sequence
7736 } else {
7737 0xffffffff
7738 };
7739 if input_seq == 0xffffffff {
7740 return Ok(false);
7741 }
7742
7743 Ok(true)
7745 }
7746
7747 OP_CHECKSEQUENCEVERIFY => {
7758 use crate::locktime::{check_bip112, decode_locktime_value, is_sequence_disabled};
7759
7760 if (flags & flags::SCRIPT_VERIFY_CHECKSEQUENCEVERIFY) == 0 {
7762 return Ok(true);
7763 }
7764
7765 if stack.is_empty() {
7766 return Ok(false);
7767 }
7768
7769 let sequence_bytes = stack.last().expect("Stack is not empty");
7772 if (flags & crate::script::flags::SCRIPT_VERIFY_MINIMALDATA) != 0
7773 && !script_num_is_minimally_encoded(sequence_bytes.as_ref())
7774 {
7775 return Err(ConsensusError::ScriptErrorWithCode {
7776 code: ScriptErrorCode::MinimalData,
7777 message: "OP_CHECKSEQUENCEVERIFY: non-minimal script number".into(),
7778 });
7779 }
7780 let sequence_number = match decode_locktime_value(sequence_bytes.as_ref()) {
7781 Some(v) => v,
7782 None => return Ok(false), };
7784 if sequence_number < 0 {
7785 return Err(ConsensusError::ScriptErrorWithCode {
7786 code: ScriptErrorCode::NegativeLocktime,
7787 message: "OP_CHECKSEQUENCEVERIFY: negative locktime".into(),
7788 });
7789 }
7790 let sequence_value = sequence_number as u32;
7792
7793 if input_index >= tx.inputs.len() {
7795 return Ok(false);
7796 }
7797 let input_sequence = tx.inputs[input_index].sequence as u32;
7798
7799 if is_sequence_disabled(sequence_value) {
7802 return Ok(true);
7803 }
7804 if !crate::sequence_locks::version_enforces_relative_lock(tx.version) {
7805 return Ok(false);
7806 }
7807 if is_sequence_disabled(input_sequence) {
7808 return Ok(false);
7809 }
7810
7811 if !check_bip112(sequence_value, input_sequence) {
7813 return Ok(false);
7814 }
7815
7816 Ok(true)
7818 }
7819
7820 OP_CHECKTEMPLATEVERIFY => {
7829 #[cfg(not(feature = "ctv"))]
7830 {
7831 upgradable_nop(flags)
7832 }
7833
7834 #[cfg(feature = "ctv")]
7835 {
7836 use crate::constants::{
7837 CTV_ACTIVATION_MAINNET, CTV_ACTIVATION_REGTEST, CTV_ACTIVATION_TESTNET,
7838 };
7839
7840 let ctv_activation = match network {
7842 crate::types::Network::Mainnet => CTV_ACTIVATION_MAINNET,
7843 crate::types::Network::Testnet => CTV_ACTIVATION_TESTNET,
7844 crate::types::Network::Regtest | crate::types::Network::Signet => {
7845 CTV_ACTIVATION_REGTEST
7846 }
7847 crate::types::Network::Testnet4 => u64::MAX,
7849 };
7850
7851 let ctv_active = block_height.map(|h| h >= ctv_activation).unwrap_or(false);
7852 if !ctv_active {
7853 return upgradable_nop(flags);
7854 }
7855
7856 if flags & flags::SCRIPT_VERIFY_DEFAULT_CHECK_TEMPLATE_VERIFY_HASH == 0 {
7857 return upgradable_nop(flags);
7858 }
7859
7860 use crate::bip119::calculate_template_hash;
7861
7862 if stack.is_empty() {
7864 return Err(ConsensusError::ScriptErrorWithCode {
7865 code: ScriptErrorCode::InvalidStackOperation,
7866 message: "OP_CHECKTEMPLATEVERIFY: insufficient stack items".into(),
7867 });
7868 }
7869
7870 let template_hash_bytes = stack.pop().unwrap();
7871
7872 if template_hash_bytes.len() != 32 {
7874 return upgradable_nop(flags);
7875 }
7876
7877 let mut expected_hash = [0u8; 32];
7879 expected_hash.copy_from_slice(&template_hash_bytes);
7880
7881 let actual_hash = calculate_template_hash(tx, input_index).map_err(|e| {
7882 ConsensusError::ScriptErrorWithCode {
7883 code: ScriptErrorCode::TxInvalid,
7884 message: format!("CTV hash calculation failed: {e}").into(),
7885 }
7886 })?;
7887
7888 use crate::crypto::hash_compare::hash_eq;
7890 let matches = hash_eq(&expected_hash, &actual_hash);
7891
7892 if !matches {
7893 return Ok(false); }
7895
7896 Ok(true)
7898 }
7899 }
7900
7901 OP_CHECKSIGFROMSTACK => {
7912 #[cfg(not(feature = "csfs"))]
7913 {
7914 if sigversion == SigVersion::Tapscript {
7918 return Ok(true);
7919 }
7920 Err(ConsensusError::ScriptErrorWithCode {
7921 code: ScriptErrorCode::BadOpcode,
7922 message: "OP_CHECKSIGFROMSTACK is undefined outside tapscript".into(),
7923 })
7924 }
7925
7926 #[cfg(feature = "csfs")]
7927 {
7928 if sigversion != SigVersion::Tapscript {
7930 return Err(ConsensusError::ScriptErrorWithCode {
7931 code: ScriptErrorCode::BadOpcode,
7932 message: "OP_CHECKSIGFROMSTACK only available in Tapscript".into(),
7933 });
7934 }
7935
7936 let csfs_active = {
7937 use crate::activation::IsForkActive;
7938 block_height.is_some_and(|height| {
7939 crate::activation::ForkActivationTable::from_network(network)
7940 .is_fork_active(crate::types::ForkId::Csfs, height)
7941 })
7942 };
7943 if !csfs_active {
7944 if flags & flags::SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS != 0 {
7945 return Err(ConsensusError::ScriptErrorWithCode {
7946 code: ScriptErrorCode::DiscourageUpgradableNops,
7947 message: "OP_CHECKSIGFROMSTACK not yet activated".into(),
7948 });
7949 }
7950 return Ok(true);
7951 }
7952
7953 use crate::bip348::verify_signature_from_stack;
7954
7955 if stack.len() < 3 {
7957 return Err(ConsensusError::ScriptErrorWithCode {
7958 code: ScriptErrorCode::InvalidStackOperation,
7959 message: "OP_CHECKSIGFROMSTACK: insufficient stack items (need 3)".into(),
7960 });
7961 }
7962
7963 let pubkey_bytes = stack.pop().unwrap(); let message_bytes = stack.pop().unwrap(); let signature_bytes = stack.pop().unwrap(); if pubkey_bytes.is_empty() {
7970 return Err(ConsensusError::ScriptErrorWithCode {
7971 code: ScriptErrorCode::PubkeyType,
7972 message: "OP_CHECKSIGFROMSTACK: pubkey size is zero".into(),
7973 });
7974 }
7975
7976 if signature_bytes.is_empty() {
7978 stack.push(to_stack_element(&[])); return Ok(true);
7980 }
7981
7982 #[cfg(feature = "production")]
7985 let is_valid = {
7986 verify_signature_from_stack(
7987 &message_bytes, &pubkey_bytes, &signature_bytes, schnorr_collector, )
7992 .unwrap_or(false)
7993 };
7994 #[cfg(not(feature = "production"))]
7995 let is_valid = verify_signature_from_stack(
7996 &message_bytes, &pubkey_bytes, &signature_bytes, )
8000 .unwrap_or(false);
8001
8002 if !is_valid {
8003 return Ok(false);
8005 }
8006
8007 stack.push(to_stack_element(&[0x01])); Ok(true)
8013 }
8014 }
8015
8016 _ => execute_opcode_cold(opcode, stack, flags),
8018 }
8019}
8020
8021#[cold]
8023fn execute_opcode_cold(opcode: u8, stack: &mut Vec<StackElement>, flags: u32) -> Result<bool> {
8024 execute_opcode(opcode, stack, flags, SigVersion::Base)
8025}
8026
8027#[cfg(all(feature = "production", feature = "profile"))]
8042pub(crate) fn get_and_reset_fast_path_counts() -> (u64, u64, u64, u64, u64, u64, u64, u64, u64) {
8043 (
8044 FAST_PATH_P2PK.swap(0, Ordering::Relaxed),
8045 FAST_PATH_P2PKH.swap(0, Ordering::Relaxed),
8046 FAST_PATH_P2SH.swap(0, Ordering::Relaxed),
8047 FAST_PATH_P2WPKH.swap(0, Ordering::Relaxed),
8048 FAST_PATH_P2WSH.swap(0, Ordering::Relaxed),
8049 FAST_PATH_P2TR.swap(0, Ordering::Relaxed),
8050 FAST_PATH_UNEXEC_IF.swap(0, Ordering::Relaxed),
8051 FAST_PATH_BARE_MULTISIG.swap(0, Ordering::Relaxed),
8052 FAST_PATH_INTERPRETER.swap(0, Ordering::Relaxed),
8053 )
8054}
8055
8056#[cfg(feature = "production")]
8058pub fn take_fast_path_unexec_if() -> u64 {
8059 FAST_PATH_UNEXEC_IF.swap(0, Ordering::Relaxed)
8060}
8061
8062#[cfg(all(feature = "production", feature = "benchmarking"))]
8069pub fn clear_script_cache() {
8070 if let Some(cache) = SCRIPT_CACHE.get() {
8071 let mut cache = cache.write().unwrap_or_else(|e| e.into_inner());
8072 cache.clear();
8073 }
8074}
8075
8076#[cfg(all(feature = "production", feature = "benchmarking"))]
8090pub fn clear_hash_cache() {
8091 crypto_ops::clear_hash_cache();
8092}
8093
8094#[cfg(all(feature = "production", feature = "benchmarking"))]
8107pub fn clear_all_caches() {
8108 clear_script_cache();
8109 clear_hash_cache();
8110}
8111
8112#[cfg(all(feature = "production", feature = "benchmarking"))]
8126pub fn clear_stack_pool() {
8127 STACK_POOL.with(|pool| {
8128 let mut pool = pool.borrow_mut();
8129 pool.clear();
8130 });
8131}
8132
8133#[cfg(all(feature = "production", feature = "benchmarking"))]
8147pub fn reset_benchmarking_state() {
8148 clear_all_caches();
8149 clear_stack_pool();
8150 disable_caching(false); #[cfg(feature = "benchmarking")]
8153 crate::transaction_hash::clear_sighash_templates();
8154}
8155
8156#[cfg(test)]
8157mod tests {
8158 use super::*;
8159
8160 #[test]
8161 fn tapscript_truncated_push_is_not_op_success() {
8162 use crate::types::{Network, OutPoint, Transaction, TransactionInput, TransactionOutput};
8163
8164 let tx = Transaction {
8165 version: 2,
8166 inputs: vec![TransactionInput {
8167 prevout: OutPoint {
8168 hash: [0u8; 32],
8169 index: 0,
8170 },
8171 sequence: 0xffff_ffff,
8172 script_sig: vec![],
8173 }]
8174 .into(),
8175 outputs: vec![TransactionOutput {
8176 value: 0,
8177 script_pubkey: vec![],
8178 }]
8179 .into(),
8180 lock_time: 0,
8181 };
8182 let eval = |script: &[u8]| {
8183 let mut stack = Vec::new();
8184 eval_script_with_context_full(
8185 script,
8186 &mut stack,
8187 0,
8188 &tx,
8189 0,
8190 &[0],
8191 &[&[]],
8192 None,
8193 None,
8194 Network::Mainnet,
8195 SigVersion::Tapscript,
8196 None,
8197 None,
8198 None,
8199 Some(0),
8200 #[cfg(feature = "production")]
8201 None,
8202 None,
8203 #[cfg(feature = "production")]
8204 None,
8205 )
8206 };
8207
8208 assert!(eval(&[0x50]).unwrap());
8210 assert!(!eval(&[0x4d, 0x50]).unwrap());
8212 assert!(!eval(&[0x4e, 0x7e]).unwrap());
8214 assert!(!eval(&[0x01, 0x50, 0x00]).unwrap());
8216
8217 assert!(!eval(&[0x01]).unwrap(), "direct push 1");
8221 for opcode in 2u8..=0x4b {
8222 assert!(!eval(&[opcode, 0x50]).unwrap(), "direct push {opcode}");
8223 }
8224 for (header, leftover) in [(0x4cu8, 0x50u8), (0x4d, 0x50), (0x4e, 0x50), (0x4e, 0x7e)] {
8225 assert!(!eval(&[header, leftover]).unwrap(), "header {header:#x}");
8226 }
8227 }
8228
8229 fn eval_tapscript(
8230 script: &[u8],
8231 network: crate::types::Network,
8232 block_height: Option<u64>,
8233 ) -> Result<bool> {
8234 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
8235 let tx = Transaction {
8236 version: 2,
8237 inputs: vec![TransactionInput {
8238 prevout: OutPoint {
8239 hash: [0u8; 32],
8240 index: 0,
8241 },
8242 sequence: 0xffff_ffff,
8243 script_sig: vec![],
8244 }]
8245 .into(),
8246 outputs: vec![TransactionOutput {
8247 value: 0,
8248 script_pubkey: vec![],
8249 }]
8250 .into(),
8251 lock_time: 0,
8252 };
8253 let mut stack = Vec::new();
8254 eval_script_with_context_full(
8255 script,
8256 &mut stack,
8257 0,
8258 &tx,
8259 0,
8260 &[0],
8261 &[&[]],
8262 block_height,
8263 None,
8264 network,
8265 SigVersion::Tapscript,
8266 None,
8267 None,
8268 None,
8269 Some(0),
8270 #[cfg(feature = "production")]
8271 None,
8272 None,
8273 #[cfg(feature = "production")]
8274 None,
8275 )
8276 }
8277
8278 #[test]
8279 fn mainnet_checksigfromstack_is_op_success() {
8280 let result = eval_tapscript(&[OP_CHECKSIGFROMSTACK], Network::Mainnet, Some(800_000));
8281 assert_eq!(result.unwrap(), true);
8282 }
8283
8284 #[cfg(feature = "csfs")]
8285 #[test]
8286 fn active_csfs_is_not_an_immediate_success() {
8287 let mainnet = eval_tapscript(&[OP_CHECKSIGFROMSTACK], Network::Mainnet, Some(0));
8288 assert_eq!(mainnet.unwrap(), true);
8289 let regtest = eval_tapscript(&[OP_CHECKSIGFROMSTACK], Network::Regtest, Some(0));
8290 assert!(
8291 !matches!(regtest, Ok(true)),
8292 "regtest CSFS must run the opcode, got {regtest:?}"
8293 );
8294 }
8295
8296 #[cfg(not(feature = "production"))]
8297 #[test]
8298 fn nonproduction_tapscript_schnorr_spend_is_accepted() {
8299 use crate::taproot::{
8300 TAPROOT_LEAF_VERSION_TAPSCRIPT, compute_script_merkle_root,
8301 compute_tapscript_signature_hash,
8302 };
8303 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
8304 use secp256k1::{Keypair, Message, Secp256k1, SecretKey};
8305
8306 let secp = Secp256k1::new();
8307 let secret = SecretKey::from_slice(&[0x42; 32]).expect("secret");
8308 let keypair = Keypair::from_secret_key(&secp, &secret);
8309 let leaf_pk = keypair.x_only_public_key().0.serialize();
8310 let mut tapscript = vec![0x20];
8311 tapscript.extend_from_slice(&leaf_pk);
8312 tapscript.push(OP_CHECKSIG);
8313 let internal = [
8314 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce, 0x87,
8315 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81, 0x5b,
8316 0x16, 0xf8, 0x17, 0x98,
8317 ];
8318 let root = compute_script_merkle_root(&tapscript, &[], TAPROOT_LEAF_VERSION_TAPSCRIPT)
8319 .expect("root");
8320 let (output_key, parity) =
8321 crate::secp256k1_backend::taproot_output_key_with_parity(&internal, &root)
8322 .expect("tweak");
8323 let mut script_pubkey = vec![0x51, 0x20];
8324 script_pubkey.extend_from_slice(&output_key);
8325 let mut control = vec![TAPROOT_LEAF_VERSION_TAPSCRIPT | parity];
8326 control.extend_from_slice(&internal);
8327 let prevout_value = 10_000i64;
8328 let tx = Transaction {
8329 version: 2,
8330 inputs: vec![TransactionInput {
8331 prevout: OutPoint {
8332 hash: [0x71; 32],
8333 index: 0,
8334 },
8335 script_sig: vec![].into(),
8336 sequence: 0xffff_ffff,
8337 }]
8338 .into(),
8339 outputs: vec![TransactionOutput {
8340 value: 9_000,
8341 script_pubkey: vec![0x51].into(),
8342 }]
8343 .into(),
8344 lock_time: 0,
8345 };
8346 let sighash = compute_tapscript_signature_hash(
8347 &tx,
8348 0,
8349 &[prevout_value],
8350 &[script_pubkey.as_slice()],
8351 &tapscript,
8352 TAPROOT_LEAF_VERSION_TAPSCRIPT,
8353 0xffff_ffff,
8354 0x00,
8355 None,
8356 )
8357 .expect("sighash");
8358 let msg = Message::from_digest_slice(&sighash).expect("digest");
8359 let sig = secp.sign_schnorr_no_aux_rand(&msg, &keypair);
8360 let witness = vec![sig.as_ref().to_vec(), tapscript, control];
8361 let accepted = verify_script_with_context_full(
8362 &tx.inputs[0].script_sig,
8363 &script_pubkey,
8364 Some(&witness),
8365 flags::SCRIPT_VERIFY_WITNESS | flags::SCRIPT_VERIFY_TAPROOT,
8366 &tx,
8367 0,
8368 &[prevout_value],
8369 &[script_pubkey.as_slice()],
8370 Some(crate::constants::TAPROOT_ACTIVATION_MAINNET),
8371 None,
8372 Network::Mainnet,
8373 SigVersion::Base,
8374 None,
8375 );
8376 assert_eq!(accepted.unwrap(), true);
8377 }
8378
8379 #[test]
8380 fn checkmultisig_pubkeys_count_toward_opcode_limit() {
8381 let mut within = vec![0x61; 160];
8382 within.push(0x00);
8383 within.push(0x00);
8384 within.extend(std::iter::repeat(0x00).take(20));
8385 within.extend_from_slice(&[0x01, 20, 0xae]);
8386 let mut stack = Vec::new();
8387 assert!(eval_script(&within, &mut stack, 0, SigVersion::Base).unwrap());
8388
8389 let mut over = vec![0x61; 181];
8390 over.push(0x00);
8391 over.push(0x00);
8392 over.extend(std::iter::repeat(0x00).take(20));
8393 over.extend_from_slice(&[0x01, 20, 0xae]);
8394 let mut stack = Vec::new();
8395 assert!(eval_script(&over, &mut stack, 0, SigVersion::Base).is_err());
8396
8397 let mut ignored = vec![0x61; 181];
8399 ignored.extend_from_slice(&[0x00, 0x00, 0x01, 21, 0xae]);
8400 let mut stack = Vec::new();
8401 assert!(!eval_script(&ignored, &mut stack, 0, SigVersion::Base).unwrap());
8402 }
8403
8404 #[test]
8405 fn false_script_result_is_an_empty_vector() {
8406 let mut stack = Vec::new();
8407 assert!(eval_script(&[0x51, 0x52, 0x87], &mut stack, 0, SigVersion::Base).unwrap());
8408 assert!(stack.last().unwrap().is_empty());
8409
8410 let mut stack = Vec::new();
8411 assert!(eval_script(&[0x51, 0x51, 0x87], &mut stack, 0, SigVersion::Base).unwrap());
8412 assert_eq!(stack[0].as_slice(), &[1]);
8413
8414 let mut stack = Vec::new();
8415 assert!(
8416 eval_script(
8417 &[0x00, 0x01, 0x02, 0xac, 0x82],
8418 &mut stack,
8419 0,
8420 SigVersion::Base
8421 )
8422 .unwrap()
8423 );
8424 assert!(stack.last().unwrap().is_empty());
8425
8426 let mut stack = Vec::new();
8427 assert!(
8428 eval_script(
8429 &[0x00, 0x00, 0x51, 0x00, 0x51, 0xae, 0x82],
8430 &mut stack,
8431 0,
8432 SigVersion::Base
8433 )
8434 .unwrap()
8435 );
8436 assert!(stack.last().unwrap().is_empty());
8437 }
8438
8439 #[test]
8440 fn non_der_signature_aborts_the_script() {
8441 use crate::constants::BIP66_ACTIVATION_MAINNET;
8442 use crate::types::{Network, OutPoint, Transaction, TransactionInput, TransactionOutput};
8443
8444 let tx = Transaction {
8445 version: 1,
8446 inputs: vec![TransactionInput {
8447 prevout: OutPoint {
8448 hash: [0u8; 32],
8449 index: 0,
8450 },
8451 sequence: 0xffff_ffff,
8452 script_sig: vec![],
8453 }]
8454 .into(),
8455 outputs: vec![TransactionOutput {
8456 value: 0,
8457 script_pubkey: vec![],
8458 }]
8459 .into(),
8460 lock_time: 0,
8461 };
8462 let eval = |script: &[u8], flags: u32| {
8463 let mut stack = Vec::new();
8464 eval_script_with_context_full(
8465 script,
8466 &mut stack,
8467 flags,
8468 &tx,
8469 0,
8470 &[0],
8471 &[&[]],
8472 Some(BIP66_ACTIVATION_MAINNET),
8473 None,
8474 Network::Mainnet,
8475 SigVersion::Base,
8476 None,
8477 None,
8478 None,
8479 None,
8480 #[cfg(feature = "production")]
8481 None,
8482 None,
8483 #[cfg(feature = "production")]
8484 None,
8485 )
8486 };
8487
8488 let bad = [0x03, 0x30, 0x01, 0x01, 0x01, 0x02, 0xac, 0x75, 0x51];
8489 assert!(eval(&bad, 0x04).is_err());
8490 let empty = [0x00, 0x01, 0x02, 0xac, 0x75, 0x51];
8491 assert!(eval(&empty, 0x04).unwrap());
8492 assert!(eval(&bad, 0).unwrap());
8493 }
8494
8495 #[test]
8496 fn nested_v0_redeem_push_must_be_canonical() {
8497 let mut redeem = vec![0x00, 0x14];
8498 redeem.extend_from_slice(&[0xab; 20]);
8499 let canonical = serialize_push_data(&redeem);
8500 let mut pushdata1 = vec![0x4c, redeem.len() as u8];
8501 pushdata1.extend_from_slice(&redeem);
8502 assert!(redeem_push_is_canonical(&canonical, &redeem));
8503 assert!(!redeem_push_is_canonical(&pushdata1, &redeem));
8504 assert_eq!(canonical[0], 22);
8505 }
8506
8507 #[test]
8508 fn keypath_spend_reaches_the_sighash_check() {
8509 use crate::script::flags::SCRIPT_VERIFY_WITNESS;
8510 use crate::types::{Network, OutPoint, Transaction, TransactionInput, TransactionOutput};
8511
8512 let mut script_pubkey = vec![OP_1, PUSH_32_BYTES];
8513 script_pubkey.extend_from_slice(&[0x11u8; 32]);
8514 let tx = Transaction {
8515 version: 2,
8516 inputs: vec![TransactionInput {
8517 prevout: OutPoint {
8518 hash: [0x22; 32],
8519 index: 0,
8520 },
8521 script_sig: vec![].into(),
8522 sequence: 0xffff_ffff,
8523 }]
8524 .into(),
8525 outputs: vec![TransactionOutput {
8526 value: 1_000,
8527 script_pubkey: vec![OP_1].into(),
8528 }]
8529 .into(),
8530 lock_time: 0,
8531 };
8532 let witness = vec![vec![0x40u8; 64]];
8533 let result = verify_script_with_context_full(
8534 &vec![].into(),
8535 &script_pubkey,
8536 Some(&witness),
8537 SCRIPT_VERIFY_WITNESS,
8538 &tx,
8539 0,
8540 &[],
8541 &[],
8542 Some(1),
8543 None,
8544 Network::Regtest,
8545 SigVersion::Tapscript,
8546 #[cfg(feature = "production")]
8547 None,
8548 None,
8549 #[cfg(feature = "production")]
8550 None,
8551 #[cfg(feature = "production")]
8552 None,
8553 #[cfg(feature = "production")]
8554 None,
8555 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
8556 None,
8557 );
8558 assert!(
8559 result.is_err(),
8560 "a key-path witness with no prevouts must reach the sighash check, got {result:?}"
8561 );
8562 }
8563
8564 #[test]
8565 fn p2sh_wrapped_unknown_witness_program_succeeds() {
8566 use digest::Digest;
8567
8568 let redeem = vec![0x52, 0x02, 0x11, 0x22];
8569 let hash = ripemd::Ripemd160::digest(sha2::Sha256::digest(&redeem));
8570 let mut script_pubkey = vec![OP_HASH160, 0x14];
8571 script_pubkey.extend_from_slice(&hash);
8572 script_pubkey.push(OP_EQUAL);
8573 let script_sig = serialize_push_data(&redeem);
8574 let witness = vec![vec![1u8]];
8575 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
8576 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
8577 let verify = |flags: u32, wit: Option<&Vec<Vec<u8>>>| {
8578 verify_script_with_context_full(
8579 &script_sig,
8580 &script_pubkey,
8581 wit,
8582 flags,
8583 &tx,
8584 0,
8585 &pv,
8586 &psp_refs,
8587 Some(500_000),
8588 None,
8589 crate::types::Network::Mainnet,
8590 SigVersion::Base,
8591 #[cfg(feature = "production")]
8592 None,
8593 None,
8594 #[cfg(feature = "production")]
8595 None,
8596 #[cfg(feature = "production")]
8597 None,
8598 #[cfg(feature = "production")]
8599 None,
8600 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
8601 None,
8602 )
8603 };
8604 assert!(verify(0x801, Some(&witness)).unwrap());
8605 assert!(!verify(0x801 | 0x1000, Some(&witness)).unwrap());
8606 let mut pushdata1 = vec![0x4c, redeem.len() as u8];
8607 pushdata1.extend_from_slice(&redeem);
8608 let (tx_pd, pv_pd, psp_pd) = minimal_tx_and_prevouts(&pushdata1, &script_pubkey);
8609 let psp_pd_refs: Vec<&[u8]> = psp_pd.iter().map(|b| b.as_ref()).collect();
8610 let noncanonical = verify_script_with_context_full(
8611 &pushdata1,
8612 &script_pubkey,
8613 Some(&witness),
8614 0x801,
8615 &tx_pd,
8616 0,
8617 &pv_pd,
8618 &psp_pd_refs,
8619 Some(500_000),
8620 None,
8621 crate::types::Network::Mainnet,
8622 SigVersion::Base,
8623 #[cfg(feature = "production")]
8624 None,
8625 None,
8626 #[cfg(feature = "production")]
8627 None,
8628 #[cfg(feature = "production")]
8629 None,
8630 #[cfg(feature = "production")]
8631 None,
8632 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
8633 None,
8634 );
8635 assert!(!noncanonical.unwrap());
8636
8637 let invalid_v0 = vec![0x00, 0x02, 0x11, 0x22];
8638 let hash = ripemd::Ripemd160::digest(sha2::Sha256::digest(&invalid_v0));
8639 let mut script_pubkey = vec![OP_HASH160, 0x14];
8640 script_pubkey.extend_from_slice(&hash);
8641 script_pubkey.push(OP_EQUAL);
8642 let script_sig = serialize_push_data(&invalid_v0);
8643 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
8644 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
8645 let result = verify_script_with_context_full(
8646 &script_sig,
8647 &script_pubkey,
8648 Some(&witness),
8649 0x801,
8650 &tx,
8651 0,
8652 &pv,
8653 &psp_refs,
8654 Some(500_000),
8655 None,
8656 crate::types::Network::Mainnet,
8657 SigVersion::Base,
8658 #[cfg(feature = "production")]
8659 None,
8660 None,
8661 #[cfg(feature = "production")]
8662 None,
8663 #[cfg(feature = "production")]
8664 None,
8665 #[cfg(feature = "production")]
8666 None,
8667 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
8668 None,
8669 );
8670 assert!(!result.unwrap());
8671 }
8672
8673 #[test]
8677 fn witness_program_false_payload_is_rejected() {
8678 use crate::constants::TAPROOT_ACTIVATION_MAINNET;
8679 use digest::Digest;
8680
8681 let verify = |script_pubkey: &[u8], script_sig: &[u8], height: u64| {
8682 let script_sig = script_sig.to_vec();
8683 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, script_pubkey);
8684 let refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
8685 verify_script_with_context_full(
8686 &script_sig,
8687 script_pubkey,
8688 None,
8689 0x801,
8690 &tx,
8691 0,
8692 &pv,
8693 &refs,
8694 Some(height),
8695 None,
8696 crate::types::Network::Mainnet,
8697 SigVersion::Base,
8698 #[cfg(feature = "production")]
8699 None,
8700 None,
8701 #[cfg(feature = "production")]
8702 None,
8703 #[cfg(feature = "production")]
8704 None,
8705 #[cfg(feature = "production")]
8706 None,
8707 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
8708 None,
8709 )
8710 };
8711
8712 let payloads: &[(&[u8], bool)] = &[
8713 (&[0x00, 0x00], false),
8714 (&[0x00, 0x80], false),
8715 (&[0x01, 0x00], true),
8716 ];
8717 for version in 0x51u8..=0x60 {
8718 for &(payload, truthy) in payloads {
8719 let mut script = vec![version, payload.len() as u8];
8720 script.extend_from_slice(payload);
8721 let got = verify(&script, &[], 400_000).unwrap();
8722 let taproot_v1 = version == 0x51 && payload.len() == 32;
8723 let expect = truthy && !taproot_v1;
8724 assert_eq!(got, expect, "native {script:02x?}");
8725 }
8726 }
8727
8728 let zeros = vec![0u8; 32];
8729 let mut neg = vec![0u8; 32];
8730 neg[31] = 0x80;
8731 let mut nonzero = vec![0u8; 32];
8732 nonzero[0] = 1;
8733 for (payload, truthy) in [(&zeros[..], false), (&neg[..], false), (&nonzero[..], true)] {
8734 let mut script = vec![0x51, 0x20];
8735 script.extend_from_slice(payload);
8736 assert!(!verify(&script, &[], TAPROOT_ACTIVATION_MAINNET).unwrap());
8737 let before = verify(&script, &[], 400_000).unwrap();
8738 assert_eq!(before, truthy, "v1-32 before taproot {payload:02x?}");
8739 }
8740
8741 let redeem = vec![0x52, 0x02, 0x00, 0x00];
8742 let hash = ripemd::Ripemd160::digest(sha2::Sha256::digest(&redeem));
8743 let mut p2sh = vec![OP_HASH160, 0x14];
8744 p2sh.extend_from_slice(&hash);
8745 p2sh.push(OP_EQUAL);
8746 let push = serialize_push_data(&redeem);
8747 assert!(!verify(&p2sh, &push, 400_000).unwrap());
8748
8749 let redeem_ok = vec![0x52, 0x02, 0x01, 0x00];
8750 let hash_ok = ripemd::Ripemd160::digest(sha2::Sha256::digest(&redeem_ok));
8751 let mut p2sh_ok = vec![OP_HASH160, 0x14];
8752 p2sh_ok.extend_from_slice(&hash_ok);
8753 p2sh_ok.push(OP_EQUAL);
8754 assert!(verify(&p2sh_ok, &serialize_push_data(&redeem_ok), 400_000).unwrap());
8755 }
8756
8757 #[test]
8761 fn p2sh_wrapped_v1_32_stays_upgradable_after_taproot() {
8762 use crate::constants::TAPROOT_ACTIVATION_MAINNET;
8763 use crate::script::flags::{SCRIPT_VERIFY_P2SH, SCRIPT_VERIFY_WITNESS};
8764 use digest::Digest;
8765
8766 let flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_WITNESS;
8767 let verify = |script_pubkey: &[u8], script_sig: &[u8]| {
8768 let script_sig = script_sig.to_vec();
8769 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, script_pubkey);
8770 let refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
8771 verify_script_with_context_full(
8772 &script_sig,
8773 script_pubkey,
8774 None,
8775 flags,
8776 &tx,
8777 0,
8778 &pv,
8779 &refs,
8780 Some(TAPROOT_ACTIVATION_MAINNET),
8781 None,
8782 crate::types::Network::Mainnet,
8783 SigVersion::Base,
8784 #[cfg(feature = "production")]
8785 None,
8786 None,
8787 #[cfg(feature = "production")]
8788 None,
8789 #[cfg(feature = "production")]
8790 None,
8791 #[cfg(feature = "production")]
8792 None,
8793 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
8794 None,
8795 )
8796 };
8797
8798 let program_len = PUSH_32_BYTES as usize;
8799 let mut truthy_redeem = vec![OP_1, PUSH_32_BYTES];
8800 truthy_redeem.extend(std::iter::repeat(1u8).take(program_len));
8801 let truthy_hash = ripemd::Ripemd160::digest(sha2::Sha256::digest(&truthy_redeem));
8802 let mut truthy_p2sh = vec![OP_HASH160, PUSH_20_BYTES];
8803 truthy_p2sh.extend_from_slice(&truthy_hash);
8804 truthy_p2sh.push(OP_EQUAL);
8805 assert!(verify(&truthy_p2sh, &serialize_push_data(&truthy_redeem)).unwrap());
8806 assert!(!verify(&truthy_redeem, &[]).unwrap());
8807
8808 let mut zero_redeem = vec![OP_1, PUSH_32_BYTES];
8809 zero_redeem.extend(std::iter::repeat(0u8).take(program_len));
8810 let zero_hash = ripemd::Ripemd160::digest(sha2::Sha256::digest(&zero_redeem));
8811 let mut zero_p2sh = vec![OP_HASH160, PUSH_20_BYTES];
8812 zero_p2sh.extend_from_slice(&zero_hash);
8813 zero_p2sh.push(OP_EQUAL);
8814 assert!(!verify(&zero_p2sh, &serialize_push_data(&zero_redeem)).unwrap());
8815 }
8816
8817 #[test]
8818 fn test_eval_script_simple() {
8819 let script = vec![OP_1]; let mut stack = Vec::new();
8821
8822 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap());
8823 assert_eq!(stack.len(), 1);
8824 assert_eq!(stack[0].as_slice(), &[1]);
8825 }
8826
8827 #[test]
8828 fn test_eval_script_overflow() {
8829 let script = vec![0x51; MAX_STACK_SIZE + 1]; let mut stack = Vec::new();
8831
8832 assert!(eval_script(&script, &mut stack, 0, SigVersion::Base).is_err());
8833 }
8834
8835 #[test]
8836 fn test_verify_script_simple() {
8837 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());
8848 }
8849
8850 #[test]
8855 fn test_op_0() {
8856 let script = vec![OP_0]; let mut stack = Vec::new();
8858 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8859 assert!(result); assert_eq!(stack.len(), 1);
8861 assert!(stack[0].is_empty());
8862 }
8863
8864 #[test]
8865 fn test_op_1_to_op_16() {
8866 for i in 1..=16 {
8868 let opcode = 0x50 + i;
8869 let script = vec![opcode];
8870 let mut stack = Vec::new();
8871 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8872 assert!(result);
8873 assert_eq!(stack.len(), 1);
8874 assert_eq!(stack[0].as_slice(), &[i]);
8875 }
8876 }
8877
8878 #[test]
8879 fn test_op_dup() {
8880 let script = vec![0x51, 0x76]; let mut stack = Vec::new();
8882 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8883 assert!(result); assert_eq!(stack.len(), 2);
8885 assert_eq!(stack[0].as_slice(), &[1]);
8886 assert_eq!(stack[1].as_slice(), &[1]);
8887 }
8888
8889 #[test]
8890 fn test_op_dup_empty_stack() {
8891 let script = vec![OP_DUP]; let mut stack = Vec::new();
8893 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8894 assert!(!result);
8895 }
8896
8897 #[test]
8898 fn test_op_hash160() {
8899 let script = vec![OP_1, OP_HASH160]; let mut stack = Vec::new();
8901 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8902 assert!(result);
8903 assert_eq!(stack.len(), 1);
8904 assert_eq!(stack[0].len(), 20); }
8906
8907 #[test]
8908 fn test_op_hash160_empty_stack() {
8909 let script = vec![OP_HASH160]; let mut stack = Vec::new();
8911 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8912 assert!(!result);
8913 }
8914
8915 #[test]
8916 fn test_op_hash256() {
8917 let script = vec![OP_1, OP_HASH256]; let mut stack = Vec::new();
8919 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8920 assert!(result);
8921 assert_eq!(stack.len(), 1);
8922 assert_eq!(stack[0].len(), 32); }
8924
8925 #[test]
8926 fn test_op_hash256_empty_stack() {
8927 let script = vec![OP_HASH256]; let mut stack = Vec::new();
8929 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8930 assert!(!result);
8931 }
8932
8933 #[test]
8934 fn test_op_equal() {
8935 let script = vec![0x51, 0x51, 0x87]; let mut stack = Vec::new();
8937 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8938 assert!(result);
8939 assert_eq!(stack.len(), 1);
8940 assert_eq!(stack[0].as_slice(), &[1]); }
8942
8943 #[test]
8944 fn test_op_equal_false() {
8945 let script = vec![0x51, 0x52, 0x87]; let mut stack = Vec::new();
8947 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8948 assert!(result); assert_eq!(stack.len(), 1);
8950 assert!(stack[0].is_empty()); }
8952
8953 #[test]
8954 fn test_op_equal_insufficient_stack() {
8955 let script = vec![0x51, 0x87]; let mut stack = Vec::new();
8957 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
8958 assert!(
8959 result.is_err(),
8960 "OP_EQUAL with insufficient stack should return error"
8961 );
8962 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
8963 assert_eq!(
8964 code,
8965 crate::error::ScriptErrorCode::InvalidStackOperation,
8966 "Should return InvalidStackOperation"
8967 );
8968 }
8969 }
8970
8971 #[test]
8972 fn test_op_verify() {
8973 let script = vec![0x51, 0x69]; let mut stack = Vec::new();
8975 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8976 assert!(result); assert_eq!(stack.len(), 0); }
8979
8980 #[test]
8981 fn test_op_verify_false() {
8982 let script = vec![0x00, 0x69]; let mut stack = Vec::new();
8984 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8985 assert!(!result);
8986 }
8987
8988 #[test]
8989 fn test_op_verify_empty_stack() {
8990 let script = vec![OP_VERIFY]; let mut stack = Vec::new();
8992 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
8993 assert!(!result);
8994 }
8995
8996 #[test]
8997 fn test_op_equalverify() {
8998 let script = vec![0x51, 0x51, 0x88]; let mut stack = Vec::new();
9000 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9001 assert!(result); assert_eq!(stack.len(), 0); }
9004
9005 #[test]
9006 fn test_op_equalverify_false() {
9007 let script = vec![0x51, 0x52, 0x88]; let mut stack = Vec::new();
9009 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
9010 assert!(
9011 result.is_err(),
9012 "OP_EQUALVERIFY with false condition should return error"
9013 );
9014 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
9015 assert_eq!(
9016 code,
9017 crate::error::ScriptErrorCode::EqualVerify,
9018 "Should return EqualVerify"
9019 );
9020 }
9021 }
9022
9023 #[test]
9024 fn test_op_checksig() {
9025 let script = vec![OP_1, OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
9029 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9030 assert!(result); assert_eq!(stack.len(), 1);
9032 }
9034
9035 #[test]
9036 fn test_op_checksig_insufficient_stack() {
9037 let script = vec![OP_1, OP_CHECKSIG]; let mut stack = Vec::new();
9039 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
9040 assert!(
9041 result.is_err(),
9042 "OP_CHECKSIG with insufficient stack should return error"
9043 );
9044 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
9045 assert_eq!(
9046 code,
9047 crate::error::ScriptErrorCode::InvalidStackOperation,
9048 "Should return InvalidStackOperation"
9049 );
9050 }
9051 }
9052
9053 #[test]
9054 fn test_unknown_opcode() {
9055 let script = vec![0xff]; let mut stack = Vec::new();
9057 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9058 assert!(!result);
9059 }
9060
9061 #[test]
9062 fn test_script_size_limit() {
9063 let script = vec![0x51; MAX_SCRIPT_SIZE + 1]; let mut stack = Vec::new();
9065 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
9066 assert!(result.is_err());
9067 }
9068
9069 #[test]
9070 fn test_operation_count_limit() {
9071 let script = vec![0x61; MAX_SCRIPT_OPS + 1]; let mut stack = Vec::new();
9074 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
9075 assert!(result.is_err());
9076 }
9077
9078 #[test]
9079 fn test_stack_underflow_multiple_ops() {
9080 let script = vec![0x51, 0x87, 0x87]; let mut stack = Vec::new();
9082 let result = eval_script(&script, &mut stack, 0, SigVersion::Base);
9083 assert!(result.is_err(), "Stack underflow should return error");
9084 if let Err(crate::error::ConsensusError::ScriptErrorWithCode { code, .. }) = result {
9085 assert_eq!(
9086 code,
9087 crate::error::ScriptErrorCode::InvalidStackOperation,
9088 "Should return InvalidStackOperation"
9089 );
9090 }
9091 }
9092
9093 #[test]
9094 fn test_final_stack_empty() {
9095 let script = vec![0x51, 0x52]; let mut stack = Vec::new();
9098 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9099 assert!(result); assert_eq!(stack.len(), 2);
9101 }
9102
9103 #[test]
9104 fn test_final_stack_false() {
9105 let script = vec![OP_0]; let mut stack = Vec::new();
9108 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9109 assert!(result); }
9111
9112 #[test]
9113 fn test_verify_script_with_witness() {
9114 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_1]; let witness = vec![OP_1]; let flags = 0;
9119
9120 let result = verify_script(&script_sig, &script_pubkey, Some(&witness), flags).unwrap();
9121 assert!(result); }
9123
9124 #[test]
9125 fn test_verify_script_failure() {
9126 let script_sig = vec![OP_1]; let script_pubkey = vec![OP_0]; let witness = None;
9130 let flags = 0;
9131
9132 let result = verify_script(&script_sig, &script_pubkey, witness, flags).unwrap();
9133 assert!(!result); }
9135
9136 #[test]
9141 fn test_op_ifdup_true() {
9142 let script = vec![OP_1, OP_IFDUP]; let mut stack = Vec::new();
9144 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9145 assert!(result); assert_eq!(stack.len(), 2);
9147 assert_eq!(stack[0].as_slice(), &[1]);
9148 assert_eq!(stack[1].as_slice(), &[1]);
9149 }
9150
9151 #[test]
9152 fn test_op_ifdup_false() {
9153 let script = vec![OP_0, OP_IFDUP]; let mut stack = Vec::new();
9155 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9156 assert!(result); assert_eq!(stack.len(), 1);
9158 assert_eq!(stack[0].as_slice(), &[] as &[u8]);
9159 }
9160
9161 #[test]
9162 fn test_op_depth() {
9163 let script = vec![OP_1, OP_1, OP_DEPTH]; let mut stack = Vec::new();
9165 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9166 assert!(result); assert_eq!(stack.len(), 3);
9168 assert_eq!(stack[2].as_slice(), &[2]); }
9170
9171 #[test]
9172 fn test_op_drop() {
9173 let script = vec![OP_1, OP_2, OP_DROP]; let mut stack = Vec::new();
9175 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9176 assert!(result); assert_eq!(stack.len(), 1);
9178 assert_eq!(stack[0].as_slice(), &[1]);
9179 }
9180
9181 #[test]
9182 fn test_op_drop_empty_stack() {
9183 let script = vec![OP_DROP]; let mut stack = Vec::new();
9185 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9186 assert!(!result);
9187 assert_eq!(stack.len(), 0);
9188 }
9189
9190 #[test]
9191 fn test_op_nip() {
9192 let script = vec![OP_1, OP_2, OP_NIP]; let mut stack = Vec::new();
9194 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9195 assert!(result); assert_eq!(stack.len(), 1);
9197 assert_eq!(stack[0].as_slice(), &[2]);
9198 }
9199
9200 #[test]
9201 fn test_op_nip_insufficient_stack() {
9202 let script = vec![OP_1, OP_NIP]; let mut stack = Vec::new();
9204 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9205 assert!(!result);
9206 assert_eq!(stack.len(), 1);
9207 }
9208
9209 #[test]
9210 fn test_op_over() {
9211 let script = vec![OP_1, OP_2, OP_OVER]; let mut stack = Vec::new();
9213 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9214 assert!(result); assert_eq!(stack.len(), 3);
9216 assert_eq!(stack[0].as_slice(), &[1]);
9217 assert_eq!(stack[1].as_slice(), &[2]);
9218 assert_eq!(stack[2].as_slice(), &[1]);
9219 }
9220
9221 #[test]
9222 fn test_op_over_insufficient_stack() {
9223 let script = vec![OP_1, OP_OVER]; let mut stack = Vec::new();
9225 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9226 assert!(!result);
9227 assert_eq!(stack.len(), 1);
9228 }
9229
9230 #[test]
9231 fn test_op_pick() {
9232 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_PICK]; let mut stack = Vec::new();
9234 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9235 assert!(result); assert_eq!(stack.len(), 4);
9237 assert_eq!(stack[3].as_slice(), &[2]); }
9239
9240 #[test]
9241 fn test_op_pick_empty_n() {
9242 let script = vec![OP_1, OP_0, OP_PICK];
9244 let mut stack = Vec::new();
9245 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9246 assert!(result); assert_eq!(stack.len(), 2);
9248 assert_eq!(stack[1].as_slice(), &[1]); }
9250
9251 #[test]
9252 fn test_op_pick_invalid_index() {
9253 let script = vec![OP_1, OP_2, OP_PICK]; let mut stack = Vec::new();
9255 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9256 assert!(!result);
9257 assert_eq!(stack.len(), 1);
9258 }
9259
9260 #[test]
9261 fn test_op_roll() {
9262 let script = vec![OP_1, OP_2, OP_3, OP_1, OP_ROLL]; let mut stack = Vec::new();
9264 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9265 assert!(result); assert_eq!(stack.len(), 3);
9267 assert_eq!(stack[0].as_slice(), &[1]);
9268 assert_eq!(stack[1].as_slice(), &[3]);
9269 assert_eq!(stack[2].as_slice(), &[2]); }
9271
9272 #[test]
9273 fn test_op_roll_zero_n() {
9274 let script = vec![OP_1, OP_0, OP_ROLL]; let mut stack = Vec::new();
9277 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9278 assert!(result); assert_eq!(stack.len(), 1);
9280 assert_eq!(stack[0].as_slice(), &[1]);
9281 }
9282
9283 #[test]
9284 fn test_op_roll_invalid_index() {
9285 let script = vec![OP_1, OP_2, OP_ROLL]; let mut stack = Vec::new();
9287 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9288 assert!(!result);
9289 assert_eq!(stack.len(), 1);
9290 }
9291
9292 #[test]
9293 fn test_op_rot() {
9294 let script = vec![OP_1, OP_2, OP_3, OP_ROT]; let mut stack = Vec::new();
9296 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9297 assert!(result); assert_eq!(stack.len(), 3);
9299 assert_eq!(stack[0].as_slice(), &[2]);
9300 assert_eq!(stack[1].as_slice(), &[3]);
9301 assert_eq!(stack[2].as_slice(), &[1]);
9302 }
9303
9304 #[test]
9305 fn test_op_rot_insufficient_stack() {
9306 let script = vec![OP_1, OP_2, OP_ROT]; let mut stack = Vec::new();
9308 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9309 assert!(!result);
9310 assert_eq!(stack.len(), 2);
9311 }
9312
9313 #[test]
9314 fn test_op_swap() {
9315 let script = vec![OP_1, OP_2, OP_SWAP]; let mut stack = Vec::new();
9317 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9318 assert!(result); assert_eq!(stack.len(), 2);
9320 assert_eq!(stack[0].as_slice(), &[2]);
9321 assert_eq!(stack[1].as_slice(), &[1]);
9322 }
9323
9324 #[test]
9325 fn test_op_swap_insufficient_stack() {
9326 let script = vec![OP_1, OP_SWAP]; let mut stack = Vec::new();
9328 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9329 assert!(!result);
9330 assert_eq!(stack.len(), 1);
9331 }
9332
9333 #[test]
9334 fn test_op_tuck() {
9335 let script = vec![OP_1, OP_2, OP_TUCK]; let mut stack = Vec::new();
9337 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9338 assert!(result); assert_eq!(stack.len(), 3);
9340 assert_eq!(stack[0].as_slice(), &[2]);
9341 assert_eq!(stack[1].as_slice(), &[1]);
9342 assert_eq!(stack[2].as_slice(), &[2]);
9343 }
9344
9345 #[test]
9346 fn test_op_tuck_insufficient_stack() {
9347 let script = vec![OP_1, OP_TUCK]; let mut stack = Vec::new();
9349 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9350 assert!(!result);
9351 assert_eq!(stack.len(), 1);
9352 }
9353
9354 #[test]
9355 fn test_op_2drop() {
9356 let script = vec![OP_1, OP_2, OP_3, OP_2DROP]; let mut stack = Vec::new();
9358 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9359 assert!(result); assert_eq!(stack.len(), 1);
9361 assert_eq!(stack[0].as_slice(), &[1]);
9362 }
9363
9364 #[test]
9365 fn test_op_2drop_insufficient_stack() {
9366 let script = vec![OP_1, OP_2DROP]; let mut stack = Vec::new();
9368 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9369 assert!(!result);
9370 assert_eq!(stack.len(), 1);
9371 }
9372
9373 #[test]
9374 fn test_op_2dup() {
9375 let script = vec![OP_1, OP_2, OP_2DUP]; let mut stack = Vec::new();
9377 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9378 assert!(result); assert_eq!(stack.len(), 4);
9380 assert_eq!(stack[0].as_slice(), &[1]);
9381 assert_eq!(stack[1].as_slice(), &[2]);
9382 assert_eq!(stack[2].as_slice(), &[1]);
9383 assert_eq!(stack[3].as_slice(), &[2]);
9384 }
9385
9386 #[test]
9387 fn test_op_2dup_insufficient_stack() {
9388 let script = vec![OP_1, OP_2DUP]; let mut stack = Vec::new();
9390 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9391 assert!(!result);
9392 assert_eq!(stack.len(), 1);
9393 }
9394
9395 #[test]
9396 fn test_op_3dup() {
9397 let script = vec![OP_1, OP_2, OP_3, OP_3DUP]; let mut stack = Vec::new();
9399 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9400 assert!(result); assert_eq!(stack.len(), 6);
9402 assert_eq!(stack[0].as_slice(), &[1]);
9403 assert_eq!(stack[1].as_slice(), &[2]);
9404 assert_eq!(stack[2].as_slice(), &[3]);
9405 assert_eq!(stack[3].as_slice(), &[1]);
9406 assert_eq!(stack[4].as_slice(), &[2]);
9407 assert_eq!(stack[5].as_slice(), &[3]);
9408 }
9409
9410 #[test]
9411 fn test_op_3dup_insufficient_stack() {
9412 let script = vec![OP_1, OP_2, OP_3DUP]; let mut stack = Vec::new();
9414 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9415 assert!(!result);
9416 assert_eq!(stack.len(), 2);
9417 }
9418
9419 #[test]
9420 fn test_op_2over() {
9421 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2OVER]; let mut stack = Vec::new();
9423 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9424 assert!(result); assert_eq!(stack.len(), 6);
9426 assert_eq!(stack[4].as_slice(), &[1]); assert_eq!(stack[5].as_slice(), &[2]);
9428 }
9429
9430 #[test]
9431 fn test_op_2over_insufficient_stack() {
9432 let script = vec![OP_1, OP_2, OP_3, OP_2OVER]; let mut stack = Vec::new();
9434 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9435 assert!(!result);
9436 assert_eq!(stack.len(), 3);
9437 }
9438
9439 #[test]
9440 fn test_op_2rot() {
9441 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_5, OP_6, OP_2ROT]; let mut stack = Vec::new();
9446 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9447 assert!(result); assert_eq!(stack.len(), 6);
9449 assert_eq!(stack[4].as_slice(), &[1]); assert_eq!(stack[5].as_slice(), &[2]); }
9452
9453 #[test]
9454 fn test_op_2rot_insufficient_stack() {
9455 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2ROT]; let mut stack = Vec::new();
9457 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9458 assert!(!result);
9459 assert_eq!(stack.len(), 4);
9460 }
9461
9462 #[test]
9463 fn test_op_2swap() {
9464 let script = vec![OP_1, OP_2, OP_3, OP_4, OP_2SWAP]; let mut stack = Vec::new();
9466 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9467 assert!(result); assert_eq!(stack.len(), 4);
9469 assert_eq!(stack[0].as_slice(), &[3]); assert_eq!(stack[1].as_slice(), &[4]);
9471 assert_eq!(stack[2].as_slice(), &[1]);
9472 assert_eq!(stack[3].as_slice(), &[2]);
9473 }
9474
9475 #[test]
9476 fn test_op_2swap_insufficient_stack() {
9477 let script = vec![OP_1, OP_2, OP_3, OP_2SWAP]; let mut stack = Vec::new();
9479 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9480 assert!(!result);
9481 assert_eq!(stack.len(), 3);
9482 }
9483
9484 #[test]
9485 fn test_op_size() {
9486 let script = vec![OP_1, OP_SIZE]; let mut stack = Vec::new();
9488 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9489 assert!(result); assert_eq!(stack.len(), 2);
9491 assert_eq!(stack[0].as_slice(), &[1]);
9492 assert_eq!(stack[1].as_slice(), &[1]); }
9494
9495 #[test]
9496 fn test_op_size_empty_stack() {
9497 let script = vec![OP_SIZE]; let mut stack = Vec::new();
9499 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9500 assert!(!result);
9501 assert_eq!(stack.len(), 0);
9502 }
9503
9504 #[test]
9505 fn test_op_return() {
9506 let script = vec![OP_1, OP_RETURN]; let mut stack = Vec::new();
9508 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9509 assert!(!result); assert_eq!(stack.len(), 1);
9511 }
9512
9513 #[test]
9514 fn test_op_checksigverify() {
9515 let script = vec![OP_1, OP_2, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
9517 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9518 assert!(!result); assert_eq!(stack.len(), 0);
9520 }
9521
9522 #[test]
9523 fn test_op_checksigverify_insufficient_stack() {
9524 let script = vec![OP_1, OP_CHECKSIGVERIFY]; let mut stack = Vec::new();
9526 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9527 assert!(!result);
9528 assert_eq!(stack.len(), 1);
9529 }
9530
9531 #[test]
9532 fn test_unknown_opcode_comprehensive() {
9533 let script = vec![OP_1, 0xff]; let mut stack = Vec::new();
9535 let result = eval_script(&script, &mut stack, 0, SigVersion::Base).unwrap();
9536 assert!(!result); assert_eq!(stack.len(), 1);
9538 }
9539
9540 #[test]
9541 fn test_verify_signature_invalid_pubkey() {
9542 let secp = signature::new_secp();
9543 let invalid_pubkey = vec![0x00]; let signature = vec![0x30, 0x06, 0x02, 0x01, 0x00, 0x02, 0x01, 0x00]; let dummy_hash = [0u8; 32];
9546 let result = signature::verify_signature(
9547 &secp,
9548 &invalid_pubkey,
9549 &signature,
9550 &dummy_hash,
9551 0,
9552 0,
9553 crate::types::Network::Regtest,
9554 SigVersion::Base,
9555 );
9556 assert!(!result.unwrap_or(false));
9557 }
9558
9559 #[test]
9560 fn test_verify_signature_invalid_signature() {
9561 let secp = signature::new_secp();
9562 let pubkey = vec![
9563 0x02, 0x79, 0xbe, 0x66, 0x7e, 0xf9, 0xdc, 0xbb, 0xac, 0x55, 0xa0, 0x62, 0x95, 0xce,
9564 0x87, 0x0b, 0x07, 0x02, 0x9b, 0xfc, 0xdb, 0x2d, 0xce, 0x28, 0xd9, 0x59, 0xf2, 0x81,
9565 0x5b, 0x16, 0xf8, 0x17, 0x98,
9566 ]; let invalid_signature = vec![0x00]; let dummy_hash = [0u8; 32];
9569 let result = signature::verify_signature(
9570 &secp,
9571 &pubkey,
9572 &invalid_signature,
9573 &dummy_hash,
9574 0,
9575 0,
9576 crate::types::Network::Regtest,
9577 SigVersion::Base,
9578 );
9579 assert!(!result.unwrap_or(false));
9580 }
9581
9582 fn minimal_tx_and_prevouts(
9588 script_sig: &[u8],
9589 script_pubkey: &[u8],
9590 ) -> (
9591 crate::types::Transaction,
9592 Vec<i64>,
9593 Vec<crate::types::ByteString>,
9594 ) {
9595 use crate::types::{OutPoint, Transaction, TransactionInput, TransactionOutput};
9596 let tx = Transaction {
9597 version: 1,
9598 inputs: vec![TransactionInput {
9599 prevout: OutPoint {
9600 hash: [0u8; 32],
9601 index: 0,
9602 },
9603 sequence: 0xffff_ffff,
9604 script_sig: script_sig.to_vec(),
9605 }]
9606 .into(),
9607 outputs: vec![TransactionOutput {
9608 value: 0,
9609 script_pubkey: script_pubkey.to_vec(),
9610 }]
9611 .into(),
9612 lock_time: 0,
9613 };
9614 let prevout_values = vec![0i64];
9615 let prevout_script_pubkeys_vec = vec![script_pubkey.to_vec()];
9616 let prevout_script_pubkeys: Vec<&ByteString> = prevout_script_pubkeys_vec.iter().collect();
9617 (tx, prevout_values, prevout_script_pubkeys_vec)
9618 }
9619
9620 #[test]
9621 fn canonical_p2pk_requires_the_push_opcode_to_match_the_key_length() {
9622 let compressed = [2u8; PUSH_33_BYTES as usize];
9623 let mut matched = vec![PUSH_33_BYTES];
9624 matched.extend_from_slice(&compressed);
9625 matched.push(OP_CHECKSIG);
9626 assert_eq!(canonical_p2pk_pubkey(&matched), Some(compressed.as_slice()));
9627
9628 let mut truncated = vec![PUSH_65_BYTES];
9629 truncated.extend_from_slice(&compressed);
9630 truncated.push(OP_CHECKSIG);
9631 assert!(canonical_p2pk_pubkey(&truncated).is_none());
9632
9633 let uncompressed = [4u8; PUSH_65_BYTES as usize];
9634 let mut matched_long = vec![PUSH_65_BYTES];
9635 matched_long.extend_from_slice(&uncompressed);
9636 matched_long.push(OP_CHECKSIG);
9637 assert_eq!(
9638 canonical_p2pk_pubkey(&matched_long),
9639 Some(uncompressed.as_slice())
9640 );
9641
9642 let mut short_push_on_long_script = vec![PUSH_33_BYTES];
9643 short_push_on_long_script.extend_from_slice(&uncompressed);
9644 short_push_on_long_script.push(OP_CHECKSIG);
9645 assert!(canonical_p2pk_pubkey(&short_push_on_long_script).is_none());
9646 }
9647
9648 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
9649 #[test]
9650 fn p2pk_fast_path_does_not_accept_a_push_that_does_not_fit() {
9651 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
9652 use secp256k1::{Message, PublicKey, Secp256k1, SecretKey};
9653
9654 let secp = Secp256k1::new();
9655 let secret = SecretKey::from_slice(&[52u8; 32]).expect("secret");
9656 let pubkey = PublicKey::from_secret_key(&secp, &secret).serialize();
9657
9658 let spend = |script_pubkey: &[u8]| {
9659 let (mut tx, prevout_values, prevout_scripts) =
9660 minimal_tx_and_prevouts(&[], script_pubkey);
9661 let sighash = calculate_transaction_sighash_single_input(
9662 &tx,
9663 0,
9664 script_pubkey,
9665 prevout_values[0],
9666 SighashType::ALL,
9667 None,
9668 )
9669 .expect("sighash");
9670 let msg = Message::from_digest_slice(&sighash).expect("digest");
9671 let mut der = secp.sign_ecdsa(&msg, &secret).serialize_der().to_vec();
9672 der.push(SighashType::ALL.0);
9673 let script_sig = serialize_push_data(&der);
9674 tx.inputs[0].script_sig = script_sig.clone();
9675 let refs: Vec<&[u8]> = prevout_scripts.iter().map(|s| s.as_slice()).collect();
9676 verify_script_with_context_full(
9677 &script_sig,
9678 script_pubkey,
9679 None,
9680 0,
9681 &tx,
9682 0,
9683 &prevout_values,
9684 &refs,
9685 None,
9686 None,
9687 crate::types::Network::Mainnet,
9688 SigVersion::Base,
9689 None,
9690 None,
9691 None,
9692 None,
9693 None,
9694 None,
9695 )
9696 .expect("verify")
9697 };
9698
9699 let mut mismatched = vec![PUSH_65_BYTES];
9700 mismatched.extend_from_slice(&pubkey);
9701 mismatched.push(OP_CHECKSIG);
9702 assert!(!spend(&mismatched));
9703
9704 let mut matched = vec![PUSH_33_BYTES];
9705 matched.extend_from_slice(&pubkey);
9706 matched.push(OP_CHECKSIG);
9707 assert!(spend(&matched));
9708 }
9709
9710 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
9711 #[test]
9712 fn raw_key_multisig_is_not_accepted_by_the_fast_path() {
9713 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
9714 use secp256k1::{Message, PublicKey, Secp256k1, SecretKey};
9715
9716 let secp = Secp256k1::new();
9717 let secret = SecretKey::from_slice(&[52u8; 32]).expect("secret");
9718 let pubkey = PublicKey::from_secret_key(&secp, &secret).serialize();
9719
9720 let spend = |script_pubkey: &[u8]| {
9721 let (mut tx, prevout_values, prevout_scripts) =
9722 minimal_tx_and_prevouts(&[], script_pubkey);
9723 let sighash = calculate_transaction_sighash_single_input(
9724 &tx,
9725 0,
9726 script_pubkey,
9727 prevout_values[0],
9728 SighashType::ALL,
9729 None,
9730 )
9731 .expect("sighash");
9732 let msg = Message::from_digest_slice(&sighash).expect("digest");
9733 let mut der = secp.sign_ecdsa(&msg, &secret).serialize_der().to_vec();
9734 der.push(SighashType::ALL.0);
9735 let mut script_sig = vec![OP_0];
9736 script_sig.extend(serialize_push_data(&der));
9737 tx.inputs[0].script_sig = script_sig.clone();
9738 let refs: Vec<&[u8]> = prevout_scripts.iter().map(|s| s.as_slice()).collect();
9739 verify_script_with_context_full(
9740 &script_sig,
9741 script_pubkey,
9742 None,
9743 0,
9744 &tx,
9745 0,
9746 &prevout_values,
9747 &refs,
9748 None,
9749 None,
9750 crate::types::Network::Mainnet,
9751 SigVersion::Base,
9752 None,
9753 None,
9754 None,
9755 None,
9756 None,
9757 None,
9758 )
9759 };
9760
9761 let mut pushed = vec![OP_1, PUSH_33_BYTES];
9762 pushed.extend_from_slice(&pubkey);
9763 pushed.push(OP_1);
9764 pushed.push(OP_CHECKMULTISIG);
9765 assert!(matches!(spend(&pushed), Ok(true)));
9766
9767 let mut raw = vec![OP_1];
9768 raw.extend_from_slice(&pubkey);
9769 raw.push(OP_1);
9770 raw.push(OP_CHECKMULTISIG);
9771 assert!(!matches!(spend(&raw), Ok(true)));
9772 }
9773
9774 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
9775 #[test]
9776 fn reserved_opcode_multisig_is_not_accepted_by_the_fast_path() {
9777 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
9778 use secp256k1::{Message, PublicKey, Secp256k1, SecretKey};
9779
9780 let secp = Secp256k1::new();
9781 let secret = SecretKey::from_slice(&[52u8; 32]).expect("secret");
9782 let pubkey = PublicKey::from_secret_key(&secp, &secret).serialize();
9783
9784 let mut redeem = vec![OP_1, PUSH_33_BYTES];
9785 redeem.extend_from_slice(&pubkey);
9786 redeem.push(OP_1);
9787 redeem.push(OP_CHECKMULTISIG);
9788
9789 let redeem_hash = Ripemd160::digest(OptimizedSha256::new().hash(&redeem));
9790 let mut p2sh = vec![OP_HASH160, PUSH_20_BYTES];
9791 p2sh.extend_from_slice(&redeem_hash);
9792 p2sh.push(OP_EQUAL);
9793
9794 let spend = |script_pubkey: &[u8], script_code: &[u8], prefix: &[u8], flags: u32| {
9795 let (mut tx, prevout_values, prevout_scripts) =
9796 minimal_tx_and_prevouts(&[], script_pubkey);
9797 let sighash = calculate_transaction_sighash_single_input(
9798 &tx,
9799 0,
9800 script_code,
9801 prevout_values[0],
9802 SighashType::ALL,
9803 None,
9804 )
9805 .expect("sighash");
9806 let msg = Message::from_digest_slice(&sighash).expect("digest");
9807 let mut der = secp.sign_ecdsa(&msg, &secret).serialize_der().to_vec();
9808 der.push(SighashType::ALL.0);
9809 let mut script_sig = prefix.to_vec();
9810 script_sig.extend(serialize_push_data(&der));
9811 if script_pubkey.len() == 23 {
9812 script_sig.extend(serialize_push_data(script_code));
9813 }
9814 tx.inputs[0].script_sig = script_sig.clone();
9815 let refs: Vec<&[u8]> = prevout_scripts.iter().map(|s| s.as_slice()).collect();
9816 verify_script_with_context_full(
9817 &script_sig,
9818 script_pubkey,
9819 None,
9820 flags,
9821 &tx,
9822 0,
9823 &prevout_values,
9824 &refs,
9825 None,
9826 None,
9827 crate::types::Network::Mainnet,
9828 SigVersion::Base,
9829 None,
9830 None,
9831 None,
9832 None,
9833 None,
9834 None,
9835 )
9836 };
9837
9838 assert!(matches!(spend(&redeem, &redeem, &[OP_0], 0), Ok(true)));
9839 assert!(!matches!(
9840 spend(&redeem, &redeem, &[OP_RESERVED], 0),
9841 Ok(true)
9842 ));
9843 assert!(matches!(
9844 spend(&p2sh, &redeem, &[OP_0], flags::SCRIPT_VERIFY_P2SH),
9845 Ok(true)
9846 ));
9847 assert!(!matches!(
9848 spend(&p2sh, &redeem, &[OP_RESERVED], flags::SCRIPT_VERIFY_P2SH),
9849 Ok(true)
9850 ));
9851 }
9852
9853 #[test]
9854 #[allow(deprecated)]
9855 fn verify_script_runs_the_p2sh_redeem_script() {
9856 let bad = vec![OP_RESERVED];
9857 let bad_hash = Ripemd160::digest(OptimizedSha256::new().hash(&bad));
9858 let mut bad_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
9859 bad_pubkey.extend_from_slice(&bad_hash);
9860 bad_pubkey.push(OP_EQUAL);
9861 assert_eq!(
9862 verify_script(
9863 &serialize_push_data(&bad),
9864 &bad_pubkey,
9865 None,
9866 flags::SCRIPT_VERIFY_P2SH
9867 )
9868 .unwrap(),
9869 false
9870 );
9871
9872 let ok = vec![OP_1];
9873 let ok_hash = Ripemd160::digest(OptimizedSha256::new().hash(&ok));
9874 let mut ok_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
9875 ok_pubkey.extend_from_slice(&ok_hash);
9876 ok_pubkey.push(OP_EQUAL);
9877 assert_eq!(
9878 verify_script(
9879 &serialize_push_data(&ok),
9880 &ok_pubkey,
9881 None,
9882 flags::SCRIPT_VERIFY_P2SH
9883 )
9884 .unwrap(),
9885 true
9886 );
9887 }
9888
9889 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
9890 #[test]
9891 fn hybrid_pubkey_is_accepted_without_strictenc() {
9892 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
9893 use secp256k1::{Message, PublicKey, Secp256k1, SecretKey};
9894
9895 const PUBKEY_UNCOMPRESSED: u8 = 0x04;
9896 const PUBKEY_HYBRID_EVEN: u8 = 0x06;
9897 const PUBKEY_HYBRID_ODD: u8 = 0x07;
9898
9899 let secp = Secp256k1::new();
9900 let secret = SecretKey::from_slice(&[53u8; 32]).expect("secret");
9901 let mut uncompressed = PublicKey::from_secret_key(&secp, &secret).serialize_uncompressed();
9902 assert_eq!(uncompressed[0], PUBKEY_UNCOMPRESSED);
9903 let y_odd = uncompressed[64] & 1 == 1;
9904 let matching = if y_odd {
9905 PUBKEY_HYBRID_ODD
9906 } else {
9907 PUBKEY_HYBRID_EVEN
9908 };
9909 let mismatched = if y_odd {
9910 PUBKEY_HYBRID_EVEN
9911 } else {
9912 PUBKEY_HYBRID_ODD
9913 };
9914
9915 let spend = |pubkey: &[u8], flags: u32| {
9916 let mut script_pubkey = vec![PUSH_65_BYTES];
9917 script_pubkey.extend_from_slice(pubkey);
9918 script_pubkey.push(OP_CHECKSIG);
9919 let (mut tx, prevout_values, prevout_scripts) =
9920 minimal_tx_and_prevouts(&[], &script_pubkey);
9921 let sighash = calculate_transaction_sighash_single_input(
9922 &tx,
9923 0,
9924 &script_pubkey,
9925 prevout_values[0],
9926 SighashType::ALL,
9927 None,
9928 )
9929 .expect("sighash");
9930 let msg = Message::from_digest_slice(&sighash).expect("digest");
9931 let mut der = secp.sign_ecdsa(&msg, &secret).serialize_der().to_vec();
9932 der.push(SighashType::ALL.0);
9933 let script_sig = serialize_push_data(&der);
9934 tx.inputs[0].script_sig = script_sig.clone();
9935 let refs: Vec<&[u8]> = prevout_scripts.iter().map(|s| s.as_slice()).collect();
9936 verify_script_with_context_full(
9937 &script_sig,
9938 &script_pubkey,
9939 None,
9940 flags,
9941 &tx,
9942 0,
9943 &prevout_values,
9944 &refs,
9945 None,
9946 None,
9947 crate::types::Network::Mainnet,
9948 SigVersion::Base,
9949 None,
9950 None,
9951 None,
9952 None,
9953 None,
9954 None,
9955 )
9956 };
9957
9958 let block_flags = flags::SCRIPT_VERIFY_P2SH
9959 | flags::SCRIPT_VERIFY_WITNESS
9960 | flags::SCRIPT_VERIFY_TAPROOT
9961 | flags::SCRIPT_VERIFY_DERSIG;
9962 uncompressed[0] = matching;
9963 assert!(matches!(spend(&uncompressed, 0), Ok(true)));
9964 assert!(matches!(spend(&uncompressed, block_flags), Ok(true)));
9965 assert!(!matches!(
9966 spend(&uncompressed, flags::SCRIPT_VERIFY_STRICTENC),
9967 Ok(true)
9968 ));
9969 uncompressed[0] = mismatched;
9970 assert!(!matches!(spend(&uncompressed, 0), Ok(true)));
9971 uncompressed[0] = PUBKEY_UNCOMPRESSED;
9972 assert!(matches!(spend(&uncompressed, 0), Ok(true)));
9973 }
9974
9975 #[test]
9976 fn discouraged_nop_uses_the_upgradable_nop_flag() {
9977 let discourage = flags::SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
9978 let reserved = [OP_NOP1, OP_NOP5, OP_NOP10, OP_CHECKTEMPLATEVERIFY];
9979
9980 let eval = |script: &[u8], flags: u32| {
9981 let mut stack = Vec::new();
9982 eval_script(script, &mut stack, flags, SigVersion::Base)
9983 };
9984 let with_context = |opcode: u8, flags: u32| {
9985 let script_pubkey = vec![OP_1, opcode];
9986 let script_sig = Vec::new();
9987 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
9988 let refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
9989 verify_script_with_context_full(
9990 &script_sig,
9991 &script_pubkey,
9992 None,
9993 flags,
9994 &tx,
9995 0,
9996 &pv,
9997 &refs,
9998 None,
9999 None,
10000 crate::types::Network::Mainnet,
10001 SigVersion::Base,
10002 #[cfg(feature = "production")]
10003 None,
10004 None,
10005 #[cfg(feature = "production")]
10006 None,
10007 #[cfg(feature = "production")]
10008 None,
10009 #[cfg(feature = "production")]
10010 None,
10011 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
10012 None,
10013 )
10014 };
10015 let is_discouraged = |result: Result<bool>| match result {
10016 Err(ConsensusError::ScriptErrorWithCode { code, .. }) => {
10017 code == ScriptErrorCode::DiscourageUpgradableNops
10018 }
10019 _ => false,
10020 };
10021
10022 for opcode in reserved {
10023 let script = [OP_1, opcode];
10024 assert!(eval(&script, 0).unwrap());
10025 assert!(is_discouraged(eval(&script, discourage)));
10026 assert!(eval(&script, flags::SCRIPT_VERIFY_CONST_SCRIPTCODE).unwrap());
10027 assert!(eval(&script, flags::SCRIPT_VERIFY_WITNESS_PUBKEYTYPE).unwrap());
10028 assert!(with_context(opcode, 0).unwrap());
10029 assert!(is_discouraged(with_context(opcode, discourage)));
10030 assert!(with_context(opcode, flags::SCRIPT_VERIFY_CONST_SCRIPTCODE).unwrap());
10031 }
10032
10033 assert!(eval(&[OP_1, OP_NOP], discourage).unwrap());
10034 assert!(eval(&[OP_1, OP_CHECKLOCKTIMEVERIFY], discourage).unwrap());
10035 assert!(eval(&[OP_0, OP_IF, OP_NOP1, OP_ENDIF, OP_1], discourage,).unwrap());
10036 assert!(with_context(OP_NOP, discourage).unwrap());
10037 assert!(with_context(OP_CHECKLOCKTIMEVERIFY, discourage).unwrap());
10038 }
10039
10040 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
10041 #[test]
10042 fn nullfail_waits_until_the_multisig_fails() {
10043 use crate::transaction_hash::{SighashType, calculate_transaction_sighash_single_input};
10044 use secp256k1::{Message, PublicKey, Secp256k1, SecretKey};
10045
10046 let secp = Secp256k1::new();
10047 let signing = SecretKey::from_slice(&[53u8; 32]).expect("secret");
10048 let other = SecretKey::from_slice(&[54u8; 32]).expect("secret");
10049 let outsider = SecretKey::from_slice(&[55u8; 32]).expect("secret");
10050 let signing_pk = PublicKey::from_secret_key(&secp, &signing).serialize();
10051 let other_pk = PublicKey::from_secret_key(&secp, &other).serialize();
10052
10053 let multisig = |prefix: &[u8], first: &[u8], second: &[u8]| {
10054 let mut script = prefix.to_vec();
10055 script.push(OP_1);
10056 script.push(PUSH_33_BYTES);
10057 script.extend_from_slice(first);
10058 script.push(PUSH_33_BYTES);
10059 script.extend_from_slice(second);
10060 script.push(OP_2);
10061 script.push(OP_CHECKMULTISIG);
10062 script
10063 };
10064 let spend = |script_pubkey: &[u8], secret: &SecretKey, flags: u32| {
10065 let (mut tx, prevout_values, prevout_scripts) =
10066 minimal_tx_and_prevouts(&[], script_pubkey);
10067 let sighash = calculate_transaction_sighash_single_input(
10068 &tx,
10069 0,
10070 script_pubkey,
10071 prevout_values[0],
10072 SighashType::ALL,
10073 None,
10074 )
10075 .expect("sighash");
10076 let msg = Message::from_digest_slice(&sighash).expect("digest");
10077 let mut der = secp.sign_ecdsa(&msg, secret).serialize_der().to_vec();
10078 der.push(SighashType::ALL.0);
10079 let mut script_sig = vec![OP_0];
10080 script_sig.extend(serialize_push_data(&der));
10081 tx.inputs[0].script_sig = script_sig.clone();
10082 let refs: Vec<&[u8]> = prevout_scripts.iter().map(|s| s.as_slice()).collect();
10083 verify_script_with_context_full(
10084 &script_sig,
10085 script_pubkey,
10086 None,
10087 flags,
10088 &tx,
10089 0,
10090 &prevout_values,
10091 &refs,
10092 None,
10093 None,
10094 crate::types::Network::Mainnet,
10095 SigVersion::Base,
10096 None,
10097 None,
10098 None,
10099 None,
10100 None,
10101 None,
10102 )
10103 };
10104 let nullfail_error = |result: Result<bool>| {
10105 matches!(
10106 result,
10107 Err(ConsensusError::ScriptErrorWithCode {
10108 code: ScriptErrorCode::SigNullFail,
10109 ..
10110 })
10111 )
10112 };
10113
10114 let nullfail = flags::SCRIPT_VERIFY_NULLFAIL;
10115 let interpreter = multisig(&[OP_NOP], &signing_pk, &other_pk);
10118 assert!(matches!(spend(&interpreter, &signing, nullfail), Ok(true)));
10119 assert!(matches!(spend(&interpreter, &signing, 0), Ok(true)));
10120 assert!(nullfail_error(spend(&interpreter, &outsider, nullfail)));
10121 assert!(matches!(spend(&interpreter, &outsider, 0), Ok(false)));
10122
10123 let fast_path = multisig(&[], &other_pk, &signing_pk);
10125 assert!(matches!(spend(&fast_path, &signing, nullfail), Ok(true)));
10126 }
10127
10128 #[test]
10129 fn test_verify_with_context_p2pkh_hash_mismatch() {
10130 let pubkey = vec![0x02u8; 33]; let sig = vec![0x30u8; 70]; let mut script_sig = Vec::new();
10134 script_sig.push(sig.len() as u8);
10135 script_sig.extend(&sig);
10136 script_sig.push(pubkey.len() as u8);
10137 script_sig.extend(&pubkey);
10138
10139 let mut script_pubkey = vec![OP_DUP, OP_HASH160, PUSH_20_BYTES];
10140 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUALVERIFY);
10142 script_pubkey.push(OP_CHECKSIG);
10143
10144 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
10145 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
10146 let result = verify_script_with_context_full(
10147 &script_sig,
10148 &script_pubkey,
10149 None,
10150 0,
10151 &tx,
10152 0,
10153 &pv,
10154 &psp_refs,
10155 Some(500_000),
10156 None,
10157 crate::types::Network::Mainnet,
10158 SigVersion::Base,
10159 #[cfg(feature = "production")]
10160 None,
10161 None, #[cfg(feature = "production")]
10163 None,
10164 #[cfg(feature = "production")]
10165 None,
10166 #[cfg(feature = "production")]
10167 None,
10168 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
10169 None,
10170 );
10171 assert!(result.is_ok());
10172 assert!(!result.unwrap());
10173 }
10174
10175 #[test]
10176 fn test_verify_with_context_p2sh_hash_mismatch() {
10177 let redeem = vec![OP_1, OP_1, OP_ADD]; let mut script_sig = Vec::new();
10180 script_sig.push(redeem.len() as u8);
10181 script_sig.extend(&redeem);
10182
10183 let mut script_pubkey = vec![OP_HASH160, PUSH_20_BYTES];
10184 script_pubkey.extend(&[0u8; 20]); script_pubkey.push(OP_EQUAL);
10186
10187 let (tx, pv, psp) = minimal_tx_and_prevouts(&script_sig, &script_pubkey);
10188 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
10189 let result = verify_script_with_context_full(
10190 &script_sig,
10191 &script_pubkey,
10192 None,
10193 0x01, &tx,
10195 0,
10196 &pv,
10197 &psp_refs,
10198 Some(500_000),
10199 None,
10200 crate::types::Network::Mainnet,
10201 SigVersion::Base,
10202 #[cfg(feature = "production")]
10203 None,
10204 None, #[cfg(feature = "production")]
10206 None,
10207 #[cfg(feature = "production")]
10208 None,
10209 #[cfg(feature = "production")]
10210 None,
10211 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
10212 None,
10213 );
10214 assert!(result.is_ok());
10215 assert!(!result.unwrap());
10216 }
10217
10218 #[test]
10219 fn test_verify_with_context_p2wpkh_wrong_witness_size() {
10220 let mut script_pubkey = vec![OP_0, PUSH_20_BYTES];
10222 script_pubkey.extend(&[0u8; 20]);
10223 let witness: Vec<Vec<u8>> = vec![vec![0x30; 70]]; let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
10225 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
10226 let empty: Vec<u8> = vec![];
10227 let result = verify_script_with_context_full(
10228 &empty,
10229 &script_pubkey,
10230 Some(&witness),
10231 0,
10232 &tx,
10233 0,
10234 &pv,
10235 &psp_refs,
10236 Some(500_000),
10237 None,
10238 crate::types::Network::Mainnet,
10239 SigVersion::Base,
10240 #[cfg(feature = "production")]
10241 None,
10242 None, #[cfg(feature = "production")]
10244 None,
10245 #[cfg(feature = "production")]
10246 None,
10247 #[cfg(feature = "production")]
10248 None,
10249 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
10250 None,
10251 );
10252 assert!(result.is_ok());
10253 assert!(!result.unwrap());
10254 }
10255
10256 #[test]
10257 fn test_verify_with_context_p2wsh_wrong_witness_script_hash() {
10258 let witness_script = vec![OP_1];
10260 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
10261 script_pubkey.extend(&[0u8; 32]); let witness: Vec<Vec<u8>> = vec![witness_script];
10263 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
10264 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
10265 let empty: Vec<u8> = vec![];
10266 let result = verify_script_with_context_full(
10267 &empty,
10268 &script_pubkey,
10269 Some(&witness),
10270 0,
10271 &tx,
10272 0,
10273 &pv,
10274 &psp_refs,
10275 Some(500_000),
10276 None,
10277 crate::types::Network::Mainnet,
10278 SigVersion::Base,
10279 #[cfg(feature = "production")]
10280 None,
10281 None, #[cfg(feature = "production")]
10283 None,
10284 #[cfg(feature = "production")]
10285 None,
10286 #[cfg(feature = "production")]
10287 None,
10288 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
10289 None,
10290 );
10291 assert!(result.is_ok());
10292 assert!(!result.unwrap());
10293 }
10294
10295 #[test]
10296 #[cfg(feature = "production")]
10297 fn test_p2wsh_multisig_fast_path() {
10298 use crate::constants::BIP147_ACTIVATION_MAINNET;
10300 use crate::crypto::OptimizedSha256;
10301
10302 let pk1 = [0x02u8; PUSH_33_BYTES as usize];
10303 let pk2 = [0x03u8; PUSH_33_BYTES as usize];
10304 let mut witness_script = vec![OP_2, PUSH_33_BYTES];
10305 witness_script.extend_from_slice(&pk1);
10306 witness_script.push(PUSH_33_BYTES);
10307 witness_script.extend_from_slice(&pk2);
10308 witness_script.push(OP_2);
10309 witness_script.push(OP_CHECKMULTISIG);
10310
10311 let wsh_hash = OptimizedSha256::new().hash(&witness_script);
10312 let mut script_pubkey = vec![OP_0, PUSH_32_BYTES];
10313 script_pubkey.extend_from_slice(&wsh_hash);
10314
10315 let witness: Vec<Vec<u8>> = vec![
10316 vec![], vec![0x30u8; 72], vec![0x30u8; 72], witness_script.clone(),
10320 ];
10321
10322 let (tx, pv, psp) = minimal_tx_and_prevouts(&[], &script_pubkey);
10323 let psp_refs: Vec<&[u8]> = psp.iter().map(|b| b.as_ref()).collect();
10324 let empty: Vec<u8> = vec![];
10325 let result = verify_script_with_context_full(
10326 &empty,
10327 &script_pubkey,
10328 Some(&witness),
10329 0x810, &tx,
10331 0,
10332 &pv,
10333 &psp_refs,
10334 Some(BIP147_ACTIVATION_MAINNET + 1),
10335 None,
10336 crate::types::Network::Mainnet,
10337 SigVersion::Base,
10338 #[cfg(feature = "production")]
10339 None,
10340 None, #[cfg(feature = "production")]
10342 None,
10343 #[cfg(feature = "production")]
10344 None,
10345 #[cfg(feature = "production")]
10346 None,
10347 #[cfg(all(feature = "production", feature = "blvm-secp256k1"))]
10348 None,
10349 );
10350 assert!(result.is_ok());
10351 assert!(!result.unwrap());
10352 }
10353}
10354
10355#[cfg(test)]
10356#[allow(unused_doc_comments)]
10357mod property_tests {
10358 use super::*;
10359 use proptest::prelude::*;
10360
10361 proptest! {
10366 #[test]
10367 fn prop_eval_script_operation_limit(extra in 0usize..=8usize) {
10368 let mut stack = Vec::new();
10369 let over = vec![OP_NOP; MAX_SCRIPT_OPS as usize + 1 + extra];
10370 let rejected = eval_script(&over, &mut stack, 0, SigVersion::Base);
10371 prop_assert!(
10372 rejected.is_err(),
10373 "more than {MAX_SCRIPT_OPS} non-push opcodes is rejected"
10374 );
10375
10376 let mut stack = Vec::new();
10377 let under = vec![OP_NOP; MAX_SCRIPT_OPS as usize];
10378 prop_assert!(eval_script(&under, &mut stack, 0, SigVersion::Base).is_ok());
10379 }
10380 }
10381
10382 proptest! {
10387 #[test]
10388 fn prop_verify_script_deterministic(
10389 script_sig in prop::collection::vec(any::<u8>(), 0..20),
10390 script_pubkey in prop::collection::vec(any::<u8>(), 0..20),
10391 witness in prop::option::of(prop::collection::vec(any::<u8>(), 0..10)),
10392 flags in any::<u32>()
10393 ) {
10394 let result1 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
10395 let result2 = verify_script(&script_sig, &script_pubkey, witness.as_ref(), flags);
10396
10397 assert_eq!(result1.is_ok(), result2.is_ok());
10398 if result1.is_ok() && result2.is_ok() {
10399 assert_eq!(result1.unwrap(), result2.unwrap());
10400 }
10401 }
10402 }
10403
10404 proptest! {
10409 #[test]
10410 fn prop_execute_opcode_no_panic(
10411 opcode in any::<u8>(),
10412 stack_items in prop::collection::vec(
10413 prop::collection::vec(any::<u8>(), 0..5),
10414 0..10
10415 ),
10416 flags in any::<u32>()
10417 ) {
10418 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
10419 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
10420
10421 match result {
10424 Ok(success) => {
10425 let _ = success;
10427 },
10428 Err(_) => {
10429 }
10432 }
10433
10434 assert!(stack.len() <= MAX_STACK_SIZE);
10436 }
10437 }
10438
10439 proptest! {
10446 #[test]
10447 fn prop_stack_operations_bounds(
10448 opcode in any::<u8>(),
10449 stack_items in prop::collection::vec(
10450 prop::collection::vec(any::<u8>(), 0..3),
10451 0..5
10452 ),
10453 flags in any::<u32>()
10454 ) {
10455 let mut stack: Vec<StackElement> = stack_items.into_iter().map(|v| to_stack_element(&v)).collect();
10456 let initial_len = stack.len();
10457
10458 let result = execute_opcode(opcode, &mut stack, flags, SigVersion::Base);
10459
10460 assert!(stack.len() <= MAX_STACK_SIZE);
10462
10463 if result.is_ok() && result.unwrap() {
10465 match opcode {
10467 OP_0 | OP_1..=OP_16 => {
10468 assert!(stack.len() == initial_len + 1);
10470 },
10471 OP_DUP => {
10472 if initial_len > 0 {
10474 assert!(stack.len() == initial_len + 1);
10475 }
10476 },
10477 OP_3DUP => {
10478 if initial_len >= 3 {
10480 assert!(stack.len() == initial_len + 3);
10481 }
10482 },
10483 OP_2OVER => {
10484 if initial_len >= 4 {
10486 assert!(stack.len() == initial_len + 2);
10487 }
10488 },
10489 OP_DROP | OP_NIP | OP_2DROP => {
10490 assert!(stack.len() <= initial_len);
10492 },
10493 _ => {
10494 assert!(stack.len() <= initial_len + 3, "Stack size should be reasonable");
10497 }
10498 }
10499 }
10500 }
10501 }
10502
10503 proptest! {
10508 #[test]
10509 fn prop_hash_operations_deterministic(
10510 input in prop::collection::vec(any::<u8>(), 0..10)
10511 ) {
10512 let elem = to_stack_element(&input);
10513 let mut stack1 = vec![elem.clone()];
10514 let mut stack2 = vec![elem];
10515
10516 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());
10520 if let (Ok(val1), Ok(val2)) = (result1, result2) {
10521 assert_eq!(val1, val2);
10522 if val1 {
10523 assert_eq!(stack1, stack2);
10524 }
10525 }
10526 }
10527 }
10528
10529 proptest! {
10534 #[test]
10535 fn prop_equality_operations_symmetric(
10536 a in prop::collection::vec(any::<u8>(), 0..5),
10537 b in prop::collection::vec(any::<u8>(), 0..5)
10538 ) {
10539 let mut stack1 = vec![to_stack_element(&a), to_stack_element(&b)];
10540 let mut stack2 = vec![to_stack_element(&b), to_stack_element(&a)];
10541
10542 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());
10546 if let (Ok(val1), Ok(val2)) = (result1, result2) {
10547 assert_eq!(val1, val2);
10548 if val1 {
10549 assert_eq!(stack1.len(), stack2.len());
10551 if !stack1.is_empty() && !stack2.is_empty() {
10552 assert_eq!(stack1[0], stack2[0]);
10553 }
10554 }
10555 }
10556 }
10557 }
10558
10559 proptest! {
10564 #[test]
10565 fn prop_script_execution_terminates(
10566 script in prop::collection::vec(any::<u8>(), 0..50)
10567 ) {
10568 let mut stack = Vec::new();
10569 let flags = 0u32;
10570
10571 let _ = eval_script(&script, &mut stack, flags, SigVersion::Base);
10572 assert!(stack.len() <= MAX_STACK_SIZE);
10573 }
10574 }
10575}