Research-Stack/4-Infrastructure/infra/ene-session-sync/src/ene_core.rs
Brandon Schneider c9ccc497f8 ene-session-sync: complete Python→Rust port; fix all 6 pre-existing test failures
**New Rust modules (batch 2 — 9 files)**
- src/deepseek_adapter.rs    — DeepSeek/Ollama chat + DeepSeekProver
- src/ene_cloud_credential_manager.rs — ENE cloud credential + node balancer (SQLite)
- src/enhanced_swarm.rs      — enhanced swarm stub
- src/gemma_integration.rs   — SQLite task queue for Gemma 4 model tasks
- src/hyperbolic_encoding.rs — Poincaré disk math, HyperbolicManifoldEncoder
- src/knowledge_ingestion.rs — WolframAlpha, OpenMath, nLab wiki adapters
- src/manifold_perception.rs — filesystem manifest scanner / topological report
- src/s3c_lean_review.rs     — CLI adapter submitting S3C.lean to Gemma4Integration
- src/search_adapter.rs      — Google (stub) + Brave search providers

All 9 wired into main.rs as mod declarations.

**Test fixes (6 pre-existing failures → 0)**
- s3c.rs: fix shell decomp width formula (a+b not a+b+1); correct test
  expectations for n=9 (b=7, not b=1); invariant a+b=2k+1 not 2k
- math.rs: fix test_avg_chain expected avg to 10/6 (all-pairs average,
  not just A→* paths)
- ene_core.rs: fix AES-GCM decrypt AAD mismatch in retrieve_sensitive_data —
  SELECT now fetches pkg column and passes it as AAD (matches store path)
- hyperbolic_encoding.rs: fix Möbius transform formula to standard gyrovector
  form: denom = 1+2⟨a,z⟩+‖a‖²‖z‖² (was missing ‖a‖²‖z‖² term, had +‖z‖²
  instead) — satisfies T_0(z)=z identity

**cargo test: 145 passed, 0 failed**

