# BitChat Encryption Methods for Live Sessions: Noise XX Protocol Implementation

> Discover BitChat's robust encryption for live sessions. Learn how Noise XX protocol, X25519 keys, ChaCha20-Poly1305, and SHA-256 ensure secure peer-to-peer communication.

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

---

**BitChat secures live peer-to-peer sessions using the Noise XX handshake pattern with X25519 elliptic curve keys, ChaCha20-Poly1305 authenticated encryption, and SHA-256 hashing.**

BitChat is an open-source, permissionless messaging framework that prioritizes cryptographic privacy for real-time communication. According to the permissionlesstech/bitchat source code, the application implements the Noise Protocol Framework's XX pattern to establish secure sessions between peers, combining modern elliptic curve cryptography with authenticated symmetric encryption.

## The Noise XX Cryptographic Suite

The implementation in [`bitchat/Services/NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Services/NoiseEncryptionService.swift) defines a complete cryptographic stack for live session establishment and message protection.

### X25519 Elliptic Curve Key Exchange

BitChat uses **X25519 (Curve25519)** for all key exchange operations within the Noise XX handshake. The static identity keys are defined and loaded in [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift) at lines 54-61, where each peer maintains a long-term Curve25519 key pair stored in the system keychain. During the three-message handshake, both initiator and responder prove possession of their static keys while simultaneously generating ephemeral X25519 key pairs to ensure forward secrecy.

### ChaCha20-Poly1305 Authenticated Encryption

All symmetric encryption operations utilize **ChaCha20-Poly1305**, the default authenticated encryption with associated data (AEAD) cipher for Noise XX. In [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift) at lines 68-82, the `encrypt` and `decrypt` methods funnel through `NoiseSessionManager`, which applies ChaCha20-Poly1305 to all payload data. This construction provides both confidentiality and integrity verification for every message transmitted during live sessions.

### SHA-256 Hashing and Peer Identification

BitChat employs **SHA-256** for multiple cryptographic functions within the Noise implementation. The hash algorithm generates peer identity fingerprints at lines 24-28 of [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift), derives the 8-byte routing ID from static key material in [`localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift), and serves as the underlying hash function for HKDF key derivation during the handshake process.

## How the Noise XX Handshake Works in BitChat

The Noise XX pattern implemented in BitChat provides **mutual authentication** through a three-message handshake where both parties present static X25519 public keys. As documented in the code comments at lines 35-36 of [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift), this pattern enables two peers with pre-existing knowledge of each other's public keys to establish an encrypted session without requiring certificates or a central authority.

The handshake achieves **forward secrecy** by combining static long-term keys with ephemeral X25519 keys generated fresh for each session. Even if a static private key is compromised later, past session contents remain protected because the symmetric ChaCha20-Poly1305 keys incorporate ephemeral contributions from both peers.

## Implementing BitChat Encryption in Swift

The `NoiseEncryptionService` class provides the primary Swift interface for establishing encrypted sessions. The service requires a keychain instance for secure key storage and exposes methods for handshake initiation and message encryption.

```swift
import Bitchat

// 1️⃣ Create the service (keychain is injected by the app)
let noiseService = NoiseEncryptionService(keychain: myKeychain)

// 2️⃣ Initiate a handshake with a peer (PeerID is the 8‑byte routing ID)
do {
    let handshakeData = try noiseService.initiateHandshake(with: peerID)
    // Send `handshakeData` over BLE or other transport
} catch {
    // Handle errors such as rate‑limit or invalid peer ID
}

// 3️⃣ Encrypt a message once the session is established
do {
    let plaintext = Data("Hello, world!".utf8)
    let encrypted = try noiseService.encrypt(plaintext, for: peerID)
    // Transmit `encrypted` payload
} catch NoiseEncryptionError.handshakeRequired {
    // Trigger a new handshake before sending
}

// 4️⃣ Decrypt an incoming message
do {
    let (decrypted, _) = try noiseService.decryptWithSessionGeneration(
        incomingData,
        from: peerID
    )
    // Use `decrypted` as the original message
} catch {
    // Session not established or message too large
}

```

The API design separates concerns between session management and transport:

- `initiateHandshake(with:)` – Begins the Noise XX three-message handshake sequence
- `encrypt(_:for:)` – Encrypts data using the established session's ChaCha20-Poly1305 key
- `decryptWithSessionGeneration(_:from:)` – Decrypts data and returns the session generation counter for replay protection

## Session Re-keying and Lifecycle Management

BitChat implements **automatic session re-keying** to limit the volume of data encrypted under a single key. The timer-driven re-key logic at lines 80-87 of [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift) periodically rotates the ChaCha20-Poly1305 encryption keys while maintaining the same X25519 static identity keys. This practice follows Noise protocol best practices for long-lived sessions, ensuring that key compromise results in minimal data exposure.

## Security Properties and Guarantees

The [`docs/privacy-assessment.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/privacy-assessment.md) file explicitly confirms the cryptographic suite for mesh sessions: "Noise XX with X25519, ChaCha20-Poly1305, and SHA-256." This combination delivers three critical security properties:

- **Mutual Authentication**: Each peer cryptographically proves possession of its static private key during the handshake
- **Forward Secrecy**: Ephemeral key contributions ensure session keys cannot be recovered from future static key compromises
- **Integrity and Confidentiality**: ChaCha20-Poly1305 provides authenticated encryption resistant to tampering and eavesdropping

The implementation is validated by the test suite in [`bitchatTests/Noise/NoiseProtocolTests.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchatTests/Noise/NoiseProtocolTests.swift), which exercises the complete Noise XX handshake flow and message encryption cycles.

## Summary

- BitChat implements the **Noise XX** handshake pattern for live peer-to-peer sessions, using **X25519** for key exchange, **ChaCha20-Poly1305** for symmetric encryption, and **SHA-256** for hashing.
- The [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift) file contains the core implementation, managing static key storage, session lifecycle, and automatic re-keying at lines 54-87.
- The protocol provides mutual authentication without certificates, forward secrecy through ephemeral keys, and authenticated encryption for all messages.
- Developers interact with the system through `NoiseEncryptionService`, utilizing `initiateHandshake(with:)`, `encrypt(_:for:)`, and `decryptWithSessionGeneration(_:from:)` methods.
- Session security is maintained through timer-driven re-keying that periodically rotates symmetric encryption material while preserving established session contexts.

## Frequently Asked Questions

### What is Noise XX and why does BitChat use it for live sessions?

Noise XX is a specific handshake pattern from the Noise Protocol Framework that provides mutual authentication using static X25519 keys combined with ephemeral key exchange. BitChat selects this pattern because it enables two peers to authenticate each other and establish encrypted sessions without requiring a centralized certificate authority or prior shared secrets. As documented in [`docs/WHITEPAPER.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/WHITEPAPER.md), this approach aligns with BitChat's permissionless philosophy while providing modern cryptographic guarantees.

### How does BitChat handle key rotation during active sessions?

BitChat implements automatic re-keying through timer-driven logic in [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift) at lines 80-87. The system periodically generates new ChaCha20-Poly1305 encryption keys using the existing X25519 session state, limiting the amount of data encrypted under any single symmetric key. This re-keying occurs transparently to the application layer and maintains session continuity while reducing exposure from potential key compromise.

### Where does BitChat store the static X25519 identity keys?

Static X25519 keys are persisted in the system keychain through dependency injection, as evidenced by the `NoiseEncryptionService` initializer requiring a keychain object. The key material is loaded at lines 54-61 of [`NoiseEncryptionService.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseEncryptionService.swift), ensuring that long-term identity keys remain in secure hardware-backed storage when available on the device, rather than application memory or insecure disk locations.

### How does BitChat verify peer identities without a central authority?

BitChat derives **PeerID** values from SHA-256 fingerprints of the static X25519 public keys, as implemented in [`localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift`](https://github.com/permissionlesstech/bitchat/blob/main/localPackages/BitFoundation/Sources/BitFoundation/PeerID.swift). The 8-byte routing ID serves as a compact, collision-resistant identifier derived from the cryptographic public key itself. During the Noise XX handshake, peers exchange and verify static public keys, confirming identity through cryptographic proof rather than centralized validation, with the SHA-256 fingerprint providing a human-verifiable reference.