This document describes the application-layer protocol definitions for BitChat, including message type enumerations, payload classifications, delegate protocols, and message status tracking. These definitions form the foundation of BitChat's communication taxonomy and provide the interface between transport implementations and higher-level application logic.
For details on binary wire format encoding and decoding, see 5.2 Binary Encoding System For Nostr-specific protocol implementation including NIP-17 gift wrapping, see 5.3 Nostr Protocol Implementation
BitChat defines a minimal set of message types optimized for the dual-transport architecture. The protocol distinguishes between public broadcast messages (sent unencrypted over BLE mesh), encrypted private messages (wrapped in Noise protocol), and infrastructure messages for network coordination.
The MessageType enum defines core message types that cover application-layer communication needs:
| Type | Value | Description | Transport |
|---|---|---|---|
announce | 0x01 | Peer presence notification with nickname | BLE mesh (public) |
message | 0x02 | Public chat message broadcast | BLE mesh (public) |
leave | 0x03 | Graceful peer departure notification | BLE mesh (public) |
courierEnvelope | 0x04 | Sealed store-and-forward mail | Trusted peer relay |
noiseHandshake | 0x10 | Noise XX pattern handshake message | BLE mesh or Nostr |
noiseEncrypted | 0x11 | Encrypted payload container | BLE mesh or Nostr |
fragment | 0x20 | Message fragment for reassembly | BLE mesh |
requestSync | 0x21 | Gossip filter-based state sync | BLE mesh (local) |
fileTransfer | 0x22 | Binary file/media payload | BLE mesh or Nostr |
boardPost | 0x23 | Signed geohash bulletin-board post | BLE mesh (gossip) |
prekeyBundle | 0x24 | Signed batch of one-time prekeys | BLE mesh (gossip) |
groupMessage | 0x25 | Group-encrypted broadcast | BLE mesh |
ping / pong | 0x26/0x27 | Directed mesh diagnostic probes | BLE mesh |
nostrCarrier | 0x28 | Mesh-to-Internet gateway carrier | BLE mesh |
voiceFrame | 0x29 | Public live voice-burst packet | BLE mesh |
Sources: localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift12-63
The following diagram illustrates how user actions translate into specific protocol message types and are routed through the system components.
Title: Message Type Routing Logic
Sources: localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift12-63 bitchat/Protocols/BitchatProtocol.swift10-61 bitchat/ViewModels/ChatViewModel.swift162-175
BitChat's protocol makes a critical distinction between public broadcast messages and private encrypted messages:
Public Messages (announce, message, leave, voiceFrame):
voiceFrame is deliberately unpadded to avoid MTU fragmentation bitchat/Services/BLE/BLEOutboundPacketPolicy.swift15-17Encrypted Messages (noiseHandshake, noiseEncrypted):
noiseEncrypted localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift22NoisePayloadType bitchat/Protocols/BitchatProtocol.swift74-76Sources: localPackages/BitFoundation/Sources/BitFoundation/MessageType.swift13-30 bitchat/Protocols/BitchatProtocol.swift10-61 bitchat/Services/BLE/BLEOutboundPacketPolicy.swift11-21
When a message is encrypted with the Noise Protocol, the plaintext payload begins with a single byte indicating the payload type. This inner type system allows multiple message semantics to share the same encrypted transport container while maintaining privacy bitchat/Protocols/BitchatProtocol.swift67-71
The NoisePayloadType enum classifies the content of decrypted Noise payloads bitchat/Protocols/BitchatProtocol.swift72-101
| Type | Value | Description | Direction |
|---|---|---|---|
privateMessage | 0x01 | Encrypted one-to-one chat message | Bidirectional |
readReceipt | 0x02 | Confirmation that message was read | Receiver → Sender |
delivered | 0x03 | Confirmation of message delivery | Receiver → Sender |
groupInvite | 0x06 | Creator-signed group state (invite) | Creator → Member |
groupKeyUpdate | 0x07 | Creator-signed group state (key rotation) | Creator → Member |
voiceFrame | 0x08 | Live voice-burst packet | Bidirectional |
verifyChallenge | 0x10 | QR-based verification challenge | Initiator → Responder |
verifyResponse | 0x11 | QR-based verification response | Responder → Initiator |
vouch | 0x12 | Batch of vouch attestations | Bidirectional |
Sources: bitchat/Protocols/BitchatProtocol.swift72-101
The diagram below shows how application data is encapsulated into Noise payloads and subsequently dispatched upon decryption.
Title: Encrypted Payload Encapsulation and Dispatch
Sources: bitchat/Protocols/BitchatProtocol.swift72-101 bitchat/Protocols/BitchatProtocol.swift116-139 bitchat/Protocols/Packets.swift159-188
The BitchatDelegate protocol defines the callback interface that transport implementations (BLEService, NostrTransport) use to notify the application layer of incoming messages and state changes. ChatViewModel acts as the primary implementer of this protocol bitchat/ViewModels/ChatViewModel.swift93-96
| Method | Parameters | Purpose |
|---|---|---|
didReceiveMessage | BitchatMessage | Deliver decoded message to UI bitchat/Protocols/BitchatProtocol.swift117 |
didConnectToPeer | PeerID | Notify peer connection (BLE) bitchat/Protocols/BitchatProtocol.swift118 |
didDisconnectFromPeer | PeerID | Notify peer disconnection (BLE) bitchat/Protocols/BitchatProtocol.swift119 |
didUpdatePeerList | [PeerID] | Batch peer list update bitchat/Protocols/BitchatProtocol.swift120 |
isFavorite | fingerprint: String → Bool | Query favorite status for trust ranking bitchat/Protocols/BitchatProtocol.swift123 |
didUpdateMessageDeliveryStatus | messageID, DeliveryStatus | Track delivery/read state bitchat/Protocols/BitchatProtocol.swift125 |
didReceiveNoisePayload | peerID, type, payload, timestamp | Low-level encrypted payload event bitchat/Protocols/BitchatProtocol.swift128 |
didReceiveGroupMessage | payload, timestamp | Opaque group envelope event bitchat/Protocols/BitchatProtocol.swift131 |
didUpdateBluetoothState | CBManagerState | CoreBluetooth state changes for UI alerts bitchat/Protocols/BitchatProtocol.swift137 |
didReceivePublicMessage | peerID, nickname, content, timestamp, messageID | Public mesh message received bitchat/Protocols/BitchatProtocol.swift138 |
Sources: bitchat/Protocols/BitchatProtocol.swift116-166 bitchat/ViewModels/ChatViewModel.swift93-96
BitChat uses Tag-Length-Value (TLV) encoding for various internal packets. This provides a flexible and extensible binary format.
Used for peer discovery and mesh routing. It contains:
nickname: User's display name bitchat/Protocols/Packets.swift7noisePublicKey: Curve25519 key for Noise handshakes bitchat/Protocols/Packets.swift8signingPublicKey: Ed25519 key for identity verification bitchat/Protocols/Packets.swift9directNeighbors: List of 8-byte peer IDs currently in range for mesh routing bitchat/Protocols/Packets.swift10capabilities: Advertised feature bits (e.g., .prekeys, .groups) bitchat/Protocols/Packets.swift11bridgeGeohash: Rendezvous geohash cell for mesh bridging bitchat/Protocols/Packets.swift15Sources: bitchat/Protocols/Packets.swift6-157 localPackages/BitFoundation/Sources/BitFoundation/PeerCapabilities.swift9-27
Used within noiseEncrypted payloads. It contains:
messageID: Unique identifier for tracking and deduplication bitchat/Protocols/Packets.swift160content: The text of the private message bitchat/Protocols/Packets.swift161Sources: bitchat/Protocols/Packets.swift159-188
Peers advertise supported features via a bitfield. This allows for forward compatibility as the protocol evolves localPackages/BitFoundation/Sources/BitFoundation/PeerCapabilities.swift9-27
.vouch, .prekeys, and .groups bitchat/Protocols/PeerCapabilities+Local.swift3-7A bitfield describing which message types are covered by a REQUEST_SYNC round. It maps MessageType to specific bit indices for wire transmission bitchat/Sync/SyncTypeFlags.swift6-65
| Message Type | Bit Index |
|---|---|
announce | 0 |
message | 1 |
leave | 2 |
noiseHandshake | 3 |
noiseEncrypted | 4 |
fragment | 5 |
requestSync | 6 |
fileTransfer | 7 |
boardPost | 8 |
prekeyBundle | 9 |
groupMessage | 10 |
Sources: bitchat/Sync/SyncTypeFlags.swift29-65 bitchatTests/Sync/SyncTypeFlagsBoardTests.swift21-25
Noise Protocol handshakes are initiated lazily—only when a user attempts to send a private message. This enum tracks the session lifecycle bitchat/Protocols/BitchatProtocol.swift106-112:
| State | Meaning |
|---|---|
none | No session exists, no attempt made bitchat/Protocols/BitchatProtocol.swift107 |
handshakeQueued | User action requires handshake, waiting for connectivity bitchat/Protocols/BitchatProtocol.swift108 |
handshaking | Currently in Noise XX handshake process bitchat/Protocols/BitchatProtocol.swift109 |
established | Session ready for encrypted payload exchange bitchat/Protocols/BitchatProtocol.swift110 |
failed(Error) | Handshake failed due to timeout or crypto error bitchat/Protocols/BitchatProtocol.swift111 |
Refresh this wiki
This wiki was recently refreshed. Please wait 6 days to refresh again.