Technical overview
How Pigeon works, in detail.
This page is for engineers, security researchers, and anyone who wants more than “it’s encrypted.” It covers the protocols, what our servers can observe, how the Bluetooth mesh routes messages, and where the gaps are today.
01Summary
Pigeon is an end-to-end encrypted messenger with two delivery paths: the internet, and a Bluetooth Low Energy mesh between nearby phones. Both paths carry the same ciphertext produced by one message core. Encryption happens above the transport, so neither our servers nor mesh relays ever hold keys that can open a private message.
- 1:1 messages
- Signal Protocol (PQXDH + Double Ratchet)
- Groups
- Sender Keys, up to 256 members
- Media
- AES-256-GCM, encrypted on device
- Backups
- Argon2id → AES-256-GCM
- Voice calls
- WebRTC DTLS-SRTP, sealed signaling
- Offline transport
- BLE GATT mesh, up to 7 hops
- Server sees
- Opaque envelopes and routing metadata
- On failure
- Fail closed, never “best effort” decrypt
02Architecture
The client is a single Flutter app for Windows, macOS, iOS, and Android. Messages are sealed into an envelope by a shared message service, then handed to whichever transport is available. The envelope keeps a stable ID across both paths, so a message sent over Bluetooth can later sync to the cloud without duplicating.
↓ SAME CIPHERTEXT, EITHER ROAD ↓
Transport is for delivery only. Trust comes from end-to-end encryption, never from TLS or the radio link.
Nearby messages are held in an outbox. When the device reconnects, they upload by the same envelope ID, and your other devices and the recipient merge them into the same chat.
03Cryptography
We use proven protocols rather than inventing our own. The Signal Protocol implementation is the official libsignal library.
| Use | Construction | Notes |
|---|---|---|
| 1:1 chats (cloud and Nearby) | Signal PQXDH + Double Ratchet | Post-quantum key agreement (Kyber prekeys). Forward secrecy and post-compromise recovery. |
| Groups | Sender Keys distributed over pairwise Signal sessions | Up to 256 members. Sender keys persist across restarts. |
| Public channels | Ed25519 signatures on posts | Public by design; signatures prove authorship. |
| Private channels | Shared AES-256-GCM key, admin-controlled | Key distributed inside E2EE envelopes. |
| Attachments | AES-256-GCM, fresh key and nonce per file | Keys travel inside the message envelope, never to the API. |
| Backups | Argon2id key derivation → AES-256-GCM | Passphrase never leaves the device. |
| Device identity | Ed25519 device key + device-bound tokens | Revocable per device. |
| Key storage | Keychain, Android Keystore, Windows secure storage | Keys leave secure storage only in memory for crypto operations. |
Verification
Every conversation has a safety number that both people can compare or scan as a QR code. Before a first Nearby chat, Pigeon requires the two people to verify safety numbers in person. There is no silent trust-on-first-use over the radio.
Failing closed
If a signature doesn’t verify, a session is missing, or an envelope type is unknown, the message is rejected. Release builds contain no switch that disables encryption or falls back to plaintext.
04Server and metadata
Our servers are a delivery service for sealed envelopes. They cannot read messages, and we don’t want them to. They do see some metadata, and we’d rather be clear about it.
| Data | Server can see? |
|---|---|
| Message text, media, call audio | No. Ciphertext only. |
| Encryption keys | No. Public prekeys only. |
| Who a message is addressed to | Yes, to route it. |
| Who sent it | Yes. We do not use sealed sender yet. |
| Timestamps and ciphertext sizes | Yes. |
| Group membership | Yes, to fan out envelopes. |
| Account identifiers | Username, and phone or email if you add one. |
| Contact list or address book | No. We don’t upload it. |
- Push notifications sent through Apple and Google contain only “New message” or “Incoming call.” No text, sender name, or call details.
- Retention. Undelivered envelopes expire after 30 days on the free plan and 365 days on Plus.
- Logs record metadata such as IDs and sizes. Message plaintext is never logged, and there is none to log.
- Transport. TLS everywhere, with certificate pinning in release builds.
- Blocks are enforced server-side and we never record the reason.
05Media, backups, and calls
Attachments
Photos, files, and voice notes are encrypted on the device with a fresh key. Only the ciphertext is uploaded. The key rides inside the end-to-end encrypted message, so our storage holds unreadable blobs.
Backups
Backups seal your conversations and local message history with a key derived from your passphrase using Argon2id. We store the ciphertext. Without the passphrase, neither you nor we can recover it.
Voice calls
One-to-one voice calls use WebRTC with DTLS-SRTP. Call setup (SDP and ICE) is sent as a sealed Signal message, not in the clear. When a direct connection isn’t possible, audio relays through our own TURN server, which sees encrypted packets only. Noise suppression runs on the device, with no cloud processing.
06Nearby mesh in detail
Nearby delivers already-encrypted envelopes over Bluetooth Low Energy when there is no internet. It is opportunistic: it works best in dense groups of people who have Pigeon and have Nearby turned on.
Transport
iOS, macOS, and Android run dual-role GATT, advertising and scanning at the same time. Windows runs as a central only, so it can connect to phones and Macs but can’t be discovered by other Windows PCs. Frames are fragmented to fit the negotiated ATT MTU.
Discovery and first contact
A signed-in device broadcasts a single-hop identity beacon so nearby contacts can find it. Before a first Nearby chat, both people verify safety numbers in person. After that, Nearby messages use the same Signal session as cloud messages. A Noise XX handshake for radio-only first contact is designed but not yet shipped.
What a relay sees
A relay handles a mesh frame containing the Signal ciphertext plus routing metadata: a message ID, TTL and hop count, and conversation and sender routing fields. It can forward, delay, or drop a frame. It cannot read or alter the message without detection.
Routing
- TTL: 7 at origin, clamped at 8, and reduced in dense areas to limit flooding.
- Relay jitter: random 10–220 ms delay before forwarding, to reduce collisions.
- Fanout: relays forward to a subset of neighbours rather than everyone.
- Dedupe: message IDs are remembered for about five minutes, so loops die out.
- Sync: when the internet returns, envelopes upload by ID and merge with the cloud copy.
Range
| Scenario | Realistic reach |
|---|---|
| Single hop | About 10 m, roughly a large room. Less through walls and bodies. |
| Festival or stadium crowd | Across a section of the grounds, if enough people nearby have Nearby on. |
| Park or trail group | Within your group and anyone in between. |
| Across town | No. Nearby isn’t a city-wide network. |
Platform status
| Platform | Role | Status |
|---|---|---|
| Android | Dual-role GATT | Working |
| iOS | Dual-role GATT | Foreground best |
| macOS | Dual-role GATT | Working |
| Windows | Central only | Scan and connect |
Limits we want you to know about. Nearby is not a replacement for emergency services. Delivery isn’t guaranteed. Store-and-forward couriering, where a phone carries a message until it meets the recipient later, isn’t built yet. iOS restricts Bluetooth in the background, so Nearby works best with Pigeon open. People nearby can observe that Bluetooth traffic exists, along with its timing and size.
07Threat model
What we design against, and what an attacker in each position could still learn.
| Adversary | Can | Cannot |
|---|---|---|
| Network eavesdropper | See that you connect to Pigeon, and traffic volume | Read messages or learn who you talk to from packet contents |
| Malicious or compelled server | Read the database, logs, and storage: routing metadata and ciphertext | Decrypt messages, media, backups, or calls |
| Compromised mesh relay | See, delay, or drop frames and their routing fields | Read or undetectably modify messages |
| Local radio observer | See Bluetooth adverts, identity beacons, timing, sizes, and proximity | Read message contents |
| Device thief | Access an unlocked, unprotected device | Open Pigeon if app lock is on; open backups without the passphrase |
Out of scope today
- Anonymity from our server. Pigeon is not a mixnet.
- Sealed sender, so the server does see who sent an envelope.
- A compromised device, such as malware that reads the screen after decryption.
- Guaranteed Bluetooth delivery, or resistance to deliberate radio jamming.
08Status and known gaps
Pigeon is in closed beta. We would rather list what’s missing than let you assume it’s there.
| Area | Status |
|---|---|
| E2EE 1:1 and group messaging | Working |
| Encrypted media and backups | Working |
| 1:1 encrypted voice calls | Working |
| Nearby mesh: multi-hop, TTL, jitter, dedupe | Landed |
| Nearby ↔ cloud sync by envelope ID | Landed |
| Radio-only first contact (Noise XX) | Planned |
| Store-and-forward courier | Planned |
| Sealed sender | Planned |
| Video and group calls | Planned |
| Independent security audit | Before public launch |
09Reporting a vulnerability
If you find a security problem, email [email protected] with Security in the subject. Include steps to reproduce and the app version. Please give us a reasonable chance to fix it before disclosing publicly. We’ll reply, keep you updated, and credit you if you’d like.
For the plain-language version of this page, see Security. For what we collect and why, see the privacy policy.