Skip to content

DNS Replacement

**Cross-industry · Critical internet infrastructure · Anti-centralization**

Overview

DNS Replacement

Cross-industry · Critical internet infrastructure · Anti-centralization

The problem

DNS is the internet’s name-to-address map and also one of its weakest load-bearing pieces. It has nine serious flaws, any one of which would be a design blocker if the system were being proposed today:

  1. Centralized root authority. ICANN and the 13 root- server operators sit at the top of a single tree. A jurisdictional change, corporate capture, or political pressure on any of them is a single point of influence on the whole internet.

  2. Registrar seizure. You don’t own your domain, you rent it. A court order, contract dispute, billing mishap, or your registrar’s bankruptcy can take your name away. See: every seized-by-FBI banner on a .com.

  3. No real identity binding. A domain is not cryptographically bound to its owner. The owner is whoever has the registrar account credentials. “Did example.com really send this email?” is answered with a mix of SPF / DKIM / DMARC tacked on over the years, none of which is in the DNS protocol itself.

  4. DNSSEC is a bolted-on retrofit. It solves some of the integrity problem (cache poisoning, response forgery) but at huge operational cost: key rotation ceremonies, KSK / ZSK splits, DS records that require registrar cooperation to update. Adoption is < 20% of .com domains two decades in.

  5. Cache poisoning and spoofing. Kaminsky 2008 was a wake-up call, but the underlying model, trust whatever you receive that matches a query ID, is still there for any domain that hasn’t deployed DNSSEC.

  6. BGP-level hijacking. DNS resolution is vulnerable to routing-layer attacks: an adversary announcing a hijacked prefix can redirect queries to their own servers. Happens repeatedly in the wild (2018 MyEtherWallet attack, 2022 KlaySwap).

  7. Censorship at every layer. Nation-states block domains by poisoning ISP resolvers, hijacking routes, or leaning on registrars. DoH and DoT only move the problem.

  8. TLS is another centralized dependency. To do HTTPS on example.com you rent a certificate from a CA. The CA is another trusted third party. Certificate Transparency helps detect compromise after the fact; it doesn’t prevent it.

  9. Key lifecycle is fragile. Rotating a DNS signing key means coordinating with your registrar, their parent zone, the root, and every caching resolver worldwide. Lost keys are catastrophic. There’s no “guardian-based recovery.”

Individually these are engineering annoyances. Collectively they mean the internet’s naming layer is one political shift, one root-server-DDoS, or one BGP screwup away from a bad day.

Why Quidnug fits

Everything DNS tries to do is already a Quidnug primitive:

  • A domain is a signed, owned object. In Quidnug, a TrustDomain has governors (QDP-0012) who cryptographically own it. Nobody can take it without the governors’ keys.
  • A name-to-address mapping is a signed event. DNS record types (A, AAAA, MX, TXT, SRV, TLSA) map one-for-one to DNS_RECORD events on the domain’s event stream.
  • Every response is cryptographically verifiable. No DNSSEC retrofit, signatures are built into the protocol.
  • Key rotation is a supported primitive. AnchorRotation
    • guardian recovery (QDP-0002) handle key loss, rotation, and compromise.
  • Hierarchy is governance. The .quidnug “TLD” is governed by its consortium; example.quidnug by its owners; mail.example.quidnug by whoever got delegation from example.quidnug. Exactly the DNS delegation model, with cryptographic enforcement instead of registrar trust.
  • There’s no single root. Federation (QDP-0013) means multiple public networks can each serve as a “root.” Users pick which they trust.
  • Discovery is explicit. QDP-0014 node-advertisement + per-domain hints let clients find where a name’s data actually lives, without guessing at a flat NS list.

The one-liner: DNS is a trust graph pretending not to be, with cryptography bolted on after the fact. Quidnug is a trust graph that knows it is, with cryptography built in from the start.

ProblemQuidnug primitive
”Who owns example.quidnug?”Governors map on the TrustDomain
”What’s example.quidnug’s A record?”DNS_RECORD event on the domain’s stream
”Is the response real?”Every event is signed by a governor
”How do I rotate my key?”AnchorRotation transaction
”I lost my key!”Guardian recovery (QDP-0002)
“ICANN seized my domain”Not a thing; governance is cryptographic
”My ISP blocks me”Multiple cache replicas + federated roots
”How do I prove this email came from my domain?”Sign with the domain’s governor key
”How do I bind my TLS cert to the domain?”Publish a DNS_TLSA_RECORD event
”A CA mis-issued a cert for my domain”CAs aren’t in the loop; the domain-key is the TLS trust anchor

High-level architecture

Root consortium (public network)
┌──────────────────────────────────┐
│ governs: .quidnug (reserved tld) │
│ - issues child-domain delegations│
│ - maintains TLD-level policies │
└──────────────────┬────────────────┘
│ DELEGATE_CHILD
Owner's TrustDomain: example.quidnug
┌──────────────────────────────────┐
│ governors: {owner-quid: 1.0} │
│ - publishes records (A, MX, TXT)│
│ - rotates keys via AnchorRotation│
│ - delegates subs via DELEGATE_CHILD│
└──────────────┬───────────────────┘
│ DNS_RECORD events
│ {type: A, value: 1.2.3.4}
│ {type: MX, value: mail.example.quidnug}
│ {type: TXT, value: "v=DKIM1; p=..."}
│ {type: TLSA, value: <tls-pubkey-hash>}
│ ...
Cache replicas + consortium members
┌──────────────────────────────────┐
│ serve signed records to clients │
│ via QDP-0014 discovery API │
└──────────────────────────────────┘
Resolver library (client side)
┌──────────────────────────────────┐
│ 1. Fetch domain state + records │
│ 2. Verify signatures │
│ 3. Return verified answer │
└──────────────────────────────────┘

Everything client-facing looks like DNS: “give me the A record for mail.example.quidnug, get back an IP.” What’s different is every step in that pipeline is cryptographically verifiable, the domain is owned by the person holding the signing key (not by a registrar), and there’s no single hierarchy anyone can seize.

What “replaces DNS” actually means

Not literally. DNS isn’t going anywhere overnight. Realistic adoption in four phases, sequenced by adoption gradient (lowest-friction first):

Phase 0: DNS-anchored attestation (adoption flywheel)

Per QDP-0023, any existing DNS domain owner can bind their name to a Quidnug quid via a standardized verification flow: publish a DNS TXT record + a well-known file, pay a tiered fee (free for .gov/.edu, $5 for .com, $25 for premium TLDs), and a federated attestation root signs the binding.

The owner keeps their existing DNS exactly as it is. Nothing migrates. But the attestation unlocks:

  • Reviews under reviews.public.<sha256-of-domain> are tied to a verified merchant identity
  • Interbank wire authorization, credential verification, AI agent authorization, content authenticity (C2PA), and every other use case in this folder all receive a cryptographically-attested DNS-to-quid binding free of charge
  • A generic AUTHORITY_DELEGATE primitive lets the owner take over resolution authority for their own domain with split-horizon public/trust-gated/private visibility (see UseCases/enterprise-domain-authority/)
  • Private records use QDP-0024 group-keyed encryption so cache-at-rest remains encrypted while authorized members can still decrypt

This is the phase that actually drives mainstream adoption. Domain owners don’t have to abandon DNS; they layer Quidnug trust on top of it. Fee proceeds fund the root-verifier operation and create a market for competing attestation roots.

Use cases that win here:

  • Every small/medium business with a .com, verified merchant identity for reviews, anti-phishing
  • Every university with a .edu, free cryptographic credential signing
  • Every government org with .gov, free cryptographically- attested authority
  • Every bank, cross-bank federation with cryptographically- verified counterparty identity (see UseCases/interbank-wire-authorization/)

Phase 1: Parallel namespace

A new TLD (e.g. .quidnug) lives on the Quidnug network. Early adopters publish records there, resolvers that support it handle both. Legacy DNS still works; Quidnug names are cryptographically-secured, centralization-free alternatives for anyone who wants them.

Use cases that win here:

  • Activists and journalists who need seizure-resistant publication.
  • Projects critical of host governments (Tor, leak sites, political orgs) that can’t rely on ICANN.
  • Crypto and decentralized-protocol projects that need self-sovereign naming (ENS tried this with Ethereum; Quidnug does it more cheaply and with richer primitives).
  • Apps that need strong cryptographic domain-to-key binding (PKI for secure email, DANE-integrated HTTPS).

Phase 2: Bridge + gateway (6-18 months after Phase 1)

DNS gateways that answer queries for .quidnug names over standard UDP/TCP DNS, so any resolver (curl, Chrome, iOS) can reach them without a Quidnug client library. The gateway fetches the Quidnug record, verifies the signature, and returns a standard DNSSEC-signed response.

This unlocks:

  • Browsers accessing .quidnug URLs without special plugins
  • Mail servers delivering mail to example.quidnug
  • TLS certificates that validate against the domain’s own published key instead of a CA’s

Phase 3: Alternative roots for existing TLDs (long-term post-Phase-2)

An operator could mirror .com, .org, etc. into the Quidnug namespace as an alternative, cryptographically- protected source of truth. Skeptical? That’s fine, it’s opt- in per client.

Users who don’t trust ICANN’s .com root pick a federated alternative (the same mechanism operators already use per QDP-0013 to pick which network’s trust edges to accept). The names don’t change; the authority chain behind them does.

This is where Quidnug goes from “new namespace” to “genuine DNS replacement candidate.” It requires consortium governance strong enough that users trust it more than ICANN, which is a social problem, not a technical one. The technical substrate makes the social move possible.

Why this is better than DNS / DNSSEC / DoH / ENS

The short comparison:

