BRING_THE_NOISE.md
BitChat implements the Noise Protocol Framework for end-to-end encryption, providing forward secrecy, identity hiding, and cryptographic authentication. This document details our Swift implementation and its integration with BitChat's decentralized mesh network.
The Noise Protocol Framework offers:
BitChat uses the Noise XX pattern:
XX:
-> e
<- e, ee, s, es
-> s, se
This three-message pattern provides:
The main service managing all Noise operations:
final class NoiseEncryptionService {
private let staticIdentityKey: Curve25519.KeyAgreement.PrivateKey
private let sessionManager: NoiseSessionManager
private let channelEncryption = NoiseChannelEncryption()
}
Individual session state for each peer:
final class NoiseSession {
private var handshakeState: NoiseHandshakeState?
private var sendCipher: NoiseCipherState?
private var receiveCipher: NoiseCipherState?
private let remoteStaticKey: Curve25519.KeyAgreement.PublicKey?
}
Thread-safe session management:
final class NoiseSessionManager {
private var sessions: [String: NoiseSession] = [:]
private let sessionsQueue = DispatchQueue(label: "noise.sessions", attributes: .concurrent)
}
Initiator sends ephemeral key
let ephemeralKey = Curve25519.KeyAgreement.PrivateKey()
let message = ephemeralKey.publicKey.rawRepresentation
Responder sends ephemeral + encrypted static
// Generate ephemeral, perform DH, encrypt static key
let encryptedStatic = encrypt(staticKey, using: sharedSecret)
Initiator sends encrypted static
// Complete handshake, derive session keys
let (sendKey, recvKey) = deriveSessionKeys(transcript)
Sessions are managed with automatic cleanup and rekey support:
// Session lookup by peer ID
func getSession(for peerID: String) -> NoiseSession?
// Automatic session removal on disconnect
func removeSession(for peerID: String)
// Rekey detection
func getSessionsNeedingRekey() -> [(String, Bool)]
Noise sessions persist across peer ID rotations through fingerprint mapping:
// Identity announcement after handshake
struct NoiseIdentityAnnouncement {
let peerID: String
let publicKey: Data
let nickname: String
let previousPeerID: String?
let signature: Data
}
All messages are encrypted using established Noise sessions:
// Encrypt message
let encrypted = try noiseService.encrypt(messageData, for: peerID)
// Decrypt message
let decrypted = try noiseService.decrypt(encryptedData, from: peerID)
enum NoiseError: Error {
case handshakeFailed
case invalidMessage
case sessionNotEstablished
case decryptionFailed
}
BitChat implements protocol version negotiation to ensure compatibility between different client versions:
case versionHello = 0x20 // Announce supported versions
case versionAck = 0x21 // Acknowledge and agree on version
ProtocolVersion.supportedVersionsBitChat's Noise implementation provides encryption while maintaining the simplicity and performance required for a peer-to-peer messaging application. The protocol's elegant design ensures that people's communications remain private, authenticated, and forward-secure without sacrificing usability.