# How BitChat Implements Source Routing for Packet Forwarding

> Discover how BitChat's source routing algorithm streamlines packet forwarding by embedding explicit relay lists in headers, eliminating network discovery needs.

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

---

**BitChat uses a source-routing algorithm where the sender embeds an explicit list of relay identifiers in the packet header, allowing intermediate nodes to forward traffic without performing network discovery or flooding operations.**

BitChat is an open-source mesh networking protocol designed for permissionless communication. The **source routing algorithm** implemented in the BitChat client enables efficient packet forwarding by having the originator pre-calculate the entire path through the network, eliminating the need for intermediate hops to maintain routing tables or perform broadcast searches.

## Packet Version 2 and the Source-Route Header

All packets utilizing the source routing mechanism use the **Packet Version 2** format defined in [`bitchat/Network/Packet.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Network/Packet.swift). The first byte encodes the version identifier, followed by a compact header containing a **route list**—an ordered array of relay identifiers represented as variable-length integers (var-ints).

The **source-route header** structure stores this list of relay IDs that the packet must traverse. Each intermediate node reads the first identifier in the list, determines the next network hop, and trims the consumed ID before forwarding. This design ensures that large payloads, including voice notes and media blobs, follow predetermined paths without triggering mesh-wide broadcast storms.

## How the Source Routing Algorithm Works

The forwarding logic follows a strict **forward-only** pattern implemented in [`bitchat/Network/RelayForwarder.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Network/RelayForwarder.swift). When a relay receives a packet, it executes the following deterministic steps:

1. **Decode the header** to extract the version number and route list.
2. **Validate the version**—if the packet uses Version 1 (legacy format without source routes), the node immediately triggers the fallback flooding mechanism.
3. **Inspect the route list**—if the list is empty, the packet has reached its final destination and is handed to the local protocol stack via `deliverLocally()`.
4. **Consume the next hop**—the relay extracts the first relay ID from the list, performs a lookup to resolve the network address, and forwards the packet with the updated (trimmed) route header.

This approach guarantees that every fragment of a fragmented message follows the identical path, preventing the reassembly issues that would occur if fragments arrived via different routes.

## Route Processing Logic

The core implementation of the source routing algorithm handles packet deserialization, version checking, and hop consumption. The following Swift code illustrates the critical path executed by the `RelayForwarder` class:

```swift
// Decode a Version-2 packet and extract the route list
let packet = try Packet.decode(rawData)
guard packet.version == .v2 else {
    // Fallback to legacy flooding logic
    return forwardViaFlooding(packet)
}
var route = packet.sourceRoute   // e.g. [relayID1, relayID2, …]

// If the route is empty, the packet is for the local node
guard let nextRelayID = route.first else {
    return deliverLocally(packet)
}

// Forward to the next hop
route.removeFirst()                       // Consume this hop
let nextRelay = try Relay.lookup(id: nextRelayID)
let forwarded = packet.withUpdatedRoute(route)
try nextRelay.send(data: forwarded.serialized)

// Fragment handling
if packet.isFragmented {
    // Each fragment carries the same sourceRoute
    // Forwarding logic is identical to the non-fragment case
    forwardFragment(packet)
}

```

Key implementation details from this logic include the **`sourceRoute`** field being mutated on each hop and the **fallback-to-flooding** path executed when version mismatches occur.

## Fragmentation and Large Payload Support

Large messages are segmented into multiple **fragments** using the logic in [`bitchat/Network/Fragmenter.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Network/Fragmenter.swift). Unlike traditional mesh protocols that might route fragments independently, BitChat ensures that **every fragment carries the identical source route** in its header.

This design choice prevents the "flood-and-reassemble" fallback that would otherwise saturate the network. Because all fragments traverse the same predetermined path, the receiving node can reassemble the payload efficiently without waiting for missing pieces from alternative routes.

## Security and Integrity

The source routing mechanism includes cryptographic protections implemented in [`bitchat/Crypto/CryptoSeal.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Crypto/CryptoSeal.swift). Each packet is authenticated using **XChaCha20-Poly1305**, with the authentication tag covering the entire packet payload including the route list.

