# How BitChat Performs BLE File Transfers and Fragment Assembly

> Learn how BitChat achieves BLE file transfers by fragmenting data into packets and reassembling them with sequence number validation and timeouts. Discover the technical details.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: internals
- Published: 2026-08-02

---

**BitChat transfers files over Bluetooth Low Energy by fragmenting payloads into BLE-sized packets and reassembling them using a per-sender buffer that validates sequence numbers and enforces a 30-second timeout.**

BitChat implements peer-to-peer file sharing over BLE mesh networks by breaking large payloads into fragments that respect the protocol’s MTU limitations. According to the `permissionlesstech/bitchat` source code, the BLE file transfer pipeline handles packetisation, transmission, and reassembly through dedicated Swift classes that manage memory buffers and cryptographic validation.

## The Six-Phase BLE File Transfer Pipeline

BitChat’s file transfer mechanism operates through six distinct stages, each handled by specific components in the `BitFoundation` module.

### Packetisation and Fragmentation

When initiating a transfer, the system reads the file into memory and wraps it in a `BitchatFilePacket`. The binary representation is then divided into fragments that do not exceed the BLE MTU, which defaults to approximately 512 bytes. The `BLEOutboundPacketPolicy` class determines whether a packet requires fragmentation based on current MTU constraints.

### Transmission via BLEService

Each fragment is handed to `BLEService.sendPacket(_:)`, which adds a fragment header containing the sequence number, total fragment count, and sender ID. The service queues these fragments in `BLEOutboundWriteBuffer` for transmission across the mesh network.

### Reception and Initial Processing

Incoming fragments arrive at `BLEService.handleReceivedPacket(_:)`, which parses the fragment header and routes the data to a `BLEFragmentAssemblyBuffer` instance keyed by the sender’s identity.

### Fragment Assembly Logic

The `BLEFragmentAssemblyBuffer` stores fragments in an in-memory map keyed by the combination of **8-byte sender ID** and **file ID**. This composite key prevents collision between concurrent transfers from different peers. The buffer maintains fragments in a map indexed by their monotonic sequence numbers, allowing out-of-order delivery tolerance.

When the final fragment arrives, the buffer concatenates payloads in sequence order. If the fragment sequence contains gaps and the 30-second timeout expires, the buffer discards the partial data to prevent memory leaks.

### File Completion and Storage

Once reassembly completes, the full payload passes to `BLEIncomingFileStore.storeIncomingFile(_:)`, which writes the data to `Downloads/` or a temporary live-capture directory. The store generates a receipt notification that triggers UI updates indicating download completion.

### Acknowledgement

BitChat optionally sends a lightweight `BLEAckPacket` back to the sender to confirm successful reassembly. The sender’s `BLEFragmentAssemblyBuffer` processes this acknowledgement to clear its transmission state and update progress indicators.

## How Fragment Assembly Works in Detail

The reassembly process in [`BLEFragmentAssemblyBuffer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEFragmentAssemblyBuffer.swift) implements several safety mechanisms to ensure reliable data reconstruction.

### Reassembly Key Structure

The buffer creates unique storage keys by concatenating the sender’s 8-byte identifier with the file identifier. This ensures that fragments belonging to different files or different peers never collide in the shared buffer space.

### Timeout and Memory Management

A **30-second inactivity timer** runs for each active assembly operation. If fragments remain incomplete after this period, the buffer purges the partial data. This timeout prevents memory leaks and accommodates peer-ID rotation in the mesh network.

### Sequence Validation and Ordering

Fragments carry monotonic sequence numbers that the buffer validates before storage. While the system tolerates out-of-order delivery by storing fragments in a sequence-numbered map, reconstruction only proceeds when all sequence numbers from 0 to N-1 are present.

### Cryptographic Safety

Before storage, fragment payloads undergo validation using `BitchatPacket.toBinaryDataForSigning()`. This ensures that reassembly only occurs on authentic data that matches the sender’s cryptographic signature.

## BLE File Transfer Implementation Examples

The following Swift code demonstrates the API surface for implementing and debugging BLE file transfers in BitChat.

### Sending a File

To initiate a transfer, create a `BitchatFilePacket` and pass it to the shared BLE service:

```swift
let fileURL = URL(fileURLWithPath: "/path/to/video.mov")
let filePacket = try BitchatFilePacket(fileURL: fileURL)
BLEService.shared.sendPacket(filePacket)

```

### Handling Incoming Fragments

Inside [`BLEService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEService.swift), received packets undergo header extraction and routing:

```swift
func handleReceivedPacket(_ packet: BitchatPacket) {
    guard let fragment = BLEFragmentHeader.from(packet) else { return }
    BLEFragmentAssemblyBuffer.shared.store(fragment: fragment, from: packet.senderID)
}

```

### Reassembling Fragments

When the buffer detects a complete sequence, it returns the concatenated data for persistence:

```swift
if let completeData = BLEFragmentAssemblyBuffer.shared.tryReassemble(
        senderID: senderID,
        fileID: fileID) {
    
    try BLEIncomingFileStore.shared.storeIncomingFile(
        data: completeData,
        from: senderID,
        fileName: originalFileName)
}

```

### Tracking Transfer Progress

Developers can inspect pending fragment counts to update progress bars:

```swift
let pending = BLEFragmentAssemblyBuffer.shared.pendingFragments(
        for: senderID, fileID: fileID)
print("Received \(pending.count) / \(expectedCount) fragments")

```

## Summary

- **BLE file transfers** in BitChat utilize six pipeline phases: packetisation, transmission, reception, assembly, completion, and acknowledgement.
- [`BLEFragmentAssemblyBuffer.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEFragmentAssemblyBuffer.swift) manages reassembly using composite keys of sender ID plus file ID, with a 30-second timeout for partial data.
- Fragments default to 512-byte MTU limits and include monotonic sequence numbers for ordering validation.
- The `BLEIncomingFileStore` persists completed files to device directories after cryptographic validation via `toBinaryDataForSigning()`.

## Frequently Asked Questions

### What is the maximum file size BitChat can transfer over BLE?

BitChat does not enforce a hardcoded file size limit; however, practical limits depend on available RAM for the `BLEFragmentAssemblyBuffer` and the 30-second timeout window. Large files transfer successfully provided the mesh delivers fragments within the timeout period and the receiving device has sufficient memory to hold the reassembly map.

### How does BitChat handle lost or out-of-order fragments?

The `BLEFragmentAssemblyBuffer` stores fragments in a map keyed by sequence number, allowing out-of-order delivery. If sequence gaps exist, the buffer waits for the missing fragments until the 30-second timeout expires. Missing fragments after timeout cause the partial file to be discarded, requiring the sender to retry the transfer.

### What happens if a BLE file transfer is interrupted?

If transmission interrupts due to connection loss or timeout, the `BLEFragmentAssemblyBuffer` automatically purges partial data from memory. The `BLEIncomingFileStore` only commits files when `tryReassemble()` returns complete data, ensuring no corrupted partial files persist to disk.

### Where are received files stored in BitChat?

Received files are written by [`BLEIncomingFileStore.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLEIncomingFileStore.swift) to standardized directories such as `Downloads/` for standard transfers or temporary live-capture folders for media streams. The store handles directory creation and file naming while generating UI receipts upon completion.