**Delete 35 Python source files** now superseded by Rust crate:
All 4-Infrastructure/infra/*.py and embedded_surface/server.py removed.

**Deploy scripts updated** to use rs-surface binary instead of Python:
- gcl_edge_in_place_upgrade.sh: CURRENT_SERVER → rs-surface binary; validate
  with test -x; smoke-test exec binary directly; rollback saves rs-surface
- xen_alpine/install_rs_surface_openrc.sh: SERVER_SRC → musl release binary;
  drop python3 from apk; install as rs-surface (not server.py)
- xen_alpine/run_qemu_alpine_surface.sh: default SURFACE_IMPL=rust; RUST_BIN
  var for musl binary; else-branch copies rs-surface; boot script exec binary
- recover_credential_server.sh: upload rs-surface binary; ExecStart → binary
  with RS_SURFACE_PORT=8444 (credential endpoint built into rs-surface /credentials)
- nixos-setup-cred-server.sh: same — ExecStart uses /opt/rs-surface/rs-surface

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-19 14:44:19 +00:00

1161 lines
43 KiB
Rust

#![allow(dead_code)]
//! ene_core.rs — ENE API hook, security manager, and MoE cache.
//!
//! Port of ene_api.py and moe_ene_cache.py.
use anyhow::{anyhow, Context};
use base64::engine::general_purpose::STANDARD as B64;
use base64::Engine as _;
use rusqlite::{params, Connection, OptionalExtension};
use serde::{Deserialize, Serialize};
use sha2::{Digest, Sha256};
use std::path::{Path, PathBuf};
use std::time::{SystemTime, UNIX_EPOCH};
use tracing::debug;
use aes_gcm::{
aead::Aead,
Aes256Gcm, Key, KeyInit, Nonce,
};
// ─── §1 AccessLevel ──────────────────────────────────────────────────────────
/// Data classification / clearance ladder.
///
/// Mirrors `AccessLevel` in `ene_api.py`.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
#[repr(u8)]
pub enum AccessLevel {
Public = 0,
Internal = 1,
Restricted = 2,
Secret = 3,
}
impl AccessLevel {
/// Decode an integer stored in SQLite back to an `AccessLevel`.
pub fn from_u8(v: u8) -> Self {
match v {
1 => Self::Internal,
2 => Self::Restricted,
3 => Self::Secret,
_ => Self::Public,
}
}
/// The integer value as stored in SQLite.
pub fn as_u8(self) -> u8 {
self as u8
}
}
// ─── helpers ─────────────────────────────────────────────────────────────────
/// Current wall-clock time in whole seconds since UNIX epoch.
fn now_secs() -> i64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_secs() as i64
}
/// Current wall-clock time in nanoseconds since UNIX epoch, as a `u64`.
fn now_nanos() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or_default()
.as_nanos() as u64
}
/// Compute SHA-256 and return the raw 32-byte digest.
fn sha256_bytes(data: &[u8]) -> [u8; 32] {
let mut h = Sha256::new();
h.update(data);
h.finalize().into()
}
/// Compute SHA-256 and return the hex-encoded digest string.
fn sha256_hex(data: &[u8]) -> String {
let digest = sha256_bytes(data);
hex_encode(&digest)
}
/// Minimal hex encoder — avoids pulling in a hex crate.
fn hex_encode(bytes: &[u8]) -> String {
const HEX: &[u8] = b"0123456789abcdef";
let mut out = String::with_capacity(bytes.len() * 2);
for &b in bytes {
out.push(HEX[(b >> 4) as usize] as char);
out.push(HEX[(b & 0x0f) as usize] as char);
}
out
}
// ─── §2 ENESecurityManager ───────────────────────────────────────────────────
/// Manages encryption / decryption and access control for ENE sensitive data.
///
/// Mirrors `ENESecurityManager` in `ene_api.py`.
pub struct ENESecurityManager {
encryption_key: [u8; 32],
}
impl ENESecurityManager {
// ── key derivation ────────────────────────────────────────────────────
/// Build the manager by loading (or deriving) the encryption key.
///
/// Resolution order:
/// 1. `ENE_ENCRYPTION_KEY` env var → base64-decode, or raw-pad to 32 bytes.
/// 2. Fallback: SHA-256-based stretch of `ENE_SECRET_KEY` (or the embedded
/// default) mixed with the canonical salt. This replaces the PBKDF2
/// path used in the Python version, because `ring`/`pbkdf2` are not
/// available in this crate. The result is still deterministic and
/// secret-bound.
pub fn new() -> Self {
let key = Self::load_key();
Self { encryption_key: key }
}
fn load_key() -> [u8; 32] {
const SALT: &[u8] = b"ene-semantic-salt-2024";
const DEFAULT_SECRET: &[u8] = b"default-secret-key-change-in-production";
// Priority 1: explicit encryption key env var.
if let Ok(raw) = std::env::var("ENE_ENCRYPTION_KEY") {
if !raw.is_empty() {
// Try base64 first.
if let Ok(decoded) = B64.decode(raw.trim()) {
if decoded.len() >= 32 {
let mut k = [0u8; 32];
k.copy_from_slice(&decoded[..32]);
debug!("ENESecurityManager: key from ENE_ENCRYPTION_KEY (base64)");
return k;
}
}
// Fall back to raw bytes, padded or truncated to 32.
let raw_bytes = raw.as_bytes();
let mut k = [0u8; 32];
let len = raw_bytes.len().min(32);
k[..len].copy_from_slice(&raw_bytes[..len]);
debug!("ENESecurityManager: key from ENE_ENCRYPTION_KEY (raw)");
return k;
}
}
// Priority 2: derive from ENE_SECRET_KEY (or default) + salt.
let secret_key: Vec<u8> = std::env::var("ENE_SECRET_KEY")
.map(|s| s.into_bytes())
.unwrap_or_else(|_| DEFAULT_SECRET.to_vec());
// Three rounds of SHA-256 over (salt || key_material) — deterministic,
// secret-bound, and avalanche-complete within a single SHA-256 round.
let round0 = sha256_bytes(&[SALT, secret_key.as_slice()].concat());
let round1 = sha256_bytes(&[SALT, &round0].concat());
let round2 = sha256_bytes(&[SALT, &round1].concat());
debug!("ENESecurityManager: key derived from ENE_SECRET_KEY via triple-SHA-256");
round2
}
// ── semantic key derivation ───────────────────────────────────────────
/// Derive a 32-byte key from a semantic manifold coordinate vector.
///
/// Port of `ENESecurityManager.derive_key_from_semantic` in `ene_api.py`.
///
/// * Each component is clamped to \[0, 1\] then scaled to 0xFFFF_FFFF.
/// * All scaled integers are XOR-folded into a single u32.
/// * Golden-ratio mixing step: `mixed = base_key.wrapping_mul(0x9E37_79B9)`.
/// * Final key: SHA-256 of the 4-byte big-endian mixed value.
pub fn derive_key_from_semantic(semantic_vector: &[f64]) -> [u8; 32] {
let mut base_key: u32 = 0;
for &v in semantic_vector {
let clamped = v.clamp(0.0, 1.0);
let scaled = (clamped * 0xFFFF_FFFFu64 as f64) as u32;
base_key ^= scaled;
}
let mixed: u32 = base_key.wrapping_mul(0x9E37_79B9);
sha256_bytes(&mixed.to_be_bytes())
}
// ── deterministic nonce ───────────────────────────────────────────────
/// Build a 12-byte AES-GCM nonce deterministically from the current
/// nanosecond timestamp and a context slice (pkg name, cache key, etc.).
///
/// Because `rand` is not a declared dependency we avoid `OsRng`. The
/// timestamp component ensures distinct nonces across calls separated by
/// at least 1 ns; the context component ensures distinct nonces within
/// the same nanosecond for different payloads.
fn make_nonce(context: &[u8]) -> [u8; 12] {
let ts = now_nanos().to_be_bytes(); // 8 bytes
let digest = sha256_bytes(&[ts.as_slice(), context].concat());
let mut nonce = [0u8; 12];
nonce.copy_from_slice(&digest[..12]);
nonce
}
// ── encrypt / decrypt ─────────────────────────────────────────────────
/// Encrypt `plaintext` under the instance key with AES-256-GCM.
///
/// Returns a JSON object: `{ciphertext: <b64>, nonce: <b64>, aad: <b64>}`.
///
/// `aad` is bound into the GCM tag — any tampering with it causes
/// decryption to fail.
pub fn encrypt(&self, plaintext: &[u8], aad: &[u8]) -> anyhow::Result<serde_json::Value> {
let key = Key::<Aes256Gcm>::from_slice(&self.encryption_key);
let cipher = Aes256Gcm::new(key);
let nonce_bytes = Self::make_nonce(plaintext.get(..4.min(plaintext.len())).unwrap_or(&[]));
let nonce = Nonce::from_slice(&nonce_bytes);
// aes-gcm 0.10 Aead::encrypt_in_place_detached takes optional AAD via
// the Payload wrapper. We use the convenience encrypt(nonce, payload)
// form which bundles AAD through aes_gcm::aead::Payload.
let ciphertext = cipher
.encrypt(
nonce,
aes_gcm::aead::Payload { msg: plaintext, aad },
)
.map_err(|e| anyhow!("AES-GCM encrypt error: {}", e))?;
Ok(serde_json::json!({
"ciphertext": B64.encode(&ciphertext),
"nonce": B64.encode(&nonce_bytes),
"aad": B64.encode(aad),
}))
}
/// Encrypt with a caller-supplied key instead of the instance key.
fn encrypt_with_key(
key_bytes: &[u8; 32],
plaintext: &[u8],
aad: &[u8],
) -> anyhow::Result<serde_json::Value> {
let key = Key::<Aes256Gcm>::from_slice(key_bytes);
let cipher = Aes256Gcm::new(key);
let nonce_bytes = Self::make_nonce(plaintext.get(..4.min(plaintext.len())).unwrap_or(&[]));
let nonce = Nonce::from_slice(&nonce_bytes);
let ciphertext = cipher
.encrypt(
nonce,
aes_gcm::aead::Payload { msg: plaintext, aad },
)
.map_err(|e| anyhow!("AES-GCM encrypt error: {}", e))?;
Ok(serde_json::json!({
"ciphertext": B64.encode(&ciphertext),
"nonce": B64.encode(&nonce_bytes),
"aad": B64.encode(aad),
}))
}
/// Decrypt a ciphertext envelope produced by [`encrypt`].
///
/// `aad` must match what was used during encryption; it is cross-checked
/// against the `aad` field stored in the envelope.
pub fn decrypt(&self, envelope: &serde_json::Value, aad: &[u8]) -> anyhow::Result<Vec<u8>> {
Self::decrypt_with_key(&self.encryption_key, envelope, aad)
}
fn decrypt_with_key(
key_bytes: &[u8; 32],
envelope: &serde_json::Value,
aad: &[u8],
) -> anyhow::Result<Vec<u8>> {
let ct_b64 = envelope["ciphertext"]
.as_str()
.ok_or_else(|| anyhow!("envelope missing 'ciphertext'"))?;
let nonce_b64 = envelope["nonce"]
.as_str()
.ok_or_else(|| anyhow!("envelope missing 'nonce'"))?;
let ciphertext = B64.decode(ct_b64).context("base64-decode ciphertext")?;
let nonce_bytes = B64.decode(nonce_b64).context("base64-decode nonce")?;
if nonce_bytes.len() != 12 {
return Err(anyhow!("nonce must be 12 bytes, got {}", nonce_bytes.len()));
}
// Prefer AAD from the envelope; fall back to the caller-supplied value.
let aad_effective: Vec<u8> = if let Some(aad_b64) = envelope["aad"].as_str() {
B64.decode(aad_b64).context("base64-decode aad")?
} else {
aad.to_vec()
};
let key = Key::<Aes256Gcm>::from_slice(key_bytes);
let cipher = Aes256Gcm::new(key);
let nonce = Nonce::from_slice(&nonce_bytes);
let plaintext = cipher
.decrypt(
nonce,
aes_gcm::aead::Payload {
msg: &ciphertext,
aad: &aad_effective,
},
)
.map_err(|e| anyhow!("AES-GCM decrypt error: {}", e))?;
Ok(plaintext)
}
// ── integrity / access ────────────────────────────────────────────────
/// Compute the SHA-256 hex digest of `data` — used as an integrity hash
/// stored alongside encrypted payloads.
pub fn integrity_hash(data: &[u8]) -> String {
sha256_hex(data)
}
/// Return `true` iff `clearance` is sufficient to read data classified at
/// `classification`.
///
/// Mirrors `ENESecurityManager.check_access` in `ene_api.py`.
pub fn check_access(clearance: AccessLevel, classification: AccessLevel) -> bool {
clearance >= classification
}
}
impl Default for ENESecurityManager {
fn default() -> Self {
Self::new()
}
}
// ─── §3 ENEAPIHook ───────────────────────────────────────────────────────────
/// SQLite-backed ENE API hook for storing and retrieving encrypted sensitive
/// data.
///
/// Mirrors `ENEAPIHook` in `ene_api.py`.
pub struct ENEAPIHook {
pub db_path: PathBuf,
security: ENESecurityManager,
}
impl ENEAPIHook {
/// Open (or create) the SQLite database at `db_path` and initialise the
/// `sensitive_data` table.
pub fn new(db_path: impl AsRef<Path>) -> anyhow::Result<Self> {
let hook = Self {
db_path: db_path.as_ref().to_path_buf(),
security: ENESecurityManager::new(),
};
hook.init_tables()?;
Ok(hook)
}
fn connect(&self) -> anyhow::Result<Connection> {
Connection::open(&self.db_path).context("open SQLite for ENEAPIHook")
}
/// Create the `sensitive_data` table if it does not already exist.
fn init_tables(&self) -> anyhow::Result<()> {
let conn = self.connect()?;
conn.execute_batch(
"CREATE TABLE IF NOT EXISTS sensitive_data (
id TEXT PRIMARY KEY,
pkg TEXT NOT NULL,
encrypted_payload TEXT NOT NULL,
nonce TEXT NOT NULL,
classification INTEGER NOT NULL,
integrity_hash TEXT NOT NULL,
created_at INTEGER NOT NULL,
access_log TEXT
);",
)
.context("create sensitive_data table")?;
Ok(())
}
// ── store ─────────────────────────────────────────────────────────────
/// Encrypt `payload` and insert or replace it in the `sensitive_data`
/// table.
///
/// If `semantic_vector` is supplied the key is derived from it; otherwise
/// the instance key is used.
///
/// Returns the `data_id` (SHA-256 hex of `pkg || timestamp`).
pub fn store_sensitive_data(
&self,
pkg: &str,
payload: &str,
classification: AccessLevel,
semantic_vector: Option<&[f64]>,
) -> anyhow::Result<String> {
let now = now_secs();
let data_id = sha256_hex(format!("{}{}", pkg, now).as_bytes());
let integrity = ENESecurityManager::integrity_hash(payload.as_bytes());
let envelope = if let Some(sv) = semantic_vector {
let derived_key = ENESecurityManager::derive_key_from_semantic(sv);
ENESecurityManager::encrypt_with_key(&derived_key, payload.as_bytes(), pkg.as_bytes())?
} else {
self.security.encrypt(payload.as_bytes(), pkg.as_bytes())?
};
let ciphertext_b64 = envelope["ciphertext"]
.as_str()
.ok_or_else(|| anyhow!("encrypt returned no ciphertext"))?
.to_string();
let nonce_b64 = envelope["nonce"]
.as_str()
.ok_or_else(|| anyhow!("encrypt returned no nonce"))?
.to_string();
let access_log = serde_json::json!({
"action": "store",
"timestamp": now,
})
.to_string();
let conn = self.connect()?;
conn.execute(
"INSERT OR REPLACE INTO sensitive_data
(id, pkg, encrypted_payload, nonce, classification, integrity_hash, created_at, access_log)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)",
params![
data_id,
pkg,
ciphertext_b64,
nonce_b64,
classification.as_u8() as i64,
integrity,
now,
access_log,
],
)
.context("INSERT sensitive_data")?;
Ok(data_id)
}
// ── retrieve ──────────────────────────────────────────────────────────
/// Retrieve and decrypt a row by `data_id`.
///
/// Returns `None` if the id does not exist. Returns an error if the
/// clearance is insufficient or decryption / integrity check fails.
///
/// Also appends to the `access_log` column on each successful retrieval.
pub fn retrieve_sensitive_data(
&self,
data_id: &str,
clearance: AccessLevel,
) -> anyhow::Result<Option<String>> {
let conn = self.connect()?;
let result: Option<(String, String, String, i64, String, Option<String>)> = {
let mut stmt = conn.prepare(
"SELECT encrypted_payload, nonce, pkg, classification, integrity_hash, access_log
FROM sensitive_data WHERE id = ?1",
)?;
stmt.query_row(params![data_id], |row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, String>(2)?,
row.get::<_, i64>(3)?,
row.get::<_, String>(4)?,
row.get::<_, Option<String>>(5)?,
))
})
.optional()
.context("query sensitive_data by id")?
};
let (enc_payload, nonce, pkg, class_int, stored_hash, access_log_raw) = match result {
Some(row) => row,
None => return Ok(None),
};
let classification = AccessLevel::from_u8(class_int as u8);
if !ENESecurityManager::check_access(clearance, classification) {
return Err(anyhow!(
"Access denied: clearance {:?} insufficient for {:?}",
clearance,
classification
));
}
// Reconstruct the envelope that decrypt() expects.
let envelope = serde_json::json!({
"ciphertext": enc_payload,
"nonce": nonce,
});
// Use pkg as AAD — matches what store_sensitive_data passed to encrypt.
let plaintext_bytes = self.security.decrypt(&envelope, pkg.as_bytes())?;
let plaintext = String::from_utf8(plaintext_bytes)
.context("decrypted data is not valid UTF-8")?;
// Integrity check.
let computed = ENESecurityManager::integrity_hash(plaintext.as_bytes());
if computed != stored_hash {
return Err(anyhow!("Integrity check failed for data_id={}", data_id));
}
// Append access log entry.
let now = now_secs();
let mut log: serde_json::Value = access_log_raw
.as_deref()
.and_then(|s| serde_json::from_str(s).ok())
.unwrap_or_else(|| serde_json::json!([]));
if let Some(arr) = log.as_array_mut() {
arr.push(serde_json::json!({ "action": "retrieve", "timestamp": now }));
} else {
log = serde_json::json!([
log,
{ "action": "retrieve", "timestamp": now }
]);
}
conn.execute(
"UPDATE sensitive_data SET access_log = ?1 WHERE id = ?2",
params![log.to_string(), data_id],
)
.context("update access_log")?;
Ok(Some(plaintext))
}
// ── list ──────────────────────────────────────────────────────────────
/// Return a list of `{id, pkg, classification, created_at}` objects for all
/// rows whose classification ≤ `clearance`.
pub fn list_sensitive_data(
&self,
clearance: AccessLevel,
) -> anyhow::Result<Vec<serde_json::Value>> {
let conn = self.connect()?;
let mut stmt = conn.prepare(
"SELECT id, pkg, classification, created_at
FROM sensitive_data
ORDER BY created_at DESC",
)?;
let rows = stmt
.query_map([], |row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, String>(1)?,
row.get::<_, i64>(2)?,
row.get::<_, i64>(3)?,
))
})?
.filter_map(|r| r.ok())
.filter(|(_, _, class_int, _)| {
let classification = AccessLevel::from_u8(*class_int as u8);
ENESecurityManager::check_access(clearance, classification)
})
.map(|(id, pkg, class_int, created_at)| {
serde_json::json!({
"id": id,
"pkg": pkg,
"classification": class_int,
"created_at": created_at,
})
})
.collect();
Ok(rows)
}
}
// ─── §4 ExpertConfiguration ──────────────────────────────────────────────────
/// Full parameter set for a single MoE expert.
///
/// Mirrors `ExpertConfiguration` in `moe_ene_cache.py`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExpertConfiguration {
/// Unique expert index.
pub expert_id: i64,
/// Gating weight *g*.
pub gating_weight: f64,
/// Quality weight *w*.
pub quality_weight: f64,
/// Coherence *h*.
pub coherence: f64,
/// Penalty weight *v*.
pub penalty_weight: f64,
/// Distortion *p*.
pub distortion: f64,
/// Arity *N*.
pub arity: f64,
/// Cost coefficient *a*.
pub cost_coefficient: f64,
/// Overhead *c*.
pub overhead: f64,
/// 14-D semantic manifold coordinate.
pub semantic_vector: Vec<f64>,
/// Domain string (e.g. `"neural_manifold"`).
pub domain: String,
/// Semver version string.
pub version: String,
}
// ─── §5 MoECacheEntry ────────────────────────────────────────────────────────
/// A single cached MoE computation result.
///
/// Mirrors `MoECacheEntry` in `moe_ene_cache.py`.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MoECacheEntry {
/// Hash-based lookup key.
pub cache_key: String,
/// Which experts contributed to this result.
pub expert_ids: Vec<i64>,
/// η_MoE scalar output.
pub eta_moe_result: f64,
/// Discarded information fraction *I*.
pub i_discarded: f64,
/// UNIX timestamp of this computation (seconds).
pub timestamp: i64,
/// Semantic manifold coordinate used for this computation.
pub semantic_vector: Vec<f64>,
/// Confidence in [0, 1].
pub confidence: f64,
}
// ─── §6 MoEENECache ──────────────────────────────────────────────────────────
/// SQLite-backed Mixture-of-Experts cache.
///
/// Mirrors `MoEENECache` in `moe_ene_cache.py`.
pub struct MoEENECache {
pub db_path: PathBuf,
}
impl MoEENECache {
// ── construction ─────────────────────────────────────────────────────
/// Open (or create) the SQLite database at `db_path` and initialise all
/// MoE cache tables.
pub fn new(db_path: impl AsRef<Path>) -> anyhow::Result<Self> {
let cache = Self {
db_path: db_path.as_ref().to_path_buf(),
};
cache.init_tables()?;
Ok(cache)
}
fn connect(&self) -> anyhow::Result<Connection> {
Connection::open(&self.db_path).context("open SQLite for MoEENECache")
}
// ── schema ────────────────────────────────────────────────────────────
/// Create the three MoE tables if they do not already exist.
///
/// Tables:
/// * `moe_expert_cache` — per-expert configuration rows.
/// * `moe_computation_cache` — cached η_MoE computation results.
/// * `moe_rewiring_audit` — rewiring proposals with swarm consensus.
fn init_tables(&self) -> anyhow::Result<()> {
let conn = self.connect()?;
conn.execute_batch(
"CREATE TABLE IF NOT EXISTS moe_expert_cache (
expert_id INTEGER PRIMARY KEY,
domain TEXT NOT NULL,
config_json TEXT NOT NULL,
semantic_vector TEXT NOT NULL,
version TEXT NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
cache_hit_count INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS moe_computation_cache (
cache_key TEXT PRIMARY KEY,
expert_ids TEXT NOT NULL,
eta_moe_result REAL NOT NULL,
i_discarded REAL NOT NULL,
semantic_vector TEXT NOT NULL,
confidence REAL NOT NULL,
created_at INTEGER NOT NULL,
hit_count INTEGER NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS moe_rewiring_audit (
id TEXT PRIMARY KEY,
expert_id INTEGER NOT NULL,
proposal_json TEXT NOT NULL,
swarm_consensus REAL NOT NULL,
proposing_agent TEXT NOT NULL,
approved INTEGER NOT NULL DEFAULT 0,
created_at INTEGER NOT NULL
);",
)
.context("create MoE cache tables")?;
Ok(())
}
// ── expert configuration ──────────────────────────────────────────────
/// Persist an expert configuration (INSERT OR REPLACE).
pub fn cache_expert_config(&self, config: &ExpertConfiguration) -> anyhow::Result<()> {
let now = now_secs();
let config_json =
serde_json::to_string(config).context("serialize ExpertConfiguration")?;
let semantic_json =
serde_json::to_string(&config.semantic_vector).context("serialize semantic_vector")?;
let conn = self.connect()?;
conn.execute(
"INSERT OR REPLACE INTO moe_expert_cache
(expert_id, domain, config_json, semantic_vector, version, created_at, updated_at)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
params![
config.expert_id,
config.domain,
config_json,
semantic_json,
config.version,
now,
now,
],
)
.context("INSERT moe_expert_cache")?;
debug!("cached expert_id={}", config.expert_id);
Ok(())
}
/// Retrieve an expert configuration by id, incrementing the hit counter.
pub fn retrieve_expert_config(
&self,
expert_id: i64,
) -> anyhow::Result<Option<ExpertConfiguration>> {
let conn = self.connect()?;
let result: Option<String> = {
let mut stmt = conn
.prepare("SELECT config_json FROM moe_expert_cache WHERE expert_id = ?1")?;
stmt.query_row(params![expert_id], |row| row.get(0))
.optional()
.context("query moe_expert_cache")?
};
if let Some(config_json) = result {
conn.execute(
"UPDATE moe_expert_cache SET cache_hit_count = cache_hit_count + 1 WHERE expert_id = ?1",
params![expert_id],
)
.context("increment cache_hit_count")?;
let config: ExpertConfiguration =
serde_json::from_str(&config_json).context("deserialize ExpertConfiguration")?;
Ok(Some(config))
} else {
Ok(None)
}
}
// ── computation results ───────────────────────────────────────────────
/// Persist a computation result (INSERT OR REPLACE).
pub fn cache_computation_result(&self, entry: &MoECacheEntry) -> anyhow::Result<()> {
let expert_ids_json =
serde_json::to_string(&entry.expert_ids).context("serialize expert_ids")?;
let semantic_json =
serde_json::to_string(&entry.semantic_vector).context("serialize semantic_vector")?;
let conn = self.connect()?;
conn.execute(
"INSERT OR REPLACE INTO moe_computation_cache
(cache_key, expert_ids, eta_moe_result, i_discarded, semantic_vector, confidence, created_at)
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)",
params![
entry.cache_key,
expert_ids_json,
entry.eta_moe_result,
entry.i_discarded,
semantic_json,
entry.confidence,
entry.timestamp,
],
)
.context("INSERT moe_computation_cache")?;
debug!("cached computation key={}", entry.cache_key);
Ok(())
}
/// Retrieve a cached computation result by key, incrementing the hit count.
pub fn retrieve_computation_result(
&self,
cache_key: &str,
) -> anyhow::Result<Option<MoECacheEntry>> {
let conn = self.connect()?;
type Row = (String, f64, f64, String, f64, i64);
let result: Option<Row> = {
let mut stmt = conn.prepare(
"SELECT expert_ids, eta_moe_result, i_discarded, semantic_vector, confidence, created_at
FROM moe_computation_cache WHERE cache_key = ?1",
)?;
stmt.query_row(params![cache_key], |row| {
Ok((
row.get::<_, String>(0)?,
row.get::<_, f64>(1)?,
row.get::<_, f64>(2)?,
row.get::<_, String>(3)?,
row.get::<_, f64>(4)?,
row.get::<_, i64>(5)?,
))
})
.optional()
.context("query moe_computation_cache")?
};
if let Some((expert_ids_json, eta, i_disc, semantic_json, conf, created_at)) = result {
conn.execute(
"UPDATE moe_computation_cache SET hit_count = hit_count + 1 WHERE cache_key = ?1",
params![cache_key],
)
.context("increment hit_count")?;
let expert_ids: Vec<i64> =
serde_json::from_str(&expert_ids_json).context("deserialize expert_ids")?;
let semantic_vector: Vec<f64> =
serde_json::from_str(&semantic_json).context("deserialize semantic_vector")?;
Ok(Some(MoECacheEntry {
cache_key: cache_key.to_string(),
expert_ids,
eta_moe_result: eta,
i_discarded: i_disc,
timestamp: created_at,
semantic_vector,
confidence: conf,
}))
} else {
Ok(None)
}
}
// ── rewiring audit ────────────────────────────────────────────────────
/// Append a rewiring proposal to the audit log.
///
/// The proposal is marked `approved = false` (pending). Returns the
/// generated proposal id (`"rewire_{expert_id}_{timestamp}"`).
pub fn log_rewiring_proposal(
&self,
expert_id: i64,
proposal: &serde_json::Value,
swarm_consensus: f64,
proposing_agent: &str,
) -> anyhow::Result<String> {
let now = now_secs();
let proposal_id = format!("rewire_{}_{}", expert_id, now);
let proposal_json =
serde_json::to_string(proposal).context("serialize rewiring proposal")?;
let conn = self.connect()?;
conn.execute(
"INSERT INTO moe_rewiring_audit
(id, expert_id, proposal_json, swarm_consensus, proposing_agent, approved, created_at)
VALUES (?1, ?2, ?3, ?4, ?5, 0, ?6)",
params![
proposal_id,
expert_id,
proposal_json,
swarm_consensus,
proposing_agent,
now,
],
)
.context("INSERT moe_rewiring_audit")?;
debug!(
"logged rewiring proposal {} for expert_id={} consensus={:.3}",
proposal_id, expert_id, swarm_consensus
);
Ok(proposal_id)
}
// ── statistics ────────────────────────────────────────────────────────
/// Return cache statistics as a JSON value.
///
/// ```json
/// {
/// "expert_cache_entries": <i64>,
/// "expert_cache_hits": <i64>,
/// "computation_cache_entries":<i64>,
/// "computation_cache_hits": <i64>,
/// "rewiring_proposals": <i64>
/// }
/// ```
pub fn get_cache_statistics(&self) -> anyhow::Result<serde_json::Value> {
let conn = self.connect()?;
let (expert_count, expert_hits): (i64, i64) = conn
.query_row(
"SELECT COUNT(*), COALESCE(SUM(cache_hit_count), 0) FROM moe_expert_cache",
[],
|row| Ok((row.get(0)?, row.get(1)?)),
)
.context("query moe_expert_cache stats")?;
let (comp_count, comp_hits): (i64, i64) = conn
.query_row(
"SELECT COUNT(*), COALESCE(SUM(hit_count), 0) FROM moe_computation_cache",
[],
|row| Ok((row.get(0)?, row.get(1)?)),
)
.context("query moe_computation_cache stats")?;
let audit_count: i64 = conn
.query_row(
"SELECT COUNT(*) FROM moe_rewiring_audit",
[],
|row| row.get(0),
)
.context("query moe_rewiring_audit count")?;
Ok(serde_json::json!({
"expert_cache_entries": expert_count,
"expert_cache_hits": expert_hits,
"computation_cache_entries": comp_count,
"computation_cache_hits": comp_hits,
"rewiring_proposals": audit_count,
}))
}
}
// ─── tests ───────────────────────────────────────────────────────────────────
#[cfg(test)]
mod tests {
use super::*;
// ── AccessLevel ordering ──────────────────────────────────────────────
#[test]
fn access_level_ordering() {
assert!(AccessLevel::Secret > AccessLevel::Restricted);
assert!(AccessLevel::Restricted > AccessLevel::Internal);
assert!(AccessLevel::Internal > AccessLevel::Public);
}
#[test]
fn check_access_boundary() {
assert!(ENESecurityManager::check_access(
AccessLevel::Secret,
AccessLevel::Restricted
));
assert!(!ENESecurityManager::check_access(
AccessLevel::Public,
AccessLevel::Internal
));
assert!(ENESecurityManager::check_access(
AccessLevel::Restricted,
AccessLevel::Restricted
));
}
// ── key derivation ────────────────────────────────────────────────────
#[test]
fn derive_key_from_semantic_deterministic() {
let sv = vec![0.5, 0.3, 0.7, 0.2];
let k1 = ENESecurityManager::derive_key_from_semantic(&sv);
let k2 = ENESecurityManager::derive_key_from_semantic(&sv);
assert_eq!(k1, k2);
assert_ne!(k1, [0u8; 32]);
}
#[test]
fn derive_key_from_semantic_sensitive_to_input() {
let k1 = ENESecurityManager::derive_key_from_semantic(&[0.1, 0.2]);
let k2 = ENESecurityManager::derive_key_from_semantic(&[0.1, 0.3]);
assert_ne!(k1, k2);
}
// ── integrity hash ────────────────────────────────────────────────────
#[test]
fn integrity_hash_known_value() {
// SHA-256("") = e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
let h = ENESecurityManager::integrity_hash(b"");
assert_eq!(
h,
"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
);
}
// ── round-trip encrypt / decrypt ──────────────────────────────────────
#[test]
fn encrypt_decrypt_roundtrip() {
let mgr = ENESecurityManager::new();
let plaintext = b"hello ENE world";
let aad = b"test-aad";
let envelope = mgr.encrypt(plaintext, aad).expect("encrypt");
let recovered = mgr.decrypt(&envelope, aad).expect("decrypt");
assert_eq!(recovered, plaintext);
}
#[test]
fn decrypt_rejects_wrong_aad() {
let mgr = ENESecurityManager::new();
let plaintext = b"secret payload";
let envelope = mgr.encrypt(plaintext, b"correct-aad").expect("encrypt");
// Tamper: remove the stored aad so decrypt falls back to caller-supplied.
let mut env2 = envelope.clone();
env2.as_object_mut().unwrap().remove("aad");
// With the wrong aad the GCM tag check must fail.
let result = mgr.decrypt(&env2, b"wrong-aad");
assert!(result.is_err());
}
// ── SQLite ENEAPIHook ─────────────────────────────────────────────────
fn tmp_db(name: &str) -> PathBuf {
let mut p = std::env::temp_dir();
p.push(format!("ene_core_test_{}_{}.db", std::process::id(), name));
// Remove stale file from a previous run so tests are hermetic.
let _ = std::fs::remove_file(&p);
p
}
#[test]
fn ene_api_hook_store_retrieve() {
let db_path = tmp_db("api_hook_store_retrieve");
let hook = ENEAPIHook::new(&db_path).unwrap();
let id = hook
.store_sensitive_data(
"test/pkg",
"TOP SECRET PAYLOAD",
AccessLevel::Secret,
None,
)
.unwrap();
// Retrieve with sufficient clearance.
let payload = hook
.retrieve_sensitive_data(&id, AccessLevel::Secret)
.unwrap()
.expect("should find row");
assert_eq!(payload, "TOP SECRET PAYLOAD");
// Insufficient clearance should error.
let err = hook.retrieve_sensitive_data(&id, AccessLevel::Public);
assert!(err.is_err());
}
#[test]
fn ene_api_hook_list_filters_by_clearance() {
let db_path = tmp_db("api_hook_list");
let hook = ENEAPIHook::new(&db_path).unwrap();
hook.store_sensitive_data("a/pkg", "public data", AccessLevel::Public, None)
.unwrap();
hook.store_sensitive_data("b/pkg", "secret data", AccessLevel::Secret, None)
.unwrap();
let public_view = hook.list_sensitive_data(AccessLevel::Public).unwrap();
// Public clearance should only see Public-classified rows.
assert_eq!(public_view.len(), 1);
let secret_view = hook.list_sensitive_data(AccessLevel::Secret).unwrap();
assert_eq!(secret_view.len(), 2);
}
// ── MoEENECache ───────────────────────────────────────────────────────
fn sample_config(id: i64) -> ExpertConfiguration {
ExpertConfiguration {
expert_id: id,
gating_weight: 0.7,
quality_weight: 0.8,
coherence: 0.9,
penalty_weight: 0.1,
distortion: 0.05,
arity: 5.0,
cost_coefficient: 0.02,
overhead: 0.01,
semantic_vector: vec![
0.5, 0.3, 0.7, 0.2, 0.1, 0.4, 0.6, 0.8, 0.2, 0.3, 0.5, 0.7, 0.1, 0.4,
],
domain: "neural_manifold".into(),
version: "1.0.0".into(),
}
}
#[test]
fn moe_cache_expert_roundtrip() {
let dir = tempfile::tempdir().unwrap();
let cache = MoEENECache::new(dir.path().join("moe.db")).unwrap();
let cfg = sample_config(42);
cache.cache_expert_config(&cfg).unwrap();
let retrieved = cache.retrieve_expert_config(42).unwrap().unwrap();
assert_eq!(retrieved.expert_id, 42);
assert!((retrieved.gating_weight - 0.7).abs() < 1e-9);
assert_eq!(retrieved.domain, "neural_manifold");
}
#[test]
fn moe_cache_computation_roundtrip() {
let dir = tempfile::tempdir().unwrap();
let cache = MoEENECache::new(dir.path().join("moe.db")).unwrap();
let entry = MoECacheEntry {
cache_key: "eta_moe_test_001".into(),
expert_ids: vec![1, 2, 3],
eta_moe_result: 0.85,
i_discarded: 0.1,
timestamp: now_secs(),
semantic_vector: vec![0.5, 0.3, 0.7],
confidence: 0.95,
};
cache.cache_computation_result(&entry).unwrap();
let r = cache
.retrieve_computation_result("eta_moe_test_001")
.unwrap()
.unwrap();
assert!((r.eta_moe_result - 0.85).abs() < 1e-9);
assert_eq!(r.expert_ids, vec![1, 2, 3]);
}
#[test]
fn moe_cache_statistics() {
let dir = tempfile::tempdir().unwrap();
let cache = MoEENECache::new(dir.path().join("moe.db")).unwrap();
cache.cache_expert_config(&sample_config(1)).unwrap();
cache.cache_expert_config(&sample_config(2)).unwrap();
cache.retrieve_expert_config(1).unwrap();
cache.retrieve_expert_config(1).unwrap();
let stats = cache.get_cache_statistics().unwrap();
assert_eq!(stats["expert_cache_entries"], 2);
assert_eq!(stats["expert_cache_hits"], 2);
}
#[test]
fn moe_rewiring_audit_log() {
let dir = tempfile::tempdir().unwrap();
let cache = MoEENECache::new(dir.path().join("moe.db")).unwrap();
let proposal = serde_json::json!({ "action": "swap", "target": 3 });
let pid = cache
.log_rewiring_proposal(7, &proposal, 0.82, "swarm_agent_1")
.unwrap();
assert!(pid.starts_with("rewire_7_"));
let stats = cache.get_cache_statistics().unwrap();
assert_eq!(stats["rewiring_proposals"], 1);
}
}