How Kant actually works.
No black boxes. Every layer below is built from named, look-up-able primitives — the same ones described in the project's own architecture docs, not marketing shorthand for something proprietary underneath.
Identity & handshake
Every peer is a deterministic Ed25519 keypair derived from the user's identity seed — there is no account, no username registered anywhere, and no server that assigns identity. Your PeerID and circuit address stay stable across restarts because they're derived, not allocated.
First contact between two peers runs an X3DH (Extended Triple Diffie-Hellman) key agreement against published prekeys and one-time prekeys (OPKs), establishing a shared secret neither peer had to transmit. From there, every conversation runs on a Double Ratchet: each message advances the ratchet, so compromising one message key never exposes the messages before or after it.
All of this lives in the shared core library, not the app — the same identity and session logic runs unmodified in the web client, the desktop build, and the CLI.
The relay is a bootstrap, not a server
Kant's relay is a stateless libp2p circuit-relay v2 bootstrap node. Peers register a signed circuit address with /register, and other peers discover them through /lookup. That's the entire job: rendezvous and relay-assisted connectivity, never message custody.
Registry entries are signed by the registering peer's identity key. Every request carries a nonce, and the relay rejects duplicates outright — a replayed /register or /lookup call doesn't get a second bite. Entries expire on TTL and get pruned on disconnect, so the registry never accumulates state beyond what's currently live.
The relay identity itself is deterministic — derived from a seed — so its multiaddr survives restarts without needing a fresh handshake from every client that already knows it.
Direct transport
Once two peers can reach each other — directly or through a circuit-relay reservation — messages travel over a custom length-prefixed framing protocol on two dedicated libp2p protocols: /kant/ping/1.0.0 for encrypted payloads and group messages, and /kant/receipt/1.0.0 for delivery and read receipts.
Frames are unidirectional by design — the sender writes and closes, rather than holding a connection open for a reply. It keeps the transport simple and makes the protocol easy to reason about frame-by-frame.
Group messaging
Group conversations run their own key handling and delivery path in the core library, distinct from the 1:1 ratchet — group membership, key rotation, and message fan-out are handled without routing group state through the relay. The relay still only ever sees ciphertext frames addressed to a peer it forwards to.
File transfer
Files are chunked, encrypted per-chunk, and sent resumably — a dropped connection doesn't mean starting over. Each chunk is independently verified, so partial transfers can be checked and retried without re-encrypting or re-sending data that already arrived intact.
Onion routing (optional)
For peers who want to hide routing metadata from the relay itself, Kant supports multi-hop onion routing with cover traffic, layered on top of the same transport. It's opt-in — direct or relay-assisted connectivity is the default, onion routing is there for the threat model that needs it.
Push wake-up, not push delivery
Android delivery uses a dedicated push-proxy service so relay operators never need Firebase credentials. The relay sends a wake signal only — never message content — through the proxy; the device then reconnects over libp2p and receives the real encrypted payload after waking. Firebase never sees anything beyond “wake up.”
Operational surface
The relay exposes the same health and metrics surface any production service would, so operators aren't flying blind:
/admin/reservations is bearer-token gated and not exposed unless explicitly configured — there's no unauthenticated admin surface reachable from the public internet by default.