Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/permissionlesstech/bitchat/llms.txt

Use this file to discover all available pages before exploring further.

Bitchat never asks for an account, a phone number, or an email address. Instead, your identity is a pair of cryptographic keys generated entirely on your device the first time the app runs. Those keys live in the iOS or macOS Keychain — they never leave the device unencrypted, and no server ever sees them. This page explains what each key does, how your peer ID is derived, what you reveal on the radio, and the tools available to manage trust with other people.

Key Material

Each device holds two long-term keypairs stored in the Keychain, plus an optional third keypair for the Nostr internet path.
Used for Noise XX key agreement with peers. When two devices connect over Bluetooth, they run the Noise XX handshake using their respective Curve25519 static keys. Successful completion produces a shared session secret that encrypts all private payloads between those two peers.The SHA-256 fingerprint of this key is your stable identity — it is what other devices save when they favorite you, and it is the root from which your peer ID is derived. The raw public key is broadcast in cleartext in signed presence announcements, so any device in radio range can read it.
// Fingerprint of the local Noise static key (Curve25519)
func noiseIdentityFingerprint() -> String
func noiseStaticPublicKeyData() -> Data

Peer ID

Every device on the mesh is identified by a short 8-byte peer ID. It is the first 8 bytes of the SHA-256 fingerprint of the device’s Curve25519 Noise static public key.
peerID = SHA-256(noiseStaticPublicKey)[0..<8]
This ID is stable across sessions and reboots as long as the Keychain entry survives. It persists through app updates, device restarts, and reinstalls that preserve the Keychain. It only changes when the identity itself is replaced — for example, by a panic wipe. The peer ID appears in every packet header as the sender field. It is the short handle used by MessageRouter routing decisions, courier addressing, and the peer list UI.
The 8-byte peer ID does not rotate between sessions. Because it is derived from a never-changing key, a passive radio observer — any device within Bluetooth range running a packet sniffer — can track your device across time and location by watching for your sender ID in mesh traffic. This is a documented limitation of the current protocol design. See the Privacy page for full details.

Mesh Presence

Devices announce themselves to the mesh using signed presence announcements that propagate multi-hop across the network. Each announcement carries:
  • Nickname — the chosen display name (cleartext)
  • Noise static public key — the Curve25519 key used for session establishment (cleartext)
  • Ed25519 signing public key — used to verify this and future packets from the sender (cleartext)
  • Capability flags — a bitmask indicating supported protocol features
  • Up to 10 direct-neighbor IDs — the peer IDs of directly connected peers, giving receivers a shallow topology map
Announcements are re-broadcast periodically. Isolated devices (no connections) announce every 4 seconds. Connected devices back off to a jittered interval of approximately 15–30 seconds to reduce traffic. A verified announce keeps a peer visible in the peer list for 60 seconds after last contact. Because the static keys and nickname are broadcast in cleartext, a passive receiver anywhere in radio range can enumerate participants and link a device’s transmissions across time and place without needing to connect or authenticate.

Favorites and Mutual Trust

Favoriting a peer pins their full Noise public key into local storage. This survives app restarts and means you can recognize and securely communicate with that person even after a gap where no announcement was heard — the key fingerprint from a previous session is trusted directly. When two peers both favorite each other, they form a mutual favorites relationship. Mutual favorites:
  • Exchange their Nostr npub public keys, enabling private message delivery over the Nostr relay network when Bluetooth is unavailable
  • Receive preferential treatment in the courier system — mutual favorites can deposit up to 5 courier envelopes per sender, versus 2 for verified strangers
A favorite notification is sent to the peer over whatever transport is available when you tap the favorite button.

QR Verification

For the strongest identity binding, Bitchat supports optional in-person QR code verification. Scanning another person’s QR code binds their displayed nickname to the full Noise key fingerprint in your local verified-peer store. This eliminates any ambiguity about whether a given peer ID on the mesh corresponds to the person you think it does. The QR flow is facilitated by VerificationModel and routes through the Transport interface’s challenge/response methods:
func sendVerifyChallenge(to peerID: PeerID, noiseKeyHex: String, nonceA: Data)
func sendVerifyResponse(to peerID: PeerID, noiseKeyHex: String, nonceA: Data)

Privacy Caveat

The static peer ID and the public keys in announcements mean a passive radio listener can track a device across time and place without connecting to it. This is a documented limitation of the current protocol, not an implementation defect. The whitepaper notes:
“Unlinkable presence is not a property this protocol currently provides.”
Specific exposure points:
  • The 8-byte sender ID in every packet header is derived from a key that never rotates.
  • Announcements broadcast the Noise static key and Ed25519 signing key in cleartext.
  • Announcements carry up to 10 direct-neighbor IDs, handing a single sniffer the local adjacency graph.
  • Origin packets leave at the default TTL (7), so hop distance from the source is observable.
Rotating on-air identity — epoch-rotating peer IDs with static-key disclosure moved inside the encrypted handshake — is planned future work. For current privacy properties and mitigations, see the Privacy reference.
Panic wipe rotates your identity completely. Triggering the emergency wipe (triple-tap) clears all identity keys from the Keychain and generates an entirely new Curve25519 static key, Ed25519 signing key, and Nostr keypair. Your peer ID, key fingerprints, and all stored favorites, conversations, and carried courier mail are permanently erased. There is no recovery — this is by design.

Build docs developers (and LLMs) love