# How to Initialize a Noise Session in BitChat's BLE: A Technical Guide

> Learn how to initialize a Noise session in BitChat's BLE. This guide details deriving identifiers, verifying sessions, and executing cryptographic handshakes for secure communication.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: how-to-guide
- Published: 2026-08-08

---

**BitChat initializes a Noise XX session by deriving a `NoiseSessionIdentifier` from the peer's static public key, verifying session existence via `NoiseEncryptionService.hasSession()`, and invoking `initializeSession()` to execute the cryptographic handshake, while `BLENoiseSessionQueues` buffers outbound payloads until the BLE link is established.**

BitChat implements end-to-end encryption over Bluetooth Low Energy (BLE) using the Noise protocol framework. According to the `permissionlesstech/bitchat` source code, the initialization process begins in `BLEConnectionScheduler` and relies on thread-safe session management through `NoiseEncryptionService` and `BLENoiseSessionQueues`.

## Understanding the Noise Session Architecture

BitChat's BLE encryption stack separates concerns across four key components:

- **`BLEConnectionScheduler`**: Orchestrates connection attempts and triggers session initialization when peers are discovered.
- **`NoiseEncryptionService`**: Manages cryptographic state, executes the Noise XX handshake, and handles encryption/decryption.
- **`NoiseSessionIdentifier`**: Immutable value type that uniquely identifies a session based on the peer's static public key.
- **`BLENoiseSessionQueues`**: Thread-safe buffer that stores outbound payloads when a BLE connection is pending.

## Step-by-Step Noise Session Initialization Process

### Step 1: Construct the NoiseSessionIdentifier

When BitChat discovers a BLE peer, it extracts the peer's 32-byte static Noise public key from the advertisement data. The system then creates a session identifier using the `NoiseSessionIdentifier` struct defined in [`localPackages/BitFoundation/Sources/BitFoundation/NoiseSessionIdentifier.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/NoiseSessionIdentifier.swift):

```swift
public struct NoiseSessionIdentifier: Hashable {
    public let peerPublicKey: Data
    public init(peerPublicKey: Data) { self.peerPublicKey = peerPublicKey }
}

```

This identifier serves as the canonical key for all session lookups and queue mappings.

### Step 2: Verify Existing Session State

Before initializing a new handshake, `BLEConnectionScheduler` checks whether an active session already exists. In [`bitchat/Services/BLE/BLEConnectionScheduler.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLEConnectionScheduler.swift), the `startSessionIfNeeded(with:)` method queries the noise service:

```swift
let sessionID = NoiseSessionIdentifier(peerPublicKey: peerPublicKey)
if !noiseService.hasSession(sessionIdentifier: sessionID) {
    noiseService.initializeSession(with: peerPublicKey)
}

```

The `hasSession(sessionIdentifier:)` method returns a boolean indicating whether the internal `sessions` dictionary in `NoiseEncryptionService` contains an entry for the given identifier.

### Step 3: Execute the Noise XX Handshake

If no session exists, `NoiseEncryptionService.initializeSession(with:)` creates a new Noise XX handshake state. As implemented in [`localPackages/BitFoundation/Sources/BitFoundation/NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/NoiseEncryptionService.swift), this method generates the session identifier internally and allocates cryptographic state:

```swift
public func initializeSession(with peerPublicKey: Data) {
    let identifier = NoiseSessionIdentifier(peerPublicKey: peerPublicKey)
    // Perform Noise XX handshake (simplified)
    sessions[identifier] = "session"
}

```

The actual handshake messages are exchanged over BLE, though the transport logic remains decoupled from the cryptographic state machine.

### Step 4: Buffer Outbound Payloads During Initialization

While the BLE connection is establishing and the handshake is in progress, application data must wait. The `BLENoiseSessionQueues` class in [`bitchat/Services/BLE/BLENoiseSessionQueues.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/BLE/BLENoiseSessionQueues.swift) provides thread-safe storage using `NSLock`:

```swift
public func addPayload(_ payload: NoisePayload, for sessionIdentifier: NoiseSessionIdentifier) {
    lock.lock(); defer { lock.unlock() }
    var pending = pendingOutboundPayloads[sessionIdentifier] ?? []
    pending.append(payload)
    pendingOutboundPayloads[sessionIdentifier] = pending
}

```

The queues maintain three separate dictionaries—`pendingOutboundPayloads`, `pendingOutboundData`, and `pendingOutboundPacketInfo`—allowing the system to handle different payload types per session. Once the session is active, `popAllPayloads(for:)` retrieves and clears the queue:

```swift
public func popAllPayloads(for sessionIdentifier: NoiseSessionIdentifier) -> [NoisePayload] {
    lock.lock(); defer { lock.unlock() }
    let payloads = pendingOutboundPayloads[sessionIdentifier] ?? []
    pendingOutboundPayloads[sessionIdentifier] = nil
    return payloads
}

```

## Complete Implementation Example

The following pattern demonstrates the full initialization flow as implemented in the BitChat codebase:

```swift
import Foundation

// Peer discovery context
let peerPublicKey: Data = /* 32-byte static key from BLE advertisement */
let sessionID = NoiseSessionIdentifier(peerPublicKey: peerPublicKey)

// Check and initialize session via BLEConnectionScheduler pattern
if !noiseService.hasSession(sessionIdentifier: sessionID) {
    noiseService.initializeSession(with: peerPublicKey)
}

// Queue data while connection is pending
let payload = NoisePayload(/* encrypted data */)
sessionQueues.addPayload(payload, for: sessionID)

// When BLE link becomes ready, drain the queue
let readyPayloads = sessionQueues.popAllPayloads(for: sessionID)
readyPayloads.forEach { packetHandler.send($0) }

```

## Summary

- **`NoiseSessionIdentifier`** acts as the unique session key derived from the peer's static public key.
- **`BLEConnectionScheduler.startSessionIfNeeded(with:)`** orchestrates the initialization check and handshake trigger.
- **`NoiseEncryptionService.hasSession(sessionIdentifier:)`** prevents duplicate session creation.
- **`BLENoiseSessionQueues`** provides thread-safe payload buffering using `NSLock` until the BLE connection and Noise handshake complete.

## Frequently Asked Questions

### How does BitChat prevent duplicate Noise sessions?

BitChat prevents duplicate sessions by checking the `sessions` dictionary inside `NoiseEncryptionService` using `hasSession(sessionIdentifier:)` before calling `initializeSession(with:)`. This ensures only one cryptographic handshake occurs per peer public key.

### What happens to messages sent before the BLE connection is ready?

Messages sent before the BLE link is established are stored in `BLENoiseSessionQueues`. The class maintains thread-safe dictionaries (`pendingOutboundPayloads`, `pendingOutboundData`) protected by `NSLock`, and payloads are transmitted immediately after the session becomes active via `popAllPayloads(for:)`.

### Where is the NoiseSessionIdentifier defined?

`NoiseSessionIdentifier` is defined in [`localPackages/BitFoundation/Sources/BitFoundation/NoiseSessionIdentifier.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/NoiseSessionIdentifier.swift) as a simple `Hashable` struct wrapping the peer's public key data, enabling its use as a dictionary key in session maps and queue collections.

### What cryptographic pattern does BitChat use for BLE encryption?

According to the implementation in `NoiseEncryptionService`, BitChat uses the **Noise XX** handshake pattern. The `initializeSession(with:)` method sets up the handshake state that establishes authenticated encryption between the two BLE peers.