Skip to main content

The three-tier boundary

Every property the client handles falls into exactly one of three tiers:
  • Verified — the client checks it cryptographically or mathematically. If it passes, it is true with overwhelming probability.
  • Trusted — the client takes it at face value from a specified source. If the source is wrong, the client is wrong.
  • Not trusted — the client never relies on this, no matter who claims it.

Verified

PropertyMechanism
Blob content correctnessBLAKE3 hash tree verification on every chunk
Voucher signaturesEIP-712 + SignatureChecker.isValidSignatureNow
NodeInfo binding (NodeId ↔ Ethereum address)EIP-712 binding signature + ed25519 ownership proof recorded on-chain
Channel settlement amountOn-chain contract enforces voucher signature + deposit cap
Manifest integrityManifest blob’s own BLAKE3 hash is the file ID; chunks are individually hash-verified
Protocol message authenticityed25519 wire signatures (and slash_sig for slash-relevant messages)
A node claiming to have bytes and then serving garbage loses every byte of that stream before payment via chunk-level BLAKE3 verification. This is the hardest, cleanest guarantee in the system.

Trusted

These are safe in a working, honest infrastructure — but they depend on something outside the client’s direct verification.
PropertyTrusted source
”These nodes exist”Your L2 RPC provider’s response to StakingRegistry.getNodes()
”This blob hash corresponds to the file I want”Whoever told you the hash (the content provider’s UI, a manifest, a friend)
“Clocks are roughly synchronized”NTP
”Gossip messages are reasonably fresh”NTP + signed timestamps (±60 s for NodeAnnounce, ±1 h for reputation reports)
“The app server I’m authenticating to is the real one”Your content provider’s out-of-band identity (NodeId fingerprint, DNS)
“Relays I route through are content-blind”QUIC encryption; structural property of iroh relays

Specific trust assumptions worth calling out

  • L2 RPC provider honesty. A malicious RPC could hide ChannelCloseInitiated events from your dispute monitor, or return a fabricated node list to eclipse you. Mitigation: multi-source bootstrap (on-chain registry + DNS seed list + optional operator static list, 2-of-3 agreement) and multiple independent RPC providers.
  • App server custody of K_blob. For encrypted content, the content provider’s app server holds the plaintext blob key. Compromise of the app server exposes all that provider’s content. Per-provider, not protocol-wide.
  • NTP correctness. Clock skew breaks gossip freshness checks and voucher replay windows. Skewed attacker + skewed victim is how certain attacks attempt to slip vouchers or fake freshness. Mitigation: generous windows absorb typical NTP jitter; gross skew is self-detecting.

Not trusted

Things you must never accept without cryptographic verification:
PropertyWhy not
”The bytes I received are what you requested”Verify the BLAKE3 hash. Do not assume by URL, NodeId, or prior trust.
”The rate I charged you is what I advertised”Slash-able offense if lied. Don’t accept charges above the advertised rate.
”I have this blob” (claim in ProbeResponse)Slash-able if wrong — but client must still verify on delivery.
”I am this NodeId” (over the wire)Verify the ed25519 signature. iroh QUIC does this at handshake.
Cross-region announcementsA node advertising “I’m in DE” without actually being in DE leaks to the network — your score computation uses measured RTT, not claimed region.
Redirects to URLsRedirects are only NodeId. A peer that sends you a URL is out of protocol.

How this plays in practice

A client fetch pipeline, tier by tier:
  1. Hash comes from the content provider (trusted — they told you what you want).
  2. Node list comes from the registry (trusted — your RPC returned it).
  3. NodeId↔Ethereum binding is verified — on-chain registry + EIP-712 + ed25519 proof.
  4. Probe response is verified (wire sig) but its has_blob: true claim is trusted provisionally — confirmed only by actual delivery.
  5. Streamed bytes are verified — BLAKE3 leaf-by-leaf. No trust.
  6. Voucher signature from you is verified on-chain by the contract — no one trusts it without signature.
  7. Settlement is verified on-chain — the contract enforces correctness.
The verified steps are load-bearing. The trusted steps are small and survey-able. The not-trusted category is never relied on.

When to be paranoid

  • You’re downloading high-value or sensitive content. Consider tightening the multi-source bootstrap policy (require 3-of-3 agreement instead of the default 2-of-3) and pinning the registry RPC to a provider you operate.
  • You’re downloading over hostile networks. Tighten voucher cadence (smaller = tighter bound on unpaid-delivery loss).
  • You’re automating downloads without human supervision. Set a hard --max-budget-usdc per fetch to bound worst-case spend.
  • You’re running multiple client identities. Rotate NodeIds aggressively to break linkability.

What this trust model explicitly does not give you

  • Anonymity from on-path observers. QUIC metadata, IP addresses, and timing are visible. This is an accountability-first design.
  • Forward secrecy for previously-delivered encrypted content. App server K_blob compromise decrypts historical ciphertexts.
  • Protection from a compromised endpoint (your own device). Device-level compromise exposes plaintext, your keys, and your session tokens. All standard device hardening applies.
See privacy for the full privacy-surface inventory and adversary model.