2022 – Present
RelaySMS
Backend Engineer
RelaySMS is a transport layer between SMS and the rest of the internet. The app encrypts a message into a compact binary payload and sends it as a normal text to a gateway number. A gateway phone picks it up and forwards it to the Publisher, which decrypts it, checks who sent it, and posts it to the platform the user asked for using that user's own OAuth 2.0 or phone number based token. It is part of SMSWithoutBorders, built at Afkanerd and funded by the Open Technology Fund. I work on the protocol and the server side, and co-authored both papers that document it.
When the internet goes down, or where mobile data is unreliable or simply too expensive, SMS is often the last long distance channel standing. What it gives you is 140 bytes in a single message, and less than that once it has to segment. No end to end encryption. A bill for every segment sent. So every byte of protocol header is money out of somebody's pocket. The problem is to fit encrypted content, its routing metadata, and proof of who sent it into as few segments as possible, while making sure nobody in the middle can read a message or forge one: not the gateway, not the carrier, not even the server.
Clients
The Android and iOS apps keep the user's keys in the platform Keystore or Keychain, build and encrypt the payload, and send it through the phone's own modem. Keeping key material on the handset is what lets everything downstream be untrusted: nothing past the device holds anything that can open a message.
Gateway clients
Gateway clients are ordinary Android phones that take in incoming SMS and forward it to the Publisher over HTTPS, SMTP, or FTP. Three protocols rather than one, because any single one of them can be blocked. Forwarding is queued on the handset behind a connectivity listener, so texts that arrive while the phone is offline wait their turn instead of disappearing.
Publisher
A Python service speaking both gRPC and REST. It decrypts the payload, authenticates the sender, reads the header to work out whether to publish with an OAuth 2.0 token or a phone number based one, and hands the content to the right adapter. When something fails the user gets an SMS saying so, without a description of which stage broke.
Request authentication
Clients ship with the Publisher's long term identity key pinned, and open each request with a Noise NK 0-RTT handshake over a fresh X25519 key, carrying a nonce and a timestamp. Pinning the key closes off a man in the middle at the gateway; the nonce and timestamp mean a captured request is worthless the second time.
Token storage
Every stored platform token gets its own identifier, hash, and set of X25519 key pairs, and none of it is tied back to a user account. The identifiers travel encrypted and are only resolved at the two ends, so getting hold of the store does not also get you a map of who uses what.
Platform adapters
Gmail, X, Telegram, Bluesky, and Mastodon are each a self contained adapter with its own credentials and API client. Supporting a new platform means writing another adapter, not touching the Publisher.
Count the cost in segments
Every protocol decision got measured in SMS segments, because a segment is a real charge on somebody's balance. Content and cryptographic headers use a compact binary encoding instead of anything text based, and the payload specification paper exists to pin that encoding down. It is the contract between the apps and the server, and writing it separately from the code is the only reason someone else could implement it.
Assume the gateway and the carrier are reading
The gateway is a volunteer's handset and the carrier sees everything crossing its network. Neither gets trusted. Content is encrypted before it leaves the device, and the Publisher identifies the sender cryptographically, not by the number the message came from. Anyone can spoof that.
Keep tokens away from identity
Platform tokens sit in the store on their own terms, each with its own identifier and keys and no link back to an account. Someone who breaks in gets tokens, not a social graph.
Design for being blocked, not just for going down
In a shutdown the failure is rarely a flaky link. It is a protocol somebody has decided to block. Supporting HTTPS, SMTP, and FTP for forwarding means losing one does not take the relay with it. The on device queue covers the ordinary case, where the gateway phone simply has not found a connection yet.
A hard byte budget clarifies everything downstream of it. Once a header field costs the user money, it becomes very obvious which fields are doing work and which are there out of habit.
Writing the protocol down as a specification, apart from the implementation, is what makes it possible for anyone to check it or rebuild it. Code will tell you what a system does. It will not tell you what it was trying to do.
Naming the untrusted parties mattered more than choosing primitives. Picking a curve and a handshake is the straightforward part. Deciding that the gateway, the carrier, and our own server all count as adversaries is what actually shaped the design.
RelaySMS ships on Android and iOS and relays through volunteer run gateways. The protocol is documented in two public papers I co-authored, and the payload specification has its own Rust implementation.