How BitChat Provides Global Reach with the Nostr Protocol: A Technical Deep Dive

BitChat achieves global reach by combining local Bluetooth mesh networking with the decentralized Nostr protocol, allowing messages to traverse from offline peer-to-peer connections to worldwide relay networks without central servers or phone number verification.

BitChat, developed by permissionlesstech/bitchat, is an iOS messaging application designed for censorship-resistant communication. While its Bluetooth mesh enables offline local messaging, the integration with Nostr ensures that users can communicate across any distance as long as they have internet connectivity. This dual-transport architecture creates a seamless bridge between hyperlocal mesh networks and the distributed global Nostr relay infrastructure.

Geohash-Based Location Channels

BitChat implements geohash-based channels to organize peer discovery across the Nostr network. Messages are routed through Nostr relays inside location-specific channels identified by geohash prefixes representing blocks, neighborhoods, or cities.

According to the repository documentation, each geographic channel corresponds to a separate Nostr kind event type. This design allows peers physically located in the same area to discover each other globally through any Nostr relay, regardless of their specific internet connection.

The geohash system is defined in docs/GeohashPresenceSpec.md, which specifies how presence events are structured for location-based discovery on Nostr channels.

Private-Envelope Message Format (Kind-1059)

Unlike standard Nostr implementations that reuse existing NIPs such as NIP-44, BitChat defines its own encrypted envelope format using kind-1059 events. These events carry BitChat-specific payloads encrypted with XChaCha20-Poly1305.

The encoding logic resides in NostrEmbeddedBitChat.swift. The encodePMForNostr function converts BitChat messages into Nostr-compatible private envelopes:

// Encode a private message into a BitChat-over-Nostr envelope
let embedded = NostrEmbeddedBitChat.encodePMForNostr(
    content: "Hello world",
    messageID: UUID().uuidString,
    recipientPeerID: peerID,
    senderPeerID: senderPeerID
)!

This custom envelope ensures that only BitChat clients can decode the message contents, maintaining end-to-end encryption even when traversing public Nostr relays.

Transport Layer and Bluetooth-to-Nostr Fallback

The NostrTransport.swift file implements the critical logic that determines when to escalate messages from local Bluetooth mesh to global Nostr relays. When a user sends a private message, BitChat first attempts delivery via the local Bluetooth mesh network. If the recipient cannot be reached locally, the system falls back to Nostr transport.

The transport layer resolves recipient identities by converting Nostr public keys (npub) to hex format before publishing:

// Resolve the recipient's Nostr public key (npub) and convert to hex
private func resolveRecipientNpub(for peerID: PeerID) -> String? {
    if let noiseKey = Data(hexString: peerID.id),
       let fav = dependencies.favoriteStatusForNoiseKey(noiseKey),
       let npub = fav.peerNostrPublicKey {
        return npub
    }
    if peerID.id.count == 16,
       let fav = dependencies.favoriteStatusForPeerID(peerID),
       let npub = fav.peerNostrPublicKey {
        return npub
    }
    return nil
}

Once resolved, the NostrTransport class publishes the encrypted event via the relay manager:

// Publish the envelope via the relay manager
dependencies.sendEvent(event)      // `event` created by NostrProtocol.createPrivateMessage

Relay Infrastructure and Rate Limiting

BitChat ships with a built-in set of well-known Nostr relays, including both clearnet and .onion Tor endpoints. When internet connectivity is available, the client connects to these relays to publish encrypted private-envelope events.

To maintain reliability without overwhelming relay infrastructure, BitChat implements acknowledgment pacing through the AckPacer class. This mechanism paces read receipts and delivery confirmations to respect relay rate limits:

// Pace acknowledgments to respect relay rate limits
dependencies.ackPacer.enqueue {
    // send ACK as a private-envelope Nostr event
}

This pacing logic is critical for maintaining stable connections to public relays while ensuring message delivery confirmation.

Optional Tor Integration for Censorship Resistance

For users operating in restrictive network environments, BitChat supports routing all Nostr traffic through Tor. The TorURLSession class forces outbound connections through the Tor network, connecting to .onion Nostr relays as documented in docs/TOR-INTEGRATION.md.

This optional layer provides additional privacy and circumvention capabilities, ensuring that even the metadata of Nostr relay connections remains protected from network surveillance.

Summary

  • Dual-transport architecture enables BitChat to use Bluetooth mesh for local messaging and Nostr relays for global reach.
  • Geohash-based channels organize peer discovery by geographic location using dedicated Nostr event kinds.
  • Kind-1059 private envelopes use XChaCha20-Poly1305 encryption to secure messages without relying on standard NIPs.
  • Intelligent fallback logic in NostrTransport.swift automatically escalates undeliverable local messages to the Nostr network.
  • Rate-limit protection via AckPacer ensures stable relay connections through paced acknowledgment delivery.
  • Tor integration provides optional metadata protection for users in high-censorship regions.

Frequently Asked Questions

How does BitChat handle messaging when users are not in Bluetooth range?

When recipients are outside Bluetooth mesh range, BitChat's NostrTransport class resolves the recipient's Nostr public key and publishes an encrypted kind-1059 event to configured Nostr relays. The recipient's device retrieves this event from any internet-connected relay, decrypting it with their private key to recover the original BitChat message.

Why does BitChat use a custom Nostr event format instead of NIP-44?

BitChat implements its own private-envelope format using kind-1059 events with XChaCha20-Poly1305 encryption rather than standard NIP-44. This design choice, implemented in NostrEmbeddedBitChat.encodePMForNostr, ensures protocol-specific features and maintains compatibility with BitChat's unique peer-to-peer identity system while avoiding dependencies on evolving NIP specifications.

Can BitChat work entirely without internet connectivity?

Yes, BitChat functions as a fully offline mesh messenger using Bluetooth Low Energy between physically proximate devices. However, to achieve global reach beyond local mesh boundaries, the application requires internet connectivity to publish and retrieve events from Nostr relays. The architecture seamlessly bridges these two modes without user intervention.

Which Nostr relays does BitChat connect to?

The application ships with a curated set of well-known Nostr relays that include both clearnet and Tor .onion endpoints. Users can connect to any compatible Nostr relay, and the optional Tor integration documented in docs/TOR-INTEGRATION.md routes traffic through the Tor network for additional privacy when accessing these relays.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →