# What Is the Source-Based Routing Protocol v2 in BitChat? Implementation Guide

> Learn about BitChat's Source-Based Routing Protocol v2 for efficient unicast delivery in mesh networks. Discover its implementation and fallback mechanisms for robust communication.

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

---

**BitChat's Source-Based Routing Protocol v2 enables efficient unicast delivery across mesh networks by embedding an explicit list of intermediate relays (the source route) directly into packet headers, falling back to flood broadcast when routes fail.**

The **Source-Based Routing Protocol v2** (SBR v2) in the [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat) repository represents a significant evolution from the legacy flooding mechanism, allowing senders to specify exact forwarding paths through the mesh. This protocol extension maintains backward compatibility with Version 1 clients while introducing structured routing data that reduces unnecessary network traffic. All routing logic is cryptographically secured through Ed25519 signatures that cover the entire packet payload, including the embedded route list.

## Overview of Source-Based Routing v2

### Packet Structure and Versioning

SBR v2 introduces a fixed **16-byte header** (expanded from 14 bytes in Version 1) to accommodate the routing metadata. The additional 2 bytes support a 4-byte payload length field required for larger unicast transmissions.

Key structural changes include:

- **Protocol Version**: Packets explicitly set to **Version 2**; Version 1 packets maintain the legacy 2-byte payload length limit
- **HAS_ROUTE Flag**: The header flag `HAS_ROUTE (0x08)` is only valid when `version ≥ 2`—legacy clients must ignore this bit
- **Source Route Field**: A variable-length list positioned **after the RecipientID** containing:
  - `Count` (1 byte): Number of intermediate hops N
  - `Hops` (N × 8 bytes): Peer IDs of the relay nodes

### Routing Identifiers

Each peer in the BitChat mesh is identified by an **8-byte routing ID** (`PeerID.routingData`), derived from the short 16-character hexadecimal peer ID. As implemented in [`localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift), this compact identifier minimizes header overhead while maintaining unique node addressing across the network.

## Topology Discovery and Route Calculation

BitChat builds its mesh topology through **confirmed edges**—bidirectional peer relationships where both nodes acknowledge each other as neighbors.

The discovery process relies on the **Neighbor List TLV** (Type 0x04) embedded within `IdentityAnnouncement` packets. When a node receives neighbor information from a peer, it validates the edge only when reciprocity is confirmed (both peers list each other). The [`MeshTopologyTracker.swift`](https://github.com/permissionlesstech/bitchat/blob/main/MeshTopologyTracker.swift) file maintains this graph structure, providing the pathfinding substrate for source route calculation.

Routes are calculated to find paths of **≤ 4 intermediate hops** through nodes that have been observed speaking Protocol v2, ensuring compatibility and minimizing latency across the mesh.

## Security and Relay Logic

### Cryptographic Protection

The protocol maintains end-to-end integrity through Ed25519 signatures that cover the **entire packet**, including the source route list. Any modification to the route by intermediate nodes invalidates the signature, causing receiving nodes to drop the packet immediately. This prevents route hijacking and ensures that only the original sender authorizes the forwarding path.

### Relay Forwarding Mechanism

When a node receives a packet via [`BLERouteForwardingPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLERouteForwardingPolicy.swift), it executes the following validation sequence:

1. Verify `version ≥ 2` and `HAS_ROUTE` flag presence
2. Locate its own `routingData` in the hop list
3. Forward the packet to the next peer in the sequence (or the final recipient if last hop)
4. Fall back to **flood/broadcast** if the next hop is unreachable

All fragmented payloads maintain Version 2 headers and carry identical route lists to preserve the unicast path across multiple physical frames.

## iOS Implementation Specifics

The iOS client implements strict origination policies to prevent routing loops and unnecessary overhead. Defined in [`BLESourceRouteOriginationPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLESourceRouteOriginationPolicy.swift), a source route is attached only when **all** six conditions are met:

- The sender is the local peer (no re-signing of forwarded packets)
- The recipient is not a broadcast address
- TTL > 1
- The recipient is not directly connected
- A complete v2 path exists with ≤ 4 intermediary hops, all speaking Protocol v2
- No recent failure entry exists in `BLESourceRouteFailureCache`

### Failure Detection and Fallback

If a routed transmission does not receive an inbound acknowledgment from the recipient within **10 seconds**, the route is marked as failed in [`BLESourceRouteFailureCache.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLESourceRouteFailureCache.swift) for **60 seconds**. During this window, the system falls back to flooding; after expiration, routing attempts resume automatically.

## Code Examples

### Creating a Source-Routed Packet

The following Swift implementation from [`BitchatPacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitchatPacket.swift) demonstrates constructing a Version 2 packet with an explicit route:

```swift
import BitFoundation

// PeerID objects for sender, recipient, and intermediate hops
let sender = myPeerID
let recipient = remotePeerID
let hop1 = intermediatePeerA
let hop2 = intermediatePeerB

// Build route using 8-byte routingData
let route = [hop1.routingData!, hop2.routingData!]

// Construct Version 2 packet with embedded route
var packet = BitchatPacket(
    version: .v2,
    senderID: sender.routingData!,
    recipientID: recipient.routingData!,
    payload: myPayloadData,
    route: route
)

// Sign entire packet including route
packet.sign(with: mySigningKey)

```

### Implementing Relay Forwarding Logic

The forwarding logic in [`BLERouteForwardingPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLERouteForwardingPolicy.swift) processes incoming routed packets:

