개요
탈중앙화 채팅 애플리케이션으로, 블루투스 Mesh 오프라인 통신과 Nostr 글로벌 연결을 지원하며, 계정이나 중앙 서버 없이 종단 간 암호화로 프라이버시를 보호하고, 위치 기반 채널과 IRC 스타일 명령어를 제공합니다.
README 미리보기
\n\n## bitchat\n\nA decentralized peer-to-peer messaging app with dual transport architecture: local Bluetooth mesh networks for offline communication and internet-based Nostr protocol for global reach. No accounts, no phone numbers, no central servers. It's the side-groupchat.\n\n[bitchat.free](http://bitchat.free)\n\n📲 [App Store](https://apps.apple.com/us/app/bitchat-mesh/id6748219622)\n\n## License\n\nThis project is released into the public domain. See the [LICENSE](LICENSE) file for details.\n\n## Features\n\n- **Dual Transport Architecture**: Bluetooth mesh for offline + Nostr protocol for internet-based messaging\n- **Location-Based Channels**: Geographic chat rooms using geohash coordinates over global Nostr relays\n- **Intelligent Message Routing**: Automatically chooses best transport (Bluetooth → Nostr fallback)\n- **Decentralized Mesh Network**: Automatic peer discovery and multi-hop message relay over Bluetooth LE\n- **Privacy First**: No accounts, no phone numbers, no persistent identifiers\n- **Private Message End-to-End Encryption**: [Noise Protocol](https://noiseprotocol.org) for mesh, NIP-17 for Nostr\n- **IRC-Style Commands**: Familiar `/slap`, `/msg`, `/who` style interface\n- **Universal App**: Native support for iOS and macOS\n- **Emergency Wipe**: Triple-tap to instantly clear all data\n- **Performance Optimizations**: LZ4 message compression, adaptive battery modes, and optimized networking\n\n## [Technical Architecture](https://deepwiki.com/permissionlesstech/bitchat)\n\nBitChat uses a **hybrid messaging architecture** with two complementary transport layers:\n\n### Bluetooth Mesh Network (Offline)\n\n- **Local Communication**: Direct peer-to-peer within Bluetooth range\n- **Multi-hop Relay**: Messages route through nearby devices (max 7 hops)\n- **No Internet Required**: Works completely offline in disaster scenarios\n- **Noise Protocol Encryption**: End-to-end encryption with forward secrecy\n- **Binary Protocol**: Compact packet format
FAQ (4)
문제 해결Xcode 27에서 'ambiguous use of words' 또는 swift-secp256k1 플러그인 검증 오류로 인해 bitchat macOS 빌드가 실패하는 문제를 해결하는 방법
고정된 21-DOT-DEV/swift-secp256k1 의존성을 0.24.0 이상으로 업그레이드하세요. 메인테이너가 Xcode 27 / Swift 6.4 플러그인 검증 실패를 수정하기 위해 특별히 0.24.0을 릴리스했습니다. 그런 다음 Package.resolved를 업데이트하고 xcodebuild -project bitchat.xcodeproj -scheme "bitchat (macOS)" -configuration Debug build 명령으로 다시 빌드하세요.
근본 원인: 고정된 0.21.1은 UInt256.swift의 사용자 정의 var words가 Swift 6.4의 Swift.BinaryInteger.words와 충돌하여('ambiguous use of words') 컴파일에 실패하고, 0.23.2는 SharedSourcesPlugin이 Xcode 27에 번들로 포함된 SwiftPM에서는 사용할 수 없는 @available(_PackageDescription 6.0) API를 사용하기 때문에 xcodebuild의 플러그인 검증에 실패합니다.
업그레이드할 수 없는 경우의 우회 방법: swift-secp256k1 0.23.2를 로컬에 벤더링하세요. localPackages/swift-secp256k1로 복사하고, Plugins/ 디렉터리를 삭제하고, 해당 Package.swift에서 .plugin(name: "SharedSourcesPlugin", capability: .buildTool()) 타겟과 P256K/ZKP 타겟의 plugins: ["SharedSourcesPlugin"]을 제거하며(Sources/Shared/*를 두 타겟의 소스 디렉터리 모두에 평탄하게 배치), Package.swift가 .package(path: "localPackages/swift-secp256k1")를 가리키도록 하고, project.pbxproj에서 XCRemoteSwiftPackageReference를 XCLocalSwiftPackageReference로 교체하고, Package.resolved를 삭제하세요. 그러면 빌드가 오류 0개로 성공합니다.
문제 해결deliveredFrameCount가 최대 12여야 하는데 16으로 나오는 불안정한(flaky) SimulatedMeshTests 실패를 어떻게 수정하나요?
이 플레이크는 테스트 하네스가 시뮬레이션된 시간만 진행시키는 동안 announce-admission 로직이 wall-clock Date()를 사용하기 때문에 발생합니다. 부하가 걸린 CI 러너에서는 0.15 s 스로틀 윈도우가 경과할 수 있으며, 그 결과 4개의 추가 announce 프레임이 생성되어 mesh.deliveredFrameCount - baseline이 12에서 16으로 증가합니다. 시뮬레이션된 메시에서 wall-clock 의존성을 제거하여 이 문제를 수정하세요: announce 스로틀에 테스트의 시뮬레이션 클록을 주입/사용하거나, 베이스라인을 기록하기 전에 메시를 유휴 상태로 드레인하여 wall-clock 기반 announce 트래픽이 측정된 델타에서 제외되도록 하세요. 관련 수정 사항은 PR #1622/#1649에서 추적되며, #1651은 베이스라인 전에 메시 트래픽을 드레인하고 스톰 버짓을 테스트 대상 릴레이 동작에 맞게 제한합니다.
문제 해결Android에서 보낸 대용량 압축 메시지가 iOS에서 아무런 경고 없이 표시되지 않는 이유는 무엇이며, 페이로드 크기 불일치 문제는 어떻게 해결하나요?
이 문제는 Android가 최대 AppConstants.Protocol.MAX_PAYLOAD_LENGTH = 10 MiB의 압축 해제 페이로드를 허용하는 반면, iOS는 FileTransferLimits.maxFramedFileBytes ≈ 1.13 MiB를 초과하는 프레임을 거부하기 때문에 발생합니다. 따라서 고도로 압축된 Android 메시지는 2–5 MiB로 확장되어 iOS에서 자동으로 삭제될 수 있습니다.
해결 방법:
1. iOS의 인바운드 압축 해제 페이로드 제한을 Android와 일치시키는 PR "Accept compressed payloads up to Android's 10 MiB decompressed ceiling"이 포함된 빌드로 iOS 클라이언트를 업데이트하세요.
2. 전역 확장 페이로드 상한을 초과하는 프레임 생성을 거부하는 인코드 측 적용 PR을 적용하여, 송신자가 디코더가 거부할 메시지를 생성하지 못하도록 하세요.
3. 임시 해결 방법으로, Android에서 이전 버전의 iOS 클라이언트로 전송할 때 비압축/원본 페이로드를 약 1.13 MiB 미만으로 유지하세요.
50,000:1 압축률 가드는 별개의 기능이며, iOS가 해당 가드가 적용되기 전에 와이어에 선언된 originalSize를 기준으로 할당하기 때문에 이러한 불일치를 방지하지 못합니다.
문제 해결pull request를 생성하거나 업데이트할 수 없는 GitHub Actions 워크플로 토큰을 어떻게 수정하나요?
기본 워크플로 토큰에는 PR을 열 수 있는 권한이 없습니다. compare URL을 열고 소스 브랜치로 automation/georelay-data를 선택하여 수동으로 생성하세요:
https://github.com/permissionlesstech/bitchat/compare/main...automation/georelay-data?expand=1
그런 다음 PR을 일반 리뷰용으로 제출하세요. 리포지토리가 여전히 토큰을 차단하는 경우, 변경되지 않은 브랜치를 개인 포크에 푸시하고 main에 대한 크로스 포크 PR을 여세요. 자동화된 실행의 경우, 워크플로 토큰에 pull-requests: write(및 필요한 경우 contents: write) 권한을 부여하거나, PR 생성 권한이 있는 PAT/앱 토큰을 사용하세요.