Files
ruvnet--RuView/rust-port/wifi-densepose-rs/crates/ruv-neural/SECURITY_REVIEW.md
T
rUv 341d9e05a8 ruv-neural: publish 11 crates to crates.io — full implementation, no stubs
* Add temporal graph evolution & RuVector integration research

GOAP Agent 8 output: 1,528-line SOTA research document covering temporal
graph models (TGN, JODIE, DyRep), RuVector graph memory design, mincut
trajectory tracking with Kalman filtering, event detection pipelines,
compressed temporal storage, cross-room transition graphs, and a 5-phase
integration roadmap.

Part of RF Topological Sensing research swarm (10 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add transformer architectures for graph sensing research

GOAP Agent 4 output: 896-line SOTA document covering Graph Transformers
(Graphormer, SAN, GPS, TokenGT), Temporal Graph Transformers (TGN, TGAT,
DyRep), ViT for RF spectrograms, transformer-based mincut prediction,
positional encoding for RF graphs, foundation models for RF sensing, and
efficient edge deployment with INT8 quantization.

Part of RF Topological Sensing research swarm (10 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add attention mechanisms for RF sensing research

GOAP Agent 3 output: 1,110-line document covering GAT for RF graphs,
self-attention for CSI sequences, cross-attention multi-link fusion,
attention-weighted differentiable mincut, spatial node attention,
antenna-level subcarrier attention, and efficient attention variants
(linear, sparse, LSH, S4/Mamba). 8 ASCII architecture diagrams.

Part of RF Topological Sensing research swarm (10 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add sublinear mincut algorithms research

GOAP Agent 5 output: 698-line document covering classical mincut complexity,
sublinear approximation (sampling, sparsifiers), dynamic mincut with lazy
recomputation hybrid, streaming sketch algorithms, Benczur-Karger
sparsification, local partitioning (PageRank-guided cuts), randomized
methods reliability analysis, and Rust implementation with const-generic
RfGraph, zero-alloc Stoer-Wagner, SIMD batch updates.

Part of RF Topological Sensing research swarm (10 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add CSI edge weight computation research

GOAP Agent 2 output: ~700-line document covering CSI feature extraction,
coherence metrics (cross-correlation, mutual information, phasor coherence),
multipath stability scoring (MUSIC, ESPRIT, ISTA), temporal windowing
(EMA, Welford, Kalman), noise robustness (phase noise, AGC, clock drift),
edge weight normalization, and implementation architecture showing 32KB
memory for 120 edges within ESP32-S3 capability.

Part of RF Topological Sensing research swarm (10 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add contrastive learning for RF coherence research

GOAP Agent 7 output: 1,226-line document covering SimCLR/MoCo/BYOL for CSI,
AETHER-Topo dual-head extension, coherence boundary detection with multi-scale
analysis, delta-driven updates (2-12x efficiency), self-supervised pre-training
protocol, triplet networks for 5-state edge classification, and MERIDIAN
cross-environment transfer with EWC continual learning.

Part of RF Topological Sensing research swarm (12 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add resolution and spatial granularity analysis research

GOAP Agent 9 output: 1,383-line document covering Fresnel zone analysis,
node density vs resolution (16-node/5m room → 30-60cm), Cramer-Rao lower
bounds with Fisher Information Matrix, graph cut resolution theory,
multi-frequency enhancement (6cm coherent dual-band limit), RF tomography
comparison, experimental validation protocols, and resolution scaling laws
(8.8cm theoretical limit).

Part of RF Topological Sensing research swarm (12 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add RF graph theory and minimum cut foundations research

GOAP Agent 1 output: Graph-theoretic foundations covering max-flow/min-cut
for RF (Ford-Fulkerson, Stoer-Wagner, Karger), RF as dynamic graph with
CSI coherence weights, topological change detection via Fiedler vector and
Cheeger inequality, dynamic graph algorithms, comparison to classical RF
sensing, formal mathematical framework, and 9 open research questions.

Part of RF Topological Sensing research swarm (12 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add ESP32 mesh hardware constraints research

GOAP Agent 6 output: ESP32 CSI capabilities (52/114 subcarriers), 16-node
mesh topology with 120 edges, TDM synchronized sensing (3ms slots),
computational budget (Stoer-Wagner uses 0.07% of one core), channel hopping,
power analysis (0.44W/node), dual-core firmware architecture, and edge vs
server computing with 100x data reduction on-device.

Part of RF Topological Sensing research swarm (12 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add system architecture and prototype design research

GOAP Agent 10 output: End-to-end architecture with pipeline diagrams,
existing crate integration mapping, new rf_topology module design (DDD
aggregate roots), 100ms latency budget breakdown, 3-phase prototype plan
(4-node POC → 16-node room → 72-node multi-room), benchmark design with
8 metrics, ADR-044 draft, and Rust trait definitions (EdgeWeightComputer,
TopologyGraph, MinCutSolver, BoundaryInterpolator).

Part of RF Topological Sensing research swarm (12 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add quantum sensing and quantum biomedical research documents

Agent 11: Quantum-level sensors (729 lines) — NV centers, SQUIDs, Rydberg
atoms, quantum illumination, quantum graph theory (walks, spectral, QAOA),
hybrid classical-quantum architecture, quantum ML (VQC, kernels, reservoir
computing), NISQ applications (D-Wave, VQE), hardware roadmap.

Agent 12: Quantum biomedical sensing (827 lines) — whole body biomagnetic
mapping, neural field imaging without electrodes, circulation sensing,
cellular EM signaling, non-contact diagnostics, coherence-based diagnostics
(disease as coherence breakdown), neural interfaces, multimodal observatory,
room-scale ambient health monitoring, graph-based biomedical analysis.

Part of RF Topological Sensing research swarm (12 agents).

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add research index synthesizing all 12 documents (14,322 lines)

Master index for RF Topological Sensing research compendium covering:
graph theory foundations, CSI edge weights, attention mechanisms,
transformers, sublinear algorithms, ESP32 hardware, contrastive learning,
temporal graphs, resolution analysis, system architecture, quantum sensors,
and quantum biomedical sensing. Includes key findings, proposed ADRs
(044, 045), and 5-phase implementation roadmap.

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add SOTA neural decoding landscape and 10 application domains research

- Doc 21: Comprehensive SOTA map (2023-2026) of brain sensors, decoders,
  and visualization systems with RuVector/mincut positioning analysis
- Doc 22: Ten application domains for brain state observatory including
  disease detection, BCI, cognitive monitoring, mental health diagnostics,
  neurofeedback, dream reconstruction, cognitive research, HCI, wearables,
  and brain network digital twins with strategic roadmap

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add NV diamond neural magnetometry research document (13/22)

Comprehensive 600+ line document covering NV center physics, neural
magnetic field sources, sensor architecture, SQUID comparison, signal
processing pipeline, RuVector integration, and development roadmap.

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add ruv-neural workspace Cargo.toml with 12 crate definitions

Workspace structure for the rUv Neural brain topology analysis system.
12 mix-and-match crates with shared dependencies including RuVector
integration, petgraph, rustfft, and WASM/ESP32 support.

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add ruv-neural crate ecosystem — 12 mix-and-match crates (WIP)

Initial implementation of the rUv Neural brain topology analysis system:
- ruv-neural-core: Core types, traits, errors, RVF format (compiles)
- ruv-neural-sensor: NV diamond, OPM, EEG sensor interfaces (in progress)
- ruv-neural-signal: DSP, filtering, spectral, connectivity (in progress)
- ruv-neural-graph: Brain connectivity graph construction (in progress)
- ruv-neural-mincut: Dynamic minimum cut topology analysis (in progress)
- ruv-neural-embed: RuVector graph embeddings (in progress)
- ruv-neural-memory: Persistent neural state memory + HNSW (compiles)
- ruv-neural-decoder: Cognitive state classification + BCI (in progress)
- ruv-neural-esp32: ESP32 edge sensor integration (compiles)
- ruv-neural-wasm: WebAssembly browser bindings (in progress)
- ruv-neural-viz: Visualization + ASCII rendering (in progress)
- ruv-neural-cli: CLI tool (in progress)

Agents still writing remaining modules. Next: fix compilation, tests, push.

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Fix ruv-neural crate compilation: all 12 crates build and 1200+ tests pass

- Fix node2vec.rs type inference error (Vec<_> → Vec<Vec<f64>>)
- Fix artifact.rs with full filter-based detection implementations
- Fix signal crate ConnectivityMetric re-export and trait method names
- Fix embed crate EmbeddingGenerator trait implementations
- Complete spectral, topology, and node2vec embedders with tests
- Complete preprocessing pipeline with sequential stage processing
- All workspace crates compile cleanly, 0 test failures

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* Add ruv-neural-cli README

https://claude.ai/code/session_01DGUAowNScGVp88bK2eiuRv

* fix: convert desktop icons from RGB to RGBA for Tauri build

Tauri's generate_context!() macro requires RGBA PNG icons. All 5 icon
files (32x32.png, 128x128.png, 128x128@2x.png, icon.icns, icon.ico)
were RGB-only, causing a proc macro panic on Linux builds.

Fixes #200

Co-Authored-By: claude-flow <ruv@ruv.net>

* Add Subcarrier Manifold and Vitals Oracle modules for 3D visualizations

- Implemented Subcarrier Manifold to visualize amplitude data as a 3D surface with height and age attributes.
- Created Vitals Oracle to represent vital signs using toroidal rings and particle trails, incorporating breathing and heart rate dynamics.
- Both modules utilize Three.js for rendering and include custom shaders for visual effects.

* feat: complete ruv-neural implementation — physics models, security, witness verification

Replace all stubs/mocks with production physics-based signal models:
- NV Diamond: ODMR Lorentzian dip, 1/f pink noise (Voss-McCartney), brain oscillations
- OPM: SERF-mode, 50/60Hz powerline harmonics, full cross-talk compensation
  via Gaussian elimination with partial pivoting
- EEG: 5 frequency bands, eye blink artifacts (Fp1/Fp2), muscle artifacts,
  impedance-based thermal noise floor
- ESP32 ADC: ring-buffer reader with calibration signal generator, i16 clamp

Security hardening (SEC-001 through SEC-005):
- RVF bounded allocation (16MB metadata, 256MB payload)
- sample_rate validation (>0, finite)
- Signal NaN/Inf rejection
- ADC resolution_bits overflow clamp
- HNSW HashSet visited tracking + bounds checks

Performance optimizations (PERF-001 through PERF-005):
- 67x fewer FFTs via pre-computed analytic signals
- VecDeque O(1) eviction in memory store
- Thread-local FFT planner caching
- BrainGraph::validate() for edge/weight integrity
- Eigenvalue convergence early termination

Ed25519 witness verification system:
- 41 capability attestations across all 12 crates
- SHA-256 digest + Ed25519 signature
- CLI commands: `witness --output` and `witness --verify`

README: ethics warning, hardware parts list (AliExpress), assembly instructions

Co-Authored-By: claude-flow <ruv@ruv.net>

* docs: add crates.io badges and install instructions to ruv-neural README

Add version badges linking to each published crate on crates.io,
cargo add instructions, and crate search link in the Crate Map table.

Co-Authored-By: claude-flow <ruv@ruv.net>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-09 10:52:24 -04:00

29 KiB

ruv-neural Crate System: Security and Performance Review

Date: 2026-03-09 Version: 0.1.0 Scope: All 12 workspace crates in the ruv-neural system Status: Implementation checklist for v0.1 and v0.2 milestones


Table of Contents

  1. Crate Inventory
  2. Security Review
  3. Performance Review
  4. Action Items

Crate Inventory

Crate Status Lines (approx) Role
ruv-neural-core Implemented ~500 Types, traits, error types, RVF format
ruv-neural-sensor Implemented ~170 Sensor data acquisition, calibration, quality
ruv-neural-signal Implemented ~450 Filtering, spectral analysis, Hilbert, connectivity
ruv-neural-graph Stub ~2 Graph construction from signals
ruv-neural-mincut Implemented ~700 Stoer-Wagner, spectral cut, Cheeger, dynamic tracking
ruv-neural-embed Implemented ~350 Spectral, topology, node2vec embeddings
ruv-neural-memory Implemented ~425 Embedding store, HNSW index
ruv-neural-decoder Implemented (lib) ~25 KNN, threshold, transition decoders
ruv-neural-esp32 Implemented ~265 ADC interface, sensor readout
ruv-neural-wasm Stub ~2 WebAssembly bindings
ruv-neural-viz Implemented (lib) ~20 Visualization, ASCII rendering, export
ruv-neural-cli Stub ~2 CLI binary

Security Review

Input Validation

All public APIs must validate their inputs at system boundaries. This section catalogs each validation requirement and its current status.

Sensor Data Validation

Check Required In Status Notes
sample_rate_hz > 0 MultiChannelTimeSeries::new MISSING Constructor accepts sample_rate_hz without validating it is positive and finite. Division by zero in duration_s() if zero.
num_channels > 0 MultiChannelTimeSeries::new PASS Returns error if data.len() == 0.
Channel lengths equal MultiChannelTimeSeries::new PASS Validates all channels have the same length.
Non-NaN/Inf values All signal processing MISSING No validation that input signals contain only finite f64 values. NaN propagation through FFT, PLV, and connectivity metrics produces silent garbage.
num_samples > 0 AdcReader::read_samples PASS Returns error if num_samples == 0.
Channel count > 0 AdcReader::read_samples PASS Returns error if no channels configured.
Channel index bounds AdcReader::load_buffer PASS Returns ChannelOutOfRange error.
sensitivity > 0 SensorChannel MISSING sensitivity_ft_sqrt_hz is a public field with no validation on construction.
sample_rate > 0 SensorChannel MISSING sample_rate_hz is a public field with no validation.

Recommendation: Add a SensorChannel::new() constructor that validates sensitivity_ft_sqrt_hz > 0, sample_rate_hz > 0, and that the orientation vector is a unit normal. Add sample_rate_hz > 0 and sample_rate_hz.is_finite() checks to MultiChannelTimeSeries::new. Add a validate_finite() utility for signal data.

Graph Construction Validation

Check Required In Status Notes
Edge indices < num_nodes BrainGraph::adjacency_matrix PARTIAL Silently skips out-of-bounds edges rather than reporting an error. This masks data corruption.
Edge weight is finite BrainGraph MISSING BrainEdge.weight is not validated. NaN/Inf weights propagate silently through Stoer-Wagner and spectral analysis.
num_nodes >= 2 stoer_wagner_mincut PASS Returns proper error.
num_nodes >= 2 fiedler_decomposition PASS Returns proper error.
num_nodes >= 2 SpectralEmbedder::embed PASS Returns proper error.
num_nodes >= 2 cheeger_constant PASS Returns proper error.
Self-loops BrainGraph MISSING No validation that source != target on edges. Self-loops could inflate degree calculations.

Recommendation: Add a BrainGraph::validate() method that checks all edge indices are within bounds, weights are finite, and no self-loops exist. Call it from stoer_wagner_mincut, spectral_bisection, and SpectralEmbedder::embed. Consider making adjacency_matrix() return Result with an error for out-of-bounds edges instead of silently ignoring them.

RVF Format Validation

Check Required In Status Notes
Magic bytes RvfHeader::validate PASS Validates against RVF_MAGIC.
Version RvfHeader::validate PASS Rejects unknown versions.
Header length RvfHeader::from_bytes PASS Checks bytes.len() < 22.
Data type tag RvfDataType::from_tag PASS Returns error for unknown tags.
metadata_json_len overflow RvfFile::read_from CONCERN metadata_json_len is cast from u32 to usize and used to allocate a Vec. A malicious file with metadata_json_len = u32::MAX (~4 GB) would cause an OOM allocation.
Payload length RvfFile::read_from CONCERN read_to_end reads unbounded data into memory. A malicious file could exhaust memory.
JSON validity RvfFile::read_from PASS Uses serde_json::from_slice which returns an error on invalid JSON.
num_entries vs actual data RvfFile::read_from MISSING The header declares num_entries and embedding_dim, but these are never cross-checked against the actual payload size.

Recommendation: Add maximum size limits for metadata_json_len (e.g., 16 MB) and total payload size. Validate that num_entries * entry_size_for_type <= data.len() after reading. Use Read::take() to cap reads.

Embedding Validation

Check Required In Status Notes
Non-empty vector NeuralEmbedding::new (core) PASS Returns error for empty vectors.
Non-empty vector NeuralEmbedding::new (embed) PASS Returns error for empty vectors.
Dimension match cosine_similarity, euclidean_distance PASS Returns DimensionMismatch error.
Zero-norm handling cosine_similarity PASS Returns 0.0 for zero-norm vectors.
NaN/Inf in vector NeuralEmbedding::new MISSING No check for non-finite values in the embedding vector.

Memory Store Validation

Check Required In Status Notes
Capacity > 0 NeuralMemoryStore::new MISSING Capacity 0 is accepted, producing a store that evicts on every insertion.
k > 0 query_nearest MISSING k=0 produces an empty result silently (acceptable but undocumented).
Dimension consistency NeuralMemoryStore::store MISSING No check that all stored embeddings have the same dimensionality. Mixed dimensions cause silent errors in query_nearest.

JSON Parsing

Check Status Notes
Uses serde derive PASS All types use #[derive(Serialize, Deserialize)]. No manual parsing anywhere.
No unsafe JSON parsing PASS Standard serde_json throughout.

Memory Safety

Check Status Notes
No unsafe code PASS Zero unsafe blocks across all crates.
Vec instead of raw pointers PASS All data structures use Vec, HashMap, BinaryHeap.
ndarray for matrix ops NOT USED Despite being listed in workspace.dependencies, matrix operations use Vec<Vec<f64>> throughout. This is bounds-checked but less efficient.
No C FFI PASS No FFI calls. ESP32 code uses pure Rust types.
No std::mem::transmute PASS None found.
No std::ptr usage PASS None found.
Bounds checking on slices PASS Uses .get(), iterator methods, and Rust's built-in bounds checks.
Integer overflow CONCERN max_raw_value() in adc.rs casts (1u32 << resolution_bits) - 1 to i16. If resolution_bits > 15, this overflows silently. Currently only 12 or 16 are intended, but 16 produces i16::MAX wrapping.

Recommendation: Add a validation check on resolution_bits in AdcConfig (must be <= 15 for i16 representation, or switch to u16/i32). Consider migrating Vec<Vec<f64>> matrix representations to ndarray::Array2<f64> for better cache performance and built-in bounds checking.


Data Privacy

Neural data is among the most sensitive personal data categories. This section covers data handling practices.

Check Status Notes
No PII in log messages NEEDS AUDIT The crate uses tracing in workspace dependencies but currently has no tracing::info! or tracing::debug! calls with data fields. As logging is added, ensure neural data values, subject IDs, and session IDs are never logged at INFO level or below.
No neural data in error messages PASS Error messages contain structural information (dimensions, indices, version numbers) but not raw signal values or embeddings.
subject_id handling CONCERN EmbeddingMetadata.subject_id is stored as plaintext Option<String>. This is PII that is included in serialized embeddings (serde), HNSW indices, and RVF files.
session_id handling CONCERN Same concern as subject_id.
Memory store encryption NOT IMPLEMENTED NeuralMemoryStore holds embeddings in plaintext Vec<f64>. No encryption-at-rest.
Memory zeroization on drop NOT IMPLEMENTED Embedding data is not zeroed when dropped. Sensitive neural data persists in deallocated memory.
WASM data boundary STUB WASM crate is not yet implemented. When implemented, must ensure no neural data is sent to external services without explicit user consent.
RVF file privacy CONCERN RvfFile serializes metadata as JSON, which may contain subject_id. No option to strip or anonymize metadata before export.

Recommendations:

  • Implement a Redactable trait for types that may contain PII, providing redact() and anonymize() methods.
  • Use the zeroize crate to zero sensitive data on drop for NeuralEmbedding, NeuralMemoryStore, and MultiChannelTimeSeries.
  • Add a strip_pii() method to RvfFile that removes or hashes identifiers before export.
  • Document privacy responsibilities in each crate's module documentation.
  • For v0.2: Add optional encryption-at-rest for NeuralMemoryStore using ring or aes-gcm.

Network Security (ESP32)

Check Status Notes
Node ID authentication NOT IMPLEMENTED ESP32 crate (ruv-neural-esp32) is currently a local ADC reader with no network protocol. When TDM protocol is added, node IDs must be authenticated.
CRC32 integrity NOT IMPLEMENTED No data packet framing or integrity checks exist yet.
TLS encryption NOT IMPLEMENTED v0.1 has no network layer. Planned for v0.2.
Packet size limits NOT IMPLEMENTED No packet protocol exists yet.
Buffer overflow prevention PARTIAL AdcReader uses a fixed-size ring buffer (4096 samples), which prevents unbounded growth. However, load_buffer silently truncates data that exceeds buffer size rather than reporting it.
DMA configuration N/A dma_enabled is a configuration flag only; actual DMA is not implemented in std mode.

Recommendations for v0.2 TDM Protocol:

  • Authenticate node IDs using a pre-shared key or challenge-response.
  • Add CRC32 or CRC32-C to every data packet.
  • Set maximum packet size to 1460 bytes (single WiFi frame MTU).
  • Use DTLS or TLS 1.3 for encryption when available.
  • Rate-limit incoming packets per node to prevent flooding.
  • Validate all fields in received packets before processing.

Supply Chain

Check Status Notes
Minimal dependencies PASS Core dependencies: thiserror, serde, serde_json, num-complex, rustfft, rand. All are well-maintained, widely-used crates.
No proc macros except serde PASS Only serde's derive macros and thiserror's derive macro are used. clap's derive is CLI-only.
All deps from crates.io PASS No git dependencies or path dependencies outside the workspace.
Workspace-managed versions PASS All dependency versions are declared in [workspace.dependencies].
petgraph usage UNUSED Listed in workspace dependencies but not imported by any crate. Remove to reduce supply chain surface.
tokio usage UNUSED Listed in workspace dependencies but not imported by any crate. Remove unless async is planned.
ruvector-* crates UNUSED Five RuVector crates listed but not imported by any workspace member. Remove unused dependencies.
Cargo.lock PRESENT Cargo.lock is committed, ensuring reproducible builds.

Recommendation: Run cargo deny check to audit for known vulnerabilities. Remove unused workspace dependencies (petgraph, tokio, ruvector-* crates) to minimize attack surface. Add cargo audit to CI.


Findings from Code Audit

SEC-001: RVF Unbounded Allocation (Severity: Medium)

Location: ruv-neural-core/src/rvf.rs, line 193

let mut meta_bytes = vec![0u8; header.metadata_json_len as usize];

A crafted RVF file with metadata_json_len = 0xFFFFFFFF allocates 4 GB. Similarly, read_to_end on line 201 reads unbounded data.

Fix: Add maximum size constants and validate before allocating:

const MAX_METADATA_LEN: u32 = 16 * 1024 * 1024; // 16 MB
const MAX_PAYLOAD_LEN: usize = 256 * 1024 * 1024; // 256 MB

if header.metadata_json_len > MAX_METADATA_LEN {
    return Err(RuvNeuralError::Serialization(
        format!("metadata_json_len {} exceeds maximum {}", header.metadata_json_len, MAX_METADATA_LEN)
    ));
}

SEC-002: Missing Sample Rate Validation (Severity: Medium)

Location: ruv-neural-core/src/signal.rs, MultiChannelTimeSeries::new

The sample_rate_hz parameter is not validated. A value of 0.0 causes division by zero in duration_s(). A negative or NaN value causes incorrect spectral analysis throughout the pipeline.

Fix: Add validation in the constructor:

if sample_rate_hz <= 0.0 || !sample_rate_hz.is_finite() {
    return Err(RuvNeuralError::Signal(
        format!("sample_rate_hz must be positive and finite, got {}", sample_rate_hz)
    ));
}

SEC-003: NaN Propagation in Signal Processing (Severity: Low)

Location: ruv-neural-signal/src/connectivity.rs, all functions

If either input signal contains NaN, the Hilbert transform produces NaN outputs, which propagate silently through PLV, coherence, and all connectivity metrics. The result is a brain graph with NaN edge weights, which causes undefined behavior in Stoer-Wagner (infinite loops or wrong results).

Fix: Add a validate_signal helper and call it at entry points:

fn validate_signal(signal: &[f64]) -> Result<()> {
    if signal.iter().any(|x| !x.is_finite()) {
        return Err(RuvNeuralError::Signal("Signal contains NaN or Inf values".into()));
    }
    Ok(())
}

SEC-004: Integer Overflow in ADC (Severity: Low)

Location: ruv-neural-esp32/src/adc.rs, AdcConfig::max_raw_value

pub fn max_raw_value(&self) -> i16 {
    ((1u32 << self.resolution_bits) - 1) as i16
}

For resolution_bits = 16, this computes 65535 as i16 = -1, which causes incorrect voltage conversion (division by -1 flips sign).

Fix: Change return type to u16 or i32, or validate resolution_bits <= 15.

SEC-005: HNSW Visited Array Allocation (Severity: Low)

Location: ruv-neural-memory/src/hnsw.rs, search_layer, line 261

let mut visited = vec![false; self.embeddings.len()];

This allocates a visited array proportional to the total number of embeddings on every search call. For large indices (100K+ embeddings), this causes unnecessary allocation pressure. More critically, if entry is >= self.embeddings.len(), the indexing on line 262 panics.

Fix: Use a HashSet<usize> instead of a boolean array for sparse visitation. Add bounds check on entry.


Performance Review

Computational Complexity

Operation Complexity Target Latency Current Status
FFT (1024 points) O(N log N) <1 ms Implemented via rustfft (SIMD-optimized). Meets target.
Hilbert transform O(N log N) <1 ms Two FFTs (forward + inverse). Meets target for N <= 4096.
PLV (channel pair) O(N) + 2x FFT <0.5 ms Calls hilbert_transform twice. Meets target for N <= 2048.
Coherence (channel pair) O(N) + 2x FFT <0.5 ms Same as PLV.
Connectivity matrix (68 regions) O(N^2 x M) <10 ms M = samples per channel, N = 68: 2,278 Hilbert pairs. May exceed target for long windows.
Stoer-Wagner mincut (68 nodes) O(V^3) <5 ms 68^3 = ~314K operations. Meets target.
Spectral embedding (68 nodes) O(V^2 x k x iterations) <3 ms With k=8, iterations=100: 68^2 x 8 x 100 = ~37M ops. May be tight.
Fiedler decomposition O(V^2 x iterations) <2 ms 1000 iterations x 68^2 = ~4.6M ops. Meets target.
Cheeger constant (exact, n<=16) O(2^n x n^2) <5 ms Exponential but capped at n=16: 65K x 256 = ~16M ops. Meets target.
HNSW insert O(log N x ef x M) <1 ms ef=200, M=16: ~3200 distance computations per insert. Meets target.
HNSW search (10K embeddings) O(log N x ef) <1 ms ef=50: ~50-200 distance computations. Meets target.
Brute-force NN (10K embeddings) O(N x d) <5 ms d=256, N=10K: 2.56M f64 ops. Acceptable but HNSW preferred.
Full pipeline (68 regions) - <50 ms Sum of above stages. Should meet target.

Memory Usage

Component Calculation Size
64-channel x 1000 Hz x 8 bytes x 1s 64 x 1000 x 8 512 KB per second
Brain graph adjacency (68 nodes) 68^2 x 8 bytes ~37 KB
Brain graph adjacency (400 nodes) 400^2 x 8 bytes ~1.25 MB
Single embedding (256-d) 256 x 8 bytes 2 KB
Memory store (10K embeddings, 256-d) 10K x 2 KB ~20 MB
HNSW index (10K, M=16, 256-d) 10K x (2KB + 16 x 16 bytes) ~22.5 MB
Stoer-Wagner working memory (68 nodes) 2 x 68^2 x 8 + 68 x vec overhead ~75 KB
Spectral embedder (68 nodes, k=8) k x 68 x 8 + Laplacian 68^2 x 8 ~41 KB
RVF file in memory header + metadata + payload Variable, unbounded (see SEC-001)

Optimization Opportunities

Immediate (v0.1)

  1. Eliminate redundant Hilbert transforms in connectivity matrix

    • compute_all_pairs calls hilbert_transform twice per channel pair.
    • For 68 channels, this means 68 x 67 = 4,556 Hilbert transforms instead of 68.
    • Fix: Pre-compute analytic signals for all channels, then compute metrics pairwise.
    • Expected speedup: ~67x for connectivity matrix computation.
  2. Replace Vec<Vec> with flat Vec for adjacency matrices

    • Current Vec<Vec<f64>> has poor cache locality due to heap-allocated inner Vecs.
    • Fix: Use Vec<f64> with manual row-major indexing, or migrate to ndarray::Array2<f64>.
    • Expected speedup: 2-4x for matrix-heavy operations (Stoer-Wagner, Laplacian).
  3. Avoid Vec::remove(0) in eviction

    • NeuralMemoryStore::evict_oldest calls self.embeddings.remove(0), which is O(n).
    • Fix: Use a VecDeque or circular buffer.
    • Expected speedup: O(1) eviction instead of O(n).
  4. Pre-allocate FFT planner

    • compute_psd, compute_stft, and hilbert_transform each create a new FftPlanner per call.
    • Fix: Cache the planner or use a thread-local planner.
    • Expected speedup: Eliminates repeated plan computation.

Medium-term (v0.2)

  1. Rayon for parallel channel processing

    • compute_all_pairs iterates channel pairs sequentially.
    • Fix: Use rayon::par_iter for the outer loop.
    • Expected speedup: Linear with core count for connectivity computation.
  2. SIMD for distance computations in HNSW

    • Euclidean distance in HnswIndex::distance uses scalar iteration.
    • Fix: Use packed_simd2 or auto-vectorization hints.
    • Expected speedup: 4-8x for 256-d vectors on AVX2.
  3. Sparse graph representation

    • Dense adjacency matrix wastes memory for sparse brain graphs.
    • For Schaefer400, storing all 160K entries when only ~10K edges exist is wasteful.
    • Fix: Use compressed sparse row (CSR) format or petgraph's sparse graph.
  4. Quantized embeddings for WASM

    • f64 embeddings are unnecessarily precise for browser-based applications.
    • Fix: Support f32 embeddings in WASM builds, halving memory and transfer size.

Long-term (v0.3+)

  1. Streaming signal processing

    • Current design loads entire time windows into memory.
    • Fix: Implement ring-buffer based streaming for real-time operation.
  2. GPU acceleration for large-scale spectral analysis

    • For Schaefer400 atlas, eigendecomposition of 400x400 matrices benefits from GPU.
    • Fix: Optional wgpu or vulkano backend for matrix operations.

ESP32 Constraints

Resource Limit Current Usage Status
SRAM 520 KB Ring buffer: 4096 x channels x 2 bytes = 8 KB (1 channel) OK
SRAM (multi-channel) 520 KB 4096 x 16 x 2 = 128 KB (16 channels) TIGHT
CPU 240 MHz dual-core ADC sampling + data transmission OK for 1 kHz
Flash 4 MB Binary size with release profile Needs measurement
WiFi throughput ~1 Mbps sustained 64 ch x 1000 Hz x 2 bytes = 128 KB/s = 1 Mbps AT LIMIT

Recommendations:

  • Use fixed-point arithmetic (i16 or Q15) instead of f64 on ESP32.
  • Implement delta encoding or simple compression for data packets.
  • Limit on-device processing to ADC readout and basic quality checks.
  • Move all signal processing (FFT, connectivity, graph construction) to the host.
  • Profile binary size with cargo bloat to ensure it fits in 4 MB flash.
  • Consider reducing ring buffer size for multi-channel configurations.

Benchmarking Recommendations

Per-Crate Microbenchmarks (criterion)

# Add to each crate's Cargo.toml
[[bench]]
name = "benchmarks"
harness = false

[dev-dependencies]
criterion = { workspace = true }
Crate Benchmark Input Size Metric
ruv-neural-signal bench_hilbert_transform 256, 512, 1024, 2048, 4096 samples ns/op
ruv-neural-signal bench_compute_psd 1024, 4096 samples ns/op
ruv-neural-signal bench_plv_pair 1024 samples ns/op
ruv-neural-signal bench_connectivity_matrix 16, 32, 68 channels x 1024 samples ms/op
ruv-neural-mincut bench_stoer_wagner 10, 20, 50, 68, 100 nodes us/op
ruv-neural-mincut bench_spectral_bisection 10, 20, 50, 68, 100 nodes us/op
ruv-neural-mincut bench_cheeger_constant 8, 12, 16 nodes (exact), 32, 68 (approx) us/op
ruv-neural-embed bench_spectral_embed 20, 50, 68, 100 nodes us/op
ruv-neural-memory bench_brute_force_nn 100, 1K, 10K embeddings x 256-d us/op
ruv-neural-memory bench_hnsw_insert 1K, 10K embeddings x 256-d us/op
ruv-neural-memory bench_hnsw_search 1K, 10K embeddings, k=10, ef=50 us/op
ruv-neural-esp32 bench_adc_read 100, 1000 samples x 1-16 channels us/op

Full Pipeline Profiling

# Generate a flamegraph of the full pipeline
cargo flamegraph --bench full_pipeline -- --bench

# Memory profiling with DHAT
cargo test --features dhat-heap -- --test full_pipeline

WASM Performance

// When ruv-neural-wasm is implemented, measure with:
performance.mark('embed-start');
const embedding = ruv_neural.embed(graphData);
performance.mark('embed-end');
performance.measure('embed', 'embed-start', 'embed-end');

ESP32 Hardware Timing

// Use esp-idf-hal's timer for hardware-level benchmarks
let start = esp_idf_hal::timer::now();
let samples = reader.read_samples(1000)?;
let elapsed_us = esp_idf_hal::timer::now() - start;

Performance Findings from Code Audit

PERF-001: Redundant Hilbert Transforms (Severity: High)

Location: ruv-neural-signal/src/connectivity.rs, compute_all_pairs

Each call to phase_locking_value, coherence, imaginary_coherence, or amplitude_envelope_correlation independently calls hilbert_transform on both input signals. In compute_all_pairs with 68 channels, each channel's analytic signal is computed 67 times.

Impact: For 68 channels x 1024 samples, this means 4,556 FFTs instead of 68. Estimated waste: ~98.5% of FFT compute in the connectivity matrix.

Fix: Pre-compute all analytic signals, then pass slices to pairwise metrics:

pub fn compute_all_pairs_optimized(channels: &[Vec<f64>], metric: &ConnectivityMetric) -> Vec<Vec<f64>> {
    let analytics: Vec<Vec<Complex<f64>>> = channels.iter()
        .map(|ch| hilbert_transform(ch))
        .collect();
    // ... use pre-computed analytics for all pair computations
}

PERF-002: O(n) Eviction in Memory Store (Severity: Medium)

Location: ruv-neural-memory/src/store.rs, evict_oldest

fn evict_oldest(&mut self) {
    self.embeddings.remove(0);  // O(n) shift
    self.rebuild_index();       // O(n) rebuild
}

For a store with 10K embeddings, every insertion at capacity triggers an O(n) shift and full index rebuild.

Fix: Use VecDeque<NeuralEmbedding> and maintain the index incrementally.

PERF-003: FFT Planner Re-creation (Severity: Medium)

Location: ruv-neural-signal/src/spectral.rs (lines 12-13), hilbert.rs (lines 25-27)

A new FftPlanner is created on every function call. rustfft caches FFT plans internally in the planner, but creating a new planner discards the cache.

Fix: Use a thread-local or static planner:

thread_local! {
    static FFT_PLANNER: RefCell<FftPlanner<f64>> = RefCell::new(FftPlanner::new());
}

PERF-004: Dense Adjacency for Sparse Graphs (Severity: Low)

Location: ruv-neural-core/src/graph.rs, adjacency_matrix

Always allocates an N x N matrix even when the graph has far fewer edges. For Schaefer400 with ~5K edges, this allocates 1.25 MB for a matrix that is ~97% zeros.

Fix: Return a sparse representation for large graphs, or provide both adjacency_matrix() and sparse_adjacency().

PERF-005: Power Iteration Convergence Not Checked (Severity: Low)

Location: ruv-neural-mincut/src/spectral_cut.rs, largest_eigenvalue

Runs a fixed 200 iterations regardless of convergence. Many graphs converge in 20-50 iterations.

Fix: Add early termination when eigenvalue change < epsilon:

if (eigenvalue - prev_eigenvalue).abs() < 1e-12 {
    break;
}

Note: fiedler_decomposition already has this check, but largest_eigenvalue does not.


Action Items

Critical (Must fix before v0.1 release)

  • SEC-001: Add maximum size limits to RVF deserialization
  • SEC-002: Validate sample_rate_hz > 0 and is_finite() in MultiChannelTimeSeries::new
  • SEC-004: Fix integer overflow in AdcConfig::max_raw_value
  • PERF-001: Pre-compute Hilbert transforms in compute_all_pairs

Important (Should fix before v0.1 release)

  • SEC-003: Add NaN/Inf validation for signal data at pipeline entry points
  • SEC-005: Add bounds check on HNSW entry point index
  • PERF-002: Replace Vec::remove(0) with VecDeque in memory store
  • PERF-003: Cache FFT planner across calls
  • Add BrainGraph::validate() for edge index bounds and weight finiteness
  • Add dimension consistency check to NeuralMemoryStore::store
  • Remove unused workspace dependencies (petgraph, tokio, ruvector-*)
  • Implement zeroize-on-drop for NeuralEmbedding and NeuralMemoryStore
  • Add strip_pii() to RvfFile
  • Migrate Vec<Vec<f64>> matrices to ndarray::Array2<f64>
  • Add Rayon parallelism for connectivity matrix computation
  • Add criterion benchmarks for all crates
  • Implement TDM protocol with CRC32 and node authentication
  • Add cargo deny and cargo audit to CI
  • Profile and optimize binary size for ESP32

Future (v0.3+)

  • Encryption-at-rest for NeuralMemoryStore
  • DTLS/TLS for ESP32 network protocol
  • Sparse graph representation for large atlases
  • f32 quantized embeddings for WASM
  • Streaming signal processing pipeline
  • GPU backend for large-scale spectral analysis

This document should be reviewed and updated after each milestone. All security findings should be verified as resolved before the corresponding release.