Offline Mesh Networking

When the internet goes down, messages still get through.

Why Offline Mesh

Internet shutdowns are a tool of authoritarian regimes. During protests, elections, and political crises, governments routinely disable mobile data, block specific apps, or shut down the internet entirely. In these scenarios, RVNT's offline mesh mode enables encrypted messaging over Bluetooth and WiFi Direct -- technologies that do not require internet infrastructure.

Offline mesh is also useful in:

  • Natural disasters where cellular infrastructure is destroyed
  • Remote areas without cellular coverage
  • Conferences or events where you want to communicate without any network dependency
  • Air-gapped environments where internet access is prohibited

Mesh Technologies

Apple: Multipeer Connectivity

Framework:    MultipeerConnectivity.framework
Platforms:    iOS 7+, macOS 10.10+
Transport:    Bluetooth LE + WiFi (infrastructure or peer-to-peer)
Range:        Bluetooth: ~10-30 meters
              WiFi Direct: ~50-100 meters
Max peers:    8 simultaneous connections
Throughput:   ~2-5 Mbps (WiFi), ~200 Kbps (BLE)
Discovery:    Bonjour-based service advertising

Service configuration:
  Service type:  "rvnt-mesh"
  Peer ID:       Random UUID (regenerated per session)
  Discovery info: { "v": "1", "pk": truncated_peer_key }

Android: Wi-Fi Aware (Neighbor Awareness Networking)

API:          WifiAwareManager (Android 8.0+)
Transport:    Wi-Fi NAN (2.4 GHz and 5 GHz)
Range:        ~50-100 meters
Max peers:    Platform-dependent (typically 8-16)
Throughput:   ~5-20 Mbps
Discovery:    Service-based (publish/subscribe)

Fallback: Bluetooth LE (Android 5.0+)
  Range:        ~10-30 meters
  Throughput:   ~200 Kbps
  Connection:   GATT server/client model

Encrypted Envelope Format

Messages sent over the mesh use the same encryption as internet-based messages. The Double Ratchet session state is shared between online and offline modes -- there is no separate "mesh session."

Mesh envelope format:

  MeshEnvelope {
      version:       u8           // 0x01
      hop_count:     u8           // Current hop count (0 = direct)
      max_hops:      u8           // Maximum allowed hops (default: 5)
      ttl:           u32          // Time-to-live in seconds (default: 3600)
      created_at:    u64          // Unix timestamp (for TTL calculation)
      envelope_id:   [16 bytes]   // Random ID (for deduplication)
      sealed_envelope: [variable] // Standard SealedSenderEnvelope
  }

  The sealed_envelope field is identical to the envelope used
  for internet-based messaging. Same encryption, same sealed
  sender, same padding. The only difference is the transport.

  Mesh-specific fields:
    hop_count:  Incremented at each relay. Prevents infinite loops.
    max_hops:   Configurable. Higher = more reach, more latency.
    ttl:        Messages expire after TTL seconds. Prevents old
                messages from circulating indefinitely.
    envelope_id: Used for deduplication. Each relay tracks recently
                 seen IDs and drops duplicates.

Store-and-Forward Routing

If the intended recipient is not in direct radio range, intermediate devices can relay the encrypted envelope. This is store-and-forward routing: a relay device stores the message temporarily and forwards it when it encounters the recipient (or another relay closer to the recipient).


  Alice ---- BLE ---- Charlie ---- WiFi ---- Dave ---- BLE ---- Bob
  (sender)           (relay)              (relay)           (recipient)

  1. Alice sends MeshEnvelope to all nearby peers
  2. Charlie receives it. Charlie is not the recipient.
     Charlie stores the envelope and broadcasts to nearby peers.
     Charlie increments hop_count.
  3. Dave receives it. Dave is not the recipient.
     Dave stores and forwards, increments hop_count.
  4. Bob receives it. Bob's recipient_id matches.
     Bob decrypts the sealed envelope normally.

  Charlie and Dave CANNOT:
    - Read the message (sealed sender + Double Ratchet encryption)
    - Identify the sender (sealed sender)
    - Determine the recipient (recipient_id is a truncated hash)
    - Modify the message (AES-256-GCM authentication)
  

Relay Policy

Relay behavior:
  - Store up to 100 mesh envelopes (LRU eviction)
  - Forward to all nearby peers every 30 seconds
  - Drop envelopes where hop_count >= max_hops
  - Drop envelopes where created_at + ttl < now()
  - Drop duplicate envelope_ids (deduplication cache: 1000 IDs)
  - Relay operates even when RVNT is in background (platform-dependent)

Storage:
  - Relay envelopes stored in memory only (not persisted to disk)
  - If app is terminated, relayed envelopes are lost
  - This is intentional: reduces forensic exposure on relay devices

Privacy Protections

Random Peer ID Per Session

Problem:
  Bluetooth and WiFi Direct use persistent device identifiers
  (MAC address, device name) that could be used to track users.

Solution:
  RVNT generates a random UUID as its mesh peer ID for each session.
  The peer ID changes every time the app restarts or every 30 minutes
  (whichever comes first).

  Session 1: PeerId = "a3b2c1d4-..."
  Session 2: PeerId = "f7e8d9c0-..."  (completely different)

  An observer scanning for Bluetooth devices will see a new identity
  each session. They cannot correlate sessions to the same user
  based on the peer ID alone.

Limitations:
  - Bluetooth MAC address randomization depends on the OS
  - iOS: randomizes MAC for BLE advertising (good)
  - Android: randomizes MAC for BLE scanning, but not always for
    Wi-Fi Aware (varies by device/OS version)
  - Device hardware fingerprinting may still be possible
    (BLE signal characteristics, etc.)

No Contact Discovery Over Mesh

The mesh layer does NOT perform contact discovery.
  - You cannot search for users over the mesh
  - You cannot browse nearby RVNT users
  - The mesh only delivers messages to known contacts
  - Contact exchange must happen before going offline
    (QR code, username lookup, direct connect)

This prevents:
  - Proximity-based surveillance ("who in this crowd uses RVNT?")
  - Contact graph leakage over the mesh
  - Mesh-based MITM on initial key exchange

Battery Policy

Mesh networking is battery-intensive. RVNT adapts:

  Battery > 50%:
    - Full mesh operation (BLE + WiFi)
    - Relay enabled
    - Scan interval: 10 seconds

  Battery 20-50%:
    - BLE only (lower power than WiFi)
    - Relay enabled (reduced: max 50 stored envelopes)
    - Scan interval: 30 seconds

  Battery < 20%:
    - BLE only
    - Relay disabled (only direct messages)
    - Scan interval: 60 seconds

  Battery < 10%:
    - Mesh networking suspended
    - Resume when charging or battery > 15%

  User override:
    Settings > Mesh > Battery Policy > Always On
    (ignores battery level, use at own risk)

Limitations

  • Range: Bluetooth: 10-30m, WiFi Direct: 50-100m. Without relays, you must be physically close.
  • Latency: Store-and-forward adds unpredictable delay. Messages may take minutes or hours to reach recipients via multi-hop relay.
  • Reliability: No delivery guarantee. If no relay path exists, the message is lost when it expires (TTL).
  • Throughput: Not suitable for large file transfers over Bluetooth. Small files (under 1 MB) work; large files should use WiFi Direct.
  • Proximity attacks: An adversary in physical proximity can detect that RVNT mesh traffic is present, even if they cannot read it.
  • Platform restrictions: Background BLE operation is limited by iOS (requires Bluetooth background mode entitlement) and Android (Doze mode, background execution limits).

Further Reading

Last updated: 2026-04-12

RVNT Documentation — Post-quantum encrypted communications