onchato · companion to the specification
Four steps take two people from a public key to a conversation
nobody else can read, and no server holds anything in between. This page
explains the mechanisms. SPEC.md specifies them.
This page explains; it does not specify. Where it and
docs/SPEC.md disagree, the specification is right and this
page is the bug. Nothing here is a wire format, a field layout or a key
schedule you should build against — each section names the numbered
section that is.
Your identity is one X25519 key pair. On the intended deployment the private half lives inside a hardware security module and never comes out: the app asks the device to perform one Diffie-Hellman and gets back a shared secret, never the key. Copying the identity means stealing the device.
There is a second tier for people without hardware — a software profile, a key pair sealed in the browser under a password. It is the same identity contract and interoperates with hardware identities; what it gives up is that a copied profile can be attacked offline forever, which is why the password has a floor rather than a warning.
Specified in §4, software profiles in §4.5.
There is no lookup, no registry, and no server that knows who talks to whom. Two people who hold each other's public key both compute the same shared secret, and that secret names the place they meet. Each derives it from the opposite direction and arrives at the same answer, which is the one piece of arithmetic the whole design rests on.
Nobody else can compute it, because it needs a private key that never left either device. The meeting place also changes every day, and each pair rolls over at its own moment rather than at midnight, so the whole user base does not resubscribe at once.
Meeting is not trusting. In the meeting place the two run a handshake that proves each is holding the identity key the other expects, and produces a fresh session key that belongs to this conversation alone.
It mixes in a post-quantum key encapsulation alongside the classical exchange. The reason is not that today's attacker can break X25519; it is that traffic recorded today can be stored until something can. Both have to fall for the session key to fall.
Specified in §6. It takes one and a half round trips and rides the same meeting place, so no separate connection is opened.
The session key is not used to encrypt anything. It seeds a ratchet: a chain that steps forward for every message and, periodically, mixes in a fresh exchange from both sides — a Diffie–Hellman, and every so often a post-quantum key alongside it, the same hybrid the handshake uses. Each message is sealed under a key derived once and then thrown away.
The consequence is the point. Compromise a device now and you get what it currently holds. You do not get last week, because those keys are gone and cannot be recomputed. You do not get next week either, because the next exchange heals the chain past the point you saw — and because that exchange is post-quantum too, a future quantum attacker who captured the chain is locked out at the next mix, not merely at the next full handshake.
Once a conversation exists there are two routes, and neither is free. Through the node, a message is ciphertext the operator forwards; the operator learns that some topic was busy, when, and how large the frames were. Directly, peer to peer, the node sees nothing at all — but the two devices exchange network addresses to find each other, so each learns roughly where the other is.
There is no setting that costs nothing, which is why the app states the trade rather than choosing quietly. The default is the node, because hiding your address from the person you are talking to is usually worth more than hiding your timing from an operator who cannot read anything anyway.
A group is a layer over the same one-to-one machinery, not a new service. Each member has a sending chain of their own; the key to read it is handed to the others over their existing encrypted one-to-one channels. Membership lives with the members, so there is nothing to ask and no operator who knows the roster.
Every message also carries a separate authentication tag for each recipient, derived from a secret only that pair shares. A member who holds somebody's sending chain can therefore read their messages but cannot forge one to a third person — and because those tags are shared secrets rather than signatures, nothing anyone receives can later be shown to an outsider as proof of who wrote it.
Removing somebody rotates the group to a new epoch with a new meeting place and fresh keys, distributed only to those who remain.
Specified in §8.
Several things this product does not have are decisions rather than gaps, and each was cheaper to build than to leave out.