What Cryptographic Key Pairs Does BitChat Use for Identity and Security
BitChat relies on two distinct cryptographic key pairs—a Noise static X25519 pair for encrypted transport and peer identification, and an Ed25519 signing pair for message authenticity—to secure its decentralized mesh protocol without central authorities.
The open-source BitChat project (permissionlesstech/bitchat) implements a privacy-preserving messaging system that derives user identity directly from these cryptographic key pairs. Generated once during initial setup and persisted for the application's lifetime, these keys enable both encrypted peer-to-peer communication and cryptographic proof of identity in a fully decentralized environment.
The Dual-Key Architecture
BitChat’s security model separates transport confidentiality from identity verification by using two asymmetric key pairs with distinct cryptographic purposes.
Noise Static X25519 Key Pair for Transport Layer Security
The Noise static X25519 key pair provides the foundation for all encrypted communication in the mesh network. According to the source code in bitchat/Identity/IdentityModels.swift (lines 117-119), the publicKey field represents this 32-byte Noise static public key used in the Noise XX handshake pattern.
Key characteristics of this key pair include:
- Generation: Created by
SecureIdentityStateManageron the application's first launch and stored with device-only accessibility in the iOS Keychain. - Peer Identification: The 8-byte peer ID shown in packet headers derives directly from
SHA-256(noiseStaticPublicKey)[0..8], as documented inbitchat/Docs/PEER-ID-ROTATION.md. - Broadcast: The public component is transmitted in cleartext within every BLE announce packet, allowing other peers to initiate encrypted sessions.
- Session Negotiation: The private key negotiates per-session encryption secrets with remote peers while remaining on the device.
Ed25519 Signing Key Pair for Identity Authentication
Complementing the transport keys, the Ed25519 signing key pair provides message integrity and non-repudiation for identity-related operations. The signingPublicKey field in IdentityModels.swift stores this optional but critical 32-byte public key.
This key pair serves specific authentication functions:
- Signature Generation: The private key signs outbound announce packets and "vouch" payloads, enabling Trust On First Use (TOFU) pinning between devices.
- Fingerprinting: A persistent fingerprint calculated as
SHA-256(signingPublicKey)allows quick lookup and verification of known contacts. - Identity Persistence: Stored alongside the Noise keys but with distinct keychain service labels, ensuring cryptographic separation of duties between encryption and signing operations.
Key Generation and Secure Storage
Both cryptographic key pairs are instantiated simultaneously by the SecureIdentityStateManager class during the initial application setup. The implementation in bitchat/Identity/SecureIdentityStateManager.swift handles the cryptographic generation and iOS Keychain persistence.
Storage protections include:
- Device-Only Accessibility: Keys are marked with
kSecAttrAccessibleWhenUnlockedThisDeviceOnly, preventing extraction via iCloud backup or migration to other devices. - Service Separation: While both keys reside in the Secure Enclave-backed keychain, they utilize different service identifiers to prevent cross-key contamination.
- Panic Wipe: The architecture supports complete key deletion through a "panic wipe" mechanism that clears both key pairs simultaneously.
Accessing Keys in Swift Code
Developers interacting with the BitChat protocol can access these cryptographic key pairs through the SecureIdentityStateManagerProtocol. Below is a practical example demonstrating key retrieval and usage patterns:
import Foundation
// Obtain the identity manager (typically injected via dependency injection)
let identityMgr: SecureIdentityStateManagerProtocol = SecureIdentityStateManager(keychain)
// 1. Retrieve the device's stable Noise X25519 public key (32 bytes)
let noisePublicKey: Data = identityMgr.noisePublicKey
// 2. Derive the 8-byte short peer ID used in packet headers
// The full peer ID is SHA-256 of the public key, taking the first 8 bytes
let peerID = PeerID(hexData: noisePublicKey)
let shortPeerID = peerID.id.prefix(8) // 16 hex characters representing 8 bytes
// 3. Access the Ed25519 signing public key for verification
if let signingPublicKey = identityMgr.signingPublicKey {
// Verify an incoming announce signature
let isValid = Ed25519.verify(
message: announcePayload,
signature: announceSignature,
publicKey: signingPublicKey
)
}
// 4. Sign outbound data using the private Ed25519 key
let signedVouch = Ed25519.sign(
message: vouchPayload,
privateKey: identityMgr.signingPrivateKey
)
The BitchatPeer model in bitchat/Models/BitchatPeer.swift wraps these keys for high-level operations, exposing noisePublicKey for session establishment and signingPublicKey for identity validation.
Security Documentation and Technical References
The following source files contain the authoritative implementation details for these cryptographic key pairs:
| File Path | Purpose |
|---|---|
bitchat/Identity/IdentityModels.swift |
Defines the Identity struct containing the fingerprint, Noise static public key, and optional Ed25519 signing public key (lines 117-119). |
bitchat/Identity/SecureIdentityStateManager.swift |
Implements key generation, secure storage, and retrieval protocols for both cryptographic key pairs. |
bitchat/Models/BitchatPeer.swift |
High-level abstraction wrapping peer identities and providing access to both public keys. |
bitchat/Docs/PEER-ID-ROTATION.md |
Technical specification detailing the derivation of peer IDs from the Noise static key. |
bitchat/Docs/privacy-assessment.md |
Privacy analysis documenting the dual-key architecture and persistent identifier implications. |
Summary
- BitChat employs two cryptographic key pairs: A Noise static X25519 pair for transport encryption and an Ed25519 pair for identity signing.
- Peer identification derives from the Noise key: The visible 8-byte peer ID consists of the first 8 bytes of
SHA-256(noiseStaticPublicKey). - Keys are device-bound: Both pairs are generated once, stored in the iOS Keychain with device-only accessibility, and survive until a panic wipe occurs.
- Separation of concerns: The Noise key handles encryption and session establishment, while the Ed25519 key handles message authenticity and trust establishment through signed vouch payloads.
Frequently Asked Questions
What cryptographic curves does BitChat use for its key pairs?
BitChat uses X25519 (Curve25519) for the Noise static key pair and Ed25519 for the signing key pair. X25519 provides the elliptic-curve Diffie-Hellman operations required for the Noise Protocol Framework's XX handshake pattern, while Ed25519 provides high-speed, high-security Edwards-curve Digital Signature Algorithm (EdDSA) operations for identity verification.
How is the BitChat peer ID generated from the cryptographic key pairs?
The peer ID is derived exclusively from the Noise static public key. According to bitchat/Docs/PEER-ID-ROTATION.md, the protocol calculates SHA-256(noiseStaticPublicKey) and extracts the first 8 bytes (64 bits) to form the canonical peer identifier displayed in the UI and used in packet headers. This derivation remains stable for the lifetime of the installation unless the user performs a key rotation or reinstalls the application.
Where are the private keys stored, and can they be backed up to iCloud?
Both private keys are stored in the iOS Secure Enclave via the Keychain with the accessibility level kSecAttrAccessibleWhenUnlockedThisDeviceOnly. This setting explicitly prevents the keys from being included in iCloud backups or transferred to a new device during migration. The keys remain strictly bound to the specific device that generated them, ensuring that compromise of cloud storage does not expose the cryptographic identity.
Why does BitChat use two separate cryptographic key pairs instead of a single multipurpose key?
The dual-key architecture enforces cryptographic separation of duties. The Noise X25519 key is ephemeral in nature (though static in BitChat's implementation) and optimized for ECDH key agreement, while the Ed25519 key is optimized for digital signatures and long-term identity attestation. Separation prevents cryptographic confusion attacks and allows the signing key to be rotated or re-generated independently of the transport key if compromised, though BitChat currently treats both as persistent installation identifiers for TOFU (Trust On First Use) consistency.
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 →