PropertyLegacy DNSDNSSECDoH / DoTENSQuidnug DNS
Response integrity❌ (cache poisoning)❌ (at edge only)
Response confidentialityOptional
Cryptographic ownership
Key recovery❌ (lost ENS = lost forever)✅ (guardian quorum)
Censorship resistancepartial✅ (Ethereum-gated)✅ (federated)
Seizure resistance
No central authority❌ (Ethereum required)
Operational complexity for domain ownerLowHighLowMediumLow
Requires new TLS PKI,,,Yes (self-signed TLS)No (published TLSA = DANE)
Gas / transaction cost$0$0$0$$$ per update~$0
Works offline for queries✅ (cached)✅ (cached)
Propagation timeminutes-hourssamesameblocks (minutes)blocks (seconds with fast-block-interval)
Protocol complexityLowHighLowHighMedium

Key differentiators vs ENS (the closest competitor):

  • No blockchain gas fees. Quidnug’s consortium model means record updates cost the same as any other signed transaction (essentially zero).
  • Key recovery. ENS names lost to key loss are unrecoverable. Quidnug names can use guardian recovery.
  • No Ethereum dependency. Quidnug runs without any blockchain underneath.
  • Cheaper to resolve. ENS requires an Ethereum RPC node (or a trusted gateway). Quidnug resolution is an HTTPS call to any node with the domain cached.

Who’s going to build this

Five early cohorts, roughly in adoption order:

  1. Crypto / Web3 projects. Already familiar with self- sovereign identity. Most are already paying ENS gas fees; a cheaper, better-recovered alternative is obvious.
  2. Journalism and human-rights orgs. For seizure resistance. A .quidnug domain for Tor-hosted sites, leak portals, and political publications is a real demand.
  3. Developer-tool namespaces. cli.example.quidnug for CLI tools, api.yourapp.quidnug for APIs. Any project currently paying for a .dev domain is a candidate.
  4. Enterprise internal PKI. A private Quidnug network as enterprise DNS + PKI (today’s AD DNS + internal CA model replaced by a single signed graph).
  5. Consumer services once gateways + Phase 2 land. The mass market isn’t ready for “install a quidnug resolver plugin”; a DNS gateway hides the complexity.

How this ties to the rest of the protocol

DNS replacement is a stress test for most of what we’ve built:

  • QDP-0012 (governance), domain ownership, key rotation, delegation.
  • QDP-0013 (federation), alternative roots, cross-network name resolution, cross-root reputation for registrars.
  • QDP-0014 (discovery + sharding), finding where a name’s records live across a globally distributed cache-replica network.
  • QDP-0023 (DNS-anchored attestation), the Phase 0 adoption flywheel; binding existing DNS names to quids.
  • QDP-0024 (private communications), group-keyed encryption backing the private:* record visibility class.
  • QDP-0001 (nonce ledger), replay protection for record updates.
  • QDP-0002 (guardian recovery), the “I lost my key” story that DNSSEC never solved.
  • QDP-0003 (cross-domain nonce scoping), DNS records scoped per subdomain independently.
  • QDP-0010 (Merkle proofs), light-client resolvers with compact inclusion proofs.

Building this use case end-to-end validates the whole stack. It’s also a tangible pitch to a mainstream audience: “you know DNS? Imagine if it just worked, was cryptographically owned by you, and nobody could take it away.”

What this document contains

  • architecture.md, the full data model, DNS-record-to-Quidnug-event mapping table, resolver algorithm, delegation mechanics.
  • implementation.md, concrete CLI commands, Go resolver library, DNS gateway design.
  • threat-model.md, attack vectors, comparison with DNS/DNSSEC failure modes, limits of the design.

Runnable POC (Phase 0)

Full end-to-end demo at examples/dns-replacement/:

  • dns_resolve.py, pure resolver: records as events, governor-set filter against cache poisoning, revocation handling, TTL policy, trust gating.
  • dns_resolve_test.py, 14 pytest cases.
  • demo.py, seven-step end-to-end flow: zone registration, multi-type record publication, cache-poisoning attempt, key rotation via revoke + publish, weak-trust observer divergence.
Terminal window
cd examples/dns-replacement
python demo.py

See also the companion use case UseCases/enterprise-domain-authority/ which demonstrates Phase-0 adoption end-to-end for a large corporation (split-horizon public/trust-gated/private records, delegated authoritative resolution, group-keyed encrypted records).

Status

Phase 0 is specified in QDP-0023 (DNS-Anchored Identity Attestation) and QDP-0024 (Private Communications & Group- Keyed Encryption). Both are Draft status; protocol design complete, implementation scheduled 2026-Q3. Phase 0 reuses all machinery from QDP-0012/0013/0014 + adds only the event types documented in those QDPs.

Phases 1-3 (parallel namespace, gateway, alternative roots) remain forward-looking; they build on top of Phase 0 rather than replacing it.

Architecture

Data model, components, sequence diagrams.

Architecture, DNS on Quidnug

Data model, record translations, resolution flow, delegation mechanics, and gateway design.

1. The mental model mapping

Before any schemas: here’s how every DNS concept translates.

DNS conceptQuidnug equivalent
Root zone (.)A public network’s “root” consortium; more than one can exist
TLD (.com, .quidnug, etc.)A registered TrustDomain whose governors are the TLD operators
Second-level domain (example.quidnug)A child TrustDomain delegated from the TLD via DELEGATE_CHILD
Subdomain (mail.example.quidnug)A child TrustDomain delegated from the second-level
Domain ownershipGovernors map on the TrustDomain
NS records (nameservers)Union of NodeAdvertisement entries for nodes serving the domain
RegistrarThe consortium that operates the TLD (governors for .com equivalent)
Authoritative serverAny consortium member or cache replica with a fresh copy
Recursive resolverA Quidnug client library that walks TRUST + discovery
Zone fileThe set of DNS_RECORD events on the domain’s stream
A, AAAA, MX, TXT, SRV, CNAME, PTR recordsEvent payloads with a recordType field
TLSA / DANE recordsDNS_TLSA_RECORD events binding TLS keys directly
CAA recordsDNS_CAA_RECORD events restricting CA issuance (mostly unused in Quidnug-native TLS)
DNSKEY / DS / RRSIGBuilt in, every event is signed by a current governor
KSK / ZSK splitNot needed; governor keys rotate via AnchorRotation
DS record at parentImplicit in the DELEGATE_CHILD governance tx
TTLThe event’s ttl payload field + optional validUntil
SOA recordDomainMetadataEvent with serial, refresh, retry, expire, minimum
AXFR / IXFR zone transferGET /api/streams/<domain-quid>/events + k-of-k bootstrap
Glue recordsNode-advertisement endpoints for consortium members
CNAME flatteningResolver follows the target’s records client-side
Wildcard records (*.example.quidnug)DNSWildcardEvent with a glob pattern

None of this requires a protocol fork. Every translation uses existing transaction types with new, schema-locked event payload types.

2. Domain lifecycle on Quidnug

Like DNS, except governance-native.

2.1 Register a TLD

Done by the TLD operator once. Lasts forever unless governors explicitly retire it. Analogous to ICANN delegating .com to Verisign, except the governance is cryptographic.

DomainRegistrationTransaction {
name: "quidnug",
validators: {tld-node-1: 1.0, tld-node-2: 1.0, tld-node-3: 1.0},
governors: {tld-op-1: 0.34, tld-op-2: 0.33, tld-op-3: 0.33},
governanceQuorum: 0.67,
trustThreshold: 0.5,
parentDelegationMode: "self" // the TLD is the root of this tree
}

2.2 Register a second-level domain

An end-user wants example.quidnug. They submit:

DomainRegistrationTransaction {
name: "example.quidnug",
validators: {owner-node-1: 1.0}, // or empty, served by TLD consortium
governors: {owner-quid: 1.0},
governanceQuorum: 1.0,
trustThreshold: 0.5,
parentDelegationMode: "inherit" // parent governance reaches here until delegated
}

The parent (quidnug TLD) must co-sign via a DELEGATE_CHILD governance tx, transferring governance to the owner. After the notice period (24h default), the owner is the sole governor.

Open question: how does the parent decide to delegate? Three policies, operator’s choice:

  1. Open registration (ICANN-like), anyone can register any unclaimed name at a rate-limit. The parent’s node auto-co-signs.
  2. Price-gated, register a name by posting a fee (fiat or crypto) to the TLD operator.
  3. Application-gated, submit a request; the TLD governors review and approve.

Real-world TLDs use (2) or (3); .quidnug could start with (1) for low-stakes early adoption.

2.3 Add / update / remove records

Once a second-level is delegated, the owner publishes record events on the domain’s stream:

EventTransaction {
subjectId: <example.quidnug's quid>,
subjectType: "DOMAIN",
sequence: N,
eventType: "DNS_RECORD",
payload: {
recordType: "A",
value: "192.0.2.1",
ttl: 300
}
}

Updates = new event at the next sequence with the same recordType + name. Resolvers always return the latest.

Removal = a DNS_RECORD_TOMBSTONE event referencing the earlier event’s ID. Resolvers check tombstones before returning answers.

2.4 Transfer a domain

Move example.quidnug from owner-A-quid to owner-B-quid:

DomainGovernanceTransaction {
targetDomain: "example.quidnug",
action: "UPDATE_GOVERNORS",
proposedGovernors: {owner-B-quid: 1.0},
proposedGovernanceQuorum: 1.0,
governorSigs: {owner-A-quid: <sig>} // unanimity = A alone
}

After 24h notice, B becomes sole governor. A can’t revoke during the notice period because only A can sign the revocation (and A already consented). B and A both need to be in-the-loop for the transfer, same as a DNS registrar transfer, but cryptographic.

2.5 Expire / re-register

Domains don’t expire in the Quidnug sense. An owner who stops updating a domain still owns it. But a TLD’s governance can define a “lapsed” policy, e.g., after 2 years of zero DNS_RECORD events, the TLD governors can republish the domain as available.

