1	//! PCIe adapter-swap gate for bare-metal admission.
2	//!
3	//! Decision logic (whitepaper v2.5 §7.2 adapter_swap_ok):
4	//!   1. If adapter_id is in the resident cache  → no swap needed → ALLOW
5	//!   2. If adapter_id NOT in cache:
6	//!      a. Read upstream PCIe bandwidth from MMIO
7	//!      b. If bandwidth ≥ BW_THRESHOLD_MBS      → swap feasible  → ALLOW
8	//!      c. Otherwise                             → swap stalls bus → DENY
9	//!
10	//! Cache is a fixed-size ring of 16 u64 adapter IDs stored in BSS.
11	//! No heap, no alloc, no OS.
12
13	use crate::mmio;
14
15	/// Minimum upstream PCIe bandwidth (MB/s) required to permit an adapter swap.
16	/// Below this threshold the fabric is congested and the swap would stall.
17	const BW_THRESHOLD_MBS: u32 = 4096; // 4 GB/s
18
19	/// Number of adapter IDs the resident cache can hold simultaneously.
20	const CACHE_SIZE: usize = 16;
21
22	/// Sentinel meaning "slot is empty".
23	const EMPTY: u64 = 0;
24
25	/// Fixed-size adapter-ID cache (zero-initialized at boot).
26	///
27	/// Entries are 64-bit adapter IDs written by admit calls.
28	/// Eviction policy: first empty slot; if full, slot 0 is overwritten (FIFO).
29	///
30	/// # Safety
31	/// Single-threaded bare-metal — no concurrent mutation possible.
32	static mut ADAPTER_CACHE: [u64; CACHE_SIZE] = [EMPTY; CACHE_SIZE];
33
34	/// Returns true if `id` is currently in the adapter cache.
35	fn cache_contains(id: u64) -> bool {
36	    // SAFETY: single-threaded bare-metal; read-only scan via raw pointer.
37	    unsafe {
38	        let base = core::ptr::addr_of!(ADAPTER_CACHE) as *const u64;
39	        for i in 0..CACHE_SIZE {
40	            if core::ptr::read_volatile(base.add(i)) == id {
41	                return true;
42	            }
43	        }
44	        false
45	    }
46	}
47
48	/// Insert `id` into the cache.  Fills the first empty slot;
49	/// if no empty slot, overwrites slot 0 (simple FIFO eviction).
50	fn cache_insert(id: u64) {
51	    // SAFETY: single-threaded bare-metal; mutations via raw pointer.
52	    unsafe {
53	        let base = core::ptr::addr_of_mut!(ADAPTER_CACHE) as *mut u64;
54	        for i in 0..CACHE_SIZE {
55	            if core::ptr::read_volatile(base.add(i)) == EMPTY {
56	                core::ptr::write_volatile(base.add(i), id);
57	                return;
58	            }
59	        }
60	        // Cache full — evict slot 0
61	        core::ptr::write_volatile(base, id);
62	    }
63	}
64
65	/// Check whether the adapter identified by `adapter_id` can be swapped in.
66	///
67	/// Returns `true`  (ALLOW) when:
68	///   - The adapter is already resident in the gate cache, OR
69	///   - Upstream PCIe bandwidth is ≥ BW_THRESHOLD_MBS (4 GB/s).
70	///
71	/// Returns `false` (DENY) when the adapter is not cached and the PCIe
72	/// fabric is congested.
73	///
74	/// Side effect: on ALLOW from a cache-miss path, `adapter_id` is added
75	/// to the cache so subsequent requests are served without MMIO reads.
76	///
77	/// # Safety
78	/// Reads from PCIe bandwidth MMIO register (see mmio.rs).
79	pub fn adapter_swap_ok(adapter_id: u64) -> bool {
80	    if adapter_id == EMPTY {
81	        // Sentinel value 0 is reserved — treat as unknown/deny.
82	        return false;
83	    }
84
85	    if cache_contains(adapter_id) {
86	        return true;
87	    }
88
89	    // Cache miss: consult PCIe bandwidth register.
90	    // SAFETY: PCIe MMIO region assumed mapped by firmware before calling.
91	    let bw = unsafe { mmio::read_pcie_bw_mbs() };
92	    if bw >= BW_THRESHOLD_MBS {
93	        cache_insert(adapter_id);
94	        true
95	    } else {
96	        false
97	    }
98	}
99
100	/// Reset the adapter cache to empty.
101	/// Only available under the `mock` feature — used by tests to prevent
102	/// cache state from leaking between test cases.
103	#[cfg(feature = "mock")]
104	pub fn clear_adapter_cache() {
105	    unsafe {
106	        let base = core::ptr::addr_of_mut!(ADAPTER_CACHE) as *mut u64;
107	        for i in 0..CACHE_SIZE {
108	            core::ptr::write_volatile(base.add(i), EMPTY);
109	        }
110	    }
111	}
112

//! PCIe adapter-swap gate for bare-metal admission.
//!
//! Decision logic (whitepaper v2.5 §7.2 adapter_swap_ok):
//!   1. If adapter_id is in the resident cache  → no swap needed → ALLOW
//!   2. If adapter_id NOT in cache:
//!      a. Read upstream PCIe bandwidth from MMIO
//!      b. If bandwidth ≥ BW_THRESHOLD_MBS      → swap feasible  → ALLOW
//!      c. Otherwise                             → swap stalls bus → DENY
//!
//! Cache is a fixed-size ring of 16 u64 adapter IDs stored in BSS.
//! No heap, no alloc, no OS.

use crate::mmio;

/// Minimum upstream PCIe bandwidth (MB/s) required to permit an adapter swap.
/// Below this threshold the fabric is congested and the swap would stall.
const BW_THRESHOLD_MBS: u32 = 4096; // 4 GB/s

/// Number of adapter IDs the resident cache can hold simultaneously.
const CACHE_SIZE: usize = 16;

/// Sentinel meaning "slot is empty".
const EMPTY: u64 = 0;

/// Fixed-size adapter-ID cache (zero-initialized at boot).
///
/// Entries are 64-bit adapter IDs written by admit calls.
/// Eviction policy: first empty slot; if full, slot 0 is overwritten (FIFO).
///
/// # Safety
/// Single-threaded bare-metal — no concurrent mutation possible.
static mut ADAPTER_CACHE: [u64; CACHE_SIZE] = [EMPTY; CACHE_SIZE];

/// Returns true if `id` is currently in the adapter cache.
fn cache_contains(id: u64) -> bool {
    // SAFETY: single-threaded bare-metal; read-only scan via raw pointer.
    unsafe {
        let base = core::ptr::addr_of!(ADAPTER_CACHE) as *const u64;
        for i in 0..CACHE_SIZE {
            if core::ptr::read_volatile(base.add(i)) == id {
                return true;
            }
        }
        false
    }
}

/// Insert `id` into the cache.  Fills the first empty slot;
/// if no empty slot, overwrites slot 0 (simple FIFO eviction).
fn cache_insert(id: u64) {
    // SAFETY: single-threaded bare-metal; mutations via raw pointer.
    unsafe {
        let base = core::ptr::addr_of_mut!(ADAPTER_CACHE) as *mut u64;
        for i in 0..CACHE_SIZE {
            if core::ptr::read_volatile(base.add(i)) == EMPTY {
                core::ptr::write_volatile(base.add(i), id);
                return;
            }
        }
        // Cache full — evict slot 0
        core::ptr::write_volatile(base, id);
    }
}

/// Check whether the adapter identified by `adapter_id` can be swapped in.
///
/// Returns `true`  (ALLOW) when:
///   - The adapter is already resident in the gate cache, OR
///   - Upstream PCIe bandwidth is ≥ BW_THRESHOLD_MBS (4 GB/s).
///
/// Returns `false` (DENY) when the adapter is not cached and the PCIe
/// fabric is congested.
///
/// Side effect: on ALLOW from a cache-miss path, `adapter_id` is added
/// to the cache so subsequent requests are served without MMIO reads.
///
/// # Safety
/// Reads from PCIe bandwidth MMIO register (see mmio.rs).
pub fn adapter_swap_ok(adapter_id: u64) -> bool {
    if adapter_id == EMPTY {
        // Sentinel value 0 is reserved — treat as unknown/deny.
        return false;
    }

    if cache_contains(adapter_id) {
        return true;
    }

    // Cache miss: consult PCIe bandwidth register.
    // SAFETY: PCIe MMIO region assumed mapped by firmware before calling.
    let bw = unsafe { mmio::read_pcie_bw_mbs() };
    if bw >= BW_THRESHOLD_MBS {
        cache_insert(adapter_id);
        true
    } else {
        false
    }
}

