Skip to content

IFM Protocol Specification

Version

v0.1 Draft — This specification is a work in progress.


Overview

IFM is a packet-based broadcast protocol over a decentralized mesh network. Unlike streaming protocols, everything in IFM is represented as discrete packets with metadata. Applications needing continuous media (voice, video) send packets at regular intervals.

Key Properties

  • Binary format — Compact, fast serialization
  • Signed packets — Every packet authenticated via Ed25519
  • TTL-limited — Packets expire after 16 hops
  • Deduplicated — BLAKE3 packet IDs prevent replay
  • Transport-agnostic — Works over QUIC, WebRTC, TCP

Companion document: Station Discovery & Relay Protocol — how stations are announced/found and relays are scored/selected without a central server.


Wire Format

All packets use a binary encoding (bincode-compatible). The on-wire format:

Field Definitions

FieldTypeSizeDescription
versionu81 byteProtocol version (current: 1)
frequency[u8; 32]32 bytesBLAKE3 hash of canonical frequency identifier
packet_id[u8; 32]32 bytesBLAKE3 hash of entire packet (minus signature)
sender[u8; 32]32 bytesSender's Ed25519 public key
timestampu648 bytesUnix milliseconds since epoch
ttlu81 byteTime-to-live in hops (default: 16)
sequenceu648 bytesMonotonically increasing per-sender sequence
payload_typeu81 byteSee Payload Types table
payload_lengthu324 bytesLength of payload in bytes
payloadVec<u8>VariableEncrypted/compressed payload data
signature[u8; 64]64 bytesEd25519 signature over all above fields

Payload Types

ValueConstantDescription
0x00TEXTUTF-8 text message
0x01VOICEOpus-encoded audio frame (20ms)
0x02VIDEOVideo frame (codec indicated in payload)
0x03IMAGEImage data (format in payload header)
0x04FILEFile chunk (see File Transfer)
0x05JSONStructured JSON data
0x06PINGKeepalive / latency probe
0x07PRESENCEPresence update (join/leave/status)
0x08CONTROLProtocol control messages
0x09PLUGINPlugin-specific payload

Packet Types (Control Messages)

Control messages use payload_type = CONTROL (0x08) with a JSON payload:

json
{
  "type": "HELLO | WELCOME | JOIN | LEAVE | ANNOUNCE | PING | PONG",
  "data": { ... }
}

HELLO

Sent when tuning to a frequency to announce presence.

json
{
  "type": "HELLO",
  "data": {
    "node_id": "12D3KooW...",
    "display_name": "optional name",
    "capabilities": ["voice", "chat", "file"],
    "frequencies": ["91.700", "chat.general"]
  }
}

WELCOME

Response to HELLO from peers already on the frequency.

json
{
  "type": "WELCOME",
  "data": {
    "node_id": "12D3KooW...",
    "peer_count": 42,
    "frequency_metadata": {
      "name": "General Chat",
      "description": "Main discussion channel",
      "language": "en",
      "encryption": "none"
    }
  }
}

JOIN

Explicit join request (for protected/hidden frequencies).

json
{
  "type": "JOIN",
  "data": {
    "frequency": "private.team",
    "key_proof": "optional cryptographic proof of key possession"
  }
}

LEAVE

Graceful departure from a frequency.

json
{
  "type": "LEAVE",
  "data": {
    "frequency": "91.700",
    "reason": "user_left | timeout | error"
  }
}

ANNOUNCE

Frequency metadata broadcast (periodic or on change).

json
{
  "type": "ANNOUNCE",
  "data": {
    "frequency": "91.700",
    "metadata": {
      "name": "Music Lounge",
      "description": "Lo-fi beats",
      "listener_count": 128,
      "capabilities": ["voice", "music"]
    }
  }
}

PING / PONG

Latency measurement and keepalive.

json
{ "type": "PING", "data": { "timestamp": 1699999999999, "nonce": "abc123" } }
{ "type": "PONG", "data": { "original_timestamp": 1699999999999, "nonce": "abc123" } }

Packet ID Generation

packet_id = BLAKE3(
  version ||
  frequency ||
  sender ||
  timestamp ||
  ttl ||
  sequence ||
  payload_type ||
  payload_length ||
  payload
)

Properties:

  • Deterministic — same packet always produces same ID
  • Collision-resistant — 256-bit output
  • Enables duplicate detection without storing full packets
  • Used for deduplication cache keys

Packet Lifetime (TTL)

  • Initial TTL: 16 hops
  • Decrement: Each relay decrements by 1
  • Expiry: Packet discarded when TTL reaches 0
  • Purpose: Prevents infinite circulation, bounds network diameter

Broadcast Mechanism (GossipSub)

IFM uses libp2p GossipSub for mesh broadcast:

1. Node creates packet, signs it
2. Publishes to GossipSub topic = frequency hash
3. GossipSub delivers to mesh peers (fanout=6)
4. Each peer:
   a. Verifies signature (Ed25519)
   b. Checks TTL > 0
   c. Checks packet_id not in dedup cache
   d. Adds to local cache
   e. Forwards to its mesh peers (TTL - 1)
5. Recipients decode and deliver to application

GossipSub Parameters

ParameterValueDescription
fanout6Number of peers to forward to
mesh_n6Target mesh degree
mesh_n_low4Minimum mesh degree
mesh_n_high12Maximum mesh degree
gossip_factor0.25Percentage of mesh to gossip to

Frequency Resolution

Human Frequency → Topic ID

Frequency Types & Canonical Prefixes

TypePrefixExampleEncryption
Publicifm://public/ifm://public/91.700None
Protectedifm://protected/ifm://protected/team.alphaChaCha20-Poly1305
Hiddenifm://hidden/ifm://hidden/game.room.42ChaCha20-Poly1305

Serialization

Binary Encoding (bincode)

  • Little-endian
  • Fixed-size integers
  • Length-prefixed variable data
  • No schema in band — schema defined by protocol version

Example: Minimal TEXT Packet (hex)

01                                              # version = 1
abcdef... (32 bytes)                           # frequency hash
123456... (32 bytes)                           # packet_id
fedcba... (32 bytes)                           # sender public key
00 00 00 00 00 65 4a 8b                        # timestamp (little-endian u64)
10                                             # ttl = 16
00 00 00 00 00 00 00 01                        # sequence = 1
00                                             # payload_type = TEXT (0)
05 00 00 00                                    # payload_length = 5
48 65 6c 6c 6f                                 # payload = "Hello"
9a 8b 7c... (64 bytes)                         # Ed25519 signature

Versioning

  • version field in packet header
  • Current version: 1
  • Breaking changes increment version
  • Nodes MUST reject packets with unknown version
  • Forward compatibility: ignore unknown payload types

Error Handling

ConditionAction
Invalid signatureDrop packet, do not relay
TTL = 0Drop packet
Duplicate packet_idDrop packet (already in cache)
Unknown versionDrop packet
Payload too largeDrop packet (max 1MB default)
Decode failureDrop packet

Maximum Sizes

LimitValueRationale
Max packet size1 MBPrevents DoS, fits in MTU with fragmentation
Max payload size1 MB - overhead~1 MB for file chunks
Dedup cache100,000 entries~3.2 MB for packet IDs
Sequence window2^32 per senderWraparound handled by timestamp

Mermaid: Packet Flow

Released under the MIT License.