Domino Compass · deterministic key runtime

·Concepts

Entropy, recipes, and derivation — the deterministic core.

01How it works

Domino Compass is a deterministic secret-generation and key-runtime system. It is not a seed-phrase generator, a wallet, a password manager, or a key vault — it is the thing that produces those from physical reality.

The four things to understand

1 · The physical material is the root of authority

An 8×7 domino card — two passes of all 28 tiles — is the source. It is read, canonicalized, and hashed. Nothing else is the root.

2 · The recipe describes how material becomes entropy

A recipe is an explicit deterministic program: which ceremony, which ordering, which normalization, which lane. It is not the secret.

3 · The runtime derives multiple independent key lanes

From one root, domain-separated derivation produces an identity lane and a Bitcoin lane as siblings — never one as the child of the other.

4 · Operational material can be replaced, delegated, recovered, stored

Capabilities, descriptors, and encrypted operational state can be rotated, revoked, and persisted — without ever exposing the root.

DOMINO · COMPASS

DOMINO — physical entropy / discrete state

The domino set is a finite, observable physical system. Its state — the ordered arrangement and orientation of 28 tiles across two passes — is the entropy source. The physical object is not magic; the deterministic encoding rules are what make it reproducible.

COMPASS — deterministic navigation through a derivation space

The compass is the navigation metaphor: from the root, a recipe steers through a derivation space to reach specific keys. Doubles carry a compass quadrant (p/b/d/q) — 2 bits of entropy each — because the quadrant is an independent, observable post-spin state.

The recipe does not contain the secret. A recipe may be backed up or stored without revealing the root secret. It is a graded secret (it reveals purpose, scope, and lane context) but it is not root-equivalent.

The conceptual stack

physical entropy → deterministic recipe → root secret (S_root) → domain-separated derivation runtime → identity keys + Bitcoin keys → capabilities / delegation / revocation → encrypted operational material → optional dStor persistence

02Physical entropy

The physical object is not magic. The deterministic encoding rules are what allow reproducibility.

Random physical entropy vs. deterministically encoded physical state

There are two distinct things, and the site keeps them separate:

Random physical entropyDeterministically encoded physical state
What it isThe unpredictable outcome of a physical process (a shuffle, a spin, a toss).The recorded state of that outcome, written down under fixed rules so it can be reproduced exactly.
RoleSupplies the uncertainty.Makes the uncertainty reproducible — the same state always yields the same bytes.
ExampleShuffling 28 dominoes into a random order.Reading that order as 56 canonical tokens, in a fixed pass structure, with doubles carrying a compass quadrant.
Why this matters: if the encoding rules were ambiguous, the same physical card could be read two ways and produce two different keys. Canonicalization before hashing means formatting ambiguity can never become accidental entropy or a collision.

From physical object to entropy input

physical object → observed state → canonical representation → entropy input

For the Domino Compass ceremony specifically:

8×7 domino card (two passes of 28 tiles) → 56 canonical tokens → 56 canonical bytes (1 byte per token) → SHA-256 → 256-bit secret S_root

Entropy accounting — honest numbers

One pass of 28 tiles contributes:

28! (ordered tile permutation) ≈ 97.94 bits 2²¹ (non-double orientations) = 21 bits 4⁷ (double compass outcomes) = 14 bits ──────────────────────────────────────────── one pass ≈ 132.94 bits

Two independent passes:

(28! × 2²¹ × 4⁷)² ≈ 265.89 bits

265.89 > 256 — two full sortitions exceed the 256-bit target. This is why the ceremony requires exactly two passes.

Do not use the naive model. The tile-token alphabet has 70 types, so a tempting shortcut is 56 × log2(70) ≈ 343 bits. This is wrong: each pass uses every tile exactly once (a permutation, not independent draws), and the canonical byte encoding is a bijection onto the true sample space (28!·2²¹·4⁷)².
SHA-256 does not add entropy. It deterministically compresses a ~265.9-bit sample space onto 256 bits. Because 265.9 > 256, essentially no entropy is lost — the hash uniformizes and compresses, it does not create.

What must remain secret, what may be public

