Skip to main content

ZeqDNS — node-scoped names and computed addresses

Two different subsystems have been described together under one name, and they behave very differently. Keep them apart:

The name registryThe computed-address layer
Routes/api/hz/*/api/dns/*
What it holdshz_names rows in Postgres, per nodean in-process address map
Live on 2026-09-03answering, priced, node-scopedtotalRecords: 0 on every node probed
Use it?yesnot yet — see below

An earlier version of this page documented human-legible names against /api/dns/*. That was wrong on both halves: names have never lived there, and /api/dns/* resolves computed addresses out of a registry that is currently empty.

The name registry — /api/hz/*

Four routes, verified against https://zeq.me/openapi.json:

RouteAuthDoes
GET /api/hz/check/:labelpublicavailability + price
GET /api/hz/resolve/:namepublicname → owner ZID (and machine)
GET /api/hz/names/:zidowner-gatedthe names a ZID owns
POST /api/hz/registerbearerclaim a name
curl -s https://zeq.me/api/hz/check/alice
# {"ok":true,"label":"alice","name":"alice.hz","available":true,"price_credits":121}

curl -s https://zeq.me/api/hz/resolve/alice.hz
# {"ok":false,"error":"not_found","name":"alice.hz"}

curl -s https://zeq.me/api/hz/names/ZEQTEST
# {"ok":false,"error":"Authentication required.","code":"UNAUTHORIZED","redirect":"/auth/"}

Names are node-scoped, and .hz is only one node's suffix

This is the part most likely to surprise you. Every node sells names under its own suffix, and .hz belongs to zeq.me. Ask the same question of five nodes and you get five different names:

for h in zeq.me zeqproof.com zeq.dev hulyas.org zeqond.com; do
printf '%-16s ' "$h"; curl -s "https://$h/api/hz/check/alice" \
| python3 -c "import sys,json;print(json.load(sys.stdin)['name'])"
done
zeq.me alice.hz
zeqproof.com alice.zeqproof
zeq.dev alice.zeqdev
hulyas.org alice.hulyasorg
zeqond.com alice.zeqond

nodeTld() derives the suffix from the node's own public origin, falling back to hz only when the origin is unpinned. The reason is stated in the source and is worth repeating, because it explains why there is no reconciliation protocol here: uniqueness is a local UNIQUE(label, tld) constraint, so the cross-node claim race is structurally impossible. No two nodes can ever sell the same name, so there is nothing to reconcile and nothing to refund.

Price is a function of the framework's own economy, not of the node: 121 credits per year on every node sampled.

A name is bought with compute credits or by burning owned envelopes. There is no external money in this path. The register body, from the live OpenAPI spec:

{ "label": "alice", "years": 1,
"payment": { "method": "credits" },
"machine_id": "optional — bind the name to one of your machines" }
{ "label": "alice",
"payment": { "method": "envelopes", "envelope_ids": ["…", "…"] } }

Registration is first-come-first-served on the local unique constraint. Each registration is written to the node's entangled state (the audit trail gives ordering) and sealed with a deterministic nameRecordHash over label, tld, ownerZid, registeredZeqond and origin — any node can recompute it from the public fields, so a registry row cannot be silently altered.

Resolution federates exactly one hop

The hz_names table is per-node, like every other private table. On its own, a name registered on one node would neither resolve nor read as taken on the others. lib/hzFederation.ts closes the read half:

  • a resolve or availability question fans out to the sibling nodes;
  • peer calls carry the header x-hz-federated: 1, and a node serving a request that already has that header answers from its local database only — so federation is exactly one hop and cannot loop;
  • every peer fetch is time-boxed, and a failure is swallowed: a peer being down degrades to "not found there", never an error to you;
  • results are cached in-process, hits longer than misses.

A resolved name comes back with its home origin, so you learn where the name lives as well as who owns it:

{ "ok": true, "name": "…", "owner_zid": "ZEQ…", "machine_id": "…",
"registered_zeqond": 0, "expires_zeqond": 0, "origin": "https://…" }

The source is candid that this is the read side of an incremental plan: it gives global resolution today and shrinks — but does not yet fully close — the registration race. Node-scoped suffixes are what make that acceptable in the meantime.

The computed-address layer — /api/dns/*

The other idea under the ZeqDNS name is genuinely different: replace a lookup with a computation. A domain is hashed, its first bytes become a seed, and the seed is run through the framework's own constants to land on an address:

addr(d)=( sfH+sin(sTZ) )mod232,s=first 8 bytes of SHA-256(d)\text{addr}(d) = \bigl(\ s \cdot f_H + \sin(s \cdot T_Z)\ \bigr) \bmod 2^{32}, \qquad s = \text{first 8 bytes of } \mathrm{SHA\text{-}256}(d)

That arithmetic is real and deterministic, and you can watch it run:

curl -s -X POST https://zeq.me/api/dns/resolve \
-H 'content-type: application/json' -d '{"domain":"api.zeq.dev"}'
# {"error":"Domain not registered","code":"NOT_FOUND",
# "domain":"api.zeq.dev","address":"00000000f0d05000"}

The address is computed. What is missing is anything to look up:

for h in zeq.me zeqproof.com zeq.dev; do printf '%-16s ' "$h"; curl -s "https://$h/api/dns/status"; echo; done
# zeq.me {"totalRecords":0,"activeRecords":0,"domains":0,"zeqond":…}
# zeqproof.com {"totalRecords":0,"activeRecords":0,"domains":0,"zeqond":…}
# zeq.dev {"totalRecords":0,"activeRecords":0,"domains":0,"zeqond":…}
warning
Do not build on /api/dns/* today

The registry behind it is an in-process map, empty on every node we probed, and it is not where .hz names live. POST /api/dns/register also carries no security requirement in the published OpenAPI spec, where POST /api/hz/register requires a bearer token — another reason to treat the /api/hz/* surface as the real one and this one as unfinished.

  • Mesh & self-hosting — the transports names ride on, and standing up your own node (which brings its own suffix with it).
  • Nodes and node-locality — the eighteen nodes, and which suffix belongs to which.
  • ZeqID — identity derived by computation, the same idea applied to people.