logicsrc/docs/openswarm/security.md
Anthony Ettinger 4fed2681ec
Some checks are pending
CI / build (push) Waiting to run
test / test (push) Waiting to run
Add the LogicSRC OpenSwarm specification family (#142)
BitTorrent distributes bytes better than any CDN and has never been a
product: nobody is paid to seed, and nothing in it is private. Every
Profullstack media property answers that with a central HTTP proxy and a
pass system bolted on, and pays for every byte it serves.

OpenSwarm is an add-on to BitTorrent, carried as BEP 10 extension
messages, that fixes both. The swarm carries AES-256-CTR ciphertext whose
integrity is pinned by two SHA-256 merkle roots in a signed manifest, so
a tracker or DHT node learns an infohash and a size. A leecher buys a
pass over x402 in USDC (the same exchange x402-gateway runs for crawl
passes, settled by CoinPay), a seeder serves inside a bounded credit
window, and the leecher signs a cumulative voucher for every verified
batch. Whoever seeds gets paid. Vanilla clients remain valid members and
browsers remain first-class peers.

Adding a file mints a key pair for it, derived from one publisher seed by
default so there is one thing to back up: the public half is the file's
identity and its BEP 46 key, the private half signs the manifest and
authorises grants and payout changes, and a separate content key
encrypts the bytes and is sealed to paying peers.

The family: a core (records, keys, hashing, transports, discovery,
events), ipfile, ippay, ipdb (a signed hash-chained catalogue with heads
on the DHT), ipaudio, ipvideo, iplive (paid relays with backpressure)
and ipname (Moshpit pins and DNS TXT). Plus the c0mpute.com integration
with seven workload types and thirteen use cases, a proposed ip CLI,
conformance profiles, a security model and an FAQ.

Registered on the site the way OpenCreds is: nav entry, docs registry,
sitemap, a /openswarm landing page, PRD 0005, and the MCP prd_next_id
expectation moved to 0006.

Specs only. No code, no schemas, no reference implementation.


Claude-Session: https://claude.ai/code/session_01YafYxayh7Gqe5MWNNQMev2

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 15:05:57 -07:00

6.8 KiB

OpenSwarm Security Model

Version: 0.1 (draft)

This document collects the security claims the member documents make and states plainly what the family does not protect.

1. What is protected, by what

Asset Protection Where
File contents AES-256-CTR under a random content key; integrity from two SHA-256 merkle trees pinned by a signed manifest ipfile §4
Content key in transit X25519 sealed box to the recipient's box key ipfile §3.2
Content key at rest for the owner Sealed to the file box key; recoverable from seed plus manifest core §4.3
Manifest authenticity Ed25519 by the file key and the publisher key, with a domain prefix core §3.4
Latest-manifest pointer BEP 44 signature by the file key, seq monotonic core §7.2
Catalogue integrity Per-entry signature plus hash chain; head on the DHT ipdb §3
Passes Ed25519 by the hub; payer bound by a request signature ippay §3
Vouchers Ed25519 by the payer; cumulative; usd recomputed by the payee ippay §4
Live segments Same cipher; root in a signed head per unit; relays verify before forwarding iplive §3
Name to key Registry pin (SHA-256 of SPKI) or DNS TXT, plus a signed record ipname §4
Peer identity on a connection hello signature over infohash and both peer ids ipfile §5.1
Link confidentiality (optional) MTP/1: X25519 + ML-KEM-768, ML-DSA-65, ChaCha20-Poly1305 core §6.5
Events Standard Webhooks HMAC-SHA256 with timestamp tolerance core §8

2. Key material

Key Type Lives Backs up as
Publisher seed 32 bytes Keystore or OpenCreds key item The one thing to back up
File seed (derived) HKDF from publisher seed and fileId Never stored Recomputed
File seed (standalone) 32 random bytes Keystore Its own OpenCreds item
Content key 32 random bytes Keystore, keys.owner, keepers, grantees keys.owner
Box keys X25519 from the seeds Derived Recomputed
Hub signing key Ed25519 Hub HSM Hub's problem
Payer EVM key secp256k1 X402_PRIVATE_KEY, wallet Wallet
Node identity libp2p Ed25519 ~/.config/c0mpute/identity.key c0mpute's problem

3. Threats and answers

A public tracker or DHT node wants to know what a swarm is. It gets an infohash, a size, a piece length, a peer count, and a file named by a hex string. The manifest is not on the DHT; the pointer to it is signed and opaque. With swarm.private it gets nothing from the DHT at all.

A peer wants bytes without paying. It gets one credit window per identity per session, then a choke. With policy.vanilla: "ciphertext" it can get all the ciphertext free, by design, and cannot read it.

A seeder wants to be paid for bytes it did not serve. It cannot; the voucher is signed by the payer for bytes the payer verified. Its only lever is to stop serving after being paid for what it already sent.

A payer signs vouchers past its cap to many seeders. Each seeder was exposed for one window. The hub pays in redemption order until the cap and refuses the rest; the payer's standing records it and future passes are refused.

A payer or seeder replays a voucher. It is cumulative and per triple; replay pays zero.

A hub key is stolen. Free passes until manifests drop the hub. The hub record SHOULD carry a successor key and publishers SHOULD list two hubs.

A hub does not pay out. It is a trusted processor; the answer is to list a different hub. Receipts are signed, so non-payment is provable.

The publisher seed is stolen. Every derived file key is compromised: the thief can revise manifests, change payout addresses and delegate keepers. Detection is a manifest revision the owner did not make, visible in the ipdb log. Remedy is publisher rotation (core §4.5) from a machine the thief does not control; successor links require the new key too, so the thief cannot forge the rotation.

The publisher seed is lost. Core §4.7. Nothing is unreadable; nothing can be changed.

A grantee leaks the content key. Anyone with the key and the ciphertext reads the file. The family prices access and does not prevent copying. A leaked key is answered by re-encryption, which protects only future readers. This is the same position every streaming service is in once the frame is on a screen, stated rather than hidden behind a DRM promise.

A relay forwards a bad segment. Every downstream peer verifies the root against a signed head and drops the relay.

A Sybil of relays surrounds an origin. They pull, earn nothing (nobody pays them), and cost the origin upload up to maxDownstream. Pins and hired relays are how an origin buys reach it controls.

A registry hands out a wrong pin. The record fails the pin check; first-seen pinning in the resolver warns on change.

An EIP-3009 proof is presented for a different resource. Known limitation of x402 v2: the struct cannot bind a resource. The hub records nonce to resource at verify time and refuses reuse (ippay §3.2).

A gateway is asked to serve plaintext to a bare <video> tag. It serves one credit window against the pass and then 402s; a gateway configured to trust the pass for the whole title is taking the whole title as its exposure, and the configuration says so.

4. What is deliberately visible

  • File size, piece length, both infohashes, tracker list, peer count.
  • Manifest name and meta, to anyone who obtains the manifest (public visibility) or any pass holder (pass visibility).
  • The existence and sequence length of a feed; the content of a public feed.
  • Segment sizes and timing of a live stream, to relays.
  • Who paid whom how much, to the hub.
  • The publisher's payout address, in the signed manifest.

5. Defaults an implementation MUST ship

Setting Default Reason
policy.creditBytes 4 MiB (ipfile), 8 MiB (iplive) Bounded exposure, no choke at the live edge
policy.voucherBytes 1 MiB, 2 MiB Four vouchers per window
policy.vanilla ciphertext Wider swarm at zero confidentiality cost
visibility public A catalogue that cannot be read is not a catalogue
Pass lifetime 30 days Long enough to stream a release, short enough to bound a stolen key
Key epoch (iplive) 900 segments 30 minutes at 2 s
Resolver cache 300 s positive, 5 s negative Matches moshpit-proxy
Keystore mode 0600 As every other Profullstack keystore

6. Cryptographic agility

cipher.alg, sigs[].alg, kdf labels with :v1 suffixes, and extension names are all versioned data. A new cipher is a new alg value and a new IV label; a new signature is a new alg; a breaking wire change is a new extension name. Nothing is edited in place, for the reason OpenCreds gives: peers that shipped the old value are still running.