phantom_protocol/lib.rs
1//! # Phantom Protocol SDK
2//!
3//! Post-quantum secure L4/L6 universal transport framework.
4//!
5//! Provides:
6//! - Hybrid key exchange (X25519 + ML-KEM-768; X-Wing-style combiner). Under
7//! `--features fips` the classical half swaps to ECDH-P-256.
8//! - Hybrid signatures (Ed25519 + ML-DSA-65) — both halves must verify.
9//! - PhantomUDP, a native reliable transport over raw UDP (the production
10//! transport), plus byte-pipe `SessionTransport` impls for TCP, browser
11//! WebSocket, WASI, embedded UART/USB, and an off-by-default TLS-mimicry leg.
12//! - Seamless single-path connection migration (not multipath aggregation —
13//! that was deliberately rejected) with liveness detection and keep-alive PINGs.
14//! - Stream multiplexing (reliable + unreliable).
15//!
16//! The core transmits only `Vec<u8>` / `Bytes`.
17//! Serialization (JSON, Protobuf, etc.) is the user's responsibility.
18
19// Security-friendly lints. Now `deny` (was `warn` until the codebase drove the
20// remaining unannotated sites to zero). Every surviving panic-shaped call in
21// production code carries an inline `// PANIC-SAFETY:` comment and a narrow
22// `#[allow(clippy::unwrap_used)]` / `#[allow(clippy::expect_used)]` at the
23// statement scope; the canonical inventory lives in `docs/security/panic-sites.md`.
24// Tests opt in to `expect_used` for readable failure diagnostics. Phase 1.3
25// (Production Readiness) — closed.
26//
27// `clippy::indexing_slicing` is deliberately omitted at this stage — it fires
28// on every constant-bounded array index and would generate too much noise.
29// It is tracked as a separate phase 1.13 item (bounds-check audit).
30//
31// On docs.rs — which sets `--cfg docsrs` on nightly via the
32// `[package.metadata.docs.rs]` table — auto-generate "Available on crate
33// feature X" badges for every `#[cfg(feature = …)]`-gated item. `doc_auto_cfg`
34// was merged into `doc_cfg` in Rust 1.92, which now carries the auto-cfg
35// behaviour. The attribute is inert on every normal (stable) build: `docsrs` is
36// never set there, so the unstable `doc_cfg` feature is never requested.
37#![cfg_attr(docsrs, feature(doc_cfg))]
38#![deny(
39 clippy::unwrap_used,
40 clippy::expect_used,
41 clippy::panic,
42 clippy::unreachable,
43 clippy::todo,
44 clippy::unimplemented,
45 clippy::missing_safety_doc
46)]
47// Tests use `expect()` / `unwrap()` / `panic!()` freely so failures surface as
48// readable diagnostics rather than swallowed `Result`s. The `deny` above only
49// governs the production code path; this `cfg_attr(test, allow(...))` flips
50// the same lints back to permissive for `cargo test` builds.
51#![cfg_attr(
52 test,
53 allow(
54 clippy::unwrap_used,
55 clippy::expect_used,
56 clippy::panic,
57 clippy::unreachable,
58 clippy::todo,
59 clippy::unimplemented,
60 clippy::missing_safety_doc,
61 // Same rationale: tests call `.unwrap()` on `Result` / `Option`
62 // routinely; the disallowed-methods list in `.clippy.toml` is
63 // for production code, not the test harness.
64 clippy::disallowed_methods
65 )
66)]
67// Deny `unsafe` by default at the crate root. The three modules that genuinely
68// require `unsafe` (a single `libc::setsockopt(SO_MAX_PACING_RATE)` call in
69// `transport::udp_transport`, native-only — the dead `sendmmsg` GSO path was
70// removed; wasm-bindgen-generated JS-boundary glue in
71// `transport::legs::websocket`, wasm32-only; `unsafe impl Send/Sync for
72// WasiLeg` over WIT-bindgen `Resource<T>` socket handles in
73// `transport::legs::wasi`, WASI-only) opt back in with a module-level
74// `#![allow(unsafe_code)]` and per-block `// SAFETY:` comments. Audit lens:
75// any future PR touching `unsafe` outside those three modules will fail this
76// lint and must justify itself explicitly.
77#![deny(unsafe_code)]
78// Phase 3.6: when neither `std` nor any std-implying feature is on, drop std
79// from the crate root so a bare-metal `--no-default-features --features
80// embedded,no-std` build links only `core` + `alloc`. The std build (the
81// default) is unchanged.
82#![cfg_attr(not(feature = "std"), no_std)]
83
84// Phase 5.5 / A8 — the FIPS 140-3 primitive swap (X25519 → ECDH-P-256,
85// ring → aws-lc-rs, blake3 → HKDF-SHA256, drop ChaCha20-Poly1305,
86// CTR_DRBG RNG, POST hook) is **shipped**. `--features fips` now
87// builds and serves a FIPS-substrate Phantom Protocol. The scaffold
88// `compile_error!` from commit `d4d121b` is gone; the only
89// remaining build-time gate enforces mutual exclusion with `no-std`,
90// since `aws-lc-rs` requires libc + dlopen / OpenSSL ABI and cannot
91// run on bare-metal.
92#[cfg(all(feature = "fips", feature = "no-std"))]
93compile_error!(
94 "Cargo features `fips` and `no-std` are mutually exclusive — \
95 `aws-lc-rs` (the FIPS-validated substrate) needs libc / dlopen \
96 and does not build for bare-metal targets. Build either with \
97 `--features fips` (FIPS posture, requires std) or with \
98 `--features embedded,no-std` (no_std posture, default crypto)."
99);
100
101// B1 — the `wasi-leg` Cargo feature lives at the WASI target (the
102// `wasi` crate's WIT bindings are only available there). Enabling it
103// on `wasm32-unknown-unknown` (the browser target with WebSocketLeg /
104// WasmRuntime) is a misconfiguration; fail the build loudly with a
105// pointer at the recipe.
106#[cfg(all(feature = "wasi-leg", target_arch = "wasm32", not(target_os = "wasi")))]
107compile_error!(
108 "The `wasi-leg` Cargo feature is only supported on WASI targets \
109 (wasm32-wasi, wasm32-wasip1, wasm32-wasip2). For \
110 wasm32-unknown-unknown (browser) builds use the default feature \
111 set, which exposes the `WebSocketLeg` + `WasmRuntime` surface \
112 instead."
113);
114
115#[cfg(not(feature = "std"))]
116extern crate alloc;
117
118// `errors` and the `transport::session_transport` / `transport::legs::embedded`
119// subtree are no_std-clean and compile under both feature configurations.
120mod errors;
121
122// ── std-only top-level modules ─────────────────────────────────────────
123// The bare-metal subset (Phase 3.6) compiles only `errors` and the embedded
124// transport subset. Everything below is gated behind `std`: it either uses
125// `tokio`, `parking_lot`, `dashmap`, raw sockets, `std::time::Instant`,
126// `std::sync::*`, or a std-bound dep (e.g. `ml-kem`, the classical-crypto
127// `ring` / `x25519-dalek`) that is itself only compiled when `std` is on.
128
129#[cfg(feature = "std")]
130pub mod config;
131#[cfg(feature = "std")]
132pub mod observability;
133#[cfg(feature = "std")]
134pub mod security;
135#[cfg(feature = "std")]
136pub mod validation;
137
138// Crypto module (hybrid KEM, hybrid sign) — std-only: pulls `ed25519-dalek`,
139// `ml-kem`, `ml-dsa` unconditionally, plus `ring` + `x25519-dalek` via the
140// default-on `classical-crypto` feature. Under `--features fips` the classical
141// substrate swaps to `aws-lc-rs` (`ring` / `x25519-dalek` dropped entirely).
142#[cfg(feature = "std")]
143pub mod crypto;
144
145// Transport module (Phantom Protocol transport). The module itself has a
146// no_std-clean subset (`session_transport`, `legs::embedded`). The rest of the
147// sub-modules opt into `std` from within `transport/mod.rs`.
148pub mod transport;
149
150// Async runtime abstraction (Phase 3.1). `TokioRuntime` is the default
151// implementation; `WasmRuntime` (browser), `EmbeddedRuntime` (host-thread
152// scaffold), and `WasiRuntime` (WASI Preview 2) are the shipped alternate
153// backends, injected via the `_with_runtime` API variants.
154#[cfg(feature = "std")]
155pub mod runtime;
156
157// Public API facade — std-only: every entry point (`PhantomSession`,
158// `PhantomListener`, `TcpSessionTransport`) depends on `tokio`.
159#[cfg(feature = "std")]
160pub mod api;
161
162// Test harness for network simulation
163#[cfg(all(test, feature = "std"))]
164pub mod test_harness;
165
166// Public exports
167#[cfg(feature = "std")]
168pub use config::PhantomConfig;
169pub use errors::CoreError;
170
171// UniFFI scaffolding. Gated on the `bindings` feature so the WASI
172// guest build (which sets `--features wasi-leg` without `bindings`)
173// skips it — UniFFI's exported-symbol metadata is incompatible with
174// `wasm-component-ld`, the wasm32-wasip2 linker. Default builds keep
175// `bindings` active, so the native FFI consumers (Swift / Kotlin /
176// Python / C bindings) see the historical surface unchanged.
177#[cfg(feature = "bindings")]
178uniffi::setup_scaffolding!();