theseus-site/whitepaper/index.html
Local Dev 6342e298f4 Licenses: MPL-2.0 for Theseus, Ariadne and Hephaestus; Apache-2.0 for Argus; CC BY 4.0 for the documents
The public repos carried no license, so nobody could legally copy or build
on the code, and the whitepaper's "free software" had nothing behind it.
Theseus and its companions take the Mozilla Public License 2.0, the
file-level copyleft Firefox and Brave use, which is compatible with every
component they bundle. The resolver and gateway libraries take Apache-2.0
so that other implementations of the registry can reuse them without
copyleft in the way. The protocol documents and the whitepaper are CC BY 4.0.

A third-party notices file lists what the browser ships and fetches, with
the source offer the GPL sing-box binary the VPN add-on downloads requires;
the matching source archive is now published beside the binaries. The
names and marks are reserved in TRADEMARKS.md, separate from the code
license, so a fork must ship under its own name. Settings › General says
the license and links the three files; the whitepaper says the same.
2026-09-29 00:18:00 +02:00

248 lines
63 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Whitepaper — Theseus.X</title>
<meta name="description" content="How Theseus Navigator resolves Bitcoin Cash names without a registrar or a resolver in the middle, how content and records are published and verified, the protections it ships on by default, the wallet and extension model, and the security model as it stands.">
<link rel="icon" href="../brand/favicon.svg" type="image/svg+xml">
<meta property="og:type" content="article">
<meta property="og:site_name" content="Theseus.X">
<meta property="og:title" content="Theseus Navigator Whitepaper">
<meta property="og:description" content="A browser in which a site's name is a record on the Bitcoin Cash blockchain, not an entry in a registrar's database.">
<meta property="og:url" content="https://theseus.x/whitepaper/">
<style>
:root{ --bg:#0b0e14; --panel:#141a24; --panel2:#18202c; --line:rgba(255,255,255,.09);
--ink:#e7eaf1; --mut:#8b98a9; --dim:#5e6678; --acid:#d6ff3d; }
*{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:radial-gradient(1100px 560px at 50% -12%,#16202e,var(--bg));color:var(--ink);
font:16px/1.7 system-ui,-apple-system,Segoe UI,Roboto,sans-serif;min-height:100vh;padding-top:52px}
a{color:var(--acid)}
.topnav{position:fixed;top:0;left:0;right:0;z-index:20;display:flex;gap:2px;align-items:center;flex-wrap:wrap;
padding:10px 1.2rem;background:rgba(11,14,20,.88);backdrop-filter:blur(10px)}
.topnav .brand{font-weight:600;color:var(--ink);text-decoration:none;margin-right:14px;font-size:15px;letter-spacing:.2px;display:flex;align-items:center;gap:8px}
.topnav .brand .g{color:var(--acid)}
.topnav .brand svg{width:20px;height:20px}
.topnav a{color:var(--mut);text-decoration:none;padding:6px 12px;border-radius:8px;font-size:14px;display:inline-flex;align-items:center;gap:6px}
.topnav a:hover{color:var(--ink);background:var(--panel)}
.topnav a.here{color:var(--acid);background:rgba(214,255,61,.08)}
.topnav a.get{margin-left:auto;background:rgba(214,255,61,.10);color:var(--acid);font-weight:500}
.topnav a.get:hover{background:rgba(214,255,61,.18)}
.topnav a .g{color:var(--acid)}
.topnav a svg.tabicon{width:15px;height:15px;flex:none}
.wrap{max-width:1040px;margin:0 auto;padding:0 1.2rem}
.layout{display:grid;grid-template-columns:220px minmax(0,760px);gap:48px;justify-content:center;align-items:start}
header.hero{padding:3rem 0 1rem}
h1{font-size:clamp(1.8rem,4.6vw,2.5rem);line-height:1.15;margin:0 0 .5rem}
h1 .g{color:var(--acid)}
.byline{color:var(--mut);font-size:.95rem;margin:0}
.toc{position:sticky;top:72px;font-size:13.5px;padding-top:3.4rem}
.toc a{display:block;color:var(--mut);text-decoration:none;padding:5px 10px;border-left:2px solid var(--line);line-height:1.35}
.toc a:hover{color:var(--ink)}
.toc a.active{color:var(--acid);border-left-color:var(--acid)}
article h2{font-size:1.45rem;margin:2.6rem 0 .8rem;padding-top:1.4rem;border-top:1px solid var(--line);scroll-margin-top:70px}
article h2:first-of-type{border-top:none;margin-top:1rem;padding-top:0}
article p{margin:0 0 1rem;max-width:72ch}
article b{color:var(--ink)}
article ul,article ol{padding-left:1.4rem;margin:0 0 1rem;max-width:72ch}
article li{margin:0 0 .45rem}
article table{border-collapse:collapse;width:100%;margin:.4rem 0 1.4rem;font-size:14px;background:var(--panel);border:1px solid var(--line);border-radius:12px;overflow:hidden}
article th,article td{padding:9px 12px;border-top:1px solid var(--line);text-align:left;vertical-align:top}
article thead th{border-top:none;background:var(--panel2);color:var(--mut);font-weight:600;font-size:12.5px;letter-spacing:.04em;text-transform:uppercase}
article td:first-child{white-space:nowrap;color:var(--ink)}
code{background:#0e131b;border:1px solid var(--line);border-radius:6px;padding:1px 6px;font-family:ui-monospace,monospace;font-size:12.5px;word-break:break-word}
figure.diagram{margin:1.2rem 0 1.6rem;background:var(--panel);border:1px solid var(--line);border-radius:14px;padding:10px 12px 6px}
figure.diagram svg{width:100%;height:auto;display:block}
figure.diagram figcaption{color:var(--dim);font-size:12.5px;padding:6px 6px 4px}
footer{border-top:1px solid var(--line);padding:2rem 0 3rem;color:var(--dim);font-size:13px;text-align:center;margin-top:3rem}
@media (max-width:900px){ .layout{grid-template-columns:minmax(0,1fr)} .toc{position:static;padding-top:0;display:flex;flex-wrap:wrap;gap:4px} .toc a{border-left:none;border:1px solid var(--line);border-radius:8px;padding:4px 9px} article td:first-child{white-space:normal} }
</style>
</head>
<body>
<nav class="topnav">
<a class="brand" href="../">
<svg viewBox="0 0 64 64" aria-hidden="true">
<rect width="64" height="64" rx="12" fill="#0b0e14"/>
<path d="M32 6 L38 32 L26 32 Z" fill="#e04e4e"/>
<path d="M38 32 L32 58 L26 32 Z" fill="#d6ff3d"/>
<path d="M6 32 L32 27 L58 32 L32 37 Z" fill="#d6ff3d" opacity=".55"/>
<circle cx="32" cy="32" r="3" fill="#0b0e14"/>
</svg>
<span>Theseus<span class="g">.X</span></span>
</a>
<a href="../plug-ins/">Plug-ins</a>
<a href="../extensions/">Extensions</a>
<a href="../brand/">Brand</a>
<a class="here" href="./">Whitepaper</a>
<a href="https://sirius.x/" title="Register a BCNR name"><svg class="tabicon" viewBox="0 0 64 64" aria-hidden="true"><rect width="64" height="64" rx="12" fill="#0b0e14"/><path d="M32 4 L36.4 27.6 L60 32 L36.4 36.4 L32 60 L27.6 36.4 L4 32 L27.6 27.6 Z" fill="#d6ff3d"/></svg><span>Sirius<span class="g">.X</span></span></a>
<a class="get" href="../#download">Get Theseus</a>
</nav>
<div class="wrap">
<div class="layout">
<aside class="toc" aria-label="Contents">
<a href="#abstract">Abstract</a>
<a href="#the-problem">The problem</a>
<a href="#names-on-bitcoin-cash">Names on Bitcoin Cash</a>
<a href="#resolution-from-a-name-to-content">Resolution: from a name to content</a>
<a href="#content-and-records">Content and records</a>
<a href="#privacy-and-protections">Privacy and protections</a>
<a href="#wallet-and-dapps">Wallet and dapps</a>
<a href="#extensions-and-plug-ins">Extensions and plug-ins</a>
<a href="#beyond-the-browser">Beyond the browser</a>
<a href="#security-model">Security model</a>
<a href="#distribution-and-updates">Distribution and updates</a>
<a href="#roadmap-and-open-questions">Roadmap and open questions</a>
<a href="#glossary-and-references">Glossary and references</a>
</aside>
<main>
<header class="hero">
<h1>Theseus Navigator <span class="g">Whitepaper</span></h1>
<p class="byline">Sep 28, 2026 · Silent Mode · describes Theseus Navigator 0.3.59</p>
</header>
<article>
<h2 id="abstract">Abstract</h2>
<p>Theseus Navigator is a desktop web browser in which a site's name is a record on the Bitcoin Cash blockchain, not an entry in a registrar's database. The browser resolves those names itself, from several independent sources at once, and fetches the content from decentralized storage or from any server the owner points at. No registrar can seize a name, no resolver sits between the user and the ledger, and the browser ships its privacy protections on by default: request blocking, consent-banner handling, DNS over HTTPS, Global Privacy Control, anti-fingerprinting and a bundled Tor route.</p>
<p>This paper describes the name system Theseus reads (the Bitcoin Cash Name Registry), how the browser turns a name into content without trusting any single party, how content and DNS-style records are published and verified, the protections and the wallet built into the browser, the extension model, and the companion tools that bring the same names to every other browser and to Android. It closes with the security model as it stands in version 0.3.59, released on 2026-09-28, and with the open questions.</p>
<p>Theseus is built by Silent Mode on Electron, currently for Windows, and is free software distributed with published checksums from two mirrors, one on ordinary DNS and one served over the name system itself.</p>
<h2 id="the-problem">The problem</h2>
<p>A web address is only as free as the weakest party between the user and the page, and today that chain has four parties in it who can each break the link without the owner's consent.</p>
<ul><li><b>The registrar and the registry.</b> The record of who holds a domain sits in a company's database, behind a registrar, a registry and their jurisdictions. It can be suspended on a complaint, seized by court order, lost to a missed renewal, or hijacked by whoever talks their way past a support desk. Whether a name is bought outright or leased for a term is not the problem; who keeps the record, and how many parties stand between the holder and it, is.</li><li><b>The resolver.</b> Whichever DNS resolver a device uses sees every name it looks up and can answer with something else. Hostile networks do exactly that: one pattern seen in the field returns A-typed data for AAAA queries, which breaks the operating system's own lookups until the device switches to an encrypted resolver.</li><li><b>The certificate authority.</b> HTTPS trust rests on a few hundred authorities, any one of which can issue a certificate for any name. The user cannot tell an issued certificate from a mis-issued one.</li><li><b>The host and the CDN.</b> A page lives on a server someone can be ordered to switch off, behind a content network that can decline to serve it.</li></ul>
<p>On top of that, the browser itself has become the instrument of tracking: third-party requests on almost every page, consent banners engineered to be accepted, fingerprinting through timezone, language, fonts and hardware, and a real IP address that follows the user everywhere.</p>
<p>A browser that wants to fix this cannot bolt a plug-in onto the existing stack. The name layer has to be replaced by something no single party controls, the resolution has to happen inside the browser from sources the browser can check against each other, content has to be addressable without a host that can be switched off, and the privacy defaults have to be on from the first launch. Theseus is built around those four requirements, and the rest of this paper describes how each one is met and where the limits still are.</p>
<h2 id="names-on-bitcoin-cash">Names on Bitcoin Cash</h2>
<p>A name in this system is a digital certificate record on the Bitcoin Cash blockchain: whoever holds the certificate holds the name, and the chain is the only registry. The record is kept on the chain instead of at a company, which removes the registrar, the registry and the resolver from between the holder and the name. The protocol is called BNS1 after its payload prefix; the name system as a whole is referred to as the Bitcoin Cash Name Registry, BCNR.</p>
<p><b>Registration.</b> One transaction does everything. It mints an immutable digital certificate whose commitment is the name itself, writes a single OP_RETURN payload of at most 200 bytes, <code>BNS1</code> followed by JSON with the operation, the name and its records, and pays 600 satoshis of dust to a fixed beacon address. The beacon is what makes the registry discoverable: any client can ask an ordinary Electrum server for the beacon's history and obtain every registration ever made, without an indexer. The certificate holds 1,000 satoshis and the transaction's first output is change, placed there so the next registration has a fresh coin at output zero, which a new certificate category requires.</p>
<p><b>Four operations</b> exist: <code>REG</code> and <code>UPD</code> for names, <code>TREG</code> and <code>TUPD</code> for top-level domains. An update spends the certificate and re-issues it, so the same transaction proves ownership and carries the new records; the address that receives the certificate becomes the owner of record. A transfer is an update whose only change is the recipient.</p>
<p><b>Records</b> are short keys in the payload.</p>
<table><thead><tr><th>Key</th><th>Meaning</th></tr></thead><tbody><tr><td><code>s3</code></td><td>A folder on Sia holding the site</td></tr><tr><td><code>ip</code></td><td>IPv4 address of a server that answers for the name</td></tr><tr><td><code>tls</code></td><td>SHA-256 fingerprint of that server's certificate</td></tr><tr><td><code>p</code></td><td>An upstream URL the gateway reverse-proxies</td></tr><tr><td><code>u</code></td><td>A URL to redirect to</td></tr><tr><td><code>h</code></td><td>A page stored inline on the chain</td></tr><tr><td><code>a</code></td><td>A Bitcoin Cash address for payments</td></tr></tbody></table>
<p>Two names carry system records: <code>electrum.bch</code> lists Electrum servers (<code>el</code>), and <code>tlds.bch</code> carries the legacy top-level list that clients still read as the native set.</p>
<p><b>Validity is computed, not declared.</b> Every client sorts the beacon's history by height and transaction, orders it so no transaction is indexed before one it spends from, and applies two rules: the first valid registration of a name wins, and an update counts only if one of its outputs carries the name's own certificate category. Uniqueness is therefore indexer policy that every honest client reaches identically, not chain consensus. The protocol has no expiry of its own. Whether names under a top-level domain are bought outright or leased, per year, per two years or not at all, is a term that domain's certificate holder can set; no name expires today. Front-running of a pending registration is possible today; a commit-reveal scheme is specified but not implemented.</p>
<p><b>Top-level domains</b> are digital certificates of the same shape on a second beacon. A TLD's records set its policy: <code>open</code>, <code>cosign</code>, <code>covenant</code> or <code>frozen</code>; a minimum label length; reserved labels; the owner's fee share in basis points (500 by default, capped at 5,000); a flat USD price that replaces tier pricing; and <code>hidden</code>, which takes the TLD off public listings and restricts registration to the owner. A registration under a <code>cosign</code> or <code>hidden</code> TLD is valid only if the transaction also spends and re-issues the TLD's certificate, so the TLD owner countersigns every name under it; the gateway keeps a seven-day queue of co-sign requests and signs nothing itself. Every policy change is a <code>TUPD</code> kept on a timeline, so a name is judged by the policy in force at its own height.</p>
<p><b>Ownership can be sold in one transaction.</b> A seller signs the certificate input and a payout output with the SIGHASH_SINGLE | ANYONECANPAY flag; anyone can complete the sale by adding payment and receiving the certificate, and cancelling is spending the certificate once. USD-pegged listings move the certificate into a covenant that pays out <code>target / price</code>, clamped between a floor and a ceiling, against an oracle quote the gateway signs from the median of five exchanges.</p>
<h2 id="resolution-from-a-name-to-content">Resolution: from a name to content</h2>
<p>Theseus treats every dotted host as a Bitcoin Cash name first and falls back to ordinary DNS only when the registry has no record for it. The registry does not privilege ICANN: <code>example.com</code> is looked up on the chain before it is looked up in DNS, and only <code>localhost</code>, IP literals and single-label hosts skip the chain. What the browser resolves against is not a remote service but a local index of the whole registry, rebuilt from sources that can be checked against each other.</p>
<figure class="diagram"><svg viewBox="0 0 760 328" role="img" aria-label="Four sources build one local index and the record picks the source" font-family="system-ui,-apple-system,Segoe UI,Roboto,sans-serif" font-size="13"><defs><marker id="res-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" fill="#5e6678"/></marker></defs>
<text x="24" y="34" font-size="15" font-weight="600" fill="#e7eaf1">Four sources build one local index; the record picks the source</text>
<g fill="none" stroke="#5e6678" stroke-width="1.25"><path d="M220 88L290 184" marker-end="url(#res-arrow)"/><path d="M220 152L290 184" marker-end="url(#res-arrow)"/><path d="M220 216L290 184" marker-end="url(#res-arrow)"/><path d="M220 280L290 184" marker-end="url(#res-arrow)"/><path d="M470 184L540 88" marker-end="url(#res-arrow)"/><path d="M470 184L540 152" marker-end="url(#res-arrow)"/><path d="M470 184L540 216" marker-end="url(#res-arrow)"/><path d="M470 184L540 280" marker-end="url(#res-arrow)"/></g>
<g><rect x="24" y="64" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="36" y="84" font-weight="600" fill="#e7eaf1">Bundled snapshot</text><text x="36" y="101" font-size="11.5" fill="#8b98a9">ships in the build</text></g><g><rect x="24" y="128" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="36" y="148" font-weight="600" fill="#e7eaf1">Profile snapshot</text><text x="36" y="165" font-size="11.5" fill="#8b98a9">saved after every poll</text></g><g><rect x="24" y="192" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="36" y="212" font-weight="600" fill="#e7eaf1">Electrum delta poll</text><text x="36" y="229" font-size="11.5" fill="#8b98a9">beacon history, every 30 s</text></g><g><rect x="24" y="256" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="36" y="276" font-weight="600" fill="#e7eaf1">Sia name list</text><text x="36" y="293" font-size="11.5" fill="#8b98a9">one fetch, used next boot</text></g>
<g><rect x="290" y="140" width="180" height="88" rx="8" fill="#d6ff3d" fill-opacity=".12" stroke="#d6ff3d" stroke-width="2"/><text x="380" y="170" text-anchor="middle" font-weight="600" fill="#e7eaf1">Local name index</text><text x="380" y="192" text-anchor="middle" font-size="11.5" fill="#8b98a9">first valid REG wins</text><text x="380" y="210" text-anchor="middle" font-size="11.5" fill="#8b98a9">UPD only from the holder</text></g>
<g><rect x="540" y="64" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="552" y="84" font-weight="600" fill="#e7eaf1">Sia site (s3)</text><text x="552" y="101" font-size="11.5" fill="#8b98a9">through the gateway mount</text></g><g><rect x="540" y="128" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="552" y="148" font-weight="600" fill="#e7eaf1">Owner's server (ip)</text><text x="552" y="165" font-size="11.5" fill="#8b98a9">TLS fingerprint pinned</text></g><g><rect x="540" y="192" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="552" y="212" font-weight="600" fill="#e7eaf1">Proxy, redirect, inline</text><text x="552" y="229" font-size="11.5" fill="#8b98a9">p, u and h records</text></g><g><rect x="540" y="256" width="196" height="48" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="552" y="276" font-weight="600" fill="#e7eaf1">Signed DNS A record</text><text x="552" y="293" font-size="11.5" fill="#8b98a9">when no content record</text></g>
</svg><figcaption>Resolution: four sources, one index, four ways to serve.</figcaption></figure>
<p>Every source writes the same index, so the browser never depends on one of them; the name's own record then decides where the bytes come from.</p>
<p><b>Four sources feed the index.</b> They start in a fixed order at launch and none of them is trusted alone.</p>
<ol><li><b>Bundled snapshot.</b> Every build ships a snapshot of the registry's beacon history (44 names and 73 beacon transactions in 0.3.59). The browser prefers a newer snapshot it has saved itself under the profile. Either way the snapshot is a floor: the index is marked stale the moment it loads, so the live sources overwrite it.</li><li><b>Delta poll.</b> Every 30 seconds the browser opens an Electrum connection, asks for the beacon's transaction history, fetches only the transactions it has not seen, and rebuilds the index. The result is written back as the profile's snapshot, so the next launch starts where this one ended.</li><li><b>Full walk.</b> On a first launch with no snapshot at all, the browser walks the beacon's entire history before answering.</li><li><b>Sia snapshot.</b> A published name list is fetched from decentralized storage and saved for the next boot, so a long-offline install catches up in one request.</li></ol>
<p>The Electrum servers come from a seed list compiled into the resolver and from the chain itself: the <code>electrum.bch</code> name carries an <code>el</code> record listing servers, refreshed at most every 30 minutes. The browser connects by hostname first and, if that fails, by the server's pinned IP with the hostname as the TLS name, which defeats DNS interference against the resolver's own transport. With Tor on, these connections go through the SOCKS proxy.</p>
<p><b>Reducing history to an index</b> is deterministic and identical on every client: the first valid registration of a name wins, and an update is honoured only when the transaction carries a proof output of the name's own certificate category, that is, only when the current holder signed it. A client that reaches the same history therefore computes the same index as every other client, with no resolver in between.</p>
<p><b>Serving the name.</b> Once a host has an entry, the browser loads it through its own <code>bns://</code> scheme and chooses the source in this order:</p>
<ol><li>A subdomain rule set by the owner (block or redirect), fetched from the gateway for hosts served directly.</li><li>A subdomain with an <code>ip</code> record is served from that IP.</li><li>Inline HTML stored on the chain (<code>h</code>), for the root path only.</li><li>A Sia site (<code>s3</code>), fetched through the public gateway's <code>/bns/</code> mount, which holds the storage keys so the browser never does.</li><li>A server address (<code>ip</code>), fetched directly. If the name also carries a <code>tls</code> record, the connection is pinned: the server certificate's SHA-256 fingerprint must equal the record or the socket is dropped, with no fallback to plain HTTP.</li><li>A proxied upstream (<code>p</code>), reverse-proxied by the browser with any path prefix kept.</li><li>A redirect (<code>u</code>).</li><li>Failing all of those, the first IPv4 address from the owner's signed DNS records, with the same TLS pin applied.</li></ol>
<p>On-chain records are authoritative. Signed DNS records extend them and never override them. Records for a name are fetched only after the name is known to be registered, so ordinary DNS hosts the user visits are never sent to the gateway.</p>
<p><b>Collisions.</b> A name that exists both on the chain and in ICANN's root is a collision. The default policy is chain first; the user can choose ICANN first, or ask each time, in which case an in-tab page offers both and can remember the choice per name or per top-level domain. Names under the registry's native top-level domains, listed on the chain by the <code>tlds.bch</code> name, are never treated as collisions.</p>
<p><b>Limits as of 0.3.59.</b> A lookup miss on an index older than eight seconds waits for one poll before answering, so an unknown host can pause a navigation by the length of one Electrum round trip. History is taken from one server at a time; the resolver library can union several servers but the browser does not yet use that path. The profile snapshot is validated by shape only, not by signature.</p>
<h2 id="content-and-records">Content and records</h2>
<p>A name points at content in one of five ways, and the two that matter most, a site on Sia and a pinned server, need no host that can be switched off and no certificate authority that can be fooled.</p>
<p><b>Sites on Sia.</b> The owner uploads a folder to the Sia network through an S3-compatible endpoint and puts its path in the name's <code>s3</code> record. The public gateway serves it at <code>navigate.st/bns/&lt;name&gt;/</code>, with the usual conveniences of a static host: <code>index.html</code> for folders, <code>/about</code> for <code>about.html</code>, and a single-page fallback to the root. Theseus reads the same mount through its <code>bns://</code> scheme, so the storage keys live on the gateway and never in the browser. Sirius Studio and Sirius Press publish straight into that folder through a gateway API where every upload is signed over the name, the path, the file's hash and a timestamp, and the signature must recover to the current holder of the certificate. Nothing else can write there.</p>
<p><b>Pinned servers.</b> An <code>ip</code> record names a server; a <code>tls</code> record beside it names the SHA-256 fingerprint of that server's certificate. The browser connects directly, ignores the certificate chain, and accepts the connection only if the fingerprint matches. The owner's own key is the trust anchor, published on the chain they control, so no authority can issue a certificate the browser would accept for that name. If the fingerprint does not match, the socket is dropped and there is no fallback to plain HTTP.</p>
<p><b>Inline, proxied and redirected.</b> A page small enough to fit the payload can live on the chain itself (<code>h</code>), served at the root path only. A <code>p</code> record makes the gateway or the browser reverse-proxy an upstream URL, keeping the path. A <code>u</code> record redirects. On the apex the order is inline, then Sia, then IP, then proxy, then redirect; for a subdomain an <code>ip</code> record wins first and a proxy is not inherited.</p>
<p><b>Signed records without a transaction.</b> Everything a DNS zone would carry lives in a file the owner signs and stores beside the site: <code>_records.json</code>. It carries a sequence number, a timestamp and A, AAAA, MX, TXT, CNAME, NS, CAA and SRV records, canonicalised with sorted keys and signed with the same key that holds the name. The gateway verifies the signature against the current certificate holder on every read, rejects a sequence number that goes backwards, and answers <code>GET /api/dns/&lt;name&gt;</code> with the verified records and a 30-second cache. Publishing an update is a signed POST, no chain transaction and no fee. Version 2 adds a <code>hosts</code> map: each subdomain can have its own folder in the bucket, a redirect, a block, or its own record set, with a wildcard entry and a depth of up to eight labels. A block beats a redirect beats a folder, and an exact entry beats the wildcard.</p>
<p>On-chain records are authoritative and signed records extend them. A signed A record is used only when the name carries no content record at all, and the on-chain <code>tls</code> pin still applies to it. Theseus fetches these records only for names it already knows are registered, so ordinary hosts the user visits are never revealed to the gateway, and it never waits for the fetch before loading a page.</p>
<p><b>Subdomain rules apply everywhere.</b> Since 0.3.59 the browser asks the gateway for a host's verified rule before serving a subdomain from an IP or from inline HTML, the two paths it serves without the gateway. A subdomain the owner has blocked or redirected therefore behaves the same whether the name is served from Sia, from the owner's server or through a proxy, and an ordinary subdomain navigation gains no round trip.</p>
<p><b>Certificates for other browsers.</b> Theseus needs no certificate authority because it checks the pin itself. Other browsers do, which is what the system-wide resolver described later provides: a local root constrained to the registry's top-level domains that mints a leaf per name on the user's own machine.</p>
<h2 id="privacy-and-protections">Privacy and protections</h2>
<p>Every protection below is on from the first launch. The table gives the mechanism and the default; the paragraphs after it give the detail that matters for a threat model.</p>
<table><thead><tr><th>Protection</th><th>Mechanism</th><th>Default</th></tr></thead><tbody><tr><td>Shield</td><td>Network request blocking against EasyList and EasyPrivacy, refreshed daily</td><td>On, allow per site</td></tr><tr><td>Cookie Pop-ups</td><td>Answers consent banners with the DuckDuckGo autoconsent rules (844 rules)</td><td>On, reject all but essentials</td></tr><tr><td>DNS over HTTPS</td><td>Chromium's built-in resolver with an encrypted upstream</td><td>Automatic, Quad9</td></tr><tr><td>Global Privacy Control</td><td><code>Sec-GPC: 1</code> header and <code>navigator.globalPrivacyControl</code></td><td>On</td></tr><tr><td>Camera, microphone, location</td><td>Permission denied unless the user allows</td><td>Denied</td></tr><tr><td>Hardware device APIs (USB, HID, serial, Bluetooth, MIDI)</td><td>Always denied</td><td>Denied</td></tr><tr><td>Media device enumeration</td><td>One blank entry per kind</td><td>Hidden</td></tr><tr><td>WebRTC</td><td>Public interface only, no non-proxied UDP under Tor</td><td>Public only</td></tr><tr><td>Timezone and language</td><td>Chromium emulation overrides; show, hide or spoof</td><td>Show</td></tr><tr><td>Browser identity</td><td>User agent and client hints shaped like the Chromium release inside</td><td>Always</td></tr><tr><td>Cookies, cache, history, site storage</td><td>Cleared on quit</td><td>Cleared</td></tr><tr><td>Tor</td><td>Bundled Tor, SOCKS proxy for the whole session</td><td>Off, one click</td></tr></tbody></table>
<p><b>Shield</b> runs inside the browser's one request hook. The main process owns the single <code>onBeforeRequest</code> listener for the session and asks each registered filter for a verdict, so add-ons cannot install competing hooks. The engine is Ghostery's adblocker library with network filters only; cosmetic filtering is not yet applied. A blocked request is cancelled before it leaves the machine. Top-level navigations are never blocked, so a page always loads even when its trackers do not.</p>
<p><b>Cookie Pop-ups</b> runs in the isolated world of every page and answers the consent dialog the way a careful user would, rejecting everything but the essentials. It never sends anything anywhere; the rule set ships with the browser.</p>
<p><b>DNS over HTTPS</b> has three modes. Automatic uses the encrypted resolver and falls back to the system resolver when it is unreachable. Increased protection never falls back, so a network that blocks the resolver blocks browsing rather than downgrading it. Off uses the system resolver. Providers are Quad9, Cloudflare, Mullvad, AdGuard, or any HTTPS resolver URL. This covers ordinary DNS hosts; chain names never touch DNS at all. With Tor on, hostnames resolve at the exit, not locally.</p>
<p><b>Identity.</b> Theseus does not announce itself. The user agent drops the Electron and application tokens, the client-hint brands and their order are computed the way Chromium computes them, and both the JavaScript surface and the request headers agree. This is what keeps commercial bot filters from rejecting the browser. A <code>window.chrome</code> shim fills the properties sites test for.</p>
<p><b>Tor</b> is bundled, not downloaded. One click starts the bundled binary with its own data directory and geoip files and points the session's proxy at it; the Electrum connections, Sia fetches and pinned IP fetches follow the same proxy, and WebRTC is restricted to proxied paths so no UDP leaves directly. Tor state is not remembered across launches. The browser is explicit that this buys IP privacy, not anonymity: it does not change the fingerprinting surface the way Tor Browser does.</p>
<p><b>VPN</b> is an add-on rather than a core feature. It runs a pinned build of sing-box speaking VLESS over REALITY with a Chrome TLS fingerprint, verifies the binary's hash before every start, and can use Silent Mode exits, a pasted <code>vless://</code> URL or a subscription URL. Exits with keys are not yet issued as of this version.</p>
<p><b>What is not done.</b> There is no referrer-policy override, no Do Not Track header, and no third-party cookie blocking beyond what clearing on quit achieves. Four main-process fetches, the gateway record lookups, the Sia snapshot pull, the proxied <code>p</code> upstream and the update check, use the process's plain HTTP client and do not follow the Tor proxy. Fingerprinting defences are opt-in emulation rather than a uniform fingerprint.</p>
<h2 id="wallet-and-dapps">Wallet and dapps</h2>
<p>Aegis is the wallet built into Theseus as a plug-in. It holds keys for seven chains from one recovery phrase, keeps every secret in memory only, and lets pages transact through injected providers that can do nothing without an approval drawn by the browser itself.</p>
<table><thead><tr><th>Chain</th><th>Networks</th><th>Derivation</th></tr></thead><tbody><tr><td>Bitcoin Cash</td><td>mainnet, chipnet</td><td>BIP32 <code>m/44'/145'/0'</code></td></tr><tr><td>Bitcoin</td><td>mainnet, testnet, signet</td><td>BIP44, 49, 84, 86</td></tr><tr><td>DigiByte</td><td>mainnet</td><td>BIP44, 49, 84, 86, coin type 20</td></tr><tr><td>Ethereum</td><td>mainnet, Sepolia, custom EIP-3085 chains</td><td><code>m/44'/60'/0'/0/0</code></td></tr><tr><td>Solana</td><td>mainnet, devnet</td><td>SLIP-0010 <code>m/44'/501'/0'/0'</code></td></tr><tr><td>Tron</td><td>mainnet, Nile</td><td><code>m/44'/195'/0'/0/0</code></td></tr><tr><td>Siacoin</td><td>mainnet</td><td>walletd v2 keys, <code>blake2b(seed, index)</code></td></tr></tbody></table>
<p><b>Key material.</b> The recovery phrase becomes a 64-byte seed the standard way, and that seed is used exactly once: to derive a per-purpose root with HKDF. The vault, which is the same vault the password manager uses, stores only that root, encrypted with 200,000 rounds of PBKDF2 and AES-GCM; the seed itself is never written to disk. Each wallet then derives its own 32-byte root from the purpose root with a fixed HKDF label, and each chain derives its keys from that. Changing any of these labels would orphan funds, so they are frozen. Imported wallets live in a second file under the same password with a different salt, so a leaked purpose root yields none of their keys. The host enforces that a plug-in can derive only under its own identifier.</p>
<p><b>Unlocking.</b> The vault unlocks with the master password in the main process; the password never reaches a renderer. An optional stay-signed-in mode keeps it encrypted under the operating system's own store, with a 15-minute idle lock and a lock on close by default. A quick-access PIN wraps the password under a PBKDF2-derived key.</p>
<p><b>The page bridge.</b> On chain-name sites Aegis injects <code>window.bitcoincash</code> with three calls: get an address, sign and send, sign a message. On every HTTPS page it injects an EIP-1193 <code>window.ethereum</code> provider (announced through EIP-6963 as <code>st.silentmode.aegis</code>), a <code>window.solana</code> provider, and the Tron provider surface, all speaking to the isolated world over tagged messages. Nothing injected can sign, read a balance or read an address on its own.</p>
<p><b>Approval.</b> Every request from a page lands in an approval sheet the browser draws in its own view, never in the page: it names the plug-in and the requesting origin, one request at a time per origin, with focus on Cancel so Enter never approves a spend by accident. Permissions are remembered per origin: address access can be granted once, and a Bitcoin Cash spending allowance of 0.001, 0.01 or 0.1 BCH lets small payments through without a prompt until it is used up.</p>
<p><b>Pairing.</b> For wallet-to-app sessions Aegis speaks WizardConnect, the LGPL protocol used by Bitcoin Cash applications, with an explicit pairing approval and no reading of the page to find a session URI. Price lookups are off until the user turns them on, so a fresh install contacts no oracle.</p>
<p><b>Limits as of 0.9.0.</b> Siacoin needs a walletd endpoint the user provides, with a public explorer as read-only fallback. WalletConnect is not implemented. The wallet is ordinary JavaScript running with the browser's privileges, which is the trust model of every plug-in and is discussed under Security model.</p>
<h2 id="extensions-and-plug-ins">Extensions and plug-ins</h2>
<p>Theseus has its own add-on model rather than Chrome's, and it publishes community extensions the same way it publishes sites: signed by a name's owner and stored on Sia, with the browser checking the signature against its own copy of the registry.</p>
<p><b>The host.</b> An add-on is a folder with a manifest and a main script. The manifest declares an identifier, a version, a category (extension by default, or plug-in for wallets and other trusted components), and the capabilities it needs. Eleven capabilities exist, each unlocking one API:</p>
<table><thead><tr><th>Capability</th><th>Grants</th></tr></thead><tbody><tr><td><code>sidebar-panel</code></td><td>A panel in the browser's sidebar</td></tr><tr><td><code>page-inject</code></td><td>Runs a script in matching pages, in the isolated world</td></tr><tr><td><code>request-filter</code></td><td>A verdict on every subresource request; top-level navigations are never blocked</td></tr><tr><td><code>session-proxy</code></td><td>Swaps the session's outbound proxy, the primitive Tor and VPN use</td></tr><tr><td><code>vault-derive</code></td><td>Keys derived from the vault under the add-on's own identifier only</td></tr><tr><td><code>approval-modal</code></td><td>An approval sheet drawn by the browser</td></tr><tr><td><code>capture-tab</code></td><td>Screenshots of the active tab</td></tr><tr><td><code>scan-page</code></td><td>Matching URIs from the active tab, never page content</td></tr><tr><td><code>open-tab</code></td><td>The add-on's own pages as full tabs</td></tr><tr><td><code>toolbar-menu</code></td><td>A dropdown on the toolbar</td></tr><tr><td><code>context-menu-item</code></td><td>Right-click items with a condition</td></tr></tbody></table>
<p>Unknown capabilities are dropped. Storage, host module imports and messaging need no capability. Page scripts run in the isolated world with a bridge that offers only the add-on's identifier, the page's origin, a message channel and an explicit evaluate-in-page call. Messages from a page are accepted only from origins the manifest lists, and messages from a panel only from the add-on's own files.</p>
<p><b>The trust model is stated plainly in the code:</b> the main script is loaded into the browser's main process with full privileges, the same model as a developer-mode browser extension. Capabilities scope what the host offers; they are not a sandbox. Installing a community extension shows a prompt naming the publisher and the site that asked, and says so in those words.</p>
<p><b>Nine add-ons ship with the browser.</b> Aegis (wallet, plug-in), Shield, Cookie Pop-ups, a Word editor for <code>.docx</code>, a PDF editor, a screenshot tool with annotation, a translator using LibreTranslate or Google, a VPN client, and a notepad that serves as the reference add-on. Bundled add-ons cannot be removed, only turned off, and are re-seeded from the build only when the bundled version is newer than the installed one.</p>
<p><b>Updates are signed twice over.</b> Each add-on has an update channel on Sia, reached through the gateway. A channel entry names a version, a tarball, its SHA-256 and a signature; the browser accepts it if the operator's Ed25519 key signs it, or if the publisher's signature verifies as described below. The tarball's hash must match, the extracted manifest's identifier and version must match the entry, size caps apply (16 MB for the package, 128 KB for the manifest), and only versions newer than the installed one are taken. Updates are staged and promoted at the next launch, or in place for extensions on request; a wallet mid-session is never hot-swapped. There is one operator key today, and it can sign an update for any identifier, which is on the roadmap to narrow.</p>
<p><b>Community publishing.</b> A publisher who owns a name uploads a package to the gateway with two signatures from that name's key, one over the upload and one over the catalogue entry, both required to recover to the name's current certificate holder. An extension identifier belongs to the first name that publishes it, and versions must increase. When Theseus installs or updates a community extension, it recovers the signer of the entry and compares it with the owner it finds for that name in its own index, not the gateway's, so the gateway cannot substitute a publisher. The publish page on <code>theseus.x</code> does the signing in the page from a recovery phrase that never leaves it, and installs are one click from that site through a <code>theseus://extensions/install/</code> link or a page-side bridge.</p>
<p><b>Plug-ins</b> are the category for components that hold keys or route traffic: Aegis is one, and the system-wide resolver is managed from the same place. They are listed apart from extensions in Settings, their updates wait for a restart, and the toolbar chip that announces a ready update stays silent for them.</p>
<h2 id="beyond-the-browser">Beyond the browser</h2>
<p>Theseus needs nothing installed on the machine to resolve names, but everything else on the machine does. Three companions extend the same registry to other browsers, to Android, and to the people who register and publish names. All of them share the resolver code with Theseus, so a name resolves the same everywhere.</p>
<p><b>Ariadne's Thread</b> is a Windows service that makes the registry visible to every application. Its installer, version 0.1.9 as of this writing, adds one Name Resolution Policy Table rule per routable top-level domain, so only those names are sent to a local daemon and everything else keeps the system's own DNS; a full mode that repoints the adapters exists but is not the default. The daemon answers DNS on the loopback address, serves HTTP and HTTPS for names, and keeps its own index of the chain by the same Electrum walk the browser uses, refreshed every 30 seconds. For HTTPS it holds a root certificate generated on the machine itself with a critical name-constraints extension limiting it to the registry's top-level domains and excluding every IP range, and it mints a two-year leaf per name on first request; the installer refuses to trust any root without those constraints, and the private key never leaves the machine. Names with an <code>ip</code> and <code>tls</code> record are reverse-proxied through the same fingerprint check Theseus applies. The list of top-level domains is synchronised every six hours from the registry's routable list minus every TLD delegated by IANA, so <code>.com</code> and its kind stay with ordinary DNS; when the list changes, the rules are adjusted and the root is rotated. A collision policy file is re-read every five seconds, so the browser's setting and the system's can agree. Theseus offers install, update, on and off from its Settings and checks the installer's hash before it runs.</p>
<p><b>Ariadne for Android</b>, version 0.21, is a tabbed browser for phones with the same resolution stack: a bundled index, a snapshot the gateway refreshes every ten minutes, an on-device Electrum walk with a 60-second cache, and a gateway fast path that races the trustless path. It claims the registry's routable top-level domains at start and refreshes them from the gateway. An optional system-wide mode runs a DNS-only VPN service on the device so other apps resolve names too; it tunnels nothing else. The package is signed with Silent Mode's own key, its certificate hash is published in the release manifest, and it is distributed from the download host rather than a store.</p>
<p><b>Sirius</b> is the registrar and the publishing desk, reachable at <code>sirius.x</code> and mirrored on the ICANN site. Registration runs entirely in the page: a built-in wallet unlocked, created or imported there, or a WizardConnect pairing with a mobile wallet, builds the one transaction that mints the certificate and pays the fees. The dashboard manages every name and TLD the wallet holds: DNS records and subdomain rules through the signed manifest at no cost, content and hosting, redirects, transfers, marketplace listings in BCH or USD, TLD policy and pricing with 90% of each sale to the owner, and the co-sign queue for gated TLDs. Sirius Studio is a page builder on GrapesJS that publishes straight to the name's Sia folder through signed uploads and sets the <code>s3</code> record with one transaction when needed; its optional assistant runs a small language model in the tab over WebGPU or against a local endpoint, and never executes model output. Sirius Press is a WordPress fork whose only change to core is 75 lines: accounts are Bitcoin Cash addresses, sign-in is a signed challenge, and every page is mirrored as static HTML to the name. The registrar speaks seven languages.</p>
<p><b>Hephaestus</b> hosts the source. It is a Forgejo instance where the account is a Bitcoin Cash address and sign-in is a signed message through an OpenID Connect proxy, with repositories on the server and large files, attachments and packages on Sia. It answers on the ICANN name with a public certificate and on <code>hephaestus.x</code> with the project's own root.</p>
<figure class="diagram"><svg viewBox="0 0 760 368" role="img" aria-label="Every client reads the chain itself; the gateway only serves bytes" font-family="system-ui,-apple-system,Segoe UI,Roboto,sans-serif" font-size="13"><defs><marker id="arch-arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="6" markerHeight="6" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" fill="#5e6678"/></marker></defs>
<text x="24" y="34" font-size="15" font-weight="600" fill="#e7eaf1">Every client reads the chain itself; the gateway only serves bytes</text>
<g fill="none" stroke="#5e6678" stroke-width="1.25"><path d="M109 120L109 176" marker-end="url(#arch-arrow)"/><path d="M283 120L283 176" marker-end="url(#arch-arrow)"/><path d="M457 120L320 176" marker-end="url(#arch-arrow)"/><path d="M631 120L320 176" marker-end="url(#arch-arrow)"/><path d="M109 120L440 176" marker-end="url(#arch-arrow)"/><path d="M283 120L440 176" marker-end="url(#arch-arrow)"/><path d="M457 120L457 176" marker-end="url(#arch-arrow)"/><path d="M631 120L631 176" marker-end="url(#arch-arrow)"/><path d="M416 204H344" marker-end="url(#arch-arrow)"/><path d="M576 232V288" marker-end="url(#arch-arrow)"/></g>
<text x="380" y="196" text-anchor="middle" font-size="11.5" fill="#8b98a9">same chain</text>
<g><rect x="24" y="64" width="170" height="56" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="36" y="84" font-weight="600" fill="#e7eaf1">Theseus Navigator</text><text x="36" y="101" font-size="11.5" fill="#8b98a9">desktop browser</text></g><g><rect x="198" y="64" width="170" height="56" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="210" y="84" font-weight="600" fill="#e7eaf1">Ariadne's Thread</text><text x="210" y="101" font-size="11.5" fill="#8b98a9">Windows resolver</text></g><g><rect x="372" y="64" width="170" height="56" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="384" y="84" font-weight="600" fill="#e7eaf1">Ariadne for Android</text><text x="384" y="101" font-size="11.5" fill="#8b98a9">phone browser</text></g><g><rect x="546" y="64" width="170" height="56" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="558" y="84" font-weight="600" fill="#e7eaf1">Sirius</text><text x="558" y="101" font-size="11.5" fill="#8b98a9">registrar and studio</text></g>
<g><rect x="24" y="176" width="320" height="56" rx="8" fill="#d6ff3d" fill-opacity=".12" stroke="#d6ff3d" stroke-width="2"/><text x="184" y="196" text-anchor="middle" font-weight="600" fill="#e7eaf1">Bitcoin Cash chain</text><text x="184" y="213" text-anchor="middle" font-size="11.5" fill="#8b98a9">read through Electrum servers, reduced locally</text></g>
<g><rect x="416" y="176" width="320" height="56" rx="8" fill="none" stroke="#5e6678" stroke-width="1.25"/><text x="576" y="196" text-anchor="middle" font-weight="600" fill="#e7eaf1">Gateway, navigate.st</text><text x="576" y="213" text-anchor="middle" font-size="11.5" fill="#8b98a9">serves Sia sites, verifies signed records</text></g>
<g><rect x="416" y="288" width="320" height="56" rx="8" fill="rgba(255,255,255,.04)" stroke="#5e6678" stroke-width="1.25"/><text x="576" y="310" text-anchor="middle" font-weight="600" fill="#e7eaf1">Sia storage</text><text x="576" y="328" text-anchor="middle" font-size="11.5" fill="#8b98a9">sites, signed records, extensions</text></g>
</svg><figcaption>Architecture: four clients, one chain, one gateway.</figcaption></figure>
<p>The three resolvers and the registrar all read the chain directly; the gateway is where bytes come from and where signed uploads land, and it reads the same chain to know who may write.</p>
<h2 id="security-model">Security model</h2>
<p>The design goal is that no single party between the user and a page can change what the page is. The table says who is trusted for what in 0.3.59; the paragraphs after it say what an attacker in each position can and cannot do.</p>
<table><thead><tr><th>Question</th><th>Who decides</th><th>What Theseus checks</th></tr></thead><tbody><tr><td>Who owns a name</td><td>The Bitcoin Cash chain</td><td>Beacon history from Electrum, reduced locally by fixed rules</td></tr><tr><td>What a name's records say</td><td>The owner, by an on-chain update</td><td>Same reduction; an update must carry the name's certificate</td></tr><tr><td>What a name's DNS records say</td><td>The owner, by a signed file</td><td>Signature recovered to the current certificate holder, by the gateway</td></tr><tr><td>Whether a pinned server is genuine</td><td>The owner's <code>tls</code> record</td><td>Certificate fingerprint compared in the browser, no chain of trust</td></tr><tr><td>What a Sia site contains</td><td>Whoever holds the name's signing key</td><td>Gateway checks the upload signature; the browser trusts the gateway for bytes</td></tr><tr><td>Which extension is genuine</td><td>The publisher's name, or the operator key</td><td>Publisher signature checked against the browser's own registry index</td></tr><tr><td>Which browser update is genuine</td><td>The ICANN mirror over TLS</td><td>SHA-256 from the manifest, no publisher signature yet</td></tr></tbody></table>
<p><b>A hostile network</b> can block or delay but not redirect. It sees encrypted DNS to a chosen resolver, TLS to Electrum servers reached by pinned IP if hostnames fail, and, with Tor on, only Tor. It cannot forge a name: the index is computed from chain history, and a fake history would need a valid transaction spending the beacon's coins. It cannot forge a pinned site: the fingerprint is on the chain. It can still see which Electrum servers and which gateway the browser talks to when Tor is off.</p>
<p><b>A hostile Electrum server</b> can lie by omission, returning a truncated history, which would make a recently registered name resolve as absent and fall through to ordinary DNS. It cannot invent a registration, because every entry is a real transaction the client parses itself. The defence today is the pool with several independent operators and pinned addresses; a union across servers exists in the resolver library and is not yet used by the browser.</p>
<p><b>A hostile gateway</b> is the largest remaining trust. For Sia sites the browser takes the bytes from the gateway's mount and cannot verify them against the chain, because the site is not hashed on the chain. For signed DNS records the gateway does the verification and the browser trusts its answer. The gateway can therefore serve a substituted Sia site or a substituted A record to a browser, though not a substituted pinned site, and not a substituted publisher for an extension, because that check runs against the browser's own index. Reducing this trust, by verifying manifests in the browser and by hashing site roots on the chain, is the main item on the roadmap.</p>
<p><b>A hostile certificate authority</b> gains nothing against a pinned name and nothing against a Sia site reached through the gateway's own certificate, which is itself an ordinary TLS endpoint. For names without a <code>tls</code> record that are served from an IP, the connection is plain HTTP and offers no protection at all; owners are expected to set the pin.</p>
<p><b>A hostile page</b> sees a browser shaped like the Chromium inside it, without the Electron tokens, with hardware and media APIs denied, and with wallet providers that can do nothing without an approval drawn outside the page. It can request fullscreen, notifications and the other benign permissions. It cannot reach the registry APIs beyond read-only lookups, and it cannot learn whether a wallet exists until the user pairs.</p>
<p><b>A hostile add-on</b> is the user's own decision. Add-on code runs in the main process with the browser's privileges, and the capabilities scope what the host offers rather than what the code can reach. Bundled add-ons come from the build; community extensions come from a named publisher whose ownership the browser checks; anything else is a folder the user placed there. There is no sandbox, and this paper does not claim one.</p>
<p><b>A hostile update</b> to the browser would have to come from the ICANN mirror over TLS, since the hash the browser checks is fetched from the same place as the file. A publisher signature on the manifest, verified against a key in the build, would close that; add-on updates already have it.</p>
<p><b>What the chain does not enforce.</b> Name uniqueness and the top-level-domain policies are indexer rules that every client applies identically; they are not consensus rules of Bitcoin Cash. A name under a top-level domain nobody has registered still indexes today because the existence gate is off by default. There is no recovery for a lost key and no authority that can return a name.</p>
<h2 id="distribution-and-updates">Distribution and updates</h2>
<p>Theseus ships as an unsigned Windows installer and a portable executable, each about 137 MB, with SHA-256 checksums published beside them, from two mirrors that do not share a failure mode.</p>
<ul><li><b>silentmode.st</b> on ordinary DNS, with stable links at <code>dl.silentmode.st/latest/</code> that redirect to the current versioned file. This is the mirror the updater reads.</li><li><b>silentmode.bch</b> on the name system, served from Sia through the gateway. A systemd timer mirrors the ICANN site into the Sia bucket every five minutes, so both surfaces carry the same release notes and hashes, and a user who can reach the chain can fetch the browser without touching DNS.</li></ul>
<p>The release page, the manifest and the <code>theseus.x</code> site all print the same two hashes, so a downloaded file can be checked against three independent surfaces.</p>
<p><b>The updater</b> checks the release manifest at launch and every six hours, downloads the installer silently in the background, and refuses to install anything whose SHA-256 does not match the manifest: a mismatch or a missing hash deletes the file and shows nothing. Only on success does the toolbar show an install chip. Clicking it quits the browser and hands over to a detached helper script that waits for the process to exit, runs the installer silently, checks that the application archive is present afterwards and reruns the installer once if it is not, then deletes itself. That last step exists because an installer killed mid-update once left an install with no application archive.</p>
<p>The manifest travels over HTTPS from the ICANN mirror; it is not yet signed by a publisher key, so the trust in an update rests on TLS to that host. A signed manifest is on the roadmap.</p>
<p><b>Add-ons update separately.</b> Bundled add-ons are seeded into the profile at first launch and re-seeded only when the bundled version changes. Updates for them and for community extensions arrive over their own channel on Sia, are verified against publisher keys, staged, and promoted in place; a four-hourly check and a toolbar chip cover the case where the user never restarts.</p>
<p><b>Companion downloads.</b> The same manifest lists Ariadne's Thread for Windows and Ariadne for Android, and Theseus reads it to offer the system-wide resolver's install or update from Settings, with the same hash check before the installer runs.</p>
<h2 id="roadmap-and-open-questions">Roadmap and open questions</h2>
<p>The system works end to end today; the items below are what stands between that and a system a stranger can rely on, in the order they matter.</p>
<ol><li><b>Less trust in the gateway.</b> Verify signed record manifests inside the browser instead of taking the gateway's word, and put a content hash for a Sia site on the chain so the bytes can be checked. Until then the gateway can substitute a Sia site or a DNS answer.</li><li><b>Front-running.</b> The commit-reveal scheme for registrations is specified and not implemented.</li><li><b>Enforcement gates.</b> Turn on the top-level-domain existence check by default so names under unregistered TLDs stop indexing, and bring the co-sign rule to the snapshot path and to Android.</li><li><b>A signed release manifest</b> for browser updates, checked against a key in the build, so an update no longer rests on TLS to one host.</li><li><b>Per-identifier update keys</b> for add-ons, so the single operator key cannot sign an update for any extension.</li><li><b>Resolution robustness.</b> Use the union of several Electrum servers' history rather than one, and stop a lookup miss from waiting on a poll.</li><li><b>Tor coverage</b> for the remaining main-process fetches: gateway record lookups, the Sia snapshot pull, proxied upstreams and the update check.</li><li><b>Protections still missing:</b> an HTTPS-only mode, cosmetic filtering in Shield, a referrer policy, and third-party cookie controls.</li><li><b>Packaging.</b> macOS and Linux builds, and a code-signing arrangement that does not depend on a certificate authority's approval.</li></ol>
<p><b>Open questions</b> the design has not settled:</p>
<ul><li>Whether name uniqueness and TLD policy should stay indexer rules or become covenant-enforced on the chain, which is the difference between "every honest client agrees" and "no client can disagree".</li><li>How a top-level domain holder's rental terms, yearly, two-yearly or none, should be enforced on the chain rather than by the registrar, and what becomes of an abandoned name under a domain with no rent.</li><li>Whether a sandbox for add-ons is worth the loss of capability, given that the wallet itself is an add-on.</li></ul>
<h2 id="glossary-and-references">Glossary and references</h2>
<table><thead><tr><th>Term</th><th>Meaning</th></tr></thead><tbody><tr><td>BCNR</td><td>Bitcoin Cash Name Registry: the name system as a whole</td></tr><tr><td>BNS1</td><td>The payload protocol: <code>BNS1</code> plus JSON in one OP_RETURN output</td></tr><tr><td>Beacon</td><td>A fixed address every registration pays dust to, so its history is the registry</td></tr><tr><td>Certificate</td><td>The immutable digital certificate on the chain whose commitment is the name; holding it is holding the name</td></tr><tr><td>REG, UPD, TREG, TUPD</td><td>Register or update a name; register or update a top-level domain</td></tr><tr><td>Routable TLDs</td><td>The top-level domains a client should resolve and certify: the public listing plus the advertised set</td></tr><tr><td>Co-sign</td><td>A registration that must also spend and re-issue the TLD's certificate</td></tr><tr><td>Signed records</td><td><code>_records.json</code>, the owner-signed file on Sia that carries DNS-style records and subdomain rules</td></tr><tr><td>Gateway</td><td>The public HTTP service at navigate.st that serves Sia sites and verifies signed records; a convenience tier, not the trustless one</td></tr><tr><td>Pinned server</td><td>An <code>ip</code> record with a <code>tls</code> fingerprint; the browser accepts only that certificate</td></tr><tr><td>Collision</td><td>A name that exists both on the chain and in ICANN's root</td></tr><tr><td>Ariadne's Thread</td><td>The Windows system-wide resolver; Ariadne is also the Android browser</td></tr><tr><td>Sirius</td><td>The registrar, dashboard, Studio site builder and Press</td></tr><tr><td>Hephaestus</td><td>The wallet-authenticated code forge</td></tr></tbody></table>
<p><b>Public surfaces</b></p>
<ul><li>Theseus: <a href="https://navigate.st/bns/theseus.x/">theseus.x</a> through the gateway, <a href="https://silentmode.st/theseus">silentmode.st/theseus</a> on ICANN DNS</li><li>Downloads and release manifest: <a href="https://dl.silentmode.st/releases-manifest.json">dl.silentmode.st</a>, mirrored at <a href="https://navigate.st/bns/silentmode.bch/releases">silentmode.bch</a></li><li>Registrar: <a href="https://navigate.st/bns/sirius.x/">sirius.x</a></li><li>Source: <a href="https://code.silentmode.st/silentmode/theseus">code.silentmode.st/silentmode/theseus</a></li><li>Gateway API root: <a href="https://navigate.st/api/tlds">navigate.st/api/tlds</a>, <code>/api/registry</code>, <code>/api/dns/&lt;name&gt;</code>, <code>/api/records/&lt;name&gt;</code>, <code>/api/market</code>, <code>/api/cosign</code>, <code>/api/site</code>, <code>/api/ext</code></li></ul>
<p><b>Design documents in the repository</b> (paths under the Silent Mode monorepo): <code>Decentralized.DNS/PROTOCOL.md</code>, <code>Decentralized.DNS/DESIGN-tld-registry.md</code>, <code>Decentralized.DNS/DESIGN-signed-records-manifest.md</code>, <code>Decentralized.DNS/INTEGRATION-signed-records-clients.md</code>, <code>Argus/DESIGN-collision-modes.md</code>, <code>TheseusNavigator/docs/ADDON-UPDATES.md</code>, <code>Argus/src/lib/resolver-web.js</code> (the network table and reduction rules), <code>Argus/src/lib/manifest.js</code> (manifest validity), <code>Argus/src/lib/register-tx.js</code> (transaction shapes).</p>
<p><b>Licensing.</b> Theseus Navigator, Ariadne's Thread and Ariadne for Android are published under the Mozilla Public License 2.0, the file-level copyleft Firefox and Brave use: changes to the project's own files stay open, and anything may be built on the browser. The resolver, gateway and protocol libraries are under the Apache License 2.0, so that other implementations of the registry can reuse them freely; the protocol documents and this paper are under Creative Commons Attribution 4.0. Sirius Press is GPL-2.0-or-later, as WordPress requires. Each build ships a third-party notices file: Chromium via Electron, Tor, DuckDuckGo autoconsent and the Ghostery adblocker (MPL-2.0), EasyList and EasyPrivacy, pdf.js, pdf-lib, mammoth, WizardConnect (LGPL-3.0), and the sing-box binary the VPN add-on fetches (GPL-3.0), whose complete source is published beside the binary. The project's names and marks are reserved and not covered by any of these licenses, so a fork must ship under its own name.</p>
<p>All facts in this paper were read from the source tree and the live surfaces on 2026-09-28 and describe Theseus Navigator 0.3.59, Ariadne's Thread 0.1.9 and Ariadne for Android 0.21.</p>
</article>
</main>
</div>
</div>
<footer>
<p>theseus.x is a BCNR name resolving to a Sia-hosted static site.
Source and issues: <a href="https://silentmode.st/">silentmode.st</a>.
Alpha software on a test network.</p>
<p>This paper is published under <a href="https://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
Theseus Navigator is free software under the <a href="https://code.silentmode.st/silentmode/theseus/src/branch/master/LICENSE">Mozilla Public License 2.0</a>;
its <a href="https://code.silentmode.st/silentmode/theseus/src/branch/master/THIRD-PARTY-NOTICES.md">third-party notices</a> and
<a href="https://code.silentmode.st/silentmode/theseus/src/branch/master/TRADEMARKS.md">trademark note</a> are in the source repository.</p>
</footer>
<script>
const links = [...document.querySelectorAll('.toc a')], heads = links.map(a => document.getElementById(a.getAttribute('href').slice(1)));
const mark = () => { let cur = 0; heads.forEach((h, i) => { if (h && h.getBoundingClientRect().top < 90) cur = i; }); links.forEach((a, i) => a.classList.toggle('active', i === cur)); };
addEventListener('scroll', mark, { passive: true }); mark();
</script>
</body>
</html>