ruvector-verified 0.1.1

Formal verification layer for RuVector: proof-carrying vector operations with sub-microsecond overhead using lean-agentic dependent types
Documentation
//! Formal verification layer for RuVector using lean-agentic dependent types.
//!
//! This crate provides proof-carrying vector operations, verified pipeline
//! composition, and formal attestation for RuVector's safety-critical paths.
//!
//! # Feature Flags
//!
//! - `hnsw-proofs`: Enable verified HNSW insert/query operations
//! - `rvf-proofs`: Enable RVF witness chain integration
//! - `coherence-proofs`: Enable coherence verification
//! - `serde`: Enable serialization of proof attestations
//! - `fast-arena`: SolverArena-style bump allocator
//! - `simd-hash`: AVX2/NEON accelerated hash-consing
//! - `gated-proofs`: Coherence-gated proof depth routing
//! - `ultra`: All optimizations (fast-arena + simd-hash + gated-proofs)
//! - `all-proofs`: All proof integrations (hnsw + rvf + coherence)

pub mod error;
pub mod invariants;
pub mod vector_types;
pub mod proof_store;
pub mod pipeline;

#[cfg(feature = "fast-arena")]
pub mod fast_arena;
pub mod pools;
pub mod cache;
#[cfg(feature = "gated-proofs")]
pub mod gated;

// Re-exports
pub use error::{VerificationError, Result};
pub use vector_types::{mk_vector_type, mk_nat_literal, prove_dim_eq};
pub use proof_store::ProofAttestation;
pub use pipeline::VerifiedStage;
pub use invariants::BuiltinDecl;

/// The proof environment bundles verification state.
///
/// One instance per thread (not `Sync` due to interior state).
/// Create with `ProofEnvironment::new()` which pre-loads RuVector type
/// declarations.
///
/// # Example
///
/// ```rust,ignore
/// use ruvector_verified::ProofEnvironment;
///
/// let mut env = ProofEnvironment::new();
/// let proof = env.prove_dim_eq(128, 128).unwrap();
/// ```
pub struct ProofEnvironment {
    /// Registered built-in symbol names.
    pub symbols: Vec<String>,
    /// Proof term counter (monotonically increasing).
    term_counter: u32,
    /// Cache of recently verified proofs: (input_hash, proof_id).
    proof_cache: std::collections::HashMap<u64, u32>,
    /// Statistics.
    pub stats: ProofStats,
}

/// Verification statistics.
#[derive(Debug, Clone, Default)]
pub struct ProofStats {
    /// Total proofs constructed.
    pub proofs_constructed: u64,
    /// Total proofs verified.
    pub proofs_verified: u64,
    /// Cache hits (proof reused).
    pub cache_hits: u64,
    /// Cache misses (new proof constructed).
    pub cache_misses: u64,
    /// Total reduction steps consumed.
    pub total_reductions: u64,
}

impl ProofEnvironment {
    /// Create a new proof environment pre-loaded with RuVector type declarations.
    pub fn new() -> Self {
        let mut symbols = Vec::with_capacity(32);
        invariants::register_builtin_symbols(&mut symbols);

        Self {
            symbols,
            term_counter: 0,
            proof_cache: std::collections::HashMap::with_capacity(256),
            stats: ProofStats::default(),
        }
    }

    /// Allocate a new proof term ID.
    pub fn alloc_term(&mut self) -> u32 {
        let id = self.term_counter;
        self.term_counter = self.term_counter.checked_add(1)
            .ok_or_else(|| VerificationError::ArenaExhausted { allocated: id })
            .expect("arena overflow");
        self.stats.proofs_constructed += 1;
        id
    }

    /// Look up a symbol index by name.
    pub fn symbol_id(&self, name: &str) -> Option<usize> {
        self.symbols.iter().position(|s| s == name)
    }

    /// Require a symbol index, or return DeclarationNotFound.
    pub fn require_symbol(&self, name: &str) -> Result<usize> {
        self.symbol_id(name).ok_or_else(|| {
            VerificationError::DeclarationNotFound { name: name.to_string() }
        })
    }

    /// Check the proof cache for a previously verified proof.
    pub fn cache_lookup(&mut self, key: u64) -> Option<u32> {
        if let Some(&id) = self.proof_cache.get(&key) {
            self.stats.cache_hits += 1;
            Some(id)
        } else {
            self.stats.cache_misses += 1;
            None
        }
    }

    /// Insert a verified proof into the cache.
    pub fn cache_insert(&mut self, key: u64, proof_id: u32) {
        self.proof_cache.insert(key, proof_id);
    }

    /// Get verification statistics.
    pub fn stats(&self) -> &ProofStats {
        &self.stats
    }

    /// Number of terms allocated.
    pub fn terms_allocated(&self) -> u32 {
        self.term_counter
    }

    /// Reset the environment (clear cache, reset counters).
    /// Useful between independent proof obligations.
    pub fn reset(&mut self) {
        self.term_counter = 0;
        self.proof_cache.clear();
        self.stats = ProofStats::default();
        // Re-register builtins
        self.symbols.clear();
        invariants::register_builtin_symbols(&mut self.symbols);
    }
}

impl Default for ProofEnvironment {
    fn default() -> Self {
        Self::new()
    }
}

/// A vector operation with a machine-checked type proof.
#[derive(Debug, Clone, Copy)]
pub struct VerifiedOp<T> {
    /// The operation result.
    pub value: T,
    /// Proof term ID in the environment.
    pub proof_id: u32,
}

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

    #[test]
    fn proof_env_new_has_builtins() {
        let env = ProofEnvironment::new();
        assert!(env.symbol_id("Nat").is_some());
        assert!(env.symbol_id("RuVec").is_some());
        assert!(env.symbol_id("Eq").is_some());
        assert!(env.symbol_id("Eq.refl").is_some());
        assert!(env.symbol_id("HnswIndex").is_some());
    }

    #[test]
    fn proof_env_alloc_term() {
        let mut env = ProofEnvironment::new();
        assert_eq!(env.alloc_term(), 0);
        assert_eq!(env.alloc_term(), 1);
        assert_eq!(env.alloc_term(), 2);
        assert_eq!(env.terms_allocated(), 3);
    }

    #[test]
    fn proof_env_cache() {
        let mut env = ProofEnvironment::new();
        assert!(env.cache_lookup(42).is_none());
        env.cache_insert(42, 7);
        assert_eq!(env.cache_lookup(42), Some(7));
        assert_eq!(env.stats().cache_hits, 1);
        assert_eq!(env.stats().cache_misses, 1);
    }

    #[test]
    fn proof_env_reset() {
        let mut env = ProofEnvironment::new();
        env.alloc_term();
        env.cache_insert(1, 2);
        env.reset();
        assert_eq!(env.terms_allocated(), 0);
        assert!(env.cache_lookup(1).is_none());
        // Builtins restored after reset
        assert!(env.symbol_id("Nat").is_some());
    }

    #[test]
    fn proof_env_require_symbol() {
        let env = ProofEnvironment::new();
        assert!(env.require_symbol("Nat").is_ok());
        assert!(env.require_symbol("NonExistent").is_err());
    }

    #[test]
    fn verified_op_copy() {
        let op = VerifiedOp { value: 42u32, proof_id: 1 };
        let op2 = op; // Copy
        assert_eq!(op.value, op2.value);
    }
}