Ring of Trust

The Ring of Trust is a cryptographically verifiable revival of the old Webring idea, rebuilt for static sites and Federated Wiki using the **Trust Favicon Pack** method.

In a Ring of Trust, a site’s `/favicon.svg` is not just an icon: it is the portable identity badge, the membership claim, the trust links, and (optionally) a cached snapshot of the wider ring.

# Trust Favicon Pack The Trust Favicon Pack is the core protocol decision: put everything needed for membership and verification inside a single, cacheable, inspectable file that every site can host. - One required artifact per site: `/favicon.svg`. - A `<metadata>` payload inside the SVG contains the ring data. - The payload is signed with a public key that is also carried in the same payload. If you can host an SVG favicon, you can join the ring.

# What the favicon contains Each member’s favicon carries a signed payload (a “pack”) that can be verified without contacting a central server. Minimum useful fields. - `site`: canonical destination URL for ring navigation. - `pub`: public key (e.g. Ed25519). - `kid`: key fingerprint used for pinning and display. - `rings`: which rings this site participates in. - `links`: neighbour pointers (prev/next/seed) that bootstrap discovery. - `sig`: signature over the canonicalised payload (excluding `sig`). Optional but powerful fields. - `vouches`: signed trust edges that express “I endorse this key / site”. - `snap`: a cached snapshot of the ring’s member list and trust edges, optionally with an IPFS CID for recovery. This allows the ring to keep working even when many member URLs are down.

# How it works The Ring of Trust is a tiny loop: fetch, verify, cache, render. - The widget fetches a site’s `/favicon.svg`. - It extracts the Trust Favicon Pack from `<metadata>`. - It verifies the signature using the embedded public key, and checks the fingerprint matches `kid`. - It follows `links` to fetch neighbour favicons, building a local verified graph. - It uses `snap` (if present) to fill in the wider ring membership without needing a central roster. - It renders Next / Previous (and optionally Random) navigation plus a minimal trust visualisation.

# CORS requirement For verification to happen entirely in the browser, member sites should serve `/favicon.svg` with permissive CORS headers. - `Access-Control-Allow-Origin: *` is the simplest approach for the favicon asset. Without this, a site can still be part of the ring socially, but automated verification becomes harder without proxies.

# Next and Previous navigation The Trust Favicon Pack supports two navigation modes. **Neighbour-linked mode.** - Each site declares `prev` and `next` in `links`. - Links can include expected neighbour `kid` values, which pins the relationship and prevents silent substitution. **Snapshot-derived mode.** - Each site carries a `snap.members` list for a ring. - All clients compute a deterministic ordering (for example by `(ringId, kid)`), then derive prev/next from position. - This works well for rings that are not strictly linear, or where membership changes frequently. Both modes can coexist: neighbour links give fast traversal, snapshots give resilience.

# Broken URLs and IPFS recovery The point of the Trust Favicon Pack is that rings should keep working when the web breaks. - The widget maintains a locally cached, last-verified graph. - If a neighbour is unreachable, the widget still navigates using the cached snapshot. - If the snapshot includes an `ipfsCid`, the widget can attempt to fetch the snapshot bytes via IPFS gateways as a recovery path. - docs.ipfs.tech IPFS is not the trust anchor; signatures and key pinning are. IPFS is just a durable transport.

# The minimal trust visualisation A Ring of Trust is more than a line of links. The “fabulous machine” is the trust structure that makes membership legible. The core minimal visualisation is **a ring of dots with trust chords**. - Dots on a circle are ring members. - The current site is a larger dot. - Prev and Next are highlighted and clickable. - Trust edges (vouches) are drawn as faint chords between dots. - Dot styling shows three states. - Hollow dot: seen in a snapshot, not yet verified in this session. - Filled dot: verified signature is valid. - Outlined dot: trusted under your policy (enough vouches from trusted members). This is the smallest graphic that communicates both browsing flow and trust structure without turning into a full graph explorer.

# Local caching The widget stores verified ring data locally (for example in `localStorage` or `IndexedDB`). - Use cached data immediately for zero-latency navigation. - Re-fetch neighbour favicons in the background and update the cache only if verification succeeds. - Keep the last N verified snapshots so the user can roll back if the ring is contested. Caching turns the ring into a resilient, offline-tolerant browsing object.

# Federated Wiki implementation In Federated Wiki, this becomes a plugin item (for example `ring-of-trust`) that renders the widget inside a page. - The plugin fetches `/favicon.svg` from the current wiki origin and from neighbour sites. - It caches verified packs across the wiki farm (optional) to avoid repeated downloads. - It renders the ring-of-dots and chords graphic, and injects Prev/Next links that navigate across sites cleanly. Because the protocol is “fetch and verify favicons”, the same widget works for ordinary static sites, wiki sites, and mixed rings.

# Why this is different from old webrings Classic webrings were charming but easy to spoof and easy to rot. Ring of Trust keeps the charm but adds verifiability and resilience by making membership and trust portable, signed, and cacheable inside the Trust Favicon Pack. A ring becomes something you can browse, mirror, and audit, rather than a central list you have to believe.

# Diagram

digraph ring_of_trust_trust_favicon_pack { rankdir=LR; bgcolor="white"; node [shape=box]; subgraph cluster_member { label="Member site (static or Federated Wiki)"; tooltip="Member site (static or Federated Wiki)"; style="rounded"; favicon [label="/favicon.svg\n(Trust Favicon Pack in <metadata>)"]; pack [label="Pack payload\n{ site, pub, kid, rings, links, vouches?, snap?, sig }"]; verify [label="Signature verification\n(sig over canonical payload)\n+ kid fingerprint check"]; } subgraph cluster_widget { label="Client widget (JavaScript)"; tooltip="Client widget (JavaScript)"; style="rounded"; cache [label="Local cache\n(IndexedDB / localStorage)\nlast-verified packs + snapshots"]; fetch [label="Fetch favicons\n(this site + neighbours)"]; build [label="Build verified graph\nmembers + trust edges"]; policy [label="Trust policy\nSeen / Verified / Trusted"]; render [label="Render UI\nRing of dots + trust chords\nPrev / Next / Random"]; } subgraph cluster_neighbours { label="Neighbour sites"; tooltip="Neighbour sites"; style="rounded"; prev [label="Prev site\n/favicon.svg"]; next [label="Next site\n/favicon.svg"]; seed [label="Seed site\n/favicon.svg"]; } subgraph cluster_resilience { label="Resilience and recovery"; tooltip="Resilience and recovery"; style="rounded"; snap [label="snap snapshot\n(member list + trust edges)\noptional ipfsCid"]; ipfs [label="IPFS gateway / node\n(fetch snapshot by CID)\noptional DNSLink/IPNS"]; broken [label="Broken URL\nor unreachable site"]; } favicon -> pack; pack -> verify; fetch -> favicon [label="GET /favicon.svg\n(CORS enabled)"]; fetch -> prev [label="follow links.prev"]; fetch -> next [label="follow links.next"]; fetch -> seed [label="follow links.seed"]; prev -> fetch [label="read Pack"]; next -> fetch [label="read Pack"]; seed -> fetch [label="read Pack"]; verify -> cache [label="store if valid"]; cache -> build [label="use immediately"]; fetch -> build [label="merge verified packs"]; pack -> snap [label="optional"]; snap -> build [label="fill wider ring"]; broken -> snap [label="fallback to cached snapshot"]; snap -> ipfs [label="if ipfsCid present"]; ipfs -> build [label="recover snapshot bytes\nthen verify by signatures"]; build -> policy; policy -> render; render -> prev [label="Prev click"]; render -> next [label="Next click"]; }

# See