This ensures that intermediate relays cannot modify the source path without detection. Any tampering with the relay identifiers invalidates the cryptographic seal, causing the receiving node to discard the packet as corrupted.

## Fallback Mechanisms

The algorithm includes a robust **fallback to flooding** for edge cases. If a packet arrives as Version 1 (indicating an older client or missing route information), or if the route list is exhausted before the payload reaches its destination, the system automatically switches to classic flooding mode.

This safeguard guarantees message delivery at the cost of increased bandwidth usage, ensuring backward compatibility and resilience in dynamic network topologies where pre-calculated routes may become stale.

## Key Implementation Files

The source routing algorithm is distributed across the following source files in the `permissionlesstech/bitchat` repository:

- **[`docs/SOURCE_ROUTING.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/SOURCE_ROUTING.md)** — The authoritative design document describing packet formats, motivations, and protocol specifications.
- **[`bitchat/Network/Packet.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Network/Packet.swift)** — Defines the `Packet` struct, version enumeration, and serialization logic for the source-route header.
- **[`bitchat/Network/RelayForwarder.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Network/RelayForwarder.swift)** — Implements the core forwarding routine that consumes the source-route list and manages hop-by-hop transmission.
- **[`bitchat/Network/Fragmenter.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Network/Fragmenter.swift)** — Handles message segmentation and ensures each fragment retains the complete source route.
- **[`bitchat/Crypto/CryptoSeal.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Crypto/CryptoSeal.swift)** — Provides cryptographic sealing and verification using XChaCha20-Poly1305, protecting route integrity.

## Summary

- **Source routing** in BitChat embeds the complete forwarding path in the packet header, eliminating per-hop routing decisions.
- **Packet Version 2** uses a var-int-encoded route list that relays trim progressively as they forward traffic.
- **Fragmented messages** carry identical source routes to ensure ordered reassembly without network flooding.
- **XChaCha20-Poly1305** authentication covers the route list, preventing path manipulation by untrusted relays.
- A **fallback to flooding** ensures compatibility and delivery when source routes are unavailable or exhausted.

## Frequently Asked Questions

### What happens if a relay in the source route is offline?

If an intermediate relay specified in the source route becomes unreachable, the packet cannot proceed along the predetermined path. According to the design in [`docs/SOURCE_ROUTING.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/SOURCE_ROUTING.md), the sending node must detect the failure through timeout or lack of acknowledgement and calculate a new route for subsequent packets. Individual packets already in transit that encounter a dead relay are dropped, as the algorithm does not support dynamic route recalculation mid-transmission.

### How does BitChat handle packets larger than a single MTU?

Large payloads are fragmented using the [`Fragmenter.swift`](https://github.com/permissionlesstech/bitchat/blob/main/Fragmenter.swift) utility, which splits the data into multiple Packet Version 2 frames. Each fragment header contains the **same source route** as the original packet, ensuring all pieces traverse the identical relay sequence. The receiving node buffers fragments until the complete payload is reassembled, preventing the broadcast storms that would occur if fragments were routed independently.

### Is the source routing algorithm vulnerable to route tampering?

No. The implementation in [`bitchat/Crypto/CryptoSeal.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Crypto/CryptoSeal.swift) applies an XChaCha20-Poly1305 authentication tag over the entire packet, including the route list. Intermediate relays can read the next-hop information but cannot modify the remaining path without invalidating the cryptographic signature. The destination node verifies this tag before processing, rejecting any packets with altered routes.

### When does BitChat fallback to flooding instead of using source routes?

The system triggers fallback flooding in two specific cases: when a packet uses **Version 1** format (which predates source routing) or when the source route list is **exhausted before reaching the destination**. The [`RelayForwarder.swift`](https://github.com/permissionlesstech/bitchat/blob/main/RelayForwarder.swift) implementation checks for these conditions and invokes `forwardViaFlooding()` to broadcast the packet mesh-wide, ensuring delivery compatibility at the cost of reduced efficiency.