# What Media Transfer Protocol Does BitChat Use for Private File Sharing?

> Discover the custom Mesh File Transferring protocol BitChat uses for secure, private file sharing. Learn how Noise encryption ensures your data stays protected with ChatMediaTransferCoordinator.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: deep-dive
- Published: 2026-08-07

---

**BitChat uses a custom "Mesh File Transferring" protocol backed by Noise encryption for private file sharing, implemented through the `MeshFileTransferring` protocol and coordinated by `ChatMediaTransferCoordinator`.**

This article examines the BitChat iOS application's approach to secure media transfers over its decentralized mesh network. The protocol combines Bluetooth Low Energy (BLE) mesh transport with the Noise cryptographic framework to enable private image, voice, and file exchanges without centralized servers.

---

## Mesh File Transferring Protocol Overview

BitChat's private file sharing operates through the **`MeshFileTransferring`** protocol defined in [`bitchat/Services/MeshTransportCapabilities.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/MeshTransportCapabilities.swift). This protocol abstracts the underlying mesh transport layer, providing a clean interface for the chat UI to initiate and manage file transfers.

### Core Protocol Methods

The `MeshFileTransferring` protocol declares three essential methods (lines 32-41):

```swift
func privateMediaSendPolicy(to peerID: PeerID) -> PrivateMediaSendPolicy
func sendFilePrivate(_ packet: BitchatFilePacket,
                     to peerID: PeerID,
                     transferId: String,
                     allowLegacyFallback: Bool)
func sendFileBroadcast(_ packet: BitchatFilePacket, transferId: String)

```

The `privateMediaSendPolicy` method drives the transfer flow. It returns one of four policies—`.encrypted`, `.legacyRequiresConsent`, `.awaitingCapabilityProof`, or `.blockedDowngrade`—determining whether the coordinator can proceed with an encrypted transfer or must use fallback mechanisms.

---

## ChatMediaTransferCoordinator: The Orchestration Layer

Private media transfers are coordinated by **`ChatMediaTransferCoordinator`**, located in [`bitchat/ViewModels/ChatMediaTransferCoordinator.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/ChatMediaTransferCoordinator.swift). This class bridges the UI layer (`ChatViewModel`) with the mesh transport.

### Policy Lookup and Transfer Initiation

Before sending, the coordinator queries the mesh transport for the target peer's capabilities (lines 59-61):

```swift
context.privateMediaSendPolicy(to: peerID)   // → PrivateMediaSendPolicy

```

Based on this policy, the coordinator chooses between:

- **Encrypted path**: Direct Noise-encrypted transfer via `sendFilePrivate`
- **Legacy consent path**: User-prompted approval for unencrypted fallback
- **Deferred path**: Wait for capability proof from an unknown peer

### Sending a File

Here's the complete flow when a user shares an image:

```swift
// 1️⃣ Initiate a private-media send (image, voice note, or generic file)
chatViewModel.mediaTransferCoordinator.sendImage(from: imageURL)

// Inside ChatMediaTransferCoordinator.swift
func sendImage(from sourceURL: URL) {
    guard context.canSendMediaInCurrentContext else { … }

    let targetPeer = context.selectedPrivateChatPeer
    let packet = try prepareImagePacket(sourceURL: URL)          // encodes the file
    let transferId = makeTransferID(messageID: message.id)

    // Register the transfer for cancellation / retry handling
    registerTransfer(transferId: transferId, messageID: message.id)

    // Choose private or broadcast path based on the current peer
    if let peerID = targetPeer {
        beginPrivateMediaSend(packet, to: peerID,
                              transferId: transferId,
                              messageID: message.id)
    } else {
        context.sendFileBroadcast(packet, transferId: transferId)
    }
}

```

---

## Noise Protocol Encryption

The **Noise protocol** ([`bitchat/Noise/NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift)) provides the cryptographic layer for private media transfers. When `privateMediaSendPolicy` returns `.encrypted`, the coordinator wraps the `BitchatFilePacket` in a Noise-encrypted envelope before transmission.

### Transport Implementation

The mesh transport implements `MeshFileTransferring` with Noise integration:

