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 are encrypted end-to-end; real-time voice and video work well on a decent connection.

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 it handles alerts in-app. A banner slides in at the top if a message arrives from a different conversation — if you are already reading that chat, nothing appears. System banners only fire when the app is in the background; the preview shown is the sender name and message body, already decrypted on your device, never fetched from a server.

Incoming calls use the native system call UI on iOS: the same full-screen lock-screen experience as a phone call, with answer and decline. Missed calls leave a local notification. Nothing about who called or from where leaves your phone in plaintext.

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 or calls, they can ask that host to send a content-free ping. For calls the ping silently wakes the app and rings. For messages the app fetches and decrypts locally, then shows a local banner. The host never receives the words.

Pings are rate-limited. This is not as reliable as iMessage — Focus, Low Power, or force-quit can delay or drop it. Do not rely on Horus as a pager.

Calls, media, groups

Voice and video calls are encrypted end-to-end. There is no clearnet meeting room. On a reasonable connection, call quality is comparable to modern messaging apps. Incoming calls ring on the lock screen on iOS, using the native system call UI. Missed calls show a notification on device.

During a video call you can switch between front and back camera without dropping the connection. Audio stays on earpiece by default for voice calls and switches to speaker for video. Muting and ending a call works from the lock screen or Dynamic Island on iOS.

Photos, files, and voice notes you send live in the sealed transcript on both phones, not on a Horus CDN. Keep them reasonably sized — huge files are the wrong shape for an encrypted anonymous 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 once they have paired with each other, even if the group creator goes offline. Leaving wipes the group on that device. Delete 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, see Support. There is no recovery email. We cannot reset your identity.