Overview
ZeroByte is three things that share one specification:
- Relay Protocol v1: how two devices derive keys from a shared secret, how they seal messages into envelopes, and the small HTTP API a relay offers.
- The relay: a blind mailbox server. One file of protocol logic, run either as a Node server with one SQLite file or as a Cloudflare Worker with one Durable Object per mailbox. No dependencies.
- The SDKs: Swift, Kotlin, JavaScript and .NET libraries that implement the client side. Each is tested against the same known-answer vectors.
The problem it solves
A phone app with a desktop or watch companion needs to move data between them. The usual options each cost something:
- A cloud backend with accounts sees every byte and becomes a liability.
- Peer-to-peer on the local network only works while both devices are on the same network and awake at the same time.
- Platform sync services tie you to one vendor and often to one platform.
ZeroByte sits between these. The relay is a store-and-forward mailbox, so the devices do not need to be online together. Everything it stores is end-to-end encrypted under keys only the two devices hold, so the relay operator learns nothing beyond traffic metadata. You can run the relay yourself in a few minutes.
How it fits together
Primary device Relay Companion device
─────────────── ───── ────────────────
link key K, link id L link key K, link id L
│ HKDF │ HKDF
├─ mailbox id ───────────────▶ /v1/<app>/mailbox/<id> ◀──────────┤ mailbox id
├─ bearer token ─────────────▶ stores SHA-256(token) ◀──────────┤ bearer token
├─ p2c key (seal) ├─ p2c key (open)
└─ c2p key (open) └─ c2p key (seal)
send: seal(p2c) ──PUT p2c/<seq>──▶ [ envelope ] ──GET p2c?after──▶ open(p2c), then prune
watch: WebSocket: "17" ─────────────▶ fetch now- Pair. Your app gives both devices the same 32-byte link key and 16-byte link id. ZeroByte does not take part in pairing and never sees the key. See Pairing devices.
- Derive. Each SDK derives, from the link key and link id, the mailbox id, the bearer token and one encryption key per direction.
- Send.
Link.sendseals a message with ChaCha20-Poly1305, numbers it, and stores it in the mailbox. - Receive. The other device watches its direction over a WebSocket, fetches new envelopes, opens them and prunes what it has read from the relay.
- Unpair. Either device erases the mailbox. A mailbox nobody writes to for 30 days erases itself.
What ZeroByte is not
- Not a sync engine. It delivers opaque messages in order between exactly two devices. Merging state, resolving conflicts and choosing what to send are your app's job. See Designing messages.
- Not a backup. Envelopes are deleted once read and the whole mailbox is deleted after 30 idle days. Nothing on the relay is meant to last.
- Not group messaging. A link connects two devices. A phone with three companions has three links.
- Not anonymous. The relay sees IP addresses while requests last, request times and envelope sizes. See Security model.
- Not a pairing protocol. You choose how the two devices agree the link key. The guide describes two sound ways.
Requirements at a glance
| Part | Requirement |
|---|---|
| Relay on Node | Node 22.13 or newer, one writable directory |
| Relay on Docker | Docker with Compose, a DNS name for HTTPS |
| Relay on Cloudflare | A Cloudflare account with Workers and Durable Objects |
| Swift SDK | iOS 16, macOS 13, watchOS 9, tvOS 16, visionOS 1 |
| Android SDK | Android API 28, or any JVM 11 |
| JavaScript SDK | Browsers with WebCrypto, Node 20, Deno, Bun, Cloudflare Workers |
| .NET SDK | .NET 10; ChaCha20-Poly1305 support (Windows 10 20H2 or newer) |
Next
- Concepts explains the vocabulary used everywhere else.
- Quickstart runs a relay on your machine and sends a first message.