zenith-foundation 0.1.0

Zenith 核心基础设施:统一错误类型、FrameToken 所有权令牌、FramePool、分层资源账本、恒定时间比较
Documentation
//! 统一随机源(全 workspace 唯一入口)
//!
//! 两类随机性严格分离:
//! - [`random_u64`] / [`try_random_u64`]:CSPRNG(操作系统熵源),用于安全敏感场景
//!   (TCP ISN、QUIC SCID、PATH_CHALLENGE、会话标识),禁止用伪随机替代
//! - [`pseudo_random_u64`] / [`Splitmix64`]:线程本地 splitmix64 伪随机(种子一次性
//!   取自 CSPRNG),用于性能敏感但无安全要求的场景(负载均衡 P2C、退避 jitter)
//!
//! 设计约束:
//! - 热路径零系统调用:伪随机走线程本地状态,仅首次播种触达 OS 熵源
//! - fail-closed:CSPRNG 失败时 [`try_random_u64`] 返回 `None`,由调用方决策;
//!   [`random_u64`] 的应急回退仍混入纳秒时间戳与原子计数(绝不退化为固定种子)

use rand::rngs::OsRng;
use rand::RngCore;
use std::cell::Cell;
use std::sync::atomic::{AtomicU64, Ordering};

/// 应急熵混合计数器(仅 CSPRNG 失败路径使用,保证多次调用输出互不相同)
static EMERGENCY_COUNTER: AtomicU64 = AtomicU64::new(0);

thread_local! {
    /// 线程本地 splitmix64 状态(Cell 零同步开销;None 表示尚未播种)
    static SPLITMIX_STATE: Cell<Option<u64>> = const { Cell::new(None) };
}

/// 从 OS 熵源读取 8 字节(CSPRNG)
///
/// # Returns
/// * `Some(u64)` - 密码学安全随机数
/// * `None` - OS 熵源失败(fail-closed,调用方必须不得退化为可预测值)
#[inline]
pub fn try_random_u64() -> Option<u64> {
    let mut buf = [0u8; 8];
    OsRng.try_fill_bytes(&mut buf).ok()?;
    Some(u64::from_ne_bytes(buf))
}

/// 从 OS 熵源获取密码学安全随机数
///
/// 安全敏感场景(TCP ISN / QUIC SCID / 挑战令牌)的唯一合法入口。
///
/// # 应急回退
/// OS 熵源在受支持平台上实际不会失败;万一失败,混入纳秒时间戳、
/// 单调原子计数与栈地址熵,保证输出不可重放(仍优于任何固定种子方案)。
#[inline]
#[must_use]
pub fn random_u64() -> u64 {
    if let Some(v) = try_random_u64() {
        return v;
    }
    // 应急熵:CSPRNG 不可用时的最后防线(绝不返回固定值)
    let nanos = std::time::SystemTime::now()
        .duration_since(std::time::UNIX_EPOCH)
        .map(|d| d.as_nanos() as u64)
        .unwrap_or(0);
    let counter = EMERGENCY_COUNTER.fetch_add(1, Ordering::Relaxed);
    let stack_addr = (&counter as *const u64) as u64;
    splitmix64_next(nanos ^ counter.rotate_left(31) ^ stack_addr)
}

/// 填充密码学安全随机字节
///
/// # Returns
/// * `true` - 填充成功
/// * `false` - OS 熵源失败(fail-closed,缓冲区保持原样)
#[inline]
pub fn try_fill_random(dest: &mut [u8]) -> bool {
    OsRng.try_fill_bytes(dest).is_ok()
}

/// splitmix64 单步推进(纯函数,供播种与应急熵复用)
#[inline]
const fn splitmix64_next(mut x: u64) -> u64 {
    x = x.wrapping_add(0x9E37_79B9_7F4A_7C15);
    let mut z = x;
    z = (z ^ (z >> 30)).wrapping_mul(0xBF58_476D_1CE4_E5B9);
    z = (z ^ (z >> 27)).wrapping_mul(0x94D0_49BB_1331_11EB);
    z ^ (z >> 31)
}

