βββ βββ
βββ
βββββββ βββββββββββ βββββββββ ββββββββ βββββββββ
βββ βββββββ βββ βββ βββ βββ βββ βββ
ββββββββ ββββββ βββ βββ βββ βββ βββ βββ
βββ βββ ββββββ βββ βββ βββ βββ ββββ βββ
βββββββββ ββββββ βββ βββ ββββββββ βββββββββ
βββ
βββ
Website | Architecture | FAQ | Terms of Service | Privacy Policy | Support
Airhop is an iOS + Android app (macOS and Windows coming soon) for private, offline-first peer-to-peer communication over Bluetooth mesh networks, with Nostr internet bridging and Cashu ecash payments. Our mission is to make censorship-resistant communication available to anyone: during natural disasters, internet blackouts, mass protests, or any situation where networks are unavailable, surveilled, or shut down.
Built on the foundation of bitchat, using the same BLE wire protocol, and service UUIDs, meaning Airhop-installed devices can automatically discover and join the same mesh as nearby Bitchat-installed devices, relay messages, and exchange DMs with zero setup. Airhop also extends the protocol with Double Ratchet forward secrecy, Tor on both platforms, offline ecash payments, and offline AI (not present in bitchat at the time of writing).
Note
Airhop is an independent side project built and maintained by Areeb Ahmed in his free time. It is not backed by any company or organization, not affiliated with or endorsed by permissionlesstech or the bitchat project, and not an impersonation of any existing app or service.
Warning
WIP. Not externally security-reviewed. All code is personally reviewed and run through the security review agent before shipping, but this is not a substitute for a formal audit. Do not rely on its security for sensitive use cases. External audit planned for v1.9.0.
| Category | Feature | Description |
|---|---|---|
| π¬ Messaging | Private DMs | One-on-one end-to-end encrypted messaging |
| Public channels | IRC-style group chat rooms anyone nearby can join | |
| Location channels | Public rooms scoped to a geohash cell, from a block to a region, bridged over the internet. Jump to any cell to read a place you are not in | |
| Private channels | Invite-only encrypted rooms. A shared key travels in the invite link, so anyone with the link joins and reads; there is no member cap | |
| Private groups | Fixed-roster encrypted group chats. The creator signs the member list (up to 16) and shares the key over Noise; only listed members can read | |
| Bulletin board | Signed notices that outlive chat: pin a post to your mesh or location for 1 to 7 days, with urgent flags. Late arrivals catch up automatically | |
| Photo sharing | Send a photo over the mesh (PNG, JPEG, GIF, WebP), up to 512 KB | |
| Video sharing | Send a video over the mesh (MP4, MOV), up to 1 MB | |
| Voice notes | Send a voice message over the mesh (AAC, 16 kHz mono), up to 512 KB | |
| Live voice | Hold the mic to talk to people in range, walkie-talkie style. Arrives in about half a second, then lands in the chat as a voice note | |
| File transfer | Send any file format over the mesh (documents, archives, anything else), up to 1 MB per file | |
| Store-and-forward courier | Messages are delivered automatically when a route becomes available, sealed to a one-time prekey for forward secrecy | |
| π Identity | No-account identity | Identity is an Ed25519 key pair stored only on your device |
| Human-readable names | Deterministic usernames derived from your public key | |
| QR contacts | Add a contact by scanning their QR code; carries their public keys, not just an ID | |
| End-to-end encryption | Secure sessions using the Noise XX protocol | |
| Forward secrecy | Double Ratchet protects past messages even if keys are later compromised | |
| Panic wipe | Triple-tap instantly erases keys and local messages (nuke your account) | |
| πΈοΈ Networking | Bluetooth mesh | Communicate with nearby devices without internet |
| Mesh bridge | Link this area's public #bluetooth chat with another out-of-range Bluetooth crowd over the internet. Off by default | |
| Multi-hop routing | Messages automatically relay across nearby devices (up to 7 hops) | |
| Relay nodes | Third-party Bitle hardware extends the mesh where nobody stands. Requires an ESP32 board, plus LoRa to link nodes | |
| WiFi high-bandwidth mode | Faster file transfers between two Android devices, or two iPhones. Not across platforms | |
| bitchat compatibility | Airhop nodes communicate directly with bitchat on iOS and Android | |
| π Internet | Internet fallback | DMs and channels keep flowing over Nostr relays when a user moves out of Bluetooth range |
| Geo-relay discovery | Discover location-based channels across 300+ distributed Nostr relays | |
| Internet gateway | Lend your connection to a nearby offline phone so it can still reach the location (geohash) channels. Off by default | |
| Tor integration | Route Nostr traffic through Tor (Arti on iOS, Orbot on Android) |
TL;DR: No internet required. No central servers. No accounts. No tracking.
| Category | Feature | Description |
|---|---|---|
| π° Payments | Cashu ecash | Pay someone standing next to you over Bluetooth, with no internet on either phone. Coins are stored encrypted on your device, checked against the mintβs signature the moment they arrive (NUT-12), and a payment that never reaches anyone can be taken back. Internet is only needed to top up, cash out, or confirm a received coin is unspent |
| Lightning | Top up from any Lightning wallet, and cash out to any Lightning invoice, through the mint you choose (NUT-04 / NUT-05) | |
| Nutzaps | Pay a Nostr identity over the internet, locked to their key so only they can spend it (NIP-61). Falls back to an encrypted message if they have not set it up | |
| Wallet recovery | Optional 12-word recovery phrase, off by default. Turn it on and a new phone can rebuild your balance by asking your mints which coins they signed (NUT-13 / NUT-09) | |
| π€ AI | Local assistant | On-device inference answers questions with zero network calls, data never leaves your device |
| π Social | AT Protocol | Opt-in bridge to Bluesky, using your Airhop identity |
| ActivityPub | Opt-in bridge to Mastodon, using your Airhop identity |
| Layer | Technology |
|---|---|
| Application Framework | React Native 0.86, Expo SDK 57 (bare workflow) |
| Network Transport | Bluetooth LE mesh (all platforms), Nostr relay bridge, plus an optional same-platform fast path: WiFi Aware between Android devices and MultipeerConnectivity between iPhones |
| Cryptographic Protocols | Noise XX handshake, Double Ratchet algorithm |
| Cryptographic Library | @noble/curves, @noble/ciphers, @noble/hashes (Cure53 audited) |
| Identity & Signatures | Ed25519 scheme |
| Network Privacy | Arti (iOS), Orbot (Android) |
| Payment System | Cashu ecash via @cashu/cashu-ts: offline transfer, NUT-12 DLEQ verification, NUT-13 recovery phrase, NUT-04 and NUT-05 Lightning, plus NIP-61 Nutzaps |
| State Management | Zustand store, MMKV storage |
| Key Storage | iOS Keychain, Android Keystore |
Airhop chooses a transport per message. Bluetooth is the only one that needs no internet and the only one that works across iOS and Android. WiFi and Nostr are used when they are available.
| Bluetooth LE mesh | WiFi (same platform) | Nostr relays | |
|---|---|---|---|
| Carries | Channel messages, DMs, files, ecash | DMs and files, when a link exists | DMs and geohash channel messages |
| Needs internet | No | No | Yes |
| Works iPhone to Android | Yes | No | Yes |
| Range | ~10-30 m indoors, up to ~100 m line of sight, extended by each hop | ~30 m | Global |
| Max hops | 7 | 1 | 1 |
| Speed | ~19 KB/s to one peer, ~16 KB/s to a channel | ~19 KB/s (shared with Bluetooth for now) | Not used for files |
| Latency per hop | 10-220 ms (randomised to avoid collisions) | n/a | Relay round trip; more over Tor |
Notes on the numbers:
- Text messages (channel and DM) are tiny and effectively instant on any transport. Throughput only matters for files.
- The ~19 KB/s figure is 467 bytes per fragment sent one every 25 ms. The delay is required: without it the radio drops fragments and the transfer never completes.
- A channel attachment paces at 30 ms instead (~16 KB/s), since each broadcast fragment requires one radio write per connected peer, increasing airtime usage as the room grows.
- WiFi currently shares that same paced queue, so it runs at the same speed as Bluetooth for now. [ Lifting the cap is planned ]
- A 1 MB file (the per-file cap) takes about 56 seconds to one peer. Attachments are capped at 1 MB for bitchat compatibility and to keep transfers short. [ Increasing the cap is planned ]
- Android WiFi Aware and iOS MultipeerConnectivity are different protocols and cannot connect to each other, so the WiFi path only works Android to Android or iPhone to iPhone.
- Nostr relays carry small signed events, not file bytes. Files can be shared over Nostr only by uploading them to a separate HTTP host and posting a link (NIP-96). Airhop does not do this: that host is a central server that can log, throttle, or take down your files, which is exactly what this app avoids. Attachments therefore travel only over Bluetooth or WiFi.
Timing intervals:
| Behaviour | Interval | Why |
|---|---|---|
| Presence broadcast | 4 s alone, 15-30 s | Fast while alone so devices meet quickly, then backs off |
| Gossip sync | 15 s | Lets a peer returning from out of range catch up on missed messages |
| Direct peer timeout | 45 s | Handles unreported link drops beyond broadcast |
| Mesh peer timeout | 60 s | Relayed peers get longer, since multi-hop packets arrive late |
| Geohash presence heartbeat | 40-80 s, randomised | Randomised so devices in one cell do not announce in lockstep |
| Geohash participant window | 5 min | How long a pubkey stays listed as present after its last event |
Offline and private messengers generally fall into three categories:
- Internet-only messaging apps that rely on online infrastructure and cannot communicate locally without internet access.
- Radio-based mesh networks that work offline but require dedicated hardware.
- Phone-to-phone mesh apps that use Bluetooth and WiFi on devices people already own.
Airhop belongs to the third category and extends it with a Nostr-based internet layer for long-distance communication when connectivity is available. The table is grouped in that order, starting with the apps most people already measure private messaging against.
| Project | Transport | Encryption | Works offline | Hardware-free | Open source | Platforms |
|---|---|---|---|---|---|---|
| Signal | Centralized servers | Signal protocol | β | β | β | iOS, Android, Desktop |
| Threema | Centralized servers | NaCl + Ibex | β | β | iOS, Android, Desktop | |
| Session | Onion routing (service nodes) | Session protocol | β | β | β | iOS, Android, Desktop |
| White Noise | Nostr relays | MLS (Marmot) | β | β | β | iOS, Android |
| Meshtastic | LoRa radio | AES-256 + Curve25519 PKI | β | β | β | iOS, Android, Web + hardware |
| goTenna | Proprietary sub-GHz radio | AES-256 + ECC-384 PKI | β | β | β | iOS, Android + hardware |
| Bridgefy | Bluetooth + WiFi | Signal (libsignal) | β | β | β | iOS, Android |
| Berty | Bluetooth + mDNS | Scuttlebutt + Ratchet | β | β | β | iOS, Android |
| Briar | Bluetooth + WiFi + Tor | Bramble | β | β | β | Android, Desktop |
| bitchat | Bluetooth + Nostr + Tor | Noise XX | β | β | β | iOS, Android |
| Airhop | Bluetooth + Nostr + WiFi + Tor | Noise XX + Double Ratchet | β | β | β | iOS, Android, Desktop, Web, CLI |
Signal and Threema are here as the benchmark rather than as alternatives. Both are excellent at what they do, and neither is trying to work without a network: Signal ties an account to a phone number and Threema to a Threema ID, and both stop entirely when the network does. Airhop is aimed at the moment after that, when there is no network to be excellent on.
git clone https://github.com/areebahmeddd/airhop
cd airhop
npm installCaution
Never run npx expo prebuild. The ios/ and android/ directories are checked in and hand-modified, and prebuild overwrites them.
Xcode setup
- Install Xcode from the Mac App Store, which also installs the iOS Simulator and base build tools
- Open Xcode at least once and let it install any additional required components when prompted
- Go to Xcode then Settings then Locations, and select the most recent version in the Command Line Tools dropdown
- Go to Xcode then Settings then Platforms, click the + icon, and add an iOS runtime if one is not already installed
- Install CocoaPods if it is not already present, then run
npx pod-installfrom the project root to install the iOS native dependencies. - Launch a simulator from the device dropdown, then run
npm run ios
The first
npm run iosbuilds the native app from scratch and can take several minutes. Later runs are much faster.
Requires a physical iPhone for BLE mesh testing (the iOS Simulator does not support Bluetooth) and supports iOS 16.0 or later.
Changing a native dependency also changes
ios/Podfile.lock, which pins exact pod versions. Regenerate it withnpx pod-installin the same commit.
If a build fails after changing dependencies, clear the Xcode and CocoaPods caches before trying again:
rm -rf ios/Pods ios/build ~/Library/Developer/Xcode/DerivedData/Airhop-*
npx pod-install
npm run iosAndroid Studio setup
- Install Android Studio from the official site, which also installs the Android SDK and base build tools
- Open Android Studio at least once and let the setup wizard install any additional required components when prompted
- Click the gear icon and open Settings, then go to Languages & Frameworks then Android SDK
- On the SDK Platforms tab, tick API 34, API 35, and API 36, then click Apply to download them, since a fresh install does not include them
- On the SDK Tools tab, confirm Android SDK Build-Tools, Android SDK Platform-Tools, and Android Emulator are installed
- Copy the SDK path shown at the top of the Android SDK page into an
ANDROID_HOMEenvironment variable, or intoandroid/local.propertiesassdk.dir=<path>, since Gradle looks there for it - Open the virtual device manager: More Actions then Virtual Device Manager from the Welcome screen, or View then Tool Windows then Device Manager if a project is already open
- Click Create Device, choose a Pixel 9 Pro profile, select one of the API levels just installed, then click Finish
- Launch the emulator from the device list, then run
npm run android
The first
npm run androidbuilds the native app from scratch and can take several minutes. Later runs are much faster.
Requires a physical Android device for BLE mesh testing (the Android Emulator does not support Bluetooth) and supports Android 8.0 (API 26) or later.
Changing a native dependency also changes
android/app/gradle.lockfile, which pins exact versions. Regenerate it in the same commit.
If a build fails after changing dependencies, clear the Gradle caches before trying again:
cd android && ./gradlew --stop
rm -rf ../node_modules/expo-modules-core/expo-module-gradle-plugin/{build,.gradle}
./gradlew app:dependencies --write-locks
./gradlew app:assembleDebug -Pkotlin.incremental=false
cd .. && npm run android| Document | Description |
|---|---|
| VISION.md | Why Airhop exists and what it will never compromise on |
| ROADMAP.md | Version targets (v0.5.0 to v2.0.0), and gap analysis |
| ARCHITECTURE.md | System architecture, design decisions, and stack rationale |
| PROTOCOLS.md | Wire format, BLE UUIDs, and protocol specifications |
| REFERENCE.md | Bitchat codebase deep dive and implementation reference |
| PROGRESS.md | Current build, development milestones, and known issues |
| GLOSSARY.md | Definitions of technical terms used throughout the documentation |
| CONTRIBUTING.md | Development workflow, coding standards, and pull request guidelines |
| SECURITY.md | Security policy and vulnerability reporting |
| CODE_OF_CONDUCT.md | Community standards and expectations |
Airhop would not exist without the work of the bitchat community. Thank you to everyone who built the foundation this project stands on. Their work is released into the public domain under the Unlicense.
| Person | Contribution |
|---|---|
| jackjackbits | Created bitchat-ios, designed the BLE mesh protocol and wire format |
| callebtc | Lead on bitchat-android, author of the Cashu ecash protocol |
| Nadim Kobeissi | Noise Protocol implementation in bitchat |
| a1denvalu3 | Built the georelays toolkit that produces assets/data/nostr_relays.csv |
Help keep the project going by donating via the website, sponsoring on GitHub, or simply giving this repository a star. What the project needs funding for is published as a funding.json manifest, following the funding.json standard.