/// Reset the adapter cache to empty.
/// Only available under the `mock` feature — used by tests to prevent
/// cache state from leaking between test cases.
#[cfg(feature = "mock")]
pub fn clear_adapter_cache() {
    unsafe {
        let base = core::ptr::addr_of_mut!(ADAPTER_CACHE) as *mut u64;
        for i in 0..CACHE_SIZE {
            core::ptr::write_volatile(base.add(i), EMPTY);
        }
    }
}


1	//! Memory-mapped I/O primitives for bare-metal hardware reads.
2	//!
3	//! In production (`not(feature = "mock")`):
4	//!   All reads use `core::ptr::read_volatile` on platform MMIO addresses.
5	//!   Addresses are SiFive HiFive-Unleashed-style defaults — override in
6	//!   a platform linker script or by editing the constants below.
7	//!
8	//! In test mode (`feature = "mock"`):
9	//!   All reads return values from in-memory AtomicU32 cells.
10	//!   Tests call the `mock_set_*` helpers to configure expected hardware state
11	//!   before calling `cubie_admit`.  No unsafe MMIO access occurs.
12
13	// ---------------------------------------------------------------------------
14	// Platform register addresses (production only)
15	// ---------------------------------------------------------------------------
16
17	/// eFuse base: 8 slots × 0x40 stride, each slot holds 8 × u32 = 32 bytes.
18	pub const EFUSE_BASE:         usize = 0x1000_0000;
19	pub const EFUSE_SLOT_STRIDE:  usize = 0x40;
20
21	/// NVLink telemetry base: 8 peers × 0x100 stride.
22	///   +0x00  SM_ACTIVITY  (u32, warp count — 0 = idle)
23	///   +0x04  VRAM_ALLOC   (u32, MiB — non-zero = memory pinned)
24	pub const NVLINK_BASE:              usize = 0xFF00_0000;
25	pub const NVLINK_PEER_STRIDE:       usize = 0x100;
26	pub const NVLINK_SM_ACTIVITY_OFF:   usize = 0x00;
27	pub const NVLINK_VRAM_ALLOC_OFF:    usize = 0x04;
28
29	/// PCIe upstream bandwidth register: MB/s available.
30	pub const PCIE_BASE:          usize = 0xFF10_0000;
31	pub const PCIE_BW_AVAIL_OFF:  usize = 0x00;
32
33	// ---------------------------------------------------------------------------
34	// Mock register bank (test builds only)
35	// ---------------------------------------------------------------------------
36
37	#[cfg(feature = "mock")]
38	use core::sync::atomic::{AtomicU32, Ordering::Relaxed};
39
40	/// 8 slots × 8 words = 64 u32 cells for eFuse key storage.
41	#[cfg(feature = "mock")]
42	pub static MOCK_EFUSE: [AtomicU32; 64] = {
43	    const ZERO: AtomicU32 = AtomicU32::new(0);
44	    [ZERO; 64]
45	};
46
47	/// NVLink SM activity counter per peer (8 peers).
48	#[cfg(feature = "mock")]
49	pub static MOCK_NVLINK_SM: [AtomicU32; 8] = {
50	    const ONE: AtomicU32 = AtomicU32::new(1); // default: SM active (safe)
51	    [ONE; 8]
52	};
53
54	/// NVLink allocated VRAM per peer (MiB, 8 peers).
55	#[cfg(feature = "mock")]
56	pub static MOCK_NVLINK_VRAM: [AtomicU32; 8] = {
57	    const ZERO: AtomicU32 = AtomicU32::new(0); // default: no VRAM held
58	    [ZERO; 8]
59	};
60
61	/// PCIe upstream bandwidth in MB/s.
62	#[cfg(feature = "mock")]
63	pub static MOCK_PCIE_BW: AtomicU32 = AtomicU32::new(8192); // default: 8 GB/s
64
65	// ---------------------------------------------------------------------------
66	// Mock setter helpers — call these in tests before cubie_admit
67	// ---------------------------------------------------------------------------
68
69	/// Set one 32-bit word of eFuse slot `slot` (0-7), word index `word` (0-7).
70	#[cfg(feature = "mock")]
71	pub fn mock_set_efuse_word(slot: u8, word: u8, value: u32) {
72	    let idx = (slot as usize) * 8 + (word as usize);
73	    MOCK_EFUSE[idx].store(value, Relaxed);
74	}
75
76	/// Set the full 32-byte eFuse key for slot `slot` from a byte array.
77	#[cfg(feature = "mock")]
78	pub fn mock_set_efuse_key(slot: u8, key: &[u8; 32]) {
79	    for (i, chunk) in key.chunks(4).enumerate() {
80	        let word = u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
81	        mock_set_efuse_word(slot, i as u8, word);
82	    }
83	}
84
85	/// Set the SM activity counter for NVLink peer `peer`.
86	#[cfg(feature = "mock")]
87	pub fn mock_set_nvlink_sm(peer: u8, value: u32) {
88	    MOCK_NVLINK_SM[peer as usize].store(value, Relaxed);
89	}
90
91	/// Set the allocated VRAM (MiB) for NVLink peer `peer`.
92	#[cfg(feature = "mock")]
93	pub fn mock_set_nvlink_vram(peer: u8, value: u32) {
94	    MOCK_NVLINK_VRAM[peer as usize].store(value, Relaxed);
95	}
96
97	/// Set the available PCIe upstream bandwidth (MB/s).
98	#[cfg(feature = "mock")]
99	pub fn mock_set_pcie_bw(value: u32) {
100	    MOCK_PCIE_BW.store(value, Relaxed);
101	}
102
103	// ---------------------------------------------------------------------------
104	// Core volatile-read primitive (production)
105	// ---------------------------------------------------------------------------
106
107	/// Read a u32 from a memory-mapped register.
108	///
109	/// # Safety
110	/// `addr` must map to a valid, aligned MMIO register on this platform.
111	#[inline(always)]
112	#[cfg(not(feature = "mock"))]
113	pub unsafe fn read_mmio_u32(addr: usize) -> u32 {
114	    core::ptr::read_volatile(addr as *const u32)
115	}
116
117	// ---------------------------------------------------------------------------
118	// eFuse key reader
119	// ---------------------------------------------------------------------------
120
121	/// Read the 32-byte symmetric key stored in eFuse slot `slot` (0-7).
122	///
123	/// Production: volatile read from MMIO eFuse registers.
124	/// Mock: reads from MOCK_EFUSE atomic cells.
125	pub unsafe fn read_efuse_key(slot: u8) -> [u8; 32] {
126	    let mut key = [0u8; 32];
127
128	    #[cfg(feature = "mock")]
129	    {
130	        let _ = slot; // suppress unused warning only in mock path below
131	        for word_idx in 0..8usize {
132	            let cell_idx = (slot as usize) * 8 + word_idx;
133	            let word = MOCK_EFUSE[cell_idx].load(Relaxed);
134	            key[word_idx * 4..word_idx * 4 + 4].copy_from_slice(&word.to_be_bytes());
135	        }
136	    }
137
138	    #[cfg(not(feature = "mock"))]
139	    {
140	        let base = EFUSE_BASE + (slot as usize) * EFUSE_SLOT_STRIDE;
141	        for word_idx in 0..8usize {
142	            let addr = base + word_idx * 4;
143	            let word = read_mmio_u32(addr);
144	            key[word_idx * 4..word_idx * 4 + 4].copy_from_slice(&word.to_be_bytes());
145	        }
146	    }
147
148	    key
149	}
150
151	// ---------------------------------------------------------------------------
152	// NVLink telemetry readers
153	// ---------------------------------------------------------------------------
154
155	/// Read the SM activity counter for NVLink peer `peer_id`.
156	pub unsafe fn read_nvlink_sm_activity(peer_id: u8) -> u32 {
157	    #[cfg(feature = "mock")]
158	    { return MOCK_NVLINK_SM[peer_id as usize].load(Relaxed); }
159
160	    #[cfg(not(feature = "mock"))]
161	    {
162	        let addr = NVLINK_BASE
163	            + (peer_id as usize) * NVLINK_PEER_STRIDE
164	            + NVLINK_SM_ACTIVITY_OFF;
165	        read_mmio_u32(addr)
166	    }
167	}
168
169	/// Read the allocated VRAM (MiB) for NVLink peer `peer_id`.
170	pub unsafe fn read_nvlink_vram_alloc(peer_id: u8) -> u32 {
171	    #[cfg(feature = "mock")]
172	    { return MOCK_NVLINK_VRAM[peer_id as usize].load(Relaxed); }
173
174	    #[cfg(not(feature = "mock"))]
175	    {
176	        let addr = NVLINK_BASE
177	            + (peer_id as usize) * NVLINK_PEER_STRIDE
178	            + NVLINK_VRAM_ALLOC_OFF;
179	        read_mmio_u32(addr)
180	    }
181	}
182
183	// ---------------------------------------------------------------------------
184	// PCIe bandwidth reader
185	// ---------------------------------------------------------------------------
186
187	/// Read available upstream PCIe bandwidth in MB/s.
188	pub unsafe fn read_pcie_bw_mbs() -> u32 {
189	    #[cfg(feature = "mock")]
190	    { return MOCK_PCIE_BW.load(Relaxed); }
191
192	    #[cfg(not(feature = "mock"))]
193	    { read_mmio_u32(PCIE_BASE + PCIE_BW_AVAIL_OFF) }
194	}
195

