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-Poly1305 AEAD for encrypted payloads
  • Hash function: SHA-256 for 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →