IFM Frequency Model
Overview
A frequency in IFM is a human-friendly namespace that maps to a 256-bit network identifier (Topic ID). This separation allows the protocol to evolve beyond the FM radio metaphor while maintaining backward compatibility.
Frequency Representation
Human-Friendly Frequency
91.700
chat.general
music.lofi
weather.tokyo
sensor.greenhouse.3
game.room.42
private.team
team.alphaCanonical Identifier
ifm://public/91.700
ifm://public/chat.general
ifm://public/music.lofi
ifm://public/weather.tokyo
ifm://public/sensor.greenhouse.3
ifm://public/game.room.42
ifm://protected/private.team
ifm://hidden/team.alphaNetwork Identifier (Topic ID)
BLAKE3("ifm://public/91.700") = 0xabcdef...
BLAKE3("ifm://public/chat.general") = 0x123456...
BLAKE3("ifm://protected/private.team") = 0x789abc...
BLAKE3("ifm://hidden/team.alpha") = 0xfedcba...Frequency Structure
rust
struct Frequency {
namespace: Namespace, // public | protected | hidden
channel: String, // human-readable channel name
version: u8, // protocol version for this frequency
}Namespace Types
| Namespace | Prefix | Encryption | Discovery | Use Case |
|---|---|---|---|---|
| Public | ifm://public/ | None (plaintext) | DHT + GossipSub | Open broadcast, chat, streaming |
| Protected | ifm://protected/ | ChaCha20-Poly1305 | DHT + GossipSub (key required to decrypt) | Private groups, team comms |
| Hidden | ifm://hidden/ | ChaCha20-Poly1305 | Invite-only (not in DHT) | Secret channels, secure comms |
Frequency Resolution
Parsing Human Frequency
Resolution Algorithm
rust
fn resolve_frequency(input: &str) -> Result<Frequency> {
// 1. Try parsing as canonical URI
if input.starts_with("ifm://") {
return parse_canonical(input);
}
// 2. Check for explicit namespace prefixes
if input.starts_with("public:") {
return Ok(Frequency { namespace: Public, channel: input[7..].into(), version: 1 });
}
if input.starts_with("protected:") || input.starts_with("private:") {
return Ok(Frequency { namespace: Protected, channel: input.split(':').nth(1).unwrap().into(), version: 1 });
}
if input.starts_with("hidden:") {
return Ok(Frequency { namespace: Hidden, channel: input[7..].into(), version: 1 });
}
// 3. Heuristic: FM-like frequencies (digits + optional dot)
if input.chars().all(|c| c.is_ascii_digit() || c == '.') {
return Ok(Frequency { namespace: Public, channel: input.into(), version: 1 });
}
// 4. Default: public namespace
Ok(Frequency { namespace: Public, channel: input.into(), version: 1 })
}Frequency Hash (Topic ID)
rust
fn frequency_to_topic_id(freq: &Frequency) -> [u8; 32] {
let canonical = freq.to_canonical_string(); // e.g., "ifm://public/91.700"
BLAKE3::hash(canonical.as_bytes()).into()
}Properties:
- Deterministic: same frequency always → same Topic ID
- Uniform distribution: suitable for DHT keyspace
- 256-bit: collision-resistant
- Used as: GossipSub topic, DHT key, cache key
Frequency Metadata
Optional metadata attached to frequencies (broadcast via ANNOUNCE packets):
rust
struct FrequencyMetadata {
name: Option<String>, // "General Chat"
description: Option<String>, // "Main discussion channel"
language: Option<String>, // "en", "es", "ja"
encryption: EncryptionType, // None | ChaCha20Poly1305
listener_count: u32, // Current peers tuned in
capabilities: Vec<Capability>, // Voice, Chat, File, Video, etc.
created_at: u64, // Unix timestamp
owner: Option<PeerId>, // For protected/hidden frequencies
}Capabilities
| Capability | Description |
|---|---|
voice | Real-time voice communication |
chat | Text messaging |
video | Video streaming |
file | File transfer |
telemetry | IoT sensor data |
gaming | Multiplayer game sync |
ai | AI agent communication |
Frequency Operations
Tune (Join Frequency)
Leave Frequency
1. GossipSub: UNSUBSCRIBE from Topic ID
2. Send LEAVE packet (optional, graceful)
3. Close frequency-specific connections
4. Clean up local state, emit "left" eventScan (Discover Frequencies)
1. DHT: Iterate known frequency announcements
2. Local: mDNS/UDP multicast for LAN frequencies
3. Return list of (Frequency, Metadata, PeerCount)Protected Frequencies
Key Derivation
Encryption
- Algorithm: ChaCha20-Poly1305 (AEAD)
- Nonce: 12-byte prefix + 4-byte packet sequence (big-endian)
- AAD: Canonical frequency string
- Applied: At packet payload level (before signing)
rust
fn encrypt_payload(payload: &[u8], key: &[u8; 32], nonce_prefix: &[u8; 12], sequence: u64, aad: &[u8]) -> Vec<u8> {
let mut nonce = [0u8; 12];
nonce[..8].copy_from_slice(nonce_prefix);
nonce[8..].copy_from_slice(&sequence.to_be_bytes());
chacha20_poly1305_encrypt(key, &nonce, payload, aad)
}Hidden Frequencies
- Not advertised in DHT
- Not announced via ANNOUNCE packets
- Joined only via direct invitation (QR code, secure link, out-of-band)
- Same encryption as protected frequencies
- Topic ID still derived from canonical form (but canonical form never published)
Frequency Naming Conventions
Public Frequencies
| Pattern | Example | Use Case |
|---|---|---|
| FM-style | 91.700, 88.5, 107.9 | Radio-like broadcast |
| Category.name | chat.general, music.lofi, news.world | Organized channels |
| Location.category | weather.tokyo, traffic.la, alerts.sf | Geo-specific |
| Sensor.type | sensor.temperature, sensor.humidity | IoT telemetry |
Protected Frequencies
| Pattern | Example | Use Case |
|---|---|---|
| private.name | private.team, private.family | Private groups |
| org.name | acme.engineering, acme.sales | Organization channels |
| project.name | project.alpha, project.launch | Project rooms |
Hidden Frequencies
| Pattern | Example | Use Case |
|---|---|---|
| secret.name | secret.op, secret.meeting | Covert comms |
| game.room.id | game.room.42, game.lobby.7 | Game sessions |
| device.id | device.camera.1, device.drone.3 | Device control |
Frequency Lifecycle
Mermaid: Frequency Resolution Flow
Examples
Public Frequency
json
{
"human": "91.700",
"canonical": "ifm://public/91.700",
"topic_id": "0xabcdef1234567890...",
"encryption": "none",
"discoverable": true
}Protected Frequency
json
{
"human": "private.team",
"canonical": "ifm://protected/team",
"topic_id": "0x1234567890abcdef...",
"encryption": "ChaCha20-Poly1305",
"discoverable": true,
"key_required": true
}Hidden Frequency
json
{
"human": "team.alpha",
"canonical": "ifm://hidden/team.alpha",
"topic_id": "0xfedcba0987654321...",
"encryption": "ChaCha20-Poly1305",
"discoverable": false,
"invite_only": true
}Custom Canonical Form
json
{
"human": "ifm://protected/acme.engineering",
"canonical": "ifm://protected/acme.engineering",
"topic_id": "0x9988776655443322...",
"encryption": "ChaCha20-Poly1305",
"discoverable": true
}