```swift
// 2️⃣ Private-media policy lookup (inside the Mesh transport)
extension SomeMeshService: MeshFileTransferring {
    func privateMediaSendPolicy(to peerID: PeerID) -> PrivateMediaSendPolicy {
        // Examine peer capabilities; return .encrypted, .legacyRequiresConsent,
        // .awaitingCapabilityProof, or .blockedDowngrade
        …
    }

    func sendFilePrivate(_ packet: BitchatFilePacket,
                         to peerID: PeerID,
                         transferId: String,
                         allowLegacyFallback: Bool) {
        // Wrap the packet in a Noise-encrypted envelope and forward
        // it over the BLE mesh.
        …
    }
}

```

### Reception and Decryption

Incoming packets pass through the Noise layer for validation and decryption:

```swift
// 3️⃣ Handling a received private-media packet (Noise decryption)
func handleIncomingPacket(_ packet: BitchatFilePacket) {
    // The Noise layer validates the envelope and extracts the payload
    let decrypted = try noiseSession.decrypt(packet)
    // Store the file and create the UI bubble
    …
}

```

---

## Legacy Fallback and Consent Flow

Not all peers support encrypted media. The coordinator handles this through the **`ChatMediaTransferContext`** protocol, which `ChatViewModel` implements. When `privateMediaSendPolicy` indicates `.legacyRequiresConsent`, the coordinator invokes:

- `requestLegacyPrivateMediaConsent()` — prompts the user for approval
- `cancelLegacyPrivateMediaConsent()` — aborts the fallback transfer

This design maintains security by default while preserving interoperability with older or constrained peers.

---

## Key Implementation Files

| Component | File Path | Purpose |
|-----------|-----------|---------|
| Coordinator | [`bitchat/ViewModels/ChatMediaTransferCoordinator.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/ChatMediaTransferCoordinator.swift) | Orchestrates sends, retries, and UI updates for private media |
| Context Protocol | [`bitchat/ViewModels/ChatMediaTransferCoordinator.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/ViewModels/ChatMediaTransferCoordinator.swift) (protocol `ChatMediaTransferContext`) | Minimal interface required from `ChatViewModel` |
| Mesh Transfer Protocol | [`bitchat/Services/MeshTransportCapabilities.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/MeshTransportCapabilities.swift) (protocol `MeshFileTransferring`) | Declares the private-media API used by the coordinator |
| Encryption Layer | [`bitchat/Noise/NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift) | Implements the Noise protocol that secures private-media packets |
| Message Packet | [`bitchat/Protocols/BitchatFilePacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Protocols/BitchatFilePacket.swift) | Binary representation of a file packet sent over the mesh |

---

## Summary

- **BitChat's media transfer protocol is custom-built**, not a standard protocol like HTTP, FTP, or BitTorrent.
- The **`MeshFileTransferring` protocol** defines the API for private and broadcast file transfers over BLE mesh.
- **`ChatMediaTransferCoordinator`** manages transfer lifecycle, policy resolution, and UI coordination.
- **Noise protocol encryption** secures payloads when both peers support encrypted media.
- **Legacy consent flow** provides backward compatibility with non-encrypted peers, requiring explicit user approval.

---

## Frequently Asked Questions

### Does BitChat use standard protocols like WebRTC or MQTT for file sharing?

No. BitChat implements a **proprietary mesh-based protocol** specific to its decentralized architecture. The `MeshFileTransferring` protocol operates over Bluetooth Low Energy mesh rather than IP-based protocols like WebRTC or MQTT.

### What happens if the recipient doesn't support encrypted media transfers?

The coordinator enters a **legacy consent flow**. It calls `requestLegacyPrivateMediaConsent()` to prompt the user for explicit approval before falling back to unencrypted transfer. The policy `.blockedDowngrade` prevents any transfer if the administrator forbids unencrypted media.

### How does the coordinator track ongoing transfers?

Each transfer receives a unique `transferId` generated via `makeTransferID(messageID:)`. The coordinator registers this ID using `registerTransfer(transferId:messageID:)`, enabling cancellation, retry logic, and progress updates bound to specific chat messages.

### Is the Noise protocol implementation custom or from a library?

The analysis references [`bitchat/Noise/NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift) as the encryption layer. While the file structure suggests BitChat maintains its own Noise implementation, the protocol itself follows the **Noise Protocol Framework** specification—a well-established cryptographic standard used by WireGuard and other modern secure protocols.