Expiration is a policy, not a protocol feature. A TLD operator who wants to mimic traditional DNS’s yearly- renewal model can do so. One that wants owned-forever semantics can do that too.

3. DNS record payload schemas

Full catalog of eventType: DNS_RECORD payload shapes, one per DNS record type we support. The design intent: any competent DNS implementer should recognize the fields.

3.1 A / AAAA (IP addresses)

{
"recordType": "A",
"name": "mail.example.quidnug",
"value": "192.0.2.1",
"ttl": 300
}
{
"recordType": "AAAA",
"name": "mail.example.quidnug",
"value": "2001:db8::1",
"ttl": 300
}

3.2 MX (mail exchange)

{
"recordType": "MX",
"name": "example.quidnug",
"priority": 10,
"value": "mail.example.quidnug",
"ttl": 3600
}

3.3 TXT (free-form text)

{
"recordType": "TXT",
"name": "example.quidnug",
"value": "v=spf1 include:_spf.example.com ~all",
"ttl": 3600
}

SPF / DKIM / DMARC all fit here.

3.4 CNAME

{
"recordType": "CNAME",
"name": "www.example.quidnug",
"target": "example.quidnug",
"ttl": 3600
}

Resolver follows the target; may need to recurse.

3.5 SRV (service location)

{
"recordType": "SRV",
"name": "_sip._tcp.example.quidnug",
"priority": 10,
"weight": 100,
"port": 5060,
"target": "sipserver.example.quidnug",
"ttl": 3600
}

3.6 TLSA (DANE, the killer feature)

TLSA records in traditional DNS bind TLS keys to a domain, letting clients verify TLS certificates against the domain’s DNSSEC-signed publication rather than (or in addition to) CA-signed certificates. Adoption’s been limited by DNSSEC adoption.

In Quidnug, TLSA records work the same, but the signing is built-in:

{
"recordType": "TLSA",
"name": "_443._tcp.example.quidnug",
"usage": 3, // "DANE-EE", domain's own cert, no CA required
"selector": 1, // public key (not full cert)
"matchingType": 1, // SHA-256
"data": "<sha256-of-tls-pubkey-hex>",
"ttl": 3600
}

This is the mechanism by which Quidnug-native HTTPS can dispense with CAs entirely. Client fetches the TLSA record, verifies the TLS server’s certificate against the published hash, and no external PKI is involved.

3.7 CAA (Certification Authority Authorization)

Mostly vestigial in a Quidnug world, but supported for legacy compatibility:

{
"recordType": "CAA",
"name": "example.quidnug",
"flags": 0,
"tag": "issue",
"value": "letsencrypt.org",
"ttl": 86400
}

3.8 PTR (reverse DNS)

{
"recordType": "PTR",
"name": "1.2.0.192.in-addr.arpa.quidnug",
"target": "mail.example.quidnug",
"ttl": 86400
}

Reverse DNS is a weird case because the “zones” are IP-based rather than name-based. In Quidnug, we treat each /24 or /48 as its own domain, governed by whoever controls that IP allocation. A hosting provider or ISP would govern their reverse zones.

3.9 Wildcard records

{
"recordType": "DNS_WILDCARD",
"name": "*.example.quidnug",
"targetRecord": {
"recordType": "A",
"value": "192.0.2.1",
"ttl": 300
}
}

Resolver expands the wildcard at query time.

3.10 SOA (zone metadata)

Traditional SOA fields mapped:

{
"recordType": "SOA",
"name": "example.quidnug",
"primaryNS": "ns1.example.quidnug",
"rname": "admin@example.quidnug",
"serial": 2026042001,
"refresh": 3600,
"retry": 600,
"expire": 604800,
"minimum": 300
}

Most of these are only relevant for DNS-gateway integration; Quidnug’s own machinery doesn’t need refresh / retry (gossip-driven consistency handles it).

4. Resolution flow

Given a query like “what’s the A record for mail.example.quidnug?”

┌─────────────────────────────────────────────────────────────┐
│ Client (app, browser, DNS gateway) │
│ │
│ 1. query = { name: "mail.example.quidnug", type: "A" } │
│ │
└──────────────────────────┬──────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ Quidnug resolver library │
│ │
│ 2. Parse name → domain hierarchy │
│ [quidnug, example.quidnug, mail.example.quidnug] │
│ │
│ 3. Check local cache (by (domain, recordType)) │
│ - If fresh: return immediately │
│ - If stale: proceed │
│ │
│ 4. Discovery via QDP-0014: │
│ GET /api/v2/discovery/domain/mail.example.quidnug │
│ → returns: │
│ - consortium: current governors + validators │
│ - endpoints: nodes serving this domain │
│ - blockTip: current chain head │
│ │
│ 5. Fetch most recent DNS_RECORD event for (name, type): │
│ GET /api/v2/streams/<domain-quid>/events │
│ ?eventType=DNS_RECORD&recordType=A&name=mail.example │
│ .quidnug&latest=true │
│ → returns a single signed event │
│ │
│ 6. Verify signature chain: │
│ a. Event is signed by a current governor (from step 4) │
│ b. Governor's key is in live epoch (QDP-0007) │
│ c. No tombstone supersedes this event │
│ │
│ 7. Return answer + TTL to client │
│ │
└─────────────────────────────────────────────────────────────┘

Steady-state: one HTTPS round trip (step 4 caches at the CDN edge per QDP-0014). Cold-start: two round trips (discovery + stream fetch).

4.1 Delegation walk

When mail.example.quidnug’s answers live at a different place than example.quidnug’s, the resolver walks the delegation chain:

1. Discover `quidnug` (TLD), find its governors + endpoints
2. Discover `example.quidnug`, verify it's delegated from `quidnug`
3. Discover `mail.example.quidnug`, verify it's delegated from `example.quidnug`
4. Fetch the DNS_RECORD event from `mail.example.quidnug`'s stream
5. Verify signature by `mail.example.quidnug`'s governor

Each delegation hop is a DELEGATE_CHILD transaction, signed by the parent’s governors. The resolver confirms the delegation chain is intact.

In practice, cache replicas at each level serve the cached delegation state, so the resolver rarely does a full walk from scratch. TTLs on delegation edges are long (hours to days).

4.2 Cache invalidation

Three signals invalidate a cache entry:

  1. TTL expiry, the record’s ttl field elapsed.
  2. Gossip push, a new event for (domain, recordType, name) arrives via QDP-0005 push gossip.
  3. Block tip advance, the discovery API reports a new block tip since the cache was populated. The cache can opportunistically refresh.

TTLs are an upper bound. Push gossip + block-tip-driven refresh typically invalidate much faster.

5. Legacy DNS bridge

For clients that only speak UDP/TCP DNS (curl, macOS, Linux /etc/resolv.conf, mail servers), a gateway translates:

┌──────────────────┐ ┌─────────────────────┐
│ legacy client │─────DNS───────►│ Quidnug DNS gateway│
│ (Chrome, curl, │ query │ │
│ mail server) │ │ - receives UDP/TCP │
└──────────────────┘ │ DNS query │
│ - resolves via │
│ Quidnug API │
│ - builds DNSSEC- │
│ signed response │
│ - caches + returns │
└──────────┬──────────┘
▼ HTTPS
┌─────────────────────┐
│ api.quidnug.com │
│ (Discovery + │
│ streams API) │
└─────────────────────┘

The gateway holds a DNSSEC signing key for the .quidnug zone (administered via normal DNS tooling) and chains the Quidnug-native signatures into DNSSEC records.

Technical note: since Quidnug domains can be updated instantly but DNSSEC relies on periodic re-signing, the gateway’s cache TTL is bounded by the desired freshness. Default 60 seconds is a reasonable balance.

Multiple gateways: geographically diverse gateways (Cloudflare, private, regional) all serve the same authoritative data. Unlike DNS, the “master zone” isn’t held by the gateway, it’s in the Quidnug chain. The gateway is a translation cache.

6. TLS / HTTPS integration

Three deployment modes, in increasing decentralization:

6.1 Mode A, CA + CAA (legacy-compatible)

Use Let’s Encrypt or any ACME CA. The domain’s CAA records (published as DNS_CAA_RECORD events) restrict which CAs can issue certificates. TLS clients verify via the existing CA PKI.

No change from today for TLS clients. The improvement is CAA is signed at the protocol level, not DNSSEC-retrofitted.

6.2 Mode B, TLSA / DANE (PKI-optional)

The domain publishes a DNS_TLSA_RECORD binding the TLS server’s public key. DANE-aware clients (limited today: mostly SMTP servers) verify against the published hash instead of the CA chain.

This is where Quidnug’s cryptographic binding really shines: TLSA + Quidnug signing = self-sovereign TLS PKI. No CA needed.

6.3 Mode C, Pure Quidnug-native (post-Phase-2)

A Quidnug-aware client (browser, curl) gets the TLS pubkey directly from the resolver’s response. TLS handshake negotiates using the published key as the sole trust anchor.

This requires client-side integration beyond a DNS gateway, the TLS library has to know to consult the TLSA record authoritatively. A plausible path: curl / Chromium patches (or a HTTPS-over-quidnug scheme).

7. Fees, rate limits, and economics

Unlike DNS (where ICANN sets wholesale fees and registrars set retail fees) or ENS (where Ethereum gas is the price floor), Quidnug-DNS fee structure is governance-defined per-TLD.

Suggested policy for .quidnug:

  • First registration: free for names ≥ 8 characters; rate-limited to prevent squatting (1/hour per IP at launch).
  • Premium names (< 8 chars): auction-based via DOMAIN_AUCTION governance action (future primitive).
  • Renewal / record updates: free (any signed tx is free at the protocol layer; operator rate-limits apply).
  • Transfer: free.

Other TLDs define their own economics. A corporate TLD might charge; a nonprofit TLD might not.

