How BitChat Uses the Nostr Protocol for Global Messaging

BitChat leverages the Nostr protocol as its global transport layer, enabling decentralized, end-to-end encrypted messaging across a worldwide relay network without central servers or user accounts.

The permissionlesstech/bitchat repository implements a dual-transport architecture that combines local Bluetooth mesh networks with the Nostr protocol for global reach. While Bluetooth handles offline peer-to-peer communication, the Nostr protocol in BitChat provides the decentralized infrastructure necessary for worldwide message delivery without relying on centralized servers, phone numbers, or traditional user accounts.

Core Responsibilities of Nostr in BitChat

Private Envelope Transport and End-to-End Encryption

BitChat uses Nostr as a carrier for its proprietary encrypted payload system. In bitchat/Nostr/NostrProtocol.swift, the createPrivateMessage method encrypts plaintext messages using XChaCha20-Poly1305, wraps them in a gift-wrap event (kind 1059), and signs each layer with secp256k1 Schnorr keys. This creates a private envelope that remains opaque to relays while traversing the global network.

The corresponding decryptPrivateMessage function handles the reverse process, extracting the original content and verifying the sender's identity through ECDH-based key exchange implemented in deriveSharedSecret and derivePrivateEnvelopeKey.

Location-Based Channels via Geohash Tagging

To enable location-aware chat rooms that function globally, BitChat implements geohash-scoped Nostr events. Functions such as createGeohashTextNote, createEphemeralGeohashEvent, and createGeohashPresenceEvent generate events tagged with a geohash (g tag), allowing clients worldwide to subscribe to specific geographic cells. This transforms Nostr's global broadcast capability into a location-filtered communication system without revealing precise GPS coordinates.

Mesh Bridging and Asynchronous Courier Drops

BitChat bridges its offline Bluetooth mesh with the global internet through specialized Nostr events. The createBridgeMeshEvent and createBridgePresenceEvent methods publish mesh traffic to Nostr relays, enabling devices with only Bluetooth connectivity to reach the global network indirectly. For reliable asynchronous delivery, createCourierDropEvent generates signed Nostr events (kind 1401) containing sealed envelopes with NIP-40 expiration tags, ensuring messages survive relay restarts and remain available for recipients who come online later.

Spam Resistance Through Proof-of-Work

To prevent abuse of public geohash channels, BitChat implements proof-of-work mining for certain ephemeral events. The createMinedEphemeralGeohashEvent function adds a PoW nonce compliant with NIP-13 to event tags before publishing, requiring computational effort that deters spam while maintaining the permissionless nature of the network.

Implementation Architecture and Key Components

The Nostr integration relies on several specialized Swift components that manage the global messaging layer:

  • NostrProtocol.swift: Core implementation containing createPrivateMessage, decryptPrivateMessage, geohash event creators, bridge functions, and cryptographic helpers.
  • NostrIdentity.swift: Manages secp256k1 key generation, Schnorr signatures, and conversions between hex public keys and bech32/npub formats.
  • NostrRelayManager.swift: Maintains connections to the distributed relay pool, handles reconnections, and manages NIP-40 expirations for courier drops.
  • NostrIdentityBridge.swift: Maps local Bluetooth mesh identities to Nostr public keys, enabling seamless transport selection between local mesh and global Nostr fallback.
  • ChatNostrCoordinator.swift: Orchestrates the UI layer integration, managing the flow of events between the user interface and the Nostr transport layer.

Practical Implementation Examples

Creating and decrypting private messages follows a straightforward pattern using the NostrProtocol struct:

// Create a private BitChat message for global Nostr delivery
let sender = try NostrIdentity.generate()
let recipientPubkey = "abcdef1234…"
let plaintext = "Hello from the other side!"

let nostrEvent = try NostrProtocol.createPrivateMessage(
    content: plaintext,
    recipientPubkey: recipientPubkey,
    senderIdentity: sender
)
// nostrEvent is a signed kind-1059 gift-wrap ready for any relay

Decryption uses the recipient's identity to unwrap the gift-wrap envelope:

// Decrypt a received private envelope from a Nostr relay
let myIdentity = try NostrIdentity.generate()
let receivedEvent = // ... fetched from relay

let (content, senderPubkey, timestamp) = try NostrProtocol.decryptPrivateMessage(
    giftWrap: receivedEvent,
    recipientIdentity: myIdentity
)

For location-based public channels:

// Publish to a geohash-scoped global channel
let geoEvent = try NostrProtocol.createGeohashTextNote(
    content: "Anyone at #dr5rsj7?",
    geohash: "dr5rsj7",
    senderIdentity: sender,
    nickname: "alice"
)

Summary

  • BitChat uses the Nostr protocol as its decentralized global transport layer, complementing offline Bluetooth mesh networks.
  • All global messages use end-to-end encryption via XChaCha20-Poly1305 private envelopes wrapped in Nostr gift-wrap events (kind 1059).
  • Geohash tagging enables location-based chat rooms that operate globally through standard Nostr relays.
  • Mesh bridge events and courier drops (kind 1401) ensure connectivity between offline Bluetooth devices and the global internet, with store-and-forward capabilities.
  • Proof-of-work (NIP-13) protects public channels from spam without requiring centralized moderation.

Frequently Asked Questions

What is the Nostr protocol's primary role in BitChat?

The Nostr protocol serves as BitChat's global messaging infrastructure, providing a decentralized relay network that enables users to exchange encrypted messages worldwide without central servers, phone numbers, or accounts. When Bluetooth peer-to-peer connections are unavailable, BitChat automatically falls back to Nostr relays to maintain connectivity.

How does BitChat encrypt messages sent over Nostr?

BitChat implements a custom private envelope protocol using XChaCha20-Poly1305 symmetric encryption. The createPrivateMessage function in NostrProtocol.swift encrypts the plaintext, wraps it in a Nostr gift-wrap event (kind 1059), and signs it with secp256k1 Schnorr keys, ensuring relays only handle opaque ciphertext while the recipient decrypts using ECDH-based key exchange.

What are geohash-scoped events in BitChat?

Geohash-scoped events are Nostr messages tagged with geographic location hashes (g tags) that create location-based chat rooms functioning globally. Functions like createGeohashTextNote generate these events, allowing users worldwide to subscribe to specific geographic cells and participate in location-aware conversations without revealing precise GPS coordinates.

How does BitChat handle offline message delivery via Nostr?

BitChat implements "courier drops" using createCourierDropEvent, which creates signed Nostr events (kind 1401) containing sealed envelopes with NIP-40 expiration tags. These store-and-forward events survive relay restarts and remain available for recipients to retrieve when they come online, bridging the gap between offline Bluetooth mesh usage and global internet connectivity.

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 →