Active DevelopmentSystemsSecurity

Emergency Mesh

Offline emergency communication. Phones exchange messages directly over Bluetooth Low Energy, relaying for each other, with no internet, no cell service and no server anywhere in the path.

FlutterDartKotlinBLECrypto
Private repository

The problem

When there is no internet, no cell service and no server, delivery stops being a request and becomes a scheduling problem: the peer you need may simply not be in range at the moment you press send.

Context and constraints

An offline messaging app for situations where infrastructure is gone. Phones talk directly to each other over Bluetooth Low Energy, carry messages for one another, and hold what they cannot yet deliver. There is no server anywhere in the design, which is a product rule rather than a deployment choice.

  • Bluetooth Low Energy has a small MTU, so anything larger than a few dozen bytes has to be fragmented and reassembled below the protocol layer.
  • A peer may be out of range at the moment of sending, so the transport cannot assume a destination exists when a message is created.
  • Mobile operating systems suspend background work aggressively, so keeping a radio available means a foreground service rather than a background task.
  • There is no server to hold identity, so keys and identities are generated and stored locally on each device.
  • Anything persisted on a device that might be lost has to be encrypted at rest.

What I built

A wire format, a cryptographic suite and an encrypted local store, all implemented and tested without hardware. On top of them, mesh routing and custody logic, and a native Kotlin Bluetooth transport covering advertising and scanning, a GATT server and client with MTU negotiation, connection ranking and retry, fragmentation and reassembly, and a foreground service that keeps the radio alive while the app is backgrounded. The Flutter application composes, signs and verifies real frames over that transport.

Architecture

A Flutter application over a native Bluetooth transport, with the protocol, cryptography and persistence layers deliberately independent of the radio so they can be tested without a device.

composesigndispatchqueuepersistsendtransmitFlutter appChat, people, SOSFrame layerCompose, sign, verifyCrypto suiteLocal identity keysMesh serviceRouting and custodyOutbox schedulerRetry and expiryEncrypted storeAt rest on devicePlatform channelDart to KotlinKotlin BLEGATT, fragmentation
Sanitized architecture from the project documentation. No identity, key material or test artifact is reproduced.
Flutter app
Chat, people, SOS
Frame layer
Compose, sign, verify
Crypto suite
Local identity keys
Mesh service
Routing and custody
Outbox scheduler
Retry and expiry
Encrypted store
At rest on device
Platform channel
Dart to Kotlin
Kotlin BLE
GATT, fragmentation

My contribution

Sole engineer. Wire format, cryptographic suite, encrypted local store, routing and custody logic, the native Bluetooth transport, and the Flutter application on top.

What actually happens on the radio

A walkthrough of the documented behaviour across three devices. Every step states whether it runs on real hardware, exists only in the simulator, or is not built — because the difference between those three is the whole point of this section.

Illustrative protocol simulation, not a recording of deployed hardware. The unreachable device is drawn that way permanently and on purpose: no sequence of steps here completes a multi-hop delivery, because the implementation cannot.

Technical decisions

What was chosen, why, and what it cost.

Keep the protocol independent of the radio

Decision
The wire format, cryptographic suite, encrypted store and mesh logic were built and tested with no device involved, behind a platform channel that the native transport implements.
Why
Bluetooth work needs two physical phones, which makes it slow and hard to test. Everything above the transport could be developed and verified without that cost.
Trade-off
A layer verified only against its own contract can still be wrong about the radio underneath it, which is exactly the gap the outstanding device-verification task exists to close.

Use a foreground service to keep the radio alive

Decision
Scanning, advertising and connection handling run inside a foreground service rather than a background task.
Why
Mobile operating systems suspend background work aggressively, and a mesh node that stops listening when the screen locks is not a mesh node.
Trade-off
A persistent notification and a real battery cost, which for a general-purpose app would be unacceptable and for an emergency tool is the point.

No server anywhere, including for errors

Decision
There is no backend for identity, delivery or even crash reporting; error handling is local by default.
Why
A tool whose premise is that infrastructure has failed cannot have a mandatory server, and that rule was applied consistently rather than only to the message path.
Trade-off
No remote diagnostics, so a failure in the field cannot be investigated after the fact unless the device is in hand.

Label the in-app mesh demo as a simulation

Decision
The application includes a demo screen that replays a simulator run as an animated topology, explicitly labelled as simulation, and it drives the same routing code the real path uses.
Why
A demo that looks like live mesh traffic when it is not would misrepresent the project to exactly the people most likely to be impressed by it.
Trade-off
The most visually convincing screen in the app is the one that carries a disclaimer.

Security and reliability

The failure modes that shaped the implementation.

Encrypted at rest

Messages, contacts and identity material are held in an encrypted local store, on the assumption that a device in an emergency is a device that might be lost.

Inbound frames are verified before they are trusted

Frames are signed on composition and verified on arrival, so anything that reaches the contact or message stores has been checked rather than merely received.

Delivery is never claimed without an acknowledgement

Direct messages are marked delivered only on a real acknowledgement. An SOS broadcast has no acknowledgement mechanism, so the interface deliberately does not tell the user it reached anyone.

Verification

How the implementation was checked, and how much of that can be shown publicly.

  • 62 native unit tests on the Bluetooth layerevidenced

    The Kotlin transport is covered by 62 unit tests and verified by compilation and packaging.

  • The native stack has not been verified on a devicenot publicly evidenced

    The final transport task requires two physical phones and has not been completed. Everything below the application layer is therefore verified against its own tests and contracts, not against hardware.

  • Single-hop exchange confirmed between two phonesevidenced

    Two devices directly in range exchange real signed frames: contacts populate from genuine announcements, and a one-to-one conversation sends, receives and acknowledges over live Bluetooth.

  • Mesh behaviour beyond one hop exists only in simulationnot publicly evidenced

    The simulator drives the same routing code as the real path, but a passing simulation is not evidence of hardware behaviour and is not presented as such.

Results

  • The protocol, cryptography, persistence and routing layers are implemented and tested without hardware, and the native Bluetooth transport is implemented in Kotlin with unit tests.
  • Two phones directly in range exchange real signed frames today, including a working one-to-one conversation with acknowledgement and store-and-forward retry.
  • Multi-hop relay — the defining behaviour of a mesh — is not implemented, and the final device-verification task for the native transport remains open.

Limitations and disclosure

What this project does not do, and what cannot be shown publicly.

  • Protocol, routing, cryptography, persistence and the native BLE transport are built and tested, but the user interface is at an early stage.
  • Not yet installable as a finished product, and not suitable for real emergencies.

The repository is private. No identity, key material, test artifact or captured traffic is reproduced here. The distinction between what runs on hardware, what exists only in simulation and what is not built is taken directly from the project's own status record rather than inferred.

Other projects in the same engineering domains.