# What Encryption Methods Does BitChat Use? A Complete Technical Breakdown

> Discover the encryption methods BitChat employs: Noise Protocol Framework, Curve25519, ChaCha20-Poly1305, SHA-256, and XChaCha20-Poly1305 for Nostr. Get a full technical breakdown.

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

---

**BitChat uses the Noise Protocol Framework with Curve25519 key exchange, ChaCha20-Poly1305 AEAD encryption, and SHA-256 hashing, plus XChaCha20-Poly1305 for Nostr compatibility.**

The permissionless BitChat messaging protocol implements a full Noise stack for on-device storage and peer-to-peer traffic protection. This analysis examines the specific algorithms, handshake patterns, and source files that comprise its cryptographic architecture.

---

## Noise Protocol Framework Implementation

BitChat builds its security layer on the **Noise Protocol Framework**, a modern approach to cryptographic protocols that combines DH handshakes with symmetric ciphers. According to the BitChat source code, the implementation resides primarily in [`bitchat/Noise/NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift) and closely follows the official Noise specification.

The four core primitives are initialized together at lines 26-29:

```swift
let noiseProtocol = NoiseProtocol(
    handshakePattern: .XX,
    dh: .curve25519,
    cipher: .chacha20Poly1305,
    hash: .sha256
)

```

Each primitive serves a distinct purpose in the security model.

---

## Key Exchange: Curve25519 (X25519)

**Diffie-Hellman key agreement uses the Curve25519 elliptic curve**, specified in [`NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseProtocol.swift) lines 27-28. This provides:

- **128-bit security level** with 32-byte public keys
- **Constant-time implementation** to resist timing attacks
- **Small, fast operations** suitable for mobile and embedded contexts

The static keys are managed through the `KeychainManager` protocol, with ephemeral keys generated per session to ensure forward secrecy.

---

## Symmetric Encryption: ChaCha20-Poly1305

The **ChaCha20-Poly1305 AEAD cipher** handles all symmetric encryption after handshake completion. Defined at line 28-29 of [`NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseProtocol.swift), this construction provides authenticated encryption with associated data—ensuring confidentiality and integrity without separate MAC operations.

Post-handshake encryption follows this pattern:

```swift
let (sendCipher, receiveCipher, _) = try handshake.getTransportCiphers(useExtractedNonce: false)
let encrypted = try sendCipher.encrypt(plaintext: messageData)

```

The `NoiseCipherState` class manages cipher instances, nonces, and replay protection through a 1024-message sliding window implemented at lines 33-36.

---

## Handshake Pattern: XX (Mutual Authentication)

BitChat selects the **Noise XX pattern** for its handshake, as declared at lines 26-28. The XX pattern provides:

1. **Mutual authentication** — both parties prove possession of static keys
2. **Identity hiding** — initiator and responder identities remain encrypted until exchanged
3. **Three-message handshake** — efficient for peer-to-peer discovery scenarios

The [`NoiseHandshakeState.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseHandshakeState.swift) file orchestrates this flow, handling key mixing and exposing transport cipher objects upon completion.

```swift
let handshake = try NoiseHandshakeState(
    role: .initiator,
    pattern: .XX,
    keychain: myKeychain,
    localStaticKey: staticKey,
    remoteStaticKey: nil,
    prologue: Data()
)
let msg1 = try handshake.writeMessage()

```

---

## Hash Function: SHA-256

**SHA-256** serves as the single cryptographic hash, specified at line 29. It functions in two capacities:

- **Handshake transcript hashing** — binds protocol messages to prevent tampering
- **Key derivation** — extracts and expands keys from DH shared secrets per the Noise specification

---

## Replay Protection Mechanism

BitChat implements **sliding-window nonce tracking** to prevent replay attacks. The `NoiseCipherState` maintains a 1024-message window at lines 33-36, rejecting any nonce that falls behind the window or duplicates an existing entry.

This protection applies to all transport messages after the handshake completes, ensuring that captured ciphertext cannot be re-injected into later sessions.

---

## Nostr Compatibility: XChaCha20-Poly1305