//! Memory-mapped I/O primitives for bare-metal hardware reads.
//!
//! In production (`not(feature = "mock")`):
//!   All reads use `core::ptr::read_volatile` on platform MMIO addresses.
//!   Addresses are SiFive HiFive-Unleashed-style defaults — override in
//!   a platform linker script or by editing the constants below.
//!
//! In test mode (`feature = "mock"`):
//!   All reads return values from in-memory AtomicU32 cells.
//!   Tests call the `mock_set_*` helpers to configure expected hardware state
//!   before calling `cubie_admit`.  No unsafe MMIO access occurs.

// ---------------------------------------------------------------------------
// Platform register addresses (production only)
// ---------------------------------------------------------------------------

/// eFuse base: 8 slots × 0x40 stride, each slot holds 8 × u32 = 32 bytes.
pub const EFUSE_BASE:         usize = 0x1000_0000;
pub const EFUSE_SLOT_STRIDE:  usize = 0x40;

/// NVLink telemetry base: 8 peers × 0x100 stride.
///   +0x00  SM_ACTIVITY  (u32, warp count — 0 = idle)
///   +0x04  VRAM_ALLOC   (u32, MiB — non-zero = memory pinned)
pub const NVLINK_BASE:              usize = 0xFF00_0000;
pub const NVLINK_PEER_STRIDE:       usize = 0x100;
pub const NVLINK_SM_ACTIVITY_OFF:   usize = 0x00;
pub const NVLINK_VRAM_ALLOC_OFF:    usize = 0x04;

/// PCIe upstream bandwidth register: MB/s available.
pub const PCIE_BASE:          usize = 0xFF10_0000;
pub const PCIE_BW_AVAIL_OFF:  usize = 0x00;

// ---------------------------------------------------------------------------
// Mock register bank (test builds only)
// ---------------------------------------------------------------------------

#[cfg(feature = "mock")]
use core::sync::atomic::{AtomicU32, Ordering::Relaxed};

/// 8 slots × 8 words = 64 u32 cells for eFuse key storage.
#[cfg(feature = "mock")]
pub static MOCK_EFUSE: [AtomicU32; 64] = {
    const ZERO: AtomicU32 = AtomicU32::new(0);
    [ZERO; 64]
};

/// NVLink SM activity counter per peer (8 peers).
#[cfg(feature = "mock")]
pub static MOCK_NVLINK_SM: [AtomicU32; 8] = {
    const ONE: AtomicU32 = AtomicU32::new(1); // default: SM active (safe)
    [ONE; 8]
};

/// NVLink allocated VRAM per peer (MiB, 8 peers).
#[cfg(feature = "mock")]
pub static MOCK_NVLINK_VRAM: [AtomicU32; 8] = {
    const ZERO: AtomicU32 = AtomicU32::new(0); // default: no VRAM held
    [ZERO; 8]
};

/// PCIe upstream bandwidth in MB/s.
#[cfg(feature = "mock")]
pub static MOCK_PCIE_BW: AtomicU32 = AtomicU32::new(8192); // default: 8 GB/s

// ---------------------------------------------------------------------------
// Mock setter helpers — call these in tests before cubie_admit
// ---------------------------------------------------------------------------

/// Set one 32-bit word of eFuse slot `slot` (0-7), word index `word` (0-7).
#[cfg(feature = "mock")]
pub fn mock_set_efuse_word(slot: u8, word: u8, value: u32) {
    let idx = (slot as usize) * 8 + (word as usize);
    MOCK_EFUSE[idx].store(value, Relaxed);
}

/// Set the full 32-byte eFuse key for slot `slot` from a byte array.
#[cfg(feature = "mock")]
pub fn mock_set_efuse_key(slot: u8, key: &[u8; 32]) {
    for (i, chunk) in key.chunks(4).enumerate() {
        let word = u32::from_be_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]);
        mock_set_efuse_word(slot, i as u8, word);
    }
}

/// Set the SM activity counter for NVLink peer `peer`.
#[cfg(feature = "mock")]
pub fn mock_set_nvlink_sm(peer: u8, value: u32) {
    MOCK_NVLINK_SM[peer as usize].store(value, Relaxed);
}

/// Set the allocated VRAM (MiB) for NVLink peer `peer`.
#[cfg(feature = "mock")]
pub fn mock_set_nvlink_vram(peer: u8, value: u32) {
    MOCK_NVLINK_VRAM[peer as usize].store(value, Relaxed);
}

/// Set the available PCIe upstream bandwidth (MB/s).
#[cfg(feature = "mock")]
pub fn mock_set_pcie_bw(value: u32) {
    MOCK_PCIE_BW.store(value, Relaxed);
}

// ---------------------------------------------------------------------------
// Core volatile-read primitive (production)
// ---------------------------------------------------------------------------

/// Read a u32 from a memory-mapped register.
///
/// # Safety
/// `addr` must map to a valid, aligned MMIO register on this platform.
#[inline(always)]
#[cfg(not(feature = "mock"))]
pub unsafe fn read_mmio_u32(addr: usize) -> u32 {
    core::ptr::read_volatile(addr as *const u32)
}

// ---------------------------------------------------------------------------
// eFuse key reader
// ---------------------------------------------------------------------------

/// Read the 32-byte symmetric key stored in eFuse slot `slot` (0-7).
///
/// Production: volatile read from MMIO eFuse registers.
/// Mock: reads from MOCK_EFUSE atomic cells.
pub unsafe fn read_efuse_key(slot: u8) -> [u8; 32] {
    let mut key = [0u8; 32];

    #[cfg(feature = "mock")]
    {
        let _ = slot; // suppress unused warning only in mock path below
        for word_idx in 0..8usize {
            let cell_idx = (slot as usize) * 8 + word_idx;
            let word = MOCK_EFUSE[cell_idx].load(Relaxed);
            key[word_idx * 4..word_idx * 4 + 4].copy_from_slice(&word.to_be_bytes());
        }
    }

    #[cfg(not(feature = "mock"))]
    {
        let base = EFUSE_BASE + (slot as usize) * EFUSE_SLOT_STRIDE;
        for word_idx in 0..8usize {
            let addr = base + word_idx * 4;
            let word = read_mmio_u32(addr);
            key[word_idx * 4..word_idx * 4 + 4].copy_from_slice(&word.to_be_bytes());
        }
    }

    key
}

// ---------------------------------------------------------------------------
// NVLink telemetry readers
// ---------------------------------------------------------------------------

/// Read the SM activity counter for NVLink peer `peer_id`.
pub unsafe fn read_nvlink_sm_activity(peer_id: u8) -> u32 {
    #[cfg(feature = "mock")]
    { return MOCK_NVLINK_SM[peer_id as usize].load(Relaxed); }

    #[cfg(not(feature = "mock"))]
    {
        let addr = NVLINK_BASE
            + (peer_id as usize) * NVLINK_PEER_STRIDE
            + NVLINK_SM_ACTIVITY_OFF;
        read_mmio_u32(addr)
    }
}

/// Read the allocated VRAM (MiB) for NVLink peer `peer_id`.
pub unsafe fn read_nvlink_vram_alloc(peer_id: u8) -> u32 {
    #[cfg(feature = "mock")]
    { return MOCK_NVLINK_VRAM[peer_id as usize].load(Relaxed); }

    #[cfg(not(feature = "mock"))]
    {
        let addr = NVLINK_BASE
            + (peer_id as usize) * NVLINK_PEER_STRIDE
            + NVLINK_VRAM_ALLOC_OFF;
        read_mmio_u32(addr)
    }
}

// ---------------------------------------------------------------------------
// PCIe bandwidth reader
// ---------------------------------------------------------------------------

