Horus

A private line.

No phone number. No cloud account. No feed. Horus is a sealed channel between you and the people you invite. Encryption happens on the phone. What leaves the device is an opaque blob.

What it is

Horus is a messenger for people who do not want to be found by a phone number, or stored on someone else’s server. Mainstream apps trade convenience for a graph: SIM, email, a cloud inbox, a backup they can see or subpoena. Horus takes the other side of that trade.

You create keys on the device. You pair with a one-time invite — a link, a QR code, or a nearby Bluetooth match. You talk over an embedded Tor path. Relays only ever see opaque blobs: never the words, photos, files, or call audio inside.

It ships as two native apps, iOS and Android, sharing one protocol. There is no Horus message server. Nothing from a chat is written on a blockchain. There is no public directory of who talks to whom.

What it is not

Horus is not a social network. There is no public profile for messaging, no “people you may know,” no phone-number graph, and no cloud backup of your chats operated by us.

It is not a blockchain messenger. An optional @ handle can be claimed so someone who already knows the name can find an invite. That registry stores a commitment, not your messages. Threads are invite sessions, not usernames.

It is not iMessage, WhatsApp, or Telegram. Delivery needs a path: Tor must be reachable, or a nearby peer you trust must help. Notifications are best-effort. If the app is force-quit and wake is off, mail waits until you open Horus again. Calls over Tor can feel slow. Video is beta.

It is not a recovery service. Lose the phone, uninstall, or wipe the app — the keys go with it. We cannot reset you.

How you start

Install from the store (when listed) or build from the public source. On first launch the app creates keys locally and asks for a display name. That name is a label on your phone. It is not registered with Horus. Nobody gets a “new user” event on our servers, because there are no user servers for chat.

The first launch also starts Tor inside the app. The first time can take several minutes while directory data is fetched. Later launches reuse what was cached. Stay on a network that can actually reach Tor. If you force-close during that first setup, you just wait longer next time — you do not create a second identity.

Install
Local keys
Invite
Accept
Chat
Link, QR, or nearby Bluetooth. You accept before the channel is live.
  1. Create a one-time invite, or join one someone sent you.
  2. The other person redeems it. Invites expire and are burned after a successful join.
  3. You accept. Until then the chat is not live. Incoming ciphertext is held, not dropped, so the first messages are not lost on the doorstep.
  4. After accept, both sides have a Double Ratchet session. That is the whole handshake. There is no “add friend by phone number” step after that.

Nearby Bluetooth is a different confirmation: you both see a short code. Matching that code is the human check. Remote link and QR still use an Accept step, because you cannot see the other person in the room.

Treat an unused invite like a secret. Anyone with the link can try to join until you accept, it expires, or it is burned. Do not post it in a public story.

How messages move

Encryption and transport are separate jobs. The app encrypts on the phone. What leaves is a blob that looks like noise. A pipe then moves that blob. In production the pipe is an published by Tor running inside the app — not Orbot, not a VPN we sell, not a Horus datacenter holding plaintext.

Your phone
Sealed blob
Tor
Their phone
Plaintext never goes to a Horus server. Relays see ciphertext only.

There is no central inbox we operate. Each conversation rendezvous on an onion mailbox. Both sides send and fetch sealed mail over Tor. If the path is down, the app keeps an outbox on the phone and flushes when it can. You can type while offline. Delivery happens when both sides have a path again.

The other person’s phone must be able to fetch. That means Horus is open, kept alive with Stay connected, or — if they opted in — woken by a content-free ping. We cannot push the message body through Apple or Google. We do not have it.

Nearby Bluetooth is optional and local: pairing codes, and — if you turn on sharing an uplink — a sealed hop through a friend who is already online. We do not receive a map of who is near whom. Bluetooth is not a location product. On some older Android versions the OS still asks for a location permission in order to scan. That is the OS. We do not collect coordinates from it.

How it works — technical

The product description above is the user path. This section is the mechanism, at the level you can publish without handing an adversary a runbook. Encryption is not “the app is on HTTPS.” Transport is not “we have a server.” Discovery is not “the chat lives on a chain.”

Dotted underlines are definitions. Solid underlines leave the page or jump the notebook.

Three planes stay apart on purpose:

Plane Job Where it runs
Cryptography Seal and open payloads; ratchet session keys On the phone, in the shared protocol
Transmission Move opaque blobs; never interpret them Embedded Tor; optional local Bluetooth
Discovery Optional @ lock so a stranger can find an invite Public commitment registry — not the chat
Plaintext in the UI
ratchet + AEAD
Opaque blob
blind pipe
Tor / nearby
Peer decrypts on device
A relay that carries the blob cannot turn it back into a message.

