diff --git a/config.toml b/config.toml index 4fb7760f..df5b2777 100644 --- a/config.toml +++ b/config.toml @@ -115,6 +115,7 @@ pages = [ "understand/core-concepts/pools/index.md", "understand/core-concepts/attestation/index.md", "understand/core-concepts/defradb/index.md", + "understand/core-concepts/did-keys/index.md", "understand/core-concepts/privacy/index.md" ] diff --git a/content/reference/architecture/index.md b/content/reference/architecture/index.md index 539244db..3b8e833f 100644 --- a/content/reference/architecture/index.md +++ b/content/reference/architecture/index.md @@ -106,8 +106,8 @@ object#relation@user For example: ```plaintext -group:host#guest@did:key:z6MkHost7 -view:0xABC#subscriber@did:key:z6MkUser1 +group:host#guest@did:key:zQ3shHost7 +view:0xABC#subscriber@did:key:zQ3shUser1 ``` Permission checks evaluate whether a chain of tuples grants a specific action. Permissions are boolean expressions over relations: `admin + creator + subscriber - banned` means anyone with the admin, creator, or subscriber relation, unless they are also banned. diff --git a/content/understand/core-concepts/did-keys/index.md b/content/understand/core-concepts/did-keys/index.md new file mode 100644 index 00000000..5b891ab8 --- /dev/null +++ b/content/understand/core-concepts/did-keys/index.md @@ -0,0 +1,84 @@ ++++ +title = "DID keys" +description = "What a DID key is, how Shinzo uses it for node identity, and how it differs from the other keys a node holds." ++++ + +Every Shinzo Host and Generator has an identity. That identity is a DID key, a string that looks like this: + +```plaintext +did:key:zQ3shND2BaSKQLTBTPrvGa5i3EdVnnAFzfJ8oLXa9aG8zWY1B +``` + +You'll see these strings in config output, in SourceHub authorization tuples, and stamped onto every document a node signs. This page covers what they are, why Shinzo uses them, and what they're not. + +## What a DID key is + +A DID key is an identifier built directly from a cryptographic public key. The key pair is generated first; the public half is then encoded into a self-describing string that anyone can read back into the same public key without asking a server, a registry, or a blockchain. + +The format is a W3C standard called `did:key`. Breaking the example apart: + +```plaintext +did:key:zQ3shND2BaSKQLTBTPrvGa5i3EdVnnAFzfJ8oLXa9aG8zWY1B + └─ multibase-encoded public key +``` + +The `did:key:` prefix says "what follows is a public key encoded in a particular way." After it comes a [multibase](https://github.com/multiformats/multibase) string. The leading `z` means base58btc encoding. Decode those bytes and you get two things glued together: + +1. A short multicodec prefix that names the key type. +1. The raw public key bytes for that type. + +For the `zQ3s...` identifiers Shinzo uses, the prefix is `0xe7 0x01`, the multicodec code for a secp256k1 public key, followed by 33 bytes of compressed key. So the whole identifier is just `multibase(multicodec(secp256k1-pub) + 33 compressed bytes)`. The `z6Mk...` form you'll meet in `did:key` examples elsewhere is the same idea with the multicodec prefix for an Ed25519 key. + +A DID key is a single public key wearing a standard, self-describing wrapper. That's the whole thing. + +## Why it's useful + +The payoff is that the identifier and the verification key are the same object. A verifier who has the DID string has everything they need to check a signature. There's no second step where they look up a document on a network, fetch a key from a registry, or trust a third party to tell them which key belongs to which identity. + +This matters for Shinzo because nodes sign data constantly. Every block a Generator produces carries a `BlockSignature`, a signature over a Merkle root of the block's document CIDs, and each document gets a `_version` entry recording who signed it. A Host that receives that data, or an app reading it later, can verify those signatures with nothing more than the signer's public key — the same key the DID encodes — without a round-trip to an identity service. + +It also means the identifier is portable and stable. The same key produces the same DID everywhere, so a node's identity follows it across restarts, networks, and deployments as long as the key material survives. + +## Why Shinzo uses it instead of other key types + +A node holds several keys, and they do different jobs. DID keys are the identity layer; the others are not. + +| Key | Job | Why it's not the identity | +| --- | --- | --- | +| Node identity key (DID key) | Signs documents, registers the node, is the node's name on the network | This _is_ the identity. | +| Consensus key | Validator duties on the source chain | Tied to consensus slots, not to Shinzo document signing. | +| Operator / withdrawal keys | Acting on a validator's behalf on ShinzoHub; controlling stake withdrawals | About the source-chain validator role and its funds, not about who produced a document. | + +You could imagine identifying nodes by their consensus address or their wallet address instead. Neither works well here. A consensus address describes a validator's role on one chain, but a Shinzo node can read from many chains and shouldn't be pinned to one validator identity. A wallet address is for moving value and changes for unrelated reasons (rotation, sweeping funds). Document signing needs an identifier that is cheap to verify, tied to the signing key itself, and not overloaded with a second meaning. + +`did:key` gives you exactly that. It's a pure signing identity: one key, one identifier, verifiable offline, with no dependency on the chain the node reads from. + +## What a DID key is not + +It's worth being clear about the edges, because the name invites a few wrong assumptions. + +### It's not a wallet address + +A DID key can sign data, but it isn't an account you send tokens to and it has nothing to do with balances. ShinzoHub uses separate bech32 addresses (`shinzo1...`) for anything value-related. + +### It's not stored on a blockchain + +Some DID methods publish a DID document to a ledger or registry that can be updated over time. `did:key` doesn't. The DID document is derived from the key on demand, so there's nothing on chain to resolve and nothing to update. The trade-off is in the next section. + +### It's not rotatable + +Because the identifier _is_ the key, changing the key changes the identity. If a node's key is lost or compromised, you can't swap in a new key and keep the same DID. You get a new DID, which is a new identity. This is why backing up the keyring secret matters: the key, the keyring, and the DID are one unit. Lose the key and the identity is gone. See the backup guidance on the [Generator](/run/run-a-generator/register/#back-up-your-node-identity-key) and [Host](/run/run-a-host/register/#back-up-your-node-identity-key) registration pages. + +### It's not encryption + +The key in a DID key is for signing and verification, not for encrypting data. Confusing the two is how private keys leak. + +## How Shinzo generates and uses one + +When a Host or Generator starts for the first time, it generates a secp256k1 key pair and stores it in the DefraDB keyring, encrypted with the keyring secret you provide (`DEFRA_KEYRING_SECRET` for the Host client, `DEFRADB_KEYRING_SECRET` for the Generator client). On every later startup it loads that same identity back out of the keyring — in the Generator client, via `GetIdentityContext()`. The public key becomes the node's `did:key` identifier; the private key stays on the node, and only the public key and signatures ever leave it. + +That DID then shows up in three places: + +- Every document a Generator writes carries a `_version` signature with the signer's identity. +- Each `BlockSignature` is the Generator's identity key signing a Merkle root over the block. +- Registration and access control on SourceHub use ACP tuples like `group:host#guest@did:key:zQ3s...`, where the DID is the subject being granted a relation. diff --git a/data/glossary.json b/data/glossary.json index 53026955..ba8ed9f7 100644 --- a/data/glossary.json +++ b/data/glossary.json @@ -1,5 +1,5 @@ { - "description": "Glossary of terms and definitions for Shinzo Network's trustless blockchain data read protocol", + "description": "Glossary of terms and definitions for Shinzo Network's decentralized data indexing protocol", "terms": [ { "term": "ABI", @@ -29,7 +29,7 @@ }, { "term": "Assertion", - "definition": "A record that ties a validator's consensus identity to an operator key, so the validator can register as a generator on ShinzoHub. On the current testnet, assertions are submitted to ShinzoHub through an admin-key approval flow. The planned contract-based flow will produce a cryptographic proof on the source chain through the outpost contract.", + "definition": "A cryptographic proof, produced on a source chain, that a validator is who they claim to be. It ties the validator's consensus identity to an operator key. Without a valid assertion, a validator cannot register as a generator on ShinzoHub.", "relatedTerms": [ "Outpost", "Operator Key", @@ -40,7 +40,7 @@ }, { "term": "AttestationRecord", - "definition": "A document a host creates to track how many independent generators produced the same data for a given block. The `vote_count` field is a P-counter CRDT, so counts converge across hosts without any coordination step.", + "definition": "A document a host creates to track how many independent generator produced the same data for a given block. The `vote_count` field is a P-counter CRDT, so counts converge across hosts without any coordination step.", "relatedTerms": [ "Host", "P-counter", @@ -50,7 +50,7 @@ }, { "term": "Bech32", - "definition": "An address encoding format used on Cosmos SDK chains. ShinzoHub uses the `shinzo` prefix (e.g., `shinzo1ws69...`). The same underlying key produces both a hex address and a bech32 address; they are different representations, not different keys.", + "definition": "An address encoding format used on Cosmos SDK chains. ShinzoHub uses the `shinzo` prefix (e.g., `shinzo1ws69...`). The same underlying key produces both a hex address and a bech32 address — they are different representations, not different keys.", "relatedTerms": [ "ShinzoHub", "Cosmos SDK" @@ -102,7 +102,7 @@ }, { "term": "Consensus Public Key", - "definition": "Also called the consensus key. The public key a validator uses to sign blocks and participate in chain consensus, and the field that identifies which validator is asserting. The key type is chain-specific: on Ethereum it is a 48-byte BLS12-381 pubkey used on the beacon chain; on Cosmos SDK chains it is typically an Ed25519 CometBFT pubkey. It is distinct from the withdrawal key, which controls stake withdrawals on the execution layer. During an assertion, this key is bound to an operator key so the generator can act on the validator's behalf on ShinzoHub.", + "definition": "Also called the consensus key. The public key a validator uses to sign blocks and participate in chain consensus, and the field that identifies which validator is asserting on the outpost. The key type is chain-specific: on Ethereum it is a 48-byte BLS12-381 pubkey used on the beacon chain; on Cosmos SDK chains it is typically an Ed25519 CometBFT pubkey. It is distinct from the withdrawal key, which controls stake withdrawals on the execution layer. During an assertion, this key is bound to an operator key so the generator can act on the validator's behalf on ShinzoHub.", "relatedTerms": [ "Validator", "Assertion", @@ -134,13 +134,14 @@ "relatedTerms": [ "ShinzoHub", "SourceHub", - "CometBFT" + "CometBFT", + "Module" ] }, { "term": "CRDT", "abbreviation": "Conflict-free Replicated Data Type", - "definition": "A data structure that multiple nodes can update independently and then merge without coordination, always reaching the same result. defraDB uses CRDTs, specifically MerkleCRDTs, to merge document updates from peers.", + "definition": "A data structure that multiple nodes can update independently and then merge without coordination, always reaching the same result. defraDB uses CRDTs — specifically MerkleCRDTs — to merge document updates from peers.", "relatedTerms": [ "MerkleCRDT", "P-counter", @@ -170,7 +171,7 @@ { "term": "DID", "abbreviation": "Decentralized Identifier", - "definition": "A self-sovereign identifier (e.g., `did:key:z6Mk...`) derived from a public key. Hosts, generators, and users are identified by DIDs in SourceHub authorization tuples.", + "definition": "A self-sovereign identifier (e.g., `did:key:zQ3s...`) derived from a public key. Host clients, Generator clients, and users are identified by DIDs in SourceHub authorization tuples.", "relatedTerms": [ "DID Key", "SourceHub", @@ -179,12 +180,12 @@ }, { "term": "DID Key", - "abbreviation": "Digital Identity Key", - "definition": "A cryptographic key pair that represents a user's or device's identity in Shinzo. It is used for signing, encrypting, and authenticating operations.", + "definition": "A node identifier built directly from a cryptographic public key using the W3C `did:key` method. Shinzo Host and Generator clients derive their DID key from a secp256k1 key pair and use it to sign documents and block batches, and as their identity in SourceHub authorization tuples. See [DID keys](/understand/core-concepts/did-keys/).", "relatedTerms": [ "DID", "Orbis", - "Host" + "Host", + "Generator" ] }, { @@ -206,7 +207,7 @@ }, { "term": "EIP-712", - "definition": "An Ethereum standard for signing structured, typed data in a form users can read before approving. The planned outpost contract will use EIP-712 for the digest that a validator's withdrawal key signs during an assertion.", + "definition": "An Ethereum standard for signing structured, typed data in a form users can read before approving. The EVM outpost contract uses EIP-712 for the digest that a validator's withdrawal key signs during an assertion.", "relatedTerms": [ "Outpost", "Assertion", @@ -233,7 +234,7 @@ }, { "term": "EVM Relayer", - "definition": "A Go process that bridges an external EVM chain (e.g. Ethereum) to ShinzoHub. It subscribes to outpost events, extracts assertion or payment data, and broadcasts the relevant Cosmos SDK messages to ShinzoHub. The assertion pipeline is not yet live on the testnet (assertions are submitted through an admin-key flow instead). Not the same as the Hermes IBC relayer.", + "definition": "A Go process that bridges an external EVM chain (e.g. Ethereum) to ShinzoHub. It subscribes to outpost events, extracts assertion or payment data, and broadcasts the relevant Cosmos SDK messages to ShinzoHub. Not the same as the Hermes IBC relayer.", "relatedTerms": [ "Outpost", "Relayer", @@ -251,7 +252,6 @@ }, { "term": "GraphQL", - "definition": "The query language for reading Shinzo data. DefraDB exposes every collection, from primitives to View outputs, as GraphQL types over the /api/v0/graphql endpoint, with filters, ordering, and nested relation selections.", "relatedTerms": [ "defraDB", "View" @@ -270,7 +270,7 @@ }, { "term": "Host", - "definition": "A Shinzo node that receives verifiable blockchain data from generators over P2P, verifies it, runs lens transforms to produce view documents, and serves those documents over GraphQL.", + "definition": "A Shinzo node that receives indexed data from generator over P2P, verifies it, runs lens transforms to produce view documents, and serves those documents over GraphQL.", "relatedTerms": [ "DID Key", "Orbis", @@ -304,7 +304,7 @@ }, { "term": "Generator", - "definition": "A node that reads blockchain data from a source chain, parses it into structured documents, and writes them to defraDB. Generators are write-only: they push data out over P2P and reject all incoming replication.", + "definition": "A node that reads blockchain data from a source chain, parses it into structured documents, and writes them to defraDB. Generator are write-only: they push data out over P2P and reject all incoming replication.", "relatedTerms": [ "Indexing", "defraDB", @@ -315,7 +315,7 @@ }, { "term": "Generator Registry", - "definition": "The ShinzoHub EVM precompile at `0x0212` that tracks registered generators. A generator cannot register here directly. It must first complete an assertion. On the current testnet, assertions are submitted through an admin-key flow; the planned flow uses an outpost contract. The registry verifies the stored assertion before accepting registration.", + "definition": "The ShinzoHub EVM precompile at `0x0212` that tracks registered generator. A generator cannot register here directly — it must first complete an assertion via an outpost contract. The registry verifies the stored assertion before accepting registration.", "relatedTerms": [ "Generator", "Precompile", @@ -325,7 +325,7 @@ }, { "term": "Indexing", - "definition": "The process of parsing blockchain data and storing it as structured, schema-compliant documents in defraDB. In Shinzo this is verifiable indexing: blocks of documents are signed by the generator that produced them, so anyone can check who the data came from.", + "definition": "The process of parsing blockchain data and storing it as structured, schema-compliant documents in defraDB.", "relatedTerms": [ "Generator", "defraDB", @@ -335,7 +335,7 @@ { "term": "IPLD", "abbreviation": "Interplanetary Linked Data", - "definition": "A data model for distributed systems (used by IPFS, among others). It structures data as Merkle DAGs so every object is content-addressed and verifiable.", + "definition": "A data model for decentralized systems (used by IPFS, among others). It structures data as Merkle DAGs so every object is content-addressed and verifiable.", "relatedTerms": [ "Merkle DAG", "Content Identifier", @@ -344,9 +344,10 @@ }, { "term": "Keeper", - "definition": "In Cosmos SDK, a Go object that owns a module's state and provides the only sanctioned way to read or write it. Precompile code on ShinzoHub calls keepers directly, for example to send an ICA packet, without going through Solidity bytecode.", + "definition": "In Cosmos SDK, a Go object that owns a module's state and provides the only sanctioned way to read or write it. Precompile code on ShinzoHub calls keepers directly — for example, to send an ICA packet — without going through Solidity bytecode.", "relatedTerms": [ "Cosmos SDK", + "Module", "Precompile" ] }, @@ -373,7 +374,7 @@ }, { "term": "libp2p", - "definition": "A peer-to-peer networking library. defraDB uses it for peer discovery and document replication between generators and hosts.", + "definition": "A peer-to-peer networking library. defraDB uses it for peer discovery and document replication between generator and hosts.", "relatedTerms": [ "defraDB" ] @@ -423,13 +424,22 @@ }, { "term": "MEV-boost", - "definition": "A service on Ethereum that lets validators hand off block construction to external builders. Because those builders control the block's `extraData` field, Shinzo's planned assertion design does not rely on it. Validator identity will be read directly from the outpost event instead.", + "definition": "A service on Ethereum that lets validators hand off block construction to external builders. Because those builders control the block's `extraData` field, Shinzo's assertion design does not rely on it — validator identity is read directly from the outpost event instead.", "relatedTerms": [ "Validator", "Outpost", "Assertion" ] }, + { + "term": "Module", + "definition": "A Cosmos SDK building block that owns a slice of chain state, handles messages, and emits events. ShinzoHub adds five custom modules (`x/admin`, `x/sourcehub`, `x/host`, `x/generator`, `x/view`) on top of the standard Cosmos set.", + "relatedTerms": [ + "Cosmos SDK", + "ShinzoHub", + "Keeper" + ] + }, { "term": "Network Gateway", "definition": "A coordination service that routes user GraphQL queries to the right host. It never touches the underlying data.", @@ -468,7 +478,7 @@ }, { "term": "Outpost", - "definition": "A smart contract that will be deployed on a source chain. Validators will call it to prove their identity before registering as a generator; users will call it to pay for view access in the source chain's native currency. Each chain type has its own outpost implementation. The outpost is not yet deployed on the testnet; assertions currently use an admin-key approval flow.", + "definition": "A smart contract deployed on a source chain. Validators call it to prove their identity before registering as generator; users call it to pay for view access in the source chain's native currency. Each chain type has its own outpost implementation.", "relatedTerms": [ "Smart Contract", "ShinzoHub", @@ -517,7 +527,7 @@ }, { "term": "Pool Registry", - "definition": "The ShinzoHub EVM precompile at `0x0213` that creates and tracks pools. `registerDemandForView(view, config, bond)` materializes a pool at the deterministic address derived from (view, config) and records the caller's demand. Hosts do not join through the registry directly; they call `join()` on a pool's `Pool.sol` contract, which forwards to the registry.", + "definition": "The ShinzoHub EVM precompile at `0x0213` that creates and tracks pools. `registerDemandForView(view, config, bond)` materialises a pool at the deterministic address derived from (view, config) and records the caller's demand. Hosts do not join through the registry directly; they call `join()` on a pool's `Pool.sol` contract, which forwards to the registry.", "relatedTerms": [ "Pool", "Precompile", @@ -555,7 +565,7 @@ }, { "term": "Re-org", - "definition": "Short for chain reorganization: the canonical block at a given height changes. When this happens, different generators may briefly hold different versions of the same block. Hosts store each version as a separate document; applications pick the one with more attestation votes.", + "definition": "Short for chain reorganization: the canonical block at a given height changes. When this happens, different generator may briefly hold different versions of the same block. Hosts store each version as a separate document; applications pick the one with more attestation votes.", "relatedTerms": [ "Generator", "AttestationRecord" @@ -572,7 +582,7 @@ }, { "term": "Scheduler", - "definition": "A coordination service that reads registrations from ShinzoHub and matches generators to hosts. Like the gateway, it never handles actual data.", + "definition": "A coordination service that reads registrations from ShinzoHub and matches generator to hosts. Like the gateway, it never handles actual data.", "relatedTerms": [ "Network Gateway", "Generator", @@ -590,7 +600,7 @@ }, { "term": "ShinzoHub", - "definition": "Shinzo's coordination chain: a Cosmos SDK chain (v0.53.4) with an integrated EVM, running CometBFT consensus. It holds the view, host, and generator registries and the economic layer (staking, pricing, payments). It does not store or serve blockchain data.", + "definition": "Shinzo's coordination chain: a Cosmos SDK chain (v0.53.4) with an integrated EVM, running CometBFT consensus. It holds the view, host, and generator registries and the economic layer (staking, pricing, payments). It does not store or serve indexed blockchain data.", "relatedTerms": [ "Host", "Outpost", @@ -626,7 +636,7 @@ }, { "term": "Source chain", - "definition": "Any external blockchain that Shinzo reads data from, whether that is a base blockchain like Ethereum, one of its scaling layers, or a Cosmos chain. A source chain hosts an outpost contract and is read by generators.", + "definition": "Any external blockchain that Shinzo indexes — Ethereum, an L2, a Cosmos chain, etc. A source chain hosts an outpost contract and is read by generator.", "relatedTerms": [ "Outpost", "Generator", @@ -635,7 +645,7 @@ }, { "term": "SourceHub", - "definition": "A separate Cosmos SDK chain built by Source Network that handles authorization for Shinzo. It runs the ACP module (based on Google's Zanzibar model) and stores authorization tuples in the form `object#relation@user`. Users never call SourceHub directly; ShinzoHub sends commands to it via ICA.", + "definition": "A separate Cosmos SDK chain built by Source Network that handles authorization for Shinzo. It runs the ACP module (based on Google's Zanzibar model) and stores authorization tuples in the form `object#relation@user`. Users never call SourceHub directly — ShinzoHub sends commands to it via ICA.", "relatedTerms": [ "ACP", "Host", @@ -679,7 +689,7 @@ }, { "term": "Validator", - "definition": "An entity that participates in a chain's consensus. A validator's identity is tied to an operator key through an assertion, allowing the operator to register as a generator on ShinzoHub. In the planned contract-based flow, the validator's withdrawal key signs an EIP-712 message on the outpost to authorize the operator key.", + "definition": "An entity that participates in a chain's consensus. On Ethereum, a validator's withdrawal key signs an EIP-712 message on the outpost to authorize an operator key as its generator.", "relatedTerms": [ "Generator", "Assertion", @@ -690,7 +700,7 @@ }, { "term": "View", - "definition": "A curated, SDL-defined representation of defraDB documents. Views transform raw chain data into a structured output shape.", + "definition": "A curated, SDL-defined representation of defraDB documents. Views transform raw indexed data into a structured output shape.", "relatedTerms": [ "defraDB", "Schema Definition Language" @@ -740,7 +750,7 @@ { "term": "WASM", "abbreviation": "WebAssembly", - "definition": "A portable, sandboxed bytecode format. Lens transforms compile to WASM, typically from Rust or AssemblyScript, and hosts run them via LensVM.", + "definition": "A portable, sandboxed bytecode format. Lens transforms compile to WASM — typically from Rust or AssemblyScript — and hosts run them via LensVM.", "relatedTerms": [ "Lens", "LensVM", @@ -776,7 +786,7 @@ }, { "term": "Withdrawal Key", - "definition": "On Ethereum, the key that controls a validator's stake withdrawals. The planned outpost contract will require the withdrawal key to sign the EIP-712 assertion digest, providing the chain's strongest proof that a given party controls the validator. On the current testnet, only the withdrawal address is needed (the assertion is admin-key-approved).", + "definition": "On Ethereum, the key that controls a validator's stake withdrawals. The outpost requires the withdrawal key to sign the EIP-712 assertion digest — it is the chain's strongest proof that a given party controls the validator.", "relatedTerms": [ "Validator", "Assertion",