/// Read available upstream PCIe bandwidth in MB/s.
pub unsafe fn read_pcie_bw_mbs() -> u32 {
    #[cfg(feature = "mock")]
    { return MOCK_PCIE_BW.load(Relaxed); }

    #[cfg(not(feature = "mock"))]
    { read_mmio_u32(PCIE_BASE + PCIE_BW_AVAIL_OFF) }
}


1	//! Integration tests for cubie_admit — runs on host with mock MMIO.
2	#![allow(unused_unsafe)] // cubie_admit is unsafe on real hardware; mock is safe
3	//!
4	//! Test matrix:
5	//!   ✓ Full allow path (all conditions pass)
6	//!   ✗ Null pointer
7	//!   ✗ Each GPU corner flag false (who/what/how)
8	//!   ✗ Each deployment corner flag false (where/when/why)
9	//!   ✗ has_valid_lease = false
10	//!   ✗ epoch_fresh = false
11	//!   ✗ HMAC mismatch (wrong capability_hmac)
12	//!   ✗ HMAC wrong key slot
13	//!   ✗ NVLink waiter detected (SM=0 + VRAM>0)
14	//!   ✗ PCIe congested (BW below threshold)
15	//!   ✓ PCIe adapter cache hit (fast path)
16	//!   ✓ NVLink safe when SM>0 (active peer)
17	//!   ✓ NVLink safe when VRAM=0 (no memory held)
18
19	use cubie_bare_metal::{
20	    cubie_admit, hmac_sha256, AdmitResult, CubieRequest,
21	    mmio, pcie,
22	};
23	use std::ptr;
24
25	// ---------------------------------------------------------------------------
26	// Test fixture helpers
27	// ---------------------------------------------------------------------------
28
29	const TEST_KEY: [u8; 32] = [0x42u8; 32];
30	const TEST_REQUEST_HASH: u64 = 0xDEAD_BEEF_CAFE_0001;
31	const TEST_ADAPTER_ID: u64 = 0x1234_5678_9ABC_DEF0;
32
33	fn compute_hmac(request_hash: u64) -> u64 {
34	    let mac = hmac_sha256(&TEST_KEY, &request_hash.to_be_bytes());
35	    u64::from_be_bytes(mac[0..8].try_into().unwrap())
36	}
37
38	/// Reset all mock state and return a fully-passing CubieRequest.
39	fn valid_request() -> CubieRequest {
40	    // Clear PCIe cache so each test starts clean
41	    pcie::clear_adapter_cache();
42
43	    // Set eFuse key for slot 0
44	    mmio::mock_set_efuse_key(0, &TEST_KEY);
45
46	    // NVLink peer 0: SM active (non-zero), no VRAM held
47	    mmio::mock_set_nvlink_sm(0, 100);
48	    mmio::mock_set_nvlink_vram(0, 0);
49
50	    // PCIe: high bandwidth
51	    mmio::mock_set_pcie_bw(8192);
52
53	    CubieRequest {
54	        who_pass: true, what_pass: true, how_pass: true,
55	        where_pass: true, when_pass: true, why_pass: true,
56	        has_valid_lease: true,
57	        epoch_fresh: true,
58	        request_hash:    TEST_REQUEST_HASH,
59	        capability_hmac: compute_hmac(TEST_REQUEST_HASH),
60	        key_slot:  0,
61	        peer_id:   0,
62	        adapter_id: TEST_ADAPTER_ID,
63	    }
64	}
65
66	fn is_allow(r: AdmitResult) -> bool {
67	    matches!(r, AdmitResult::Allow)
68	}
69
70	fn is_deny(r: AdmitResult) -> bool {
71	    matches!(r, AdmitResult::Deny)
72	}
73
74	// ---------------------------------------------------------------------------
75	// Happy path
76	// ---------------------------------------------------------------------------
77
78	#[test]
79	fn allow_all_conditions_pass() {
80	    let req = valid_request();
81	    assert!(is_allow(unsafe { cubie_admit(&req) }));
82	}
83
84	// ---------------------------------------------------------------------------
85	// Null pointer
86	// ---------------------------------------------------------------------------
87
88	#[test]
89	fn deny_null_pointer() {
90	    assert!(is_deny(unsafe { cubie_admit(ptr::null()) }));
91	}
92
93	// ---------------------------------------------------------------------------
94	// GPU corner: one flag false at a time
95	// ---------------------------------------------------------------------------
96
97	#[test]
98	fn deny_who_false() {
99	    let mut req = valid_request();
100	    req.who_pass = false;
101	    assert!(is_deny(unsafe { cubie_admit(&req) }));
102	}
103
104	#[test]
105	fn deny_what_false() {
106	    let mut req = valid_request();
107	    req.what_pass = false;
108	    assert!(is_deny(unsafe { cubie_admit(&req) }));
109	}
110
111	#[test]
112	fn deny_how_false() {
113	    let mut req = valid_request();
114	    req.how_pass = false;
115	    assert!(is_deny(unsafe { cubie_admit(&req) }));
116	}
117
118	// ---------------------------------------------------------------------------
119	// Deployment corner: one flag false at a time
120	// ---------------------------------------------------------------------------
121
122	#[test]
123	fn deny_where_false() {
124	    let mut req = valid_request();
125	    req.where_pass = false;
126	    assert!(is_deny(unsafe { cubie_admit(&req) }));
127	}
128
129	#[test]
130	fn deny_when_false() {
131	    let mut req = valid_request();
132	    req.when_pass = false;
133	    assert!(is_deny(unsafe { cubie_admit(&req) }));
134	}
135
136	#[test]
137	fn deny_why_false() {
138	    let mut req = valid_request();
139	    req.why_pass = false;
140	    assert!(is_deny(unsafe { cubie_admit(&req) }));
141	}
142
143	// ---------------------------------------------------------------------------
144	// Lease and epoch
145	// ---------------------------------------------------------------------------
146
147	#[test]
148	fn deny_lease_invalid() {
149	    let mut req = valid_request();
150	    req.has_valid_lease = false;
151	    assert!(is_deny(unsafe { cubie_admit(&req) }));
152	}
153
154	#[test]
155	fn deny_epoch_stale() {
156	    let mut req = valid_request();
157	    req.epoch_fresh = false;
158	    assert!(is_deny(unsafe { cubie_admit(&req) }));
159	}
160
161	// ---------------------------------------------------------------------------
162	// HMAC checks
163	// ---------------------------------------------------------------------------
164
165	#[test]
166	fn deny_hmac_mismatch() {
167	    let mut req = valid_request();
168	    req.capability_hmac = req.capability_hmac.wrapping_add(1); // corrupt
169	    assert!(is_deny(unsafe { cubie_admit(&req) }));
170	}
171
172	#[test]
173	fn deny_hmac_wrong_key_slot() {
174	    // Slot 1 key is all-zeros (never set) — HMAC will not match slot 0 MAC
175	    let mut req = valid_request();
176	    req.key_slot = 1;
177	    assert!(is_deny(unsafe { cubie_admit(&req) }));
178	}
179
180	#[test]
181	fn deny_hmac_wrong_request_hash() {
182	    let mut req = valid_request();
183	    // capability_hmac was computed for TEST_REQUEST_HASH, now hash is different
184	    req.request_hash = TEST_REQUEST_HASH.wrapping_add(1);
185	    assert!(is_deny(unsafe { cubie_admit(&req) }));
186	}
187
188	#[test]
189	fn allow_hmac_exact_match() {
190	    // Recompute with a different hash to confirm the crypto path works end-to-end
191	    let hash = 0xFEED_FACE_DEAD_BEEF_u64;
192	    let mut req = valid_request();
193	    req.request_hash    = hash;
194	    req.capability_hmac = compute_hmac(hash);
195	    assert!(is_allow(unsafe { cubie_admit(&req) }));
196	}
197
198	// ---------------------------------------------------------------------------
199	// NVLink waiter detection
200	// ---------------------------------------------------------------------------
201
202	#[test]
203	fn deny_nvlink_waiter_sm_zero_vram_held() {
204	    let mut req = valid_request();
205	    mmio::mock_set_nvlink_sm(0, 0);   // SM idle
206	    mmio::mock_set_nvlink_vram(0, 512); // 512 MiB held — waiter signature
207	    assert!(is_deny(unsafe { cubie_admit(&req) }));
208	}
209
210	#[test]
211	fn allow_nvlink_sm_active_vram_held() {
212	    // SM active + VRAM held = legitimate compute, not a waiter
213	    let req = valid_request();
214	    mmio::mock_set_nvlink_sm(0, 50);
215	    mmio::mock_set_nvlink_vram(0, 512);
216	    assert!(is_allow(unsafe { cubie_admit(&req) }));
217	}
218
219	#[test]
220	fn allow_nvlink_sm_zero_no_vram() {
221	    // SM idle + no VRAM = peer is genuinely idle, not holding anything
222	    let req = valid_request();
223	    mmio::mock_set_nvlink_sm(0, 0);
224	    mmio::mock_set_nvlink_vram(0, 0);
225	    assert!(is_allow(unsafe { cubie_admit(&req) }));
226	}
227
228	// ---------------------------------------------------------------------------
229	// PCIe adapter cache and bandwidth
230	// ---------------------------------------------------------------------------
231
232	#[test]
233	fn deny_pcie_congested_cache_miss() {
234	    pcie::clear_adapter_cache();
235	    let req = valid_request();
236	    mmio::mock_set_pcie_bw(1024); // 1 GB/s — below 4 GB/s threshold
237	    assert!(is_deny(unsafe { cubie_admit(&req) }));
238	}
239
240	#[test]
241	fn allow_pcie_good_bandwidth() {
242	    pcie::clear_adapter_cache();
243	    let req = valid_request();
244	    mmio::mock_set_pcie_bw(4096); // exactly at threshold — allowed
245	    assert!(is_allow(unsafe { cubie_admit(&req) }));
246	}
247
248	#[test]
249	fn allow_pcie_cache_hit_bypasses_bw_check() {
250	    pcie::clear_adapter_cache();
251	    let req = valid_request();
252	    // First call: BW good → adapter gets cached
253	    mmio::mock_set_pcie_bw(8192);
254	    assert!(is_allow(unsafe { cubie_admit(&req) }));
255	    // Second call: BW now bad, but adapter is cached → still allowed
256	    mmio::mock_set_pcie_bw(100);
257	    assert!(is_allow(unsafe { cubie_admit(&req) }));
258	}
259
260	#[test]
261	fn deny_zero_adapter_id_sentinel() {
262	    let mut req = valid_request();
263	    req.adapter_id = 0; // sentinel EMPTY value
264	    assert!(is_deny(unsafe { cubie_admit(&req) }));
265	}
266

//! Integration tests for cubie_admit — runs on host with mock MMIO.
#![allow(unused_unsafe)] // cubie_admit is unsafe on real hardware; mock is safe
//!
//! Test matrix:
//!   ✓ Full allow path (all conditions pass)
//!   ✗ Null pointer
//!   ✗ Each GPU corner flag false (who/what/how)
//!   ✗ Each deployment corner flag false (where/when/why)
//!   ✗ has_valid_lease = false
//!   ✗ epoch_fresh = false
//!   ✗ HMAC mismatch (wrong capability_hmac)
//!   ✗ HMAC wrong key slot
//!   ✗ NVLink waiter detected (SM=0 + VRAM>0)
//!   ✗ PCIe congested (BW below threshold)
//!   ✓ PCIe adapter cache hit (fast path)
//!   ✓ NVLink safe when SM>0 (active peer)
//!   ✓ NVLink safe when VRAM=0 (no memory held)

use cubie_bare_metal::{
    cubie_admit, hmac_sha256, AdmitResult, CubieRequest,
    mmio, pcie,
};
use std::ptr;

// ---------------------------------------------------------------------------
// Test fixture helpers
// ---------------------------------------------------------------------------

const TEST_KEY: [u8; 32] = [0x42u8; 32];
const TEST_REQUEST_HASH: u64 = 0xDEAD_BEEF_CAFE_0001;
const TEST_ADAPTER_ID: u64 = 0x1234_5678_9ABC_DEF0;

fn compute_hmac(request_hash: u64) -> u64 {
    let mac = hmac_sha256(&TEST_KEY, &request_hash.to_be_bytes());
    u64::from_be_bytes(mac[0..8].try_into().unwrap())
}

/// Reset all mock state and return a fully-passing CubieRequest.
fn valid_request() -> CubieRequest {
    // Clear PCIe cache so each test starts clean
    pcie::clear_adapter_cache();

    // Set eFuse key for slot 0
    mmio::mock_set_efuse_key(0, &TEST_KEY);

    // NVLink peer 0: SM active (non-zero), no VRAM held
    mmio::mock_set_nvlink_sm(0, 100);
    mmio::mock_set_nvlink_vram(0, 0);

    // PCIe: high bandwidth
    mmio::mock_set_pcie_bw(8192);

    CubieRequest {
        who_pass: true, what_pass: true, how_pass: true,
        where_pass: true, when_pass: true, why_pass: true,
        has_valid_lease: true,
        epoch_fresh: true,
        request_hash:    TEST_REQUEST_HASH,
        capability_hmac: compute_hmac(TEST_REQUEST_HASH),
        key_slot:  0,
        peer_id:   0,
        adapter_id: TEST_ADAPTER_ID,
    }
}

fn is_allow(r: AdmitResult) -> bool {
    matches!(r, AdmitResult::Allow)
}

fn is_deny(r: AdmitResult) -> bool {
    matches!(r, AdmitResult::Deny)
}

// ---------------------------------------------------------------------------
// Happy path
// ---------------------------------------------------------------------------

#[test]
fn allow_all_conditions_pass() {
    let req = valid_request();
    assert!(is_allow(unsafe { cubie_admit(&req) }));
}

// ---------------------------------------------------------------------------
// Null pointer
// ---------------------------------------------------------------------------

#[test]
fn deny_null_pointer() {
    assert!(is_deny(unsafe { cubie_admit(ptr::null()) }));
}

// ---------------------------------------------------------------------------
// GPU corner: one flag false at a time
// ---------------------------------------------------------------------------