Cryptography

Identity is generated on first launch (X25519, plus a encapsulation key for the invite). There is no Horus CA and no account key we keep. Lose the install, lose the identity.

Pairing is the only time a runs. After accept, 1:1 mail is a with . That is the same shape as Signal: and break-in recovery over time, not a single static key for the life of the chat.

Layer Construction Deliberately not
Invite Single-use, time-limited; hybrid root A reusable user id; a phone-number prekey server
1:1 chat Double Ratchet + ChaCha20-Poly1305 TLS to a Horus API that can read the body
Groups Encrypted fan-out among members who already have 1:1s A Horus group server, or MLS (not shipped)
At rest Platform keystore / Keychain-backed ciphertext on device An unencrypted export we host
1

Creator builds an invite: handshake material, expiry, one-time use. The blob is a secret until it is burned.

2

Joiner redeems (link, QR, or nearby). They send a hello onto the creator’s onion path — still ciphertext, still not a Horus inbox.

3

Creator accepts. Pre-accept ciphertext is buffered, not dropped. After accept both sides have ratchet state.

4

Send and poll are only sealed frames. Receipts ride inside that encryption. We never get a plaintext carbon copy.

Groups do not get a special Horus mailbox. Members already paired 1:1; the group payload is sealed and fanned out on those sessions. Leave wipes this device. Delete-for-everyone asks every member to wipe. That is weaker than a full MLS membership story — we do not pretend otherwise.

Transmission

The protocol encrypts first. A pipe then carries bytes it cannot read. Production is embedded Tor on both iOS and Android: the app publishes an and speaks SOCKS to the Tor network from inside the process. You do not install a separate helper.

On this phone
App
Protocol
Embedded Tor
↓ ciphertext only
Tor relays
Peer onion
Peer app
Both sides rendezvous on the conversation’s onion path. Relays are untrusted with content.
Path When What it carries
Tor onion mailbox Default production AEAD ciphertext; circuit metadata Tor already has
Local Path down Sealed frames waiting on the device
Nearby Bluetooth Optional pairing / optional sealed hop Invite chunks or already-sealed payloads, on-device
Optional, off by default Generic OS banner; never the message

Calls use the same sealed path, not clearnet WebRTC. That is why they can be slow. Other pipes exist for development or experiments; they still only see blobs. We do not publish operator endpoints here.

On-chain locks

The chain is not the messenger. It is an optional lock so a name can be unique and resolvable to a new invite, without publishing a map of username → encryption key.

Discovery (optional)
@handle
commitment only
Public registry
Burnable invite
Messaging (always off-chain)
Session / invite id
Double Ratchet
Tor blobs
Renaming @ does not move, rename, or delete existing sessions.
The registry may hold It does not hold
A that a name is taken Your onion, your device, your chats
A findable invite blob, if you chose to be findable A public key directory for everyone to scrape
An install-scoped lock so one install cannot squat every name Your IP address, or an advertising identifier

Salt that would let you update the lock later stays on the phone. Changing @ frees the old name. One handle per install. After you already chat, a handle can show on their profile of you because the session announced it peer-to-peer — not because they queried the chain for every message.

We do not publish canister identifiers, gateway URLs, or the exact hash construction here. Those are implementation details in the source, not something this page should amplify.

What “sealed” means

On the wire, a message is . Forged blobs fail closed: they do not decrypt. After you pair, the session uses a so keys move forward. The invite handshake includes a step so the opening of the session is not only classical Diffie–Hellman.

Photos, files, and voice notes go through the same sealed transcript. They are compressed to stay small enough for Tor. A raw camera roll dump is the wrong shape for this path. Calls are encrypted voice (and beta video) over the same kind of sealed path — not a clearnet WebRTC meeting room.

Receipts (delivered / read) travel inside the encryption, not as a cloud tick we log. Timestamps you see are the time on the device, not a server clock we own.

“Sealed” does not mean invisible. Tor still has circuits. Volume and timing can show that something is moving. A person you accepted can still screenshot, forward, or lie. Android can block screenshots in the app; iOS cannot do that reliably, so we do not pretend it does.

Chat and @ are different planes

Every thread is keyed by the invite that created it — a session, not a username. Claiming or renaming @ does not move, rename, or delete chats. If you already talk to someone, changing your handle does not break that thread.