MaterialStatusWhy
The 8×7 domino card / transcript / canonical bytesSECRETIt is the root. Anyone with it can regenerate every key.
The derivation path / transcript bytesSECRETWith a public start seed, the path is the secrecy.
The recipeGRADEDNot root-equivalent, but reveals purpose, scope, lane context, and the commitment. Protect it.
Public fingerprintsPUBLICVerification handles. They prove regeneration without revealing the secret.
Capability recordsPUBLICDelegation statements. They can be shared with service peers.
Watch-only descriptors / xpubPUBLICTrack funds without signing authority.

03Recipes

A recipe is an explicit deterministic program — a transformation description — not vague "instructions." It describes how physical material becomes deterministic entropy and which lanes to derive.

Recipe ≠ root secret

The recipe is a versioned structured object. Its canonical serialization hashes to its identifier:

recipe_id = SHA-256(canonical_recipe_bytes)

The recipe must not contain S_root, the canonical transcript bytes, or any value from which S_root is recoverable. It may be backed up or stored without necessarily revealing the root secret.

Recipe fields

FieldMeaning
recipe_versione.g. dc-recipe-v1
ceremony_profilewhich physical ceremony, e.g. dc-v1-8x7
domain_taghigh-level namespace, e.g. pluronymous
entropy_card_commitmentnon-revealing commitment to the physical card
purposeNostr identity, Kapnet actor, service-peer access, trustee recovery, decoy…
scoperead-only, sign events, publish to channel, spend up to limit…
service_namespacewhich service the key is for
actor_namespacewhich actor / identity
identity_laneNostr, Kapnet, KNU, Pluronymous, delegation, recovery, revocation
bitcoin_lanekey paths, descriptors, watch-only, payment, claim, recovery, decoy
time_authorizationwall-clock and/or Bitcoin-native
revocation_lanewhich revocation path applies
child_indexper-recipe child index
networkmainnet / testnet / regtest / KNU
output_typensec, private key, BIP-39, BIP-85 child, descriptor…
checksumintegrity of the recipe itself
signaturerecipe signature by an authority

Non-revealing entropy-card commitment

The commitment is a one-way hash that is not equal to S_root and does not reveal it:

entropy_card_commitment = SHA-256(canonical_transcript_bytes || "dc-commit-v1")

The domain tag "dc-commit-v1" makes the commitment input different from the KDF input (canonical_transcript_bytes alone), so the commitment is a distinct hash. An attacker who obtains the recipe gets a one-way hash of the transcript, not the root secret. The commitment is used for verification and binding, never as a derivation input.

Recipe authentication

The recipe must be signed by an authority, and the signature must be over the canonical recipe bytes. A recipe without a valid signature from a trusted authority must be rejected — otherwise an attacker could substitute a malicious recipe with bitcoin_lane: spend-capable for a watch-only recipe, and the user would derive spend keys they never intended.

Mandatory fingerprint verification: the runtime must verify the public fingerprint against the expected value before honoring any derived key. A recipe that produces a different fingerprint must be rejected. This detects recipe substitution even if the signature is compromised.

Recipe builder

Build a recipe and inspect its exact serialized form. The builder shows the canonical JSON and the resulting recipe_id.

recipe_id
The entropy_card_commitment is filled from the current transcript in the simulator. Changing any field changes recipe_id — and therefore every derived key.

04Derivation

From the root secret, a domain-separated runtime derives parallel, independent key lanes. The Bitcoin tree is a sibling of the identity key — never a child.

The derivation pipeline

physical entropy card (8×7 transcript) → canonical_bytes (56 bytes) → S_root = SHA-256(canonical_bytes) → entropy_card_commitment = SHA-256(canonical_bytes || "dc-commit-v1") → recipe → recipe_id = SHA-256(recipe_bytes) → derivation_transcript (length-delimited) → lane_seed = HKDF-SHA256(ikm=S_root, salt=recipe_id, info=transcript) → BIP32 master = BIP32_FromSeed(lane_seed) → identity_key = master / identity_path [sibling] → bitcoin_tree = master / bitcoin_path [sibling, NOT child] → public_fingerprint = SHA-256(pubkey || recipe_id || lane_tag)
Root model preserved: S_root = SHA-256(canonical_transcript_bytes) is the ceremony root and is unchanged. HKDF is a post-root lane expander, not the root derivation. It never replaces S_root; it domain-separates it into per-lane seeds.

Domain separation