/// Splitmix64 伪随机生成器(值语义,零堆分配)
///
/// 适用于无安全要求的性能场景;安全场景必须使用 [`random_u64`]。
#[derive(Debug, Clone)]
pub struct Splitmix64 {
    state: u64,
}

impl Splitmix64 {
    /// 以指定种子构造
    #[inline]
    #[must_use]
    pub const fn with_seed(seed: u64) -> Self {
        Self { state: seed }
    }

    /// 以 CSPRNG 种子构造(应急回退同 [`random_u64`])
    #[inline]
    #[must_use]
    pub fn seeded() -> Self {
        Self {
            state: random_u64(),
        }
    }

    /// 生成下一个伪随机数
    #[inline]
    pub fn next_u64(&mut self) -> u64 {
        self.state = splitmix64_next(self.state);
        self.state
    }

    /// 生成 `[0, bound)` 区间伪随机数(bound 为 0 时返回 0)
    #[inline]
    pub fn next_bounded(&mut self, bound: u64) -> u64 {
        if bound == 0 {
            return 0;
        }
        self.next_u64() % bound
    }
}

/// 线程本地伪随机(热路径零系统调用、零同步开销)
///
/// 首次调用时以 CSPRNG 播种;后续调用纯用户态推进。
/// 适用于负载均衡 P2C、退避 jitter 等性能敏感场景。
#[inline]
#[must_use]
pub fn pseudo_random_u64() -> u64 {
    SPLITMIX_STATE.with(|cell| {
        let state = match cell.get() {
            Some(s) => s,
            None => {
                let seed = random_u64();
                cell.set(Some(seed));
                seed
            }
        };
        let next = splitmix64_next(state);
        cell.set(Some(next));
        next
    })
}

/// 线程本地伪随机,输出 `[0, bound)`(bound 为 0 时返回 0)
#[inline]
#[must_use]
pub fn pseudo_random_bounded(bound: u64) -> u64 {
    if bound == 0 {
        return 0;
    }
    pseudo_random_u64() % bound
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_random_u64_not_constant() {
        let a = random_u64();
        let b = random_u64();
        assert_ne!(a, b, "CSPRNG 连续输出不得相同");
    }

    #[test]
    fn test_try_random_u64_works() {
        assert!(try_random_u64().is_some());
    }

    #[test]
    fn test_try_fill_random() {
        let mut buf = [0u8; 32];
        assert!(try_fill_random(&mut buf));
        assert!(buf.iter().any(|&b| b != 0), "填充后缓冲区应非全零");
    }

    #[test]
    fn test_splitmix64_deterministic() {
        let mut a = Splitmix64::with_seed(42);
        let mut b = Splitmix64::with_seed(42);
        for _ in 0..100 {
            assert_eq!(a.next_u64(), b.next_u64());
        }
    }

    #[test]
    fn test_splitmix64_sequence_unique() {
        let mut rng = Splitmix64::with_seed(1);
        let mut seen = std::collections::HashSet::new();
        for _ in 0..1000 {
            assert!(seen.insert(rng.next_u64()), "splitmix64 序列不得重复");
        }
    }

    #[test]
    fn test_splitmix64_bounded() {
        let mut rng = Splitmix64::with_seed(7);
        for _ in 0..1000 {
            assert!(rng.next_bounded(10) < 10);
        }
        assert_eq!(rng.next_bounded(0), 0);
    }

    #[test]
    fn test_pseudo_random_u64_not_constant() {
        let a = pseudo_random_u64();
        let b = pseudo_random_u64();
        assert_ne!(a, b);
    }

    #[test]
    fn test_pseudo_random_bounded() {
        for _ in 0..1000 {
            assert!(pseudo_random_bounded(64) < 64);
        }
        assert_eq!(pseudo_random_bounded(0), 0);
    }

    #[test]
    fn test_seeded_constructor() {
        let mut rng = Splitmix64::seeded();
        let _ = rng.next_u64();
    }
}