Discovery — optional

You may claim a handle so someone who already knows @you can start a new invite. The registry stores a lock, not a public key directory, and never your messages. One handle per install. Changing it frees the old name; someone else may take it later.

Messaging — always off-chain

Mail is Double Ratchet ciphertext over Tor. After you are already chatting, your handle can show on their profile of you because the session announces it peer-to-peer — not because they look you up on a chain again.

A handle is a label, not a login. Reinstall and you start over. We cannot restore keys. Do not treat @ as a permanent identity you could recover from us.

On this phone

History lives on the device, sealed at rest. Android uses the system keystore. iOS uses the Keychain plus on-device encryption. Optional App Lock (biometrics or the device passcode) can gate the UI when you leave the app. It is off until you turn it on. Locking the UI is not the same as encrypting the disk — it is a door on the app.

Display name, appearance, app icon, Stay connected, Wake when closed, Share uplink: those are local preferences. They are not a Horus profile page.

Uninstalling Horus deletes what the app stored locally. That is how you delete your data. We cannot reach into the phone to wipe a chat, and we cannot decrypt a transcript we never held.

Trusted with plaintext
Keys
UI
History
Not trusted with plaintext
Tor relays
Handle registry
Wake host
Only the two phones in a session can open the blob.

Notifications

When Horus is open, or kept alive with Stay connected, it fetches mail itself and can show a local alert. The banner does not include the message body. Stay connected is best-effort: it helps while the OS still lets the app work. Force-quit still needs something else.

Wake when closed is optional and off by default. If you enable it, a wake host we operate may hold a random wake id and the device token Apple or Google issued to this install. When someone writes to you, they can ask that host to ping your token with a generic banner — “You have a new message” — and no preview. Ciphertext still travels on Tor. The host never receives the words.

Apple and Google see that a generic notification went to that token. Knowing the wake id is enough to request a ping. Pings are rate-limited. This is not as reliable as iMessage: Focus, Low Power, or force-quit can delay or drop it. Do not buy Horus as a pager.

Calls, media, groups

Voice is encrypted over the same Tor path as chat. It can be slower than an ordinary cellular call. That is honest, not a bug we hide. Video exists and is marked beta — treat it as experimental. There is no clearnet meeting room, no ICE to a Google stun server for the call itself.

Photos and files you send live in the sealed transcript on both phones, not on a Horus CDN. Keep them small. Huge media is the wrong tool for this path.

Groups are encrypted among the members. There is no Horus group server holding membership or history. You add people you already have as 1:1 contacts. Members can keep talking if the person who created the group goes offline, once they have paired with each other. Leaving wipes the group on that device. Deleting for everyone asks every member to wipe the transcript.

How your data is handled

The short version: we do not run a cloud account, we do not store your chats, and we do not sell data. There is no analytics SDK. The longer version is the Privacy Policy.

Never collected by Horus

  • Phone number, email, or password
  • Message bodies, photos, files, call audio
  • Address book, precise location, advertising IDs
  • Analytics or crash reports from an SDK

May exist outside the phone

  • Tor: circuits and ciphertext, not the message
  • Optional @: a commitment, not the chat
  • Optional wake: random id + device token
  • This website: theme preference in local storage

Permissions the OS may ask for: Bluetooth (nearby pairing, on-device), Camera (QR), Microphone (calls), Notifications. You can refuse them. Features that need them will simply not work. None of those permissions are a side channel we use to build a profile.

This website is static. It does not set analytics cookies. The only thing it stores in the browser is whether you chose Dark.

If you lose the phone

The keys are on that install. There is no Horus backup account. A hardware backup you make yourself is your business; we do not run one. Get a new phone, install Horus, you are a new person as far as the protocol is concerned. Old chats do not follow you. People will need to invite you again.

If Wake when closed was on, uninstalling (or the token going stale) is how that ping stops. We cannot decrypt old mail sitting on someone else’s device. Unsend is not a cloud delete. If you already sent it, they have it.

What we do not claim

A compromised phone is game over for that user. Malware on the device can read the screen. We cannot prevent that.

Tor raises the cost of watching you. It is not magic against a well-resourced adversary who can watch both ends of a path for a long time. Timing and volume can still leak that something is moving.

Horus has not had an independent security audit. Do not treat it as “production hardened” in the sense of a reviewed, insured product. The protocol is open. The limits are listed here on purpose.

If you need help, open an issue on the public repository — see Support. There is no recovery email. We cannot reset your identity.