For interoperability with Nostr protocol requirements, BitChat includes an additional AEAD variant in [`XChaCha20Poly1305Compat.swift`](https://github.com/permissionlesstech/bitchat/blob/main/XChaCha20Poly1305Compat.swift). The **XChaCha20-Poly1305** construction extends the nonce size from 96 bits to 192 bits, enabling safer random nonce generation for long-lived keys.

```swift
let secretKey = SymmetricKey(size: .bits256)
let nonce = try XChaCha20Poly1305Compat.Nonce()
let sealed = try XChaCha20Poly1305Compat.seal(message, using: secretKey, nonce: nonce)

```

This compatibility layer operates separately from the main Noise stack, accessed through the `bitchat.Nostr` module.

---

## Security Properties Delivered

| Property | Implementation Mechanism |
|----------|------------------------|
| **Mutual authentication** | XX pattern with static key signatures |
| **Forward secrecy** | Per-session ephemeral DH exchanges |
| **Integrity & confidentiality** | ChaCha20-Poly1305 AEAD |
| **Replay resistance** | 1024-message sliding-window nonce filter |
| **Side-channel resistance** | Constant-time public key validation |

---

## Key Source Files

- **[`bitchat/Noise/NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift)** — Core Noise primitives and protocol configuration
- **[`bitchat/Noise/NoiseHandshakeState.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseHandshakeState.swift)** — Handshake orchestration and key mixing
- **[`bitchat/Noise/NoiseCipherState.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseCipherState.swift)** — Symmetric encryption and replay protection
- **[`bitchat/Nostr/XChaCha20Poly1305Compat.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/XChaCha20Poly1305Compat.swift)** — Extended-nonce AEAD for Nostr compatibility

---

## Summary

- BitChat encryption methods rely entirely on the Noise Protocol Framework with XX handshake pattern
- **Curve25519** provides elliptic-curve Diffie-Hellman key exchange with 128-bit security
- **ChaCha20-Poly1305** delivers authenticated encryption for all transport traffic
- **SHA-256** handles handshake hashing and key derivation
- A **1024-message sliding window** prevents replay attacks on transport messages
- **XChaCha20-Poly1305** in [`XChaCha20Poly1305Compat.swift`](https://github.com/permissionlesstech/bitchat/blob/main/XChaCha20Poly1305Compat.swift) enables Nostr protocol interoperability

---

## Frequently Asked Questions

### Does BitChat use end-to-end encryption?

Yes. BitChat implements true end-to-end encryption through the Noise Protocol Framework. The XX handshake pattern ensures both peers authenticate each other with static keys, and all subsequent traffic encrypts with ChaCha20-Poly1305 keys derived from ephemeral Curve25519 exchanges.

### What is the difference between ChaCha20-Poly1305 and XChaCha20-Poly1305 in BitChat?

ChaCha20-Poly1305 uses a 96-bit nonce and serves as the default AEAD within the Noise protocol. XChaCha20-Poly1305 in [`XChaCha20Poly1305Compat.swift`](https://github.com/permissionlesstech/bitchat/blob/main/XChaCha20Poly1305Compat.swift) extends the nonce to 192 bits, reducing collision risk when using random nonces—particularly important for Nostr compatibility where long-term keys encrypt multiple messages.

### How does BitChat prevent replay attacks?

The `NoiseCipherState` class implements a 1024-message sliding-window nonce tracker at lines 33-36 of [`NoiseProtocol.swift`](https://github.com/permissionlesstech/bitchat/blob/main/NoiseProtocol.swift). This rejects any message with a nonce already seen or fallen outside the window, ensuring captured ciphertext cannot be replayed in future sessions.

### Is BitChat's cryptography suitable for Bluetooth Low Energy (BLE) messaging?

Yes. The selected algorithms—Curve25519 and ChaCha20-Poly1305—were specifically chosen for performance on constrained devices. The compact 32-byte public keys, fast constant-time operations, and minimal handshake overhead make the implementation well-suited for BLE and other low-bandwidth transports.