This document describes how R4W supports integration with a Crypto Service Interface (CSI) to enable commercial secure SDR applications. The architecture separates trusted (RED) plaintext processing from untrusted (BLACK) RF/PHY processing.
| Term | Definition |
|---|---|
| RED | Trusted domain: plaintext voice/data, mission logic, key management |
| BLACK | Untrusted domain: ciphertext, waveform/PHY, RF processing, over-the-air |
| Crypto Boundary | Policy-enforced interface between RED and BLACK domains |
| CSI | Crypto Service Interface - the API that enforces the boundary |
┌─────────────────────────────────────────┐
│ Application (CLI, GUI, Mission Logic) │
│ │
│ message.as_bytes() ──────────────────►│
├─────────────────────────────────────────┤
│ Waveform Trait │
│ modulate(&[u8]) -> Vec<IQSample> │
│ demodulate(&[IQSample]) -> DemodResult│
├─────────────────────────────────────────┤
│ HAL (StreamHandle, TunerControl) │
├─────────────────────────────────────────┤
│ RF Hardware / Simulator │
└─────────────────────────────────────────┘
┌─────────────────────────────────────────┐
│ Application (Voice Codec, Data Stack) │ RED
│ │
│ PlaintextIn { payload, policy_id } │
├═════════════════════════════════════════┤
│ Crypto Service Interface (CSI) │ ← CRYPTO BOUNDARY
│ - Flow management │
│ - AEAD encryption/decryption │
│ - Replay protection │
│ - Key reference (no raw keys) │
│ - Zeroization │
│ │
│ CiphertextOut { ciphertext } │
├═════════════════════════════════════════┤
│ Waveform Trait (sees only ciphertext) │ BLACK
│ modulate(&[u8]) -> Vec<IQSample> │
├─────────────────────────────────────────┤
│ HAL (StreamHandle, TunerControl) │ BLACK
├─────────────────────────────────────────┤
│ RF Hardware │ BLACK
└─────────────────────────────────────────┘
pub trait Waveform {
fn modulate(&self, data: &[u8]) -> Vec<IQSample>;
fn demodulate(&self, samples: &[IQSample]) -> DemodResult;
}The waveform layer treats input as opaque bytes. It doesn’t know or care whether the bytes are plaintext or ciphertext. This is exactly what a crypto boundary requires.
The HAL layer (StreamHandle,
TunerControl, ClockControl) only deals
with: - IQ samples - Frequencies and gains - Timing and
synchronization
No plaintext ever needs to touch this layer.
The physical layer plan includes: - Lock-free ring buffers
(RingBuffer<T>) - Pre-allocated buffer pools -
no_std compatibility - Deterministic timing
These are exactly what CSI requires for embedded deployment.
// Application submits plaintext
csi.submit_plaintext(PlaintextIn {
flow_id: 100,
service: ServiceType::Voice,
policy_id: 1,
seq: next_seq(),
aad: None,
payload: voice_frame,
})?;
// CSI produces ciphertext
if let Some(ct) = csi.poll_ciphertext() {
// Waveform modulates ciphertext (opaque bytes)
let samples = waveform.modulate(&ct.ciphertext);
stream.write(&samples, None, timeout)?;
}// HAL receives samples
let (count, ts) = stream.read(&mut buffer, timeout)?;
// Waveform demodulates to ciphertext
let result = waveform.demodulate(&buffer[..count]);
// CSI decrypts and verifies
csi.submit_ciphertext(CiphertextIn {
flow_id: 100,
seq: Some(result.seq),
ciphertext: result.bits.into(),
rx_meta: None,
})?;
// Application receives verified plaintext
if let Some(pt) = csi.poll_plaintext() {
match pt.result {
CryptoResult::Ok => process_voice(pt.payload),
CryptoResult::AuthFail => log_security_event(),
CryptoResult::Replay => drop_duplicate(),
_ => handle_error(pt.result),
}
}| Direction | Message | Purpose |
|---|---|---|
| RED → CSI | PlaintextIn |
Submit framed payload for encryption |
| CSI → BLACK | CiphertextOut |
Authenticated ciphertext for PHY |
| BLACK → CSI | CiphertextIn |
Received ciphertext for verification |
| CSI → RED | PlaintextOut |
Verified plaintext (empty on auth fail) |
| Command | Purpose |
|---|---|
CreateFlow |
Establish secure channel with policy binding |
DestroyFlow |
Tear down channel |
BindKey |
Associate key reference with flow |
Rekey |
Rotate key, increment epoch |
Zeroize |
Securely erase keys/state |
StatusQuery |
Health, counters, error state |
pub trait CryptoService {
// Control plane
fn control(&mut self, cmd: ControlMsg) -> Result<ControlReply, CryptoResult>;
fn status(&self) -> StatusReply;
// TX path
fn submit_plaintext(&mut self, msg: PlaintextIn) -> Result<(), CryptoResult>;
fn poll_ciphertext(&mut self) -> Option<CiphertextOut>;
// RX path
fn submit_ciphertext(&mut self, msg: CiphertextIn) -> Result<(), CryptoResult>;
fn poll_plaintext(&mut self) -> Option<PlaintextOut>;
}csi/
├── csi-core/ # no_std: types, flow table, replay window
├── csi-queues/ # no_std: bbqueue-based SPSC channels
├── csi-backend-soft/ # no_std: ChaCha20-Poly1305 AEAD
└── csi-backend-hw/ # no_std: hardware crypto acceleration
crates/r4w-secure/
├── src/
│ ├── lib.rs # Integration layer
│ ├── pipeline.rs # CSI + Waveform pipeline
│ └── voice.rs # Voice codec integration
└── Cargo.toml # feature-gated dependency on csi-core
# crates/r4w-core/Cargo.toml
[features]
default = []
secure = [] # Marker feature indicating crypto-boundary awareness
# crates/r4w-secure/Cargo.toml (future)
[dependencies]
r4w-core = { path = "../r4w-core", features = ["secure"] }
csi-core = { path = "../../csi/csi-core" }For commercial secure SDR posture, implementations MUST:
heapless
types with compile-time limits