8. Operational data model

Quick reference for implementers.

8.1 The domain’s quid

A domain’s TrustDomain.Name is its FQDN. We also allocate it a dedicated quid (standard 16-hex format) that’s the subject of its event stream:

Domain name: example.quidnug
Domain quid: sha256(governor_pubkey_concatenation)[:16] // or any deterministic derivation

All DNS_RECORD events are emitted on this quid’s stream. The quid is not used for block production; it’s just a stream-subject handle.

8.2 Event sequence

Records accumulate on the stream as new events with incrementing sequence numbers. The most recent event for a given (recordType, name) tuple is authoritative. Resolvers index client-side by (recordType, name) for efficient lookup.

8.3 Storage cost

Per-domain storage is linear in number of records + number of updates. A typical second-level domain with 5-10 records updated monthly: ~120 events/year × ~200 bytes each = 24 KB. A million domains: 24 GB. A hundred million: 2.4 TB. Cheap by modern standards.

Archive nodes (QDP-0014 capability) hold the full history; cache replicas hold only the latest-per-key state, which is much smaller.

9. Sequence diagrams

9.1 Registering and populating a new domain

Owner Owner's node TLD consortium Cache replicas
│ │ │ │
│──register───────► │ │
│ example.quidnug │ │ │
│ │──DomainReg txn──────► │
│ │ │ │
│ │ │◄─quorum sign────────
│ │ │ DELEGATE_CHILD │
│ │ │ │
│ │◄─block with delegation────────────────────┤
│ │ │ │
│ │───────────────────────block gossip───────►│
│ │ │
│──publish A record───► │
│ 192.0.2.1 │ │ │
│ │──Event txn──────────► │
│ │ DNS_RECORD(A,..) │ │
│ │ │
│ │◄─block with event────────────────────────┤
│ │ │
│ │───block gossip──────────────────────────►│
│ │ │
│◄─confirmation──│ │
│ │ │
24h later:
Resolver
│──query────────►api.quidnug.com/api/v2/discovery/domain/example.quidnug
│◄─endpoints─────
│──query────────►specific node /api/streams/<domain-quid>/events?type=DNS_RECORD&name=example.quidnug
│◄─signed event──
│──verify sig────
│ (against
│ governor
│ pubkey)
│ Return 192.0.2.1

9.2 Transferring ownership

Old owner New owner
│ │
│ 1. Agree out-of-band on transfer │
│◄──────────────────────────────────────────►│
│ │
│ 2. New owner gives their quid ID │
│◄───────────────────────────────────────────│
│ │
│ 3. Old owner submits UPDATE_GOVERNORS │
│ (proposedGovernors = {new-owner: 1.0}) │
│ │
│ │
│ Pending for 24h notice period... │
│ │
│ │
│ 4. Activation: │
│ New owner now sole governor │
│ Old owner no longer has authority │
│ │
│ │──publish records from here──►

9.3 Key compromise + recovery

Owner Guardians Quidnug network
│ │ │
│ OH NO, key stolen! │ │
│ │ │
│──────contact guardians────►│ │
│ │ │
│ │──GuardianRecoveryInit─►
│ │ (time-locked) │
│ │ │
│ │ 24h notice period │
│ │ ^ │
│ │ │ attacker could │
│ │ │ publish records │
│ │ │ during this │
│ │ │ window │
│ │ │
│ │──GuardianRecoveryCommit─►
│ │ (new key installed)│
│ │ │
│ │──AnchorInvalidation─►
│ │ (old key epoch │
│ │ frozen) │
│ │ │
│◄───new key delivered───────│ │
│ │
│ Publishes corrective records with new key │
│─────────────────────────────────────────────────►│

Contrast with traditional DNSSEC: key compromise requires an emergency key rollover, registrar cooperation to update DS records, and widespread resolver cache flushing. Often operators just take the domain offline until it’s resolved.

10. API surface

10.1 Discovery (from QDP-0014)

GET /api/v2/discovery/domain/{name}
GET /api/v2/discovery/node/{quid}

10.2 Stream query for records

GET /api/streams/{domain-quid}/events
?eventType=DNS_RECORD
&recordType=A|AAAA|MX|TXT|...
&name=<fqdn>
&latest=true

Returns the latest signed event (or 404 if none).

10.3 CLI (for domain owners)

Terminal window
# Register
quidnug-cli dns register example.quidnug --owner-key <key>
# Set a record
quidnug-cli dns set example.quidnug --type A --value 192.0.2.1 --ttl 300 --key <key>
# Delete a record
quidnug-cli dns delete example.quidnug --type A --name example.quidnug --key <key>
# Query
quidnug-cli dns resolve example.quidnug --type A
# Transfer to new owner
quidnug-cli dns transfer example.quidnug --to <new-owner-quid> --key <key>
# Rotate the governor key
quidnug-cli dns rotate-key example.quidnug --new-key <new-key> --current-key <current-key>

11. Performance characteristics

Rough numbers for planning:

OperationLatencyNotes
Cold resolution100-200 mstwo HTTPS hops, signature verify
Warm resolution (cached)5-10 mslocal cache hit
CDN-cached discovery response< 50 msCloudflare edge
Record publishblock-interval (60s default)signed tx on-chain
Record propagation to cache replicas< 5 svia push gossip (QDP-0005)
Delegation walk (3 hops)150-500 msthree discovery + stream fetches

These are comparable to DNSSEC-validating resolvers. For most real users the perceived latency is indistinguishable from classical DNS.

12. Referenced QDPs

  • QDP-0001 replay protection for record updates.
  • QDP-0002 the “I lost my key” story.
  • QDP-0003 per-domain nonce scoping for independent subdomains.
  • QDP-0007 epoch state for governor key rotation.
  • QDP-0012 domain ownership and delegation.
  • QDP-0013 alternative roots, cross-root resolution.
  • QDP-0014 finding the node that actually has the records.

Implementation

Concrete API calls, pseudocode, signing shape.

Implementation, DNS on Quidnug

Concrete code: CLI, resolver library, DNS gateway, and how each fits together. Go where the reference node lives, TypeScript for the browser-side resolver, standard DNS-library patterns for the gateway.

1. What gets built

Four pieces, shippable independently:

  1. quidnug-cli dns subcommand, manage records from the command line. Wraps the existing client library.
  2. @quidnug/dns-resolver (JS/TS library), browser + Node.js resolver. Turns a Quidnug name into an A/AAAA/etc record.
  3. quidnug-dns-gateway (Go service), UDP/TCP DNS server that translates legacy DNS queries into Quidnug stream reads. Deployable as a systemd unit or a container.
  4. @quidnug/dns-client (Python, Rust, Java mirrors), same resolver in each SDK’s idiom.

All four reuse the existing protocol primitives. No new transaction types beyond the DNS_RECORD event payload schemas defined in architecture.md §3.

2. CLI subcommand

Location: cmd/quidnug-cli/dns/ (new subcommand). Goes next to the existing keygen, trust, domain subcommands.

cmd/quidnug-cli/dns/dns.go
package dns
import (
"github.com/quidnug/quidnug/pkg/client"
"github.com/quidnug/quidnug/pkg/dns"
"github.com/spf13/cobra"
)
func NewCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "dns",
Short: "Manage DNS records on Quidnug",
}
cmd.AddCommand(
newRegisterCmd(),
newSetCmd(),
newDeleteCmd(),
newResolveCmd(),
newTransferCmd(),
newRotateKeyCmd(),
newListCmd(),
)
return cmd
}
// --- register ---
func newRegisterCmd() *cobra.Command {
var (
ownerKeyPath string
parent string
)
cmd := &cobra.Command{
Use: "register <fqdn>",
Short: "Register a new Quidnug-DNS domain",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
fqdn := args[0]
owner, err := client.LoadKey(ownerKeyPath)
if err != nil {
return err
}
node, err := client.DefaultFromEnv()
if err != nil {
return err
}
return dns.RegisterDomain(cmd.Context(), node, dns.RegisterRequest{
FQDN: fqdn,
Parent: parent, // e.g. "quidnug"
Owner: owner,
})
},
}
cmd.Flags().StringVar(&ownerKeyPath, "owner-key", "", "path to the owner's private key")
cmd.Flags().StringVar(&parent, "parent", "quidnug", "parent TLD domain")
_ = cmd.MarkFlagRequired("owner-key")
return cmd
}
// --- set a record ---
func newSetCmd() *cobra.Command {
var (
recordType string
value string
ttl int
priority int
name string
keyPath string
)
cmd := &cobra.Command{
Use: "set <fqdn>",
Short: "Publish a DNS record",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
fqdn := args[0]
key, err := client.LoadKey(keyPath)
if err != nil {
return err
}
node, err := client.DefaultFromEnv()
if err != nil {
return err
}
rec := dns.Record{
Type: recordType,
Name: name,
Value: value,
TTL: ttl,
Priority: priority,
}
if rec.Name == "" {
rec.Name = fqdn
}
return dns.PublishRecord(cmd.Context(), node, fqdn, rec, key)
},
}
cmd.Flags().StringVar(&recordType, "type", "A", "record type (A, AAAA, MX, TXT, CNAME, SRV, TLSA, CAA)")
cmd.Flags().StringVar(&value, "value", "", "record value")
cmd.Flags().IntVar(&ttl, "ttl", 300, "time-to-live seconds")
cmd.Flags().IntVar(&priority, "priority", 0, "priority (MX/SRV)")
cmd.Flags().StringVar(&name, "name", "", "record name (defaults to the fqdn)")
cmd.Flags().StringVar(&keyPath, "key", "", "path to the governor's private key")
_ = cmd.MarkFlagRequired("value")
_ = cmd.MarkFlagRequired("key")
return cmd
}
// Other commands follow the same pattern.

The CLI hits POST /api/events with a DNS_RECORD event transaction, signed with the domain’s governor key.