Two derivations are distinct if any bound field differs:

  • Lane separation: identity vs bitcoin lanes use different lane_tag values, so the same recipe yields distinct keys per lane.
  • Recipe separation: different recipes (different recipe_id salt) yield distinct keys even for the same lane.
  • Child separation: different child_index values yield distinct keys.
  • Field binding: changing any field (e.g. scope) changes the transcript bytes and therefore the derived secret.

Canonical derivation transcript (byte-level)

The info input to HKDF is a length-delimited binary transcript. Each field is serialized as 1-byte tag || 2-byte big-endian length || field bytes, in a fixed order. No field may be omitted, reordered, or padded.

┌─────────┬─────────┬──────────┬────────────┐ │ version │ source │ profile │ parameters │ └─────────┴─────────┴──────────┴────────────┘ tag 0x01 domain_tag (UTF-8) tag 0x02 recipe_version (UTF-8) tag 0x03 lane_tag (UTF-8: identity/bitcoin/recovery/decoy) tag 0x04 purpose (UTF-8) tag 0x05 scope (UTF-8) tag 0x06 time_authorization (UTF-8) tag 0x07 revocation_lane (UTF-8) tag 0x08 child_index (4-byte big-endian) tag 0x09 network (UTF-8) tag 0x0A entropy_card_commitment (32 raw bytes)
Why length-delimited and not JSON: canonical JSON is delimiter-based and has canonicalization pitfalls (number forms, unicode normalization, key ordering) that can produce the same semantic object with different bytes — a collision risk. Length-prefixing makes the byte representation unambiguous.
What is NOT bound: the public fingerprint. It is a post-derivation verification handle, not a pre-derivation input. Binding it would create a circular dependency.

Derivation visualizer

Root Secret branches into sibling runtime lanes — parallel domain-separated derivations, not one lane as the child of the other.

Root Secret (S_root) ├── identity lane m/220'/0'/0' │ ├── primary identity │ ├── delegated identity │ └── application-specific identity └── bitcoin lane m/86'/0'/0'/0/0 (BIP-86) · m/84'/0'/0'/0/0 (BIP-84) ├── account ├── descriptor ├── signing key └── watch-only projection

Changing the derivation profile (e.g. BIP-86 vs BIP-84) visibly produces a different subtree.

05Identity + Bitcoin dual runtime

Identity and Bitcoin keys originate from the same deterministic root while remaining cryptographically domain separated.

Same root, distinct lanes

same physical root → same deterministic root secret (S_root) then: root + identity domain → identity keys root + Bitcoin domain → Bitcoin keys

Explicitly:

identity secret ≠ Bitcoin secret identity key ≠ Bitcoin key identity fingerprint ≠ Bitcoin fingerprint

This is a core Domino Compass property. The two lanes are derived from the same master (which comes from the lane seed), as siblings — never one as the child of the other.

Why sibling, not child

If the Bitcoin tree were a child of the identity key, then identity compromise would equal funds compromise. Because the Bitcoin tree is a sibling of the identity key (both children of the same master), a leaked identity key does not reveal the Bitcoin lane.

Honest authority note: identity and Bitcoin lanes share one master, one physical card, and one air-gapped signer device. A compromise of any of these falls both lanes. The separation is at the derivation level, not the authority level. For true separation (e.g. funds vs. identity), use separate physical cards — one per authority domain.

Bitcoin-lane posture

The Bitcoin lane is not a single spend capability; it is a namespace whose spend posture is set by the profile:

PostureMeaning
spend-capablethe lane derives spend keys
watch-onlythe lane derives descriptors / xpub only, no private spend keys
claim-onlythe lane derives claim keys for a specific claim
service-payment-onlythe lane derives payment keys for a specific service
recovery-onlythe lane derives recovery-branch keys
decoythe lane derives decoy keys

A spend-capable lane is an explicit, deliberate choice, never the default.

22Versioning

Deterministic cryptographic systems require strict versioning. Changing any versioned component may deliberately produce a different derivation result.

Versioned components

Recipe v1 Derivation Profile v1 Encoding v1

Changing any versioned component may deliberately produce a different derivation result. The system must not silently reinterpret older recipes.

Why: a deterministic system's whole value is that the same inputs produce the same outputs. If a recipe could be silently reinterpreted under a new encoding, recovery would produce a different key than the original — a silent, unrecoverable divergence. Versioning makes the divergence explicit and detectable.