#[test]
fn deny_who_false() {
    let mut req = valid_request();
    req.who_pass = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_what_false() {
    let mut req = valid_request();
    req.what_pass = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_how_false() {
    let mut req = valid_request();
    req.how_pass = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

// ---------------------------------------------------------------------------
// Deployment corner: one flag false at a time
// ---------------------------------------------------------------------------

#[test]
fn deny_where_false() {
    let mut req = valid_request();
    req.where_pass = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_when_false() {
    let mut req = valid_request();
    req.when_pass = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_why_false() {
    let mut req = valid_request();
    req.why_pass = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

// ---------------------------------------------------------------------------
// Lease and epoch
// ---------------------------------------------------------------------------

#[test]
fn deny_lease_invalid() {
    let mut req = valid_request();
    req.has_valid_lease = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_epoch_stale() {
    let mut req = valid_request();
    req.epoch_fresh = false;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

// ---------------------------------------------------------------------------
// HMAC checks
// ---------------------------------------------------------------------------

#[test]
fn deny_hmac_mismatch() {
    let mut req = valid_request();
    req.capability_hmac = req.capability_hmac.wrapping_add(1); // corrupt
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_hmac_wrong_key_slot() {
    // Slot 1 key is all-zeros (never set) — HMAC will not match slot 0 MAC
    let mut req = valid_request();
    req.key_slot = 1;
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_hmac_wrong_request_hash() {
    let mut req = valid_request();
    // capability_hmac was computed for TEST_REQUEST_HASH, now hash is different
    req.request_hash = TEST_REQUEST_HASH.wrapping_add(1);
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn allow_hmac_exact_match() {
    // Recompute with a different hash to confirm the crypto path works end-to-end
    let hash = 0xFEED_FACE_DEAD_BEEF_u64;
    let mut req = valid_request();
    req.request_hash    = hash;
    req.capability_hmac = compute_hmac(hash);
    assert!(is_allow(unsafe { cubie_admit(&req) }));
}

// ---------------------------------------------------------------------------
// NVLink waiter detection
// ---------------------------------------------------------------------------

#[test]
fn deny_nvlink_waiter_sm_zero_vram_held() {
    let mut req = valid_request();
    mmio::mock_set_nvlink_sm(0, 0);   // SM idle
    mmio::mock_set_nvlink_vram(0, 512); // 512 MiB held — waiter signature
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn allow_nvlink_sm_active_vram_held() {
    // SM active + VRAM held = legitimate compute, not a waiter
    let req = valid_request();
    mmio::mock_set_nvlink_sm(0, 50);
    mmio::mock_set_nvlink_vram(0, 512);
    assert!(is_allow(unsafe { cubie_admit(&req) }));
}

#[test]
fn allow_nvlink_sm_zero_no_vram() {
    // SM idle + no VRAM = peer is genuinely idle, not holding anything
    let req = valid_request();
    mmio::mock_set_nvlink_sm(0, 0);
    mmio::mock_set_nvlink_vram(0, 0);
    assert!(is_allow(unsafe { cubie_admit(&req) }));
}

// ---------------------------------------------------------------------------
// PCIe adapter cache and bandwidth
// ---------------------------------------------------------------------------

#[test]
fn deny_pcie_congested_cache_miss() {
    pcie::clear_adapter_cache();
    let req = valid_request();
    mmio::mock_set_pcie_bw(1024); // 1 GB/s — below 4 GB/s threshold
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}

#[test]
fn allow_pcie_good_bandwidth() {
    pcie::clear_adapter_cache();
    let req = valid_request();
    mmio::mock_set_pcie_bw(4096); // exactly at threshold — allowed
    assert!(is_allow(unsafe { cubie_admit(&req) }));
}

#[test]
fn allow_pcie_cache_hit_bypasses_bw_check() {
    pcie::clear_adapter_cache();
    let req = valid_request();
    // First call: BW good → adapter gets cached
    mmio::mock_set_pcie_bw(8192);
    assert!(is_allow(unsafe { cubie_admit(&req) }));
    // Second call: BW now bad, but adapter is cached → still allowed
    mmio::mock_set_pcie_bw(100);
    assert!(is_allow(unsafe { cubie_admit(&req) }));
}

#[test]
fn deny_zero_adapter_id_sentinel() {
    let mut req = valid_request();
    req.adapter_id = 0; // sentinel EMPTY value
    assert!(is_deny(unsafe { cubie_admit(&req) }));
}


Now I have everything I need. Let me write the comprehensive context document.


1	//! HMAC-SHA256 per FIPS 198-1 — no_std, no heap, no external crates.
2	//!
3	//! hmac_sha256(key: &[u8; 32], msg: &[u8]) -> [u8; 32]
4	//!
5	//! Key is always 32 bytes (eFuse slot output). Block-size key = key padded
6	//! with 0x00 bytes to 64 bytes.  Inner and outer hash inputs are stacked
7	//! on the call-frame as fixed-size arrays — no allocations.
8
9	use crate::sha256::sha256;
10
11	/// HMAC-SHA256 (FIPS 198-1).
12	///
13	/// `key` — 32-byte symmetric key (e.g. read from eFuse slot).
14	/// `msg` — message bytes (up to 64 bytes for single outer-block; longer
15	///          messages still work via sha256's multi-block path).
16	pub fn hmac_sha256(key: &[u8; 32], msg: &[u8]) -> [u8; 32] {
17	    // ------------------------------------------------------------------
18	    // Inner hash: H( (K ⊕ ipad) ∥ msg )
19	    //   K padded to 64 bytes: key[0..32] ⊕ 0x36, zeros[32..64] ⊕ 0x36
20	    // ------------------------------------------------------------------
21	    // Buffer is 64 (ipad key) + 64 (max msg) = 128 bytes.
22	    // For capability_hmac_verify the message is always 8 bytes (u64).
23	    let mlen = msg.len();
24	    let mut inner = [0u8; 128];
25	    for i in 0..32 {
26	        inner[i] = key[i] ^ 0x36;
27	    }
28	    for i in 32..64 {
29	        inner[i] = 0x36; // zero-pad ^ ipad
30	    }
31	    inner[64..64 + mlen].copy_from_slice(msg);
32	    let inner_hash = sha256(&inner[..64 + mlen]);
33
34	    // ------------------------------------------------------------------
35	    // Outer hash: H( (K ⊕ opad) ∥ inner_hash )
36	    //   K padded to 64 bytes: key[0..32] ⊕ 0x5c, zeros[32..64] ⊕ 0x5c
37	    //   Outer input is always exactly 64 + 32 = 96 bytes.
38	    // ------------------------------------------------------------------
39	    let mut outer = [0u8; 96];
40	    for i in 0..32 {
41	        outer[i] = key[i] ^ 0x5c;
42	    }
43	    for i in 32..64 {
44	        outer[i] = 0x5c;
45	    }
46	    outer[64..96].copy_from_slice(&inner_hash);
47	    sha256(&outer)
48	}
49
50	/// Constant-time 32-byte equality — avoids early-exit timing oracle.
51	pub fn ct_eq_32(a: &[u8; 32], b: &[u8; 32]) -> bool {
52	    let mut diff = 0u8;
53	    for i in 0..32 {
54	        diff |= a[i] ^ b[i];
55	    }
56	    diff == 0
57	}
58

//! HMAC-SHA256 per FIPS 198-1 — no_std, no heap, no external crates.
//!
//! hmac_sha256(key: &[u8; 32], msg: &[u8]) -> [u8; 32]
//!
//! Key is always 32 bytes (eFuse slot output). Block-size key = key padded
//! with 0x00 bytes to 64 bytes.  Inner and outer hash inputs are stacked
//! on the call-frame as fixed-size arrays — no allocations.

use crate::sha256::sha256;

/// HMAC-SHA256 (FIPS 198-1).
///
/// `key` — 32-byte symmetric key (e.g. read from eFuse slot).
/// `msg` — message bytes (up to 64 bytes for single outer-block; longer
///          messages still work via sha256's multi-block path).
pub fn hmac_sha256(key: &[u8; 32], msg: &[u8]) -> [u8; 32] {
    // ------------------------------------------------------------------
    // Inner hash: H( (K ⊕ ipad) ∥ msg )
    //   K padded to 64 bytes: key[0..32] ⊕ 0x36, zeros[32..64] ⊕ 0x36
    // ------------------------------------------------------------------
    // Buffer is 64 (ipad key) + 64 (max msg) = 128 bytes.
    // For capability_hmac_verify the message is always 8 bytes (u64).
    let mlen = msg.len();
    let mut inner = [0u8; 128];
    for i in 0..32 {
        inner[i] = key[i] ^ 0x36;
    }
    for i in 32..64 {
        inner[i] = 0x36; // zero-pad ^ ipad
    }
    inner[64..64 + mlen].copy_from_slice(msg);
    let inner_hash = sha256(&inner[..64 + mlen]);

    // ------------------------------------------------------------------
    // Outer hash: H( (K ⊕ opad) ∥ inner_hash )
    //   K padded to 64 bytes: key[0..32] ⊕ 0x5c, zeros[32..64] ⊕ 0x5c
    //   Outer input is always exactly 64 + 32 = 96 bytes.
    // ------------------------------------------------------------------
    let mut outer = [0u8; 96];
    for i in 0..32 {
        outer[i] = key[i] ^ 0x5c;
    }
    for i in 32..64 {
        outer[i] = 0x5c;
    }
    outer[64..96].copy_from_slice(&inner_hash);
    sha256(&outer)
}

/// Constant-time 32-byte equality — avoids early-exit timing oracle.
pub fn ct_eq_32(a: &[u8; 32], b: &[u8; 32]) -> bool {
    let mut diff = 0u8;
    for i in 0..32 {
        diff |= a[i] ^ b[i];
    }
    diff == 0
}


1	// cubie_runtime_spec.rs — Verus runtime spec for Cubie admission model
2	//
3	// Corresponds to: CubieBridgeV1_40 + CubieTrustCompilerV2_0 Boolean model
4	// Verified-exact theorems bridged here:
5	//   gpu_failure_implies_denial      (CubieBridgeV1_40, VERIFIED_EXACT)
6	//   deployment_failure_implies_denial (CubieBridgeV1_40, VERIFIED_EXACT)
7	//   gpu_only_pass_witness           (CubieBridgeV1_40, VERIFIED_EXACT)
8	//   deployment_only_pass_witness    (CubieBridgeV1_40, VERIFIED_EXACT)
9	//   admit_decomposition             (CubieBridgeV1_40, VERIFIED_EXACT)
10	//
11	// HMAC verification is NOT attempted here — treated as an uninterpreted
12	// trusted predicate (capability_hmac_valid). Prove: if it fails → deny.
13	//
14	// No heap allocation in hot path. No network calls. No asymmetric crypto.
15	// All proofs are pure spec-level; exec layer must be added separately.
16
17	#![allow(unused_imports)]
18	use vstd::prelude::*;
19
20	verus! {
21
22	// ---------------------------------------------------------------------------
23	// Core struct
24	// ---------------------------------------------------------------------------
25
26	/// The six semantic faces of a CubieRequest.
27	/// Maps to the six-faced 3×3 object in the Cubie formal model:
28	///   Who(0) What(1) When(2) Where(3) Why(4) How(5)
29	///
30	/// Epoch fields support replay-protection checks defined in
31	/// CubieTrustCompilerV2_0 (epoch_advance_strictly_increases, bypass_no_lease).
32	pub struct CubieRequest {
33	    // Face predicates — one per semantic face
34	    pub who_pass:        bool,   // Identity face (Who)
35	    pub what_pass:       bool,   // Lineage face (What)
36	    pub when_pass:       bool,   // Runtime face (When)
37	    pub where_pass:      bool,   // Context face (Where)
38	    pub why_pass:        bool,   // Policy face (Why)
39	    pub how_pass:        bool,   // Outcome face (How)
40
41	    // Epoch fields for host verifier and replay guard
42	    pub telemetry_epoch: u64,
43	    pub policy_epoch:    u32,
44	    pub payload_hash:    u64,
45	}
46
47	// ---------------------------------------------------------------------------
48	// Spec functions
49	// ---------------------------------------------------------------------------
50
51	/// Checks a single face predicate by index (0–5).
52	/// Any index outside 0–5 returns false (deny-by-default).
53	/// Corresponds to the per-face denial theorems in CubieTrustCompilerV1_50.
54	pub open spec fn face_pass(req: &CubieRequest, face_idx: u8) -> bool {
55	    match face_idx {
56	        0 => req.who_pass,
57	        1 => req.what_pass,
58	        2 => req.when_pass,
59	        3 => req.where_pass,
60	        4 => req.why_pass,
61	        5 => req.how_pass,
62	        _ => false,
63	    }
64	}
65
66	/// All six faces must pass for a full surface admit.
67	/// Corresponds to CubieTrustCompilerV1_50.admit_implies_*_pass family.
68	pub open spec fn all_faces_pass(req: &CubieRequest) -> bool {
69	    req.who_pass && req.what_pass && req.when_pass
70	    && req.where_pass && req.why_pass && req.how_pass
71	}
72
73	/// GPU corner: Who + What + How (top-face cluster).
74	/// Directly encodes CubieBridgeV1_40:
75	///   WriteOK c policyOK = gpu_corner c && deployment_corner c && topology c && policyOK
76	pub open spec fn gpu_corner_pass(req: &CubieRequest) -> bool {
77	    req.who_pass && req.what_pass && req.how_pass
78	}
79
80	/// Deployment corner: Where + When + Why (bottom-face cluster).
81	/// Directly encodes the deployment_corner predicate from CubieBridgeV1_40.
82	pub open spec fn deployment_corner_pass(req: &CubieRequest) -> bool {
83	    req.where_pass && req.when_pass && req.why_pass
84	}
85
86	/// Top-level admission decision.
87	/// Both corners + topology + policy must pass.
88	/// Encodes CubieBridgeV1_40 WriteOK decomposition (admit_decomposition, VERIFIED_EXACT).
89	pub open spec fn admit(req: &CubieRequest, topology_ok: bool, policy_ok: bool) -> bool {
90	    gpu_corner_pass(req) && deployment_corner_pass(req) && topology_ok && policy_ok
91	}
92
93	// ---------------------------------------------------------------------------
94	// Verified-exact proofs (bridging Coq/Lean to Verus runtime layer)
95	// ---------------------------------------------------------------------------
96
97	/// Theorem: GPU corner failure implies admission denial.
98	/// VERIFIED_EXACT: CubieBridgeV1_40.gpu_failure_implies_denial
99	proof fn gpu_failure_implies_denial(req: &CubieRequest, topology_ok: bool, policy_ok: bool)
100	    requires !gpu_corner_pass(req)
101	    ensures  !admit(req, topology_ok, policy_ok)
102	{
103	    // Follows directly from admit definition:
104	    // admit = gpu_corner_pass && ... => !gpu_corner_pass => !admit
105	}
106
107	/// Theorem: Deployment corner failure implies admission denial.
108	/// VERIFIED_EXACT: CubieBridgeV1_40.deployment_failure_implies_denial
109	proof fn deployment_failure_implies_denial(req: &CubieRequest, topology_ok: bool, policy_ok: bool)
110	    requires !deployment_corner_pass(req)
111	    ensures  !admit(req, topology_ok, policy_ok)
112	{
113	    // Analogous to gpu_failure_implies_denial
114	}
115
116	/// Theorem: Any false face predicate denies when all-faces required.
117	/// Corresponds to CubieTrustCompilerV1_50 face_localized_denial family.
118	proof fn false_face_denies_full_surface(req: &CubieRequest, face: u8)
119	    requires face < 6 && !face_pass(req, face)
120	    ensures  !all_faces_pass(req)
121	{
122	    // If any face is false, the conjunction is false
123	}
124
125	/// Witness: GPU corner can pass while deployment corner fails (independence).
126	/// VERIFIED_EXACT: CubieBridgeV1_40.gpu_only_pass_witness
127	proof fn gpu_only_pass_witness()
128	    ensures exists |req: CubieRequest, t: bool, p: bool|
129	        gpu_corner_pass(&req) && !deployment_corner_pass(&req) && !admit(&req, t, p)
130	{
131	    let req = CubieRequest {
132	        who_pass: true, what_pass: true, how_pass: true,   // GPU corner passes
133	        when_pass: false, where_pass: false, why_pass: false, // deployment corner fails
134	        telemetry_epoch: 0, policy_epoch: 0, payload_hash: 0,
135	    };
136	    assert(gpu_corner_pass(&req));
137	    assert(!deployment_corner_pass(&req));
138	    assert(!admit(&req, true, true));
139	}
140
141	/// Witness: Deployment corner can pass while GPU corner fails (independence).
142	/// VERIFIED_EXACT: CubieBridgeV1_40.deployment_only_pass_witness
143	proof fn deployment_only_pass_witness()
144	    ensures exists |req: CubieRequest, t: bool, p: bool|
145	        !gpu_corner_pass(&req) && deployment_corner_pass(&req) && !admit(&req, t, p)
146	{
147	    let req = CubieRequest {
148	        who_pass: false, what_pass: false, how_pass: false, // GPU corner fails
149	        when_pass: true, where_pass: true, why_pass: true,  // deployment corner passes
150	        telemetry_epoch: 0, policy_epoch: 0, payload_hash: 0,
151	    };
152	    assert(!gpu_corner_pass(&req));
153	    assert(deployment_corner_pass(&req));
154	    assert(!admit(&req, true, true));
155	}
156
157	/// Theorem: All faces true + topology + policy admits.
158	proof fn full_pass_admits(req: &CubieRequest)
159	    requires all_faces_pass(req)
160	    ensures  admit(req, true, true)
161	{
162	    assert(gpu_corner_pass(req));
163	    assert(deployment_corner_pass(req));
164	}
165
166	/// Theorem: Denial count bounded by 54 (one per oriented facelet).
167	/// VERIFIED_EXACT: CubieTrustCompilerV1_50.denial_count_bounded_54
168	/// Here expressed as: number of false faces ≤ 6 (one per face)
169	/// The full 54-facelet bound is proven in the Coq/Lean source.
170	proof fn denial_count_bounded(req: &CubieRequest)
171	    ensures
172	        (if !req.who_pass  { 1nat } else { 0nat })
173	        + (if !req.what_pass { 1nat } else { 0nat })
174	        + (if !req.when_pass { 1nat } else { 0nat })
175	        + (if !req.where_pass{ 1nat } else { 0nat })
176	        + (if !req.why_pass  { 1nat } else { 0nat })
177	        + (if !req.how_pass  { 1nat } else { 0nat })
178	        <= 6
179	{
180	    // Trivially bounded: at most 6 faces can be false
181	}
182
183	/// EXEC: top-level admit gate.
184	pub fn exec_admit(req: &CubieRequest, topology_ok: bool, policy_ok: bool) -> (result: bool)
185	    ensures result == admit(req, topology_ok, policy_ok),
186	{
187	    exec_gpu_corner_pass(req) && exec_deployment_corner_pass(req) && topology_ok && policy_ok
188	}
189
190	fn exec_gpu_corner_pass(req: &CubieRequest) -> (result: bool)
191	    ensures result == gpu_corner_pass(req),
192	{
193	    req.who_pass && req.what_pass && req.how_pass
194	}
195
196	fn exec_deployment_corner_pass(req: &CubieRequest) -> (result: bool)
197	    ensures result == deployment_corner_pass(req),
198	{
199	    req.where_pass && req.when_pass && req.why_pass
200	}
201
202	} // verus!
203

// cubie_runtime_spec.rs — Verus runtime spec for Cubie admission model
//
// Corresponds to: CubieBridgeV1_40 + CubieTrustCompilerV2_0 Boolean model
// Verified-exact theorems bridged here:
//   gpu_failure_implies_denial      (CubieBridgeV1_40, VERIFIED_EXACT)
//   deployment_failure_implies_denial (CubieBridgeV1_40, VERIFIED_EXACT)
//   gpu_only_pass_witness           (CubieBridgeV1_40, VERIFIED_EXACT)
//   deployment_only_pass_witness    (CubieBridgeV1_40, VERIFIED_EXACT)
//   admit_decomposition             (CubieBridgeV1_40, VERIFIED_EXACT)
//
// HMAC verification is NOT attempted here — treated as an uninterpreted
// trusted predicate (capability_hmac_valid). Prove: if it fails → deny.
//
// No heap allocation in hot path. No network calls. No asymmetric crypto.
// All proofs are pure spec-level; exec layer must be added separately.

#![allow(unused_imports)]
use vstd::prelude::*;

verus! {

// ---------------------------------------------------------------------------
// Core struct
// ---------------------------------------------------------------------------

/// The six semantic faces of a CubieRequest.
/// Maps to the six-faced 3×3 object in the Cubie formal model:
///   Who(0) What(1) When(2) Where(3) Why(4) How(5)
///
/// Epoch fields support replay-protection checks defined in
/// CubieTrustCompilerV2_0 (epoch_advance_strictly_increases, bypass_no_lease).
pub struct CubieRequest {
    // Face predicates — one per semantic face
    pub who_pass:        bool,   // Identity face (Who)
    pub what_pass:       bool,   // Lineage face (What)
    pub when_pass:       bool,   // Runtime face (When)
    pub where_pass:      bool,   // Context face (Where)
    pub why_pass:        bool,   // Policy face (Why)
    pub how_pass:        bool,   // Outcome face (How)

    // Epoch fields for host verifier and replay guard
    pub telemetry_epoch: u64,
    pub policy_epoch:    u32,
    pub payload_hash:    u64,
}

// ---------------------------------------------------------------------------
// Spec functions
// ---------------------------------------------------------------------------

/// Checks a single face predicate by index (0–5).
/// Any index outside 0–5 returns false (deny-by-default).
/// Corresponds to the per-face denial theorems in CubieTrustCompilerV1_50.
pub open spec fn face_pass(req: &CubieRequest, face_idx: u8) -> bool {
    match face_idx {
        0 => req.who_pass,
        1 => req.what_pass,
        2 => req.when_pass,
        3 => req.where_pass,
        4 => req.why_pass,
        5 => req.how_pass,
        _ => false,
    }
}

/// All six faces must pass for a full surface admit.
/// Corresponds to CubieTrustCompilerV1_50.admit_implies_*_pass family.
pub open spec fn all_faces_pass(req: &CubieRequest) -> bool {
    req.who_pass && req.what_pass && req.when_pass
    && req.where_pass && req.why_pass && req.how_pass
}

/// GPU corner: Who + What + How (top-face cluster).
/// Directly encodes CubieBridgeV1_40:
///   WriteOK c policyOK = gpu_corner c && deployment_corner c && topology c && policyOK
pub open spec fn gpu_corner_pass(req: &CubieRequest) -> bool {
    req.who_pass && req.what_pass && req.how_pass
}

/// Deployment corner: Where + When + Why (bottom-face cluster).
/// Directly encodes the deployment_corner predicate from CubieBridgeV1_40.
pub open spec fn deployment_corner_pass(req: &CubieRequest) -> bool {
    req.where_pass && req.when_pass && req.why_pass
}

/// Top-level admission decision.
/// Both corners + topology + policy must pass.
/// Encodes CubieBridgeV1_40 WriteOK decomposition (admit_decomposition, VERIFIED_EXACT).
pub open spec fn admit(req: &CubieRequest, topology_ok: bool, policy_ok: bool) -> bool {
    gpu_corner_pass(req) && deployment_corner_pass(req) && topology_ok && policy_ok
}

// ---------------------------------------------------------------------------
// Verified-exact proofs (bridging Coq/Lean to Verus runtime layer)
// ---------------------------------------------------------------------------

/// Theorem: GPU corner failure implies admission denial.
/// VERIFIED_EXACT: CubieBridgeV1_40.gpu_failure_implies_denial
proof fn gpu_failure_implies_denial(req: &CubieRequest, topology_ok: bool, policy_ok: bool)
    requires !gpu_corner_pass(req)
    ensures  !admit(req, topology_ok, policy_ok)
{
    // Follows directly from admit definition:
    // admit = gpu_corner_pass && ... => !gpu_corner_pass => !admit
}

/// Theorem: Deployment corner failure implies admission denial.
/// VERIFIED_EXACT: CubieBridgeV1_40.deployment_failure_implies_denial
proof fn deployment_failure_implies_denial(req: &CubieRequest, topology_ok: bool, policy_ok: bool)
    requires !deployment_corner_pass(req)
    ensures  !admit(req, topology_ok, policy_ok)
{
    // Analogous to gpu_failure_implies_denial
}

/// Theorem: Any false face predicate denies when all-faces required.
/// Corresponds to CubieTrustCompilerV1_50 face_localized_denial family.
proof fn false_face_denies_full_surface(req: &CubieRequest, face: u8)
    requires face < 6 && !face_pass(req, face)
    ensures  !all_faces_pass(req)
{
    // If any face is false, the conjunction is false
}

/// Witness: GPU corner can pass while deployment corner fails (independence).
/// VERIFIED_EXACT: CubieBridgeV1_40.gpu_only_pass_witness
proof fn gpu_only_pass_witness()
    ensures exists |req: CubieRequest, t: bool, p: bool|
        gpu_corner_pass(&req) && !deployment_corner_pass(&req) && !admit(&req, t, p)
{
    let req = CubieRequest {
        who_pass: true, what_pass: true, how_pass: true,   // GPU corner passes
        when_pass: false, where_pass: false, why_pass: false, // deployment corner fails
        telemetry_epoch: 0, policy_epoch: 0, payload_hash: 0,
    };
    assert(gpu_corner_pass(&req));
    assert(!deployment_corner_pass(&req));
    assert(!admit(&req, true, true));
}

/// Witness: Deployment corner can pass while GPU corner fails (independence).
/// VERIFIED_EXACT: CubieBridgeV1_40.deployment_only_pass_witness
proof fn deployment_only_pass_witness()
    ensures exists |req: CubieRequest, t: bool, p: bool|
        !gpu_corner_pass(&req) && deployment_corner_pass(&req) && !admit(&req, t, p)
{
    let req = CubieRequest {
        who_pass: false, what_pass: false, how_pass: false, // GPU corner fails
        when_pass: true, where_pass: true, why_pass: true,  // deployment corner passes
        telemetry_epoch: 0, policy_epoch: 0, payload_hash: 0,
    };
    assert(!gpu_corner_pass(&req));
    assert(deployment_corner_pass(&req));
    assert(!admit(&req, true, true));
}

/// Theorem: All faces true + topology + policy admits.
proof fn full_pass_admits(req: &CubieRequest)
    requires all_faces_pass(req)
    ensures  admit(req, true, true)
{
    assert(gpu_corner_pass(req));
    assert(deployment_corner_pass(req));
}

/// Theorem: Denial count bounded by 54 (one per oriented facelet).
/// VERIFIED_EXACT: CubieTrustCompilerV1_50.denial_count_bounded_54
/// Here expressed as: number of false faces ≤ 6 (one per face)
/// The full 54-facelet bound is proven in the Coq/Lean source.
proof fn denial_count_bounded(req: &CubieRequest)
    ensures
        (if !req.who_pass  { 1nat } else { 0nat })
        + (if !req.what_pass { 1nat } else { 0nat })
        + (if !req.when_pass { 1nat } else { 0nat })
        + (if !req.where_pass{ 1nat } else { 0nat })
        + (if !req.why_pass  { 1nat } else { 0nat })
        + (if !req.how_pass  { 1nat } else { 0nat })
        <= 6
{
    // Trivially bounded: at most 6 faces can be false
}

/// EXEC: top-level admit gate.
pub fn exec_admit(req: &CubieRequest, topology_ok: bool, policy_ok: bool) -> (result: bool)
    ensures result == admit(req, topology_ok, policy_ok),
{
    exec_gpu_corner_pass(req) && exec_deployment_corner_pass(req) && topology_ok && policy_ok
}

fn exec_gpu_corner_pass(req: &CubieRequest) -> (result: bool)
    ensures result == gpu_corner_pass(req),
{
    req.who_pass && req.what_pass && req.how_pass
}

fn exec_deployment_corner_pass(req: &CubieRequest) -> (result: bool)
    ensures result == deployment_corner_pass(req),
{
    req.where_pass && req.when_pass && req.why_pass
}

} // verus!


Now I have all the source. Writing the full context document: