Offline Protocol Rust crates on crates.io
The Rust SDK is a set of offline-protocol crates on crates.io, and the main one is added with a single command:
cargo add offline-protocol
offline-protocol is the main protocol engine, with encryption on by default. It builds on sibling crates, each with one job:
| Crate | Role |
|---|---|
offline-protocol-core | Core types and data structures |
offline-protocol-sealed | Sealed-envelope codec, address derivation and signing payloads, shared with bare-metal leaf nodes |
offline-protocol-transport | The transport abstraction for Bluetooth LE, Wi-Fi, internet, Reticulum and Nostr |
offline-protocol-router | DORS routing and relay management |
offline-protocol-reliability | Acknowledgments, retries and deduplication |
offline-protocol-mls | End-to-end encryption with MLS (RFC 9420) |
offline-protocol-services | Service discovery and request and response over the mesh |
offline-protocol-data | Replicated documents (CRDT) that merge after offline edits |
offline-protocol-leaf | A constrained device as a member that never commits, for bare metal |
offline-protocol-web | The engine for the experimental browser binding |
Crate versions match the release: offline-protocol 0.31.0 is the same release as the npm and PyPI packages of that number. The crates are AGPL-3.0-only, with a commercial licence available.
I/O-free protocol engine
The Rust crates are I/O-free protocol engines for everything that moves a message. They keep status, send and receive queues, metrics and Bluetooth LE fragmentation state, and they route, encrypt and pick a transport, but they never open a socket or touch a radio for the protocol itself. The one socket they do open is the telemetry pipe’s HTTPS upload, and only once an app enables telemetry with a key.
That split is what lets the same engine sit inside an iOS app, an Android app and a Python gateway. It also defines the work: the React Native and Python packages ship the platform bridges, and when you consume the crates directly with cargo add, you write the bridge yourself.
Platform bridge responsibilities
A platform bridge owns the real sockets, relays and radios, and the offline-protocol-transport crate documents its contract. The protocol engine talks to each transport through the Transport trait, where send() enqueues and receive() dequeues. The bridge works the other side of the same queues:
- Drain outbound work with
get_next_message(),get_next_signed_event()or, for Bluetooth LE,get_next_fragment(). - Perform the send over the real link.
- Report the outcome with
confirm_sent()orreport_send_failure(). - Inject inbound bytes with
on_data_received()oron_fragment_received(). - Drive availability with
on_status_changed().
Until a bridge is attached, send() only queues messages, and for every transport except Bluetooth LE, start() does not mark the transport available, so send() returns TransportNotAvailable. In a pure Rust integration, your bridge marks the transport available, drains the queues and does the I/O. Most transports signal pending work through a set_on_messages_available callback, so no poll timer is needed; the internet transport is the exception and must be polled.
The bridge also supplies persistent storage for the target, and storage is the other half of what the platforms page lists for a Rust integration.
Built-in file stores for Rust hosts
The offline-protocol crate includes file stores for a host with no platform keystore, behind its default file-store feature:
| Type | Role |
|---|---|
SealedFileMlsStorage | MLS material sealed with ChaCha20-Poly1305 under keys derived from an operator-supplied store key and the account namespace |
FileProtocolStateStorage | Protocol state in the same format the iOS, Android and Python providers write |
FileStorePair::open | Opens both stores together and refuses directory pairs the engine would lose data over |
EnvStoreKey, StaticStoreKey | Store key from the OFFLINE_PROTOCOL_STORE_KEY environment variable, or from bytes the host already holds |
A wrong key is refused at open with FileStoreError::WrongStoreKey before any record is read. Each store locks its directory while open, so a second engine over the same directories fails with FileStoreError::InUse. Because the state format is shared, a state directory opens under any binding for the same account. The SDK’s replicated_notes example runs on these stores.
Rust version requirement
The crates need Rust 1.87 or newer, the rust-version the workspace manifest declares. Building the native library behind the other bindings from source is a separate case: the Python, C and Flutter docs ask for Rust 1.91 or newer for that build.
offline-protocol-leaf for microcontrollers
offline-protocol-leaf is the crate for firmware that takes part in the encrypted mesh, on a device such as a lock or a sensor. It builds without default features for bare-metal targets, the no_std style of Rust used in firmware, and its build targets include ESP32-C6, ESP32-H2, ESP32-C3 and ESP32-C2 (RISC-V), Cortex-M0, Cortex-M33 and WASI.
A leaf is an MLS group member that receives, responds and persists its state, and a full peer, such as a phone or a Linux host, creates the group and handles membership changes. Firmware supplies the radio I/O, a hardware entropy source, the time at pairing and durable storage through LeafStore. Which microcontrollers can run Offline Protocol? has the full target table, and Can a microcontroller run end-to-end encrypted mesh messaging? covers the memory and design questions.
Rust crates or a ready binding
Use the crates directly when you need the engine inside your own Rust program, a platform no binding covers, or firmware. If you want transports already wired, a ready binding saves the bridge work: React Native on phones, or Python on macOS, Linux and Windows hosts, ships Bluetooth LE, peer-stream and relay bridges over the same engine.