peat-btle
BLE mesh transport that connects phones, watches, sensors, and embedded devices when there's no network infrastructure. Part of the Peat ecosystem.
Overview
When there's no WiFi, no cell service, and no satellite — BLE still works. peat-btle turns the Bluetooth radio in every phone, watch, and microcontroller into a mesh transport, enabling device-to-device coordination without any infrastructure. An Android phone running ATAK, a WearTAK watch, and an ESP32 sensor can all discover each other and sync state over BLE.
Key Features
- Cross-Platform: Linux, Android, iOS, macOS, Windows, ESP32
- Power Efficient: Designed for 18+ hour battery life on smartwatches
- Long Range: Coded PHY support for 300m+ range (BLE 5.0+)
- Mesh Topology: Hierarchical mesh with automatic peer discovery
- Efficient Sync: Delta-based CRDT synchronization over GATT
- Embedded Ready:
no_stdsupport for bare-metal targets
Why peat-btle?
Traditional BLE mesh implementations (like those in commercial sync SDKs) often suffer from:
| Problem | Impact | peat-btle Solution |
|---|---|---|
| Continuous scanning | 20%+ radio duty cycle | Batched sync windows (<5%) |
| Gossip-based discovery | All devices advertise constantly | Hierarchical discovery (leaf nodes don't scan) |
| Full mesh participation | Every device relays everything | Lite profile (minimal state, single parent) |
| Result | 3-4 hour watch battery | 18-24 hour battery life |
Platform Support
Pre-release: This crate is under active development. APIs may change.
| Platform | Status | Notes |
|---|---|---|
| Linux (BlueZ 5.48+) | Stable | Ubuntu, Raspberry Pi tested |
| macOS | Stable | CoreBluetooth, tested with ESP32 peers |
| Android 6+ | Stable | WearOS support, UniFFI bindings |
| ESP32 (NimBLE) | Stable | 50+ examples, Feather Sense, M5Stack |
| iOS 13+ | Beta | CoreBluetooth partial — service discovery and characteristic callbacks incomplete |
| Windows 10+ | Planned | WinRT adapter exists, not yet tested |
Installation
Add to your Cargo.toml:
[]
= { = "0.1", = ["linux"] }
Feature Flags
| Feature | Description |
|---|---|
std (default) |
Standard library support |
linux |
Linux/BlueZ support via bluer |
android |
Android support via JNI |
ios |
iOS support via CoreBluetooth |
macos |
macOS support via CoreBluetooth |
windows |
Windows support via WinRT |
embedded |
Embedded/no_std support |
esp32 |
ESP32 support via ESP-IDF |
coded-phy |
Enable Coded PHY for extended range |
extended-adv |
Enable extended advertising |
Quick Start
use ;
async
Architecture
Standalone vs HIVE Integration
peat-btle is designed for dual use:
- Standalone: Pure embedded mesh (ESP32/Pico devices) without any full HIVE nodes
- HIVE Integration: BLE transport for full HIVE nodes, with gateway translation to Automerge
┌─────────────────────────────────────────────────────────────────────────┐
│ HIVE Integration Mode │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Full HIVE Node (Phone) │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ AutomergeIroh │ │ │
│ │ │ (Full CRDT documents) │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ ↕ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ Translation Layer (HIVE repo) │ │ │
│ │ │ Maps: Automerge ↔ peat-btle lightweight │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ ↕ │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ peat-btle │ │ │
│ │ │ (BLE transport + lightweight CRDTs) │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────────────────┘ │
│ ↕ BLE │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ Embedded Node (ESP32/Pico) │ │
│ │ peat-btle │ │
│ │ (standalone, lightweight CRDTs) │ │
│ └───────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
Why two modes? Automerge is too resource-intensive for embedded targets (requires ~10MB+ RAM, std library). peat-btle's lightweight CRDTs (GCounter, Peripheral) provide the same semantics in <256KB RAM. Full HIVE nodes translate between formats.
Component Architecture
┌─────────────────────────────────────────────────────────────┐
│ Application │
├─────────────────────────────────────────────────────────────┤
│ BluetoothLETransport │
│ (MeshTransport trait implementation) │
├──────────────┬──────────────┬──────────────┬────────────────┤
│ Discovery │ GATT │ Mesh │ Power │
│ (Beacon, │ (Service, │ (Topology, │ (Scheduler, │
│ Scanner) │ Protocol) │ Routing) │ Profiles) │
├──────────────┴──────────────┴──────────────┴────────────────┤
│ BleAdapter Trait │
├──────────┬──────────┬──────────┬──────────┬─────────────────┤
│ Linux │ Android │ iOS │ Windows │ ESP32 │
│ (BlueZ) │ (JNI) │(CoreBT) │ (WinRT) │ (NimBLE) │
└──────────┴──────────┴──────────┴──────────┴─────────────────┘
Core Components
| Component | Description |
|---|---|
| Discovery | Peat beacon format, scanning, and advertising |
| GATT | BLE service definition and sync protocol |
| Mesh | Topology management and message routing |
| PHY | Physical layer configuration (1M, 2M, Coded) |
| Power | Radio scheduling and battery optimization |
| Sync | Delta-based CRDT synchronization |
Power Profiles
| Profile | Radio Duty | Sync Interval | Watch Battery* |
|---|---|---|---|
| Aggressive | 20% | 1 second | ~6 hours |
| Balanced | 10% | 5 seconds | ~12 hours |
| LowPower | 2% | 30 seconds | ~20 hours |
| UltraLow | 0.5% | 2 minutes | ~36 hours |
*Estimated for typical smartwatch (300mAh battery)
GATT Service
peat-btle defines a custom GATT service for mesh communication:
| UUID | Characteristic | Description |
|---|---|---|
0xF47A |
Service | Peat BLE Service (16-bit short form) |
0x0001 |
Node Info | Node ID, capabilities, hierarchy level |
0x0002 |
Sync State | Vector clock and sync metadata |
0x0003 |
Sync Data | CRDT delta payloads (chunked) |
0x0004 |
Command | Control commands (connect, disconnect, etc.) |
0x0005 |
Status | Connection status and errors |
Mesh-Wide Encryption
peat-btle supports optional mesh-wide encryption using ChaCha20-Poly1305 AEAD. When enabled, all documents are encrypted before transmission, providing confidentiality across multi-hop BLE relay.
Enabling Encryption
use ;
// Create a 32-byte shared secret (distribute securely to all mesh nodes)
let secret: = ; // Use a real secret in production!
// Configure mesh with encryption
let config = new
.with_encryption;
let mesh = new;
// All documents sent through this mesh are now encrypted
let encrypted_doc = mesh.build_document;
How It Works
- Algorithm: ChaCha20-Poly1305 authenticated encryption
- Key Derivation: HKDF-SHA256 from shared secret + mesh ID
- Overhead: 30 bytes per document (2 marker + 12 nonce + 16 auth tag)
- Wire Format:
ENCRYPTED_MARKER (0xAE) | reserved | nonce | ciphertext
Multi-Hop Security
Node A ──encrypted──> Node B (relay) ──encrypted──> Node C
│
Can forward but
only decrypts if
has formation key
Nodes without the shared secret can relay encrypted documents but cannot read their contents. This provides end-to-end confidentiality even across untrusted relay nodes.
Backward Compatibility
- Encrypted nodes can receive unencrypted documents (for gradual rollout)
- Unencrypted nodes will reject encrypted documents they can't decrypt
Per-Peer E2EE (End-to-End Encryption)
For sensitive communications, peat-btle supports per-peer end-to-end encryption using X25519 key exchange and ChaCha20-Poly1305. Unlike mesh-wide encryption where all formation members share a key, per-peer E2EE ensures only the sender and recipient can decrypt messages—even other mesh members cannot read them.
Enabling Per-Peer E2EE
use ;
// Create mesh instances
let config1 = new;
let mesh1 = new;
let config2 = new;
let mesh2 = new;
// Enable E2EE on both nodes (generates identity keys)
mesh1.enable_peer_e2ee;
mesh2.enable_peer_e2ee;
// Initiate E2EE session from mesh1 to mesh2
let key_exchange1 = mesh1.initiate_peer_e2ee.unwrap;
// Send key_exchange1 to mesh2 over BLE...
// mesh2 handles incoming key exchange and responds
let key_exchange2 = mesh2.handle_key_exchange.unwrap;
// Send key_exchange2 back to mesh1...
// mesh1 completes the handshake
mesh1.handle_key_exchange;
// Session established! Now send encrypted messages
let encrypted = mesh1.send_peer_e2ee.unwrap;
// Send encrypted to mesh2...
// mesh2 decrypts
let plaintext = mesh2.handle_peer_e2ee_message.unwrap;
assert_eq!;
How It Works
- Key Exchange: X25519 Diffie-Hellman to establish a shared secret
- Key Derivation: HKDF-SHA256 binds the session key to both node IDs
- Encryption: ChaCha20-Poly1305 AEAD with replay protection
- Wire Format:
PEER_E2EE_MARKER (0xAF) | reserved | recipient | sender | counter | nonce | ciphertext
Security Properties
| Property | Description |
|---|---|
| Forward Secrecy | Ephemeral keys can be used for session establishment |
| Replay Protection | Monotonic counters prevent message replay attacks |
| Authentication | Poly1305 MAC ensures message integrity |
| Confidentiality | Only sender and recipient can decrypt |
Overhead
Per-peer E2EE adds 46 bytes overhead per message:
- 2 bytes: Marker header
- 4 bytes: Recipient node ID
- 4 bytes: Sender node ID
- 8 bytes: Counter (replay protection)
- 12 bytes: Nonce
- 16 bytes: Authentication tag
Use Cases
- Sensitive Commands: Squad leader → specific soldier
- Private Messages: Point-to-point communication within formation
- Credential Exchange: Secure key material distribution
Encryption Layers
┌─────────────────────────────────────────────────────────────────┐
│ Phase 1: Mesh-Wide (Formation Key) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ All formation members can decrypt │ │
│ │ Protects: External eavesdroppers │ │
│ │ Overhead: 30 bytes │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │
│ Phase 2: Per-Peer E2EE (Session Key) │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ Only sender + recipient can decrypt │ │
│ │ Protects: Other mesh members, compromised relays │ │
│ │ Overhead: 46 bytes │ │
│ └─────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
Device Identity
peat-btle provides cryptographic device identity using Ed25519 keypairs. Each device generates a persistent identity that binds its node ID to a public key, preventing impersonation attacks.
Creating a Device Identity
use ;
// Generate a new device identity
let identity = generate;
// The node_id is derived from the public key (collision-resistant)
let node_id = identity.node_id;
let public_key = identity.public_key;
// Create a signed attestation proving ownership of this identity
let attestation = identity.create_attestation;
// Verify an attestation from another device
if attestation.verify
Identity Attestation
When nodes communicate, they exchange signed attestations proving they control their claimed node ID:
| Field | Size | Description |
|---|---|---|
node_id |
4 bytes | Claimed node identifier |
public_key |
32 bytes | Ed25519 public key |
timestamp_ms |
8 bytes | Attestation creation time |
signature |
64 bytes | Ed25519 signature over all fields |
Mesh Genesis
New meshes are created through a genesis protocol that establishes cryptographic roots:
use ;
// Create founder's identity
let founder = generate;
// Create a new mesh
let genesis = create;
// Get derived values
let mesh_id = genesis.mesh_id; // e.g., "A1B2C3D4"
let secret = genesis.encryption_secret; // 32-byte derived key
let beacon_key = genesis.beacon_key_base; // For encrypted beacons
// Create shareable credentials for other nodes
let credentials = from_genesis;
Membership Policies
| Policy | Description |
|---|---|
Open |
Anyone with mesh_id can attempt to join (demos, open networks) |
Controlled |
Explicit enrollment by authority required (default) |
Strict |
Only pre-provisioned devices can join (high security) |
Genesis Data
The genesis contains all cryptographic material to bootstrap a mesh:
- mesh_seed: 256-bit CSPRNG seed (root secret)
- mesh_id: 8 hex chars derived from name + seed
- encryption_secret: HKDF-derived key for mesh-wide encryption
- beacon_key_base: HKDF-derived key for encrypted advertisements
- creator_identity: Founder's DeviceIdentity (initial authority)
BLE Pairing Attack Resilience
Threat: Attacks like WhisperPair (CVE-2024-XXXXX) can downgrade BLE pairing security by manipulating the key exchange timing, resulting in weaker session keys.
PEAT-BTLE Mitigation: BLE link security is not the trust boundary.
-
Discovery-only dependency: Peat uses BLE for proximity detection and initial rendezvous. Security-critical operations require application-layer authentication per ADR-006.
-
PKI verification: Device identity is established via Ed25519 keypairs, verified at connection establishment before any CRDT sync occurs.
-
Mesh-wide encryption: ChaCha20-Poly1305 encrypts all sync payloads regardless of BLE security level.
-
Defense in depth: Even a fully compromised BLE link exposes only encrypted, authenticated traffic that cannot be injected into the Peat mesh.
Recommendation: For maximum security, enable mesh-wide encryption (default in
MeshGenesis) and consider per-peer E2EE for sensitive operations.
Platform Requirements
Linux
- BlueZ 5.48 or later
- D-Bus system bus access
- Bluetooth adapter with BLE support
# Check BlueZ version
# Ensure bluetooth service is running
Android
- Android 6.0 (API 23) or later
BLUETOOTH,BLUETOOTH_ADMIN,ACCESS_FINE_LOCATIONpermissions- For BLE 5.0 features: Android 8.0 (API 26) or later
iOS
- iOS 13.0 or later
NSBluetoothAlwaysUsageDescriptionin Info.plist- CoreBluetooth framework
Examples
See the examples/ directory:
linux_scanner.rs- Scan for Peat nodes on Linuxlinux_advertiser.rs- Advertise as an Peat nodemesh_demo.rs- Two-node mesh demonstration
Run examples with:
Testing
# Run unit tests (no hardware required)
# Run with Linux platform tests (requires Bluetooth adapter)
# Run specific test module
Contributing
Contributions are welcome! Priority areas:
- Android Implementation - JNI bindings to Android Bluetooth API
- Windows Implementation - WinRT Bluetooth APIs
- Hardware Testing - Real-world validation on various devices
Please see CONTRIBUTING.md for guidelines.
License
Licensed under the Apache License, Version 2.0. See LICENSE for details.
Acknowledgments
Developed by (r)evolve - Revolve Team LLC as part of the HIVE Protocol project.