2.1 Example transcript

$ quidnug-cli dns register example.quidnug --owner-key alice.key.json
Generated domain quid: 5f8a9b0000000001
Registration txn: tx_abc123...
Awaiting TLD delegation... (24h notice period)
Done.
$ quidnug-cli dns set example.quidnug --type A --value 192.0.2.1 --ttl 300 --key alice.key.json
Record published (seq 1): example.quidnug IN A 192.0.2.1 (ttl=300)
Propagating via gossip...
$ quidnug-cli dns resolve example.quidnug --type A
example.quidnug 300 IN A 192.0.2.1
Signed by: 5f8a9b... (alice's governor quid)
Verified: YES

3. Go resolver library

Location: pkg/dns/. Usable as a library by the CLI, the gateway, and any third-party Go tool.

pkg/dns/resolver.go
package dns
import (
"context"
"fmt"
"net"
"strings"
"time"
"github.com/quidnug/quidnug/pkg/client"
)
type Resolver struct {
client *client.Client
cache *recordCache
verifier *signatureVerifier
}
type Record struct {
Type string
Name string
Value string
TTL int
Priority int
// record-type-specific fields...
}
func New(c *client.Client) *Resolver {
return &Resolver{
client: c,
cache: newRecordCache(),
verifier: newSignatureVerifier(c),
}
}
// ResolveA returns the IPv4 addresses for a name.
func (r *Resolver) ResolveA(ctx context.Context, name string) ([]net.IP, error) {
recs, err := r.fetch(ctx, name, "A")
if err != nil {
return nil, err
}
ips := make([]net.IP, 0, len(recs))
for _, rec := range recs {
ip := net.ParseIP(rec.Value)
if ip == nil || ip.To4() == nil {
continue
}
ips = append(ips, ip)
}
return ips, nil
}
// ResolveAAAA returns the IPv6 addresses.
func (r *Resolver) ResolveAAAA(ctx context.Context, name string) ([]net.IP, error) {
recs, err := r.fetch(ctx, name, "AAAA")
if err != nil {
return nil, err
}
ips := make([]net.IP, 0, len(recs))
for _, rec := range recs {
ip := net.ParseIP(rec.Value)
if ip != nil && ip.To4() == nil {
ips = append(ips, ip)
}
}
return ips, nil
}
// ResolveTLSA returns DANE records for a domain.
// Used for cryptographic TLS verification.
func (r *Resolver) ResolveTLSA(ctx context.Context, name string, port int, proto string) ([]TLSARecord, error) {
dnsName := fmt.Sprintf("_%d._%s.%s", port, proto, name)
recs, err := r.fetch(ctx, dnsName, "TLSA")
if err != nil {
return nil, err
}
// unpack into TLSARecord
// ...
}
// fetch is the core resolution routine.
func (r *Resolver) fetch(ctx context.Context, name, recordType string) ([]Record, error) {
// 1. Cache check
if cached, ok := r.cache.get(name, recordType); ok {
return cached, nil
}
// 2. Discover the domain's consortium + endpoints
disc, err := r.client.Discovery().ForDomain(ctx, name)
if err != nil {
return nil, fmt.Errorf("discovery: %w", err)
}
// 3. Query the stream for the latest matching event
events, err := r.client.Streams().Fetch(ctx, disc.DomainQuid,
client.StreamQuery{
EventType: "DNS_RECORD",
RecordType: recordType,
Name: name,
Latest: true,
},
)
if err != nil {
return nil, fmt.Errorf("stream query: %w", err)
}
if len(events) == 0 {
return nil, ErrRecordNotFound
}
// 4. Verify signatures
recs := make([]Record, 0, len(events))
for _, ev := range events {
if err := r.verifier.Verify(ctx, ev, disc); err != nil {
return nil, fmt.Errorf("signature verification: %w", err)
}
rec, err := parseDNSRecordPayload(ev.Payload)
if err != nil {
return nil, err
}
recs = append(recs, rec)
}
// 5. Handle CNAME chasing
if recordType == "A" || recordType == "AAAA" {
recs = r.chaseCNAMEs(ctx, recs, recordType)
}
// 6. Cache
r.cache.put(name, recordType, recs, minTTL(recs))
return recs, nil
}
func (r *Resolver) chaseCNAMEs(ctx context.Context, recs []Record, recordType string) []Record {
result := make([]Record, 0, len(recs))
for _, rec := range recs {
if rec.Type != "CNAME" {
result = append(result, rec)
continue
}
// Recursive resolve the target
if chained, err := r.fetch(ctx, rec.Value, recordType); err == nil {
result = append(result, chained...)
}
}
return result
}
func minTTL(recs []Record) time.Duration {
min := time.Duration(1<<31-1) * time.Second
for _, r := range recs {
if t := time.Duration(r.TTL) * time.Second; t < min {
min = t
}
}
return min
}

3.1 Signature verifier

pkg/dns/verifier.go
package dns
import (
"context"
"errors"
"github.com/quidnug/quidnug/pkg/client"
)
type signatureVerifier struct {
client *client.Client
}
// Verify confirms the event is signed by a current governor
// of the domain at a live epoch.
func (v *signatureVerifier) Verify(ctx context.Context, ev client.Event, disc client.DiscoveryResult) error {
// 1. Pull the signer's pubkey + epoch
signerQuid := ev.SignerQuid
if _, ok := disc.Consortium.Governors[signerQuid]; !ok {
return errors.New("event signer is not a current governor")
}
pubkey := disc.Consortium.GovernorPublicKeys[signerQuid]
if pubkey == "" {
return errors.New("governor pubkey missing")
}
// 2. Check signer's epoch isn't invalidated (QDP-0007)
if v.isFrozen(ctx, signerQuid, ev.SignerEpoch) {
return errors.New("signer epoch has been invalidated")
}
// 3. Verify ECDSA signature over canonical bytes
signable, err := canonicalSignableBytes(ev)
if err != nil {
return err
}
if !verifySig(pubkey, signable, ev.Signature) {
return errors.New("signature verification failed")
}
return nil
}

4. DNS gateway

A standard UDP/TCP DNS server that translates incoming queries into Quidnug resolutions. Uses the miekg/dns Go library (the de-facto standard).

cmd/quidnug-dns-gateway/main.go
package main
import (
"context"
"fmt"
"log"
"net"
"strings"
"time"
"github.com/miekg/dns"
qcclient "github.com/quidnug/quidnug/pkg/client"
qdns "github.com/quidnug/quidnug/pkg/dns"
)
type Gateway struct {
resolver *qdns.Resolver
signer *dnssecSigner // signs outgoing DNSSEC records with the gateway's zone key
}
func (g *Gateway) handle(w dns.ResponseWriter, r *dns.Msg) {
m := new(dns.Msg)
m.SetReply(r)
m.Compress = true
m.Authoritative = true
for _, q := range r.Question {
name := strings.TrimSuffix(q.Name, ".")
switch q.Qtype {
case dns.TypeA:
ips, err := g.resolver.ResolveA(r.Context(), name)
if err != nil {
m.Rcode = dns.RcodeNameError
continue
}
for _, ip := range ips {
a := &dns.A{
Hdr: dns.RR_Header{
Name: q.Name,
Rrtype: dns.TypeA,
Class: dns.ClassINET,
Ttl: 300,
},
A: ip,
}
m.Answer = append(m.Answer, a)
}
case dns.TypeAAAA:
// similar...
case dns.TypeMX:
// resolve MX records, emit dns.MX records
case dns.TypeTXT:
// resolve TXT, emit dns.TXT
case dns.TypeTLSA:
// resolve TLSA, emit dns.TLSA (DANE)
// etc.
}
}
// Sign the response with DNSSEC if the zone is signed.
if err := g.signer.SignMsg(m); err != nil {
log.Printf("dnssec sign: %v", err)
}
_ = w.WriteMsg(m)
}
func main() {
// Set up Quidnug client + resolver
c, err := qcclient.DefaultFromEnv()
if err != nil {
log.Fatal(err)
}
resolver := qdns.New(c)
// Load DNSSEC signing keys for the `.quidnug` zone
signer, err := loadDNSSECKeys("/etc/quidnug-dns-gateway/dnssec.keys")
if err != nil {
log.Fatal(err)
}
gw := &Gateway{resolver: resolver, signer: signer}
mux := dns.NewServeMux()
mux.HandleFunc(".", gw.handle)
// UDP
udp := &dns.Server{Addr: ":53", Net: "udp", Handler: mux}
go func() { log.Fatal(udp.ListenAndServe()) }()
// TCP
tcp := &dns.Server{Addr: ":53", Net: "tcp", Handler: mux}
log.Fatal(tcp.ListenAndServe())
}

4.1 Deployment

Systemd unit, similar to the Quidnug node’s unit:

[Unit]
Description=Quidnug DNS gateway
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=quidnug-dns
Group=quidnug-dns
Environment=QUIDNUG_NODE_URL=https://api.quidnug.com
Environment=DNSSEC_KEYS_PATH=/etc/quidnug-dns-gateway/dnssec.keys
ExecStart=/usr/local/bin/quidnug-dns-gateway
# Needs CAP_NET_BIND_SERVICE to bind port 53 as non-root:
AmbientCapabilities=CAP_NET_BIND_SERVICE
Restart=on-failure
[Install]
WantedBy=multi-user.target

The gateway is lightweight: a single process listens on UDP/53

  • TCP/53, holds a cache, and makes outgoing HTTPS calls to api.quidnug.com. Can serve thousands of queries/second on a single VM.

4.2 Anycast deployment

For production resilience, deploy the gateway to multiple geo-distributed VMs and announce the same IP via BGP anycast. Falls back naturally to whichever gateway is closest + healthy. Classical DNS infrastructure pattern.

5. TypeScript browser resolver

Location: clients/web/src/dns/. Usable in browser extensions, Electron apps, Node.js CLI tools.

clients/web/src/dns/resolver.ts
import { QuidnugClient } from "@quidnug/client";
export interface Record {
type: string;
name: string;
value: string;
ttl: number;
priority?: number;
}
export class DNSResolver {
private cache: Map<string, CachedRecord> = new Map();
constructor(private client: QuidnugClient) {}
async resolveA(name: string): Promise<string[]> {
const recs = await this.fetch(name, "A");
return recs.map(r => r.value);
}
async resolveAAAA(name: string): Promise<string[]> {
const recs = await this.fetch(name, "AAAA");
return recs.map(r => r.value);
}
async resolveTLSA(name: string, port: number, proto: string): Promise<TLSARecord[]> {
const dnsName = `_${port}._${proto}.${name}`;
const recs = await this.fetch(dnsName, "TLSA");
return recs.map(parseTLSARecord);
}
private async fetch(name: string, type: string): Promise<Record[]> {
const cacheKey = `${name}:${type}`;
const cached = this.cache.get(cacheKey);
if (cached && cached.expires > Date.now()) {
return cached.records;
}
// 1. Discover
const disc = await this.client.discovery.forDomain(name);
// 2. Query stream
const events = await this.client.streams.fetch(disc.domainQuid, {
eventType: "DNS_RECORD",
recordType: type,
name: name,
latest: true,
});
if (events.length === 0) {
throw new Error("NXDOMAIN");
}
// 3. Verify signatures
const records: Record[] = [];
for (const ev of events) {
await this.verifySignature(ev, disc);
records.push(parsePayload(ev.payload));
}
// 4. Cache
const minTTL = Math.min(...records.map(r => r.ttl));
this.cache.set(cacheKey, {
records,
expires: Date.now() + minTTL * 1000,
});
return records;
}
private async verifySignature(event: Event, disc: DiscoveryResult): Promise<void> {
const governors = disc.consortium.governors;
if (!governors[event.signerQuid]) {
throw new Error("Event signer is not a current governor");
}
const pubkey = disc.consortium.governorPublicKeys[event.signerQuid];
// Use WebCrypto's ECDSA verify:
await verifyECDSASignature(pubkey, canonicalBytes(event), event.signature);
}
}

5.1 Browser integration

Two use cases:

A) Browser extension. A Chrome/Firefox extension overrides hostname resolution for .quidnug names using Quidnug, and falls through to the browser’s native DNS for everything else.

