← Back to File Sharing

PeerFile.link

Private WebRTC signaling over Nostr

⚠️ Warning

This is experimental software that has not been reviewed by a security professional and is for demonstration purposes only. Do not use this software for sensitive or production applications. The cryptographic implementations and security assumptions may contain vulnerabilities.

How It Works

PeerFile uses Nostr as a secure signaling channel for WebRTC connections, enabling truly peer-to-peer file sharing without compromising privacy. All signaling data is encrypted end-to-end, preventing relay operators from monitoring connections or content.

Privacy

Nostr Implementation

PeerFile uses NIP-78 with custom tags for efficient WebRTC signaling discovery and encrypted content exchange.

Traditional WebRTC requires a signaling server that can monitor all connection attempts and metadata. Nostr + Encryption provides a decentralized signaling network where relay operators cannot read signaling content or correlate connections, even with access to all events.

Event Structure

{
  "kind": 30078,
  "tags": [
    ["d", "peerfile.link"],             // App identifier
    ["x", "a1b2c3d4e5f6g7h8"],         // PIN discovery hash
    ["t", "offer|answer|ice"],         // Message type
    ["r", "sender|receiver"]           // Role
  ],
  "content": "encrypted_webrtc_data"
}

Query Optimization

Efficient relay filtering using indexed tags prevents downloading all events:

// Efficient: O(1) hash lookup
{ kinds: [30078], "#x": [pinHash], "#t": ["offer"], limit: 1 }

Cryptography

Dual-key system derived from PIN separates discovery from content encryption, preventing relay operators from correlating connections or reading signaling data.

Key Derivation

// Discovery (visible in tags, enables filtering)
discoveryHash = SHA-256("discovery-" + pin)[0:8]

// Encryption (hidden, protects content)
encryptionKey = AES-GCM-Key(SHA-256("peerfile.link-" + pin))

Content Protection

All WebRTC signaling (offers, answers, ICE candidates) encrypted with AES-GCM:

// Encrypt
iv = random(12 bytes)
encrypted = AES-GCM(encryptionKey, iv, json_data)
content = base64(iv + encrypted)

Why Not NIP-44?

NIP-44 is Nostr's standard encryption protocol, but it's designed for persistent identity-based messaging between known users. PeerFile intentionally uses anonymous sessions with temporary PINs rather than long-term keypairs.

Security Properties

Connection Flow

  1. PIN Generation: Sender creates 6-character PIN, derives keys
  2. Offer Publication: Encrypted WebRTC offer → Nostr relay
  3. Discovery: Receiver queries by PIN hash, decrypts offer
  4. Answer Exchange: Encrypted WebRTC answer → Nostr relay
  5. ICE Candidates: NAT traversal via STUN, fallback to TURN
  6. P2P Transfer: Direct connection established, file transfer begins

Result: Peer-to-peer file transfer with encrypted signaling over a decentralized network, protected against surveillance and monitoring.

Self Hosting

PeerFile is written in pure Go and compiles to a single static binary with no external dependencies:


• An experiment in "Other Stuff" •

← Back to File Sharing