| Crates.io | nomad-protocol |
| lib.rs | nomad-protocol |
| version | 0.2.0 |
| created_at | 2025-12-25 11:58:19.405254+00 |
| updated_at | 2025-12-26 10:56:26.745231+00 |
| description | NOMAD Protocol - Network-Optimized Mobile Application Datagram. A secure UDP-based state synchronization protocol. |
| homepage | https://github.com/DanEscher98/nomad-rs |
| repository | https://github.com/DanEscher98/nomad-rs |
| max_upload_size | |
| id | 2004468 |
| size | 476,968 |
Network-Optimized Mobile Application Datagram
A secure, UDP-based state synchronization protocol designed for real-time applications over unreliable networks. Inspired by Mosh but redesigned from scratch with modern cryptography and a generic state synchronization framework.
Add to your Cargo.toml:
[dependencies]
nomad-protocol = "0.1"
use nomad_protocol::prelude::*;
#[derive(Clone)]
struct GameState {
players: Vec<Player>,
score: u32,
}
#[derive(Clone)]
struct GameDiff {
// Your diff representation
}
impl SyncState for GameState {
type Diff = GameDiff;
const STATE_TYPE_ID: &'static str = "com.example.game.v1";
fn diff_from(&self, old: &Self) -> Self::Diff {
// Compute idempotent diff
todo!()
}
fn apply_diff(&mut self, diff: &Self::Diff) -> Result<(), ApplyError> {
// Apply diff (must be idempotent)
todo!()
}
fn encode_diff(diff: &Self::Diff) -> Vec<u8> {
// Serialize for wire
todo!()
}
fn decode_diff(data: &[u8]) -> Result<Self::Diff, DecodeError> {
// Deserialize from wire
todo!()
}
}
use nomad_protocol::prelude::*;
#[tokio::main]
async fn main() -> Result<(), NomadError> {
// Connect to server
let client = NomadClient::<GameState>::builder()
.server_public_key(server_pubkey)
.connect("game.example.com:19999")
.await?;
// Send state updates
client.update_state(|state| {
state.score += 10;
}).await?;
Ok(())
}
use nomad_protocol::prelude::*;
#[tokio::main]
async fn main() -> Result<(), NomadError> {
let server = NomadServer::<GameState>::builder()
.private_key(server_privkey)
.bind("0.0.0.0:19999")
.await?;
// Accept connections
while let Some(session) = server.accept().await {
tokio::spawn(async move {
handle_session(session).await;
});
}
Ok(())
}
| Feature | Default | Description |
|---|---|---|
full |
✓ | Enable all features |
client |
✓ | High-level client API |
server |
✓ | High-level server API |
compression |
✓ | zstd compression support |
transport |
✓ | Transport layer |
sync |
✓ | Sync layer |
Minimal build (core + crypto only):
[dependencies]
nomad-protocol = { version = "0.1", default-features = false }
┌─────────────────────────────────────────────────────────────┐
│ APPLICATION Your App (impl SyncState) │
├─────────────────────────────────────────────────────────────┤
│ EXTENSIONS compression (zstd) │
├─────────────────────────────────────────────────────────────┤
│ SYNC LAYER versioning • idempotent diffs • convergence│
├─────────────────────────────────────────────────────────────┤
│ TRANSPORT frames • session ID • RTT • keepalive │
├─────────────────────────────────────────────────────────────┤
│ SECURITY Noise_IK • XChaCha20-Poly1305 • BLAKE2s │
├─────────────────────────────────────────────────────────────┤
│ UDP tokio::net::UdpSocket │
└─────────────────────────────────────────────────────────────┘
NOMAD uses a fixed cryptographic suite with no negotiation:
| Purpose | Algorithm |
|---|---|
| Key Exchange | X25519 (Noise_IK pattern) |
| AEAD | XChaCha20-Poly1305 |
| Hash | BLAKE2s-256 |
| KDF | HKDF-BLAKE2s |
| Metric | Target |
|---|---|
| Handshake | < 1 RTT |
| Reconnection | < 100ms |
| Frame rate | 50 Hz max |
| Throughput | > 10 MB/s |
This workspace publishes a single crate nomad-protocol that contains all functionality. Internal modules:
| Module | Description |
|---|---|
core |
Core traits and constants |
crypto |
Cryptographic primitives (Noise_IK, XChaCha20-Poly1305) |
transport |
Frame encoding, RTT estimation, connection migration |
sync |
State synchronization with idempotent diffs |
extensions |
Optional extensions (compression) |
client |
High-level async client API |
server |
High-level async server API |
| Feature | NOMAD | Mosh |
|---|---|---|
| Encryption | XChaCha20-Poly1305 | AES-OCB |
| Key Exchange | Noise_IK (1-RTT) | Out-of-band (SSH) |
| State Types | Generic (any) | Terminal only |
| Rekeying | Every 2 min | No |
| Forward Secrecy | Yes | No |
| Protocol Version | Extensible | Fixed |
The protocol specification is maintained separately. See the specs/ directory for:
0-PROTOCOL.md - Overview and constants1-SECURITY.md - Cryptography and handshake2-TRANSPORT.md - Framing and timing3-SYNC.md - State synchronization4-EXTENSIONS.md - Optional extensionsLicensed under either of:
at your option.
Contributions are welcome! Please read our contributing guidelines before submitting PRs.