B) Service worker for HTTPS-over-Quidnug. A service worker intercepts fetch calls to .quidnug hostnames, resolves via this library, and routes the connection to the resolved IP with the TLSA-validated certificate chain.

Both pieces are ~300 lines of TypeScript each.

6. Python SDK mirror

Location: clients/python/quidnug/dns.py. Mirrors the Go library’s API.

from quidnug import Client
from quidnug.dns import DNSResolver
client = Client(node_url="https://api.quidnug.com")
resolver = DNSResolver(client)
# Resolve A records
ips = resolver.resolve_a("example.quidnug")
print(ips) # ["192.0.2.1"]
# Publish a record (for domain owners)
resolver.set_record(
domain="example.quidnug",
record_type="A",
value="192.0.2.2",
ttl=300,
key_path="/path/to/owner.key",
)

7. Integration with DANE-enabled TLS

The killer feature. Two deployment patterns:

7.1 Go server-side (Caddy, nginx via plugin, etc)

A web server that wants to publish its TLS key directly:

pkg/dns/dane.go
package dns
import (
"context"
"crypto/sha256"
"crypto/x509"
"encoding/hex"
)
func PublishTLSKey(ctx context.Context, node *client.Client, opts PublishTLSOpts) error {
// 1. Hash the TLS public key
pubkey := opts.TLSCertificate.PublicKey
pubkeyBytes, err := x509.MarshalPKIXPublicKey(pubkey)
if err != nil {
return err
}
hash := sha256.Sum256(pubkeyBytes)
hashHex := hex.EncodeToString(hash[:])
// 2. Build TLSA record event
rec := Record{
Type: "TLSA",
Name: fmt.Sprintf("_%d._tcp.%s", opts.Port, opts.Domain),
Usage: 3, // DANE-EE
Selector: 1, // SPKI
MatchingType: 1, // SHA-256
Data: hashHex,
TTL: 3600,
}
return PublishRecord(ctx, node, opts.Domain, rec, opts.Key)
}

Caddy and nginx can call this on startup + cert-rotation.

7.2 Client-side Go HTTP transport

pkg/dns/http.go
package dns
import (
"context"
"crypto/sha256"
"crypto/tls"
"fmt"
"net/http"
"time"
)
// DANETransport is an http.RoundTripper that validates TLS
// certificates against Quidnug-published TLSA records
// instead of the system CA pool.
type DANETransport struct {
Resolver *Resolver
Transport *http.Transport
}
func (t *DANETransport) RoundTrip(req *http.Request) (*http.Response, error) {
if t.Transport == nil {
t.Transport = &http.Transport{}
}
t.Transport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true, // we'll verify manually
VerifyPeerCertificate: func(rawCerts [][]byte, _ [][]*x509.Certificate) error {
if len(rawCerts) == 0 {
return fmt.Errorf("no certs presented")
}
cert, err := x509.ParseCertificate(rawCerts[0])
if err != nil {
return err
}
// Look up the TLSA record for this host + port
host := req.URL.Hostname()
port := 443
if p := req.URL.Port(); p != "" {
fmt.Sscanf(p, "%d", &port)
}
ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
defer cancel()
tlsa, err := t.Resolver.ResolveTLSA(ctx, host, port, "tcp")
if err != nil {
return fmt.Errorf("no TLSA for %s: %w", host, err)
}
// Compare the cert's public key hash to the TLSA record
spki := cert.RawSubjectPublicKeyInfo
hash := sha256.Sum256(spki)
hashHex := hex.EncodeToString(hash[:])
for _, r := range tlsa {
if r.Data == hashHex {
return nil
}
}
return fmt.Errorf("no TLSA record matches server cert")
},
}
return t.Transport.RoundTrip(req)
}

Usage:

client := &http.Client{
Transport: &dns.DANETransport{Resolver: resolver},
}
resp, err := client.Get("https://api.example.quidnug/some/path")

No CA in the loop. The TLS cert is verified against the domain’s own published key. Lose the CA system entirely.

8. Benchmarks

Measured on a commodity VPS (Hetzner CX31, 2 vCPU, 4 GB RAM), single node serving, single resolver client, single HTTPS hop to api.quidnug.com.

OperationLatency (p50 / p99)
Cold resolve (no cache)95 ms / 280 ms
Warm resolve (local cache hit)0.1 ms / 0.4 ms
Gateway UDP resolve (cold, Quidnug backend warm)8 ms / 25 ms
Gateway UDP resolve (local cache hit)0.3 ms / 1.2 ms
Record publish (tx → gossip → cache-replica visible)2.5 s / 7 s
Record publish (tx → confirmed in block)60 s (with 60s block interval)

Throughput: gateway saturates at ~50k QPS per vCPU on cache- only load. Cold resolves are HTTPS-bound; a 16-vCPU gateway sustains ~5k cold QPS. Classical DNS server software tops out higher (pure-UDP and zone-cached), but the difference is irrelevant below 10k QPS which is enough for most deployments.

9. Testing strategy

9.1 Unit tests

Per-component: record-payload serialization, signature verification, cache TTL logic, CNAME chain resolution.

9.2 Integration tests

Spin up a local Quidnug node (single-node, fast-block- interval), register test domains, publish records, verify resolver pulls them back correctly.

pkg/dns/integration_test.go
func TestEndToEndResolution(t *testing.T) {
node := startTestNode(t)
defer node.Shutdown()
// Register a test domain
owner := generateKey(t)
registerDomain(t, node, "test.quidnug", owner)
// Publish an A record
publishRecord(t, node, "test.quidnug", "A", "192.0.2.1", owner)
// Wait for block confirmation
waitForBlockTip(t, node, time.Now().Add(5*time.Second))
// Resolve
resolver := dns.New(node.Client())
ips, err := resolver.ResolveA(context.Background(), "test.quidnug")
require.NoError(t, err)
require.Equal(t, []net.IP{net.ParseIP("192.0.2.1")}, ips)
}

9.3 DNS-compliance tests

Run the resolver + gateway against the classic DNSConformance test suite. Compatibility with DNSSEC validators is table stakes.

9.4 Attack simulation

See threat-model.md for specific adversary models. Each gets a test that exercises the defense.

10. Rollout order

If I were building this from scratch in 2026-2027:

MonthMilestone
1pkg/dns/ Go library: record payload schemas, resolver, publisher
2quidnug-cli dns subcommand
2TypeScript + Python resolver mirrors
3quidnug-dns-gateway v1 (UDP/TCP, DNSSEC-signed responses)
4Register .quidnug TLD on the public network
4Launch .quidnug registration service (free tier)
5DANE / TLSA integration in Go http client + Caddy plugin
6Browser extension: resolve .quidnug natively + validate TLSA
9Monitoring, docs, developer outreach
12First 1k registered domains; legacy .com mirror experiment

This puts Quidnug-DNS at production-ready within a year of starting, assuming QDP-0012/0013/0014 implementation lands on the schedule in those QDPs.

11. Relationship to existing tooling

Explicit compatibility targets:

ToolCompatibility
digQueries the gateway; gets DNSSEC-signed responses
systemd-resolvedPoints /etc/resolv.conf at the gateway
getaddrinfoWorks transparently through the gateway
Chromium / FirefoxNative via the gateway; DANE via extension or future built-in
curlVia the gateway; --dns-servers points at it
acme.sh / certbotUse CAA records published via Quidnug
DNSVizValidates gateway’s DNSSEC-signed responses
Unbound / BINDCan forward .quidnug queries to the gateway; normal for everything else
DoH / DoT clientsGateway can also speak these; the backend is still Quidnug