```swift
func forward(_ packet: BitchatPacket) {
    guard packet.version >= .v2,
          packet.flags.contains(.hasRoute),
          let route = packet.route,
          !route.isEmpty else {
        // No valid source route: fall back to flood
        flood(packet)
        return
    }

    // Locate self in the route sequence
    guard let myIndex = route.firstIndex(of: myPeerID.routingData!) else {
        // Not in route path: ignore or flood
        flood(packet)
        return
    }

    // Determine next hop (intermediate or final recipient)
    let nextHopData: Data
    if myIndex + 1 < route.count {
        nextHopData = route[myIndex + 1]
    } else {
        nextHopData = packet.recipientID
    }

    // Unicast to next hop
    sendToPeer(
        data: packet.encode(),
        peerID: PeerID(routingData: nextHopData)!
    )
}

```

### Validating Confirmed Edges

Before forwarding, nodes verify topology through [`MeshTopologyTracker.swift`](https://github.com/permissionlesstech/bitchat/blob/main/MeshTopologyTracker.swift):

```swift
let mesh = MeshTopologyTracker.shared
guard mesh.isConfirmedEdge(between: myPeerID, and: nextHopPeerID) else {
    // Unconfirmed edge: abort routing, use broadcast
    flood(packet)
    return
}

```

## Key Source Files

The Source-Based Routing Protocol v2 is implemented across the following core files:

- **[`docs/SOURCE_ROUTING.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/SOURCE_ROUTING.md)** — Complete protocol specification covering versioning, route format, and security model
- **[`localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift)** — Defines `routingData` conversion and 8-byte mesh ID generation
- **[`localPackages/BitFoundation/Sources/BitFoundation/BinaryProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/BinaryProtocol.swift)** — Parses headers and validates `HAS_ROUTE` flags
- **[`bitchat/Services/BLE/BLESourceRouteOriginationPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLESourceRouteOriginationPolicy.swift)** — iOS policy engine for route attachment decisions
- **[`bitchat/Services/BLE/BLESourceRouteFailureCache.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLESourceRouteFailureCache.swift)** — Manages route failure states and timeout logic
- **[`bitchat/Services/BLE/BLERouteForwardingPolicy.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLERouteForwardingPolicy.swift)** — Core relay implementation and next-hop selection
- **[`bitchat/Services/MeshTopologyTracker.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/MeshTopologyTracker.swift)** — Maintains confirmed-edge graph for route calculation
- **[`bitchat/Services/BitchatPacket.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BitchatPacket.swift)** — Packet construction and encoding API
- **[`bitchat/Services/TransportConfig.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/TransportConfig.swift)** — Routing configuration flags and protocol constants

## Summary

- **Source-Based Routing Protocol v2** upgrades BitChat packets to 16-byte headers with embedded explicit relay lists
- The **`HAS_ROUTE (0x08)`** flag activates only in Version 2+, with strict backward compatibility for legacy clients
- Routes consist of **1-byte hop count** followed by **8-byte PeerID segments** placed after the RecipientID field
- **Confirmed edges** from bidirectional Neighbor List TLVs (Type 0x04) provide the topology graph for pathfinding
- **Ed25519 signatures** cover the entire packet including routes, preventing tampering by intermediate nodes
- iOS clients apply strict **origination policies** (6 conditions) and **60-second failure caching** to optimize mesh efficiency
- Automatic fallback to **flood broadcast** occurs when routes fail, next hops are unreachable, or edges are unconfirmed

## Frequently Asked Questions

### What is the difference between Version 1 and Version 2 packets in BitChat?

Version 1 packets use a **14-byte fixed header** with a 2-byte payload length limit and do not support routing flags. Version 2 expands the header to **16 bytes** (adding a 4-byte payload length field) and introduces the **`HAS_ROUTE (0x08)`** flag to indicate the presence of a source route list. Legacy Version 1 clients safely ignore the routing flag while continuing to process standard broadcasts.

### How does BitChat ensure source routes have not been tampered with?

The protocol uses **Ed25519 digital signatures** that cryptographically cover the entire packet, including the source route list and payload. Because the signature is computed over the complete serialized bytes, any modification to the route by an intermediate relay invalidates the signature. Receiving nodes verify signatures before processing, dropping packets that fail authentication.

### What happens when a source route fails in BitChat v2?

When a routed transmission receives no acknowledgment within **10 seconds**, the route is marked as failed in [`BLESourceRouteFailureCache.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BLESourceRouteFailureCache.swift) and excluded from routing decisions for **60 seconds**. During this period, the sender falls back to **flood broadcast** to ensure message delivery. After the cache entry expires, the system attempts source routing again to detect topology healing.

### How does a BitChat node discover available routes?

Nodes build a mesh topology through **Neighbor List TLVs (Type 0x04)** exchanged in `IdentityAnnouncement` packets. The [`MeshTopologyTracker.swift`](https://github.com/permissionlesstech/bitchat/blob/main/MeshTopologyTracker.swift) module constructs a graph of **confirmed edges**, where an edge exists only if both peers acknowledge each other as neighbors. Source routes are calculated as paths of **≤ 4 hops** through this confirmed-edge graph, ensuring all intermediate nodes are known and reachable.