In development. RVNT is pre-release — not yet security-audited. Source code, public builds, and the iOS / App Store release aren’t available yet. See the roadmap →

Prekey Bundles: How Encrypted Chat Works When You're Offline

You open a messaging app, type “hey, you up?” to someone whose phone is dark on a nightstand three time zones away, and hit send. The message is end-to-end encrypted before it leaves your device. But encryption requires a shared secret key, and a shared secret normally takes two live participants negotiating it together. Your contact is asleep. There is no one on the other end to negotiate with. So how did your app produce a key that only the two of you can ever reconstruct — without either of you being online at the same time?

The answer is a small, unglamorous data structure called a prekey bundle: a packet of public keys your contact published in advance so that anyone can start an encrypted conversation with them later, alone, without their participation. It is the piece of plumbing that makes secure messaging feel like email instead of a phone call. Understanding it explains a lot about why modern encrypted chat is both remarkably private and quietly dependent on one verification step most people skip.

The asynchronous problem

Classic Diffie-Hellman key exchange — the textbook way two parties agree on a secret over an open channel — assumes both parties are online. Each side generates a fresh ephemeral keypair, sends the other its public half, and combines its own private key with the peer’s public key to arrive at the same shared value. It is elegant and it works, but it is fundamentally a handshake: a back-and-forth that needs both hands present at the same moment.

Real conversations are asynchronous. People are asleep, on planes, out of signal, or simply ignoring you. A protocol that requires a live handshake can’t deliver the first message until both devices happen to be awake together.

The pre-2010 workaround was ugly: queue an encryption request, wait for the recipient to come online, run the handshake, then finally send the message. That is slow, leaks the fact that you’re trying to reach someone, and falls apart the instant either party has flaky connectivity. The breakthrough — formalized by Trevor Perrin and Moxie Marlinspike in the Extended Triple Diffie-Hellman (X3DH) specification — was to let one party do their half of the handshake ahead of time and leave the results sitting on a server for whoever wants them. That cached half-handshake is the prekey bundle.

What’s actually in a prekey bundle

When your contact first set up the app, their device generated several keypairs and uploaded only the public halves. A prekey bundle, as defined in the X3DH spec, contains:

  • The identity key (IK) — a long-lived public key that is the cryptographic identity of that account. It rarely or never changes. In RVNT this is an Ed25519 key claimed by proof of work rather than tied to a phone number or email.
  • A signed prekey (SPK) — a medium-lived key the account rotates periodically (days to weeks). Crucially, it ships with a signature from the identity key over the prekey, proving the same account that owns the identity also authorized this prekey.
  • A batch of one-time prekeys (OPKs) — single-use public keys, of which the server hands out exactly one per requester and then deletes it.

The signature is the load-bearing detail. When you fetch a bundle, the first thing your client does is verify the signed prekey against the identity key. The X3DH spec is explicit: “Alice verifies the prekey signature and aborts the protocol if verification fails.” That check ensures the prekey wasn’t swapped out by whoever stored the bundle — a point we’ll return to, because it has a sharp edge.

Key in the bundleLifetimeJob
Identity key (IK)PermanentAuthenticates the account; anchors trust
Signed prekey (SPK)Medium-term, rotatedProvides authentication + forward secrecy; signed by IK
One-time prekey (OPK)Single use, consumedAdds forward secrecy and replay protection

Deriving a shared secret, alone

Here is the part that feels like sleight of hand. With the bundle in hand, you generate one ephemeral keypair of your own and then perform a series of Diffie-Hellman operations — combining your private keys with their public keys — to compute a shared secret. Your contact, when they eventually wake up and receive your first message, runs the mirror-image computation with their private keys and your public ephemeral key, and lands on the identical secret. Neither of you was online with the other; the math simply meets in the middle.

X3DH does this not once but with several DH operations layered together. RVNT’s hybrid key exchange performs four:

DH1 = DH(IK_A, SPK_B)   identity ↔ signed prekey   → mutual authentication
DH2 = DH(EK_A, IK_B)    ephemeral ↔ identity        → forward secrecy
DH3 = DH(EK_A, SPK_B)   ephemeral ↔ signed prekey   → forward secrecy
DH4 = DH(EK_A, OPK_B)   ephemeral ↔ one-time prekey → replay protection