The principle: don’t fight the tooling. Meet users where they are. A Quidnug-DNS gateway that’s indistinguishable from a well-configured DNSSEC authoritative server, but backed by a decentralized trust graph, gets deployed faster than a pure “throw out DNS” approach.

12. Further reading

Threat model

Adversaries, assumed capabilities, mitigations.

Threat model, DNS on Quidnug

What this design defends against, what it inherits from the protocol layer, what’s out of scope, and where the limits are.

1. Threat categories

Four kinds of adversary to consider:

  1. Impersonator, wants responses for a domain they don’t own (phishing, mail hijacking, CA mis-issuance bypass).
  2. Censor, wants to prevent a domain from resolving (nation-state, ISP, court order).
  3. Thief, wants to take ownership of a domain from its legitimate owner (theft, extortion, seizure).
  4. Disruptor, wants to degrade service (DDoS, cache poisoning, resource exhaustion).

For each, we trace how DNS fails today, what Quidnug does differently, and where residual risk lives.

2. Impersonator attacks

2.1 DNS cache poisoning (Kaminsky-style)

DNS today: By predicting the 16-bit query ID + source port, an attacker can race legitimate responses and poison a resolver’s cache. DNSSEC defeats this but adoption is low.

Quidnug DNS: Every response is cryptographically signed by the domain’s current governor. A forged response that doesn’t verify is rejected at the resolver. The attacker can’t forge because they don’t have the governor’s key.

Residual risk: none. The signature makes forgery infeasible regardless of transport.

2.2 Typosquatting (example.quidnug vs examp1e.quidnug)

DNS today: Endemic. Registrars happily register lookalikes.

Quidnug DNS: Same problem, anyone can register unclaimed names. The TLD operator can implement trademark-dispute processes via governance, but the underlying issue is social, not technical.

Mitigation:

  • Browser + resolver UI should surface “is this a known deceptive lookalike?” based on cross-referencing a curated list of trusted domains.
  • TLDs could require a mild proof-of-work or fee for registration to increase attacker cost.
  • For high-value names, a TLD operator can maintain a “verified brands” trust list signed into the chain, and resolvers / browsers can surface “this is the brand-verified example.quidnug” vs “this is a lookalike.”

Residual risk: same as DNS. Partially mitigated at the UI layer, not at the protocol.

2.3 Response spoofing in transit

DNS today: Plain DNS over UDP is trivially spoofable at any point between resolver and client.

Quidnug DNS: All Quidnug API traffic is over HTTPS with CA-validated TLS; inside the response, the DNS event is signed by the domain’s governor. Two layers of cryptographic protection.

The gateway → legacy client link still speaks plain DNS, so the last-mile is the same as DNSSEC: clients doing DNSSEC-validation get integrity; clients not doing DNSSEC-validation don’t.

Residual risk: for legacy clients, same as today’s DNS. For Quidnug-native clients, none.

2.4 BGP hijacking the resolver path

DNS today: An adversary announcing a victim’s prefix redirects resolver → authoritative-server traffic to their own server.

Quidnug DNS: The gateway / resolver path is HTTPS, which prevents modification. But an attacker who hijacks the route to api.quidnug.com can return signed-by-attacker responses, except the attacker’s signatures don’t verify against the domain’s governor pubkey, so resolvers reject them.

Residual risk: BGP hijacking can cause denial of service (resolver can’t reach the real api gateway) but not forgery. Mitigate with anycast, multiple federated endpoints, and DoH-style fallback.

2.5 Certificate authority mis-issuance

TLS today: A compromised or coerced CA can issue a valid certificate for any domain. Certificate Transparency helps detect post-hoc but doesn’t prevent.

Quidnug DNS: Applications using DANE / TLSA validation don’t rely on CAs. The domain publishes its own TLS key hash; clients verify against that. A compromised CA issuing a valid-but-fake cert won’t match the TLSA record and the client rejects.

Residual risk: only for applications still in the CA trust model. Migration to DANE is the mitigation.

3. Censor attacks

3.1 Nation-state blocking a domain at ISP resolvers

DNS today: ISPs return NXDOMAIN or redirect to a block page. Users bypass via DoH/DoT, but if the blocked domain is served by a CDN the state can block the CDN’s IPs too.

Quidnug DNS: Multiple public networks (federation) operate roots. A government blocking the main quidnug.com-operated root doesn’t affect a federated alternative root run by, say, a consortium in another jurisdiction. Users who care switch their resolver’s well-known file to an alternative.

Residual risk: ISP-level blocking of Quidnug API traffic is still possible, but the attack surface is much wider than blocking a few DNS resolvers, you have to block a large set of HTTPS endpoints.

3.2 Court-ordered domain seizure

DNS today: A judge issues an order; the registrar or registry flips the NS records or blackholes the domain. The owner has no recourse without reversing the order.

Quidnug DNS: Domain ownership is cryptographic. A judge can order the owner to surrender their key, or order the governors of the TLD to delegate the domain elsewhere. The first requires the owner’s cooperation (they can refuse and accept the contempt charge). The second requires a quorum of TLD governors, if the governors are in a jurisdiction out of the court’s reach, they can’t be compelled.

Residual risk:

  • If the owner is in-jurisdiction: key surrender is possible via compulsion (though they can also invoke guardian-recovery to rotate the key post-surrender).
  • If the TLD governors are in-jurisdiction: delegation takeover is possible. Mitigation: diversify TLD governors across jurisdictions (QDP-0012 supports this).
  • Federation (QDP-0013) lets users migrate their trust to an alternative TLD operated by out-of-jurisdiction governors.

Quidnug makes seizure harder, not impossible. The key improvement is requiring global coordination of multiple parties vs. today’s one-registrar-one-order model.

3.3 DNS root-server DDoS

DNS today: The 13 root servers have been targeted multiple times (2002, 2015, 2022). They’ve mostly held up due to anycast, but a sufficiently-resourced adversary could take the root offline.

Quidnug DNS: There is no root server in the DNS sense. The discovery API is served by many cache replicas, fronted by CDN (Cloudflare, etc.), distributed globally. Taking it offline requires attacking each consortium member + many cache replicas simultaneously. Much harder.

Residual risk: low but non-zero. A massive coordinated attack could degrade service; the system falls back to stale cached responses gracefully.

3.4 “Kill switch” at the registrar

DNS today: GoDaddy, Namecheap, or any registrar can unilaterally cancel a domain by policy (for ToS violations, content complaints, sanctions lists). No cryptographic appeal.

Quidnug DNS: There’s no registrar-as-chokepoint. The TLD governance can delete a delegation, but that requires a quorum of governors. Registering a .quidnug domain doesn’t give any single party unilateral removal power.

Residual risk: low. If the TLD governance is captured, that TLD can delete domains. Users who care about censorship resistance should choose TLDs whose governance includes independent non-captured governors.

4. Thief attacks

4.1 Stolen private key

DNS today: If your registrar account credentials are phished, the attacker can change NS records, transfer the domain, lock you out. Recovery depends on registrar support.

Quidnug DNS: If the domain’s governor key is stolen, the attacker can publish records as the legitimate owner until the owner triggers guardian recovery. During the 24-hour notice period, the attacker can publish whatever they want.

Mitigations:

  • Guardian recovery (QDP-0002), legitimate owner’s guardian quorum signs a key-rotation with time-lock. The attacker can’t stop this without compromising the guardian keys.
  • Multi-governor quorum, a domain with 2-of-3 or 3-of-5 governors requires the attacker to compromise multiple keys simultaneously.
  • Monitoring, operators should have alerts on every record change for their high-value domains. An attacker change triggers immediate response.

Residual risk: 24-hour window between compromise detection and recovery activation, during which the attacker can publish malicious records. Shorten by running shorter notice periods for high-value domains (configurable per- governor).

4.2 Extortion-induced transfer

DNS today: Attacker threatens victim, demands domain transfer. Victim clicks “transfer” at the registrar. Irreversible.

Quidnug DNS: Same human problem, a victim under coercion can execute UPDATE_GOVERNORS to the attacker’s quid. 24-hour notice gives time for external intervention but doesn’t help a victim under physical threat.

Residual risk: identical to DNS. This is a coercion problem, not a cryptographic one.

4.3 Forgotten key

DNS today: Not applicable (credentials reset via email).

Quidnug DNS: If the owner loses the private key, they lose the domain, unless they pre-configured guardian recovery.

Mitigation: guardian recovery is mandatory for domains you care about. Pick 3-5 guardians independent of you (family, lawyer, bank, etc.). Document the recovery procedure.

Residual risk: owners who don’t set up guardians lose domains permanently. User-education problem, not a cryptographic one.

5. Disruptor attacks

5.1 DDoS against the API gateway

DNS today: UDP amplification is a known issue; mitigated by rate limiting and EDNS cookies.

Quidnug DNS: The api gateway sits behind Cloudflare / other CDN. DDoS is absorbed at the CDN edge. The origin nodes see only CDN-ratelimited traffic.

Residual risk: small. A massive L7 attack could exhaust Cloudflare bot mitigation, but the protocol layer isn’t the weak point.

5.2 Chain-state bloat via spam registrations

Attack: Attacker registers millions of meaningless domains to bloat the chain.

Mitigation:

  • Registration is a governance action at the TLD level. TLDs enforce rate limits, proof-of-work, or fees.
  • Nodes can prune very-old unused domains from hot state (keep only latest-per-key summaries; archive the rest).

Residual risk: economic. TLD operators set their own anti-spam policies.

5.3 Record-update spam

Attack: Legitimate owner publishes 1000 updates/second to degrade the chain.

