← callwhite

About the workYılmaz Mert · TRgenci

The longer version: what the system is and the engineering behind it.

The problem

End-to-end encryption is a solved engineering problem. The primitives are public, the libraries are audited, and a competent team can ship a messenger nobody can read. Almost everyone has.

Underneath, the layer nobody solved kept running. All of those systems still have to know which account to deliver to, which means a server that holds the answer to who is talking to whom. The content is sealed; the social graph is a table.

The distinction is not academic; it is a difference in cost. Reading one person's messages takes a warrant, an exploit or an analyst. Reading everyone's contact graph takes a database query — and unlike content, a contact graph is small, structured, keeps indefinitely, and joins easily with everything else anyone holds about you. It survives all of the encryption: knowing that a journalist and an official exchanged forty messages on a particular night rarely requires knowing what they said.

Metadata is the half that scales — and the half almost nobody removes, because removing it means giving up the server that makes delivery easy. callwhite gave it up.

What callwhite is

A messenger with no server in the message path. There is a relay, and it is deliberately simple: an opaque key-value store that accepts a fixed-size blob at an address, returns a fixed-size blob when asked, and knows nothing else. It cannot derive the addresses it is asked for, cannot tie an address to a sender, cannot tie a read to a reader.

Addresses come from a rolling chain both sides derive independently from key material only they hold. Nothing external links one address to the next; each looks unrelated to the one before. Write authority is bound to a per-slot blinded key rather than to an account, so the relay verifies that a write is legitimate without learning who wrote it. A query that finds nothing returns decoy bytes; the relay cannot even be used as an oracle for whether an address is in use.

Around that sits everything that makes a messenger a messenger: pairing that forces a safety-number comparison before sending, group chats with managed membership and a per-epoch secret, photos and voice notes split into the same fixed-size blobs as text, constant-rate read traffic under which an idle chat and a busy one look the same, memory-hard proof of work on every write, and a vault whose size does not change with what it holds.

How it is built

Eight Rust crates, two clients, one core. The cryptography does not know it has a user interface; the interface cannot make a cryptographic decision on its own. If a rule has to hold on both platforms, it lives in the core as a single function both clients call.

  • Core — Rust. Ratchet, addressing, framing, group epochs, cover traffic, vault. No I/O, no platform, no UI.
  • Android — Kotlin and Jetpack Compose, bound to the same core through a generated UniFFI bridge.
  • Desktop — Tauri; the interface is plain HTML and CSS, the decisions are in Rust. No framework, no bundled browser engine.
  • Relay — an opaque key-value store: returns decoy bytes on a miss, demands proof of work on every write, and keeps nothing that could become a contact graph.
  • Build — pinned toolchain, Clippy with -D warnings, a CycloneDX dependency inventory per release, and a signing key that never leaves the machine it lives on.

Discipline

One sentence: a fix does not count until something fails without it.

Every behavioural rule is pinned by a gate, and those gates are attacked: production code is deliberately broken and the gate is seen to fail. A gate that stays green under mutation does not count. 1233 automated tests hold four layers at once — Rust core, desktop client, browser layer, Android.

The codebase has been through nine structured internal adversarial review rounds; there has been no independent third-party audit. A finding only counts once it survives an attempt to refute it: one round confirmed 43 of 53 candidates, another 100 of 123; the last two ran with an independent refutation pass and 300 mutants actually executed. Closed code findings carry a regression test named after them wherever one can be written.

Both clients call the same core. Where a rule must hold on both platforms it lives in the core as one function, and tests verify that the two clients do the same thing — phone and desktop cannot silently diverge.

Contact

Available for remote contract and full-time work on systems, cryptography and Rust. The callwhite source is available for exclusive transfer.

Yılmaz Mert · GitHub · LinkedIn