mirror of
https://github.com/permissionlesstech/bitchat.git
synced 2026-07-25 22:05:21 +00:00
Add comprehensive AI-friendly documentation across core files (#328)
- Created AI_CONTEXT.md as central documentation hub for AI assistants - Added detailed file-level documentation to all major components - Documented architecture, design decisions, and security considerations - Added usage examples and integration guidance - Improved code discoverability with clear component descriptions Documentation covers: - BluetoothMeshService: Core networking and mesh protocol - BitchatProtocol: Application-layer protocol design - NoiseProtocol: Cryptographic implementation details - ChatViewModel: Business logic and state management - IdentityModels: Three-layer identity architecture - NoiseEncryptionService: High-level encryption API - SecureIdentityStateManager: Secure persistence layer - BinaryProtocol: Low-level wire format This documentation will significantly improve AI understanding of the codebase structure and enable faster, more accurate assistance with development tasks. Co-authored-by: jack <jackjackbits@users.noreply.github.com>
This commit is contained in:
@@ -6,11 +6,86 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # IdentityModels
|
||||
///
|
||||
/// Defines BitChat's innovative three-layer identity model that balances
|
||||
/// privacy, security, and usability in a decentralized mesh network.
|
||||
///
|
||||
/// ## Overview
|
||||
/// BitChat's identity system separates concerns across three distinct layers:
|
||||
/// 1. **Ephemeral Identity**: Short-lived, rotatable peer IDs for privacy
|
||||
/// 2. **Cryptographic Identity**: Long-term Noise static keys for security
|
||||
/// 3. **Social Identity**: User-assigned names and trust relationships
|
||||
///
|
||||
/// This separation allows users to maintain stable cryptographic identities
|
||||
/// while frequently rotating their network identifiers for privacy.
|
||||
///
|
||||
/// ## Three-Layer Architecture
|
||||
///
|
||||
/// ### Layer 1: Ephemeral Identity
|
||||
/// - Random 8-byte peer IDs that rotate periodically
|
||||
/// - Provides network-level privacy and prevents tracking
|
||||
/// - Changes don't affect cryptographic relationships
|
||||
/// - Includes handshake state tracking
|
||||
///
|
||||
/// ### Layer 2: Cryptographic Identity
|
||||
/// - Based on Noise Protocol static key pairs
|
||||
/// - Fingerprint derived from SHA256 of public key
|
||||
/// - Enables end-to-end encryption and authentication
|
||||
/// - Persists across peer ID rotations
|
||||
///
|
||||
/// ### Layer 3: Social Identity
|
||||
/// - User-assigned names (petnames) for contacts
|
||||
/// - Trust levels from unknown to verified
|
||||
/// - Favorite/blocked status
|
||||
/// - Personal notes and metadata
|
||||
///
|
||||
/// ## Privacy Design
|
||||
/// The model is designed with privacy-first principles:
|
||||
/// - No mandatory persistent storage
|
||||
/// - Optional identity caching with user consent
|
||||
/// - Ephemeral IDs prevent long-term tracking
|
||||
/// - Social mappings stored locally only
|
||||
///
|
||||
/// ## Trust Model
|
||||
/// Four levels of trust:
|
||||
/// 1. **Unknown**: New or unverified peers
|
||||
/// 2. **Casual**: Basic interaction history
|
||||
/// 3. **Trusted**: User has explicitly trusted
|
||||
/// 4. **Verified**: Cryptographic verification completed
|
||||
///
|
||||
/// ## Identity Resolution
|
||||
/// When a peer rotates their ephemeral ID:
|
||||
/// 1. Cryptographic handshake reveals their fingerprint
|
||||
/// 2. System looks up social identity by fingerprint
|
||||
/// 3. UI seamlessly maintains user relationships
|
||||
/// 4. Historical messages remain properly attributed
|
||||
///
|
||||
/// ## Conflict Resolution
|
||||
/// Handles edge cases like:
|
||||
/// - Multiple peers claiming same nickname
|
||||
/// - Nickname changes and conflicts
|
||||
/// - Identity rotation during active chats
|
||||
/// - Network partitions and rejoins
|
||||
///
|
||||
/// ## Usage Example
|
||||
/// ```swift
|
||||
/// // When peer connects with new ID
|
||||
/// let ephemeral = EphemeralIdentity(peerID: "abc123", ...)
|
||||
/// // After handshake
|
||||
/// let crypto = CryptographicIdentity(fingerprint: "sha256...", ...)
|
||||
/// // User assigns name
|
||||
/// let social = SocialIdentity(localPetname: "Alice", ...)
|
||||
/// ```
|
||||
///
|
||||
|
||||
import Foundation
|
||||
|
||||
// MARK: - Three-Layer Identity Model
|
||||
|
||||
// Layer 1: Ephemeral (per-session)
|
||||
/// Represents the ephemeral layer of identity - short-lived peer IDs that provide network privacy.
|
||||
/// These IDs rotate periodically to prevent tracking while maintaining cryptographic relationships.
|
||||
struct EphemeralIdentity {
|
||||
let peerID: String // 8 random bytes
|
||||
let sessionStart: Date
|
||||
@@ -25,7 +100,9 @@ enum HandshakeState {
|
||||
case failed(reason: String)
|
||||
}
|
||||
|
||||
// Layer 2: Cryptographic (persistent)
|
||||
/// Represents the cryptographic layer of identity - the stable Noise Protocol static key pair.
|
||||
/// This identity persists across ephemeral ID rotations and enables secure communication.
|
||||
/// The fingerprint serves as the permanent identifier for a peer's cryptographic identity.
|
||||
struct CryptographicIdentity: Codable {
|
||||
let fingerprint: String // SHA256 of public key
|
||||
let publicKey: Data // Noise static public key
|
||||
@@ -33,7 +110,9 @@ struct CryptographicIdentity: Codable {
|
||||
let lastHandshake: Date?
|
||||
}
|
||||
|
||||
// Layer 3: Social (user-assigned)
|
||||
/// Represents the social layer of identity - user-assigned names and trust relationships.
|
||||
/// This layer provides human-friendly identification and relationship management.
|
||||
/// All data in this layer is local-only and never transmitted over the network.
|
||||
struct SocialIdentity: Codable {
|
||||
let fingerprint: String
|
||||
var localPetname: String? // User's name for this peer
|
||||
@@ -53,6 +132,9 @@ enum TrustLevel: String, Codable {
|
||||
|
||||
// MARK: - Identity Cache
|
||||
|
||||
/// Persistent storage for identity mappings and relationships.
|
||||
/// Provides efficient lookup between fingerprints, nicknames, and social identities.
|
||||
/// Storage is optional and controlled by user privacy settings.
|
||||
struct IdentityCache: Codable {
|
||||
// Fingerprint -> Social mapping
|
||||
var socialIdentities: [String: SocialIdentity] = [:]
|
||||
@@ -105,6 +187,9 @@ struct PrivacySettings: Codable {
|
||||
|
||||
// MARK: - Conflict Resolution
|
||||
|
||||
/// Strategies for resolving identity conflicts in the decentralized network.
|
||||
/// Handles cases where multiple peers claim the same nickname or when
|
||||
/// identity mappings become ambiguous due to network partitions.
|
||||
enum ConflictResolution {
|
||||
case acceptNew(petname: String) // "John (2)"
|
||||
case rejectNew
|
||||
|
||||
@@ -6,9 +6,96 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # SecureIdentityStateManager
|
||||
///
|
||||
/// Manages the persistent storage and retrieval of identity mappings with
|
||||
/// encryption at rest. This singleton service maintains the relationship between
|
||||
/// ephemeral peer IDs, cryptographic fingerprints, and social identities.
|
||||
///
|
||||
/// ## Overview
|
||||
/// The SecureIdentityStateManager provides a secure, privacy-preserving way to
|
||||
/// maintain identity relationships across app launches. It implements:
|
||||
/// - Encrypted storage of identity mappings
|
||||
/// - In-memory caching for performance
|
||||
/// - Thread-safe access patterns
|
||||
/// - Automatic debounced persistence
|
||||
///
|
||||
/// ## Architecture
|
||||
/// The manager operates at three levels:
|
||||
/// 1. **In-Memory State**: Fast access to active identities
|
||||
/// 2. **Encrypted Cache**: Persistent storage in Keychain
|
||||
/// 3. **Privacy Controls**: User-configurable persistence settings
|
||||
///
|
||||
/// ## Security Features
|
||||
///
|
||||
/// ### Encryption at Rest
|
||||
/// - Identity cache encrypted with AES-GCM
|
||||
/// - Unique 256-bit encryption key per device
|
||||
/// - Key stored separately in Keychain
|
||||
/// - No plaintext identity data on disk
|
||||
///
|
||||
/// ### Privacy by Design
|
||||
/// - Persistence is optional (user-controlled)
|
||||
/// - Minimal data retention
|
||||
/// - No cloud sync or backup
|
||||
/// - Automatic cleanup of stale entries
|
||||
///
|
||||
/// ### Thread Safety
|
||||
/// - Concurrent read access via GCD barriers
|
||||
/// - Write operations serialized
|
||||
/// - Atomic state updates
|
||||
/// - No data races or corruption
|
||||
///
|
||||
/// ## Data Model
|
||||
/// Manages three types of identity data:
|
||||
/// 1. **Ephemeral Sessions**: Current peer connections
|
||||
/// 2. **Cryptographic Identities**: Public keys and fingerprints
|
||||
/// 3. **Social Identities**: User-assigned names and trust
|
||||
///
|
||||
/// ## Persistence Strategy
|
||||
/// - Changes batched and debounced (2-second window)
|
||||
/// - Automatic save on app termination
|
||||
/// - Crash-resistant with atomic writes
|
||||
/// - Migration support for schema changes
|
||||
///
|
||||
/// ## Usage Patterns
|
||||
/// ```swift
|
||||
/// // Register a new peer identity
|
||||
/// manager.registerPeerIdentity(peerID, publicKey, fingerprint)
|
||||
///
|
||||
/// // Update social identity
|
||||
/// manager.updateSocialIdentity(fingerprint, nickname, trustLevel)
|
||||
///
|
||||
/// // Query identity
|
||||
/// let identity = manager.resolvePeerIdentity(peerID)
|
||||
/// ```
|
||||
///
|
||||
/// ## Performance Optimizations
|
||||
/// - In-memory cache eliminates Keychain roundtrips
|
||||
/// - Debounced saves reduce I/O operations
|
||||
/// - Efficient data structures for lookups
|
||||
/// - Background queue for expensive operations
|
||||
///
|
||||
/// ## Privacy Considerations
|
||||
/// - Users can disable all persistence
|
||||
/// - Identity cache can be wiped instantly
|
||||
/// - No analytics or telemetry
|
||||
/// - Ephemeral mode for high-risk users
|
||||
///
|
||||
/// ## Future Enhancements
|
||||
/// - Selective identity export
|
||||
/// - Cross-device identity sync (optional)
|
||||
/// - Identity attestation support
|
||||
/// - Advanced conflict resolution
|
||||
///
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
|
||||
/// Singleton manager for secure identity state persistence and retrieval.
|
||||
/// Provides thread-safe access to identity mappings with encryption at rest.
|
||||
/// All identity data is stored encrypted in the device Keychain for security.
|
||||
class SecureIdentityStateManager {
|
||||
static let shared = SecureIdentityStateManager()
|
||||
|
||||
|
||||
@@ -6,6 +6,77 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # NoiseProtocol
|
||||
///
|
||||
/// A complete implementation of the Noise Protocol Framework for end-to-end
|
||||
/// encryption in BitChat. This file contains the core cryptographic primitives
|
||||
/// and handshake logic that enable secure communication between peers.
|
||||
///
|
||||
/// ## Overview
|
||||
/// The Noise Protocol Framework is a modern cryptographic framework designed
|
||||
/// for building secure protocols. BitChat uses Noise to provide:
|
||||
/// - Mutual authentication between peers
|
||||
/// - Forward secrecy for all messages
|
||||
/// - Protection against replay attacks
|
||||
/// - Minimal round trips for connection establishment
|
||||
///
|
||||
/// ## Implementation Details
|
||||
/// This implementation follows the Noise specification exactly, using:
|
||||
/// - **Pattern**: XX (most versatile, provides mutual authentication)
|
||||
/// - **DH**: Curve25519 (X25519 key exchange)
|
||||
/// - **Cipher**: ChaCha20-Poly1305 (AEAD encryption)
|
||||
/// - **Hash**: SHA-256 (for key derivation and authentication)
|
||||
///
|
||||
/// ## Security Properties
|
||||
/// The XX handshake pattern provides:
|
||||
/// 1. **Identity Hiding**: Both parties' identities are encrypted
|
||||
/// 2. **Forward Secrecy**: Past sessions remain secure if keys are compromised
|
||||
/// 3. **Key Compromise Impersonation Resistance**: Compromised static key doesn't allow impersonation to that party
|
||||
/// 4. **Mutual Authentication**: Both parties verify each other's identity
|
||||
///
|
||||
/// ## Handshake Flow (XX Pattern)
|
||||
/// ```
|
||||
/// Initiator Responder
|
||||
/// --------- ---------
|
||||
/// -> e (ephemeral key)
|
||||
/// <- e, ee, s, es (ephemeral, DH, static encrypted, DH)
|
||||
/// -> s, se (static encrypted, DH)
|
||||
/// ```
|
||||
///
|
||||
/// ## Key Components
|
||||
/// - **NoiseCipherState**: Manages symmetric encryption with nonce tracking
|
||||
/// - **NoiseSymmetricState**: Handles key derivation and handshake hashing
|
||||
/// - **NoiseHandshakeState**: Orchestrates the complete handshake process
|
||||
///
|
||||
/// ## Replay Protection
|
||||
/// Implements sliding window replay protection to prevent message replay attacks:
|
||||
/// - Tracks nonces within a 1024-message window
|
||||
/// - Rejects duplicate or too-old nonces
|
||||
/// - Handles out-of-order message delivery
|
||||
///
|
||||
/// ## Usage Example
|
||||
/// ```swift
|
||||
/// let handshake = NoiseHandshakeState(
|
||||
/// pattern: .XX,
|
||||
/// role: .initiator,
|
||||
/// localStatic: staticKeyPair
|
||||
/// )
|
||||
/// let messageBuffer = handshake.writeMessage(payload: Data())
|
||||
/// // Send messageBuffer to peer...
|
||||
/// ```
|
||||
///
|
||||
/// ## Security Considerations
|
||||
/// - Static keys must be generated using secure random sources
|
||||
/// - Keys should be stored securely (e.g., in Keychain)
|
||||
/// - Handshake state must not be reused after completion
|
||||
/// - Transport messages have a nonce limit (2^64-1)
|
||||
///
|
||||
/// ## References
|
||||
/// - Noise Protocol Framework: http://www.noiseprotocol.org/
|
||||
/// - Noise Specification: http://www.noiseprotocol.org/noise.html
|
||||
///
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
import os.log
|
||||
@@ -15,6 +86,8 @@ import os.log
|
||||
|
||||
// MARK: - Constants and Types
|
||||
|
||||
/// Supported Noise handshake patterns.
|
||||
/// Each pattern provides different security properties and authentication guarantees.
|
||||
enum NoisePattern {
|
||||
case XX // Most versatile, mutual authentication
|
||||
case IK // Initiator knows responder's static key
|
||||
@@ -50,6 +123,10 @@ struct NoiseProtocolName {
|
||||
|
||||
// MARK: - Cipher State
|
||||
|
||||
/// Manages symmetric encryption state for Noise protocol sessions.
|
||||
/// Handles ChaCha20-Poly1305 AEAD encryption with automatic nonce management
|
||||
/// and replay protection using a sliding window algorithm.
|
||||
/// - Warning: Nonce reuse would be catastrophic for security
|
||||
class NoiseCipherState {
|
||||
// Constants for replay protection
|
||||
private static let NONCE_SIZE_BYTES = 4
|
||||
@@ -284,6 +361,10 @@ class NoiseCipherState {
|
||||
|
||||
// MARK: - Symmetric State
|
||||
|
||||
/// Manages the symmetric cryptographic state during Noise handshakes.
|
||||
/// Responsible for key derivation, protocol name hashing, and maintaining
|
||||
/// the chaining key that provides key separation between handshake messages.
|
||||
/// - Note: This class implements the SymmetricState object from the Noise spec
|
||||
class NoiseSymmetricState {
|
||||
private var cipherState: NoiseCipherState
|
||||
private var chainingKey: Data
|
||||
@@ -384,6 +465,10 @@ class NoiseSymmetricState {
|
||||
|
||||
// MARK: - Handshake State
|
||||
|
||||
/// Orchestrates the complete Noise handshake process.
|
||||
/// This is the main interface for establishing encrypted sessions between peers.
|
||||
/// Manages the handshake state machine, message patterns, and key derivation.
|
||||
/// - Important: Each handshake instance should only be used once
|
||||
class NoiseHandshakeState {
|
||||
private let role: NoiseRole
|
||||
private let pattern: NoisePattern
|
||||
|
||||
@@ -6,6 +6,88 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # BinaryProtocol
|
||||
///
|
||||
/// Low-level binary encoding and decoding for BitChat protocol messages.
|
||||
/// Optimized for Bluetooth LE's limited bandwidth and MTU constraints.
|
||||
///
|
||||
/// ## Overview
|
||||
/// BinaryProtocol implements an efficient binary wire format that minimizes
|
||||
/// overhead while maintaining extensibility. It handles:
|
||||
/// - Compact binary encoding with fixed headers
|
||||
/// - Optional field support via flags
|
||||
/// - Automatic compression for large payloads
|
||||
/// - Endianness handling for cross-platform compatibility
|
||||
///
|
||||
/// ## Wire Format
|
||||
/// ```
|
||||
/// Header (Fixed 13 bytes):
|
||||
/// +--------+------+-----+-----------+-------+----------------+
|
||||
/// |Version | Type | TTL | Timestamp | Flags | PayloadLength |
|
||||
/// |1 byte |1 byte|1byte| 8 bytes | 1 byte| 2 bytes |
|
||||
/// +--------+------+-----+-----------+-------+----------------+
|
||||
///
|
||||
/// Variable sections:
|
||||
/// +----------+-------------+---------+------------+
|
||||
/// | SenderID | RecipientID | Payload | Signature |
|
||||
/// | 8 bytes | 8 bytes* | Variable| 64 bytes* |
|
||||
/// +----------+-------------+---------+------------+
|
||||
/// * Optional fields based on flags
|
||||
/// ```
|
||||
///
|
||||
/// ## Design Rationale
|
||||
/// The protocol is designed for:
|
||||
/// - **Efficiency**: Minimal overhead for small messages
|
||||
/// - **Flexibility**: Optional fields via flag bits
|
||||
/// - **Compatibility**: Network byte order (big-endian)
|
||||
/// - **Performance**: Zero-copy where possible
|
||||
///
|
||||
/// ## Compression Strategy
|
||||
/// - Automatic compression for payloads > 256 bytes
|
||||
/// - LZ4 algorithm for speed over ratio
|
||||
/// - Original size stored for decompression
|
||||
/// - Flag bit indicates compressed payload
|
||||
///
|
||||
/// ## Flag Bits
|
||||
/// - Bit 0: Has recipient ID (directed message)
|
||||
/// - Bit 1: Has signature (authenticated message)
|
||||
/// - Bit 2: Is compressed (LZ4 compression applied)
|
||||
/// - Bits 3-7: Reserved for future use
|
||||
///
|
||||
/// ## Size Constraints
|
||||
/// - Maximum packet size: 65,535 bytes (16-bit length field)
|
||||
/// - Typical packet size: < 512 bytes (BLE MTU)
|
||||
/// - Minimum packet size: 21 bytes (header + sender ID)
|
||||
///
|
||||
/// ## Encoding Process
|
||||
/// 1. Construct header with fixed fields
|
||||
/// 2. Set appropriate flags
|
||||
/// 3. Compress payload if beneficial
|
||||
/// 4. Append variable-length fields
|
||||
/// 5. Calculate and append signature if needed
|
||||
///
|
||||
/// ## Decoding Process
|
||||
/// 1. Validate minimum packet size
|
||||
/// 2. Parse fixed header
|
||||
/// 3. Extract flags and determine field presence
|
||||
/// 4. Parse variable fields based on flags
|
||||
/// 5. Decompress payload if compressed
|
||||
/// 6. Verify signature if present
|
||||
///
|
||||
/// ## Error Handling
|
||||
/// - Graceful handling of malformed packets
|
||||
/// - Clear error messages for debugging
|
||||
/// - No crashes on invalid input
|
||||
/// - Logging of protocol violations
|
||||
///
|
||||
/// ## Performance Notes
|
||||
/// - Allocation-free for small messages
|
||||
/// - Streaming support for large payloads
|
||||
/// - Efficient bit manipulation
|
||||
/// - Platform-optimized byte swapping
|
||||
///
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Data {
|
||||
@@ -18,21 +100,10 @@ extension Data {
|
||||
}
|
||||
}
|
||||
|
||||
// Binary Protocol Format:
|
||||
// Header (Fixed 13 bytes):
|
||||
// - Version: 1 byte
|
||||
// - Type: 1 byte
|
||||
// - TTL: 1 byte
|
||||
// - Timestamp: 8 bytes (UInt64)
|
||||
// - Flags: 1 byte (bit 0: hasRecipient, bit 1: hasSignature)
|
||||
// - PayloadLength: 2 bytes (UInt16)
|
||||
//
|
||||
// Variable sections:
|
||||
// - SenderID: 8 bytes (fixed)
|
||||
// - RecipientID: 8 bytes (if hasRecipient flag set)
|
||||
// - Payload: Variable length
|
||||
// - Signature: 64 bytes (if hasSignature flag set)
|
||||
|
||||
/// Implements binary encoding and decoding for BitChat protocol messages.
|
||||
/// Provides static methods for converting between BitchatPacket objects and
|
||||
/// their binary wire format representation.
|
||||
/// - Note: All multi-byte values use network byte order (big-endian)
|
||||
struct BinaryProtocol {
|
||||
static let headerSize = 13
|
||||
static let senderIDSize = 8
|
||||
|
||||
@@ -6,12 +6,65 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # BitchatProtocol
|
||||
///
|
||||
/// Defines the application-layer protocol for BitChat mesh networking, including
|
||||
/// message types, packet structures, and encoding/decoding logic.
|
||||
///
|
||||
/// ## Overview
|
||||
/// BitchatProtocol implements a binary protocol optimized for Bluetooth LE's
|
||||
/// constrained bandwidth and MTU limitations. It provides:
|
||||
/// - Efficient binary message encoding
|
||||
/// - Message fragmentation for large payloads
|
||||
/// - TTL-based routing for mesh networks
|
||||
/// - Privacy features like padding and timing obfuscation
|
||||
/// - Integration points for end-to-end encryption
|
||||
///
|
||||
/// ## Protocol Design
|
||||
/// The protocol uses a compact binary format to minimize overhead:
|
||||
/// - 1-byte message type identifier
|
||||
/// - Variable-length fields with length prefixes
|
||||
/// - Network byte order (big-endian) for multi-byte values
|
||||
/// - PKCS#7-style padding for privacy
|
||||
///
|
||||
/// ## Message Flow
|
||||
/// 1. **Creation**: Messages are created with type, content, and metadata
|
||||
/// 2. **Encoding**: Converted to binary format with proper field ordering
|
||||
/// 3. **Fragmentation**: Split if larger than BLE MTU (512 bytes)
|
||||
/// 4. **Transmission**: Sent via BluetoothMeshService
|
||||
/// 5. **Routing**: Relayed by intermediate nodes (TTL decrements)
|
||||
/// 6. **Reassembly**: Fragments collected and reassembled
|
||||
/// 7. **Decoding**: Binary data parsed back to message objects
|
||||
///
|
||||
/// ## Security Considerations
|
||||
/// - Message padding obscures actual content length
|
||||
/// - Timing obfuscation prevents traffic analysis
|
||||
/// - Integration with Noise Protocol for E2E encryption
|
||||
/// - No persistent identifiers in protocol headers
|
||||
///
|
||||
/// ## Message Types
|
||||
/// - **Announce/Leave**: Peer presence notifications
|
||||
/// - **Message**: User chat messages (broadcast or directed)
|
||||
/// - **Fragment**: Multi-part message handling
|
||||
/// - **Delivery/Read**: Message acknowledgments
|
||||
/// - **Noise**: Encrypted channel establishment
|
||||
/// - **Version**: Protocol compatibility negotiation
|
||||
///
|
||||
/// ## Future Extensions
|
||||
/// The protocol is designed to be extensible:
|
||||
/// - Reserved message type ranges for future use
|
||||
/// - Version negotiation for backward compatibility
|
||||
/// - Optional fields for new features
|
||||
///
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
|
||||
// MARK: - Message Padding
|
||||
|
||||
// Privacy-preserving padding utilities
|
||||
/// Provides privacy-preserving message padding to obscure actual content length.
|
||||
/// Uses PKCS#7-style padding with random bytes to prevent traffic analysis.
|
||||
struct MessagePadding {
|
||||
// Standard block sizes for padding
|
||||
static let blockSizes = [256, 512, 1024, 2048]
|
||||
@@ -79,6 +132,9 @@ struct MessagePadding {
|
||||
|
||||
// MARK: - Message Types
|
||||
|
||||
/// Defines all message types in the BitChat protocol.
|
||||
/// Each type has a unique identifier for efficient binary encoding.
|
||||
/// Types are grouped by function: user messages, protocol control, encryption, etc.
|
||||
enum MessageType: UInt8 {
|
||||
case announce = 0x01
|
||||
case leave = 0x03
|
||||
@@ -144,13 +200,19 @@ enum LazyHandshakeState {
|
||||
|
||||
// MARK: - Special Recipients
|
||||
|
||||
// Special recipient ID for broadcast messages
|
||||
/// Defines special recipient identifiers used in the protocol.
|
||||
/// These magic values indicate broadcast or system-level recipients
|
||||
/// rather than specific peer IDs.
|
||||
struct SpecialRecipients {
|
||||
static let broadcast = Data(repeating: 0xFF, count: 8) // All 0xFF = broadcast
|
||||
}
|
||||
|
||||
// MARK: - Core Protocol Structures
|
||||
|
||||
/// The core packet structure for all BitChat protocol messages.
|
||||
/// Encapsulates all data needed for routing through the mesh network,
|
||||
/// including TTL for hop limiting and optional encryption.
|
||||
/// - Note: Packets larger than BLE MTU (512 bytes) are automatically fragmented
|
||||
struct BitchatPacket: Codable {
|
||||
let version: UInt8
|
||||
let type: UInt8
|
||||
@@ -209,7 +271,9 @@ struct BitchatPacket: Codable {
|
||||
|
||||
// MARK: - Delivery Acknowledgments
|
||||
|
||||
// Delivery acknowledgment structure
|
||||
/// Acknowledgment sent when a message is successfully delivered to a recipient.
|
||||
/// Provides delivery confirmation for reliable messaging and UI feedback.
|
||||
/// - Note: Only sent for direct messages, not broadcasts
|
||||
struct DeliveryAck: Codable {
|
||||
let originalMessageID: String
|
||||
let ackID: String
|
||||
@@ -656,7 +720,10 @@ struct ProtocolNack: Codable {
|
||||
|
||||
// MARK: - Peer Identity Rotation
|
||||
|
||||
// Enhanced identity announcement with rotation support
|
||||
/// Announces a peer's cryptographic identity to enable secure communication.
|
||||
/// Contains the peer's Noise static public key and supports identity rotation
|
||||
/// by binding ephemeral peer IDs to stable cryptographic fingerprints.
|
||||
/// - Note: Critical for establishing end-to-end encrypted channels
|
||||
struct NoiseIdentityAnnouncement: Codable {
|
||||
let peerID: String // Current ephemeral peer ID
|
||||
let publicKey: Data // Noise static public key
|
||||
@@ -1078,6 +1145,10 @@ enum DeliveryStatus: Codable, Equatable {
|
||||
|
||||
// MARK: - Message Model
|
||||
|
||||
/// Represents a user-visible message in the BitChat system.
|
||||
/// Handles both broadcast messages and private encrypted messages,
|
||||
/// with support for mentions, replies, and delivery tracking.
|
||||
/// - Note: This is the primary data model for chat messages
|
||||
class BitchatMessage: Codable {
|
||||
let id: String
|
||||
let sender: String
|
||||
|
||||
@@ -6,6 +6,76 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # BluetoothMeshService
|
||||
///
|
||||
/// The core networking component that manages peer-to-peer Bluetooth LE connections
|
||||
/// and implements the BitChat mesh networking protocol.
|
||||
///
|
||||
/// ## Overview
|
||||
/// This service is the heart of BitChat's decentralized architecture. It manages all
|
||||
/// Bluetooth LE communications, enabling devices to form an ad-hoc mesh network without
|
||||
/// any infrastructure. The service handles:
|
||||
/// - Peer discovery and connection management
|
||||
/// - Message routing and relay functionality
|
||||
/// - Protocol version negotiation
|
||||
/// - Connection state tracking and recovery
|
||||
/// - Integration with the Noise encryption layer
|
||||
///
|
||||
/// ## Architecture
|
||||
/// The service operates in a dual mode:
|
||||
/// - **Central Mode**: Scans for and connects to other BitChat devices
|
||||
/// - **Peripheral Mode**: Advertises its presence and accepts connections
|
||||
///
|
||||
/// This dual-mode operation enables true peer-to-peer connectivity where any device
|
||||
/// can initiate or accept connections, forming a resilient mesh topology.
|
||||
///
|
||||
/// ## Mesh Networking
|
||||
/// Messages are relayed through the mesh using a TTL (Time To Live) mechanism:
|
||||
/// - Each message has a TTL that decrements at each hop
|
||||
/// - Messages are cached to prevent loops (via Bloom filters)
|
||||
/// - Store-and-forward ensures delivery to temporarily offline peers
|
||||
///
|
||||
/// ## Connection Lifecycle
|
||||
/// 1. **Discovery**: Devices scan and advertise simultaneously
|
||||
/// 2. **Connection**: BLE connection established
|
||||
/// 3. **Version Negotiation**: Ensure protocol compatibility
|
||||
/// 4. **Authentication**: Noise handshake for encrypted channels
|
||||
/// 5. **Message Exchange**: Bidirectional communication
|
||||
/// 6. **Disconnection**: Graceful cleanup and state preservation
|
||||
///
|
||||
/// ## Security Integration
|
||||
/// - Coordinates with NoiseEncryptionService for private messages
|
||||
/// - Maintains peer identity mappings
|
||||
/// - Handles lazy handshake initiation
|
||||
/// - Ensures message authenticity
|
||||
///
|
||||
/// ## Performance Optimizations
|
||||
/// - Connection pooling and reuse
|
||||
/// - Adaptive scanning based on battery level
|
||||
/// - Message batching for efficiency
|
||||
/// - Smart retry logic with exponential backoff
|
||||
///
|
||||
/// ## Thread Safety
|
||||
/// All public methods are thread-safe. The service uses:
|
||||
/// - Serial queues for Core Bluetooth operations
|
||||
/// - Thread-safe collections for peer management
|
||||
/// - Atomic operations for state updates
|
||||
///
|
||||
/// ## Error Handling
|
||||
/// - Automatic reconnection for lost connections
|
||||
/// - Graceful degradation when Bluetooth is unavailable
|
||||
/// - Clear error reporting through BitchatDelegate
|
||||
///
|
||||
/// ## Usage Example
|
||||
/// ```swift
|
||||
/// let meshService = BluetoothMeshService()
|
||||
/// meshService.delegate = self
|
||||
/// meshService.localUserID = "user123"
|
||||
/// meshService.startMeshService()
|
||||
/// ```
|
||||
///
|
||||
|
||||
import Foundation
|
||||
import CoreBluetooth
|
||||
import Combine
|
||||
@@ -64,6 +134,10 @@ enum PeerConnectionState: CustomStringConvertible {
|
||||
}
|
||||
}
|
||||
|
||||
/// Manages all Bluetooth LE networking operations for the BitChat mesh network.
|
||||
/// This class handles peer discovery, connection management, message routing,
|
||||
/// and protocol negotiation. It acts as both a BLE central (scanner) and
|
||||
/// peripheral (advertiser) simultaneously to enable true peer-to-peer connectivity.
|
||||
class BluetoothMeshService: NSObject {
|
||||
// MARK: - Constants
|
||||
|
||||
@@ -712,7 +786,10 @@ class BluetoothMeshService: NSObject {
|
||||
|
||||
// MARK: - Peer Identity Mapping
|
||||
|
||||
// Get peer's fingerprint (replaces getPeerPublicKey)
|
||||
/// Retrieves the cryptographic fingerprint for a given peer.
|
||||
/// - Parameter peerID: The ephemeral peer ID
|
||||
/// - Returns: The peer's Noise static key fingerprint if known, nil otherwise
|
||||
/// - Note: This fingerprint remains stable across peer ID rotations
|
||||
func getPeerFingerprint(_ peerID: String) -> String? {
|
||||
return noiseService.getPeerFingerprint(peerID)
|
||||
}
|
||||
@@ -724,7 +801,10 @@ class BluetoothMeshService: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a peer ID belongs to us (current or previous)
|
||||
/// Checks if a given peer ID belongs to the local device.
|
||||
/// - Parameter peerID: The peer ID to check
|
||||
/// - Returns: true if this is our current or recent peer ID, false otherwise
|
||||
/// - Note: Accounts for grace period during peer ID rotation
|
||||
func isPeerIDOurs(_ peerID: String) -> Bool {
|
||||
if peerID == myPeerID {
|
||||
return true
|
||||
@@ -741,7 +821,12 @@ class BluetoothMeshService: NSObject {
|
||||
return false
|
||||
}
|
||||
|
||||
// Update peer identity binding when receiving announcements
|
||||
/// Updates the identity binding for a peer when they rotate their ephemeral ID.
|
||||
/// - Parameters:
|
||||
/// - newPeerID: The peer's new ephemeral ID
|
||||
/// - fingerprint: The peer's stable cryptographic fingerprint
|
||||
/// - binding: The complete identity binding information
|
||||
/// - Note: This maintains continuity of identity across peer ID rotations
|
||||
func updatePeerBinding(_ newPeerID: String, fingerprint: String, binding: PeerIdentityBinding) {
|
||||
// Use async to ensure we're not blocking during view updates
|
||||
collectionsQueue.async(flags: .barrier) { [weak self] in
|
||||
@@ -1246,6 +1331,10 @@ class BluetoothMeshService: NSObject {
|
||||
|
||||
// MARK: - Service Management
|
||||
|
||||
/// Starts the Bluetooth mesh networking services.
|
||||
/// This initializes both central (scanning) and peripheral (advertising) modes,
|
||||
/// enabling the device to both discover peers and be discovered.
|
||||
/// Call this method after setting the delegate and localUserID.
|
||||
func startServices() {
|
||||
// Starting services
|
||||
// Start both central and peripheral services
|
||||
@@ -1382,6 +1471,14 @@ class BluetoothMeshService: NSObject {
|
||||
self.characteristic = characteristic
|
||||
}
|
||||
|
||||
/// Sends a message through the mesh network.
|
||||
/// - Parameters:
|
||||
/// - content: The message content to send
|
||||
/// - mentions: Array of user IDs being mentioned in the message
|
||||
/// - recipientID: Optional recipient ID for directed messages (nil for broadcast)
|
||||
/// - messageID: Optional custom message ID (auto-generated if nil)
|
||||
/// - timestamp: Optional custom timestamp (current time if nil)
|
||||
/// - Note: Messages are automatically routed through the mesh using TTL-based forwarding
|
||||
func sendMessage(_ content: String, mentions: [String] = [], to recipientID: String? = nil, messageID: String? = nil, timestamp: Date? = nil) {
|
||||
// Defensive check for empty content
|
||||
guard !content.isEmpty else { return }
|
||||
@@ -1443,6 +1540,13 @@ class BluetoothMeshService: NSObject {
|
||||
}
|
||||
|
||||
|
||||
/// Sends an end-to-end encrypted private message to a specific peer.
|
||||
/// - Parameters:
|
||||
/// - content: The message content to encrypt and send
|
||||
/// - recipientPeerID: The peer ID of the recipient
|
||||
/// - recipientNickname: The nickname of the recipient (for UI display)
|
||||
/// - messageID: Optional custom message ID (auto-generated if nil)
|
||||
/// - Note: This method automatically handles Noise handshake if not already established
|
||||
func sendPrivateMessage(_ content: String, to recipientPeerID: String, recipientNickname: String, messageID: String? = nil) {
|
||||
// Defensive checks
|
||||
guard !content.isEmpty, !recipientPeerID.isEmpty, !recipientNickname.isEmpty else {
|
||||
|
||||
@@ -6,12 +6,91 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # NoiseEncryptionService
|
||||
///
|
||||
/// High-level encryption service that manages Noise Protocol sessions for secure
|
||||
/// peer-to-peer communication in BitChat. Acts as the bridge between the transport
|
||||
/// layer (BluetoothMeshService) and the cryptographic layer (NoiseProtocol).
|
||||
///
|
||||
/// ## Overview
|
||||
/// This service provides a simplified API for establishing and managing encrypted
|
||||
/// channels between peers. It handles:
|
||||
/// - Static identity key management
|
||||
/// - Session lifecycle (creation, maintenance, teardown)
|
||||
/// - Message encryption/decryption
|
||||
/// - Peer authentication and fingerprint tracking
|
||||
/// - Automatic rekeying for forward secrecy
|
||||
///
|
||||
/// ## Architecture
|
||||
/// The service operates at multiple levels:
|
||||
/// 1. **Identity Management**: Persistent Curve25519 keys stored in Keychain
|
||||
/// 2. **Session Management**: Per-peer Noise sessions with state tracking
|
||||
/// 3. **Message Processing**: Encryption/decryption with proper framing
|
||||
/// 4. **Security Features**: Rate limiting, fingerprint verification
|
||||
///
|
||||
/// ## Key Features
|
||||
///
|
||||
/// ### Identity Keys
|
||||
/// - Static Curve25519 key pair for Noise XX pattern
|
||||
/// - Ed25519 signing key pair for additional authentication
|
||||
/// - Keys persisted securely in iOS/macOS Keychain
|
||||
/// - Fingerprints derived from SHA256 of public keys
|
||||
///
|
||||
/// ### Session Management
|
||||
/// - Lazy session creation (on-demand when sending messages)
|
||||
/// - Automatic session recovery after disconnections
|
||||
/// - Configurable rekey intervals for forward secrecy
|
||||
/// - Graceful handling of simultaneous handshakes
|
||||
///
|
||||
/// ### Security Properties
|
||||
/// - Forward secrecy via ephemeral keys in handshakes
|
||||
/// - Mutual authentication via static key exchange
|
||||
/// - Protection against replay attacks
|
||||
/// - Rate limiting to prevent DoS attacks
|
||||
///
|
||||
/// ## Encryption Flow
|
||||
/// ```
|
||||
/// 1. Message arrives for encryption
|
||||
/// 2. Check if session exists for peer
|
||||
/// 3. If not, initiate Noise handshake
|
||||
/// 4. Once established, encrypt message
|
||||
/// 5. Add message type header for protocol handling
|
||||
/// 6. Return encrypted payload for transmission
|
||||
/// ```
|
||||
///
|
||||
/// ## Integration Points
|
||||
/// - **BluetoothMeshService**: Calls this service for all private messages
|
||||
/// - **ChatViewModel**: Monitors encryption status for UI indicators
|
||||
/// - **NoiseHandshakeCoordinator**: Prevents handshake race conditions
|
||||
/// - **KeychainManager**: Secure storage for identity keys
|
||||
///
|
||||
/// ## Thread Safety
|
||||
/// - Concurrent read access via reader-writer queue
|
||||
/// - Session operations protected by per-peer queues
|
||||
/// - Atomic updates for critical state changes
|
||||
///
|
||||
/// ## Error Handling
|
||||
/// - Graceful fallback for encryption failures
|
||||
/// - Clear error messages for debugging
|
||||
/// - Automatic retry with exponential backoff
|
||||
/// - User notification for critical failures
|
||||
///
|
||||
/// ## Performance Considerations
|
||||
/// - Sessions cached in memory for fast access
|
||||
/// - Minimal allocations in hot paths
|
||||
/// - Efficient binary message format
|
||||
/// - Background queue for CPU-intensive operations
|
||||
///
|
||||
|
||||
import Foundation
|
||||
import CryptoKit
|
||||
import os.log
|
||||
|
||||
// MARK: - Encryption Status
|
||||
|
||||
/// Represents the current encryption status of a peer connection.
|
||||
/// Used for UI indicators and decision-making about message handling.
|
||||
enum EncryptionStatus: Equatable {
|
||||
case none // Failed or incompatible
|
||||
case noHandshake // No handshake attempted yet
|
||||
@@ -52,6 +131,10 @@ enum EncryptionStatus: Equatable {
|
||||
|
||||
// MARK: - Noise Encryption Service
|
||||
|
||||
/// Manages end-to-end encryption for BitChat using the Noise Protocol Framework.
|
||||
/// Provides a high-level API for establishing secure channels between peers,
|
||||
/// handling all cryptographic operations transparently.
|
||||
/// - Important: This service maintains the device's cryptographic identity
|
||||
class NoiseEncryptionService {
|
||||
// Static identity key (persistent across sessions)
|
||||
private let staticIdentityKey: Curve25519.KeyAgreement.PrivateKey
|
||||
@@ -416,6 +499,8 @@ class NoiseEncryptionService {
|
||||
|
||||
// MARK: - Protocol Message Types for Noise
|
||||
|
||||
/// Message types for the Noise encryption protocol layer.
|
||||
/// These types wrap the underlying BitChat protocol messages with encryption metadata.
|
||||
enum NoiseMessageType: UInt8 {
|
||||
case handshakeInitiation = 0x10
|
||||
case handshakeResponse = 0x11
|
||||
@@ -426,6 +511,9 @@ enum NoiseMessageType: UInt8 {
|
||||
|
||||
// MARK: - Noise Message Wrapper
|
||||
|
||||
/// Container for encrypted messages in the Noise protocol.
|
||||
/// Provides versioning and type information for proper message handling.
|
||||
/// The actual message content is encrypted in the payload field.
|
||||
struct NoiseMessage: Codable {
|
||||
let type: UInt8
|
||||
let sessionID: String // Random ID for this handshake session
|
||||
|
||||
@@ -6,6 +6,77 @@
|
||||
// For more information, see <https://unlicense.org>
|
||||
//
|
||||
|
||||
///
|
||||
/// # ChatViewModel
|
||||
///
|
||||
/// The central business logic and state management component for BitChat.
|
||||
/// Coordinates between the UI layer and the networking/encryption services.
|
||||
///
|
||||
/// ## Overview
|
||||
/// ChatViewModel implements the MVVM pattern, serving as the binding layer between
|
||||
/// SwiftUI views and the underlying BitChat services. It manages:
|
||||
/// - Message state and delivery
|
||||
/// - Peer connections and presence
|
||||
/// - Private chat sessions
|
||||
/// - Command processing
|
||||
/// - UI state like autocomplete and notifications
|
||||
///
|
||||
/// ## Architecture
|
||||
/// The ViewModel acts as:
|
||||
/// - **BitchatDelegate**: Receives messages and events from BluetoothMeshService
|
||||
/// - **State Manager**: Maintains all UI-relevant state with @Published properties
|
||||
/// - **Command Processor**: Handles IRC-style commands (/msg, /who, etc.)
|
||||
/// - **Message Router**: Directs messages to appropriate chats (public/private)
|
||||
///
|
||||
/// ## Key Features
|
||||
///
|
||||
/// ### Message Management
|
||||
/// - Batches incoming messages for performance (100ms window)
|
||||
/// - Maintains separate public and private message queues
|
||||
/// - Limits message history to prevent memory issues (1337 messages)
|
||||
/// - Tracks delivery and read receipts
|
||||
///
|
||||
/// ### Privacy Features
|
||||
/// - Ephemeral by design - no persistent message storage
|
||||
/// - Supports verified fingerprints for secure communication
|
||||
/// - Blocks messages from blocked users
|
||||
/// - Emergency wipe capability (triple-tap)
|
||||
///
|
||||
/// ### User Experience
|
||||
/// - Smart autocomplete for mentions and commands
|
||||
/// - Unread message indicators
|
||||
/// - Connection status tracking
|
||||
/// - Favorite peers management
|
||||
///
|
||||
/// ## Command System
|
||||
/// Supports IRC-style commands:
|
||||
/// - `/nick <name>`: Change nickname
|
||||
/// - `/msg <user> <message>`: Send private message
|
||||
/// - `/who`: List connected peers
|
||||
/// - `/slap <user>`: Fun interaction
|
||||
/// - `/clear`: Clear message history
|
||||
/// - `/help`: Show available commands
|
||||
///
|
||||
/// ## Performance Optimizations
|
||||
/// - Message batching reduces UI updates
|
||||
/// - Caches expensive computations (RSSI colors, encryption status)
|
||||
/// - Debounces autocomplete suggestions
|
||||
/// - Efficient peer list management
|
||||
///
|
||||
/// ## Thread Safety
|
||||
/// - All @Published properties trigger UI updates on main thread
|
||||
/// - Background operations use proper queue management
|
||||
/// - Atomic operations for critical state updates
|
||||
///
|
||||
/// ## Usage Example
|
||||
/// ```swift
|
||||
/// let viewModel = ChatViewModel()
|
||||
/// viewModel.nickname = "Alice"
|
||||
/// viewModel.startServices()
|
||||
/// viewModel.sendMessage("Hello, mesh network!")
|
||||
/// ```
|
||||
///
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import Combine
|
||||
@@ -15,6 +86,9 @@ import CommonCrypto
|
||||
import UIKit
|
||||
#endif
|
||||
|
||||
/// Manages the application state and business logic for BitChat.
|
||||
/// Acts as the primary coordinator between UI components and backend services,
|
||||
/// implementing the BitchatDelegate protocol to handle network events.
|
||||
class ChatViewModel: ObservableObject {
|
||||
// MARK: - Published Properties
|
||||
|
||||
@@ -409,6 +483,10 @@ class ChatViewModel: ObservableObject {
|
||||
|
||||
// MARK: - Message Sending
|
||||
|
||||
/// Sends a message through the BitChat network.
|
||||
/// - Parameter content: The message content to send
|
||||
/// - Note: Automatically handles command processing if content starts with '/'
|
||||
/// Routes to private chat if one is selected, otherwise broadcasts
|
||||
func sendMessage(_ content: String) {
|
||||
guard !content.isEmpty else { return }
|
||||
|
||||
@@ -456,6 +534,11 @@ class ChatViewModel: ObservableObject {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sends an encrypted private message to a specific peer.
|
||||
/// - Parameters:
|
||||
/// - content: The message content to encrypt and send
|
||||
/// - peerID: The recipient's peer ID
|
||||
/// - Note: Automatically establishes Noise encryption if not already active
|
||||
func sendPrivateMessage(_ content: String, to peerID: String) {
|
||||
guard !content.isEmpty else { return }
|
||||
guard let recipientNickname = meshService.getPeerNicknames()[peerID] else {
|
||||
@@ -511,6 +594,9 @@ class ChatViewModel: ObservableObject {
|
||||
|
||||
// MARK: - Private Chat Management
|
||||
|
||||
/// Initiates a private chat session with a peer.
|
||||
/// - Parameter peerID: The peer's ID to start chatting with
|
||||
/// - Note: Switches the UI to private chat mode and loads message history
|
||||
func startPrivateChat(with peerID: String) {
|
||||
let peerNickname = meshService.getPeerNicknames()[peerID] ?? "unknown"
|
||||
|
||||
@@ -1698,6 +1784,9 @@ extension ChatViewModel: BitchatDelegate {
|
||||
|
||||
// MARK: - Command Handling
|
||||
|
||||
/// Processes IRC-style commands starting with '/'.
|
||||
/// - Parameter command: The full command string including the leading slash
|
||||
/// - Note: Supports commands like /nick, /msg, /who, /slap, /clear, /help
|
||||
private func handleCommand(_ command: String) {
|
||||
let parts = command.split(separator: " ")
|
||||
guard let cmd = parts.first else { return }
|
||||
|
||||
Reference in New Issue
Block a user