What Encryption Methods Does Bit Chat Use? A Deep Dive into Noise Protocol Security
Bit Chat uses the Noise Protocol Framework with the XX handshake pattern, combining Curve25519 key exchange, ChaCha20-Poly1305 authenticated encryption, and SHA-256 hashing for secure peer-to-peer messaging.
All cryptographic operations in the bitchat repository are built on a self-contained implementation of the Noise Protocol Framework, a modern standard for lightweight, secure transport protocols. The code explicitly avoids legacy TLS complexity while providing mutual authentication, forward secrecy, and replay protection out of the box.
Core Encryption Methods in Bit Chat
Noise Protocol: The Foundation
The [bitchat/Noise/NoiseProtocol.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift) file defines the complete cryptographic suite. Lines 26-29 declare the exact algorithms used across all connections:
- Handshake pattern:
XX— mutual authentication where both peers exchange and verify static public keys - Diffie-Hellman:
Curve25519(X25519) for elliptic-curve key agreement - Symmetric cipher:
ChaCha20-Poly1305AEAD for encrypted payloads - Hash function:
SHA-256for key derivation and handshake transcript hashing
This selection mirrors the Noise_XX_25519_ChaChaPoly_SHA256 protocol name from the Noise specification.
Key Exchange with Curve25519
The Curve25519 implementation provides 128-bit security with constant-time operations. Static keys are loaded through a KeychainManager abstraction, ensuring private keys never leave secure enclaves unnecessarily.
Authenticated Encryption
ChaCha20-Poly1305 handles all bulk data encryption after handshake completion. This AEAD construction provides:
- Confidentiality via ChaCha20 stream cipher
- Integrity via Poly1305 message authentication code
- 96-bit nonces with automatic tracking
Security Features in the Implementation
Mutual Authentication
The XX pattern requires both initiator and responder to present valid static keys. Each peer verifies the other's identity through explicit static-key signatures embedded in the handshake transcript.
Forward Secrecy
Every session derives unique ephemeral keys through multiple X25519 operations. Even if long-term static keys are compromised later, past session keys cannot be reconstructed.
Replay Attack Protection
Lines 33-36 of NoiseProtocol.swift implement a 1024-message sliding-window nonce tracker in NoiseCipherState. This rejects:
- Duplicated messages with reused nonces
- Messages with nonces outside the valid window
- Out-of-order messages beyond recovery range
Timing Attack Mitigation
The implementation uses constant-time comparisons for public-key validation, eliminating side-channel leaks during handshake verification.
Extended Algorithm: XChaCha20-Poly1305 for Nostr
For interoperability with Nostr protocol messages, Bit Chat includes [XChaCha20Poly1305Compat.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/XChaCha20Poly1305Compat.swift). This variant uses:
- 192-bit nonces instead of 96-bit, enabling safer random nonce generation
- Same ChaCha20-Poly1305 core construction
- Dedicated compatibility layer keeping Nostr traffic isolated from Noise sessions
Code Examples: Working with Bit Chat Encryption
Establishing a Noise Handshake (XX Pattern)
import BitFoundation
import BitLogger
import CryptoKit
import bitchat
// Initialize with your long-term static key from secure storage
let staticKey = Curve25519.KeyAgreement.PrivateKey()
// Create handshake state as initiator
let handshake = try NoiseHandshakeState(
role: .initiator,
pattern: .XX,
keychain: myKeychain,
localStaticKey: staticKey,
remoteStaticKey: nil, // discovered during handshake
prologue: Data() // optional domain separation
)
// Send first message containing ephemeral public key
let msg1 = try handshake.writeMessage()
// Transmit msg1, receive msg2, then complete authentication
let payload = try handshake.readMessage(msg2)
Encrypting and Decrypting Application Data
// Extract cipher states after handshake completion
let (sendCipher, receiveCipher, _) = try handshake.getTransportCiphers(
useExtractedNonce: false
)
// Encrypt outbound message
let plaintext = "Secure message".data(using: .utf8)!
let ciphertext = try sendCipher.encrypt(plaintext: plaintext)
// Decrypt inbound message on peer
let recovered = try receiveCipher.decrypt(ciphertext: ciphertext)
print(String(data: recovered, encoding: .utf8)!) // "Secure message"
Using Nostr-Compatible XChaCha20-Poly1305
import bitchat.Nostr
let secretKey = SymmetricKey(size: .bits256)
let nonce = try XChaCha20Poly1305Compat.Nonce()
let message = Data("Nostr event payload".utf8)
// Seal with 192-bit nonce
let sealed = try XChaCha20Poly1305Compat.seal(
message,
using: secretKey,
nonce: nonce
)
// Verify and open
let opened = try XChaCha20Poly1305Compat.open(
sealed,
using: secretKey,
nonce: nonce
)
Key Source Files for Encryption
| File | Purpose |
|---|---|
[bitchat/Noise/NoiseProtocol.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift) |
Algorithm definitions, constants, and NoiseCipherState with replay protection |
[bitchat/Noise/NoiseHandshakeState.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseHandshakeState.swift) |
Handshake orchestration, key mixing, and transport cipher export |
[bitchat/Noise/NoiseCipherState.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Noise/NoiseProtocol.swift#L28-L31) |
Symmetric encryption operations and nonce management |
[bitchat/Nostr/XChaCha20Poly1305Compat.swift](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/Nostr/XChaCha20Poly1305Compat.swift) |
Extended-nonce AEAD for Nostr protocol compatibility |
Summary
- Bit Chat implements Noise_XX_25519_ChaChaPoly_SHA256 for all peer-to-peer encryption
- Curve25519 provides the elliptic-curve foundation for key agreement
- ChaCha20-Poly1305 AEAD secures all application data with integrated authentication
- SHA-256 hashes drive the symmetric key derivation function
- A 1024-message sliding window prevents replay attacks without external state
- XChaCha20-Poly1305 extends compatibility to Nostr's 192-bit nonce requirements
- Constant-time operations protect against timing side-channels throughout
Frequently Asked Questions
Does Bit Chat use TLS or SSL for encryption?
No. Bit Chat deliberately avoids TLS in favor of the Noise Protocol Framework. Noise provides equivalent security guarantees with substantially less code complexity, making it ideal for resource-constrained peer-to-peer messaging over Bluetooth Low Energy and similar transports.
What happens if a message nonce is reused?
The NoiseCipherState sliding-window tracker in NoiseProtocol.swift rejects any nonce it has seen before or that falls outside the valid 1024-message window. This prevents decryption and terminates the suspicious session, protecting against replay and forgery attacks.
Can Bit Chat encrypt messages for offline delivery?
The core Noise implementation requires interactive key agreement. However, the XChaCha20Poly1305Compat module supports static-key encryption suitable for Nostr's relay-based store-and-forward model, using randomly generated 192-bit nonces safe for single-use encryption without handshake.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →