Documentation / Node identity & registry
HiNet Node Identity & Network Registry — Spec
Status: Draft v0.1 · Companion to HiNet-Technical-Spec.md (node-identity, peer-protocol), HiNet-Sovereign-Intelligence-Vision.md (§8 "portable, encrypted, owner-keyed iCore"), Node-Packaging-Addendum (Ed25519/Keychain identity, WorkOrder signing), Foundational-Model-Plan §3.3.2 (competence signatures), and master-task-list M2-003 (node identity module), M1-001 (compatibility class / passport), PF-1 / M5-005 (competence-signature routing).
Scope. Two coupled pieces: (1) the per-node cryptographic identity an iCore carries — the owner-held keypair, the derived stable node id, and the human name/handle on top of it; and (2) the HiNet Registry — the central service that keeps the global pool of nodes so they can be discovered and routed to. This is the substrate the iQuorum/iCorp layer, the spectrum router, and pay-per-use attribution all build on: you cannot route to, pay, or membrane an iCore you cannot name and verify.
Terminology is reused verbatim from the existing docs: iCore (= 1 human), iQuorum, iCorp (rigid org-gated quorum), qCore, membrane, ConsentGrant, the audit hash-chain, Δ_public/Δ_private, competence signature, model passport / compatibility class, WorkOrder/BackendReceipt, ComputeBackend, VaultReplication, the human-first lease, right-sizing to the minimal sufficient qCore.
Naming caution (EXISTS): the built runtime already has
hinetd/registry.py— that is the local model registry (loads/caches MLX roots). It is unrelated to this document. Here "Registry" always means the network node registry (a new central service). To avoid collision in code, the node-side client isRegistryClientand the service ishinet-registry/registryd.
0. What already exists vs. what is new
| Piece | Status | Where |
|---|---|---|
| Audit hash-chain (tamper-evident, per-node) | EXISTS | hinetd/audit.py |
Consent store / ConsentGrant gate |
EXISTS | hinetd/consent.py |
DeltaViewStore (skill/voice training set → source of Δ_public) |
EXISTS | hinetd/classify.py |
| Model passport / compatibility class as a concept | SPEC'd, not coded | Foundational-Plan M1-001 |
| Competence signature (routing) as a concept | SPEC'd, not coded | Foundational-Plan §3.3.2 |
Ed25519 identity in Keychain, node_sig on WorkOrder |
SPEC'd, not coded | Node-Packaging §B; AuditEvent.signature field is present but unsigned today |
NodeProfile / PeerAnnouncement YAML contracts |
SPEC'd (shape only) | Technical-Spec "Data Contracts" |
| Per-node keypair generation + node-id derivation | NEW (this doc) | node-identity module (M2-003) |
| HiNet Registry service (global node pool, discovery) | NEW (this doc) | hinet-registry on Quorumz GCP |
| Registration / rotation / revocation flows | NEW (this doc) | |
| Capability indexing (ANN over competence centroids) | NEW (this doc) | |
| Decentralized migration path (DHT) | NEW, later |
1. Per-node cryptographic identity
1.1 The keypair (owner-held, never leaves)
Every iCore holds one Ed25519 identity keypair (Bernstein et al., 2011), consistent with the existing plan (Node-Packaging §B: ed25519-dalek, private key in Keychain/Secure Enclave; Personal-Data-and-Sovereignty §4.2: Ed25519 signing key separate from the vault DEK).
- Custody. Private key lives in the OS Keychain / Secure Enclave, owned by the Rust security core in the Tauri build. MVP fallback (before Rust core lands):
hinetdgenerates and holds the key viacryptography/pynaclin an OS-permission-restricted file under~/.hinet/identity/(0600), migrated into Keychain when the Rust core ships. The private key never leaves the device except as ciphertext insideVaultReplication(encrypted under the owner's DEK/recovery phrase). - Two keys, one role split (recommended — OPEN DECISION D1):
k_id— the genesis identity key. Its public half defines the node id forever (see §1.2). Rotated only rarely, via a signed rotation cert (§3.4); the id survives rotation.k_sign— the current signing subkey, authorized byk_id, used for day-to-day request signing (registration, heartbeats, WorkOrders). Rotatingk_signis cheap and does not change the node id.- This decouples who you are (stable, self-certifying) from what key signs right now (rotatable, revocable). The simpler single-key alternative (id = hash of the only key; rotation = new id + alias) is D1's fallback if the subkey machinery is judged premature for MVP.
- The identity key is also the key that signs the local audit hash-chain (EXISTS but currently unsigned — closing that is a small change: sign each
AuditEventwithk_sign, chained underk_id).
1.2 Node id derivation (self-certifying)
The node id is derived from the identity pubkey, so anyone holding the id can verify a presented pubkey matches it — no PKI, no trusted issuer. Reuses the existing icore_ prefix (NodeProfile.node_id: "icore_...").
raw = ed25519_pubkey_bytes(k_id) # 32 bytes
h = SHA-256(0x01 || raw) # 0x01 = HiNet node-id version/domain byte
node_id = "icore_" + crockford_base32(h[:20]).lower() # 20 bytes → 32 base32 chars
# example: icore_9x7q2m4k1t8v3b6n0p5r7s9w2c4e6g8h
- Self-certifying:
verify(node_id, pubkey) := node_id == "icore_" + b32(sha256(0x01||pubkey)[:20]). Impersonation of a specificnode_idrequires its private key. - Interop representations (NEW, later):
- DID:
did:key:z6Mk…(Ed25519 multicodec0xed01) — the W3C-standard form of the same key, for cross-ecosystem verifiable credentials (the Technical-Spec's "future DID binding"). - libp2p PeerId: derived from the same Ed25519 key when the DHT path lands (§5) — so the node's network identity and its HiNet identity are the same key.
- Wallet binding (NEW, later, OPTIONAL): an owner may link an EVM address (sign the
node_idwith the wallet, store the signature) for payout routing (§6A pay-per-use) and sybil-resistance — kept separate from the identity key so custody models don't blur.
1.3 Naming: human label + stable crypto id
Three distinct fields — do not conflate:
| Field | Mutable? | Unique? | Purpose |
|---|---|---|---|
node_id |
No (immutable, crypto) | Globally (self-certifying) | Machine address; verification anchor |
node_name |
Yes (owner edits) | No | Human display label ("Eitan's coding iCore"); free text |
handle |
Yes (re-claimable) | Yes, registry-scoped | @-mention target in the "Slack-for-AI" UX (Vision §5/§6) |
node_nameandhandleare owner-signed metadata in the registry record (§2), not part of the crypto id — changing them is a signedPATCH, cheap, and doesn't touch the key.- Handle uniqueness is the one property that genuinely needs a coordinator (a pure hash can't allocate
@alice). MVP: first-claim-wins, owner-signed, disputes resolved by the platform; this is the main thing the central registry provides that a DHT can't trivially replicate (§5). Handles are optional — a node is fully functional addressed bynode_idalone.
2. The HiNet Registry service (the global node pool)
2.1 What it is
A new central service, hinet-registry, that keeps the discoverable directory of the network's nodes: identity → pubkey → capabilities → reachability → membrane → liveness. It is the bootstrap + discovery + naming layer — think libp2p rendezvous/bootstrap node + a capability ANN index + a handle registry, not a source of authority over identity (identity is self-certifying; §1.2).
The registry's trust envelope is deliberately small: because every record is owner-signed and every id is self-certifying, the registry cannot forge an identity, a pubkey binding, or a capability claim. It can only censor, withhold, reorder, or stall. That bounded trust is exactly what makes the decentralization migration (§5) tractable — the data model doesn't change, only who indexes it.
2.2 Deployment (Quorumz GCP, HiNet-scoped resources)
Per the central-infra note, HiNet central services run in the Quorumz GCP project but on their own HiNet-product resources:
- Service: Cloud Run service
hinet-registry(own service accounthinet-registry@…), fronted atregistry.mind.quorumz.com. - DB (NEW): its own Cloud SQL Postgres instance
hinet-registry-db(isolated from Quorumz's app DB), with thepgvectorextension for competence-centroid ANN. - Object store: a GCS bucket for large signed blobs (competence attestations/scorecards, key-history exports).
- Transparency log (NEW, later): an append-only, Merkle-committed log of
(node_id, pubkey, handle)bindings (Certificate-Transparency-style) so clients can detect a registry that serves a wrong pubkey for an id/handle. - Isolation from Quorumz's own data is a hard requirement (separate DB instance + SA + bucket), so HiNet's directory can't be entangled with Quorumz journalism data.
2.3 Data model — NodeRecord
Reconciles the existing NodeProfile + PeerAnnouncement YAML contracts into one persisted record.
Postgres DDL (NEW):
CREATE TABLE node_record (
node_id TEXT PRIMARY KEY, -- "icore_..." (self-certifying)
identity_pubkey BYTEA NOT NULL, -- Ed25519 k_id pubkey (32B); id derives from this
signing_pubkey BYTEA NOT NULL, -- current k_sign pubkey (rotatable)
key_history JSONB NOT NULL DEFAULT '[]', -- [{pubkey, authorized_by, rotated_at, cert_sig}]
owner_ref TEXT, -- opaque owner handle: mind.quorumz.com account id / wallet / null
node_name TEXT, -- human display label
handle TEXT UNIQUE, -- "@alice", registry-scoped unique, nullable
passport JSONB NOT NULL, -- model passport / compatibility class (M1-001)
competence JSONB NOT NULL, -- CompetenceSignature (labels, langs, code, data-classes, self-desc)
competence_vec VECTOR(768), -- pgvector: competence centroid (ANN routing)
endpoint JSONB, -- reachability: multiaddr(s) / relay / "local_only"
visibility TEXT NOT NULL DEFAULT 'public', -- public | unlisted | membrane_hidden
membrane_id TEXT, -- iCorp/membrane binding (nullable → free iCore)
lease JSONB, -- active human-first lease terms (nullable)
attestation_level TEXT NOT NULL DEFAULT 'none', -- none | local | tee (from Capabilities)
status TEXT NOT NULL DEFAULT 'active', -- active | paused | leased | revoked | tombstoned
reputation JSONB NOT NULL DEFAULT '{}', -- usage-earned scores (later)
last_seen TIMESTAMPTZ, -- heartbeat freshness
registered_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
record_sig BYTEA NOT NULL -- owner Ed25519 sig over canonical record (self-authenticating)
);
CREATE INDEX ON node_record USING ivfflat (competence_vec vector_cosine_ops); -- ANN
CREATE INDEX ON node_record (membrane_id);
CREATE INDEX ON node_record (status, visibility);
-- capability inverted index (coarse routing by taxonomy label / language / passport class):
CREATE TABLE node_capability_tag (
node_id TEXT REFERENCES node_record(node_id) ON DELETE CASCADE,
facet TEXT NOT NULL, -- 'domain' | 'language' | 'code_stack' | 'data_class' | 'passport_class'
value TEXT NOT NULL,
PRIMARY KEY (node_id, facet, value)
);
CREATE INDEX ON node_capability_tag (facet, value);
JSON view (the wire form clients see) — NodeRecord:
{
"node_id": "icore_9x7q2m4k1t8v3b6n0p5r7s9w2c4e6g8h",
"identity_pubkey": "ed25519:base64…",
"signing_pubkey": "ed25519:base64…",
"node_name": "Eitan's coding iCore",
"handle": "@eitan-dev",
"owner_ref": "qz_acct_…", // or wallet, or null for anon
"passport": { // M1-001 compatibility class
"base_model_id": "Qwen3-Next-80B-A3B-Instruct",
"tokenizer_hash": "…", "chat_template_hash": "…",
"quant": "4bit", "adapter_contract": "moe-switchlinear+attn-qv",
"compatibility_class": "qwen3-next-a3b/v1"
},
"competence": { /* CompetenceSignature — see §4 */ },
"endpoint": { "reachability": "relay", "multiaddrs": ["/dns4/relay.mind.quorumz.com/…/p2p/…"] },
"visibility": "public",
"membrane_id": null,
"lease": null,
"attestation_level": "local",
"status": "active",
"last_seen": "2026-08-18T09:00:00Z",
"record_sig": "ed25519:base64…" // owner sig over canonical(record minus this field)
}
Every field the prompt asked for is present: id (node_id), pubkey (identity_pubkey/signing_pubkey), owner (owner_ref), node name (node_name/handle), declared capabilities/specialities (competence + competence_vec + node_capability_tag), endpoint/reachability (endpoint), iCorp/membrane binding (membrane_id/lease), last-seen (last_seen), status (status).
2.4 Membrane / iCorp records (NEW)
The registry also holds the org layer (Vision §2–§3). Kept minimal here; the full iCorp/lease lifecycle is its own spec.
CREATE TABLE membrane (
membrane_id TEXT PRIMARY KEY, -- "icorp_..." for iCorps, "gov_..." later
kind TEXT NOT NULL, -- 'icorp' | 'gov'
display_name TEXT NOT NULL,
admin_pubkeys JSONB NOT NULL, -- Ed25519 keys allowed to admit/revoke members
external_identity JSONB, -- the single business-unit identity shown publicly
created_at TIMESTAMPTZ DEFAULT now()
);
- A node's
membrane_id+leaseexpress the human-first lease (Vision §3): while leased, the iCore is bound to the iCorp; on unbind (leave), the node reverts tomembrane_id=null(iCore travels with the human) — but its contribution to the iCorp model is out of registry scope (it stays in the iCorp's weights). The registry only tracks the binding, not the intelligence. - Visibility rule (the membrane, enforced): a node with
visibility="membrane_hidden"is never returned to public discovery; public queries that route to it see only the iCorp external identity, honoring "internal iCores are neither referenced nor paid individually."
3. Flows: registration, revocation, re-registration, rotation
All mutating requests use a signed envelope with anti-replay:
// SignedEnvelope
{ "payload": { … }, "node_id": "icore_…",
"signing_pubkey": "ed25519:…", // must be authorized by k_id per key_history
"nonce": "…", // from POST /v1/challenges (single-use, short TTL)
"issued_at": "…", "expiry": "…",
"sig": "ed25519:… over canonical(payload||nonce||issued_at||expiry)" }
The registry verifies: (a) node_id self-certifies against identity_pubkey; (b) signing_pubkey is authorized by the identity key via key_history; (c) signature valid; (d) nonce fresh & unused; (e) not expired. Every registry interaction is also appended to the node's local audit hash-chain (EXISTS) via audit.append("registry.register", …).
3.1 Registration (keygen → sign → verify → join) — MVP
Node (hinetd / Rust core) Registry (hinet-registry)
───────────────────────── ─────────────────────────
1. Ensure identity keypair exists
(Keychain; else ~/.hinet/identity) — generate k_id (+k_sign) if first run
2. Derive node_id = icore_ + b32(sha256(0x01||pub_kid))
3. Build competence signature locally (§4) from Δ_public/deltaview (never raw vault)
4. GET /v1/challenges ──────────────────────────▶ issue single-use nonce
◀────────────────────────── { nonce, ttl }
5. Build RegistrationRequest {node_id, identity_pubkey, signing_pubkey,
node_name, handle?, passport, competence, competence_vec, endpoint,
visibility, membrane_id?, membrane_admission_proof?}
6. Sign envelope with k_sign
7. POST /v1/nodes ──────────────────────────────▶ verify: id↔pubkey, sig, nonce,
handle free, (if membrane) admission proof
→ UPSERT node_record status=active
→ index tags + competence_vec (ANN)
→ append to transparency log
◀────────────────────────── 201 { NodeRecord, MembershipReceipt }
8. Verify MembershipReceipt (registry-signed), store, audit.append("registry.register")
9. Begin heartbeats (§3.2)
MembershipReceipt = registry-signed {node_id, registered_at, registry_pubkey, log_index} — proves the node is in the pool at a log position (useful once the transparency log exists).
3.2 Heartbeat / reachability — MVP
POST /v1/nodes/{id}/heartbeat (signed, cheap) every ~30–60 s updates last_seen and may refresh endpoint. Discovery filters on freshness (last_seen within a window) so dead nodes fall out of routing without an explicit deregister. Mirrors PeerAnnouncement.availability (EXISTS as a contract). Endpoints are self-declared; the router (or an asker) verifies reachability by dialing + a challenge-response before trusting an endpoint (anti-spoof, §7).
3.3 Revocation & re-registration
- Owner revocation:
POST /v1/nodes/{id}/revokewith a signed RevocationCert{node_id, reason, revoked_at, sig(k_id)}→status=revoked,visibilityforced hidden, dropped from ANN. The RevocationCert is self-standing (signed by the identity key) so it can also be gossiped in the decentralized future — the registry is not the source of truth for "is this node revoked," the cert is. - Re-registration / restore-on-new-machine: the owner restores identity + vault via
VaultReplication(EXISTS as design) on a new device — samek_id⇒ samenode_id. Registration is therefore an UPSERT, not a new identity: the flow in §3.1 runs again, updatingendpoint/signing_pubkey. This is why re-registration is free and the id is durable across hardware. - iCorp unbind (lease end): membrane admin or owner signs to clear
membrane_id/lease; node reverts to free. Admin can revoke the lease binding but cannot revoke the node (human-first sovereignty — the membrane governs the binding, never the atom).
3.4 Key rotation
Two rotation scopes (matches the two-key model, §1.1; OPEN DECISION D1 governs whether both exist in MVP):
- Signing-subkey rotation (cheap, expected):
POST /v1/nodes/{id}/rotatewith a RotationCert{new_signing_pubkey, authorized_by: k_id, rotated_at, sig(k_id)}. Registry appends tokey_history, updatessigning_pubkey.node_idunchanged. Old subkey immediately unusable. - Identity-key rotation (rare, recovery/compromise): a GenesisRotationCert
{new_identity_pubkey, prev_identity_pubkey, rotated_at, sig(old_k_id) [+ sig(recovery_key)]}chains the new identity key to the old. OPEN DECISION D2: doesnode_idstay pinned to the original genesis pubkey (id never changes; rotation is a signed key-history the registry + transparency log carry) — or does it mint a newnode_idwith a signed alias link to the old? Recommendation: pin the id to the original and carry a verifiable key-history, so a compromised-but-recovered node keeps its identity, reputation, and handle. If the identity key is lost (no old-key signature possible), recovery falls back to the recovery phrase / Shamir escrow (Personal-Data-and-Sovereignty §4.2); with neither, key loss = identity loss (the sovereignty price, stated at onboarding).
4. Capability / speciality indexing (routable without leaking)
4.1 The CompetenceSignature (reuses Foundational-Plan §3.3.2 exactly)
What a node declares it is good at — assembled locally, from the consented, generalized Δ_public / DeltaView (EXISTS: classify.py already partitions skill/voice into the DeltaView), never from raw vault content:
// CompetenceSignature (goes in node_record.competence + competence_vec + node_capability_tag)
{
"self_description": "Senior backend/infra engineer; Python, Go, GCP, trading systems.", // owner text, public-safe
"passport_class": "qwen3-next-a3b/v1", // only same-class composes by weight (M1-001)
"domains": ["software-engineering", "devops", "quant-finance"], // from a shared taxonomy
"languages": ["en", "he"], // human languages (cross-lingual RAG already proven)
"code_stacks": ["python", "go", "terraform"],
"data_classes":["code", "documents", "messages"],// GENERALIZED classes, NOT the data itself
"competence_centroid": [ /* 768-d */ ], // SUPERSEDED as competence-of-truth → coarse ANN discovery hint only; per-speciality competence + derived effective_strength now come from Verifiable Competence Attestation (Routing §2.5; stored §4.5)
"generality": 0.42, // how broad vs narrow (feeds right-sizing)
"declared_at": "…",
"proof_level": "declared", // node-level coarse floor only; the real proof-tier is PER-SPECIALITY: declared | committed | provenance | challenged | usage | attested (6-tier, Routing §2.5.2 / §4.5.1)
"proof_refs": [] // signed scorecards / attestations (§4.5)
}
Superseded (0.12.0) — competence is per-speciality now. The single node-level
competence_centroidabove is a coarse discovery hint only; the authoritative competence model is per-speciality Verifiable Competence Attestation (Routing §2.5), from which the router derives a verified, decayingeffective_strength(Routing §2.5.4). The registry stores/serves those per-speciality attestations (§4.5); it never computes trust.
4.2 Privacy: how declaration doesn't leak private data
The whole point (Sim-to-Real-Gap flags routing-at-scale + capability privacy as High risk):
- Only generalized artifacts are published: taxonomy labels + a competence centroid computed over the
Δ_public/ DeltaView projection — the same consented, leakage-gated, de-identified surface the network is already allowed to learn from. Raw vault records,Δ_private, and per-item embeddings never touch the registry. - Data-classes, not data:
data_classessays "I have code and messages", never which repos or whose messages. - Leakage gate on the centroid (OPEN DECISION D3): the centroid is a low-dimensional mean, but embedding-inversion is a real attack surface. Mitigations to evaluate: publish a quantized / dimensionality-reduced centroid, add DP-noise, or publish only cluster-id membership rather than a raw vector. Measured in E2 alongside
Δ_publicleakage. - Membrane hiding:
visibility="membrane_hidden"competence is indexed only inside the iCorp workspace, never in public ANN.
4.3 Proving competence (progression — declaration is worthless until proven)
Superseded (0.12.0): competence proof is now PER-SPECIALITY, not a single node-level ladder. The old 4-tier node-level ladder (declared | challenged | usage | attested) is replaced by the 6-tier per-speciality proof ladder — declared | committed | provenance | challenged | usage | attested — defined canonically in Routing §2.5.2 (Verifiable Competence Attestation) and stored/served registry-side in §4.5.1 (with the honest trust caveats: committed is auditable-not-trusted, challenged counts only when weight_bound, attested is research-grade / unavailable to the laptop persona).
The load-bearing discipline is unchanged and still lives here: a self-declared claim carries routing weight 0 (and committed ~0 for payout-bearing routing) — declaration is worthless until proven. The registry stores the tier + signed proofs; the router derives the verified, decaying effective_strength and gates payout-bearing routing on attested + proof-of-personhood (Routing §2.5.4). See §4.5.1 for the full registry-side ladder.
4.4 Indexing & the routing handoff (keep the boundary clean)
- The registry answers discovery ("which nodes plausibly match this need?") via: pgvector ANN over
competence_vec+ inverted-index filter overnode_capability_tag(domain/language/passport-class) + freshness/status/visibility filters. It returns a ranked candidate set, not a final answer team. - The spectrum router / qCore router (separate component, M1-004/M5-005/PF-1) then does per-prompt selection: score the prompt against candidate signatures → right-size to the minimal sufficient set (narrow → own iCore; cross-domain → a few; general → escalate) → pick composition mode by fidelity × budget. The registry is the index; the router is the decision. This doc specs the index and the discovery API; the router is out of scope here (referenced only).
5. Decentralized-DB path (central now → DHT later)
5.1 Why central first (pragmatic MVP)
Central hinet-registry (Cloud SQL + pgvector) is the bootstrap: it gives fast global discovery, handle uniqueness/naming, capability ANN (hard to do on a raw DHT), and a single place to reach for a cold start — with none of the DHT engineering. Because records are owner-signed and ids self-certifying, the central DB is trusted only for availability + honest indexing, not for identity/capability truth. That bounded trust is the whole migration strategy.
5.2 Migration path
Every NodeRecord is already a self-authenticating, content-addressable object (record_sig over canonical bytes; keyed by a self-certifying id). So the data is portable to a decentralized substrate without changing its trust model — only who stores/indexes it changes. Staged:
- Signed-record export (do now, cheap): expose
GET /v1/nodes/{id}returning the fully signed record +MembershipReceipt, so a node is never locked in — anyone can verify a record offline. (This is the single most important forward-compat hook.) - Gossip form: the existing
PeerAnnouncementcontract (EXISTS as a shape) is the gossip projection of aNodeRecord— publish signed announcements over libp2p pubsub. - DHT resolution: put
node_id → signed NodeRecordin a libp2p Kademlia DHT (the Technical-Spec'sPeerId/DHT direction). The node's libp2pPeerIdderives from the same Ed25519 identity key (§1.2), so id resolution is self-verifying on the DHT too. - Registry demotes to one indexer among many: it becomes a bootstrap node + capability-ANN indexer + naming authority, not the source of truth.
5.3 Trade-offs
| Concern | Central registry (MVP) | Pure DHT | Hybrid (recommended target) |
|---|---|---|---|
| Cold-start discovery | ✅ trivial | ⚠️ needs bootstrap peers | ✅ registry as bootstrap |
| Capability ANN search | ✅ pgvector | ❌ ANN over a DHT is hard | ✅ federated indexers |
| Handle uniqueness / naming | ✅ authoritative | ❌ needs a naming layer (stake/social) | ✅ registry as naming authority |
| Censorship / single point of failure | ❌ can censor/withhold/stall | ✅ resilient | ✅ signed records verifiable anywhere |
| Identity forgery | ✅ impossible (self-certifying) | ✅ impossible | ✅ impossible |
| Sybil resistance | ⚠️ needs gating (§7) | ❌ worse (free identities) | ⚠️ gating + stake |
| Ops cost | ✅ low | ❌ high | ⚠️ medium |
Open decisions: D4 — sybil-resistant, decentralized handle naming is the genuinely hard part (candidates: stake-based registry, ENS-style, or social-graph attestation); D5 — decentralized capability ANN (federated indexers vs. locality-sensitive DHT keys). Both are later; MVP keeps naming + ANN central.
4.5 Verifiable Competence Attestation — storage, serving & gating [NEW]
Implements Routing §2.5 on the registry side: the registry stores + serves signed attestations and pre-filters discovery to fresh, proven, publicly-exposed specialities; it never computes trust (that is router-local, Routing §2.5.4).
4.5.1 proof_level ladder — extended for attested competence [NEW]
The proof_level ladder gains the accountability tier and the honest trust caveats from Routing §2.5.2. The registry stores and serves per-speciality attestations; it never grants trust — the router derives effective_strength locally (Routing §2.5.4).
| Level | Mechanism | Registry role | Status |
|---|---|---|---|
declared |
self-asserted labels + cluster-id | store; router weight 0 | MVP |
committed |
Merkle commitment + RFC3161 root_chain + audit-chain + expiry (Routing §2.5.2 T-A) |
store bundle + serve signed; auditable, not trusted — router weight ~0 for payout | NEW, MVP |
provenance |
zkEmail-DKIM / zkTLS / signed-git (channel, not expertise) | store proof_refs; caps trust |
NEW, later |
challenged |
decentralized eval — counts only if weight_bound (else a general model fronting) |
store signed Scorecard | NEW, later |
usage |
real accept/reject from receipts (down-adjust only; cold-start quarantined) | store reputation |
NEW, later |
attested |
TEE quote binding {measure_code_hash, vault_root, model_hash} |
store quote | NEW, research — unavailable to laptop persona |
4.5.2 speciality_attestation + governed-taxonomy tables (extends §2.3) [NEW]
-- per-speciality attestation: self-authenticating, DHT-portable, independently verifiable
CREATE TABLE speciality_attestation (
node_id TEXT REFERENCES node_record(node_id) ON DELETE CASCADE,
domain TEXT NOT NULL, -- canonical taxonomy id "tax:<domain>@v<n>" (governed; Routing §2.5.6)
method_tier TEXT NOT NULL, -- declared|committed|provenance|challenged|usage|attested
weight_bound BOOLEAN NOT NULL DEFAULT false, -- true iff capability answers bound to committed weights (anti-fronting)
personhood TEXT NOT NULL DEFAULT 'none', -- none|account|proof_of_personhood (gates payout-bearing routing)
exposure TEXT NOT NULL DEFAULT 'public', -- public|membrane|private
max_sensitivity TEXT NOT NULL DEFAULT 'normal', -- HCR SensitivityClass ceiling; sensitive|secret ⇒ never public
vault_root TEXT, -- committed Merkle root (density_proof)
n_items INT, diversity REAL, months_populated INT, span_days INT, slope REAL,
first_party_fraction REAL DEFAULT 0,
capability_score REAL,
root_chain JSONB, -- [{root,n_D,tsa_token,log_index,at}] — the non-backdatable curve
proof_refs JSONB, -- signed scorecards / zk proofs / TEE quotes (GCS blob refs)
verifier_set JSONB, -- who attested each component
attested_at TIMESTAMPTZ, expires_at TIMESTAMPTZ,
record_sig BYTEA NOT NULL, -- owner Ed25519 sig over canonical bundle (self-authenticating)
PRIMARY KEY (node_id, domain)
);
CREATE INDEX ON speciality_attestation (domain, method_tier, expires_at); -- discovery pre-filters to FRESH proven
CREATE INDEX ON speciality_attestation (expires_at) WHERE expires_at > now();
-- governed taxonomy dictionary (Routing §2.5.6) — the registry is the naming authority for domain-ids
CREATE TABLE competence_taxonomy (
domain_id TEXT PRIMARY KEY, -- "tax:solidity-security@v3"
version INT NOT NULL,
label TEXT NOT NULL,
centroid VECTOR(768), -- embedded taxonomy anchor (label-snap target)
rebased_from TEXT, -- split/merge lineage (deterministic re-basing)
published_at TIMESTAMPTZ DEFAULT now()
);
-- node_capability_tag gains freshness/tier facets so coarse discovery pre-filters to fresh + proven
ALTER TABLE node_capability_tag ADD COLUMN method_tier TEXT;
ALTER TABLE node_capability_tag ADD COLUMN expires_at TIMESTAMPTZ;
Transparency log extension [LATER]: extend the planned CT log from (node_id, pubkey, handle) to also anchor (node_id, domain, root, n_D, at) — the append-only, non-backdatable accumulation curve. Net-new later infrastructure, not an existing primitive (labeled honestly).
4.5.3 Discovery + serving rules (enforced) [NEW]
GET /v1/discover*andPOST /v1/discover/vectorMUST filterexposure != 'public'out of the public pool, dropexpires_at <= now(), and dropmax_sensitivity IN ('sensitive','secret')— a leak here breaks HiNet's absolute sovereignty constraint (D3).- The registry serves
method_tier,weight_bound,personhood,root_chain,proof_refs,expires_at; it never computeseffective_strength(that is sovereign, router-local — Routing §2.5.4). POST /v1/nodes/{id}/attestations(alreadylaterin §6.1) carries theCompetenceAttestationbundle; the registry verifies the Ed25519 signature and self-certification but takes every competence claim on faith — trust is the router's job, gated on tier +weight_bound+personhood.- Payout-bearing routing (settlement path) MUST require
method_tier='attested' AND personhood='proof_of_personhood';declared/committedare discovery-only.
4.5.4 Sybil — extended (see §7.1) [NEW]
Calendar-cost accumulation is paid once and cloned across N vaults in parallel → it rate-limits, it does not resist Sybils. Mitigations (MVP): declared/committed unweighted for payout; per-owner_ref cap on routable specialities; rate-limit attestation submission. (Later, required before payout-bearing trust): proof-of-personhood (D6), stake-to-attest with slashing on honeypot failures, [LATER] cross-node corpus-overlap (PSI) detection so one dataset can't mint N first-party experts.
4.5.5 D3 — centroid publication resolved to a hard gate [NEW]
Publishing any centroid is gated: default to cluster_id membership only (no raw or quantized vector); a dp_centroid ships only after E2 empirically bounds embedding-inversion; the SensitivityClass ceiling is a hard filter (sensitive/secret domains never publicly attested); per-domain owner opt-in required. Moved from open-decision to enforced precondition.
6. API surface
6.1 Registry service (registry.mind.quorumz.com, NEW)
| Method / path | Auth | Purpose | Tier |
|---|---|---|---|
POST /v1/challenges |
none | Issue single-use nonce for signed calls | MVP |
POST /v1/nodes |
signed | Register / upsert a NodeRecord |
MVP |
GET /v1/nodes/{node_id} |
none | Fetch signed record (+ MembershipReceipt) |
MVP |
PATCH /v1/nodes/{node_id} |
signed | Update name/handle/capabilities/endpoint/visibility | MVP |
POST /v1/nodes/{node_id}/heartbeat |
signed | Refresh last_seen / endpoint |
MVP |
POST /v1/nodes/{node_id}/rotate |
signed (RotationCert) | Rotate signing subkey / identity key | MVP (subkey), later (genesis) |
POST /v1/nodes/{node_id}/revoke |
signed (RevocationCert) | Tombstone the node | MVP |
GET /v1/handles/{handle} |
none | Resolve @handle → node_id |
MVP |
GET /v1/discover?domain=&language=&passport=&status=active&fresh=1&k=20 |
none | Coarse capability search (inverted index) | MVP |
POST /v1/discover/vector {centroid|prompt_embedding, filters, k} |
none | ANN over competence centroids → ranked candidates | MVP |
POST /v1/nodes/{node_id}/attestations |
signed | Attach a signed Scorecard / TEE quote (proof_ref) |
later |
POST /v1/membranes · POST /v1/membranes/{id}/leases · DELETE …/leases/{node_id} |
signed (admin) | iCorp create + human-first lease bind/unbind | later |
GET /v1/log/proof?node_id= |
none | Transparency-log inclusion proof for a binding | later |
6.2 Node-local (hinetd, extends existing /node/*)
| Method / path | Purpose | Status |
|---|---|---|
GET /node/identity |
Return {node_id, identity_pubkey, signing_pubkey, node_name, handle} |
NEW (M2-003) |
POST /node/identity/init |
Generate keypair if absent (Keychain / file fallback) | NEW |
POST /node/identity/rotate |
Local rotation → drives POST /v1/nodes/{id}/rotate |
NEW |
GET / PUT /node/capabilities |
View/edit the CompetenceSignature; recompute centroid from DeltaView |
NEW (reads EXISTS DeltaView) |
POST /node/registry/register |
Run the §3.1 flow via RegistryClient |
NEW |
POST /node/registry/heartbeat (scheduled) |
Reuses the existing Scheduler (EXISTS) |
NEW hook |
GET /audit/events |
Already logs every registry interaction | EXISTS |
RegistryClient (NEW, node-side) owns: challenge fetch, envelope signing (via Rust core / MVP Python key), retry/backoff, and appending each interaction to the audit chain (EXISTS).
7. Threat model
7.1 Sybil (cheap mass identities to game routing/payouts)
- Risk: identities are free (just a keypair), so an attacker floods the pool with fake "expert" nodes to capture routing/queries and (later) pay-per-use royalties.
- Mitigations (MVP): (a)
declaredcompetence is unweighted in routing untilchallenged/usage-proven (§4.3) — a fake node earns nothing without passing public probes and real accept/reject feedback; (b) owner gating — registration requires amind.quorumz.comaccount (email/wallet) asowner_ref, raising per-identity cost; (c) rate-limit registration per owner/IP. - Mitigations (later): proof-of-personhood toward the 1-human-1-iCore ideal (OPEN DECISION D6 — how strict?), stake to register, reputation decay, iCorp membership requiring admin admission.
7.2 Impersonation
- Impersonating a node_id: infeasible — the id self-certifies to the pubkey (§1.2); you'd need the private key. Replay is blocked by single-use nonce + expiry on every signed envelope.
- Handle squatting / wrong-pubkey-for-handle: the registry allocates handles, so a malicious/compromised registry could bind
@aliceto the wrong key. Mitigation: clients always verifynode_id ↔ pubkeylocally (never trust the registry's binding blindly), and the transparency log (later) lets anyone detect a registry that served an inconsistent(node_id, pubkey, handle). Handle disputes: first-claim + owner-signed + platform arbitration (MVP). - Endpoint spoofing: endpoints are self-declared; before trusting one, the router/asker dials it and runs a challenge-response (prove control of the signing key over that endpoint).
- Registry compromise (bounded): a compromised registry can censor, withhold, reorder, stall — it cannot forge identities or capability claims (records are owner-signed). Transparency log + signed-record export cap the damage and enable the DHT fallback.
7.3 Capability-privacy
- Risk: capability declaration leaks private data; or the competence centroid is inverted to reconstruct vault content.
- Mitigations: only generalized labels +
Δ_public-derived centroid are ever published (§4.2); raw data /Δ_privatenever leave; data-classes not data; the leakage gate already applied toΔ_publiccovers the centroid; membrane-hidden iCorp members are excluded from public ANN. Centroid inversion is an open risk (D3): mitigate with quantization / DP-noise / cluster-id-only publication; measure in E2. - Membership/attribution leakage: public discovery of an iCorp's internals is prevented by the
visibilityrule (§2.4) — iCorps answer as one identity; members are neither listed nor individually paid.
7.4 Other
- Eclipse (DHT era): diverse bootstrap peers + signed records; a node can't be fed a forged pubkey (self-certifying).
- Poisoned competence claims: neutralized by the proof ladder (§4.3) — unproven claims don't route.
- Replay / stale records: nonce +
expiry+updated_atmonotonicity; heartbeats expire dead nodes.
8. MVP vs. later
MVP (build first):
1. Node-identity module (M2-003): Ed25519 keypair (Keychain / file fallback), node_id derivation, k_sign signing, sign the existing audit chain. NEW.
2. hinet-registry service on Quorumz GCP / HiNet resources: own Cloud SQL (pgvector) + Cloud Run; NodeRecord + node_capability_tag. NEW.
3. Registration + heartbeat + revoke + re-register(upsert) with signed-envelope + challenge-nonce auth. NEW.
4. CompetenceSignature (declared) built from the existing DeltaView; centroid ANN + tag filters; GET /v1/discover*. NEW (reads EXISTS DeltaView).
5. Handle allocation (first-claim, owner-signed). NEW.
6. Signed-record export (GET /v1/nodes/{id} returns fully signed record) — the forward-compat hook for §5. NEW.
7. Node-local /node/identity*, /node/capabilities, /node/registry/*; audit every interaction (EXISTS chain). NEW.
Later / research:
- Signing-subkey vs genesis-key split hardening; genesis rotation + recovery-phrase/Shamir path.
- Competence proofs beyond declared: challenged (public-probe Scorecards), usage reputation, attested (TEE/zkLLM).
- iCorp/membrane + human-first lease records and admin flows.
- Transparency (CT-style) log + inclusion proofs.
- Wallet binding for payout routing.
- Decentralization: libp2p PeerId (same key), pubsub PeerAnnouncement gossip, Kademlia DHT resolution, federated ANN indexers, decentralized naming.
- Centroid-leakage hardening (DP / quantization / cluster-id).
9. Open decisions (flagged)
- D1 — two-key vs one-key identity. Recommend genesis
k_id(defines the stable id) + rotatablek_sign; fallback is a single key where rotation mints a new id. Affects §1.1, §3.4. - D2 — id stability across identity-key rotation. Recommend pinning
node_idto the original genesis pubkey with a verifiable key-history vs. new-id-plus-alias. §3.4. - D3 — competence-centroid leakage. Raw vector vs. quantized / DP-noised / cluster-id-only; measured in E2. §4.2.
- D4 — decentralized naming (handle uniqueness without a central authority). §5.3.
- D5 — decentralized capability ANN (federated indexers vs. LSH-in-DHT). §5.3.
- D6 — sybil gating strength (how strictly to enforce 1-human-1-iCore; proof-of-personhood vs. stake vs. account-gating). §7.1.
- D7 — owner_ref binding — anonymous nodes (no
owner_ref) allowed in the public pool, or is account/wallet binding mandatory? Trades privacy against sybil-resistance. §2.3/§7.1.