Skip to main content

blvm_consensus/
optimizations.rs

1//! BLVM Runtime Optimization Passes
2//!
3//! Additional optimization passes for 10-30% performance gains
4//!
5//! This module provides runtime optimization passes:
6//! - Constant folding (pre-computed constants)
7//! - Bounds check optimization (proven bounds)
8//! - Inlining hints (hot function markers)
9//! - Memory layout optimization (cache-friendly structures)
10//!
11//! Reference: Orange Paper Section 13.1 - Performance Considerations
12
13use crate::constants::*;
14
15/// Pre-computed constants for constant folding optimization
16///
17/// These constants are computed at compile time to avoid runtime computation
18/// in hot paths. Reference: BLVM Optimization Pass 2 - Constant Folding
19#[cfg(feature = "production")]
20pub mod precomputed_constants {
21    use super::*;
22
23    /// Pre-computed: 2^64 - 1 (used for wrapping arithmetic checks)
24    pub const U64_MAX: u64 = u64::MAX;
25
26    /// Pre-computed: MAX_MONEY as u64 (for comparisons)
27    pub const MAX_MONEY_U64: u64 = MAX_MONEY as u64;
28
29    /// Pre-computed: Inverse of SATOSHIS_PER_BTC (for BTC conversion)
30    pub const BTC_PER_SATOSHI: f64 = 1.0 / (SATOSHIS_PER_BTC as f64);
31
32    /// Pre-computed: 2^32 - 1 (for 32-bit wrapping checks)
33    pub const U32_MAX: u32 = u32::MAX;
34
35    /// Pre-computed: Number of satoshis in 1 BTC (for readability)
36    pub const ONE_BTC_SATOSHIS: i64 = SATOSHIS_PER_BTC;
37}
38
39/// Memory layout optimization: Cache-friendly hash array
40///
41/// Optimizes hash array access for cache locality.
42/// Uses 32-byte aligned structures for better cache performance.
43///
44/// This structure ensures each hash is aligned to a 32-byte boundary, which:
45/// - Reduces cache line splits
46/// - Improves prefetching behavior
47/// - Better fits modern CPU cache architectures (64-byte cache lines)
48///
49/// Reference: BLVM Optimization Pass 3 - Memory Layout Optimization
50/// Cache-aligned hash for optimized batch operations
51#[repr(align(32))]
52#[derive(Clone)]
53pub struct CacheAlignedHash([u8; 32]);
54
55impl CacheAlignedHash {
56    #[inline]
57    pub fn new(hash: [u8; 32]) -> Self {
58        Self(hash)
59    }
60
61    #[inline]
62    pub fn as_bytes(&self) -> &[u8; 32] {
63        &self.0
64    }
65}
66
67/// Memory prefetching optimization
68///
69/// Provides platform-specific prefetch hints to improve cache performance
70/// for sequential memory accesses. Used before batch UTXO lookups and
71/// other sequential data structure traversals.
72///
73/// Reference: BLVM Optimization Pass 1.3 - Memory Prefetching
74#[cfg(feature = "production")]
75pub mod prefetch {
76    /// Prefetch data for read access
77    ///
78    /// Hints the CPU to prefetch data into cache before it's needed.
79    /// This improves performance for sequential memory access patterns.
80    ///
81    /// # Safety
82    /// The pointer must be valid, but it doesn't need to be dereferenceable
83    /// at the time of the call. The prefetch is a hint and may be ignored.
84    #[cfg(target_arch = "x86_64")]
85    #[inline(always)]
86    pub unsafe fn prefetch_read(ptr: *const i8) {
87        use std::arch::x86_64::{_MM_HINT_T0, _mm_prefetch};
88        unsafe {
89            _mm_prefetch(ptr, _MM_HINT_T0);
90        }
91    }
92
93    #[cfg(target_arch = "aarch64")]
94    #[inline(always)]
95    pub unsafe fn prefetch_read(ptr: *const i8) {
96        // std::arch::aarch64::_prefetch requires the unstable
97        // `stdarch_aarch64_prefetch` feature (issue #117217) and is not yet
98        // available on stable Rust.  Use inline asm instead: `core::arch::asm!`
99        // is stable since 1.59 and emits the identical PRFM instruction.
100        // PRFM PLDL1KEEP = Prefetch for Load, L1, temporal (≡ _prefetch hint T0).
101        core::arch::asm!(
102            "prfm pldl1keep, [{addr}]",
103            addr = in(reg) ptr,
104            options(nostack, readonly, preserves_flags)
105        );
106    }
107
108    #[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
109    #[inline(always)]
110    pub unsafe fn prefetch_read(_ptr: *const i8) {
111        // No-op for unsupported architectures
112    }
113
114    /// Prefetch a slice of data for sequential access
115    ///
116    /// Prefetches the next cache line(s) of data to improve sequential access.
117    /// Safe wrapper around prefetch_read that works with slices.
118    #[inline(always)]
119    pub fn prefetch_slice<T>(slice: &[T], index: usize) {
120        if index < slice.len() {
121            unsafe {
122                let ptr = slice.as_ptr().add(index) as *const i8;
123                prefetch_read(ptr);
124            }
125        }
126    }
127
128    /// Prefetch multiple elements ahead in a slice
129    ///
130    /// Prefetches elements at `index + offset` to prepare for future access.
131    /// Useful for sequential loops where you know you'll access elements ahead.
132    #[inline(always)]
133    pub fn prefetch_ahead<T>(slice: &[T], index: usize, offset: usize) {
134        let prefetch_index = index.saturating_add(offset);
135        prefetch_slice(slice, prefetch_index);
136    }
137}
138
139/// Memory layout optimization: Compact stack frame
140///
141/// Compact stack frame for script execution optimization
142/// Optimized stack frame structure for cache locality.
143#[repr(C, packed)]
144pub struct CompactStackFrame {
145    pub opcode: u8,
146    pub flags: u32,
147    pub script_offset: u16,
148    pub stack_height: u16,
149}
150
151impl CompactStackFrame {
152    #[inline]
153    pub fn new(opcode: u8, flags: u32, script_offset: u16, stack_height: u16) -> Self {
154        Self {
155            opcode,
156            flags,
157            script_offset,
158            stack_height,
159        }
160    }
161}
162
163/// Inlining hints for hot functions
164///
165/// Functions marked with HOT_INLINE should be aggressively inlined.
166/// These are called in tight loops and benefit from inlining.
167#[macro_export]
168#[cfg(feature = "production")]
169macro_rules! hot_inline {
170    () => {
171        #[inline(always)]
172    };
173}
174
175/// Constant folding: Pre-compute common hash results
176///
177/// Caches common hash pre-images for constant folding.
178#[cfg(feature = "production")]
179pub mod constant_folding {
180    /// Pre-computed: SHA256 of empty string
181    pub const EMPTY_STRING_HASH: [u8; 32] = [
182        0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9,
183        0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52,
184        0xb8, 0x55,
185    ];
186
187    /// Pre-computed: Double SHA256 of empty string
188    pub const EMPTY_STRING_DOUBLE_HASH: [u8; 32] = [
189        0x5d, 0xf6, 0xe0, 0xe2, 0x76, 0x13, 0x59, 0xf3, 0x73, 0x9a, 0x1c, 0x6f, 0x87, 0x40, 0x64,
190        0x0a, 0xf1, 0x2e, 0xc7, 0xc3, 0x72, 0x4a, 0x5c, 0x2c, 0xa5, 0xf3, 0x0f, 0x26, 0x60, 0x87,
191        0x7e, 0x6b,
192    ];
193
194    /// Check if input matches empty string hash (constant folding)
195    #[inline(always)]
196    pub fn is_empty_hash(hash: &[u8; 32]) -> bool {
197        *hash == EMPTY_STRING_HASH
198    }
199
200    /// Check if input matches empty string double hash (constant folding)
201    #[inline(always)]
202    pub fn is_empty_double_hash(hash: &[u8; 32]) -> bool {
203        *hash == EMPTY_STRING_DOUBLE_HASH
204    }
205
206    /// Constant-fold: Check if hash is zero (all zeros)
207    #[inline(always)]
208    pub fn is_zero_hash(hash: &[u8; 32]) -> bool {
209        hash.iter().all(|&b| b == 0)
210    }
211}
212
213/// Dead code elimination markers
214///
215/// Functions/constants marked with this can be eliminated if unused.
216#[cfg(feature = "production")]
217#[allow(dead_code)]
218pub mod dead_code_elimination {
219    /// Mark code for dead code elimination analysis
220    /// This is a marker function - the compiler can eliminate unused paths
221    #[inline(never)]
222    #[cold]
223    pub fn mark_unused() {
224        // This function never executes in production builds
225        // It's a marker for dead code elimination pass
226    }
227
228    /// Hint to compiler that branch is unlikely (dead code elimination)
229    ///
230    /// Note: In stable Rust, this is a no-op but serves as documentation
231    /// for future optimization opportunities (unstable `likely`/`unlikely` intrinsics).
232    #[inline(always)]
233    pub fn unlikely(condition: bool) -> bool {
234        // Stable Rust doesn't have likely/unlikely intrinsics
235        // This is a placeholder for future optimization
236        condition
237    }
238}
239
240/// SIMD Vectorization: Batch hash operations
241///
242/// Provides batch hash processing for parallel hash operations.
243/// Leverages existing SIMD in sha2 crate (asm feature) + Rayon for CPU-core parallelization.
244///
245/// Provides batch functions for:
246/// - SHA256 and double SHA256 (Bitcoin standard)
247/// - RIPEMD160 and HASH160 (OP_HASH160)
248///
249/// Uses chunked processing for better cache locality and parallelizes across CPU cores
250/// when batch size is large enough (≥8 items).
251///
252/// Reference: BLVM Optimization Pass 5 - SIMD Vectorization
253#[cfg(feature = "production")]
254pub mod simd_vectorization {
255    use crate::crypto::OptimizedSha256;
256    use digest::Digest;
257    use ripemd::Ripemd160;
258
259    /// Minimum batch size for parallelization (overhead not worth it for smaller batches).
260    /// batch_sha256 uses OptimizedSha256 (SHA-NI when available) for consistency with batch_double_sha256_aligned.
261    const PARALLEL_THRESHOLD: usize = 8;
262
263    /// Chunk size for cache-friendly processing. Hardware-derived via ibd_tuning.
264    #[inline]
265    fn chunk_size() -> usize {
266        blvm_primitives::ibd_tuning::hash_batch_chunk_size()
267    }
268
269    /// Batch SHA256: Compute SHA256 for multiple independent inputs
270    ///
271    /// # Arguments
272    /// * `inputs` - Slice of byte slices to hash
273    ///
274    /// # Returns
275    /// Vector of 32-byte hashes, one per input (in same order)
276    ///
277    /// # Performance
278    /// - Small batches (< 4 items): Sequential (overhead not worth parallelization)
279    /// - Medium batches (4-7 items): Chunked sequential
280    /// - Large batches (≥8 items): Multi-core parallelization with Rayon
281    ///
282    /// # Optimizations
283    /// - Uses sha2 crate with "asm" feature for optimized assembly
284    /// - For large batches, leverages Rayon for multi-core parallelization
285    /// - AVX2 batch optimization available via `crypto::avx2_batch` module
286    pub fn batch_sha256(inputs: &[&[u8]]) -> Vec<[u8; 32]> {
287        if inputs.is_empty() {
288            return Vec::new();
289        }
290
291        // Small batches: sequential processing. Use OptimizedSha256 (SHA-NI when available).
292        if inputs.len() < 4 {
293            let hasher = OptimizedSha256::new();
294            return inputs.iter().map(|input| hasher.hash(input)).collect();
295        }
296
297        // Medium batches: chunked sequential processing
298        if inputs.len() < PARALLEL_THRESHOLD {
299            let hasher = OptimizedSha256::new();
300            let mut results = Vec::with_capacity(inputs.len());
301            for chunk in inputs.chunks(chunk_size()) {
302                for input in chunk {
303                    results.push(hasher.hash(input));
304                }
305            }
306            return results;
307        }
308
309        // Large batches: Try AVX2 first, then fallback to multi-core parallelization
310        #[cfg(target_arch = "x86_64")]
311        {
312            use crate::crypto::sha256_avx2;
313            if sha256_avx2::is_avx2_available() {
314                // Use AVX2 batch processing for chunks of 8
315                use crate::crypto::avx2_batch;
316                return avx2_batch::batch_sha256_avx2(inputs);
317            }
318        }
319
320        // Fallback: serial chunked processing. The previous `par_chunks` rayon path was
321        // disastrous in IBD: N validation workers × per-block calls × shared rayon pool =
322        // catastrophic oversubscription. SHA-NI single-thread is fast enough; cross-block
323        // parallelism (worker pool) is the only level we want.
324        let hasher = OptimizedSha256::new();
325        let mut results = Vec::with_capacity(inputs.len());
326        for chunk in inputs.chunks(chunk_size()) {
327            for input in chunk {
328                results.push(hasher.hash(input));
329            }
330        }
331        results
332    }
333
334    /// Batch double SHA256: Compute SHA256(SHA256(x)) for multiple inputs
335    ///
336    /// This is Bitcoin's standard hash function used for transaction IDs, block hashes, etc.
337    ///
338    /// # Arguments
339    /// * `inputs` - Slice of byte slices to hash
340    ///
341    /// # Returns
342    /// Vector of 32-byte hashes, one per input (in same order)
343    pub fn batch_double_sha256(inputs: &[&[u8]]) -> Vec<[u8; 32]> {
344        // Use aligned version for better cache performance
345        batch_double_sha256_aligned(inputs)
346            .into_iter()
347            .map(|h| *h.as_bytes())
348            .collect()
349    }
350
351    /// Batch double SHA256 with cache-aligned output
352    ///
353    /// Returns cache-aligned hash structures for better memory performance.
354    /// Uses 32-byte alignment for optimal cache line utilization.
355    ///
356    /// # Arguments
357    /// * `inputs` - Slice of byte slices to hash
358    ///
359    /// # Returns
360    /// Vector of cache-aligned 32-byte hashes, one per input (in same order)
361    pub fn batch_double_sha256_aligned(inputs: &[&[u8]]) -> Vec<super::CacheAlignedHash> {
362        if inputs.is_empty() {
363            return Vec::new();
364        }
365
366        // Small batches: sequential processing (overhead not worth it)
367        // Use OptimizedSha256 (SHA-NI when available) instead of sha2
368        let hasher = OptimizedSha256::new();
369        if inputs.len() < 4 {
370            return inputs
371                .iter()
372                .map(|input| super::CacheAlignedHash::new(hasher.hash256(input)))
373                .collect();
374        }
375
376        // Medium batches: chunked sequential processing
377        if inputs.len() < PARALLEL_THRESHOLD {
378            let mut results = Vec::with_capacity(inputs.len());
379            for chunk in inputs.chunks(chunk_size()) {
380                for input in chunk {
381                    results.push(super::CacheAlignedHash::new(hasher.hash256(input)));
382                }
383            }
384            return results;
385        }
386
387        // Serial chunked processing — see `batch_sha256` for rationale (rayon oversubscribes
388        // the pool when N IBD workers each push hashing batches; SHA-NI keeps the per-worker
389        // path fast on its own thread).
390        let hasher = OptimizedSha256::new();
391        let mut results = Vec::with_capacity(inputs.len());
392        for chunk in inputs.chunks(chunk_size()) {
393            for input in chunk {
394                results.push(super::CacheAlignedHash::new(hasher.hash256(input)));
395            }
396        }
397        results
398    }
399
400    /// Batch RIPEMD160: Compute RIPEMD160 for multiple inputs
401    ///
402    /// # Arguments
403    /// * `inputs` - Slice of byte slices to hash
404    ///
405    /// # Returns
406    /// Vector of 20-byte hashes, one per input (in same order)
407    pub fn batch_ripemd160(inputs: &[&[u8]]) -> Vec<[u8; 20]> {
408        if inputs.is_empty() {
409            return Vec::new();
410        }
411
412        // Small batches: sequential processing
413        if inputs.len() < 4 {
414            return inputs
415                .iter()
416                .map(|input| {
417                    let hash = Ripemd160::digest(input);
418                    let mut result = [0u8; 20];
419                    result.copy_from_slice(&hash);
420                    result
421                })
422                .collect();
423        }
424
425        // Medium batches: chunked sequential processing
426        if inputs.len() < PARALLEL_THRESHOLD {
427            let mut results = Vec::with_capacity(inputs.len());
428            for chunk in inputs.chunks(chunk_size()) {
429                for input in chunk {
430                    let hash = Ripemd160::digest(input);
431                    let mut result = [0u8; 20];
432                    result.copy_from_slice(&hash);
433                    results.push(result);
434                }
435            }
436            return results;
437        }
438
439        // Serial chunked processing — same rationale as `batch_sha256`: cross-block
440        // parallelism is provided by the IBD worker pool; rayon par_chunks here
441        // oversubscribes the global pool when N workers each call this per-block.
442        let mut results = Vec::with_capacity(inputs.len());
443        for chunk in inputs.chunks(chunk_size()) {
444            for input in chunk {
445                let hash = Ripemd160::digest(input);
446                let mut result = [0u8; 20];
447                result.copy_from_slice(&hash);
448                results.push(result);
449            }
450        }
451        results
452    }
453
454    /// Batch HASH160: Compute RIPEMD160(SHA256(x)) for multiple inputs
455    ///
456    /// This is Bitcoin's HASH160 operation (OP_HASH160 in script).
457    ///
458    /// # Arguments
459    /// * `inputs` - Slice of byte slices to hash
460    ///
461    /// # Returns
462    /// Vector of 20-byte hashes, one per input (in same order)
463    pub fn batch_hash160(inputs: &[&[u8]]) -> Vec<[u8; 20]> {
464        if inputs.is_empty() {
465            return Vec::new();
466        }
467
468        // Small batches: sequential processing. Use OptimizedSha256 (SHA-NI) for SHA256 part.
469        if inputs.len() < 4 {
470            let hasher = OptimizedSha256::new();
471            return inputs
472                .iter()
473                .map(|input| {
474                    let sha256_hash: [u8; 32] = hasher.hash(input);
475                    let ripemd160_hash = Ripemd160::digest(sha256_hash);
476                    let mut result = [0u8; 20];
477                    result.copy_from_slice(&ripemd160_hash);
478                    result
479                })
480                .collect();
481        }
482
483        // Medium batches: chunked sequential processing
484        if inputs.len() < PARALLEL_THRESHOLD {
485            let hasher = OptimizedSha256::new();
486            let mut results = Vec::with_capacity(inputs.len());
487            for chunk in inputs.chunks(chunk_size()) {
488                for input in chunk {
489                    let sha256_hash: [u8; 32] = hasher.hash(input);
490                    let ripemd160_hash = Ripemd160::digest(sha256_hash);
491                    let mut result = [0u8; 20];
492                    result.copy_from_slice(&ripemd160_hash);
493                    results.push(result);
494                }
495            }
496            return results;
497        }
498
499        // Serial chunked processing — see `batch_sha256` for rationale.
500        let hasher = OptimizedSha256::new();
501        let mut results = Vec::with_capacity(inputs.len());
502        for chunk in inputs.chunks(chunk_size()) {
503            for input in chunk {
504                let sha256_hash: [u8; 32] = hasher.hash(input);
505                let ripemd160_hash = Ripemd160::digest(sha256_hash);
506                let mut result = [0u8; 20];
507                result.copy_from_slice(&ripemd160_hash);
508                results.push(result);
509            }
510        }
511        results
512    }
513}
514
515#[cfg(feature = "production")]
516pub use constant_folding::*;
517#[cfg(feature = "production")]
518pub use precomputed_constants::*;
519
520/// Proven bounds for runtime optimization
521///
522/// These bounds are proven by formal verification and can be used
523/// for runtime optimizations without additional safety checks.
524///
525/// Proven runtime bounds for BLVM optimizations
526///
527/// These bounds have been formally proven and are used for runtime optimizations.
528/// Unlike proof-time limits (in `_helpers::proof_limits`), these represent actual
529/// Bitcoin limits that have been proven to hold in all cases.
530///
531/// Reference: BLVM Optimization Pass
532#[cfg(feature = "production")]
533pub mod proven_bounds {
534    use crate::constants::{MAX_INPUTS, MAX_OUTPUTS};
535
536    /// Maximum transaction size (proven by formal verification in transaction.rs)
537    pub const MAX_TX_SIZE_PROVEN: usize = 100000; // Bytes
538
539    /// Maximum block size (proven by formal verification in block.rs)
540    pub const MAX_BLOCK_SIZE_PROVEN: usize = 4000000; // Bytes (4MB)
541
542    /// Maximum inputs per transaction (proven by formal verification)
543    /// References actual Bitcoin limit from constants.rs
544    pub const MAX_INPUTS_PROVEN: usize = MAX_INPUTS;
545
546    /// Maximum outputs per transaction (proven by formal verification)
547    /// References actual Bitcoin limit from constants.rs
548    pub const MAX_OUTPUTS_PROVEN: usize = MAX_OUTPUTS;
549
550    /// Maximum transactions per block (proven by formal verification)
551    /// Note: Bitcoin limit is effectively unbounded by consensus rules, but practical limit
552    /// is around 10,000 transactions per block based on block size limits.
553    pub const MAX_TRANSACTIONS_PROVEN: usize = 10000;
554
555    /// Maximum previous headers for difficulty adjustment (proven by formal verification)
556    pub const MAX_PREV_HEADERS_PROVEN: usize = 5;
557}
558
559/// Optimized access using proven bounds
560///
561/// Uses bounds proven by formal verification to optimize runtime access.
562/// This is safe because formal proofs guarantee these bounds hold.
563///
564/// Reference: Formal proofs in transaction.rs, block.rs, mining.rs, pow.rs, etc.
565/// These proofs formally verify that certain bounds always hold, allowing us to
566/// use optimized access patterns without runtime bounds checks.
567#[cfg(feature = "production")]
568pub mod optimized_access {
569    use super::proven_bounds;
570
571    /// Get element with proven bounds check
572    ///
573    /// Uses proven maximum sizes to optimize bounds checking.
574    /// For transactions proven to have <= MAX_INPUTS_PROVEN inputs,
575    /// we can use optimized access patterns.
576    ///
577    /// # Safety
578    /// This function is safe because formal proofs guarantee bounds.
579    /// However, it still returns `Option` to handle cases where:
580    /// - Runtime bounds differ from proof bounds (should not happen in practice)
581    /// - Defensive programming (fail-safe)
582    ///
583    /// # Panics
584    /// Never panics - always returns `None` if out of bounds.
585    ///
586    /// # Examples
587    /// ```rust
588    /// use blvm_consensus::optimizations::optimized_access::get_proven;
589    /// use blvm_consensus::types::Transaction;
590    ///
591    /// # let tx = Transaction { version: 1, inputs: vec![].into(), outputs: vec![].into(), lock_time: 0 };
592    /// # let index = 0;
593    /// if let Some(input) = get_proven(&tx.inputs, index) {
594    ///     // Safe to use
595    /// }
596    /// ```
597    #[inline(always)]
598    pub fn get_proven<T>(slice: &[T], index: usize) -> Option<&T> {
599        // Formal proofs have proven index < MAX_SIZE in various proofs
600        // We can use unsafe access for proven-safe indices
601        // This is safe because formal proofs guarantee bounds
602        if index < slice.len() {
603            unsafe { Some(slice.get_unchecked(index)) }
604        } else {
605            None
606        }
607    }
608
609    /// Pre-allocate buffer using proven maximum size
610    ///
611    /// Uses proven maximum sizes to avoid reallocation.
612    /// For example, transaction buffers can be pre-sized to MAX_TX_SIZE_PROVEN.
613    #[inline(always)]
614    pub fn prealloc_proven<T>(max_size: usize) -> Vec<T> {
615        // Pre-allocate to proven maximum to avoid reallocation
616        Vec::with_capacity(max_size)
617    }
618
619    /// Pre-allocate transaction buffer using proven maximum
620    #[inline(always)]
621    pub fn prealloc_tx_buffer() -> Vec<u8> {
622        prealloc_proven::<u8>(proven_bounds::MAX_TX_SIZE_PROVEN)
623    }
624
625    /// Pre-allocate block buffer using proven maximum
626    #[inline(always)]
627    pub fn prealloc_block_buffer() -> Vec<u8> {
628        prealloc_proven::<u8>(proven_bounds::MAX_BLOCK_SIZE_PROVEN)
629    }
630
631    /// Get element with proven bounds (alias for get_proven for compatibility)
632    #[inline(always)]
633    pub fn get_proven_by_<T>(slice: &[T], index: usize) -> Option<&T> {
634        get_proven(slice, index)
635    }
636}
637
638/// Alias module for _optimized_access (for backward compatibility)
639#[cfg(feature = "production")]
640pub mod _optimized_access {
641    use super::optimized_access;
642
643    /// Get element with proven bounds
644    #[inline(always)]
645    pub fn get_proven_by_<T>(slice: &[T], index: usize) -> Option<&T> {
646        optimized_access::get_proven(slice, index)
647    }
648}
649
650/// Re-export prealloc helpers for convenience
651#[cfg(feature = "production")]
652pub use optimized_access::{prealloc_block_buffer, prealloc_tx_buffer};
653
654/// Reference implementations for equivalence proofs
655///
656/// These are safe versions of optimized functions, used to prove
657/// that optimizations are correct via formal verification.
658#[cfg(feature = "production")]
659pub mod reference_implementations {
660    /// Reference (safe) implementation of get_proven
661    /// This is the version we prove equivalence against
662    #[inline(always)]
663    pub fn get_proven_reference<T>(slice: &[T], index: usize) -> Option<&T> {
664        slice.get(index) // Safe version
665    }
666}
667
668/// Runtime assertions for optimization correctness
669///
670/// These functions provide runtime checks in debug builds to verify
671/// that optimizations match their reference implementations.
672#[cfg(all(
673    feature = "production",
674    any(debug_assertions, feature = "runtime-invariants")
675))]
676pub mod runtime_assertions {
677    use super::optimized_access::get_proven;
678    use super::reference_implementations::get_proven_reference;
679
680    /// Checked version of get_proven with runtime assertions
681    ///
682    /// This function performs runtime checks in debug builds to ensure
683    /// the optimized implementation matches the reference implementation.
684    #[inline(always)]
685    pub fn get_proven_checked<T>(slice: &[T], index: usize) -> Option<&T> {
686        let result_optimized = get_proven(slice, index);
687        let result_reference = get_proven_reference(slice, index);
688
689        // Runtime check: both must agree
690        debug_assert_eq!(
691            result_optimized.is_some(),
692            result_reference.is_some(),
693            "Optimization correctness check failed: optimized and reference disagree on Some/None"
694        );
695
696        if let (Some(opt_val), Some(ref_val)) = (result_optimized, result_reference) {
697            debug_assert_eq!(
698                opt_val as *const T, ref_val as *const T,
699                "Optimization correctness check failed: optimized and reference return different pointers"
700            );
701        }
702
703        result_optimized
704    }
705}