Each line buys a distinct security property. DH1 binds both identity keys, so an attacker who doesn’t hold a private identity key can’t produce the secret — that’s the mutual authentication. DH2 and DH3 fold in your single-use ephemeral key, so even if a long-term key is stolen later, this session’s secret is unrecoverable, because the ephemeral private key was deleted right after use. DH4 consumes a one-time prekey, which the server deletes on handout, so an attacker can’t replay your opening message to spin up a duplicate session.

All of these outputs are concatenated and run through HKDF to produce a single root secret. An attacker has to compromise every relevant private key to reconstruct it; any one key alone is useless. That root secret then seeds the Double Ratchet, which takes over and gives every subsequent message its own forward-secret key — the subject of a separate deep dive.

There’s a quantum wrinkle worth naming. Plain DH is breakable by a future quantum computer running Shor’s algorithm, which threatens harvest-now-decrypt-later attacks — recording today’s ciphertext to crack a decade from now. RVNT therefore adds a fifth agreement: an ML-KEM-768 encapsulation, the lattice-based KEM standardized in FIPS 203 (published August 13, 2024). Its shared secret is concatenated alongside the four DH outputs before hashing, so the session stays secure as long as either the classical or the post-quantum half holds.

The server’s deliberately narrow job

Notice what the server did in all of this: it stored some public keys and handed one bundle to whoever asked. That’s it. It never saw a private key, never participated in deriving the secret, and cannot decrypt anything that follows. In RVNT there is no content server at all — the app is fully peer-to-peer — but even in a server-mediated design like Signal’s, the server’s role in key exchange is intentionally minimal. As the X3DH spec puts it, once both parties authenticate each other, “the only additional attack available to the server is to refuse to hand out one-time prekeys.”

That phrase — the only additional attack — is doing a lot of work, and it conceals the one real danger.

The server has to vouch for which identity key belongs to which account, because it’s the one serving you the bundle. If the server is honest, fine. If the server is compromised, coerced, or simply lying, it can hand you a bundle containing an identity key it controls instead of your contact’s. You’d derive a perfectly valid shared secret — with the attacker. The attacker decrypts your message, re-encrypts it under your contact’s real key, and forwards it along. Classic machine-in-the-middle, and the prekey signature check does not save you here: the malicious bundle is internally consistent because the attacker signed their own fake prekey with their own fake identity key. Everything verifies. It just verifies against the wrong person.

Verification is the step that closes the hole

This is exactly the gap that key verification exists to close, and it’s why every serious encrypted messenger offers some form of safety number or fingerprint comparison. The principle is simple: each conversation has a value derived from both parties’ real identity keys. If you and your contact compare that value through a channel the server doesn’t control — reading it aloud on a phone call, scanning a QR code in person, posting it somewhere the attacker can’t forge — and the values match, you’ve proven that no substituted key sits between you. The X3DH spec recommends precisely this: “Before or after an X3DH key agreement, the parties may compare their identity public keys through some authenticated channel.”

The cryptography guarantees you have a secure channel to someone. Verification is how you confirm that someone is who you think it is. Skip it and a key-substitution attack is undetectable.

RVNT exposes this as a verification step you can walk through with a contact (how to verify), and because it has no central content server, the trust surface is already smaller than in a server-mediated system. But smaller is not zero, and RVNT does not pretend otherwise: if you never verify, a hostile relay or a spoofed bundle source could in principle insert itself, exactly as with any other protocol in this family. Verification remains the human step the math cannot do for you.

What this does and doesn’t protect

It’s worth being precise about the boundary. Prekey bundles and X3DH protect the contents of your conversation and provide forward secrecy and post-quantum hedging for the key exchange. They do not, on their own, hide that you’re talking to someone, when, or how often — that’s metadata, and it leaks through the act of fetching a bundle in the first place. RVNT layers sealed sender, Tor routing, and a mixnet on top to attack that surface, but those are separate mechanisms from the key exchange described here.

And the honest caveats apply throughout: RVNT is pre-release software and has not been independently audited. The design follows well-studied constructions — X3DH, the Double Ratchet, FIPS-standardized post-quantum KEMs — but “follows good designs” and “has been proven correct in practice by outside experts” are different claims, and only the first one is true today.

What the prekey bundle gets right is the quiet miracle most people never think about: the ability to start a genuinely private conversation with someone who isn’t there. A few public keys, published in advance, let a stranger’s first message arrive already encrypted to a recipient who was asleep when it was composed. The only thing the math can’t supply is the last mile of trust — and that, deliberately, it hands back to you.

Keep reading

All posts →