Skip to main content

blvm_consensus/script/
stack.rs

1//! Stack types and operations for script execution.
2//!
3//! StackElement, to_stack_element, and cast_to_bool are used by both
4//! production and non-production script execution paths.
5
6#[cfg(feature = "spec-lock")]
7use blvm_spec_lock::spec_locked;
8
9use crate::types::*;
10
11#[cfg(feature = "production")]
12use smallvec::SmallVec;
13
14/// Stack element: inline up to 80 bytes when production (sigs, pubkeys, hashes), else `Vec<u8>`.
15#[cfg(feature = "production")]
16pub type StackElement = SmallVec<[u8; 80]>;
17#[cfg(not(feature = "production"))]
18pub type StackElement = ByteString;
19
20/// Convert bytes to StackElement (for tests and callers needing explicit conversion).
21#[inline]
22pub fn to_stack_element(data: &[u8]) -> StackElement {
23    #[cfg(feature = "production")]
24    return SmallVec::from_slice(data);
25    #[cfg(not(feature = "production"))]
26    return data.to_vec();
27}
28
29/// CastToBool: truthiness check for stack elements (BIP62/consensus).
30/// Returns true if ANY byte is non-zero, except for "negative zero" (0x80 in last byte, rest zeros).
31#[cfg_attr(feature = "spec-lock", spec_locked("5.2.4", "CastToBool"))]
32#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result == false || v.len() > 0))]
33#[cfg(feature = "production")]
34#[inline(always)]
35pub fn cast_to_bool(v: &[u8]) -> bool {
36    for i in 0..v.len() {
37        if v[i] != 0 {
38            // Negative zero: all zeros except 0x80 in the last byte
39            if i == v.len() - 1 && v[i] == 0x80 {
40                return false;
41            }
42            return true;
43        }
44    }
45    false
46}
47
48#[cfg_attr(feature = "spec-lock", spec_locked("5.2.4", "CastToBool"))]
49#[cfg_attr(feature = "spec-lock", blvm_spec_lock::ensures(result == false || v.len() > 0))]
50#[cfg(not(feature = "production"))]
51#[inline]
52pub fn cast_to_bool(v: &[u8]) -> bool {
53    for i in 0..v.len() {
54        if v[i] != 0 {
55            // Negative zero: all zeros except 0x80 in the last byte
56            if i == v.len() - 1 && v[i] == 0x80 {
57                return false;
58            }
59            return true;
60        }
61    }
62    false
63}