* Implement Nostr NIP-17 integration for offline mutual favorite messaging - Add Nostr relay connectivity and NIP-17 gift-wrapped private messages - Implement dual transport system: Bluetooth mesh + Nostr relays - Add favorites persistence with mutual detection and Nostr key exchange - Support offline messaging for mutual favorites via Nostr relays - Handle peer identity rotation with automatic favorite key updates - Fix UI to show all favorites (online and offline) in peer list - Add proper message routing based on peer availability - Update peer list icons: 📶 for mesh, 🌐 for Nostr, 🌙 for one-sided - Fix toolbar display for offline peers in private chat view - Add network entitlements for macOS and iOS - Implement automatic noise key updates when peers reconnect * Implement Nostr NIP-17 for private messaging between mutual favorites - Add support for NIP-17 gift-wrapped private messages with double encryption - Enable private messaging via Nostr when mutual favorites are offline - Fix peer reconnection issues: users now stay in private chat when peer reconnects - Fix read receipt delivery: send pending receipts when peer comes back online - Add message ID tracking through Nostr transport for proper delivery acknowledgments - Update peer noise key mapping when peers reconnect with different IDs - Check for Nostr messages when app becomes active - Implement 7-day message retrieval window for better reliability * Fix private message UI refresh and adjust PEOPLE header spacing - Fix UI not updating when receiving private messages on mesh - Add immediate batch processing for messages in active chat - Force UI update when viewing current chat peer - Ensure real-time message display without navigation - Reduce PEOPLE header spacing from 16 to 12 points for tighter UI * Fix build errors and unused value warnings in Nostr favorites integration * Implement read receipts via Nostr - Added sendReadReceipt method to MessageRouter to send receipts via mesh or Nostr - Added handleReadReceipt to process incoming read receipts from Nostr - Made ReadReceipt.readerID mutable to allow updates - Added missing notification names and error cases - Uncommented and enabled read receipt handling in ChatViewModel - Read receipts now work seamlessly via both mesh and Nostr transports * Fix ReadReceipt initialization - use correct constructor * Implement persistent message deduplication for Nostr - Added ProcessedMessagesService to track messages across app restarts - Store processed message IDs and last timestamp in UserDefaults - Skip already processed messages when receiving from Nostr - Adjust subscription filter to use smart timestamp (last processed or 24h) - Prevents duplicate messages when reconnecting to Nostr relays * Fix peer list UI not updating to Nostr mode on disconnect - Remove peer from peerNicknames when connection state changes to disconnected - Ensures UI properly reflects peer disconnection state - Peer list now correctly shows Nostr mode (🌐) when peer walks out of range * Update peer count to include Nostr peers and improve UI indicators - Peer count now shows total peers including those available via Nostr - Count appears purple when only Nostr peers are connected - Private message header shows purple globe icon for Nostr transport - Consistent visual language for Nostr connectivity across the app * Improve RSSI real-time updates and fix UI flashing - Reduce RSSI update timer from 10s to 5s and per-peripheral from 5s to 3s - Add RSSI change detection with 2 dBm threshold for responsive updates - Always update previous RSSI values to fix gradual change detection bug - Trigger RSSI read on peer authentication for immediate status - Fix UI flashing 'nobody around' by removing array clearing on updates - Add proper cleanup of RSSI tracking on disconnect and peer rotation * Fix favorite nickname updates and peer list filtering - Add updateNickname method to FavoritesPersistenceService to update nicknames while preserving favorite status - Update announce handler to check for existing favorites and update their nicknames - Remove dead BluetoothMeshService+PublicAPI.swift file - Move sendFavoriteNotification to main BluetoothMeshService - Fix peer list to only show connected peers and user's favorites (not peers who favorite the user) - Remove UI logic for showing peers who favorite us but we don't favorite back * Remove dead code and fix ghost connections Phase 1 - Remove abandoned peer ID rotation code: - Remove previousPeerID property and rotationGracePeriod constant - Remove grace period logic from isPeerIDOurs() - Remove previousPeerID handling from announce packets - Pass nil for previousPeerID in identity announcements Phase 2 - Fix ghost connections from relayed packets: - CRITICAL FIX: Only add peers to activePeers if they have a peripheral connection - Check for peripheral connection before marking peer as active - Prevents ghost connections when announce packets are relayed - Log warning when rejecting relayed announce without peripheral Phase 3 - Begin consolidating redundant peer tracking: - Create new PeerSession class to unify peer data in one place - Add helper methods for PeerSession management - Integrate PeerSession into announce packet handling - Update authentication state changes to use PeerSession - Update peripheral mapping and RSSI to sync with PeerSession - Update disconnect and leave handling to update PeerSession - Add consolidated getter methods for peer info This fixes the issue where peers appeared connected without actually having a Bluetooth connection, and begins the migration to a cleaner single-source-of-truth peer tracking system. * Fix multiple connect messages on peer restart - Move hasPeripheralConnection check outside sync block to fix scope issue - Add debug logging to track connect message conditions - Ensure connect messages only show on first connection or reconnection with peripheral * Optimize RSSI updates for better battery life - Add app state tracking to BluetoothMeshService - Only update RSSI when app is in foreground and peer list is visible - Add setPeerListVisible method to control RSSI updates - Remove individual periodic RSSI updates in favor of centralized timer - Update ContentView to notify mesh service of peer list visibility changes - Improve battery efficiency by avoiding unnecessary RSSI reads * Initialize peer list visibility state on view appear - Ensure RSSI timer state is properly initialized when view loads - Call setPeerListVisible with initial showSidebar value * Fix duplicate peers and multiple disconnect messages - Fixed duplicate peer entries when relay-connected by adding relay-connected peers to connectedNicknames set - Added deduplication logic for disconnect messages with 2-second window to prevent multiple disconnect notifications for same peer - Added cleanup for old disconnect notification tracking to prevent memory growth * Fix peer count indicator color logic - Show green for any mesh peer (direct Bluetooth or relay connected) - Show purple only for Nostr-only peers (no mesh connections) - Show red only when no peers are reachable at all - Fixed to use meshPeerCount instead of viewModel.isConnected which only checked direct connections * Fix relay connection issues and peripheral mapping cleanup - Fixed relay-connected peers being marked as directly connected when receiving identity announce - Added proper cleanup of temp peripheral mappings when discovering real peer ID - Fixed disconnect notification deduplication cleanup - Improved debug logging to show actual connection state (direct/relay/nostr/offline) - Added debug logging for relay connection detection - Fixed compiler warning about unused variable * Fix Unknown peer disconnect notifications and disable faulty relay detection - Add check to prevent disconnect notifications for Unknown peers that never announced - Disable relay connection detection until proper relay tracking is implemented - In a 2-peer network, peers should never show as relay-connected * Fix RSSI updates and peer visibility after reconnection - Add updatePeers() call in didUpdatePeerList to refresh RSSI values in UI - Track version hello times to better detect direct connections - Allow peers to be marked active if recent version hello received - Fix thread safety for version hello tracking - Clean up old version hello times to prevent memory leaks * Remove RSSI tracking completely and replace with radio icon for mesh connections * Fix build errors after RSSI removal - Add missing peripheralID declaration in didDiscover delegate method - Remove obsolete setPeerListVisible calls from ContentView * Center private message header elements using ZStack layout - Replace HStack with ZStack for perfect centering - Globe/nick/lock cluster now always centered regardless of button sizes - Back and favorite buttons positioned in overlay HStack * Fix private chat view showing Unknown when peer reconnects with new ID - Update FavoritesPersistenceService to notify with both old and new keys - Handle peer ID changes in ChatViewModel to migrate private chat data - Update selectedPrivateChatPeer when favorite's noise key changes - Maintain chat history and unread status across peer ID changes * Fix read receipts after peer reconnection and replace nos.lol relay - Updated sendReadReceipt to resolve current peer ID when peers reconnect with new IDs - Enhanced MessageRouter to check favorites for current noise keys - Replaced nos.lol relay with relay.snort.social to avoid PoW requirements * Fix message routing to use Nostr when peers are disconnected Changed message routing logic to check actual peer connection status using isPeerConnected() instead of just checking if peer exists in nickname list. This ensures that offline mutual favorites correctly route messages through Nostr instead of attempting Bluetooth handshakes. Also added safety check to prevent starting private chat with ourselves. * Add debug logging for Nostr timestamp randomization Added logging to track the random offset being applied to Nostr event timestamps to debug why messages appear 8-9 minutes in the future. * Fix Nostr timestamp issue by reducing randomization range Temporarily reduced the timestamp randomization from +/-15 minutes to +/-1 minute to address messages appearing 8-9 minutes in the future. Added detailed UTC/local time logging to help debug the issue. The random offset should have been evenly distributed but was consistently showing positive offsets. This change mitigates the issue while we investigate the root cause. * Fix message routing for offline favorites and reduce Nostr timestamp randomization - Fix transport selection to properly detect disconnected peers using isPeerConnected() - Change from checking peer nicknames to checking actual connection status - Reduce Nostr timestamp randomization from ±15 minutes to ±1 minute - Add detailed timestamp logging for debugging * Improve PM header UI and encryption status display - Show transport icons (radio/link/globe) in PM header matching peer list - Always show lock icon if noise session ever established (no handshake icon) - Change verified icon from shield to checkmark seal - Use consistent green color (textColor) for PM header and encryption icons * Update AI_CONTEXT.md with comprehensive Nostr implementation details - Add Nostr and MessageRouter to architecture diagram - Document NIP-17 gift wrap implementation - Explain favorites integration and mutual requirement - Detail message routing logic and transport selection - Add security considerations and debugging tips - Update common tasks with Nostr-specific guidance * Fix data consistency issues in favorites, chat migration, and bloom filter - Fix favorites deduplication to use public key instead of nickname Prevents losing favorites when multiple peers use same nickname - Fix private chat migration to use fingerprints instead of nicknames Prevents merging unrelated conversations that share nicknames Fallback to nickname matching only for legacy data without fingerprints - Fix bloom filter reset to preserve messages from last 10 minutes Prevents duplicate message processing after bloom filter resets Keeps processedMessages for 10 minutes while bloom filter resets every 5 * Add mutual favorites internet messaging to app info * Remove excessive debug/info logging for production readiness - Removed ~140 debug/info level logs across core services - Preserved critical logs: errors, warnings, security events, state changes - Kept logs for: peer join/leave, favorite status, mutual relationships - Cleaned up verbose logging in: Bluetooth mesh, Nostr, message routing - Improved performance by reducing log I/O overhead 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * Implement performance optimizations and fix build warnings - Add UI update debouncing (50ms) to prevent excessive SwiftUI refreshes - Implement memory bounds for processedMessages with LRU eviction - Add encryption queue cleanup for disconnected peers - Optimize peer lookups from O(n) to O(1) with indexed dictionary - Fix multiple compiler warnings (unused variables, missing break statements) - Optimize peer counting with single-pass reduce operation - Fix ViewBuilder control flow issue in ContentView - Fix Dictionary initialization type mismatches with Array wrapper * Add TTL-based cleanup for Noise handshake sessions - Add session TTL (5 minutes) and max session limit (50) to NoiseHandshakeCoordinator - Clean up old established sessions to prevent unbounded memory growth - Move handshake cleanup timer out of DEBUG conditional for production use - Run cleanup every 60 seconds in production (vs 30s in debug) - Clean up crypto state immediately on peer disconnect - Prevents memory leaks from accumulating Noise sessions * Pre-compute and store fingerprints in PeerSession for O(1) lookups - Store fingerprint in PeerSession when peer authenticates - Update getPeerFingerprint() and getFingerprint() to check PeerSession first - Replace all noiseService.getPeerFingerprint() calls with optimized version - Eliminates repeated SHA256 calculations during message processing - Improves performance for favorite checks and encryption status updates * Implement exponential backoff for Nostr relay connections - Add reconnection tracking fields to Relay struct (attempts, timing) - Replace fixed 5-second delay with exponential backoff (1s → 2s → 4s... max 5min) - Stop reconnection attempts after 10 failures to prevent infinite retries - Reset attempt counter on successful connection - Add utility methods: retryConnection(), getRelayStatuses(), resetAllConnections() - DNS failures still bypass retry logic as before - Improves battery life and reduces server load from constant reconnection attempts --------- Co-authored-by: jack <jackjackbits@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
18 KiB
AI Context for BitChat
This document provides essential context for AI assistants working on the BitChat codebase. Read this first to understand the project's architecture, design decisions, and key concepts.
Project Overview
BitChat is a decentralized, peer-to-peer messaging application that works over Bluetooth mesh networks without requiring internet connectivity, servers, or phone numbers. It's designed for scenarios where traditional communication infrastructure is unavailable or untrusted.
Key Features
- Bluetooth Mesh Networking: Multi-hop message relay over BLE
- Privacy-First Design: No accounts, no persistent identifiers
- End-to-End Encryption: Uses Noise Protocol Framework for private messages
- Store & Forward: Messages cached for offline peers
- IRC-Style Commands: Familiar
/msg,/whointerface - Cross-Platform: Native iOS and macOS support
- Nostr Integration: Seamless fallback for mutual favorites when out of Bluetooth range
- Hybrid Transport: Automatic switching between Bluetooth and Nostr
Architecture Overview
┌─────────────────────────────────────────────────────────────────┐
│ User Interface │
│ (ContentView, ChatViewModel) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Application Services │
│ (MessageRetryService, DeliveryTracker, NotificationService) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Message Router │
│ (Transport selection, Favorites integration) │
└─────────────────────────────────────────────────────────────────┘
│ │
┌───────────────────────────────┐ ┌────────────────────────────────┐
│ Security Layer │ │ Nostr Protocol Layer │
│ (NoiseEncryptionService, │ │ (NostrProtocol, NIP-17, │
│ SecureIdentityStateManager) │ │ NostrRelayManager) │
└───────────────────────────────┘ └────────────────────────────────┘
│ │
┌───────────────────────────────┐ ┌────────────────────────────────┐
│ Protocol Layer │ │ Transport │
│ (BitchatProtocol, Binary- │ │ (WebSocket to Nostr │
│ Protocol, NoiseProtocol) │ │ relay servers) │
└───────────────────────────────┘ └────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Bluetooth Transport Layer │
│ (BluetoothMeshService) │
└─────────────────────────────────────────────────────────────────┘
Core Components
1. BluetoothMeshService (Transport Layer)
- Location:
bitchat/Services/BluetoothMeshService.swift - Purpose: Manages BLE connections and implements mesh networking
- Key Responsibilities:
- Peer discovery (scanning and advertising simultaneously)
- Connection management (acts as both central and peripheral)
- Message routing and relay
- Version negotiation with peers
- Automatic reconnection and topology management
2. BitchatProtocol (Protocol Layer)
- Location:
bitchat/Protocols/BitchatProtocol.swift - Purpose: Defines the application-level messaging protocol
- Key Features:
- Binary packet format for efficiency
- Message types: Chat, Announcement, PrivateMessage, etc.
- TTL-based routing (max 7 hops)
- Message deduplication via unique IDs
- Privacy features: padding, timing obfuscation
3. NoiseProtocol Implementation
- Locations:
bitchat/Noise/NoiseProtocol.swift- Core protocol implementationbitchat/Noise/NoiseSession.swift- Session managementbitchat/Services/NoiseEncryptionService.swift- High-level encryption API
- Purpose: Provides end-to-end encryption for private messages
- Implementation Details:
- Uses Noise_XX_25519_AESGCM_SHA256 pattern
- Mutual authentication via static keys
- Forward secrecy via ephemeral keys
- Integrated with identity management
4. Identity System
- Location:
bitchat/Identity/ - Three-Layer Model:
- Ephemeral Identity: Short-lived, rotates frequently
- Cryptographic Identity: Long-term Noise static keypair
- Social Identity: User-chosen nickname and metadata
- Trust Levels: Untrusted → Verified → Trusted → Blocked
5. ChatViewModel
- Location:
bitchat/ViewModels/ChatViewModel.swift - Purpose: Central state management and business logic
- Responsibilities:
- Message handling and batching
- Command processing (/msg, /who, etc.)
- UI state management
- Private chat coordination
6. Nostr Integration
- Locations:
bitchat/Nostr/NostrProtocol.swift- NIP-17 private message implementationbitchat/Nostr/NostrRelayManager.swift- WebSocket relay connectionsbitchat/Nostr/NostrIdentity.swift- Nostr key managementbitchat/Services/MessageRouter.swift- Transport selection logic
- Purpose: Enables communication with mutual favorites when out of Bluetooth range
- Key Features:
- NIP-17 gift-wrapped private messages for metadata privacy
- Automatic relay connection management
- Seamless transport switching between Bluetooth and Nostr
- Integrated with favorites system for mutual authentication
7. MessageRouter
- Location:
bitchat/Services/MessageRouter.swift - Purpose: Intelligent routing between Bluetooth mesh and Nostr transports
- Transport Selection Logic:
- Always prefer Bluetooth mesh when peer is connected
- Use Nostr for mutual favorites when peer is offline
- Fail gracefully when no transport is available
- Message Types Routed:
- Regular chat messages
- Favorite/unfavorite notifications
- Delivery acknowledgments
- Read receipts
Key Design Decisions
1. Protocol Design
- Binary Protocol: Chosen for efficiency over BLE's limited bandwidth
- No JSON: Reduces parsing overhead and message size
- Custom Framing: Handles BLE's 512-byte MTU limitations
2. Security Architecture
- Noise Protocol: Industry-standard, well-analyzed framework
- XX Pattern: Provides mutual authentication and forward secrecy
- No Long-Term Identifiers: Enhances privacy and deniability
3. Mesh Networking
- Store & Forward: Essential for intermittent connectivity
- TTL-Based Routing: Prevents infinite loops in mesh
- Bloom Filters: Efficient duplicate detection
4. Privacy Features
- Message Padding: Obscures message length
- Cover Traffic: Optional dummy messages
- Timing Obfuscation: Randomized delays
- Emergency Wipe: Triple-tap to clear all data
5. Nostr Integration
- NIP-17 Gift Wraps: Maximum metadata privacy
- Ephemeral Keys: Each message uses unique ephemeral keys
- Mutual Favorites Only: Requires bidirectional trust
- Transport Abstraction: Users don't need to know about Nostr
Code Organization
Services (/bitchat/Services/)
Application-level services that coordinate between layers:
BluetoothMeshService: Core networkingNoiseEncryptionService: Encryption coordinationMessageRetryService: Reliability layerDeliveryTracker: Acknowledgment handlingNotificationService: System notifications
Protocols (/bitchat/Protocols/)
Protocol definitions and implementations:
BitchatProtocol: Application protocolBinaryProtocol: Low-level encodingBinaryEncodingUtils: Helper functions
Noise (/bitchat/Noise/)
Noise Protocol Framework implementation:
NoiseProtocol: Core cryptographic operationsNoiseSession: Session state managementNoiseHandshakeCoordinator: Handshake orchestrationNoiseSecurityConsiderations: Security validations
Views & ViewModels
MVVM architecture for UI:
ContentView: Main chat interfaceChatViewModel: Business logic and state- Supporting views for settings, identity, etc.
Nostr Protocol Implementation
Overview
BitChat integrates Nostr as a secondary transport for communicating with mutual favorites when Bluetooth connectivity is unavailable. This integration is transparent to users - messages automatically route through Nostr when needed.
NIP-17 Private Direct Messages
BitChat implements NIP-17 (Private Direct Messages) for metadata-private communication:
-
Gift Wrap Structure:
Gift Wrap (kind 1059) → Seal (kind 13) → Rumor (kind 1)- Rumor: The actual message content (unsigned)
- Seal: Encrypted rumor, hides sender identity
- Gift Wrap: Double-encrypted, tagged for recipient
-
Ephemeral Keys:
- Each message uses TWO ephemeral key pairs
- Seal uses one ephemeral key
- Gift wrap uses a different ephemeral key
- Provides sender anonymity and forward secrecy
-
Timestamp Randomization:
- ±1 minute randomization (reduced from NIP-17's ±15 minutes)
- Prevents timing correlation attacks
- Configurable in
NostrProtocol.randomizedTimestamp()
Favorites Integration
The Nostr transport is only available for mutual favorites:
-
Favorite Establishment:
- User favorites a peer via
/favcommand - Favorite notification sent via Bluetooth (if connected)
- Peer's Nostr public key exchanged during favorite process
- Stored in
FavoritesPersistenceService
- User favorites a peer via
-
Mutual Requirement:
- Both peers must favorite each other
- Prevents spam and unwanted Nostr messages
- Enforced by
MessageRoutertransport selection
-
Nostr Key Management:
- Derived from Noise static key using BIP-32
- Path:
m/44'/1237'/0'/0/0(1237 = "NOSTR" in decimal) - Consistent npub across app reinstalls
- Keys never leave the device
Message Routing Logic
MessageRouter automatically selects transport:
if peerAvailableOnMesh {
transport = .bluetoothMesh // Always prefer mesh
} else if isMutualFavorite {
transport = .nostr // Use Nostr for offline favorites
} else {
throw MessageRouterError.peerNotReachable
}
Relay Configuration
Default relays (hardcoded for reliability):
wss://relay.damus.iowss://relay.primal.netwss://offchain.pubwss://nostr21.com
Relay selection criteria:
- Geographic distribution
- High uptime
- No authentication required
- Support for ephemeral events
Message Format
Structured content for different message types:
- Chat:
MSG:<messageID>:<content> - Favorite:
FAVORITED:<senderNpub>orUNFAVORITED:<senderNpub> - Delivery ACK:
DELIVERED:<messageID> - Read Receipt:
READ:<base64EncodedReceipt>
Implementation Details
-
NostrRelayManager:
- Manages WebSocket connections to relays
- Handles reconnection logic
- Processes EVENT, EOSE, OK, NOTICE messages
- Implements NIP-01 relay protocol
-
NostrProtocol:
- Implements NIP-17 encryption/decryption
- Handles gift wrap creation/unwrapping
- Manages ephemeral key generation
- Provides Schnorr signatures
-
ProcessedMessagesService:
- Prevents duplicate message processing
- Tracks last subscription timestamp
- Persists across app launches
- 30-day retention window
Security Considerations
-
Metadata Protection:
- Sender identity hidden via ephemeral keys
- Recipient only visible in gift wrap p-tag
- Timing correlation prevented via randomization
- Message content double-encrypted
-
Relay Trust:
- Relays cannot read message content
- Relays can see recipient pubkey (gift wrap)
- Relays cannot determine sender
- Multiple relays used for redundancy
-
Key Hygiene:
- Ephemeral keys used once and discarded
- Static Nostr key derived from Noise key
- No key reuse between messages
- Keys cleared from memory after use
Debugging Nostr Issues
-
Check relay connections:
- Look for "Connected to Nostr relay" in logs
- Verify WebSocket state in NostrRelayManager
- Check for relay errors/notices
-
Verify gift wrap creation:
- Enable debug logging in NostrProtocol
- Check ephemeral key generation
- Verify encryption steps
-
Message delivery:
- Check ProcessedMessagesService for duplicates
- Verify subscription filters
- Look for EVENT messages in relay responses
Development Guidelines
1. Security First
- Never log sensitive data (keys, message content)
- Use
SecureLoggerfor security-aware logging - Validate all inputs from network
- Follow principle of least privilege
2. Performance Considerations
- BLE has limited bandwidth (~20KB/s practical)
- Minimize protocol overhead
- Batch operations where possible
- Use compression for large messages
3. Testing
- Unit tests for protocol logic
- Integration tests for service interactions
- End-to-end tests for user flows
- Mock objects for BLE testing
4. Error Handling
- Graceful degradation for network issues
- Clear error messages for users
- Automatic retry with backoff
- Never expose internal errors
Common Tasks
Adding a New Message Type
- Define in
MessageTypeenum inBitchatProtocol.swift - Implement encoding/decoding logic
- Add handling in
ChatViewModel - Update UI if needed
- Add tests
Implementing a New Command
- Add to
ChatViewModel.processCommand() - Define any new message types needed
- Implement command logic
- Add autocomplete support
- Update help text
Debugging Bluetooth Issues
- Check
BluetoothMeshServicelogs - Verify peer states and connections
- Monitor characteristic updates
- Use Bluetooth debugging tools
Working with Nostr Transport
- Verify mutual favorite status in
FavoritesPersistenceService - Check Nostr key derivation in
NostrIdentity - Monitor relay connections in
NostrRelayManager - Test gift wrap encryption/decryption
- Verify transport selection in
MessageRouter
Adding Nostr Features
- Understand NIP-17 gift wrap structure
- Maintain ephemeral key hygiene
- Test with multiple relays
- Preserve metadata privacy
- Handle relay disconnections gracefully
Security Threat Model
Assumptions
- Adversaries can intercept all Bluetooth traffic
- Devices may be compromised
- No trusted infrastructure available
Protections
- End-to-end encryption for private messages
- Message authentication via HMAC
- Forward secrecy via ephemeral keys
- Deniability through lack of signatures
Limitations
- Public messages are unencrypted by design
- Metadata (who talks to whom) partially visible
- Timing attacks possible on mesh network
- No protection against flooding/spam (yet)
Performance Optimizations
Implemented
- LZ4 compression for messages
- Adaptive duty cycling for battery
- Connection caching and reuse
- Bloom filters for deduplication
Future Improvements
- Protocol buffer encoding
- Better mesh routing algorithms
- Predictive pre-connection
- Smarter retransmission
Troubleshooting Guide
Common Issues
- Peers not discovering: Check Bluetooth permissions, ensure app is in foreground
- Messages not delivering: Verify mesh connectivity, check TTL values
- Handshake failures: Ensure identity state is consistent, check key storage
- Performance issues: Monitor connection count, check for message loops
External Dependencies
Swift Packages
- CryptoKit: Apple's crypto framework
- Network.framework: For future internet support
- No third-party dependencies (by design)
System Requirements
- iOS 14.0+ / macOS 11.0+
- Bluetooth LE hardware
- ~50MB storage for app + data
Future Roadmap
Planned Features
- Internet bridging for hybrid networks
- Group chat with forward secrecy
- Voice messages with Opus codec
- File transfer support
Architecture Evolution
- Plugin system for transports
- Modular protocol stack
- Cross-platform core library
- Federation between networks
Quick Start for AI Assistants
- Understand the layers: Transport → Protocol → Security → Services → UI
- Follow the data flow: BLE/Nostr → Binary/JSON → Protocol → ViewModel → View
- Respect security boundaries: Never mix trusted and untrusted data
- Test thoroughly: This is critical infrastructure for users
- Ask about design decisions: Many choices have non-obvious reasons
- Dual Transport: Remember that messages can flow over Bluetooth OR Nostr
- Favorites System: Nostr only works between mutual favorites
When in doubt, prioritize security and privacy over features. BitChat users depend on this app in situations where traditional communication has failed them.