For engineers The design, in enough detail to judge it

How Mirage works.

What the cryptography does, what the infrastructure can and cannot see, and how the engine fits inside another product. Plain about the parts that are finished and the parts that are not.

A message inside two layers of protection: sealed by the session, then carried inside an encrypted QUIC tunnel. hello OUTER LAYER QUIC · TLS 1.3 INNER SEAL per-message key CONTENT only the ends see it
Threat model

Start with what it does not do.

Every messenger protects against something and leaves something else exposed. A design can only be judged once both halves are on the table.

Holds up against

  • An ISP or network operator reading message or call content
  • The relay operator reading anything it carries, including us
  • Someone reading your contact list off our servers: it is not there
  • Past traffic being decrypted after a key is later compromised
  • Tampering with a message in transit, which is detected, not just unlikely

Does not protect against

  • A compromised endpoint: malware or a screen reader on your own device
  • The person you are talking to, who can always keep or forward what you send
  • A global adversary correlating timing across the whole network
  • Someone who obtains your recovery phrase
  • Anyone watching your local link learning that you are connected at all
No external audit has been done yet. The design is described here so it can be reviewed, not because it already has been. Treat it as a protocol worth examining rather than one already vouched for.
Identity

There is no account, only a key.

No phone number, no email, no registration. A user is a public key, and the identifier other people see is derived from it. Nothing about the identity needs a server to exist.

Identity is designed in two tiers so that losing hardware is not the same as losing the account. A root key (Ed25519) never encrypts anything; its only job is to sign a versioned roster, the list of devices that currently belong to you. Publishing a new roster version is how a stolen device gets revoked. Multi-device in progress

Verification works the way it should: compare a fingerprint out of band. The app shows it in short groups so it can be read aloud. If you lose every device, a BIP-39 recovery phrase restores the account.

Sessions

Keys move forward, never back.

A conversation starts with an X3DH key agreement over X25519, which lets the first message go out even while the other side is offline. From there the session runs a Double Ratchet: every message advances the key material, so a key stolen today does not open yesterday's traffic, and the session heals once a compromised key falls out of use.

Calls run their own ratchet, separate from text, because media keys rotate on a different rhythm. Content is sealed with ChaCha20-Poly1305 or AES-256-GCM. Both are authenticated encryption, so tampering is detected rather than merely unlikely.

Getting connected

Several routes, raced in parallel.

NAT is why most peer-to-peer software quietly falls back to a server. Mirage tries several strategies at once and takes whichever wins, so a direct path is used whenever one exists.

Straight to the peer

If the address is already known from peer exchange, a QUIC connection opens immediately and no server is involved.

Introduced by the mesh early

When other desktop nodes are reachable, they can help both sides punch out through their NATs instead of the central relay.

Hole punching via the relay

The relay times a UDP rendezvous between the two sides. It introduces them; it does not carry the session.

Through the relay, still sealed

When no direct path works, the relay forwards packets it cannot open. A TCP/443 fallback for networks that drop UDP entirely is planned

Infrastructure

What the relay can and cannot see.

The relay exists for discovery, NAT traversal and holding messages for people who are offline. It keeps no user accounts, and what it carries is sealed before it arrives. This is the honest inventory.

Message and call contentnever
Private keysnever
Your contact listnever
That an address connectedyes
Size and timing of relayed packetsyes
That a sealed envelope is waiting for someoneyes

The "yes" rows are the part worth arguing about, and they are why the design pushes so hard toward direct connections: what the relay never carries, it can never be asked to hand over.

Offline delivery

Sealed envelopes, held by someone who can't open them.

When the recipient is offline, the message is encrypted into an envelope and left with the relay. The envelope is authenticated, so the holder cannot alter it, and opaque, so the holder cannot read it. It is delivered when the recipient comes back; the relay learns only that something was waiting.

Today envelopes are kept in the relay's memory for up to a day. Letting desktop nodes in the mesh hold them instead, and encrypted history backup, are designed and in progress

Network resilience

Built for networks that get in the way.

Everything runs over QUIC on UDP/443, with TLS 1.3 inside, so certificates and session metadata are not visible to an analyser on the path. Control traffic (key exchange, peer discovery, presence) rides the same tunnel as messages. There is no second channel to watch.

Beyond that, the transport can shape its own packet stream so it does not carry the statistical fingerprint of a messenger. This hardening is an option for deployments on hostile or heavily filtered networks, not a requirement of the protocol.

The mechanism is deliberately not documented here. Publishing the specifics would mostly help the people building classifiers. The cryptography is the opposite case: its strength must never depend on secrecy, so it is described in full.

Rooms and groups

One idea for chats and calls: the room.

A text conversation and a call are the same object inside the engine: a room. Inside the QUIC connection each room uses independent streams, one for control, one for outgoing media and a separate incoming stream per participant, so one slow peer cannot stall everyone else.

Routers are blind: they forward sealed packets without holding the keys to any of them. One-to-one chats and calls ship today. Small group calls share a key agreed between the participants and are in testing for up to eight people. Group chats in progress

Group key management is moving to MLS (RFC 9420) through a Rust bridge around openmls. The bridge is built and load-tested; wiring it into the engine is the work in progress.

The engine

Five layers, nothing kept on disk.

All of the above lives in a C++20 core. The interface on top is replaceable; the desktop messenger is simply the first thing to sit there.

The core keeps nothing on disk. No database, no config files, no key store. It is an in-memory network engine that emits events, and everything persistent belongs to the application that embeds it. The rule exists for recoverability, and it happens to make the engine easy to host inside somebody else's product.

Mirage Engine

The same core, inside your product.

Mirage is proprietary and owned outright. If you need private communication inside something you are already building, the core can be licensed and integrated instead of rebuilt. The messenger is its reference application, not the only thing it can be.

A versioned C ABI

Callable from anything with an FFI: Node, Python, Go, Rust, C#, Swift. A context-owned, semantically versioned ABI 2.0 is in development and is the surface we will commit to.

Callback-driven

Register handlers for messages, room state, call events and decoded media. The engine drives your application; it does not impose an event loop of its own.

You own storage and UI

Keys, history and presentation stay inside your product, under your compliance and retention rules rather than ours.

Your infrastructure

The relay is a small Go service in one container. Run it in your own network and jurisdiction; it keeps no user accounts to migrate or subpoena.

/* ABI 2.0 (in development): the shape of an integration, names may still change */
mirage_abi_version(…);        /* major must match, minor at least yours */
mirage_context_create(…);     /* one engine per context, several per process */
mirage_set_callbacks(…);      /* messages, rooms, calls, media */
mirage_room_create(…);
mirage_room_send_text(…);
mirage_room_leave(…);
mirage_context_stop(…);
mirage_context_destroy(…);

Realistic fits: clinics and advisory apps, field and industrial tools that must keep working on difficult networks, hardware that needs an encrypted control channel, and products that would rather not hand their users' conversations to a messaging vendor.

Worth saying before you plan around it: the engine is in early access, no external security audit has been carried out, and there is no mobile build yet. If you are evaluating it for production, that is the first conversation to have, and we would rather have it early than sell past it.

Want to walk through the design?

We're happy to go through the protocol, the code or an integration with your engineers. Design partners get early access and a real say in what comes next.

Book a technical walkthrough

Or read about the design-partner programme.