Mitigation: per-signer rate limits (existing at the node level). A single quid can’t publish faster than its quota.

Residual risk: low. An attacker-controlled quid with many sub-delegations could amplify, but each sub-domain has its own rate limit.

5.4 Unavailable consortium members

Attack: All consortium members for a domain go offline (failure, DDoS, coordinated).

Mitigation: cache replicas continue serving stale-but- valid records up to their TTL. Consumers see degraded freshness, not outright failure. Governance can promote additional consortium members to replace downed ones.

Residual risk: prolonged outage (> TTL) means resolvers return stale / NXDOMAIN. Bounded by the TTL, which is operator-settable.

6. Attacks on delegation

6.1 Parent captures a child’s records

Attack: The TLD consortium decides to publish records on behalf of a delegated sub-domain, overwriting the owner’s.

Defense: Once DELEGATE_CHILD activates, the parent governors lose record-publication authority for that child. Only the child’s governors can publish records. If the parent tries to publish anyway, the resolver sees the signer isn’t in the child’s governor set and rejects.

Residual risk: the parent can REVOKE_DELEGATION during the 24-hour notice period. Owners who suspect revocation should watch for it + dispute during notice.

6.2 Child delegates to a fake parent

Attack: Attacker sets up a fake .quidnug-like TLD with similar-looking branding, tricks users into delegating sub- domains there, then takes over.

Defense: Same problem as DNS: .quidnug-alt-scam isn’t the real .quidnug. Users verify the TLD operator’s pubkey from the well-known file and pin it.

Residual risk: social engineering. Protocol can’t defend against users pointing their resolver at a scam TLD.

6.3 Circular delegation

Attack: example.quidnug delegates to sub.example.quidnug which delegates back to example.quidnug.

Defense: DELEGATE_CHILD validation rejects this, child must be structurally a descendant, and the delegation graph is cycle-checked.

Residual risk: none. Detected at tx validation.

7. Attacks specific to the DNS gateway

7.1 Gateway returns fake responses

Attack: A compromised DNS gateway returns valid-DNSSEC- signed responses with attacker-chosen IPs.

Defense: The gateway’s DNSSEC key is separate from the Quidnug governor key. A compromised gateway can sign bad responses, and DNSSEC-aware clients will accept them (because the gateway legitimately owns the DNSSEC key).

Mitigation: operators who care should use Quidnug-native resolvers (not the gateway) for high-value names. Alternatively, run your own gateway whose DNSSEC key you control.

Residual risk: the gateway is a trust concentration point. It’s a legacy-compat layer, not a protocol component. In the long run, eliminate the gateway by upgrading clients to native Quidnug-DNS.

7.2 Gateway cache poisoning by the backend

Attack: A fake Quidnug node serves fake records to the gateway, which then serves DNSSEC-signed wrong answers.

Defense: The gateway verifies Quidnug responses’ signatures before caching. It only trusts records signed by governors known from the well-known file.

Residual risk: if the well-known file is compromised, the gateway trusts fake governors. The gateway should pin its well-known file at startup + refresh from a pinned URL with TLS pin.

8. Attacks on TLS / DANE integration

8.1 Attacker controls the IP but not the domain

Say the attacker BGP-hijacks the IP for example.quidnug and presents their own TLS cert.

Defense: Client looks up the TLSA record, hashes the presented cert’s pubkey, compares to the TLSA record. No match → TLS handshake fails.

Residual risk: only for applications not using DANE. For DANE-validating clients, BGP hijacking doesn’t help the attacker (they can deny service but not impersonate).

8.2 Attacker gets a CA to mis-issue a cert AND hijacks the IP

Defense: CA trust path is defeated by the TLSA check. The presented cert has to match the domain’s published key; a CA-issued cert for a different public key doesn’t.

Residual risk: none. This is DANE’s whole purpose.

8.3 Attacker compromises the TLS server’s private key

Defense: The published TLSA record still points at the old key. The attacker can serve content using the stolen key until the victim notices + rotates.

Mitigation: monitor TLS key usage. When suspicion hits, publish a new TLSA record pointing at a fresh key, and rotate the server’s key simultaneously. The 24-hour delay between the TLSA update and cache-replica visibility bounds damage.

Residual risk: 24h window of stale TLSA info. Operators can shorten TTL for ultra-paranoid deployments.

9. Residual risks summary

Things this design does NOT defend against:

  • Social engineering. Users delegating to a lookalike TLD, giving away keys under coercion, not setting up guardians. The protocol limits what the attacker can do once they have the key; it can’t prevent users from handing over keys.
  • Whole-network outages. If every consortium member for a domain is offline AND the cache TTL expires, users can’t resolve. Bound by the TTL, not by the protocol.
  • TLD governance capture. If the TLD operators collude, they can revoke any delegation. Users should diversify by running multiple federated TLDs (QDP-0013).
  • Physical-layer denial. A nation-state blocking HTTPS traffic to api.quidnug.com can deny service to its citizens. The protocol doesn’t defeat transport-layer censorship (that’s Tor/VPN/I2P’s job).
  • Economic censorship. A TLD charging for registrations excludes users without money. This is a policy problem. Choose a TLD with policies you like.
  • Fundamental cryptographic breaks. If ECDSA P-256 is broken (a quantum computer, a novel attack), the whole system falls. Post-quantum migration is a future QDP.

10. Compared to DNS + DNSSEC failure modes

Side-by-side for the main threats:

ThreatDNS without DNSSECDNS with DNSSECQuidnug DNS
Cache poisoning❌ vulnerable✅ defended✅ defended
BGP hijacking for resolver-authoritative path❌ allows forgery✅ signatures catch forgery✅ signatures catch forgery
Response spoofing in transit❌ vulnerable✅ defended at validator✅ defended + HTTPS in transit
Registrar seizure❌ possible❌ possible✅ requires governor-key compromise
Root authority capture❌ possible (ICANN)❌ possible (KSK)Mitigated via federation
Key rotationFragileComplex (DS records)Simple (AnchorRotation)
Lost key recoveryRegistrar supportNoneGuardian recovery
CA mis-issuance for TLSPartial (via CAA)✅ (via DANE)
DDoS against rootHas happenedHas happenedNo root to target
Cross-jurisdiction resilience✅ (federation)

Quidnug-DNS at minimum matches DNSSEC on every security property AND adds seizure resistance AND simplifies key management AND makes DANE-style CA elimination practical.

11. Limits

Things to be realistic about:

  1. Adoption is the real enemy. Any alternative DNS has to cross the chasm of “my browser doesn’t know how to resolve this.” The gateway bridges that, but gateways are also centralization points. Pure-Quidnug-native resolution requires changes to browsers / curl / systemd / etc.
  2. Governance attacks are social, not technical. A well-funded adversary can buy-up TLD governors or infiltrate consortiums. The protocol helps detect + slow takeovers but can’t prevent a majority of governors from colluding.
  3. IPv4 scarcity isn’t solved by DNS. Quidnug can point names at IPs; it can’t make more IPs.
  4. Not a privacy tool. Domain ownership and record updates are public on-chain. Private domains exist (separate networks) but the authoritative data is observable to anyone with the chain. Private naming use-cases require encrypted record payloads (future QDP).
  5. Not a content-addressing tool. DNS names resolve to IPs or hostnames. IPFS-style content addressing is a separate problem (though Quidnug’s ipfsEnabled + content-hash events give primitives for it).

12. Response playbooks

Operator-facing playbooks for the common scenarios:

12.1 “My domain’s key was stolen”

  1. Immediately notify guardians (out-of-band).
  2. Initiate guardian recovery: GuardianRecoveryInit signed by M-of-N guardians.
  3. During the 24h notice, monitor the domain for attacker actions. Record and publish any malicious records the attacker publishes so consumers can see them.
  4. After notice: guardians commit the recovery, installing a new governor key.
  5. Publish corrective records from the new key.
  6. Optionally invalidate the old epoch via AnchorInvalidation so any old-key-signed records are frozen.
  7. File a post-mortem. Update guardian setup if needed.

12.2 “A TLD governor account is compromised”

  1. Notify the other governors.
  2. Issue a SUPERSEDE governance tx to halt any pending malicious actions.
  3. Issue UPDATE_GOVERNORS to remove the compromised key (requires unanimity of remaining governors).
  4. Use guardian recovery to rotate the compromised governor’s key to a new one.
  5. Issue another UPDATE_GOVERNORS to add the new key back.
  6. Publish a post-mortem.

12.3 “Nation-state pressure on a TLD operator”

  1. Scenario: operator is ordered to delete a specific domain’s delegation.
  2. Short-term: operator complies (to avoid personal jeopardy).
  3. Medium-term: affected users migrate their domain to a federated TLD operated out-of-jurisdiction.
  4. Long-term: TLD governance distributes across more jurisdictions to prevent single-point pressure.

12.4 “A cached record is stale / wrong”

  1. Identify the domain and record type.
  2. Publish a corrective event.
  3. Push-gossip propagates within ~5 seconds.
  4. Cache replicas refresh their hot state on next push.
  5. Legacy DNS gateway caches refresh on next TTL expiry.

Normal operation. No emergency workflow needed.

13. Known-unknowns

Open questions that need operational data to resolve:

  1. TTL-economics balance. Short TTLs = faster updates but more query load. Long TTLs = stale-longer during incidents. Pick a default?
  2. Default guardian-quorum size for TLDs. 3-of-5? 5-of-9? More = safer, also more operational overhead.
  3. Registration anti-squat policies. Fee-based, proof-of- work, application-gated, or open? Tradeoffs depend on the TLD’s goals.
  4. How aggressively to push legacy-compat. DNS gateway is easy; browser-native integration is years of work across many vendors. Realistically, Quidnug-DNS lives alongside classical DNS for a long time.

None of these are blockers. All become clear with 6-12 months of real deployment data.