The canonical codebase is the Rust crate under sonicdrop-rs/ (Tokio, libp2p, SQLite, Protobuf). Where this document uses formulas or abstract names, the exact wire layouts, HKDF info strings, and defaults are defined in source - notably:
- Crypto & addressing:
sonicdrop-rs/src/crypto/mod.rs(compute_target_hash,derive_session_key, inner payload AES-GCM with AAD =H_target). - Onion:
sonicdrop-rs/src/network/onion.rs(layer encryption, ephemeral Ed25519, HKDF labelslayer_store/layer_relay). - Protocol state machine:
sonicdrop-rs/src/protocol/{send,receive,resend,epoch}.rs. - Persistence:
sonicdrop-rs/migrations/*.sql,sonicdrop-rs/src/state/. - Network runtime:
sonicdrop-rs/src/network/{dht,unified,onion_transport}.rs. - Handshake (ultrasonic + WAJ):
sonicdrop-rs/src/handshake/.
See ARCHITECTURE.md for a full module map and sonicdrop-rs/SPEC_GAP_CHECKLIST.md for spec-vs-code parity. SECURITY.md lists the Rust stack’s HKDF salt/info inventory.
SonicDrop is an asynchronous, high-latency messaging protocol designed for "Metadata-Free" communication. Unlike standard instant messengers (which rely on a central server routing messages between sockets), Sonic-Drop treats the network as a passive storage medium.
-
Topology: A Distributed Hash Table (DHT) overlay network where nodes act as temporary storage silos (Inboxes).
-
Directionality: Communication occurs on two mathematically distinct, unidirectional tracks (
$A \to B$ and$B \to A$ ). -
Addressing: Addresses are ephemeral. They exist only for the duration of a message's Time-To-Live (TTL) and are derived deterministically.
Objective: To establish a shared cryptographic state and a "Root of Trust" without relying on internet infrastructure or Public Key Infrastructure (PKI).
Mechanism:
Alice and Bob meet physically. Their devices perform an air-gapped Diffie-Hellman exchange using near-ultrasonic frequencies (18kHz-24kHz). This band is chosen to prevent remote interception (audio attenuates quickly) while remaining audible to standard hardware microphones/speakers.
The Shared State (
At the end of the handshake, both devices possess:
-
Root Key (
$K_{root}$ ): The master secret derived via ECDH. -
Epoch Nonce (
$E$ ): Initialized to$0$ . -
State Counters:
$C_{A\to B} = 0$ ,$C_{B\to A} = 0$ . -
The Backup Pool (
$P_{backup}$ ): A list of$n$ high-uptime, static nodes (Entry Nodes) used solely for "Epoch Recovery" (Phase 5).
Context: Alice (
Alice does not send the message to Bob. She calculates where Bob will be looking. She derives the Target_Hash for the current counter index.
Alice performs a DHT lookup to find the neighborhood of nodes responsible for
To ensure message ordering and replay protection, the internal payload is structured as follows:
The payload is encoded as protobuf InnerPayload (header, message_body, counter, timestamp, resend metadata), then encrypted under AES-GCM with H_target as AAD.
-
Local History: Alice caches this payload in her local
Buffer_History(a hash map keyed by$C_{A\to B}$ ) for$r$ generations to facilitate potential future resends.
Alice constructs a nested onion packet. Unlike Tor (which focuses on a stream), this is a packet-switched "Drop" command. She selects
The final layer (the exit node/Inbox) receives a specific instruction:
CMD: STORE
KEY:
VAL:
Once the packet is injected into the network, Alice immediately increments
Context: A storage node (
The node is "oblivious" - it does not know who sent the packet (Alice is hidden by the Onion layers) nor who will retrieve it (Bob has not requested it yet).
-
Validation (on onion path): Relay/inbox nodes that unwrap onion layers verify the per-layer Ed25519 signature before accepting the layer content.
-
Storage:
$N$ storesVALatKEYin its local Kademlia-style table. -
TTL: A strict timer (e.g., 24 hours) is initiated. Upon expiration, the data is scrubbed. This provides Forward Secrecy; if Bob's key is compromised next week, messages sent today are already deleted from the network.
Context: Bob comes online. He calculates the addresses for his "Lookahead Window" - the next
Bob queries these addresses.
-
Cover Traffic: To an outside observer, Bob is querying random DHT hashes. If
$w=5$ , but only 1 message exists, the other 4 lookups act as natural dummy traffic. -
Retrieval: Bob downloads any data found.
Bob attempts to decrypt all blobs.
-
Success: He updates his local
$C_{read}$ to the highest contiguous index. -
Failure (The Gap): If Bob retrieves Message #5 and #7, but #6 returns
404 Not Found, he adds #6 to hisMissing_Set.
Every outgoing message includes a Header section. When Bob's Missing_Set is non-empty, he embeds a "Negative Acknowledgment" (NACK) vector in the header of his next outgoing message on the
Context: Alice receives Bob's message and sees NACK_Vector:[6].
Alice does not try to re-upload to Address #6. That address is "dead" (compromised, offline, or timed out).
The Encapsulated Resend:
-
Alice retrieves
$M_6$ from her local buffer. -
She wraps
$M_6$ inside a special frame called aResend_Tombstone. -
She transmits this inside her current outgoing message slot (e.g., #51).
Bob receives #51, unpacks it, identifies the resend flag, and virtually "backfills" slot #6 in his local database, allowing the conversation stream to resolve.
Context: A catastrophic desynchronization (counters drift too far, or the conversation has been dormant for months).
-
Beaconing: Bob polls the pre-shared Backup Pool nodes (
$B_{1...k}$ ). These act as "Dead Drop of Last Resort." -
Hard Resync: Bob posts a
HARD_RESYNCblob encrypted to Alice using X25519 ECDH, HKDF-SHA256 (SonicDrop_backup_v1/hard_resync), and AES-256-GCM, containing a new random Epoch Nonce ($E_{new}$ ). Only Alice, who holds the corresponding private key, can decrypt the command. -
Discovery: Alice, realizing the main chain is dead, polls the Backup Pool, finds the Resync command, decrypts it with her persistent X25519 private key, and updates her global state.
-
Replenishment: Upon the first successful message exchange on the new Epoch (tracked via an
epoch_backup_exchangedflag), Alice and Bob exchange a list of new Backup Nodes to replace the ones they just utilized, preventing analysis of the static backup addresses. The flag resets on each epoch transition.
Incoming messages are held for a random delay (default 1-5 seconds) before becoming retrievable. This breaks the tight time correlation between send and receive events, making traffic analysis attacks harder.
Nodes generate fake STORE commands to random peers at configurable intervals. This ensures real traffic is indistinguishable from background noise.
Inbox storage persists to SQLite on disk, allowing nodes to survive restarts without losing queued messages.
Per-direction AES-256 session keys are derived from
$$K_{session} = \text{HKDF}(K_{root}, \text{salt}=\text{"SonicDrop_session_v1"}, \text{info}=\text{"session_
_epoch_"})$$Each onion layer includes an Ed25519 signature over the encrypted inner payload. Relay nodes verify the signature before performing ECDH decryption, providing sender authentication independent of the AES-GCM tag.
| Parameter | Symbol | Default | Description |
|---|---|---|---|
| Buffer retention | 50 | Messages cached for potential resend | |
| Lookahead window | 5 | Addresses queried per sweep cycle | |
| Message TTL | - | 86 400 s (24 h) | Inbox expiry time |
| Relay hops | 2 | Onion routing relay count | |
| Redundancy | 3 | Storage nodes per message |