Inspiration

We wanted to build a communication tool that works in environments where infrastructure fails (e. g. festivals, protests, natural disasters, crowded events with saturated networks). We researched peer-to-peer Bluetooth mesh protocols and found that most existing solutions either required WiFi, a central server, or proprietary hardware. We built the version that didn't.

What it does

  • Broadcasts messages to every device in the mesh, useful for announcements or finding people in a crowd
  • Direct encrypted messages to contacts added via QR code scan, end-to-end encrypted using NaCl
  • Topic channels: subscribe to a named channel like mainstage and see every message sent to that name, no invite needed
  • Meeting points: drop a pin on a map and send it to a contact over the mesh; the app notifies them automatically when you arrive within 15 metres using GPS geofencing Everything works with zero internet, zero servers, zero accounts your identity is a nickname and a cryptographic keypair generated on your device

How we built it

  • React Native + Expo for cross-platform mobile (iOS + Android)
  • Bluetooth Low Energy dual-role : every phone simultaneously advertises as a GATT peripheral and scans as a central, creating a fully connected mesh of direct BLE links
  • Custom native modules for iOS and Android to run the BLE peripheral/advertising layer, which React Native libraries alone can't handle
  • Flooding with TTL deduplication as the mesh routing algorithm: Every packet carries a 4-char ID, each node relays it once and drops duplicates via a seen-cache with a 60-second expiry
  • Haversine formula for GPS-based arrival detection on meeting points

Challenges we ran into

  • iOS BLE peripheral restrictions: iOS doesn't allow advertising a GATT server the standard way when the app is backgrounded, requiring a custom native Expo module and specific entitlements. Background scanning is also throttled.
  • MTU limitations: BLE packets have a small max payload (~512 bytes after MTU negotiation on Android, less on iOS), requiring us to keep packets compact enough to fit in a single write
  • Build times: native modules (Kotlin + Swift) require full native builds; no Expo Go support, every change needed a device rebuild
  • Loop prevention: without the seen-cache, a single broadcast would bounce infinitely between nodes. Getting the deduplication + TTL logic right across concurrent BLE connections was non-trivial. ## Accomplishments that we're proud of
  • A fully working serverless mesh: messages genuinely hop multiple devices to reach a recipient out of direct range
  • End-to-end encryption that requires zero manual key exchange. Keys propagate automatically through packet metadata
  • A clean layered architecture (transport → router → UI) with interface contracts, making the routing logic fully testable without any BLE hardware

What we learned

  • BLE dual-role (central + peripheral simultaneously) and GATT server architecture on iOS and Android
  • Epidemic routing algorithms and the tradeoffs vs. more sophisticated protocols like AODV or DSR
  • Writing custom native Expo modules in Swift and Kotlin to expose hardware APIs not available in JS NaCl box cryptography and passive key distribution in a trustless peer-to-peer network

What's next for Toot

  • Probabilistic/gossip relay to replace pure flooding and reduce BLE bandwidth consumption in dense crowds
  • Delivery acknowledgements: Currently, there is no confirmation that a message reached its destination
  • Add private Groupchats features (Not the same as the Topic feature, because topics can be accessed by anyone)
  • SOS broadcast — a high-priority packet type with maximum TTL that pre-empts normal routing

Built With

Share this project:

Updates