Skip to main content

bsv_rs/script/
spend.rs

1//! Bitcoin Script interpreter for spend validation.
2//!
3// Allow large error type - ScriptEvaluationError intentionally captures full
4// execution state for debugging failed script executions.
5#![allow(clippy::result_large_err)]
6//!
7//! This module implements the full Bitcoin Script interpreter for BSV, enabling
8//! validation of transaction spends by executing unlocking and locking scripts.
9//!
10//! # Example
11//!
12//! ```rust,ignore
13//! use bsv_rs::script::{Spend, LockingScript, UnlockingScript};
14//!
15//! let spend = Spend::new(SpendParams {
16//!     source_txid: [0u8; 32],
17//!     source_output_index: 0,
18//!     source_satoshis: 100_000,
19//!     locking_script: LockingScript::from_asm("OP_DUP OP_HASH160 ... OP_CHECKSIG")?,
20//!     transaction_version: 1,
21//!     other_inputs: vec![],
22//!     outputs: vec![],
23//!     input_index: 0,
24//!     unlocking_script: UnlockingScript::from_asm("<sig> <pubkey>")?,
25//!     input_sequence: 0xffffffff,
26//!     lock_time: 0,
27//!     memory_limit: None,
28//! });
29//!
30//! let valid = spend.validate()?;
31//! ```
32
33use super::evaluation_error::{ExecutionContext, ScriptEvaluationError};
34use super::op::*;
35use super::script_num::ScriptNum;
36use super::{LockingScript, Script, ScriptChunk, UnlockingScript};
37use crate::primitives::bsv::sighash::{
38    compute_sighash_for_signing, SighashParams, TxInput, TxOutput, SIGHASH_FORKID,
39};
40use crate::primitives::bsv::tx_signature::TransactionSignature;
41use crate::primitives::ec::PublicKey;
42use crate::primitives::{hash160, ripemd160, sha1, sha256, sha256d, to_hex, BigNumber};
43
44// ============================================================================
45// Configuration Constants
46// ============================================================================
47
48/// Maximum size of a single script element (1GB for BSV unlimited)
49const MAX_SCRIPT_ELEMENT_SIZE: usize = 1024 * 1024 * 1024;
50
51/// Default memory limit for stack usage (32MB)
52const DEFAULT_MEMORY_LIMIT: usize = 32_000_000;
53
54/// Maximum number of keys in a multisig (i32::MAX for BSV)
55const MAX_MULTISIG_KEY_COUNT: i64 = i32::MAX as i64;
56
57/// Require minimal push encoding
58const REQUIRE_MINIMAL_PUSH: bool = true;
59
60/// Require push-only unlocking scripts
61const REQUIRE_PUSH_ONLY_UNLOCKING: bool = true;
62
63/// Require low-S signatures
64const REQUIRE_LOW_S_SIGNATURES: bool = true;
65
66/// Require clean stack after execution
67const REQUIRE_CLEAN_STACK: bool = true;
68
69// ============================================================================
70// Pre-computed Script Numbers
71// ============================================================================
72
73lazy_static::lazy_static! {
74    /// Pre-computed script number for -1
75    static ref SCRIPTNUM_NEG_1: Vec<u8> = ScriptNum::to_bytes(&BigNumber::from_i64(-1));
76
77    /// Pre-computed script numbers for 0-16
78    static ref SCRIPTNUMS_0_TO_16: Vec<Vec<u8>> = (0..=16)
79        .map(|i| ScriptNum::to_bytes(&BigNumber::from_i64(i)))
80        .collect();
81}
82
83// ============================================================================
84// Spend Parameters
85// ============================================================================
86
87/// Parameters for constructing a Spend validator.
88pub struct SpendParams {
89    /// The transaction ID of the source UTXO (32 bytes, internal byte order).
90    pub source_txid: [u8; 32],
91    /// The index of the output in the source transaction.
92    pub source_output_index: u32,
93    /// The satoshi value of the source UTXO.
94    pub source_satoshis: u64,
95    /// The locking script of the source UTXO.
96    pub locking_script: LockingScript,
97    /// The version of the spending transaction.
98    pub transaction_version: i32,
99    /// Other inputs in the spending transaction (excluding this one).
100    pub other_inputs: Vec<TxInput>,
101    /// Outputs of the spending transaction.
102    pub outputs: Vec<TxOutput>,
103    /// The index of this input in the spending transaction.
104    pub input_index: usize,
105    /// The unlocking script for this spend.
106    pub unlocking_script: UnlockingScript,
107    /// The sequence number of this input.
108    pub input_sequence: u32,
109    /// The lock time of the spending transaction.
110    pub lock_time: u32,
111    /// Optional memory limit in bytes (default: 32MB).
112    pub memory_limit: Option<usize>,
113}
114
115// ============================================================================
116// Spend Struct
117// ============================================================================
118
119/// The Spend struct represents a spend action and validates it by executing
120/// the unlocking and locking scripts.
121pub struct Spend {
122    // Transaction context
123    source_txid: [u8; 32],
124    source_output_index: u32,
125    source_satoshis: u64,
126    locking_script: LockingScript,
127    transaction_version: i32,
128    other_inputs: Vec<TxInput>,
129    outputs: Vec<TxOutput>,
130    input_index: usize,
131    unlocking_script: UnlockingScript,
132    input_sequence: u32,
133    lock_time: u32,
134
135    // Execution state
136    context: ExecutionContext,
137    program_counter: usize,
138    last_code_separator: Option<usize>,
139    stack: Vec<Vec<u8>>,
140    alt_stack: Vec<Vec<u8>>,
141    if_stack: Vec<bool>,
142    memory_limit: usize,
143    stack_mem: usize,
144    alt_stack_mem: usize,
145}
146
147impl Spend {
148    /// Creates a new Spend validator from the given parameters.
149    pub fn new(params: SpendParams) -> Self {
150        let mut spend = Self {
151            source_txid: params.source_txid,
152            source_output_index: params.source_output_index,
153            source_satoshis: params.source_satoshis,
154            locking_script: params.locking_script,
155            transaction_version: params.transaction_version,
156            other_inputs: params.other_inputs,
157            outputs: params.outputs,
158            input_index: params.input_index,
159            unlocking_script: params.unlocking_script,
160            input_sequence: params.input_sequence,
161            lock_time: params.lock_time,
162            context: ExecutionContext::UnlockingScript,
163            program_counter: 0,
164            last_code_separator: None,
165            stack: Vec::new(),
166            alt_stack: Vec::new(),
167            if_stack: Vec::new(),
168            memory_limit: params.memory_limit.unwrap_or(DEFAULT_MEMORY_LIMIT),
169            stack_mem: 0,
170            alt_stack_mem: 0,
171        };
172        spend.reset();
173        spend
174    }
175
176    /// Resets the interpreter state for re-execution.
177    pub fn reset(&mut self) {
178        self.context = ExecutionContext::UnlockingScript;
179        self.program_counter = 0;
180        self.last_code_separator = None;
181        self.stack.clear();
182        self.alt_stack.clear();
183        self.if_stack.clear();
184        self.stack_mem = 0;
185        self.alt_stack_mem = 0;
186    }
187
188    /// Validates the spend by executing both scripts.
189    ///
190    /// # Returns
191    ///
192    /// `Ok(true)` if the spend is valid, or an error describing why validation failed.
193    pub fn validate(&mut self) -> Result<bool, ScriptEvaluationError> {
194        // Check that unlocking script is push-only
195        if REQUIRE_PUSH_ONLY_UNLOCKING && !self.unlocking_script.is_push_only() {
196            return Err(self.error(
197                "Unlocking scripts can only contain push operations, and no other opcodes.",
198            ));
199        }
200
201        // Execute both scripts
202        while self.step()? {
203            // Continue until script ends
204            if self.context == ExecutionContext::LockingScript
205                && self.program_counter >= self.locking_script.chunks().len()
206            {
207                break;
208            }
209        }
210
211        // Verify if_stack is empty (all conditionals closed)
212        if !self.if_stack.is_empty() {
213            return Err(self.error(
214                "Every OP_IF, OP_NOTIF, or OP_ELSE must be terminated with OP_ENDIF prior to the end of the script.",
215            ));
216        }
217
218        // Clean stack rule
219        if REQUIRE_CLEAN_STACK && self.stack.len() != 1 {
220            return Err(self.error(&format!(
221                "The clean stack rule requires exactly one item to be on the stack after script execution, found {}.",
222                self.stack.len()
223            )));
224        }
225
226        // Top value must be truthy
227        if self.stack.is_empty() {
228            return Err(self.error(
229                "The top stack element must be truthy after script evaluation (stack is empty).",
230            ));
231        }
232
233        if !ScriptNum::cast_to_bool(&self.stack[self.stack.len() - 1]) {
234            return Err(self.error("The top stack element must be truthy after script evaluation."));
235        }
236
237        Ok(true)
238    }
239
240    /// Executes a single instruction (step).
241    ///
242    /// # Returns
243    ///
244    /// `Ok(true)` if execution should continue, `Ok(false)` if the script is complete.
245    pub fn step(&mut self) -> Result<bool, ScriptEvaluationError> {
246        // Check memory limits
247        if self.stack_mem > self.memory_limit {
248            return Err(self.error(&format!(
249                "Stack memory usage has exceeded {} bytes",
250                self.memory_limit
251            )));
252        }
253        if self.alt_stack_mem > self.memory_limit {
254            return Err(self.error(&format!(
255                "Alt stack memory usage has exceeded {} bytes",
256                self.memory_limit
257            )));
258        }
259
260        // Switch from unlocking to locking script when unlocking is complete
261        if self.context == ExecutionContext::UnlockingScript
262            && self.program_counter >= self.unlocking_script.chunks().len()
263        {
264            self.context = ExecutionContext::LockingScript;
265            self.program_counter = 0;
266        }
267
268        // Get current script and check if we're done
269        let current_chunks = match self.context {
270            ExecutionContext::UnlockingScript => self.unlocking_script.chunks(),
271            ExecutionContext::LockingScript => self.locking_script.chunks(),
272        };
273
274        if self.program_counter >= current_chunks.len() {
275            return Ok(false);
276        }
277
278        let operation = &current_chunks[self.program_counter];
279        let current_opcode = operation.op;
280
281        // Check for oversized data push
282        if let Some(ref data) = operation.data {
283            if data.len() > MAX_SCRIPT_ELEMENT_SIZE {
284                return Err(self.error(&format!(
285                    "Data push > {} bytes (pc={})",
286                    MAX_SCRIPT_ELEMENT_SIZE, self.program_counter
287                )));
288            }
289        }
290
291        // Determine if we're currently executing (not in a false conditional branch)
292        let is_executing = !self.if_stack.contains(&false);
293
294        // Check for disabled opcodes when executing
295        if is_executing && is_opcode_disabled(current_opcode) {
296            return Err(self.error(&format!(
297                "This opcode is currently disabled. (Opcode: {}, PC: {})",
298                opcode_to_name(current_opcode).unwrap_or("UNKNOWN"),
299                self.program_counter
300            )));
301        }
302
303        // Execute opcode
304        if is_executing && current_opcode <= OP_PUSHDATA4 {
305            // Push data operations
306            if REQUIRE_MINIMAL_PUSH && !is_chunk_minimal_push(operation) {
307                return Err(self.error(&format!(
308                    "This data is not minimally-encoded. (PC: {})",
309                    self.program_counter
310                )));
311            }
312            let data = operation.data.clone().unwrap_or_default();
313            self.push_stack(data)?;
314        } else if is_executing || (OP_IF..=OP_ENDIF).contains(&current_opcode) {
315            // Execute the opcode
316            self.execute_opcode(current_opcode, operation)?;
317        }
318
319        self.program_counter += 1;
320        Ok(true)
321    }
322
323    // ========================================================================
324    // Opcode Execution
325    // ========================================================================
326
327    fn execute_opcode(
328        &mut self,
329        opcode: u8,
330        chunk: &ScriptChunk,
331    ) -> Result<(), ScriptEvaluationError> {
332        let is_executing = !self.if_stack.contains(&false);
333
334        match opcode {
335            // ================================================================
336            // Push Operations (0x00-0x60)
337            // ================================================================
338            OP_1NEGATE => {
339                self.push_stack_copy(&SCRIPTNUM_NEG_1)?;
340            }
341            OP_0 => {
342                self.push_stack_copy(&SCRIPTNUMS_0_TO_16[0])?;
343            }
344            OP_1..=OP_16 => {
345                let n = (opcode - OP_1 + 1) as usize;
346                self.push_stack_copy(&SCRIPTNUMS_0_TO_16[n])?;
347            }
348
349            // ================================================================
350            // NOPs (do nothing)
351            // ================================================================
352            OP_NOP | OP_NOP1 | OP_NOP2 | OP_NOP3 | OP_NOP4 | OP_NOP5 | OP_NOP6 | OP_NOP7
353            | OP_NOP8 | OP_NOP9 | OP_NOP10 => {}
354            // Extended NOPs (0xba-0xff)
355            0xba..=0xff => {}
356
357            // ================================================================
358            // Flow Control (0x63-0x6a)
359            // ================================================================
360            OP_IF | OP_NOTIF => {
361                let mut f_value = false;
362                if is_executing {
363                    if self.stack.is_empty() {
364                        return Err(self.error(
365                            "OP_IF and OP_NOTIF require at least one item on the stack when they are used!",
366                        ));
367                    }
368                    let buf = self.pop_stack()?;
369                    f_value = ScriptNum::cast_to_bool(&buf);
370                    if opcode == OP_NOTIF {
371                        f_value = !f_value;
372                    }
373                }
374                self.if_stack.push(f_value);
375            }
376            OP_ELSE => {
377                if self.if_stack.is_empty() {
378                    return Err(self.error("OP_ELSE requires a preceeding OP_IF."));
379                }
380                let last = self.if_stack.len() - 1;
381                self.if_stack[last] = !self.if_stack[last];
382            }
383            OP_ENDIF => {
384                if self.if_stack.is_empty() {
385                    return Err(self.error("OP_ENDIF requires a preceeding OP_IF."));
386                }
387                self.if_stack.pop();
388            }
389            OP_VERIFY => {
390                if self.stack.is_empty() {
391                    return Err(
392                        self.error("OP_VERIFY requires at least one item to be on the stack.")
393                    );
394                }
395                let f_value = ScriptNum::cast_to_bool(self.stack_top()?);
396                if !f_value {
397                    return Err(self.error("OP_VERIFY requires the top stack value to be truthy."));
398                }
399                self.pop_stack()?;
400            }
401            OP_RETURN => {
402                // Jump to end of current script
403                let end = match self.context {
404                    ExecutionContext::UnlockingScript => self.unlocking_script.chunks().len(),
405                    ExecutionContext::LockingScript => self.locking_script.chunks().len(),
406                };
407                self.program_counter = end;
408                self.if_stack.clear();
409                // Counteract the final increment
410                if self.program_counter > 0 {
411                    self.program_counter -= 1;
412                }
413            }
414
415            // ================================================================
416            // Stack Operations (0x6b-0x7d)
417            // ================================================================
418            OP_TOALTSTACK => {
419                if self.stack.is_empty() {
420                    return Err(
421                        self.error("OP_TOALTSTACK requires at least one item to be on the stack.")
422                    );
423                }
424                let item = self.pop_stack()?;
425                self.push_alt_stack(item)?;
426            }
427            OP_FROMALTSTACK => {
428                if self.alt_stack.is_empty() {
429                    return Err(self.error(
430                        "OP_FROMALTSTACK requires at least one item to be on the alt stack.",
431                    ));
432                }
433                let item = self.pop_alt_stack()?;
434                self.push_stack(item)?;
435            }
436            OP_2DROP => {
437                if self.stack.len() < 2 {
438                    return Err(
439                        self.error("OP_2DROP requires at least two items to be on the stack.")
440                    );
441                }
442                self.pop_stack()?;
443                self.pop_stack()?;
444            }
445            OP_2DUP => {
446                if self.stack.len() < 2 {
447                    return Err(
448                        self.error("OP_2DUP requires at least two items to be on the stack.")
449                    );
450                }
451                let buf1 = self.stack_top_n(2)?.to_vec();
452                let buf2 = self.stack_top()?.to_vec();
453                self.push_stack(buf1)?;
454                self.push_stack(buf2)?;
455            }
456            OP_3DUP => {
457                if self.stack.len() < 3 {
458                    return Err(
459                        self.error("OP_3DUP requires at least three items to be on the stack.")
460                    );
461                }
462                let buf1 = self.stack_top_n(3)?.to_vec();
463                let buf2 = self.stack_top_n(2)?.to_vec();
464                let buf3 = self.stack_top()?.to_vec();
465                self.push_stack(buf1)?;
466                self.push_stack(buf2)?;
467                self.push_stack(buf3)?;
468            }
469            OP_2OVER => {
470                if self.stack.len() < 4 {
471                    return Err(
472                        self.error("OP_2OVER requires at least four items to be on the stack.")
473                    );
474                }
475                let buf1 = self.stack_top_n(4)?.to_vec();
476                let buf2 = self.stack_top_n(3)?.to_vec();
477                self.push_stack(buf1)?;
478                self.push_stack(buf2)?;
479            }
480            OP_2ROT => {
481                if self.stack.len() < 6 {
482                    return Err(
483                        self.error("OP_2ROT requires at least six items to be on the stack.")
484                    );
485                }
486                let x6 = self.pop_stack()?;
487                let x5 = self.pop_stack()?;
488                let x4 = self.pop_stack()?;
489                let x3 = self.pop_stack()?;
490                let x2 = self.pop_stack()?;
491                let x1 = self.pop_stack()?;
492                self.push_stack(x3)?;
493                self.push_stack(x4)?;
494                self.push_stack(x5)?;
495                self.push_stack(x6)?;
496                self.push_stack(x1)?;
497                self.push_stack(x2)?;
498            }
499            OP_2SWAP => {
500                if self.stack.len() < 4 {
501                    return Err(
502                        self.error("OP_2SWAP requires at least four items to be on the stack.")
503                    );
504                }
505                let x4 = self.pop_stack()?;
506                let x3 = self.pop_stack()?;
507                let x2 = self.pop_stack()?;
508                let x1 = self.pop_stack()?;
509                self.push_stack(x3)?;
510                self.push_stack(x4)?;
511                self.push_stack(x1)?;
512                self.push_stack(x2)?;
513            }
514            OP_IFDUP => {
515                if self.stack.is_empty() {
516                    return Err(
517                        self.error("OP_IFDUP requires at least one item to be on the stack.")
518                    );
519                }
520                let top = self.stack_top()?.to_vec();
521                if ScriptNum::cast_to_bool(&top) {
522                    self.push_stack(top)?;
523                }
524            }
525            OP_DEPTH => {
526                let depth = BigNumber::from_u64(self.stack.len() as u64);
527                self.push_stack(ScriptNum::to_bytes(&depth))?;
528            }
529            OP_DROP => {
530                if self.stack.is_empty() {
531                    return Err(
532                        self.error("OP_DROP requires at least one item to be on the stack.")
533                    );
534                }
535                self.pop_stack()?;
536            }
537            OP_DUP => {
538                if self.stack.is_empty() {
539                    return Err(self.error("OP_DUP requires at least one item to be on the stack."));
540                }
541                let top = self.stack_top()?.to_vec();
542                self.push_stack(top)?;
543            }
544            OP_NIP => {
545                if self.stack.len() < 2 {
546                    return Err(
547                        self.error("OP_NIP requires at least two items to be on the stack.")
548                    );
549                }
550                let top = self.pop_stack()?;
551                self.pop_stack()?;
552                self.push_stack(top)?;
553            }
554            OP_OVER => {
555                if self.stack.len() < 2 {
556                    return Err(
557                        self.error("OP_OVER requires at least two items to be on the stack.")
558                    );
559                }
560                let second = self.stack_top_n(2)?.to_vec();
561                self.push_stack(second)?;
562            }
563            OP_PICK | OP_ROLL => {
564                if self.stack.len() < 2 {
565                    return Err(self.error(&format!(
566                        "{} requires at least two items to be on the stack.",
567                        opcode_to_name(opcode).unwrap_or("OP_PICK/ROLL")
568                    )));
569                }
570                let n_bytes = self.pop_stack()?;
571                let bn = ScriptNum::from_bytes(&n_bytes, REQUIRE_MINIMAL_PUSH)
572                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
573
574                let n = bn.to_i64().unwrap_or(i64::MAX);
575                if n < 0 || n >= self.stack.len() as i64 {
576                    return Err(self.error(&format!(
577                        "{} requires the top stack element to be 0 or a positive number less than the current size of the stack.",
578                        opcode_to_name(opcode).unwrap_or("OP_PICK/ROLL")
579                    )));
580                }
581
582                let n_idx = n as usize;
583                let item = self.stack[self.stack.len() - 1 - n_idx].clone();
584
585                if opcode == OP_ROLL {
586                    let remove_idx = self.stack.len() - 1 - n_idx;
587                    let removed = self.stack.remove(remove_idx);
588                    self.stack_mem -= removed.len();
589                    self.push_stack(item)?;
590                } else {
591                    // OP_PICK
592                    self.push_stack(item)?;
593                }
594            }
595            OP_ROT => {
596                if self.stack.len() < 3 {
597                    return Err(
598                        self.error("OP_ROT requires at least three items to be on the stack.")
599                    );
600                }
601                let x3 = self.pop_stack()?;
602                let x2 = self.pop_stack()?;
603                let x1 = self.pop_stack()?;
604                self.push_stack(x2)?;
605                self.push_stack(x3)?;
606                self.push_stack(x1)?;
607            }
608            OP_SWAP => {
609                if self.stack.len() < 2 {
610                    return Err(
611                        self.error("OP_SWAP requires at least two items to be on the stack.")
612                    );
613                }
614                let x2 = self.pop_stack()?;
615                let x1 = self.pop_stack()?;
616                self.push_stack(x2)?;
617                self.push_stack(x1)?;
618            }
619            OP_TUCK => {
620                if self.stack.len() < 2 {
621                    return Err(
622                        self.error("OP_TUCK requires at least two items to be on the stack.")
623                    );
624                }
625                let top = self.stack_top()?.to_vec();
626                self.ensure_stack_mem(top.len())?;
627                let insert_idx = self.stack.len() - 2;
628                self.stack.insert(insert_idx, top.clone());
629                self.stack_mem += top.len();
630            }
631            OP_SIZE => {
632                if self.stack.is_empty() {
633                    return Err(
634                        self.error("OP_SIZE requires at least one item to be on the stack.")
635                    );
636                }
637                let size = self.stack_top()?.len();
638                let bn = BigNumber::from_u64(size as u64);
639                self.push_stack(ScriptNum::to_bytes(&bn))?;
640            }
641
642            // ================================================================
643            // Splice Operations (BSV re-enabled)
644            // ================================================================
645            OP_CAT => {
646                if self.stack.len() < 2 {
647                    return Err(
648                        self.error("OP_CAT requires at least two items to be on the stack.")
649                    );
650                }
651                let buf2 = self.pop_stack()?;
652                let buf1 = self.pop_stack()?;
653                let mut result = buf1;
654                result.extend(buf2);
655                if result.len() > MAX_SCRIPT_ELEMENT_SIZE {
656                    return Err(self.error(&format!(
657                        "It's not currently possible to push data larger than {} bytes.",
658                        MAX_SCRIPT_ELEMENT_SIZE
659                    )));
660                }
661                self.push_stack(result)?;
662            }
663            OP_SPLIT => {
664                if self.stack.len() < 2 {
665                    return Err(
666                        self.error("OP_SPLIT requires at least two items to be on the stack.")
667                    );
668                }
669                let pos_bytes = self.pop_stack()?;
670                let data = self.pop_stack()?;
671
672                let pos_bn = ScriptNum::from_bytes(&pos_bytes, REQUIRE_MINIMAL_PUSH)
673                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
674                let pos = pos_bn.to_i64().unwrap_or(-1);
675
676                if pos < 0 || pos > data.len() as i64 {
677                    return Err(self.error(
678                        "OP_SPLIT requires the first stack item to be a non-negative number less than or equal to the size of the second-from-top stack item.",
679                    ));
680                }
681
682                let split_idx = pos as usize;
683                let left = data[..split_idx].to_vec();
684                let right = data[split_idx..].to_vec();
685                self.push_stack(left)?;
686                self.push_stack(right)?;
687            }
688            OP_NUM2BIN => {
689                if self.stack.len() < 2 {
690                    return Err(
691                        self.error("OP_NUM2BIN requires at least two items to be on the stack.")
692                    );
693                }
694                let size_bytes = self.pop_stack()?;
695                let size_bn = ScriptNum::from_bytes(&size_bytes, REQUIRE_MINIMAL_PUSH)
696                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
697                let size = size_bn.to_i64().unwrap_or(-1);
698
699                if size < 0 || size > MAX_SCRIPT_ELEMENT_SIZE as i64 {
700                    return Err(self.error(&format!(
701                        "It's not currently possible to push data larger than {} bytes or negative size.",
702                        MAX_SCRIPT_ELEMENT_SIZE
703                    )));
704                }
705                let size = size as usize;
706
707                let rawnum = self.pop_stack()?;
708                let minimal = ScriptNum::minimally_encode(&rawnum);
709
710                if minimal.len() > size {
711                    return Err(self.error(
712                        "OP_NUM2BIN requires that the size expressed in the top stack item is large enough to hold the value expressed in the second-from-top stack item.",
713                    ));
714                }
715
716                if minimal.len() == size {
717                    self.push_stack(minimal)?;
718                } else {
719                    // Pad to size, preserving sign
720                    let mut result = vec![0u8; size];
721                    let mut signbit = 0u8;
722
723                    if !minimal.is_empty() {
724                        signbit = minimal[minimal.len() - 1] & 0x80;
725                        let mut minimal_copy = minimal.clone();
726                        if let Some(last) = minimal_copy.last_mut() {
727                            *last &= 0x7f;
728                        }
729                        result[..minimal_copy.len()].copy_from_slice(&minimal_copy);
730                    }
731
732                    if signbit != 0 {
733                        result[size - 1] |= 0x80;
734                    }
735                    self.push_stack(result)?;
736                }
737            }
738            OP_BIN2NUM => {
739                if self.stack.is_empty() {
740                    return Err(
741                        self.error("OP_BIN2NUM requires at least one item to be on the stack.")
742                    );
743                }
744                let buf = self.pop_stack()?;
745                let result = ScriptNum::minimally_encode(&buf);
746                if !ScriptNum::is_minimally_encoded(&result) {
747                    return Err(
748                        self.error("OP_BIN2NUM requires that the resulting number is valid.")
749                    );
750                }
751                self.push_stack(result)?;
752            }
753
754            // ================================================================
755            // Bitwise Operations
756            // ================================================================
757            OP_INVERT => {
758                if self.stack.is_empty() {
759                    return Err(
760                        self.error("OP_INVERT requires at least one item to be on the stack.")
761                    );
762                }
763                let buf = self.pop_stack()?;
764                let result: Vec<u8> = buf.iter().map(|&b| !b).collect();
765                self.push_stack(result)?;
766            }
767            OP_AND | OP_OR | OP_XOR => {
768                if self.stack.len() < 2 {
769                    return Err(self.error(&format!(
770                        "{} requires at least two items on the stack.",
771                        opcode_to_name(opcode).unwrap_or("OP")
772                    )));
773                }
774                let buf2 = self.pop_stack()?;
775                let buf1 = self.pop_stack()?;
776                if buf1.len() != buf2.len() {
777                    return Err(self.error(&format!(
778                        "{} requires the top two stack items to be the same size.",
779                        opcode_to_name(opcode).unwrap_or("OP")
780                    )));
781                }
782                let result: Vec<u8> = buf1
783                    .iter()
784                    .zip(buf2.iter())
785                    .map(|(&a, &b)| match opcode {
786                        OP_AND => a & b,
787                        OP_OR => a | b,
788                        _ => a ^ b, // OP_XOR
789                    })
790                    .collect();
791                self.push_stack(result)?;
792            }
793            OP_EQUAL | OP_EQUALVERIFY => {
794                if self.stack.len() < 2 {
795                    return Err(self.error(&format!(
796                        "{} requires at least two items to be on the stack.",
797                        opcode_to_name(opcode).unwrap_or("OP_EQUAL")
798                    )));
799                }
800                let buf2 = self.pop_stack()?;
801                let buf1 = self.pop_stack()?;
802                let equal = buf1 == buf2;
803                self.push_stack(if equal { vec![1] } else { vec![] })?;
804
805                if opcode == OP_EQUALVERIFY {
806                    if !equal {
807                        return Err(self.error(
808                            "OP_EQUALVERIFY requires the top two stack items to be equal.",
809                        ));
810                    }
811                    self.pop_stack()?;
812                }
813            }
814            OP_LSHIFT | OP_RSHIFT => {
815                if self.stack.len() < 2 {
816                    return Err(self.error(&format!(
817                        "{} requires at least two items to be on the stack.",
818                        opcode_to_name(opcode).unwrap_or("OP")
819                    )));
820                }
821                let n_bytes = self.pop_stack()?;
822                let buf = self.pop_stack()?;
823
824                let n_bn = ScriptNum::from_bytes(&n_bytes, REQUIRE_MINIMAL_PUSH)
825                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
826                let n = n_bn.to_i64().unwrap_or(-1);
827
828                if n < 0 {
829                    return Err(self.error(&format!(
830                        "{} requires the top item on the stack not to be negative.",
831                        opcode_to_name(opcode).unwrap_or("OP")
832                    )));
833                }
834
835                if buf.is_empty() {
836                    self.push_stack(vec![])?;
837                } else {
838                    // Convert to BigNumber, shift, convert back
839                    let bn = BigNumber::from_bytes_be(&buf);
840                    let n_u32 = n as u32;
841                    let shifted = if opcode == OP_LSHIFT {
842                        // Left shift
843                        bn.mul(&BigNumber::from_u64(1u64 << n_u32.min(63)))
844                    } else {
845                        // Right shift
846                        bn.div(&BigNumber::from_u64(1u64 << n_u32.min(63)))
847                    };
848                    let result = shifted.to_bytes_be(buf.len());
849                    self.push_stack(result)?;
850                }
851            }
852
853            // ================================================================
854            // Arithmetic Operations
855            // ================================================================
856            OP_1ADD | OP_1SUB | OP_NEGATE | OP_ABS | OP_NOT | OP_0NOTEQUAL => {
857                if self.stack.is_empty() {
858                    return Err(self.error(&format!(
859                        "{} requires at least one item to be on the stack.",
860                        opcode_to_name(opcode).unwrap_or("OP")
861                    )));
862                }
863                let buf = self.pop_stack()?;
864                let mut bn = ScriptNum::from_bytes(&buf, REQUIRE_MINIMAL_PUSH)
865                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
866
867                bn = match opcode {
868                    OP_1ADD => bn.add(&BigNumber::one()),
869                    OP_1SUB => bn.sub(&BigNumber::one()),
870                    OP_NEGATE => bn.neg(),
871                    OP_ABS => bn.abs(),
872                    OP_NOT => {
873                        if bn.is_zero() {
874                            BigNumber::one()
875                        } else {
876                            BigNumber::zero()
877                        }
878                    }
879                    OP_0NOTEQUAL => {
880                        if bn.is_zero() {
881                            BigNumber::zero()
882                        } else {
883                            BigNumber::one()
884                        }
885                    }
886                    _ => bn,
887                };
888                self.push_stack(ScriptNum::to_bytes(&bn))?;
889            }
890            OP_ADD
891            | OP_SUB
892            | OP_MUL
893            | OP_DIV
894            | OP_MOD
895            | OP_BOOLAND
896            | OP_BOOLOR
897            | OP_NUMEQUAL
898            | OP_NUMEQUALVERIFY
899            | OP_NUMNOTEQUAL
900            | OP_LESSTHAN
901            | OP_GREATERTHAN
902            | OP_LESSTHANOREQUAL
903            | OP_GREATERTHANOREQUAL
904            | OP_MIN
905            | OP_MAX => {
906                if self.stack.len() < 2 {
907                    return Err(self.error(&format!(
908                        "{} requires at least two items to be on the stack.",
909                        opcode_to_name(opcode).unwrap_or("OP")
910                    )));
911                }
912                let buf2 = self.pop_stack()?;
913                let buf1 = self.pop_stack()?;
914                let bn1 = ScriptNum::from_bytes(&buf1, REQUIRE_MINIMAL_PUSH)
915                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
916                let bn2 = ScriptNum::from_bytes(&buf2, REQUIRE_MINIMAL_PUSH)
917                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
918
919                let result = match opcode {
920                    OP_ADD => bn1.add(&bn2),
921                    OP_SUB => bn1.sub(&bn2),
922                    OP_MUL => bn1.mul(&bn2),
923                    OP_DIV => {
924                        if bn2.is_zero() {
925                            return Err(self.error("OP_DIV cannot divide by zero!"));
926                        }
927                        bn1.div(&bn2)
928                    }
929                    OP_MOD => {
930                        if bn2.is_zero() {
931                            return Err(self.error("OP_MOD cannot divide by zero!"));
932                        }
933                        bn1.mod_floor(&bn2)
934                    }
935                    OP_BOOLAND => {
936                        if !bn1.is_zero() && !bn2.is_zero() {
937                            BigNumber::one()
938                        } else {
939                            BigNumber::zero()
940                        }
941                    }
942                    OP_BOOLOR => {
943                        if !bn1.is_zero() || !bn2.is_zero() {
944                            BigNumber::one()
945                        } else {
946                            BigNumber::zero()
947                        }
948                    }
949                    OP_NUMEQUAL | OP_NUMEQUALVERIFY => {
950                        if bn1 == bn2 {
951                            BigNumber::one()
952                        } else {
953                            BigNumber::zero()
954                        }
955                    }
956                    OP_NUMNOTEQUAL => {
957                        if bn1 != bn2 {
958                            BigNumber::one()
959                        } else {
960                            BigNumber::zero()
961                        }
962                    }
963                    OP_LESSTHAN => {
964                        if bn1 < bn2 {
965                            BigNumber::one()
966                        } else {
967                            BigNumber::zero()
968                        }
969                    }
970                    OP_GREATERTHAN => {
971                        if bn1 > bn2 {
972                            BigNumber::one()
973                        } else {
974                            BigNumber::zero()
975                        }
976                    }
977                    OP_LESSTHANOREQUAL => {
978                        if bn1 <= bn2 {
979                            BigNumber::one()
980                        } else {
981                            BigNumber::zero()
982                        }
983                    }
984                    OP_GREATERTHANOREQUAL => {
985                        if bn1 >= bn2 {
986                            BigNumber::one()
987                        } else {
988                            BigNumber::zero()
989                        }
990                    }
991                    OP_MIN => {
992                        if bn1 < bn2 {
993                            bn1
994                        } else {
995                            bn2
996                        }
997                    }
998                    OP_MAX => {
999                        if bn1 > bn2 {
1000                            bn1
1001                        } else {
1002                            bn2
1003                        }
1004                    }
1005                    _ => BigNumber::zero(),
1006                };
1007
1008                self.push_stack(ScriptNum::to_bytes(&result))?;
1009
1010                if opcode == OP_NUMEQUALVERIFY {
1011                    if !ScriptNum::cast_to_bool(self.stack_top()?) {
1012                        return Err(self
1013                            .error("OP_NUMEQUALVERIFY requires the top stack item to be truthy."));
1014                    }
1015                    self.pop_stack()?;
1016                }
1017            }
1018            OP_WITHIN => {
1019                if self.stack.len() < 3 {
1020                    return Err(
1021                        self.error("OP_WITHIN requires at least three items to be on the stack.")
1022                    );
1023                }
1024                let max_bytes = self.pop_stack()?;
1025                let min_bytes = self.pop_stack()?;
1026                let x_bytes = self.pop_stack()?;
1027                let max_bn = ScriptNum::from_bytes(&max_bytes, REQUIRE_MINIMAL_PUSH)
1028                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
1029                let min_bn = ScriptNum::from_bytes(&min_bytes, REQUIRE_MINIMAL_PUSH)
1030                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
1031                let x_bn = ScriptNum::from_bytes(&x_bytes, REQUIRE_MINIMAL_PUSH)
1032                    .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
1033
1034                let in_range = x_bn >= min_bn && x_bn < max_bn;
1035                self.push_stack(if in_range { vec![1] } else { vec![] })?;
1036            }
1037
1038            // ================================================================
1039            // Crypto Operations
1040            // ================================================================
1041            OP_RIPEMD160 => {
1042                if self.stack.is_empty() {
1043                    return Err(
1044                        self.error("OP_RIPEMD160 requires at least one item to be on the stack.")
1045                    );
1046                }
1047                let buf = self.pop_stack()?;
1048                let hash = ripemd160(&buf);
1049                self.push_stack(hash.to_vec())?;
1050            }
1051            OP_SHA1 => {
1052                if self.stack.is_empty() {
1053                    return Err(
1054                        self.error("OP_SHA1 requires at least one item to be on the stack.")
1055                    );
1056                }
1057                let buf = self.pop_stack()?;
1058                let hash = sha1(&buf);
1059                self.push_stack(hash.to_vec())?;
1060            }
1061            OP_SHA256 => {
1062                if self.stack.is_empty() {
1063                    return Err(
1064                        self.error("OP_SHA256 requires at least one item to be on the stack.")
1065                    );
1066                }
1067                let buf = self.pop_stack()?;
1068                let hash = sha256(&buf);
1069                self.push_stack(hash.to_vec())?;
1070            }
1071            OP_HASH160 => {
1072                if self.stack.is_empty() {
1073                    return Err(
1074                        self.error("OP_HASH160 requires at least one item to be on the stack.")
1075                    );
1076                }
1077                let buf = self.pop_stack()?;
1078                let hash = hash160(&buf);
1079                self.push_stack(hash.to_vec())?;
1080            }
1081            OP_HASH256 => {
1082                if self.stack.is_empty() {
1083                    return Err(
1084                        self.error("OP_HASH256 requires at least one item to be on the stack.")
1085                    );
1086                }
1087                let buf = self.pop_stack()?;
1088                let hash = sha256d(&buf);
1089                self.push_stack(hash.to_vec())?;
1090            }
1091            OP_CODESEPARATOR => {
1092                self.last_code_separator = Some(self.program_counter);
1093            }
1094            OP_CHECKSIG | OP_CHECKSIGVERIFY => {
1095                if self.stack.len() < 2 {
1096                    return Err(self.error(&format!(
1097                        "{} requires at least two items to be on the stack.",
1098                        opcode_to_name(opcode).unwrap_or("OP_CHECKSIG")
1099                    )));
1100                }
1101                let pubkey_bytes = self.pop_stack()?;
1102                let sig_bytes = self.pop_stack()?;
1103
1104                // Validate encodings
1105                self.check_signature_encoding(&sig_bytes)?;
1106                self.check_public_key_encoding(&pubkey_bytes)?;
1107
1108                // Build subscript
1109                let subscript = self.build_subscript(&sig_bytes)?;
1110
1111                // Verify signature
1112                let success = if sig_bytes.is_empty() {
1113                    false
1114                } else {
1115                    self.verify_signature(&sig_bytes, &pubkey_bytes, &subscript)?
1116                };
1117
1118                self.push_stack(if success { vec![1] } else { vec![] })?;
1119
1120                if opcode == OP_CHECKSIGVERIFY {
1121                    if !success {
1122                        return Err(self.error(
1123                            "OP_CHECKSIGVERIFY requires that a valid signature is provided.",
1124                        ));
1125                    }
1126                    self.pop_stack()?;
1127                }
1128            }
1129            OP_CHECKMULTISIG | OP_CHECKMULTISIGVERIFY => {
1130                self.op_checkmultisig(opcode)?;
1131            }
1132
1133            // ================================================================
1134            // Data Push (handled above, but catch any missed)
1135            // ================================================================
1136            0x01..=0x4b => {
1137                // Direct push opcodes - should have data
1138                let data = chunk.data.clone().unwrap_or_default();
1139                self.push_stack(data)?;
1140            }
1141            OP_PUSHDATA1 | OP_PUSHDATA2 | OP_PUSHDATA4 => {
1142                let data = chunk.data.clone().unwrap_or_default();
1143                self.push_stack(data)?;
1144            }
1145
1146            // ================================================================
1147            // Unknown/Invalid Opcode
1148            // ================================================================
1149            _ => {
1150                return Err(self.error(&format!(
1151                    "Invalid opcode {} (pc={}).",
1152                    opcode, self.program_counter
1153                )));
1154            }
1155        }
1156
1157        Ok(())
1158    }
1159
1160    // ========================================================================
1161    // OP_CHECKMULTISIG Implementation
1162    // ========================================================================
1163
1164    fn op_checkmultisig(&mut self, opcode: u8) -> Result<(), ScriptEvaluationError> {
1165        // Get number of public keys
1166        if self.stack.is_empty() {
1167            return Err(self.error(&format!(
1168                "{} requires at least 1 item for nKeys.",
1169                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG")
1170            )));
1171        }
1172
1173        let n_keys_bytes = self.pop_stack()?;
1174        let n_keys_bn = ScriptNum::from_bytes(&n_keys_bytes, REQUIRE_MINIMAL_PUSH)
1175            .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
1176        let n_keys = n_keys_bn.to_i64().unwrap_or(-1);
1177
1178        if !(0..=MAX_MULTISIG_KEY_COUNT).contains(&n_keys) {
1179            return Err(self.error(&format!(
1180                "{} requires a key count between 0 and {}.",
1181                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG"),
1182                MAX_MULTISIG_KEY_COUNT
1183            )));
1184        }
1185        let n_keys = n_keys as usize;
1186
1187        // Get public keys
1188        if self.stack.len() < n_keys {
1189            return Err(self.error(&format!(
1190                "{} stack too small for keys. Need {}, have {}.",
1191                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG"),
1192                n_keys,
1193                self.stack.len()
1194            )));
1195        }
1196
1197        let mut pubkeys = Vec::with_capacity(n_keys);
1198        for _ in 0..n_keys {
1199            pubkeys.push(self.pop_stack()?);
1200        }
1201
1202        // Get number of signatures
1203        if self.stack.is_empty() {
1204            return Err(self.error(&format!(
1205                "{} requires item for nSigs.",
1206                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG")
1207            )));
1208        }
1209
1210        let n_sigs_bytes = self.pop_stack()?;
1211        let n_sigs_bn = ScriptNum::from_bytes(&n_sigs_bytes, REQUIRE_MINIMAL_PUSH)
1212            .map_err(|e| self.error(&format!("Invalid script number: {}", e)))?;
1213        let n_sigs = n_sigs_bn.to_i64().unwrap_or(-1);
1214
1215        if n_sigs < 0 || n_sigs as usize > n_keys {
1216            return Err(self.error(&format!(
1217                "{} requires the number of signatures to be no greater than the number of keys.",
1218                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG")
1219            )));
1220        }
1221        let n_sigs = n_sigs as usize;
1222
1223        // Get signatures
1224        if self.stack.len() < n_sigs {
1225            return Err(self.error(&format!(
1226                "{} stack too small for sigs. Need {}, have {}.",
1227                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG"),
1228                n_sigs,
1229                self.stack.len()
1230            )));
1231        }
1232
1233        let mut sigs = Vec::with_capacity(n_sigs);
1234        for _ in 0..n_sigs {
1235            sigs.push(self.pop_stack()?);
1236        }
1237
1238        // Build subscript and remove all signatures
1239        let base_script = match self.context {
1240            ExecutionContext::UnlockingScript => self.unlocking_script.as_script().clone(),
1241            ExecutionContext::LockingScript => self.locking_script.as_script().clone(),
1242        };
1243        let start_idx = self.last_code_separator.map(|i| i + 1).unwrap_or(0);
1244        let chunks = base_script.chunks();
1245        let subscript_chunks: Vec<ScriptChunk> = chunks.into_iter().skip(start_idx).collect();
1246        let mut subscript = Script::from_chunks(subscript_chunks);
1247
1248        for sig in &sigs {
1249            let sig_script = Script::new();
1250            let mut sig_script = sig_script;
1251            sig_script.write_bin(sig);
1252            subscript.find_and_delete(&sig_script);
1253        }
1254
1255        // Verify signatures
1256        let mut success = true;
1257        let mut sig_idx = 0;
1258        let mut key_idx = 0;
1259
1260        while success && sig_idx < n_sigs {
1261            if key_idx >= n_keys {
1262                success = false;
1263                break;
1264            }
1265
1266            let sig_bytes = &sigs[sig_idx];
1267            let pubkey_bytes = &pubkeys[key_idx];
1268
1269            // Validate encodings
1270            if self.check_signature_encoding(sig_bytes).is_err()
1271                || self.check_public_key_encoding(pubkey_bytes).is_err()
1272            {
1273                return Err(self.error(&format!(
1274                    "{} requires correct encoding for the public key and signature.",
1275                    opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG")
1276                )));
1277            }
1278
1279            let sig_valid = if sig_bytes.is_empty() {
1280                false
1281            } else {
1282                self.verify_signature(sig_bytes, pubkey_bytes, &subscript)
1283                    .unwrap_or(false)
1284            };
1285
1286            if sig_valid {
1287                sig_idx += 1;
1288            }
1289            key_idx += 1;
1290
1291            if n_sigs - sig_idx > n_keys - key_idx {
1292                success = false;
1293            }
1294        }
1295
1296        // Pop dummy element (NULLDUMMY)
1297        if self.stack.is_empty() {
1298            return Err(self.error(&format!(
1299                "{} requires an extra item (dummy) to be on the stack.",
1300                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG")
1301            )));
1302        }
1303        let dummy = self.pop_stack()?;
1304        if !dummy.is_empty() {
1305            return Err(self.error(&format!(
1306                "{} requires the extra stack item (dummy) to be empty.",
1307                opcode_to_name(opcode).unwrap_or("OP_CHECKMULTISIG")
1308            )));
1309        }
1310
1311        self.push_stack(if success { vec![1] } else { vec![] })?;
1312
1313        if opcode == OP_CHECKMULTISIGVERIFY {
1314            if !success {
1315                return Err(self.error(
1316                    "OP_CHECKMULTISIGVERIFY requires that a sufficient number of valid signatures are provided.",
1317                ));
1318            }
1319            self.pop_stack()?;
1320        }
1321
1322        Ok(())
1323    }
1324
1325    // ========================================================================
1326    // Signature Verification Helpers
1327    // ========================================================================
1328
1329    fn check_signature_encoding(&self, sig: &[u8]) -> Result<(), ScriptEvaluationError> {
1330        if sig.is_empty() {
1331            return Ok(());
1332        }
1333
1334        // Check basic DER format
1335        if !is_valid_signature_encoding(sig) {
1336            return Err(self.error("The signature format is invalid."));
1337        }
1338
1339        // Parse and check additional requirements
1340        let tx_sig = TransactionSignature::from_checksig_format(sig)
1341            .map_err(|_| self.error("The signature format is invalid."))?;
1342
1343        if REQUIRE_LOW_S_SIGNATURES && !tx_sig.has_low_s() {
1344            return Err(self.error("The signature must have a low S value."));
1345        }
1346
1347        if (tx_sig.scope() & SIGHASH_FORKID) == 0 {
1348            return Err(self.error("The signature must use SIGHASH_FORKID."));
1349        }
1350
1351        Ok(())
1352    }
1353
1354    fn check_public_key_encoding(&self, pubkey: &[u8]) -> Result<(), ScriptEvaluationError> {
1355        if pubkey.is_empty() {
1356            return Err(self.error("Public key is empty."));
1357        }
1358
1359        if pubkey.len() < 33 {
1360            return Err(self.error("The public key is too short, it must be at least 33 bytes."));
1361        }
1362
1363        if pubkey[0] == 0x04 {
1364            if pubkey.len() != 65 {
1365                return Err(self.error("The non-compressed public key must be 65 bytes."));
1366            }
1367        } else if pubkey[0] == 0x02 || pubkey[0] == 0x03 {
1368            if pubkey.len() != 33 {
1369                return Err(self.error("The compressed public key must be 33 bytes."));
1370            }
1371        } else {
1372            return Err(self.error("The public key is in an unknown format."));
1373        }
1374
1375        // Try to parse it
1376        PublicKey::from_bytes(pubkey)
1377            .map_err(|_| self.error("The public key is in an unknown format."))?;
1378
1379        Ok(())
1380    }
1381
1382    fn build_subscript(&self, sig_bytes: &[u8]) -> Result<Script, ScriptEvaluationError> {
1383        let base_script = match self.context {
1384            ExecutionContext::UnlockingScript => self.unlocking_script.as_script().clone(),
1385            ExecutionContext::LockingScript => self.locking_script.as_script().clone(),
1386        };
1387
1388        let start_idx = self.last_code_separator.map(|i| i + 1).unwrap_or(0);
1389        let chunks = base_script.chunks();
1390        let subscript_chunks: Vec<ScriptChunk> = chunks.into_iter().skip(start_idx).collect();
1391        let mut subscript = Script::from_chunks(subscript_chunks);
1392
1393        // Remove the signature from the subscript
1394        let mut sig_script = Script::new();
1395        sig_script.write_bin(sig_bytes);
1396        subscript.find_and_delete(&sig_script);
1397
1398        Ok(subscript)
1399    }
1400
1401    fn verify_signature(
1402        &self,
1403        sig_bytes: &[u8],
1404        pubkey_bytes: &[u8],
1405        subscript: &Script,
1406    ) -> Result<bool, ScriptEvaluationError> {
1407        // Parse signature and public key
1408        let tx_sig = match TransactionSignature::from_checksig_format(sig_bytes) {
1409            Ok(s) => s,
1410            Err(_) => return Ok(false),
1411        };
1412
1413        let pubkey = match PublicKey::from_bytes(pubkey_bytes) {
1414            Ok(p) => p,
1415            Err(_) => return Ok(false),
1416        };
1417
1418        // Build inputs array for sighash
1419        let inputs = self.build_inputs_array();
1420
1421        // Compute sighash
1422        let sighash = compute_sighash_for_signing(&SighashParams {
1423            version: self.transaction_version,
1424            inputs: &inputs,
1425            outputs: &self.outputs,
1426            locktime: self.lock_time,
1427            input_index: self.input_index,
1428            subscript: &subscript.to_binary(),
1429            satoshis: self.source_satoshis,
1430            scope: tx_sig.scope(),
1431        });
1432
1433        // Verify
1434        Ok(pubkey.verify(&sighash, tx_sig.signature()))
1435    }
1436
1437    fn build_inputs_array(&self) -> Vec<TxInput> {
1438        let mut inputs = Vec::with_capacity(self.other_inputs.len() + 1);
1439
1440        // Add other inputs
1441        for (i, other) in self.other_inputs.iter().enumerate() {
1442            if i == self.input_index {
1443                // Insert our input at the correct position
1444                inputs.push(TxInput {
1445                    txid: self.source_txid,
1446                    output_index: self.source_output_index,
1447                    script: self.unlocking_script.to_binary(),
1448                    sequence: self.input_sequence,
1449                });
1450            }
1451            inputs.push(other.clone());
1452        }
1453
1454        // Handle case where our input is at the end or other_inputs is empty
1455        if self.input_index >= self.other_inputs.len() {
1456            inputs.push(TxInput {
1457                txid: self.source_txid,
1458                output_index: self.source_output_index,
1459                script: self.unlocking_script.to_binary(),
1460                sequence: self.input_sequence,
1461            });
1462        }
1463
1464        inputs
1465    }
1466
1467    // ========================================================================
1468    // Stack Helpers
1469    // ========================================================================
1470
1471    fn push_stack(&mut self, item: Vec<u8>) -> Result<(), ScriptEvaluationError> {
1472        self.ensure_stack_mem(item.len())?;
1473        self.stack_mem += item.len();
1474        self.stack.push(item);
1475        Ok(())
1476    }
1477
1478    fn push_stack_copy(&mut self, item: &[u8]) -> Result<(), ScriptEvaluationError> {
1479        self.push_stack(item.to_vec())
1480    }
1481
1482    fn pop_stack(&mut self) -> Result<Vec<u8>, ScriptEvaluationError> {
1483        if self.stack.is_empty() {
1484            return Err(self.error("Attempted to pop from an empty stack."));
1485        }
1486        let item = self.stack.pop().unwrap();
1487        self.stack_mem -= item.len();
1488        Ok(item)
1489    }
1490
1491    fn stack_top(&self) -> Result<&Vec<u8>, ScriptEvaluationError> {
1492        if self.stack.is_empty() {
1493            return Err(self.error("Stack is empty."));
1494        }
1495        Ok(&self.stack[self.stack.len() - 1])
1496    }
1497
1498    fn stack_top_n(&self, n: usize) -> Result<&Vec<u8>, ScriptEvaluationError> {
1499        if self.stack.len() < n {
1500            return Err(self.error(&format!(
1501                "Stack underflow accessing element at index {}. Stack length is {}.",
1502                n,
1503                self.stack.len()
1504            )));
1505        }
1506        Ok(&self.stack[self.stack.len() - n])
1507    }
1508
1509    fn push_alt_stack(&mut self, item: Vec<u8>) -> Result<(), ScriptEvaluationError> {
1510        self.ensure_alt_stack_mem(item.len())?;
1511        self.alt_stack_mem += item.len();
1512        self.alt_stack.push(item);
1513        Ok(())
1514    }
1515
1516    fn pop_alt_stack(&mut self) -> Result<Vec<u8>, ScriptEvaluationError> {
1517        if self.alt_stack.is_empty() {
1518            return Err(self.error("Attempted to pop from an empty alt stack."));
1519        }
1520        let item = self.alt_stack.pop().unwrap();
1521        self.alt_stack_mem -= item.len();
1522        Ok(item)
1523    }
1524
1525    fn ensure_stack_mem(&self, additional: usize) -> Result<(), ScriptEvaluationError> {
1526        if self.stack_mem + additional > self.memory_limit {
1527            return Err(self.error(&format!(
1528                "Stack memory usage has exceeded {} bytes",
1529                self.memory_limit
1530            )));
1531        }
1532        Ok(())
1533    }
1534
1535    fn ensure_alt_stack_mem(&self, additional: usize) -> Result<(), ScriptEvaluationError> {
1536        if self.alt_stack_mem + additional > self.memory_limit {
1537            return Err(self.error(&format!(
1538                "Alt stack memory usage has exceeded {} bytes",
1539                self.memory_limit
1540            )));
1541        }
1542        Ok(())
1543    }
1544
1545    // ========================================================================
1546    // Error Helpers
1547    // ========================================================================
1548
1549    fn error(&self, message: &str) -> ScriptEvaluationError {
1550        ScriptEvaluationError::new(
1551            message,
1552            to_hex(&self.source_txid),
1553            self.source_output_index,
1554            self.context,
1555            self.program_counter,
1556            self.stack.clone(),
1557            self.alt_stack.clone(),
1558            self.if_stack.clone(),
1559            self.stack_mem,
1560            self.alt_stack_mem,
1561        )
1562    }
1563}
1564
1565// ============================================================================
1566// Helper Functions
1567// ============================================================================
1568
1569/// Checks if an opcode is disabled.
1570fn is_opcode_disabled(op: u8) -> bool {
1571    matches!(op, OP_2MUL | OP_2DIV | OP_VER | OP_VERIF | OP_VERNOTIF)
1572}
1573
1574/// Checks if a chunk uses minimal push encoding.
1575fn is_chunk_minimal_push(chunk: &ScriptChunk) -> bool {
1576    let data = match &chunk.data {
1577        Some(d) => d,
1578        None => return true,
1579    };
1580    let op = chunk.op;
1581
1582    if data.is_empty() {
1583        return op == OP_0;
1584    }
1585
1586    if data.len() == 1 && data[0] >= 1 && data[0] <= 16 {
1587        return op == OP_1 + (data[0] - 1);
1588    }
1589
1590    if data.len() == 1 && data[0] == 0x81 {
1591        return op == OP_1NEGATE;
1592    }
1593
1594    if data.len() <= 75 {
1595        return op as usize == data.len();
1596    }
1597
1598    if data.len() <= 255 {
1599        return op == OP_PUSHDATA1;
1600    }
1601
1602    if data.len() <= 65535 {
1603        return op == OP_PUSHDATA2;
1604    }
1605
1606    true
1607}
1608
1609/// Validates DER signature encoding (simplified check).
1610fn is_valid_signature_encoding(sig: &[u8]) -> bool {
1611    if sig.len() < 9 || sig.len() > 73 {
1612        return false;
1613    }
1614
1615    // Sequence tag
1616    if sig[0] != 0x30 {
1617        return false;
1618    }
1619
1620    // Length check
1621    if sig[1] as usize != sig.len() - 3 {
1622        return false;
1623    }
1624
1625    // R value
1626    if sig[2] != 0x02 {
1627        return false;
1628    }
1629
1630    let r_len = sig[3] as usize;
1631    if r_len == 0 || 5 + r_len >= sig.len() {
1632        return false;
1633    }
1634
1635    // S value
1636    let s_offset = 4 + r_len;
1637    if sig[s_offset] != 0x02 {
1638        return false;
1639    }
1640
1641    let s_len = sig[s_offset + 1] as usize;
1642    if s_len == 0 {
1643        return false;
1644    }
1645
1646    // Check total length
1647    if r_len + s_len + 7 != sig.len() {
1648        return false;
1649    }
1650
1651    // Check R not negative
1652    if (sig[4] & 0x80) != 0 {
1653        return false;
1654    }
1655
1656    // Check R not excessively padded
1657    if r_len > 1 && sig[4] == 0x00 && (sig[5] & 0x80) == 0 {
1658        return false;
1659    }
1660
1661    // Check S not negative
1662    let s_value_offset = s_offset + 2;
1663    if (sig[s_value_offset] & 0x80) != 0 {
1664        return false;
1665    }
1666
1667    // Check S not excessively padded
1668    if s_len > 1 && sig[s_value_offset] == 0x00 && (sig[s_value_offset + 1] & 0x80) == 0 {
1669        return false;
1670    }
1671
1672    true
1673}
1674
1675#[cfg(test)]
1676mod tests {
1677    use super::*;
1678
1679    #[test]
1680    fn test_is_opcode_disabled() {
1681        assert!(is_opcode_disabled(OP_2MUL));
1682        assert!(is_opcode_disabled(OP_2DIV));
1683        assert!(is_opcode_disabled(OP_VER));
1684        assert!(is_opcode_disabled(OP_VERIF));
1685        assert!(is_opcode_disabled(OP_VERNOTIF));
1686
1687        assert!(!is_opcode_disabled(OP_DUP));
1688        assert!(!is_opcode_disabled(OP_MUL));
1689        assert!(!is_opcode_disabled(OP_CAT));
1690    }
1691
1692    #[test]
1693    fn test_is_chunk_minimal_push() {
1694        // OP_0 for empty data
1695        let chunk = ScriptChunk::new(OP_0, Some(vec![]));
1696        assert!(is_chunk_minimal_push(&chunk));
1697
1698        // Direct push for small data
1699        let chunk = ScriptChunk::new(3, Some(vec![1, 2, 3]));
1700        assert!(is_chunk_minimal_push(&chunk));
1701
1702        // OP_1 for [1]
1703        let chunk = ScriptChunk::new(OP_1, Some(vec![1]));
1704        assert!(is_chunk_minimal_push(&chunk));
1705
1706        // Non-minimal: using push opcode for [1] instead of OP_1
1707        let chunk = ScriptChunk::new(1, Some(vec![1]));
1708        assert!(!is_chunk_minimal_push(&chunk));
1709    }
1710
1711    #[test]
1712    fn test_simple_stack_script() {
1713        // Test: OP_1 OP_2 OP_ADD OP_3 OP_EQUAL
1714        // Should leave [1] on stack (true)
1715        let locking = LockingScript::from_asm("OP_ADD OP_3 OP_EQUAL").unwrap();
1716        let unlocking = UnlockingScript::from_asm("OP_1 OP_2").unwrap();
1717
1718        let mut spend = Spend::new(SpendParams {
1719            source_txid: [0u8; 32],
1720            source_output_index: 0,
1721            source_satoshis: 0,
1722            locking_script: locking,
1723            transaction_version: 1,
1724            other_inputs: vec![],
1725            outputs: vec![],
1726            input_index: 0,
1727            unlocking_script: unlocking,
1728            input_sequence: 0xffffffff,
1729            lock_time: 0,
1730            memory_limit: None,
1731        });
1732
1733        let result = spend.validate();
1734        assert!(result.is_ok(), "Expected valid spend, got {:?}", result);
1735    }
1736
1737    #[test]
1738    fn test_if_else_endif() {
1739        // Test: OP_1 OP_IF OP_2 OP_ELSE OP_3 OP_ENDIF
1740        // Should push 2 (true branch)
1741        let locking = LockingScript::from_asm("OP_IF OP_2 OP_ELSE OP_3 OP_ENDIF").unwrap();
1742        let unlocking = UnlockingScript::from_asm("OP_1").unwrap();
1743
1744        let mut spend = Spend::new(SpendParams {
1745            source_txid: [0u8; 32],
1746            source_output_index: 0,
1747            source_satoshis: 0,
1748            locking_script: locking,
1749            transaction_version: 1,
1750            other_inputs: vec![],
1751            outputs: vec![],
1752            input_index: 0,
1753            unlocking_script: unlocking,
1754            input_sequence: 0xffffffff,
1755            lock_time: 0,
1756            memory_limit: None,
1757        });
1758
1759        let result = spend.validate();
1760        assert!(result.is_ok(), "Expected valid spend, got {:?}", result);
1761    }
1762
1763    #[test]
1764    fn test_hash_operations() {
1765        // Test that hash operations work
1766        // SHA256 produces 32 bytes, we check the size is 32 (0x20)
1767        // Use NIP to remove the hash after SIZE, leaving just the size to compare
1768        let locking = LockingScript::from_asm("OP_SHA256 OP_SIZE OP_NIP 20 OP_EQUAL").unwrap();
1769        let unlocking = UnlockingScript::from_asm("00").unwrap();
1770
1771        let mut spend = Spend::new(SpendParams {
1772            source_txid: [0u8; 32],
1773            source_output_index: 0,
1774            source_satoshis: 0,
1775            locking_script: locking,
1776            transaction_version: 1,
1777            other_inputs: vec![],
1778            outputs: vec![],
1779            input_index: 0,
1780            unlocking_script: unlocking,
1781            input_sequence: 0xffffffff,
1782            lock_time: 0,
1783            memory_limit: None,
1784        });
1785
1786        let result = spend.validate();
1787        assert!(result.is_ok(), "Expected valid spend, got {:?}", result);
1788    }
1789
1790    #[test]
1791    fn test_failing_script() {
1792        // Test: just OP_0 should fail (stack has falsy value)
1793        let locking = LockingScript::from_asm("OP_0").unwrap();
1794        let unlocking = UnlockingScript::new();
1795
1796        let mut spend = Spend::new(SpendParams {
1797            source_txid: [0u8; 32],
1798            source_output_index: 0,
1799            source_satoshis: 0,
1800            locking_script: locking,
1801            transaction_version: 1,
1802            other_inputs: vec![],
1803            outputs: vec![],
1804            input_index: 0,
1805            unlocking_script: unlocking,
1806            input_sequence: 0xffffffff,
1807            lock_time: 0,
1808            memory_limit: None,
1809        });
1810
1811        let result = spend.validate();
1812        assert!(result.is_err(), "Expected failed validation");
1813    }
1814}